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.
1434 lines
44 KiB
1434 lines
44 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Team management class. Contains all the details for a specific team |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
#include "cbase.h" |
|
#include "team.h" |
|
#include "tf_team.h" |
|
#include "tf_func_resource.h" |
|
#include "tf_player.h" |
|
#include "techtree.h" |
|
#include "tf_obj.h" |
|
#include "tf_obj_resupply.h" |
|
#include "orders.h" |
|
#include "entitylist.h" |
|
#include "team_spawnpoint.h" |
|
#include "team_messages.h" |
|
#include "tf_obj_powerpack.h" |
|
#include "tf_gamerules.h" |
|
#include "engine/IEngineSound.h" |
|
#include "tier1/strtools.h" |
|
#include "tf_stats.h" |
|
#include "tf_obj_buff_station.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
#define OBJECT_COVERED_DIST 1000 |
|
#define RESOURCE_GIVE_TIME 30 |
|
#define RESOURCE_GIVE_AMOUNT 150 |
|
#define RESOURCE_DONATION_AMT_PER_PLAYER 10 |
|
|
|
bool IsEntityVisibleToTactical( int iLocalTeamNumber, int iLocalTeamPlayers, |
|
int iLocalTeamObjects, int iEntIndex, const char *pEntName, int pEntTeamNumber, const Vector &pEntOrigin ); |
|
extern ConVar tf_destroyobjects; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: SendProxy that converts the UtlVector list of radar scanners to entindexes, where it's reassembled on the client |
|
//----------------------------------------------------------------------------- |
|
void SendProxy_ObjectList( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ) |
|
{ |
|
CTFTeam *pTeam = (CTFTeam*)pData; |
|
|
|
// If this fails, then SendProxyArrayLength_TeamObjects didn't work. |
|
Assert( iElement < pTeam->GetNumObjects() ); |
|
|
|
CBaseObject *pObject = pTeam->GetObject(iElement); |
|
EHANDLE hObject; |
|
hObject = pObject; |
|
|
|
SendProxy_EHandleToInt( pProp, pStruct, &hObject, pOut, iElement, objectID ); |
|
} |
|
|
|
|
|
int SendProxyArrayLength_TeamObjects( const void *pStruct, int objectID ) |
|
{ |
|
CTFTeam *pTeam = (CTFTeam*)pStruct; |
|
int iObjects = pTeam->GetNumObjects(); |
|
Assert( iObjects < MAX_OBJECTS_PER_TEAM ); |
|
return iObjects; |
|
} |
|
|
|
|
|
// Datatable |
|
IMPLEMENT_SERVERCLASS_ST(CTFTeam, DT_TFTeam) |
|
SendPropFloat( SENDINFO(m_fResources), 16, SPROP_NOSCALE ), |
|
SendPropFloat( SENDINFO(m_fPotentialResources), 16, SPROP_NOSCALE ), |
|
SendPropInt( SENDINFO(m_bHaveZone), 1, SPROP_UNSIGNED ), |
|
|
|
SendPropArray2( |
|
SendProxyArrayLength_TeamObjects, |
|
SendPropInt("object_array_element", 0, SIZEOF_IGNORE, NUM_NETWORKED_EHANDLE_BITS, SPROP_UNSIGNED, SendProxy_ObjectList), |
|
MAX_OBJECTS_PER_TEAM, |
|
0, |
|
"object_array" |
|
) |
|
END_SEND_TABLE() |
|
|
|
LINK_ENTITY_TO_CLASS( tf_team_manager, CTFTeam ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Get a pointer to the specified TF team manager |
|
//----------------------------------------------------------------------------- |
|
CTFTeam *GetGlobalTFTeam( int iIndex ) |
|
{ |
|
return (CTFTeam*)GetGlobalTeam( iIndex ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Needed because this is an entity, but should never be used |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::Init( const char *pName, int iNumber ) |
|
{ |
|
BaseClass::Init( pName, iNumber ); |
|
|
|
InitializeTeamResources(); |
|
InitializeTechTree(); |
|
InitializeOrders(); |
|
ClearMessages(); |
|
|
|
m_flNextResourceTime = 0; |
|
|
|
// Only detect changes every half-second. |
|
NetworkProp()->SetUpdateInterval( 0.75f ); |
|
|
|
m_flTotalResourcesSoFar = m_iLastUpdateSentAt = 0; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFTeam::~CTFTeam( void ) |
|
{ |
|
m_aResourcesBeingCollected.Purge(); |
|
m_aResupplyBeacons.Purge(); |
|
m_aObjects.Purge(); |
|
m_aOrders.Purge(); |
|
|
|
delete m_pTechnologyTree; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::Precache( void ) |
|
{ |
|
// Precache all the technologies in the techtree |
|
for ( int i = 0; i < m_pTechnologyTree->GetNumberTechnologies(); i++ ) |
|
{ |
|
PrecacheTechnology( m_pTechnologyTree->GetTechnology(i) ); |
|
} |
|
|
|
PrecacheScriptSound( "TFTeam.CapturedZone" ); |
|
PrecacheScriptSound( "TFTeam.LostZone" ); |
|
PrecacheScriptSound( "TFTeam.ObtainStolenTechnology" ); |
|
PrecacheScriptSound( "TFTeam.BoughtPreferredTechnology" ); |
|
PrecacheScriptSound( "TFTeam.AddOrder" ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Precache a technology's files |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::PrecacheTechnology( CBaseTechnology *pTech ) |
|
{ |
|
// Precache sounds for every class result |
|
for (int i = 0; i < TFCLASS_CLASS_COUNT; i++ ) |
|
{ |
|
if ( pTech->GetSoundFile(i) && (pTech->GetSoundFile(i)[0] != 0) ) |
|
{ |
|
PrecacheScriptSound( pTech->GetSoundFile(i) ); |
|
pTech->SetClassResultSound( i, 0 ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called every frame |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::Think( void ) |
|
{ |
|
UpdateOrders(); |
|
UpdateMessages(); |
|
|
|
// FIXME: Try this out? |
|
/* |
|
// Give resources to the team at regular intervals |
|
if (gpGlobals->curtime >= m_flNextResourceTime) |
|
{ |
|
AddTeamResources( RESOURCE_GIVE_AMOUNT ); |
|
m_flNextResourceTime = gpGlobals->curtime + RESOURCE_GIVE_TIME; |
|
} |
|
*/ |
|
|
|
UpdateTechnologies(); |
|
|
|
/* FIXME: Re-enable once we figure out what the correct orders should be |
|
// Create new personal orders |
|
if ( m_flPersonalOrderUpdateTime < gpGlobals->curtime ) |
|
{ |
|
CreatePersonalOrders(); |
|
m_flPersonalOrderUpdateTime = gpGlobals->curtime + PERSONAL_ORDER_UPDATE_TIME; |
|
} |
|
*/ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// DATA HANDLING |
|
//----------------------------------------------------------------------------- |
|
// Purpose: Check to see if we should resend the entire tech tree to a player on Hud reinitialisation, which happens every player respawn |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::UpdateClientData( CBasePlayer *pPlayer ) |
|
{ |
|
CBaseTFPlayer *pTFPlayer = (CBaseTFPlayer *)pPlayer; |
|
// If we're initialising the hud, update all technologies |
|
if ( pTFPlayer->HUDNeedsRestart() ) |
|
{ |
|
// Check all the technologies and resend any that differ from this client's representation |
|
for ( int i = 0; i < m_pTechnologyTree->GetNumberTechnologies(); i++ ) |
|
{ |
|
// Update all technologies |
|
CBaseTechnology *technology = m_pTechnologyTree->GetTechnology(i); |
|
if ( technology ) |
|
{ |
|
// Check to see if any resource levels have changed |
|
if ( pTFPlayer->AvailableTech(i).m_nResourceLevel != technology->GetResourceLevel() ) |
|
{ |
|
UpdateClientTechnology( i, pTFPlayer ); |
|
continue; |
|
} |
|
|
|
if ( technology->GetAvailable() != pTFPlayer->AvailableTech(i).m_nAvailable ) |
|
{ |
|
UpdateClientTechnology( i, pTFPlayer ); |
|
continue; |
|
} |
|
|
|
byte pcount = technology->GetPreferenceCount(); |
|
if ( pTFPlayer->GetPreferredTechnology() == i ) |
|
{ |
|
pcount |= 0x80; |
|
} |
|
|
|
if ( pcount != pTFPlayer->AvailableTech(i).m_nUserCount ) |
|
{ |
|
UpdateClientTechnology( i, pTFPlayer ); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Update a technology for a player |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::UpdateClientTechnology( int iTechID, CBaseTFPlayer *pPlayer ) |
|
{ |
|
CBaseTechnology *pTechnology = m_pTechnologyTree->GetTechnology( iTechID ); |
|
if ( !pTechnology ) |
|
return; |
|
|
|
byte pcount = pTechnology->GetPreferenceCount(); |
|
|
|
if ( pPlayer->GetPreferredTechnology() == iTechID ) |
|
{ |
|
pcount |= 0x80; |
|
} |
|
|
|
CSingleUserRecipientFilter user( pPlayer ); |
|
user.MakeReliable(); |
|
|
|
// Update this technology |
|
UserMessageBegin( user, "Technology" ); |
|
WRITE_BYTE( iTechID ); |
|
WRITE_BYTE( pTechnology->GetAvailable() ); |
|
WRITE_BYTE( pcount ); |
|
WRITE_SHORT( (short)pTechnology->GetResourceLevel() ); |
|
MessageEnd(); |
|
|
|
// Update the player's client tech representation |
|
pPlayer->AvailableTech(iTechID).m_nAvailable = pTechnology->GetAvailable(); |
|
pPlayer->AvailableTech(iTechID).m_nUserCount = pcount; |
|
pPlayer->AvailableTech(iTechID).m_nResourceLevel = pTechnology->GetResourceLevel(); |
|
|
|
/* |
|
Msg( "Sent %s(%d) to %s:\n", pTechnology->GetName(), iTechID, pPlayer->GetPlayerName() ); |
|
Msg( " Available: %d\n", pTechnology->GetAvailable() ); |
|
Msg( " PrefCount: %d\n", pTechnology->GetPreferenceCount() ); |
|
Msg( " Level : %0.2f\n", pTechnology->GetResourceLevel() ); |
|
*/ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Check to see if any technology has changed, and resend it to players if it has |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::UpdateTechnologyData( void ) |
|
{ |
|
for ( int i = 0; i < m_pTechnologyTree->GetNumberTechnologies(); i++ ) |
|
{ |
|
// Update all technologies |
|
CBaseTechnology *pTechnology = m_pTechnologyTree->GetTechnology(i); |
|
if ( pTechnology && pTechnology->IsDirty() ) |
|
{ |
|
// Send it to all our clients |
|
for ( int iPlayer = 0; iPlayer < m_aPlayers.Count(); iPlayer++ ) |
|
{ |
|
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)m_aPlayers[iPlayer]; |
|
UpdateClientTechnology( i, pPlayer ); |
|
} |
|
|
|
pTechnology->SetDirty( false ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFTeam::ShouldTransmitToPlayer( CBasePlayer* pRecipient, CBaseEntity* pEntity ) |
|
{ |
|
return IsEntityVisibleToTactical( pEntity ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Is the specified entity visible on this team's tactical view? |
|
//----------------------------------------------------------------------------- |
|
bool CTFTeam::IsEntityVisibleToTactical( CBaseEntity *pEntity ) |
|
{ |
|
return ::IsEntityVisibleToTactical( GetTeamNumber(), GetNumPlayers(), |
|
GetNumObjects(), pEntity->entindex(), (char*)STRING(pEntity->m_iClassname), |
|
pEntity->GetTeamNumber(), pEntity->GetAbsOrigin() ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// RESOURCES |
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
// Purpose: Add a resource zone to the list of zones to collect from |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::AddResourceZone( CResourceZone *pResource ) |
|
{ |
|
TRACE_OBJECT( UTIL_VarArgs( "%0.2f CTFTeam::AddResourceZone adding res zone %p to team %s\n", gpGlobals->curtime, |
|
pResource, GetName() ) ); |
|
|
|
// If this resource is already owned by another team, remove it from them |
|
CTFTeam *pOwners = pResource->GetOwningTeam(); |
|
if ( pOwners ) |
|
{ |
|
pOwners->RemoveResourceZone( pResource ); |
|
} |
|
|
|
pResource->SetOwningTeam( GetTeamNumber() ); |
|
|
|
m_aResourcesBeingCollected.AddToTail( pResource ); |
|
m_bHaveZone = true; |
|
|
|
// Tell all the team's members |
|
for ( int i = 0; i < m_aPlayers.Count(); i++ ) |
|
{ |
|
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)m_aPlayers[i]; |
|
CSingleUserRecipientFilter filter( pPlayer ); |
|
filter.MakeReliable(); |
|
CBaseEntity::EmitSound( filter, pPlayer->entindex(), "TFTeam.CapturedZone" ); |
|
} |
|
|
|
// Recalculate team's orders |
|
RecalcOrders(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Remove a resource zone from the list of zones being collected from |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::RemoveResourceZone( CResourceZone *pResource ) |
|
{ |
|
TRACE_OBJECT( UTIL_VarArgs( "%0.2f CTFTeam::RemoveResourceZone removing res zone %p from team %s\n", gpGlobals->curtime, |
|
pResource, GetName() ) ); |
|
|
|
// Now remove the zone from our list |
|
m_aResourcesBeingCollected.FindAndRemove( pResource ); |
|
|
|
// Still have a zone if there are other zones in the list |
|
m_bHaveZone = ( m_aResourcesBeingCollected.Count() > 0 ); |
|
|
|
// Tell all the team's members |
|
for ( int i = 0; i < m_aPlayers.Count(); i++ ) |
|
{ |
|
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)m_aPlayers[i]; |
|
CSingleUserRecipientFilter filter( pPlayer ); |
|
filter.MakeReliable(); |
|
CBaseEntity::EmitSound( filter, pPlayer->entindex(),"TFTeam.LostZone" ); |
|
} |
|
|
|
// Recalculate team's orders |
|
RecalcOrders(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Recalculate the potential resources |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::UpdatePotentialResources( void ) |
|
{ |
|
// Set potential to current amount |
|
m_fPotentialResources = GetTeamResources(); |
|
|
|
// This used to be used for collectors. |
|
// It could be updated to count all incoming resources in en-route resource boxes. |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return the amount of resources a player should get when joining this team |
|
//----------------------------------------------------------------------------- |
|
float CTFTeam::GetJoiningPlayerResources( void ) |
|
{ |
|
// If we had our banks set recently, use that amount |
|
if ( gpGlobals->curtime < (m_flLastBankSetTime + 30.0) ) |
|
return m_flLastBankSetAmount; |
|
|
|
if ( !GetNumPlayers() ) |
|
return 0; |
|
|
|
// Otherwise, take the average of all the players on the team |
|
RecomputeTeamResources(); |
|
return ( GetTeamResources() / GetNumPlayers() ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::SetRecentBankSet( float flResources ) |
|
{ |
|
m_flLastBankSetAmount = flResources; |
|
m_flLastBankSetTime = gpGlobals->curtime; |
|
} |
|
|
|
//------------------------------------------------------------------------------------------------------------------ |
|
// TECHNOLOGY TREE |
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::InitializeTechTree( void ) |
|
{ |
|
m_pTechnologyTree = new CTechnologyTree( filesystem, GetTeamNumber() ); |
|
|
|
// Now iterate through added techs and automatically make level 0 techs available |
|
for (int i = 0; i < m_pTechnologyTree->GetNumberTechnologies(); i++ ) |
|
{ |
|
CBaseTechnology *tech = m_pTechnologyTree->GetTechnology(i); |
|
if ( !tech ) |
|
continue; |
|
|
|
if ( tech->GetLevel() == 0 ) |
|
{ |
|
EnableTechnology( tech ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTechnologyTree *CTFTeam::GetTechnologyTree( void ) |
|
{ |
|
return m_pTechnologyTree; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: A new technology has been attained by this team. Give it to every player. |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::EnableTechnology( CBaseTechnology *technology, bool bStolen ) |
|
{ |
|
CTeamFortress *rules = TFGameRules(); |
|
if ( rules ) |
|
{ |
|
// Disable autoswitching if we are getting a weapon |
|
rules->SetAllowWeaponSwitch( false ); |
|
} |
|
|
|
// Set the technology's resources to the costs |
|
// Needed because technologies can be enabled through other means than resource spending |
|
technology->ForceComplete(); |
|
|
|
// Apply technology to team first. |
|
technology->AddTechnologyToTeam( this ); |
|
|
|
// Iterate though players |
|
for (int i = 0; i < m_aPlayers.Count(); i++ ) |
|
{ |
|
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)m_aPlayers[i]; |
|
technology->AddTechnologyToPlayer( pPlayer ); |
|
|
|
CSingleUserRecipientFilter filter( pPlayer ); |
|
filter.MakeReliable(); |
|
|
|
// Play the sound |
|
if (bStolen) |
|
{ |
|
CBaseEntity::EmitSound( filter, pPlayer->entindex(), "TFTeam.ObtainStolenTechnology" ); |
|
} |
|
else |
|
{ |
|
if ( technology->GetSoundFile(0) && technology->GetSoundFile(0)[0] ) |
|
{ |
|
EmitSound_t ep; |
|
ep.m_nChannel = CHAN_STATIC; |
|
ep.m_pSoundName = technology->GetSoundFile(0); |
|
|
|
CBaseEntity::EmitSound( filter, pPlayer->entindex(), ep ); |
|
} |
|
} |
|
|
|
// Remove all the player's votes on this technology |
|
CBaseTechnology *pPreferredTech = m_pTechnologyTree->GetTechnology( pPlayer->GetPreferredTechnology() ); |
|
if ( pPreferredTech && pPreferredTech == technology ) |
|
{ |
|
// Tell the player his preferred tech has been bought |
|
if (!bStolen) |
|
{ |
|
CBaseEntity::EmitSound( filter, pPlayer->entindex(), "TFTeam.BoughtPreferredTechnology" ); |
|
} |
|
|
|
pPlayer->SetPreferredTechnology( m_pTechnologyTree, -1 ); |
|
} |
|
} |
|
|
|
// Let the team see if it wants to do anything with this specific technology |
|
GainedNewTechnology( technology ); |
|
|
|
// Reenable autoswitching |
|
if ( rules ) |
|
{ |
|
rules->SetAllowWeaponSwitch( true ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: For debugging.. |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::EnableAllTechnologies() |
|
{ |
|
for ( int i = 0; i < m_pTechnologyTree->GetNumberTechnologies(); i++ ) |
|
{ |
|
CBaseTechnology *technology = m_pTechnologyTree->GetTechnology(i); |
|
if ( !technology || technology->IsHidden() ) |
|
continue; |
|
|
|
EnableTechnology( technology ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called any time a player votes/changes preferences on the client |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::RecomputePreferences( void ) |
|
{ |
|
// Zero total counters |
|
m_pTechnologyTree->ClearPreferenceCount(); |
|
|
|
// Zero out all preferences and iterate through active players |
|
int i; |
|
for ( i = 0; i < m_pTechnologyTree->GetNumberTechnologies(); i++ ) |
|
{ |
|
CBaseTechnology *technology = m_pTechnologyTree->GetTechnology(i); |
|
if ( technology ) |
|
{ |
|
// Zero internal counters |
|
technology->ZeroPreferences(); |
|
} |
|
} |
|
|
|
// Now loop through players and see what's preferred |
|
for ( i = 0; i < m_aPlayers.Count(); i++ ) |
|
{ |
|
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)m_aPlayers[i]; |
|
if ( !pPlayer ) |
|
continue; |
|
|
|
int preferred = pPlayer->GetPreferredTechnology(); |
|
// No preference set, don't worry about this player |
|
if ( preferred == -1 ) |
|
continue; |
|
|
|
if ( preferred < 0 || preferred >= MAX_TECHNOLOGIES ) |
|
{ |
|
Msg( "Player %s tried to set preference to out of range tech %i\n", preferred ); |
|
continue; |
|
} |
|
|
|
// Reference technology |
|
CBaseTechnology *technology = m_pTechnologyTree->GetTechnology(preferred); |
|
Assert( technology ); |
|
if ( !technology ) |
|
continue; |
|
|
|
// Msg( "player %s prefers %s\n", pPlayer->GetPlayerName(), technology->GetPrintName() ); |
|
|
|
// Add one vote |
|
technology->IncrementPreferences(); |
|
// Add one vote to totals |
|
m_pTechnologyTree->IncrementPreferences(); |
|
} |
|
|
|
// Any time preferences are changed/set, see if we should make any purchases immediately. |
|
RecomputePurchases(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Figure our how many resources we've got in the team |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::RecomputeTeamResources( void ) |
|
{ |
|
// Recalculate the total amount of resources the team has |
|
m_fResources = 0.0f; |
|
for ( int i = 0; i < GetNumPlayers(); i++ ) |
|
{ |
|
m_fResources += ((CBaseTFPlayer*)GetPlayer(i))->GetBankResources(); |
|
} |
|
|
|
UpdatePotentialResources(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Attempt to spend resources according to player's preferences |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::RecomputePurchases( void ) |
|
{ |
|
RecomputeTeamResources(); |
|
|
|
// Cycle through all players, and spend their resources on the technologies they're voting for |
|
for ( int iPlayer = 0; iPlayer < m_aPlayers.Count(); iPlayer++ ) |
|
{ |
|
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)GetPlayer( iPlayer ); |
|
|
|
// See if he has any resources to spend on a tech |
|
if ( pPlayer->GetBankResources() <= 0 ) |
|
continue; |
|
|
|
// Has he got a preffered tech? |
|
if ( pPlayer->GetPreferredTechnology() != -1 ) |
|
{ |
|
// Get the player's voted-for technology |
|
CBaseTechnology *pPreferredTech = m_pTechnologyTree->GetTechnology( pPlayer->GetPreferredTechnology() ); |
|
if ( pPreferredTech && pPreferredTech->GetAvailable() == false ) |
|
{ |
|
if ( !pPreferredTech->GetResourceCost() ) |
|
continue; |
|
|
|
// Try to spend resources on the tech |
|
int iResourcesSpent = MIN( pPlayer->GetBankResources(), pPreferredTech->GetResourceCost() - pPreferredTech->GetResourceLevel() ); |
|
if ( pPreferredTech->IncreaseResourceLevel( iResourcesSpent ) ) |
|
{ |
|
// The technology's had enough resources spent to buy it, so enable it |
|
EnableTechnology( pPreferredTech ); |
|
Msg( "%s bought %s\n", GetName(), pPreferredTech->GetPrintName() ); |
|
} |
|
|
|
// Reduce the player's bank |
|
if ( iResourcesSpent ) |
|
{ |
|
pPlayer->RemoveBankResources( iResourcesSpent ); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return true if the team owns the specified technology |
|
//----------------------------------------------------------------------------- |
|
bool CTFTeam::HasNamedTechnology( const char *name ) |
|
{ |
|
// Look it up |
|
// FIXME: This could be too slow, consider using #define'd/indexed names? |
|
CBaseTechnology *tech = m_pTechnologyTree->GetTechnology( name ); |
|
if ( !tech ) |
|
return false; |
|
if ( !tech->GetAvailable() ) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: A new technology has been received by the team. Do anything specific to this technology here. |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::GainedNewTechnology( CBaseTechnology *pTechnology ) |
|
{ |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called by the team's Think function |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::UpdateTechnologies( void ) |
|
{ |
|
// Update clients |
|
UpdateTechnologyData(); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------------------------------------------------ |
|
// PLAYERS |
|
//----------------------------------------------------------------------------- |
|
// Purpose: Add the specified player to this team. Remove them from their current team, if any. |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::AddPlayer( CBasePlayer *pPlayer ) |
|
{ |
|
BaseClass::AddPlayer( pPlayer ); |
|
|
|
// Give the player this team's technology |
|
for ( int i = 0; i < m_pTechnologyTree->GetNumberTechnologies(); i++ ) |
|
{ |
|
CBaseTechnology *technology = m_pTechnologyTree->GetTechnology(i); |
|
if ( !technology ) |
|
continue; |
|
|
|
if ( technology->IsHidden() ) |
|
continue; |
|
|
|
// Not yet available to team, skip |
|
if ( !technology->GetAvailable() ) |
|
continue; |
|
|
|
// Add it. |
|
technology->AddTechnologyToPlayer( (CBaseTFPlayer*)pPlayer ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Clean up the player's objects when they leave |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::RemovePlayer( CBasePlayer *pPlayer ) |
|
{ |
|
BaseClass::RemovePlayer( pPlayer ); |
|
|
|
// Destroy all objects belonging to this player |
|
if ( tf_destroyobjects.GetFloat() ) |
|
{ |
|
// Work backwards through the list because objects remove themselves |
|
int iSize = m_aObjects.Count(); |
|
for (int i = iSize-1; i >= 0; i--) |
|
{ |
|
if ( (m_aObjects[i]->GetBuilder() == pPlayer) && (m_aObjects[i]->ShouldAutoRemove()) ) |
|
{ |
|
UTIL_Remove( m_aObjects[i] ); |
|
} |
|
} |
|
} |
|
|
|
RecomputePreferences(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return the number of team members of the specified class |
|
//----------------------------------------------------------------------------- |
|
int CTFTeam::GetNumOfClass( TFClass iClass ) |
|
{ |
|
int iNumber = 0; |
|
for ( int i = 0; i < GetNumPlayers(); i++ ) |
|
{ |
|
if ( ((CBaseTFPlayer*)GetPlayer(i))->IsClass(iClass) ) |
|
{ |
|
iNumber++; |
|
} |
|
} |
|
return iNumber; |
|
} |
|
|
|
//------------------------------------------------------------------------------------------------------------------ |
|
// RESOURCE BANK |
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::InitializeTeamResources( void ) |
|
{ |
|
m_fResources = 0.0f; |
|
m_fPotentialResources = 0.0f; |
|
m_bHaveZone = false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
float CTFTeam::GetTeamResources( void ) |
|
{ |
|
return m_fResources; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Add resources to this team |
|
//----------------------------------------------------------------------------- |
|
int CTFTeam::AddTeamResources( float fAmount, int nStat ) |
|
{ |
|
fAmount = clamp(fAmount, 0, 9999.f); |
|
|
|
m_flTotalResourcesSoFar += fAmount; |
|
|
|
TFStats()->IncrementTeamStat( GetTeamNumber(), TF_TEAM_STAT_RESOURCES_COLLECTED, fAmount ); |
|
|
|
// Divvy the resources out to the players |
|
int iAmountPerPlayer = Ceil2Int( fAmount / GetNumPlayers() ); // Yes, this does create some resources in the roundoff. |
|
for ( int i = 0; i < GetNumPlayers(); i++ ) |
|
{ |
|
CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetPlayer(i); |
|
pPlayer->AddBankResources( iAmountPerPlayer ); |
|
TFStats()->IncrementPlayerStat( pPlayer, TF_PLAYER_STAT_RESOURCES_ACQUIRED, fAmount ); |
|
|
|
if (nStat >= 0) |
|
{ |
|
TFStats()->IncrementPlayerStat( pPlayer, (TFPlayerStatId_t)nStat, fAmount ); |
|
} |
|
} |
|
|
|
ResourceLoadDeposited(); |
|
|
|
return iAmountPerPlayer; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Give resources to the player |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::DonateResources( CBaseTFPlayer *pPlayer ) |
|
{ |
|
int nPlayerCount = GetNumPlayers(); |
|
if (nPlayerCount <= 1) |
|
return; |
|
|
|
int pResourceCount; |
|
int pResourcePerPlayer; |
|
int pDonationCount; |
|
|
|
bool bDonating = false; |
|
pResourceCount = pPlayer->GetBankResources(); |
|
|
|
// Figure out how many resources per player to donate |
|
pResourcePerPlayer = pResourceCount / (nPlayerCount - 1); |
|
if (pResourceCount % (nPlayerCount - 1) != 0) |
|
++pResourcePerPlayer; |
|
|
|
// Clamp to max amt per teammate for each hit... |
|
if (pResourcePerPlayer > RESOURCE_DONATION_AMT_PER_PLAYER) |
|
pResourcePerPlayer = RESOURCE_DONATION_AMT_PER_PLAYER; |
|
|
|
// Figure out if we are donating anything at all |
|
if (pResourceCount > 0) |
|
bDonating = true; |
|
if (!bDonating) |
|
return; |
|
|
|
// Now that we've figured how much to donate, do it! |
|
for ( int i = 0; i < nPlayerCount; i++ ) |
|
{ |
|
CBaseTFPlayer *pDest = (CBaseTFPlayer*)GetPlayer(i); |
|
if (pDest == pPlayer) |
|
continue; |
|
|
|
// The last guy(s) gets the scraps... too bad. |
|
int nCountToDonate = pResourceCount; |
|
if (nCountToDonate > pResourcePerPlayer) |
|
nCountToDonate = pResourcePerPlayer; |
|
pResourceCount -= nCountToDonate; |
|
pDonationCount = nCountToDonate; |
|
|
|
pPlayer->DonateResources( pDest, pDonationCount ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: New resources have just been dumped in the bank |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::ResourceLoadDeposited( void ) |
|
{ |
|
// HACK TEST CODE |
|
// Remove after Resource Experiment! |
|
static int iIncrements = 250; |
|
if ( m_flTotalResourcesSoFar >= (m_iLastUpdateSentAt + iIncrements) ) |
|
{ |
|
while ( m_flTotalResourcesSoFar >= (m_iLastUpdateSentAt + iIncrements) ) |
|
{ |
|
m_iLastUpdateSentAt += iIncrements; |
|
} |
|
|
|
EntityMessageBegin( (CBaseEntity*)this ); |
|
WRITE_LONG( m_iLastUpdateSentAt ); |
|
MessageEnd(); |
|
} |
|
|
|
// Now see if we should buy anything |
|
RecomputePurchases(); |
|
} |
|
|
|
//------------------------------------------------------------------------------------------------------------------ |
|
// RESUPPLY BEACONS |
|
//----------------------------------------------------------------------------- |
|
// Purpose: Add the specified resupply beacon to this team. |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::AddResupply( CObjectResupply *pResupply ) |
|
{ |
|
TRACE_OBJECT( UTIL_VarArgs( "%0.2f CTFTeam::AddResupply adding resupply %p to team %s\n", gpGlobals->curtime, |
|
pResupply, GetName() ) ); |
|
|
|
m_aResupplyBeacons.AddToTail( pResupply ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Remove this resupply beacon from the team |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::RemoveResupply( CObjectResupply *pResupply ) |
|
{ |
|
TRACE_OBJECT( UTIL_VarArgs( "%0.2f CTFTeam::RemoveResupply remove resupply %p from team %s\n", gpGlobals->curtime, |
|
pResupply, GetName() ) ); |
|
|
|
// Now remove the beacon from our list |
|
m_aResupplyBeacons.FindAndRemove( pResupply ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTFTeam::GetNumObjects( int iObjectType ) |
|
{ |
|
// Asking for a count of a specific object type? |
|
if ( iObjectType > 0 ) |
|
{ |
|
int iCount = 0; |
|
for ( int i = 0; i < GetNumObjects(); i++ ) |
|
{ |
|
CBaseObject *pObject = GetObject(i); |
|
if ( pObject && pObject->GetType() == iObjectType ) |
|
{ |
|
iCount++; |
|
} |
|
} |
|
return iCount; |
|
} |
|
|
|
return m_aObjects.Count(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CBaseObject *CTFTeam::GetObject( int num ) |
|
{ |
|
Assert( num >= 0 && num < m_aObjects.Count() ); |
|
return m_aObjects[ num ]; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTFTeam::GetNumResupplies( void ) |
|
{ |
|
return m_aResupplyBeacons.Count(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CObjectResupply *CTFTeam::GetResupply( int num ) |
|
{ |
|
Assert( num >= 0 && num < m_aResupplyBeacons.Count() ); |
|
return m_aResupplyBeacons[ num ]; |
|
} |
|
|
|
|
|
bool CTFTeam::IsCoveredBySentryGun( const Vector &vPos ) |
|
{ |
|
for( int i=0; i < m_aObjects.Count(); i++ ) |
|
{ |
|
CBaseObject *pObj = m_aObjects[i]; |
|
|
|
if ( pObj->IsSentrygun() && vPos.DistTo( pObj->GetAbsOrigin() ) < OBJECT_COVERED_DIST ) |
|
return true; |
|
|
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
int CTFTeam::GetNumShieldWallsCoveringPosition( const Vector &vPos ) |
|
{ |
|
int count = 0; |
|
|
|
for ( int i=0; i < m_aObjects.Count(); i++ ) |
|
{ |
|
CBaseObject *pObj = m_aObjects[i]; |
|
|
|
if ( pObj->GetType() == OBJ_SHIELDWALL ) |
|
{ |
|
if ( vPos.DistTo( pObj->GetAbsOrigin() ) < OBJECT_COVERED_DIST ) |
|
++count; |
|
} |
|
} |
|
|
|
return count; |
|
} |
|
|
|
|
|
int CTFTeam::GetNumResuppliesCoveringPosition( const Vector &vPos ) |
|
{ |
|
int count = 0; |
|
|
|
for ( int i=0; i < m_aResupplyBeacons.Count(); i++ ) |
|
{ |
|
CBaseObject *pObj = m_aResupplyBeacons[i]; |
|
if ( vPos.DistTo( pObj->GetAbsOrigin() ) < RESUPPLY_COVER_DIST ) |
|
++count; |
|
} |
|
|
|
return count; |
|
} |
|
|
|
|
|
int CTFTeam::GetNumRespawnStationsCoveringPosition( const Vector &vPos ) |
|
{ |
|
int count = 0; |
|
|
|
for ( int i=0; i < m_aObjects.Count(); i++ ) |
|
{ |
|
CBaseObject *pObj = m_aObjects[i]; |
|
|
|
if ( pObj->GetType() == OBJ_RESPAWN_STATION ) |
|
{ |
|
if ( vPos.DistTo( pObj->GetAbsOrigin() ) < OBJECT_COVERED_DIST ) |
|
{ |
|
++count; |
|
} |
|
} |
|
} |
|
|
|
return count; |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------------------------------------------------ |
|
// OBJECTS |
|
//----------------------------------------------------------------------------- |
|
// Purpose: Add the specified object to this team. |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::AddObject( CBaseObject *pObject ) |
|
{ |
|
TRACE_OBJECT( UTIL_VarArgs( "%0.2f CTFTeam::AddObject adding object %p:%s to team %s\n", gpGlobals->curtime, |
|
pObject, pObject->GetClassname(), GetName() ) ); |
|
|
|
bool alreadyInList = IsObjectOnTeam( pObject ); |
|
Assert( !alreadyInList ); |
|
if ( !alreadyInList ) |
|
{ |
|
m_aObjects.AddToTail( pObject ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns true if the object is in the team's list of objects |
|
//----------------------------------------------------------------------------- |
|
bool CTFTeam::IsObjectOnTeam( CBaseObject *pObject ) const |
|
{ |
|
return ( m_aObjects.Find( pObject ) != -1 ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Remove this object from the team |
|
// Removes all references from all sublists as well |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::RemoveObject( CBaseObject *pObject ) |
|
{ |
|
if ( m_aObjects.Count() <= 0 ) |
|
return; |
|
|
|
if ( m_aObjects.Find( pObject ) != -1 ) |
|
{ |
|
TRACE_OBJECT( UTIL_VarArgs( "%0.2f CTFTeam::RemoveObject removing %p:%s from %s\n", gpGlobals->curtime, |
|
pObject, pObject->GetClassname(), GetName() ) ); |
|
|
|
m_aObjects.FindAndRemove( pObject ); |
|
} |
|
else |
|
{ |
|
TRACE_OBJECT( UTIL_VarArgs( "%0.2f CTFTeam::RemoveObject couldn't remove %p:%s from %s\n", gpGlobals->curtime, |
|
pObject, pObject->GetClassname(), GetName() ) ); |
|
} |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------------------------------------------------ |
|
// ORDERS |
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::InitializeOrders( void ) |
|
{ |
|
m_flPersonalOrderUpdateTime = 0; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Add a new order to our list. If it already exists, bump it's priority to the new priority. |
|
//----------------------------------------------------------------------------- |
|
COrder* CTFTeam::AddOrder( |
|
int iOrderType, |
|
CBaseEntity *pTarget, |
|
CBaseTFPlayer *pPlayer, |
|
float flDistanceToRemove, |
|
float flLifetime, |
|
COrder *pNewOrder |
|
) |
|
{ |
|
// Remove any orders to the player. |
|
RemoveOrdersToPlayer( pPlayer ); |
|
|
|
// The new system requires order class to be passed in. |
|
Assert( pNewOrder ); |
|
|
|
// All the order create functions should just use new to create the order class, |
|
// then we'll attach the edict in here. There's no reason to use LINK_ENTITY_TO_CLASS |
|
// and CreateEntityByName. |
|
Assert( !pNewOrder->edict() ); |
|
pNewOrder->NetworkProp()->AttachEdict(); |
|
|
|
pNewOrder->ChangeTeam( GetTeamNumber() ); |
|
OrderHandle hOrder; |
|
hOrder = pNewOrder; |
|
m_aOrders.AddToTail( hOrder ); |
|
|
|
// Update target |
|
pNewOrder->SetTarget( pTarget ); |
|
pNewOrder->SetDistance( flDistanceToRemove ); |
|
|
|
// Update lifetime. |
|
pNewOrder->SetLifetime( flLifetime ); |
|
|
|
Assert( pPlayer->GetOrder() == NULL ); |
|
|
|
pNewOrder->SetOwner( pPlayer ); |
|
pPlayer->SetOrder( pNewOrder ); |
|
|
|
// "New Order Received!" |
|
CSingleUserRecipientFilter filter( pPlayer ); |
|
filter.MakeReliable(); |
|
CBaseEntity::EmitSound( filter, pPlayer->entindex(),"TFTeam.AddOrder" ); |
|
|
|
// Debug check.. it should never create an order with its termination conditions |
|
// already met. |
|
Assert( !pNewOrder->Update() ); |
|
|
|
return pNewOrder; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::RemoveOrder( COrder *pOrder ) |
|
{ |
|
OrderHandle hOrder; |
|
hOrder = pOrder; |
|
|
|
m_aOrders.FindAndRemove( hOrder ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Recalculate the team's orders & their priorities |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::RecalcOrders( void ) |
|
{ |
|
// Update all existing orders |
|
UpdateOrders(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::UpdateOrders( void ) |
|
{ |
|
// Tell all our current orders to update themselves. Walk backwards because we may remove them. |
|
int iSize = m_aOrders.Count(); |
|
for (int i = iSize-1; i >= 0; i--) |
|
{ |
|
// Orders without owners should be removed |
|
bool bShouldRemove = ( |
|
!m_aOrders[i] || |
|
!m_aOrders[i]->GetOwner() || |
|
m_aOrders[i]->Update() ); |
|
if ( bShouldRemove ) |
|
{ |
|
COrder *pOrder = m_aOrders[i]; |
|
m_aOrders.Remove( i ); |
|
UTIL_Remove( pOrder ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: An event has just occurred that affects orders. Tell all our orders that |
|
// have the specified entity as a target. |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::UpdateOrdersOnEvent( COrderEvent_Base *pOrder ) |
|
{ |
|
// Tell all our current orders to update themselves. Walk backwards because we may remove them. |
|
int iSize = m_aOrders.Count(); |
|
for (int i = iSize-1; i >= 0; i--) |
|
{ |
|
bool bShouldRemove = m_aOrders[i]->UpdateOnEvent( pOrder ); |
|
if ( bShouldRemove ) |
|
{ |
|
COrder *pOrder = m_aOrders[i]; |
|
m_aOrders.Remove( i ); |
|
UTIL_Remove( pOrder ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Create personal orders for all the team's members |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::CreatePersonalOrders( void ) |
|
{ |
|
// Create personal orders for each player |
|
for ( int i = 0; i < m_aPlayers.Count(); i++ ) |
|
{ |
|
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)m_aPlayers[i]; |
|
|
|
// Don't create orders for bots, undefined or dead people |
|
if ( !(pPlayer->GetFlags() & FL_FAKECLIENT) && pPlayer->IsAlive() && !pPlayer->IsClass( TFCLASS_UNDECIDED ) ) |
|
{ |
|
CreatePersonalOrder( pPlayer ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Create personal orders for specified player |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::CreatePersonalOrder( CBaseTFPlayer *pPlayer ) |
|
{ |
|
// We still haven't made a personal order, so ask the class if it wants to |
|
if ( pPlayer->GetPlayerClass() ) |
|
{ |
|
pPlayer->GetPlayerClass()->CreatePersonalOrder(); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::RemoveOrdersToPlayer( CBaseTFPlayer *pPlayer ) |
|
{ |
|
// Walk backwards because we're removing them. |
|
int iSize = m_aOrders.Count(); |
|
for (int i = iSize-1; i >= 0; i--) |
|
{ |
|
// Orders without owners should be removed |
|
if ( m_aOrders[i].Get() ) |
|
{ |
|
if( m_aOrders[i]->GetOwner() == pPlayer ) |
|
{ |
|
COrder *pOrder = m_aOrders[i]; |
|
m_aOrders.Remove( i ); |
|
|
|
pOrder->DetachFromPlayer(); |
|
UTIL_Remove( pOrder ); |
|
} |
|
} |
|
else |
|
{ |
|
m_aOrders.Remove( i ); |
|
} |
|
} |
|
|
|
pPlayer->SetOrder( NULL ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Count and return the number of orders of the type with the specified target |
|
//----------------------------------------------------------------------------- |
|
int CTFTeam::CountOrders( int flags, int iOrderType, CBaseEntity *pTarget, CBaseTFPlayer *pOwner ) |
|
{ |
|
int iOrderCount = 0; |
|
|
|
// Count the number of global orders |
|
for ( int i = 0; i < m_aOrders.Count(); i++ ) |
|
{ |
|
COrder *pOrder = m_aOrders[i]; |
|
|
|
if( flags & COUNTORDERS_TYPE ) |
|
if( pOrder->GetType() != iOrderType ) |
|
continue; |
|
|
|
if( flags & COUNTORDERS_TARGET ) |
|
if( pOrder->GetTargetEntity() != pTarget ) |
|
continue; |
|
|
|
if( flags & COUNTORDERS_OWNER ) |
|
if( pOrder->GetOwner() != pOwner ) |
|
continue; |
|
|
|
// Ok, this order matches the criteria. |
|
iOrderCount++; |
|
} |
|
|
|
return iOrderCount; |
|
} |
|
|
|
|
|
int CTFTeam::CountOrdersOwnedByPlayer( CBaseTFPlayer *pPlayer ) |
|
{ |
|
return CountOrders( COUNTORDERS_OWNER, 0, 0, pPlayer ); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------------------------------------------------ |
|
// MESSAGES |
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::ClearMessages( void ) |
|
{ |
|
int iSize = m_aMessages.Count(); |
|
for (int i = iSize-1; i >= 0; i--) |
|
{ |
|
CTeamMessage *pMessage = m_aMessages[i]; |
|
m_aMessages.Remove( i ); |
|
delete pMessage; |
|
} |
|
|
|
m_aMessages.Purge(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Post a message of the specified type |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::PostMessage( int iMessageID, CBaseEntity *pEntity, char *sData ) |
|
{ |
|
// First see if we've got this message in the queue already |
|
for ( int i = 0; i < m_aMessages.Count(); i++ ) |
|
{ |
|
CTeamMessage *pMessage = m_aMessages[i]; |
|
if ( (pMessage->GetID() == iMessageID) && (pMessage->GetEntity() == pEntity) ) |
|
{ |
|
// Already in the queue, abort. |
|
return; |
|
} |
|
} |
|
|
|
// Create a new message and add it to my tail |
|
CTeamMessage *pMessage = CTeamMessage::Create( this, iMessageID, pEntity ); |
|
if ( sData && sData[0] ) |
|
{ |
|
pMessage->SetData( sData ); |
|
} |
|
m_aMessages.AddToTail( pMessage ); |
|
|
|
// Tell the message to fire |
|
pMessage->FireMessage(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::UpdateMessages( void ) |
|
{ |
|
// Go through my messages and kill any that have reached their TTL |
|
int iSize = m_aMessages.Count(); |
|
for (int i = iSize-1; i >= 0; i--) |
|
{ |
|
CTeamMessage *pMessage = m_aMessages[i]; |
|
if ( gpGlobals->curtime > pMessage->GetTTL() ) |
|
{ |
|
m_aMessages.Remove( i ); |
|
delete pMessage; |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Tell all our powerpacks to update their powered objects. |
|
// pPackToIgnore: Pack to ignore, because it's dying. |
|
// pObjectToTarget: An object looking for power, because it's being placed |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::UpdatePowerpacks( CObjectPowerPack *pPackToIgnore, CBaseObject *pObjectToTarget ) |
|
{ |
|
for ( int i = 0; i < GetNumObjects(); i++ ) |
|
{ |
|
CBaseObject *pObject = GetObject(i); |
|
assert(pObject); |
|
if ( pObject == pPackToIgnore || pObject->GetType() != OBJ_POWERPACK ) |
|
continue; |
|
|
|
((CObjectPowerPack*)pObject)->PowerNearbyObjects( pObjectToTarget ); |
|
|
|
// Quit as soon as we've powered the specified one, if there is one |
|
if ( pObjectToTarget && pObjectToTarget->IsPowered() ) |
|
break; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Tell all our buff stations to update and look for objects. |
|
// Input: pBuffStationToIgnore: Buff station to ignore, because it is dying |
|
// pObjectToTarget: an object looking for a buff station, because it is being placed |
|
//----------------------------------------------------------------------------- |
|
void CTFTeam::UpdateBuffStations( CObjectBuffStation *pBuffStationToIgnore, CBaseObject *pObjectToTarget, bool bPlacing ) |
|
{ |
|
for ( int iObject = 0; iObject < GetNumObjects(); ++iObject ) |
|
{ |
|
CBaseObject *pObject = GetObject( iObject ); |
|
assert( pObject ); |
|
|
|
if ( pObject->GetType() != OBJ_BUFF_STATION ) |
|
continue; |
|
|
|
CObjectBuffStation *pBuffStation = static_cast<CObjectBuffStation*>( pObject ); |
|
if ( pBuffStation == pBuffStationToIgnore ) |
|
continue; |
|
|
|
pBuffStation->BuffNearbyObjects( pObjectToTarget, bPlacing ); |
|
|
|
// Quit as soon as we've powered the specified one, if there is one. |
|
if ( pObjectToTarget && pObjectToTarget->IsHookedAndBuffed() ) |
|
break; |
|
} |
|
} |
|
|
|
//------------------------------------------------------------------------------------------------------------------ |
|
// UTILITY FUNCS |
|
//----------------------------------------------------------------------------- |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFTeam* CTFTeam::GetEnemyTeam() |
|
{ |
|
// Look for nearby enemy objects we can capture. |
|
int iMyTeam = GetTeamNumber(); |
|
if( iMyTeam == 0 ) |
|
return NULL; |
|
|
|
int iEnemyTeam = !(iMyTeam - 1) + 1; |
|
return (CTFTeam*)GetGlobalTeam( iEnemyTeam ); |
|
} |
|
|
|
|
|
|