Rotating Pickups/Code: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(New page: <pre> //================ Coder: Maestro ==============// // // Purpose: Make a healthkit that rotates // //=============================================================================...)
 
No edit summary
Line 255: Line 255:
}
}
</pre>
</pre>
== See Also ==
*[[Rotating Pickups|Rotating Pickups]]

Revision as of 07:15, 8 February 2009

//================ Coder: Maestro				 ==============//
//
// Purpose: Make a healthkit that rotates
//
//=============================================================================//

#include "cbase.h" // The base for all entities
#include "player.h" // The player itself
#include "items.h" // Where we derive our class from
#include "engine/IEngineSound.h" // This takes care of the sounds

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

// This defines the size of a box around our pickup
#define		ITEM_PICKUP_BOX_BLOAT           24

// A full rotation divided by the number of seconds it takes to rotate
#define		ITEM_ROTATION_RATE             ( 360.0f / 9.0f )

// Define what will be the default health inside
#define         DEFAULT_HEALTH_TO_GIVE         25

// Define what will be the default respawn time
#define         DEFAULT_RESPAWN_TIME           20


//-----------------------------------------------------------------------------
// Small rotating health kit. Heals the player when picked up.
//-----------------------------------------------------------------------------
class CRotatingPickup : public CItem
{
public:
	DECLARE_CLASS( CRotatingPickup, CItem );
	DECLARE_DATADESC();

	CRotatingPickup();

	void			Spawn( void );
	void			Precache( void );

	bool			MyTouch( CBasePlayer *pPlayer );
	void			FallThink( void ) { return; } // Override the function that makes items fall to the ground
	void			RotateThink( void );

	CBaseEntity*		Respawn( void );
	void			Materialize( void );

protected:

	int			m_iHealthToGive;
	int			m_iRespawnTime;
	Vector			RespawnPosition;

private:

	void			UpdateSpawnPosition( Vector originalSpawnPosition );

};

LINK_ENTITY_TO_CLASS( item_rotating, CRotatingPickup );

PRECACHE_REGISTER( item_rotating );

BEGIN_DATADESC( CRotatingPickup )

DEFINE_KEYFIELD( m_iHealthToGive, FIELD_INTEGER, "health"),
DEFINE_KEYFIELD( m_iRespawnTime, FIELD_INTEGER, "respawntime"),

DEFINE_THINKFUNC( RotateThink ),

END_DATADESC()

