Rotating Pickups/Code
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