diff options
Diffstat (limited to 'game/server/tf2/order_assist.cpp')
| -rw-r--r-- | game/server/tf2/order_assist.cpp | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/game/server/tf2/order_assist.cpp b/game/server/tf2/order_assist.cpp new file mode 100644 index 0000000..0a9f12e --- /dev/null +++ b/game/server/tf2/order_assist.cpp @@ -0,0 +1,177 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "order_assist.h" +#include "tf_team.h" +#include "order_helpers.h" + + +// If a player has been shot within this time delta, commandos will get orders to assist. +#define COMMANDO_ASSIST_SHOT_DELAY 3.0f + +// How close a commando has to be to a teammate to get an assist order. +#define COMMAND_ASSIST_DISTANCE 1200 +#define COMMAND_ASSIST_DISTANCE_SQR (COMMAND_ASSIST_DISTANCE*COMMAND_ASSIST_DISTANCE) + + + +IMPLEMENT_SERVERCLASS_ST( COrderAssist, DT_OrderAssist ) +END_SEND_TABLE() + + +static bool IsValidFn_OnEnemyTeam( void *pUserData, int a ) +{ + edict_t *pEdict = engine->PEntityOfEntIndex( a+1 ); + if ( !pEdict ) + return false; + + CBaseEntity *pBaseEntity = CBaseEntity::Instance( pEdict ); + if ( !pBaseEntity ) + return false; + + CSortBase *p = (CSortBase*)pUserData; + return pBaseEntity->GetTeam() != p->m_pPlayer->GetTeam(); +} + + +static bool IsValidFn_PlayersWantingAssist( void *pUserData, int a ) +{ + CSortBase *pSortBase = (CSortBase*)pUserData; + CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)pSortBase->m_pPlayer->GetTeam()->GetPlayer( a ); + + if ( !pPlayer->IsAlive() ) + { + // This guy sure could have used an assist but YOU'RE TOO SLOW!!! + return false; + } + + // Don't try to assist yourself... + if ( pPlayer == pSortBase->m_pPlayer ) + return false; + + // Make sure this guy was shot recently. + if ( (gpGlobals->curtime - pPlayer->LastTimeDamagedByEnemy()) > COMMANDO_ASSIST_SHOT_DELAY ) + return false; + + // Is the guy close enough? + if ( pSortBase->m_pPlayer->GetAbsOrigin().DistToSqr( pPlayer->GetAbsOrigin() ) > COMMAND_ASSIST_DISTANCE_SQR ) + return false; + + return true; +} + + +bool COrderAssist::CreateOrder( CPlayerClass *pClass ) +{ + // Search for a (live) nearby player who's just been shot. + CSortBase info; + info.m_pPlayer = pClass->GetPlayer(); + + int sorted[512]; + int nSorted = BuildSortedActiveList( + sorted, + ARRAYSIZE( sorted ), + SortFn_TeamPlayersByDistance, + IsValidFn_PlayersWantingAssist, + &info, + pClass->GetTeam()->GetNumPlayers() + ); + + if ( nSorted ) + { + COrderAssist *pOrder = new COrderAssist; + + CBaseTFPlayer *pPlayerToAssist = (CBaseTFPlayer*)pClass->GetTeam()->GetPlayer( sorted[0] ); + + pClass->GetTeam()->AddOrder( + ORDER_ASSIST, + pPlayerToAssist, + info.m_pPlayer, + COMMAND_ASSIST_DISTANCE, + 25, + pOrder ); + + // Add the closest enemies. + CSortBase enemySortInfo; + enemySortInfo.m_pPlayer = pPlayerToAssist; + + int sortedEnemies[256]; + int nSortedEnemies = BuildSortedActiveList( + sortedEnemies, + ARRAYSIZE( sortedEnemies ), + SortFn_PlayerEntitiesByDistance, + IsValidFn_OnEnemyTeam, + &info, + gpGlobals->maxClients + ); + + nSortedEnemies = MIN( nSortedEnemies, NUM_ASSIST_ENEMIES ); + for ( int i=0; i < nSortedEnemies; i++ ) + { + CBaseEntity *pEnt = CBaseEntity::Instance( engine->PEntityOfEntIndex( sortedEnemies[i] + 1 ) ); + Assert( dynamic_cast<CBasePlayer*>( pEnt ) ); + pOrder->m_Enemies[i] = pEnt; + } + } + + return false; +} + + +bool COrderAssist::Update() +{ + if ( !GetTargetEntity() || !GetTargetEntity()->IsAlive() ) + return true; + + return BaseClass::Update(); +} + + +bool COrderAssist::UpdateOnEvent( COrderEvent_Base *pEvent ) +{ + if ( !GetTargetEntity() ) + return true; + + switch( pEvent->GetType() ) + { + // If our boy dies, then he doesn't care about assistance anymore. + case ORDER_EVENT_PLAYER_KILLED: + { + COrderEvent_PlayerKilled *pKilled = (COrderEvent_PlayerKilled*)pEvent; + if ( pKilled->m_pPlayer == GetTargetEntity() ) + return true; + } + break; + + // Did we damage one of the enemies? + case ORDER_EVENT_PLAYER_DAMAGED: + { + COrderEvent_PlayerDamaged *pPlayerDamaged = (COrderEvent_PlayerDamaged*)pEvent; + if ( pPlayerDamaged->m_TakeDamageInfo.GetInflictor() == GetOwner() ) + { + for ( int i=0; i < NUM_ASSIST_ENEMIES; i++ ) + { + if ( pPlayerDamaged->m_pPlayerDamaged == m_Enemies[i].Get() ) + { + // Reset the timer on the guy we're defending, in case we killed his + // attacker really quickly. +// CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetTargetEntity(); +// pPlayer->m_flLastTimeDamagedByEnemy = 0; + + return true; + } + } + } + } + break; + } + + return BaseClass::UpdateOnEvent( pEvent ); +} + + |