summaryrefslogtreecommitdiff
path: root/game/server/tf2/controlzone.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/tf2/controlzone.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/server/tf2/controlzone.cpp')
-rw-r--r--game/server/tf2/controlzone.cpp331
1 files changed, 331 insertions, 0 deletions
diff --git a/game/server/tf2/controlzone.cpp b/game/server/tf2/controlzone.cpp
new file mode 100644
index 0000000..a58a0ba
--- /dev/null
+++ b/game/server/tf2/controlzone.cpp
@@ -0,0 +1,331 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Complete definition of the ControlZone behavioral entity
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "tf_shareddefs.h"
+#include "cbase.h"
+#include "EntityOutput.h"
+#include "tf_player.h"
+#include "controlzone.h"
+#include "team.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Since the control zone is a data only class, force it to always be sent ( shouldn't change often so )
+// bandwidth usage should be small.
+// Input : **ppSendTable -
+// *recipient -
+// *pvs -
+// clientArea -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+int CControlZone::UpdateTransmitState()
+{
+ if ( IsEffectActive( EF_NODRAW ) )
+ {
+ return SetTransmitState( FL_EDICT_DONTSEND );
+ }
+ else
+ {
+ return SetTransmitState( FL_EDICT_ALWAYS );
+ }
+}
+
+IMPLEMENT_SERVERCLASS_ST(CControlZone, DT_ControlZone)
+ SendPropInt( SENDINFO(m_nZoneNumber), 8, SPROP_UNSIGNED ),
+END_SEND_TABLE()
+
+LINK_ENTITY_TO_CLASS( trigger_controlzone, CControlZone);
+
+BEGIN_DATADESC( CControlZone )
+
+ // outputs
+ DEFINE_OUTPUT( m_ControllingTeam, "ControllingTeam" ),
+
+ // inputs
+ DEFINE_INPUTFUNC( FIELD_VOID, "SetTeam", InputSetTeam ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "LockTeam", InputLockControllingTeam ),
+
+ // keys
+ DEFINE_KEYFIELD_NOT_SAVED( m_iLockAfterChange, FIELD_INTEGER, "LockAfterChange" ),
+ DEFINE_KEYFIELD_NOT_SAVED( m_flTimeTillCaptured, FIELD_FLOAT, "UncontestedTime" ),
+ DEFINE_KEYFIELD_NOT_SAVED( m_flTimeTillContested, FIELD_FLOAT, "ContestedTime" ),
+ DEFINE_KEYFIELD_NOT_SAVED( m_nZoneNumber, FIELD_INTEGER, "ZoneNumber" ),
+
+END_DATADESC()
+
+
+
+// Control Zone Ent Flags
+#define CZF_DONT_USE_TOUCHES 1
+
+//-----------------------------------------------------------------------------
+// Purpose: Initializes the control zone
+// Records who was the original controlling team (for control locking)
+//-----------------------------------------------------------------------------
+void CControlZone::Spawn( void )
+{
+ // set the starting controlling team
+ m_ControllingTeam.Set( GetTeamNumber(), this, this );
+
+ // remember who the original controlling team was (for control locking)
+ m_iDefendingTeam = GetTeamNumber();
+
+ // Solid
+ SetSolid( SOLID_BSP );
+ AddSolidFlags( FSOLID_TRIGGER );
+ SetMoveType( MOVETYPE_NONE );
+ SetModel( STRING( GetModelName() ) ); // set size and link into world
+
+ // TF2 rules
+ m_flTimeTillContested = 10.0; // Go to contested 10 seconds after enemies enter the zone
+ m_flTimeTillCaptured = 5.0; // Go to captured state as soon as only one team holds the zone
+
+ if ( m_nZoneNumber == 0 )
+ {
+ Warning( "Warning, trigger_controlzone without Zone Number set\n" );
+ }
+
+ m_ZonePlayerList.Purge();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Records that a player has entered the zone, and updates it's state
+// according, maybe starting to change team.
+// Input : *pOther - the entity that left the zone
+//-----------------------------------------------------------------------------
+void CControlZone::StartTouch( CBaseEntity *pOther )
+{
+ CBaseTFPlayer *pl = ToBaseTFPlayer( pOther );
+ if ( !pl )
+ return;
+
+ CHandle< CBaseTFPlayer > hHandle;
+ hHandle = pl;
+
+ m_ZonePlayerList.AddToTail( hHandle );
+
+ ReevaluateControllingTeam();
+
+ // Set this player's current zone to this zone
+ pl->SetCurrentZone( this );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Records that a player has left the zone, and updates it's state
+// according, maybe starting to change team.
+// Input : *pOther - the entity that left the zone
+//-----------------------------------------------------------------------------
+void CControlZone::EndTouch( CBaseEntity *pOther )
+{
+ CBaseTFPlayer *pl = ToBaseTFPlayer( pOther );
+ if ( !pl )
+ return;
+
+ CHandle< CBaseTFPlayer > hHandle;
+ hHandle = pl;
+ m_ZonePlayerList.FindAndRemove( hHandle );
+
+ ReevaluateControllingTeam();
+
+ // Unset this player's current zone if it's this one
+ if ( pl->GetCurrentZone() == this )
+ pl->SetCurrentZone( NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks to see if it's time to change controllers
+//-----------------------------------------------------------------------------
+void CControlZone::ReevaluateControllingTeam( void )
+{
+ // Count the number of players in each team
+ int i;
+ memset( m_iPlayersInZone, 0, sizeof( m_iPlayersInZone ) );
+ for ( i = 0; i < m_ZonePlayerList.Size(); i++ )
+ {
+ if ( m_ZonePlayerList[i] != NULL && (m_ZonePlayerList[i]->GetTeamNumber() > 0) )
+ {
+ m_iPlayersInZone[ m_ZonePlayerList[i]->GetTeamNumber() ] += 1;
+ }
+ }
+
+ // Abort immediately if we're not using touches to changes teams
+ if ( HasSpawnFlags( CZF_DONT_USE_TOUCHES ) )
+ return;
+
+ // if we're locked in place, no changes can occur to controlling team except through an explicit map ResetTeam
+ if ( m_iLocked )
+ return;
+
+ bool foundAnyTeam = false;
+ int teamFound = 0;
+
+ // check to see if any teams have no players
+ for ( i = 0; i < GetNumberOfTeams(); i++ )
+ {
+ if ( m_iPlayersInZone[i] )
+ {
+ if ( foundAnyTeam )
+ {
+ // we've already found a team, so it's being contested;
+ teamFound = ZONE_CONTESTED;
+ break;
+ }
+
+ foundAnyTeam = true;
+ teamFound = i;
+ }
+ }
+
+ // no one in the area!
+ if ( teamFound == 0 )
+ {
+ // just leave it as it is, let it continue to change team
+ // exception: if the zone state is contested, and there aren't any players in the zone,
+ // just return to the team who used to own the zone.
+ if ( GetTeamNumber() == ZONE_CONTESTED )
+ {
+ ChangeTeam(m_iDefendingTeam);
+ SetControllingTeam( this, m_iDefendingTeam );
+ }
+
+ return;
+ }
+
+ // if it's the same controlling team, don't worry about it
+ if ( teamFound == GetTeamNumber() )
+ {
+ // the right team is in control, don't even think of switching
+ m_iTryingToChangeToTeam = 0;
+ SetNextThink( TICK_NEVER_THINK );
+ return;
+ }
+
+ // Find out if the zone isn't owned by anyone at all (hasn't been touched since the map started, and it started un-owned)
+ bool bHasBeenOwned = true;
+ if ( m_iDefendingTeam == 0 && GetTeamNumber() == 0 )
+ bHasBeenOwned = false;
+
+ // if it's not contested, always go to contested mode
+ if ( GetTeamNumber() != ZONE_CONTESTED && teamFound != GetTeamNumber() )
+ {
+ // Unowned zones are captured immediately (no contesting stage)
+ if ( bHasBeenOwned )
+ teamFound = ZONE_CONTESTED;
+ }
+
+ // if it's the team we're trying to change to, don't worry about it
+ if ( teamFound == m_iTryingToChangeToTeam )
+ return;
+
+ // set up the time to change to the new team soon
+ m_iTryingToChangeToTeam = teamFound;
+
+ // changing from contested->uncontested and visa-versa have different delays
+ if ( m_iTryingToChangeToTeam != ZONE_CONTESTED )
+ {
+ if ( !bHasBeenOwned )
+ {
+ DevMsg( 1, "trigger_controlzone: (%s) changing team to %d NOW\n", GetDebugName(), m_iTryingToChangeToTeam );
+ SetNextThink( gpGlobals->curtime + 0.1f );
+ }
+ else
+ {
+ DevMsg( 1, "trigger_controlzone: (%s) changing team to %d in %.2f seconds\n", GetDebugName(), m_iTryingToChangeToTeam, m_flTimeTillCaptured );
+ SetNextThink( gpGlobals->curtime + m_flTimeTillCaptured );
+ }
+ }
+ else
+ {
+ DevMsg( 1, "trigger_controlzone: (%s) changing to contested in %f seconds\n", GetDebugName(), m_flTimeTillContested );
+ SetNextThink( gpGlobals->curtime + m_flTimeTillContested );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks to see if an uncontested territory is ready to change state
+// to the new controlling team.
+//-----------------------------------------------------------------------------
+void CControlZone::Think( void )
+{
+ if ( m_iTryingToChangeToTeam != 0 )
+ {
+ // held zone long enough
+ SetControllingTeam( this, m_iTryingToChangeToTeam );
+
+ // lock against further change if set
+ if ( m_iLockAfterChange )
+ {
+ LockControllingTeam();
+ }
+
+ // Re-evaluate controlling team if we were changing to Contested (enemy may have withdrawn)
+ if ( GetTeamNumber() == ZONE_CONTESTED )
+ {
+ ReevaluateControllingTeam();
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: set it so the team can no longer change, until a set controlling team action occurs
+//-----------------------------------------------------------------------------
+void CControlZone::InputLockControllingTeam( inputdata_t &inputdata )
+{
+ LockControllingTeam();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Input handler that sets the controlling team to the activator's team.
+//-----------------------------------------------------------------------------
+void CControlZone::InputSetTeam( inputdata_t &inputdata )
+{
+ // Abort if it's already the defending team
+ if ( inputdata.pActivator->GetTeamNumber() == GetTeamNumber() )
+ return;
+
+ // set the new team
+ ChangeTeam(inputdata.pActivator->GetTeamNumber());
+ SetControllingTeam( inputdata.pActivator, GetTeamNumber() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Changes the team controlling this zone
+// Input : newTeam - the new team to change to
+//-----------------------------------------------------------------------------
+void CControlZone::SetControllingTeam( CBaseEntity *pActivator, int newTeam )
+{
+ DevMsg( 1, "trigger_controlzone: (%s) changing team to: %d\n", GetDebugName(), newTeam );
+
+ // remember this team as the defenders of the zone
+ m_iDefendingTeam = GetTeamNumber();
+
+ // reset state, firing the output
+ ChangeTeam(newTeam);
+ m_ControllingTeam.Set( GetTeamNumber(), pActivator, this );
+ m_iLocked = FALSE;
+ m_iTryingToChangeToTeam = 0;
+ SetNextThink( TICK_NEVER_THINK );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlZone::LockControllingTeam( void )
+{
+ // never lock a zone in contested mode
+ if ( GetTeamNumber() == ZONE_CONTESTED )
+ return;
+
+ // zones never lock to the defenders
+ if ( GetTeamNumber() == m_iDefendingTeam )
+ return;
+
+ m_iLocked = TRUE;
+}
+