Rotating Pickups/Code: Difference between revisions
Jump to navigation
Jump to search
Islandstone (talk | contribs) No edit summary |
Thunder4ik (talk | contribs) m (clean up, added uncategorised, deadend tags) |
||
(One intermediate revision by one other user not shown) | |||
Line 1: | Line 1: | ||
{{Dead end|date=January 2024}} | |||
__TOC__ | |||
== Server == | |||
#include "cbase.h" | <source lang=cpp> | ||
#include "cbase.h" | |||
#include "items.h" | #include "items.h" | ||
// memdbgon must be the last include file in a .cpp file!!! | // memdbgon must be the last include file in a .cpp file!!! | ||
#include "tier0/memdbgon.h" | #include "tier0/memdbgon.h" | ||
#define PICKUP_DECAL "decals/item_base" | |||
#define | #define PICKUP_MODEL "models/items/healthkit.mdl" | ||
#define PICKUP_MIN_HEIGHT 50 | |||
/ | int PickupDecalIndex; // set by CRotatingPickup::Precache() | ||
#define | |||
#define | |||
// | |||
#define SF_SUPPRESS_PICKUP_DECAL 0x00000002 | |||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
// | // Rotating health kit. Heals the player when picked up. | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
class CRotatingPickup : public CItem | class CRotatingPickup : public CItem | ||
{ | { | ||
DECLARE_CLASS( CRotatingPickup, CItem ); | DECLARE_CLASS( CRotatingPickup, CItem ); | ||
DECLARE_DATADESC(); | DECLARE_DATADESC(); | ||
DECLARE_SERVERCLASS(); | |||
public: | |||
CRotatingPickup(); | CRotatingPickup(); | ||
void | void Spawn(); | ||
void | void Activate(); | ||
void Precache(); | |||
bool | bool MyTouch( CBasePlayer *pPlayer ); | ||
CBaseEntity* | CBaseEntity* Respawn(); | ||
void Materialize( | void Materialize(); | ||
int m_iHealthToGive; | |||
float m_fRespawnTime; | |||
int | CNetworkVar(bool, m_bRespawning); | ||
private: | private: | ||
Vector MdlTop; | |||
}; | }; | ||
Line 65: | Line 51: | ||
BEGIN_DATADESC( CRotatingPickup ) | BEGIN_DATADESC( CRotatingPickup ) | ||
DEFINE_KEYFIELD( m_iHealthToGive, FIELD_INTEGER, "givehealth"), | |||
DEFINE_KEYFIELD( m_fRespawnTime, FIELD_FLOAT, "respawntime"), | |||
END_DATADESC() | |||
IMPLEMENT_SERVERCLASS_ST( CRotatingPickup, DT_RotatingPickup ) | |||
SendPropBool( SENDINFO( m_bRespawning )), | |||
SendPropExclude( "DT_BaseEntity", "m_angRotation" ), | |||
END_SEND_TABLE() | |||
CRotatingPickup::CRotatingPickup() | CRotatingPickup::CRotatingPickup() | ||
{ | { | ||
if ( m_iHealthToGive <= 0 ) | if ( m_iHealthToGive <= 0 ) | ||
m_iHealthToGive = | m_iHealthToGive = 25; | ||
if ( | if ( m_fRespawnTime <= 0 ) | ||
m_fRespawnTime = 20; | |||
} | } | ||
void CRotatingPickup::Spawn() | |||
void CRotatingPickup::Spawn( | |||
{ | { | ||
// CItem is designed for Vphys objects, so we need to undo a couple of things its spawn() does | |||
Vector OriginalLocation = GetAbsOrigin(); | |||
BaseClass::Spawn(); | |||
VPhysicsDestroyObject(); | |||
SetAbsOrigin(OriginalLocation); | |||
UseClientSideAnimation(); | |||
SetModel(PICKUP_MODEL); | |||
SetMoveType(MOVETYPE_NONE); | |||
// | // Grab the highest point on the model before we change the bounding box | ||
MdlTop = GetAbsOrigin(); | |||
MdlTop.z += GetModelPtr()->hull_max().z; | |||
SetSolid(SOLID_NONE); | |||
CollisionProp()->UseTriggerBounds(true,6); // Reign in the volume added to the trigger collision box | |||
Vector OBBSize = Vector(CollisionProp()->OBBSize().Length() / 2); // need to use length as the model will be rotated at 45 degrees on clients | |||
SetSize(-OBBSize,OBBSize); // Resize the bounding box | |||
// | AddEffects(EF_NOSHADOW); | ||
} | } | ||
void CRotatingPickup::Activate() | |||
void CRotatingPickup:: | |||
{ | { | ||
BaseClass::Activate(); | |||
// Ensure minimum distance above a standable surfare | |||
trace_t tr; | |||
UTIL_TraceLine(MdlTop,MdlTop + Vector(0,0,-PICKUP_MIN_HEIGHT),MASK_PLAYERSOLID,this,COLLISION_GROUP_NONE,&tr); // measuring from MdlTop | |||
if(tr.DidHit()) | |||
{ | |||
if ( !HasSpawnFlags( SF_SUPPRESS_PICKUP_DECAL ) ) | |||
engine->StaticDecal(tr.endpos,PickupDecalIndex,0,0,false); // mark the location of the pickup | |||
SetAbsOrigin( GetAbsOrigin() + ( Vector(0,0,PICKUP_MIN_HEIGHT*(1-tr.fraction)) ) ); | |||
} | |||
} | } | ||
void CRotatingPickup:: | void CRotatingPickup::Precache() | ||
{ | { | ||
PrecacheModel( PICKUP_MODEL ); | |||
PrecacheScriptSound( "HealthKit.Touch" ); | |||
PrecacheScriptSound( "AlyxEmp.Charge" ); | |||
PickupDecalIndex = UTIL_PrecacheDecal(PICKUP_DECAL, true ); | |||
} | } | ||
// | // Called from CItem::ItemTouch() | ||
bool CRotatingPickup::MyTouch( CBasePlayer *pPlayer ) | bool CRotatingPickup::MyTouch( CBasePlayer *pPlayer ) | ||
{ | { | ||
if ( pPlayer && pPlayer->GetHealth() < pPlayer->GetMaxHealth() ) | if ( pPlayer && pPlayer->GetHealth() < pPlayer->GetMaxHealth() ) | ||
{ | { | ||
pPlayer->TakeHealth( m_iHealthToGive, DMG_GENERIC ); | pPlayer->TakeHealth( m_iHealthToGive, DMG_GENERIC ); | ||
CSingleUserRecipientFilter PlayerFilter( pPlayer ); | |||
PlayerFilter.MakeReliable(); | |||
UserMessageBegin( PlayerFilter, "ItemPickup" ); | |||
UserMessageBegin( | |||
WRITE_STRING( GetClassname() ); | WRITE_STRING( GetClassname() ); | ||
MessageEnd(); | MessageEnd(); | ||
EmitSound( PlayerFilter, pPlayer->entindex(), "HealthKit.Touch" ); // this should be done by the HUD really | |||
Respawn(); | |||
Respawn(); | |||
return true; | return true; | ||
} | } | ||
Line 186: | Line 139: | ||
} | } | ||
// | // Disappear | ||
CBaseEntity* CRotatingPickup::Respawn() | |||
CBaseEntity* CRotatingPickup::Respawn( | |||
{ | { | ||
SetTouch(NULL); | |||
m_bRespawning = true; | |||
SetThink ( &CRotatingPickup::Materialize ); | |||
SetNextThink( gpGlobals->curtime + m_fRespawnTime ); | |||
return this; | |||
} | |||
// Reappear | |||
void CRotatingPickup::Materialize() | |||
{ | |||
EmitSound("AlyxEmp.Charge"); | |||
m_bRespawning = false; | |||
SetTouch(&CItem::ItemTouch); | |||
} | |||
</source> | |||
== Client == | |||
<source lang=cpp> | |||
#include "cbase.h" | |||
// memdbgon must be the last include file in a .cpp file!!! | |||
#include "tier0/memdbgon.h" | |||
#define ITEM_ROTATION_RATE ( 360.0f / 4.0f ) | |||
#define PICKUP_MIN_HEIGHT 50 | |||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
// | // Rotating health kit. Heals the player when picked up. | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
class C_RotatingPickup : public C_BaseAnimating | |||
{ | { | ||
DECLARE_CLASS( C_RotatingPickup, C_BaseAnimating ); | |||
{ | DECLARE_CLIENTCLASS(); | ||
public: | |||
C_RotatingPickup() { | |||
ClientRotAng = QAngle(45,0,0); | |||
m_bRespawning = m_bRespawning_Cache = false; | |||
} | } | ||
void Spawn() { ClientThink(); } | |||
bool IsRespawning(); | |||
void ClientThink(); | |||
void PostDataUpdate(DataUpdateType_t updateType); | |||
bool ShouldDraw(); | |||
bool m_bRespawning; | |||
bool m_bRespawning_Cache; | |||
private: | |||
QAngle ClientRotAng; // m_angRotation is stomped sometimes (CItem returning the ent to spawn position?) | |||
}; | |||
LINK_ENTITY_TO_CLASS( item_rotating, C_RotatingPickup ); | |||
IMPLEMENT_CLIENTCLASS_DT( C_RotatingPickup, DT_RotatingPickup,CRotatingPickup ) | |||
RecvPropBool( RECVINFO(m_bRespawning) ), | |||
END_RECV_TABLE() | |||
inline bool C_RotatingPickup::IsRespawning() | |||
{ | |||
return m_bRespawning; | |||
} | } | ||
void C_RotatingPickup::ClientThink() | |||
void | |||
{ | { | ||
// | if (IsAbsQueriesValid()) | ||
{ | |||
// Rotate | |||
ClientRotAng.y += ITEM_ROTATION_RATE * gpGlobals->frametime; | |||
if ( ClientRotAng.y >= 360 ) | |||
ClientRotAng.y -= 360; | |||
SetAbsAngles( ClientRotAng ); | |||
} | |||
// | SetNextClientThink(CLIENT_THINK_ALWAYS); | ||
} | |||
void C_RotatingPickup::PostDataUpdate(DataUpdateType_t updateType) | |||
{ | |||
if (m_bRespawning_Cache != m_bRespawning) | |||
{ | |||
// Appear/disappear | |||
UpdateVisibility(); | |||
ClientRotAng.y = 0; | |||
m_bRespawning_Cache = m_bRespawning; | |||
} | |||
return BaseClass::PostDataUpdate(updateType); | |||
} | |||
bool C_RotatingPickup::ShouldDraw() | |||
{ | |||
return !IsRespawning() && BaseClass::ShouldDraw(); | |||
} | } | ||
</ | </source> | ||
== FGD == | |||
== | <source lang=php> | ||
@PointClass base(Item) studio("models/items/healthkit.mdl") = item_rotating: "A spinning health kit" | |||
[ | |||
givehealth(integer) : "Health to give" : 25 | |||
respawntime(float) : "Respawn time" : 20 | |||
spawnflags(Flags) = | |||
[ | |||
2 : "Suppress location decal" : 0 | |||
] | |||
] | |||
</source> | |||
{{Uncategorized|date=January 2024}} |
Latest revision as of 10:09, 21 January 2024

This article has no
links to other VDC articles. Please help improve this article by adding links
that are relevant to the context within the existing text.
January 2024


January 2024
Server
#include "cbase.h"
#include "items.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define PICKUP_DECAL "decals/item_base"
#define PICKUP_MODEL "models/items/healthkit.mdl"
#define PICKUP_MIN_HEIGHT 50
int PickupDecalIndex; // set by CRotatingPickup::Precache()
#define SF_SUPPRESS_PICKUP_DECAL 0x00000002
//-----------------------------------------------------------------------------
// Rotating health kit. Heals the player when picked up.
//-----------------------------------------------------------------------------
class CRotatingPickup : public CItem
{
DECLARE_CLASS( CRotatingPickup, CItem );
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
public:
CRotatingPickup();
void Spawn();
void Activate();
void Precache();
bool MyTouch( CBasePlayer *pPlayer );
CBaseEntity* Respawn();
void Materialize();
int m_iHealthToGive;
float m_fRespawnTime;
CNetworkVar(bool, m_bRespawning);
private:
Vector MdlTop;
};
LINK_ENTITY_TO_CLASS( item_rotating, CRotatingPickup );
PRECACHE_REGISTER( item_rotating );
BEGIN_DATADESC( CRotatingPickup )
DEFINE_KEYFIELD( m_iHealthToGive, FIELD_INTEGER, "givehealth"),
DEFINE_KEYFIELD( m_fRespawnTime, FIELD_FLOAT, "respawntime"),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST( CRotatingPickup, DT_RotatingPickup )
SendPropBool( SENDINFO( m_bRespawning )),
SendPropExclude( "DT_BaseEntity", "m_angRotation" ),
END_SEND_TABLE()
CRotatingPickup::CRotatingPickup()
{
if ( m_iHealthToGive <= 0 )
m_iHealthToGive = 25;
if ( m_fRespawnTime <= 0 )
m_fRespawnTime = 20;
}
void CRotatingPickup::Spawn()
{
// CItem is designed for Vphys objects, so we need to undo a couple of things its spawn() does
Vector OriginalLocation = GetAbsOrigin();
BaseClass::Spawn();
VPhysicsDestroyObject();
SetAbsOrigin(OriginalLocation);
UseClientSideAnimation();
SetModel(PICKUP_MODEL);
SetMoveType(MOVETYPE_NONE);
// Grab the highest point on the model before we change the bounding box
MdlTop = GetAbsOrigin();
MdlTop.z += GetModelPtr()->hull_max().z;
SetSolid(SOLID_NONE);
CollisionProp()->UseTriggerBounds(true,6); // Reign in the volume added to the trigger collision box
Vector OBBSize = Vector(CollisionProp()->OBBSize().Length() / 2); // need to use length as the model will be rotated at 45 degrees on clients
SetSize(-OBBSize,OBBSize); // Resize the bounding box
AddEffects(EF_NOSHADOW);
}
void CRotatingPickup::Activate()
{
BaseClass::Activate();
// Ensure minimum distance above a standable surfare
trace_t tr;
UTIL_TraceLine(MdlTop,MdlTop + Vector(0,0,-PICKUP_MIN_HEIGHT),MASK_PLAYERSOLID,this,COLLISION_GROUP_NONE,&tr); // measuring from MdlTop
if(tr.DidHit())
{
if ( !HasSpawnFlags( SF_SUPPRESS_PICKUP_DECAL ) )
engine->StaticDecal(tr.endpos,PickupDecalIndex,0,0,false); // mark the location of the pickup
SetAbsOrigin( GetAbsOrigin() + ( Vector(0,0,PICKUP_MIN_HEIGHT*(1-tr.fraction)) ) );
}
}
void CRotatingPickup::Precache()
{
PrecacheModel( PICKUP_MODEL );
PrecacheScriptSound( "HealthKit.Touch" );
PrecacheScriptSound( "AlyxEmp.Charge" );
PickupDecalIndex = UTIL_PrecacheDecal(PICKUP_DECAL, true );
}
// Called from CItem::ItemTouch()
bool CRotatingPickup::MyTouch( CBasePlayer *pPlayer )
{
if ( pPlayer && pPlayer->GetHealth() < pPlayer->GetMaxHealth() )
{
pPlayer->TakeHealth( m_iHealthToGive, DMG_GENERIC );
CSingleUserRecipientFilter PlayerFilter( pPlayer );
PlayerFilter.MakeReliable();
UserMessageBegin( PlayerFilter, "ItemPickup" );
WRITE_STRING( GetClassname() );
MessageEnd();
EmitSound( PlayerFilter, pPlayer->entindex(), "HealthKit.Touch" ); // this should be done by the HUD really
Respawn();
return true;
}
return false;
}
// Disappear
CBaseEntity* CRotatingPickup::Respawn()
{
SetTouch(NULL);
m_bRespawning = true;
SetThink ( &CRotatingPickup::Materialize );
SetNextThink( gpGlobals->curtime + m_fRespawnTime );
return this;
}
// Reappear
void CRotatingPickup::Materialize()
{
EmitSound("AlyxEmp.Charge");
m_bRespawning = false;
SetTouch(&CItem::ItemTouch);
}
Client
#include "cbase.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define ITEM_ROTATION_RATE ( 360.0f / 4.0f )
#define PICKUP_MIN_HEIGHT 50
//-----------------------------------------------------------------------------
// Rotating health kit. Heals the player when picked up.
//-----------------------------------------------------------------------------
class C_RotatingPickup : public C_BaseAnimating
{
DECLARE_CLASS( C_RotatingPickup, C_BaseAnimating );
DECLARE_CLIENTCLASS();
public:
C_RotatingPickup() {
ClientRotAng = QAngle(45,0,0);
m_bRespawning = m_bRespawning_Cache = false;
}
void Spawn() { ClientThink(); }
bool IsRespawning();
void ClientThink();
void PostDataUpdate(DataUpdateType_t updateType);
bool ShouldDraw();
bool m_bRespawning;
bool m_bRespawning_Cache;
private:
QAngle ClientRotAng; // m_angRotation is stomped sometimes (CItem returning the ent to spawn position?)
};
LINK_ENTITY_TO_CLASS( item_rotating, C_RotatingPickup );
IMPLEMENT_CLIENTCLASS_DT( C_RotatingPickup, DT_RotatingPickup,CRotatingPickup )
RecvPropBool( RECVINFO(m_bRespawning) ),
END_RECV_TABLE()
inline bool C_RotatingPickup::IsRespawning()
{
return m_bRespawning;
}
void C_RotatingPickup::ClientThink()
{
if (IsAbsQueriesValid())
{
// Rotate
ClientRotAng.y += ITEM_ROTATION_RATE * gpGlobals->frametime;
if ( ClientRotAng.y >= 360 )
ClientRotAng.y -= 360;
SetAbsAngles( ClientRotAng );
}
SetNextClientThink(CLIENT_THINK_ALWAYS);
}
void C_RotatingPickup::PostDataUpdate(DataUpdateType_t updateType)
{
if (m_bRespawning_Cache != m_bRespawning)
{
// Appear/disappear
UpdateVisibility();
ClientRotAng.y = 0;
m_bRespawning_Cache = m_bRespawning;
}
return BaseClass::PostDataUpdate(updateType);
}
bool C_RotatingPickup::ShouldDraw()
{
return !IsRespawning() && BaseClass::ShouldDraw();
}
FGD
@PointClass base(Item) studio("models/items/healthkit.mdl") = item_rotating: "A spinning health kit"
[
givehealth(integer) : "Health to give" : 25
respawntime(float) : "Respawn time" : 20
spawnflags(Flags) =
[
2 : "Suppress location decal" : 0
]
]

This article has not been added to any content
categories. Please help out by
adding categories.
January 2024


January 2024