Push Gameplay

From Valve Developer Community
Revision as of 05:15, 10 February 2006 by Imatard (talk | contribs) (Contact me as needed)
Jump to: navigation, search

I realize this is not a complete walkthrough tutorial, but this is as good as i am able to get at my current work load. You guys can ... wikificate this all you wish. Its working, tested and in game.

1 Brush Entity 1 FGD Entry

Done...

Brush Entity

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: White --- Push Point Entity
//
//=============================================================================//
 
#include "cbase.h"
 
extern ConVar	showtriggers;
 
class CPushPoint : public CBaseToggle
{
public:
	DECLARE_CLASS( CPushPoint, CBaseToggle );
	DECLARE_DATADESC();
 
	void Spawn( void );
 
	virtual void StartTouch( CBaseEntity *pOther );
	virtual void EndTouch( CBaseEntity *pOther );
	void PlayerUpdateThink();
	bool CreateVPhysics( void );
 
	// Push Functions
	int GetStatus( void );
private:
	// Push Controls
	int				m_nControlled;		// Has this point been captured? By which team?
	float			m_fCaptured;		// Timer for capture
	
	// Alien Variables & Outputs
	COutputEvent m_OnAlienCapture;
	COutputEvent m_OnAlienStartTouch;
	COutputEvent m_OnAlienEndTouch;
	CUtlVector<CBasePlayerHandle> m_hAliens;

	// Human Variables & Outputs
	COutputEvent m_OnHumanCapture;
	COutputEvent m_OnHumanStartTouch;
	COutputEvent m_OnHumanEndTouch;
	CUtlVector<CBasePlayerHandle> m_hHumans;

	// Mapping Tagged Fields
	string_t		m_sNext;
	string_t		m_sPrev;
	string_t		m_sLocation;
	float			m_fCapture_time;

	// Misc. Outputs
	COutputEvent m_OnCapture;
	COutputEvent m_OnStartTouch;
	COutputEvent m_OnEndTouch;
};
 
LINK_ENTITY_TO_CLASS( push_block, CPushPoint );
 
// Start of our data description for the class
BEGIN_DATADESC( CPushPoint )
 
	// Think Functions
	DEFINE_THINKFUNC( PlayerUpdateThink ),

	// Mapping Tagged Fields
	DEFINE_KEYFIELD( m_sNext, FIELD_STRING, "next" ),
	DEFINE_KEYFIELD( m_sPrev, FIELD_STRING, "prev" ),
	DEFINE_KEYFIELD( m_sLocation, FIELD_STRING, "location"),
	DEFINE_KEYFIELD( m_fCapture_time, FIELD_FLOAT, "timer" ),
	
	// Alien Outputs
	DEFINE_OUTPUT( m_OnAlienCapture, "OnAlienCapture" ),
	DEFINE_OUTPUT( m_OnAlienStartTouch, "OnAlienStartTouch" ),
	DEFINE_OUTPUT( m_OnAlienEndTouch, "OnAlienEndTouch" ),

	// Human Outputs
	DEFINE_OUTPUT( m_OnHumanCapture, "OnHumanCapture" ),
	DEFINE_OUTPUT( m_OnHumanStartTouch, "OnHumanStartTouch" ),
	DEFINE_OUTPUT( m_OnHumanEndTouch, "OnHumanEndTouch" ),

	// Misc. Outputs
	DEFINE_OUTPUT( m_OnCapture, "OnCapture" ),
	DEFINE_OUTPUT( m_OnStartTouch, "OnStartTouch" ),
	DEFINE_OUTPUT( m_OnEndTouch, "OnEndTouch" ),
 
END_DATADESC()
 
//-----------------------------------------------------------------------------
// Purpose: Sets up the entity's initial state
//-----------------------------------------------------------------------------
void CPushPoint::Spawn( void )
{
	m_nControlled = 0;
 
	// We should use the bsp
	SetSolid( SOLID_BSP );	
	// And not collide with it
	AddSolidFlags( FSOLID_NOT_SOLID );
	// But still use it for interaction
	AddSolidFlags( FSOLID_TRIGGER );	
 
	// use the trigger no draw garbage
	if ( showtriggers.GetInt() == 0 )
	{
		AddEffects( EF_NODRAW );
	}

	// Use our brushmodel
	SetModel( STRING( GetModelName() ) );
 
	// Create our physics hull information
	CreateVPhysics();
}
 
//-----------------------------------------------------------------------------
// Purpose: Setup our physics information so we collide properly
//-----------------------------------------------------------------------------
bool CPushPoint::CreateVPhysics( void )
{
	// For collisions with physics objects
	VPhysicsInitShadow( false, false );
 
	return true;
}
 
 
int CPushPoint::GetStatus( void )
{
	return m_nControlled;
}
 
