summaryrefslogtreecommitdiff
path: root/game/server/tf2/order_assist.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/server/tf2/order_assist.cpp')
-rw-r--r--game/server/tf2/order_assist.cpp177
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 );
+}
+
+