You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
4.3 KiB
177 lines
4.3 KiB
//========= 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 ); |
|
} |
|
|
|
|
|
|