//-----------------------------------------------------------------------------
// Purpose: Initialize member variables
//-----------------------------------------------------------------------------
CRotatingPickup::CRotatingPickup()
{
	m_bShouldFall = false;

	if ( m_iHealthToGive <= 0 )
		m_iHealthToGive = DEFAULT_HEALTH_TO_GIVE;

	if ( m_iRespawnTime <= 0 )
		m_iRespawnTime = DEFAULT_RESPAWN_TIME;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CRotatingPickup::Spawn( void )
{
	BaseClass::Spawn(); //Spawn the baseclass

	Precache();	// Make sure the assets are loaded

	SetMoveType( MOVETYPE_NONE ); // It will only rotate, not move
	SetSolid( SOLID_BBOX ); // It is solid
	SetCollisionGroup( COLLISION_GROUP_WEAPON ); // And it can collide with stuff

	CollisionProp()->UseTriggerBounds( true, ITEM_PICKUP_BOX_BLOAT ); // Create a collision trigger around the object
	SetTouch(&CRotatingPickup::ItemTouch); // ItemTouch is a function in our base class that takes care of touches

	UpdateSpawnPosition( GetAbsOrigin() ); // We update our position relative to the ground

	// Set the x angle, since it will never change
	QAngle angle = GetAbsAngles();
	angle.x = 45;
	SetAbsAngles( angle );

	m_takedamage = DAMAGE_EVENTS_ONLY;

	SetModel( "models/items/healthkit.mdl" ); // Set the model we'll use

	// Start thinking in 0.01 seconds
	SetThink( &CRotatingPickup::RotateThink );
	SetNextThink( gpGlobals->curtime + 0.01f );
}

//-----------------------------------------------------------------------------
// Purpose: Make sure the engine loads the sounds and models before they are used
//-----------------------------------------------------------------------------
void CRotatingPickup::Precache( void )
{
	PrecacheModel( "models/items/healthkit.mdl" ); // Change this to get another model
	PrecacheScriptSound( "HealthKit.Touch" );  // scripts/game_sounds_items.txt
}

void CRotatingPickup::UpdateSpawnPosition( Vector originalPosition )
{
	// Create local variables
	trace_t tr; // The trace
	Vector end, dir, final; // The vectors
	QAngle down; // The angles

	down.y = -90; //Make angle point down

	AngleVectors( down, &dir); //Make the vector point to the angle

	end = originalPosition + dir * MAX_TRACE_LENGTH; // Get the end point

	// Trace a line down to the ground
	UTIL_TraceLine( originalPosition, end, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );

	final = tr.endpos; // final is now the position of the ground right beneath our entity

	final.z += 50; // Add 50 units in height 

	SetAbsOrigin( final ); // Update our position to be 50 units above the ground
	RespawnPosition = final; // Store our position for easy access later
}

//-----------------------------------------------------------------------------
// Purpose: Give the player health and plays a sound
// Input  : *pPlayer - 
// Output : 
//-----------------------------------------------------------------------------
bool CRotatingPickup::MyTouch( CBasePlayer *pPlayer )
{
	//Check the pointer and check if the player needs more health
	if ( pPlayer && pPlayer->GetHealth() < pPlayer->GetMaxHealth() ) 
	{
		pPlayer->TakeHealth( m_iHealthToGive, DMG_GENERIC );

		// This code is related to the hud
		CSingleUserRecipientFilter user( pPlayer );
		user.MakeReliable();

		UserMessageBegin( user, "ItemPickup" );
		WRITE_STRING( GetClassname() );
		MessageEnd();

		// Output the sound sound
		CPASAttenuationFilter filter( pPlayer, "HealthKit.Touch" );
		EmitSound( filter, pPlayer->entindex(), "HealthKit.Touch" );

		//Msg("A player picked up something!\n" ); //Uncomment this line to get a note in the console when picked up

		Respawn(); // Respawn our pickup

		return true;
	}

	return false;
}

//-----------------------------------------------------------------------------
// Purpose: Initiate the respawning process
//-----------------------------------------------------------------------------
CBaseEntity* CRotatingPickup::Respawn( void )
{
	// It can't be touched and it can't be seen
	SetTouch( NULL );
	AddEffects( EF_NODRAW );

	//Reset the movetypes
	SetMoveType( MOVETYPE_NONE );
	SetSolid( SOLID_BBOX );
	SetCollisionGroup( COLLISION_GROUP_WEAPON );

	UTIL_SetOrigin( this, RespawnPosition ); //Get our respawn position from earlier

	// Reset the angles
	QAngle angle = GetAbsAngles();
	angle.x = 45;
	SetAbsAngles( angle );

	RemoveAllDecals(); //Remove any decals

	//Start thinking when the pickup should appear again
	SetThink ( &CRotatingPickup::Materialize );
	SetNextThink( gpGlobals->curtime + m_iRespawnTime );

	return this;
}

//-----------------------------------------------------------------------------
// Purpose: Finalize the respawning process
//-----------------------------------------------------------------------------
void CRotatingPickup::Materialize( void )
{
	if ( IsEffectActive( EF_NODRAW ) )
	{
		//Changing from invisible state to visible.
		RemoveEffects( EF_NODRAW );
	}

	EmitSound( "AlyxEmp.Charge" ); //Emit a sound

	SetTouch( &CRotatingPickup::ItemTouch ); //Reset our think functions

	SetThink( &CRotatingPickup::RotateThink ); // Start rotating again
	SetNextThink( gpGlobals->curtime + 0.01f ); // Think in 0.01 sec
}

//-----------------------------------------------------------------------------
// Purpose: Make our model rotate
//-----------------------------------------------------------------------------
void CRotatingPickup::RotateThink( void )
{
	// This makes sure the model rotates independent of the fps
	float dt = gpGlobals->curtime - GetLastThink(); 

	QAngle angles = GetAbsAngles(); //Get the current angles

	// Set the angles according to the rotation rate and fps
	angles.y += ( ITEM_ROTATION_RATE * dt ); 

	if ( angles.y >= 360 )	// If the rotation is more than 360, 
		angles.y -= 360;	// subtract 360 to avoid large variables

	SetAbsAngles( angles ); // Set the angles now
	SetNextThink( gpGlobals->curtime + 0.01f ); // Think again in 0.01 sec
}

See Also