void CPushPoint::StartTouch( CBaseEntity *pOther )
{
	// Someone has touched me
	if (!pOther->IsPlayer())
		return;

	// they are a player... grab him/her
	CBasePlayer *pPlayer = ToBasePlayer(pOther);
 
	// if their team is in control of me...
	if (pPlayer->GetTeamNumber() == m_nControlled)
	{			
		// let them know and skip out
		Msg("You already control this point '%s'.\n",  m_sLocation.ToCStr() ); 
		return;
	}

	// Someone has touched me and im not captured by them...
	m_OnStartTouch.FireOutput(pOther,this);

	// See which previous point to call...
	string_t pPrevious = pPlayer->GetTeamNumber() == TEAM_HUMANS? m_sNext : m_sPrev;
	
	// See who the fuck just touched me
	pPlayer->GetTeamNumber() == TEAM_HUMANS? m_OnHumanStartTouch.FireOutput(pPlayer, this) : m_OnAlienStartTouch.FireOutput(pPlayer, this);;

	// Grab the previous push point
	CPushPoint *pPush = dynamic_cast<CPushPoint *>(gEntList.FindEntityByName( NULL, pPrevious, NULL ));
 
	// If there is a previous push point AND its not captured by the jerk who touched me...
	if (pPush && pPush->GetStatus() != pPlayer->GetTeamNumber())
	{
		Msg("You do not control the previous point '%s'.\nGo back.\n",  m_sLocation.ToCStr() ); 
		return ;
	}

	// Cool, i guess i can start thinking now.
	SetThink( &CPushPoint::PlayerUpdateThink );
	SetNextThink( gpGlobals->curtime + 0.2 );

	BaseClass::StartTouch( pOther );
}
 
 
void CPushPoint::EndTouch( CBaseEntity *pOther )
{
	// Someone stopped touching me, is it a player?
	if (pOther->IsPlayer())
	{
		// grab the player
		CBasePlayer *player = ToBasePlayer(pOther);

		// see what they team they are on...
		if (player->GetTeamNumber() == TEAM_HUMANS)
		{
			// remove them 
			m_hHumans.FindAndRemove(player);
			// Fire output
			m_OnHumanEndTouch.FireOutput(player,this);
		}
		else if (player->GetTeamNumber() == TEAM_ALIENS)
		{
			// remove them
			m_hAliens.FindAndRemove(player);
			// fire output
			m_OnAlienEndTouch.FireOutput(player,this);
		}

		// If there is no one of importance touching me...
		if (m_hAliens.Count() == 0 && m_hHumans.Count() == 0)
		{
			// Clear the thinking and timer
			SetThink(NULL);
			SetNextThink(0);
			m_fCaptured = 0;
		}
	}
	BaseClass::EndTouch( pOther );
}
// look for dead/spectating players in our volume, to call touch on
void CPushPoint::PlayerUpdateThink()
{
	// Set up my next thought process
	SetThink( &CPushPoint::PlayerUpdateThink );
	SetNextThink( gpGlobals->curtime + 0.2 );

	// Clear out the lists
	m_hAliens.RemoveAll();
	m_hHumans.RemoveAll();

	// See who is intersecting me and put them into the appropriate list
	for (int i=0; i<gpGlobals->maxClients; i++ )
	{
		// this player
		CBasePlayer *player = UTIL_PlayerByIndex( i );
 
		// is ... not a player...
		if ( !player )
			continue;
 
		// oh they are, they have to be alive too so...
		if ( !player->IsAlive() )
			continue;
 
		// if the player is intersecting the trigger, track it by storing them into the appropriate listing
		if ( Intersects( player ) )
			player->GetTeamNumber() == TEAM_ALIENS ? m_hAliens.AddToTail( player ) : m_hHumans.AddToTail( player );
	}

	DevMsg(1,"humans %d aliens %d\n capture time %.2f offset %.2f", m_hHumans.Count(), m_hAliens.Count(), m_fCaptured, m_fCapture_time);
	if (m_hAliens.Count() && !m_hHumans.Count() || !m_hAliens.Count() && m_hHumans.Count())
		if (m_fCaptured)
		{
			if (m_fCaptured < gpGlobals->curtime)
			{
				m_nControlled = m_hAliens.Count() ? TEAM_ALIENS : TEAM_HUMANS;	
				Msg("You have just captured the %s\n", m_sLocation.ToCStr());
				SetThink(NULL);
				SetNextThink(0);
			}
		}
		else
			m_fCaptured = gpGlobals->curtime + m_fCapture_time;
	else 
		if (m_fCaptured)
		{
			Msg("Fuck He's Here!\n");
			m_fCaptured = 0;
		}
}

FGD Entry

@include "base.fgd"

//-------------------------------------------------------------------------
//
// Push Point Map Entity
//
//-------------------------------------------------------------------------
@SolidClass base(Targetname) = push_block : "Push Entity Brush."
[
    // Mapping Tagged Fields
	next(string) : "Next Objective" : "" : "Set this to the next objective's name."
	prev(string) : "Previous Objective" : "" : "Set this to the previous objective's name."
    location(string) : "Location" : "" : "Set this to the name of this location to be echoed."
	timer(float) : "Time To Capture" : "1.0" : "Set this to the time it takes to capture this point."

	// Alien Outputs
	output OnAlienCapture(void) : "Fired when the Aliens team captures this point."
	output OnAlienStartTouch(void) : "Fired when the Aliens team touches this point, if this point has not been captured."
	output OnAlienEndTouch(void) : "Fired when the Aliens team stops touching this point, if this point has not been captured."

	// Human Outputs
	output OnHumanCapture(void) : "Fired when the Humans team captures this point."
	output OnHumanStartTouch(void) : "Fired when the Humans team touches this point, if this point has not been captured."
	output OnHumanEndTouch(void) : "Fired when the Humans team stops touching this point, if this point has not been captured."

	// Misc. Outputs
	output OnCapture(void) : "Fired when this point is captured."
	output OnStartTouch(void) : "Fired when this point is touched, if this point has not been captured."
	output OnEndTouch(void) : "Fired when a player stops touching this point, if this point has not been captured."
]

Contact me as needed

Full tutorial is possibly going to be on my site if this post is frequented enough to give me cause enough to write it.

ImaTard 04:14, 10 Feb 2006 (PST)