diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/tf2/controlzone.cpp | |
| download | archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip | |
Diffstat (limited to 'game/server/tf2/controlzone.cpp')
| -rw-r--r-- | game/server/tf2/controlzone.cpp | 331 |
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; +} + |