Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
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.

178 lines
4.3 KiB

5 years ago
//========= 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 );
}