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.
 
 
 
 
 
 

467 lines
11 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: tf_populator_spawners
// Implementations of NPC Spawning Code for PvE related game modes (MvM)
//=============================================================================//
#ifndef TF_POPULATORS_H
#define TF_POPULATORS_H
#include "tf_population_manager.h"
class KeyValues;
class IPopulator;
class IPopulationSpawner;
class CPopulationManager;
class CWave;
class CSpawnLocation;
//-----------------------------------------------------------------------
class CSpawnLocation
{
public:
CSpawnLocation();
bool Parse( KeyValues *data );
bool IsValid( void ) const;
SpawnLocationResult FindSpawnLocation( Vector& vSpawnPosition );
private:
CTFNavArea *SelectSpawnArea( void ) const;
RelativePositionType m_relative;
TFTeamSpawnVector_t m_teamSpawnVector;
int m_nSpawnCount;
int m_nRandomSeed;
bool m_bClosestPointOnNav;
};
inline bool CSpawnLocation::IsValid( void ) const
{
return m_relative != UNDEFINED || m_teamSpawnVector.Count() > 0;
}
//-----------------------------------------------------------------------
// For spawning bots/players at a specific position
class CPopulatorInternalSpawnPoint : public CPointEntity
{
DECLARE_CLASS( CPopulatorInternalSpawnPoint, CPointEntity );
};
extern CHandle< CPopulatorInternalSpawnPoint > g_internalSpawnPoint;
//-----------------------------------------------------------------------
// A Populator manages the populating of entities in the environment.
class IPopulator
{
public:
IPopulator( CPopulationManager *manager )
{
m_manager = manager;
m_spawner = NULL;
}
virtual ~IPopulator()
{
if ( m_spawner )
{
delete m_spawner;
}
m_spawner = NULL;
}
virtual bool Parse( KeyValues *data ) = 0;
virtual void PostInitialize( void ) { } // create initial population at start of scenario
virtual void Update( void ) { } // continuously invoked to modify population over time
virtual void UnpauseSpawning() {}
virtual void OnPlayerKilled( CTFPlayer *corpse ) { }
CPopulationManager *GetManager( void ) const { return m_manager; }
virtual bool HasEventChangeAttributes( const char* pszEventName ) const
{
if ( m_spawner )
{
return m_spawner->HasEventChangeAttributes( pszEventName );
}
return false;
}
IPopulationSpawner *m_spawner;
private:
CPopulationManager *m_manager;
};
//-----------------------------------------------------------------------
// Invokes its spawner when mission conditions are met
class CMissionPopulator : public IPopulator
{
public:
CMissionPopulator( CPopulationManager *manager );
virtual ~CMissionPopulator() { }
virtual bool Parse( KeyValues *data );
virtual void Update( void ); // continuously invoked to modify population over time
virtual void UnpauseSpawning( void );
int BeginAtWave( void ) { return m_beginAtWaveIndex; }
int StopAtWave( void ) { return m_stopAtWaveIndex; }
CTFBot::MissionType GetMissionType( void ){ return m_mission; }
private:
CTFBot::MissionType m_mission;
CSpawnLocation m_where;
bool UpdateMissionDestroySentries( void );
bool UpdateMission( CTFBot::MissionType mission );
enum StateType
{
NOT_STARTED,
INITIAL_COOLDOWN,
RUNNING
};
StateType m_state;
float m_initialCooldown;
float m_cooldownDuration;
CountdownTimer m_cooldownTimer;
CountdownTimer m_checkForDangerousSentriesTimer;
int m_desiredCount;
int m_beginAtWaveIndex; // this mission becomes active at this wave number
int m_stopAtWaveIndex; // stop when this wave becomes active
};
//-----------------------------------------------------------------------
// Invokes its spawner at random positions scattered throughout
// the environment at PostInitialize()
class CRandomPlacementPopulator : public IPopulator
{
public:
CRandomPlacementPopulator( CPopulationManager *manager );
virtual ~CRandomPlacementPopulator() { }
virtual bool Parse( KeyValues *data );
virtual void PostInitialize( void ); // create initial population at start of scenario
int m_count;
float m_minSeparation;
unsigned int m_navAreaFilter;
};
//-----------------------------------------------------------------------
// Invokes its spawner periodically
class CPeriodicSpawnPopulator : public IPopulator
{
public:
CPeriodicSpawnPopulator( CPopulationManager *manager );
virtual ~CPeriodicSpawnPopulator() { }
virtual bool Parse( KeyValues *data );
virtual void PostInitialize( void ); // create initial population at start of scenario
virtual void Update( void ); // continuously invoked to modify population over time
virtual void UnpauseSpawning( void );
CSpawnLocation m_where;
float m_minInterval;
float m_maxInterval;
private:
CountdownTimer m_timer;
};
//-----------------------------------------------------------------------
// Spawns a group of entities within a Wave
class CWaveSpawnPopulator : public IPopulator
{
public:
CWaveSpawnPopulator( CPopulationManager *manager );
virtual ~CWaveSpawnPopulator();
virtual bool Parse( KeyValues *data );
virtual void Update( void ); // continuously invoked to modify population over time
virtual void OnPlayerKilled( CTFPlayer *corpse );
CSpawnLocation m_where;
int m_totalCount;
int m_remainingCount;
int m_nClassCounts;
int m_maxActive; // the maximum number of entities active at one time
int m_spawnCount; // the number of entities to spawn at once
float m_waitBeforeStarting;
float m_waitBetweenSpawns; // between spawns of mobs
bool m_bWaitBetweenSpawnAfterDeath;
CFmtStr m_startWaveWarningSound;
EventInfo *m_startWaveOutput;
CFmtStr m_firstSpawnWarningSound;
EventInfo *m_firstSpawnOutput;
CFmtStr m_lastSpawnWarningSound;
EventInfo *m_lastSpawnOutput;
CFmtStr m_doneWarningSound;
EventInfo *m_doneOutput;
int m_totalCurrency;
int m_unallocatedCurrency;
CUtlString m_name;
CUtlString m_waitForAllSpawned;
CUtlString m_waitForAllDead;
bool IsDone( void ) const
{
return m_state == DONE;
}
bool IsDoneSpawningBots( void ) const
{
return m_state > SPAWNING;
}
// Invoked by td_setnextwave to finish off a wave
void ForceFinish( void );
void ForceReset( void )
{
m_unallocatedCurrency = m_totalCurrency;
m_remainingCount = m_totalCount;
m_state = PENDING;
}
bool IsSupportWave( void ) const { return m_bSupportWave; }
bool IsLimitedSupportWave( void ) const { return m_bLimitedSupport; }
void SetParent( CWave *pParent ) { m_pParent = pParent; }
int GetCurrencyAmountPerDeath( void );
void OnNonSupportWavesDone( void );
private:
bool IsFinishedSpawning( void );
CountdownTimer m_timer;
EntityHandleVector_t m_activeVector;
int m_countSpawnedSoFar;
int m_myReservedSlotCount;
bool m_bSupportWave;
bool m_bLimitedSupport;
CWave *m_pParent;
enum InternalStateType
{
PENDING,
PRE_SPAWN_DELAY,
SPAWNING,
WAIT_FOR_ALL_DEAD,
DONE
};
InternalStateType m_state;
void SetState( InternalStateType eState );
int ReservePlayerSlots( int count ); // reserve 'count' player slots so other WaveSpawns don't take them
void ReleasePlayerSlots( int count ); // release 'count' player slots that have been previously reserved
static int m_reservedPlayerSlotCount;
bool m_bRandomSpawn;
SpawnLocationResult m_spawnLocationResult;
Vector m_vSpawnPosition;
};
struct WaveClassCount_t
{
int nClassCount;
string_t iszClassIconName;
unsigned int iFlags;
};
//-----------------------------------------------------------------------
// Spawns sequential "waves" of entities over time.
// A wave consists of one or more WaveSpawns that all run concurrently.
// The wave is done when all contained WaveSpawns are done.
class CWave : public IPopulator
{
public:
CWave( CPopulationManager *manager );
virtual ~CWave();
virtual bool Parse( KeyValues *data );
virtual void Update( void );
virtual void OnPlayerKilled( CTFPlayer *corpse );
virtual bool HasEventChangeAttributes( const char* pszEventName ) const OVERRIDE;
void ForceFinish(); // used when forcing a wave to finish
void ForceReset(); // used when forcing a wave to start
CWaveSpawnPopulator *FindWaveSpawnPopulator( const char *name ); // find a CWaveSpawnPopulator by name
void AddClassType( string_t iszClassIconName, int nCount, unsigned int iFlags );
int GetNumClassTypes( void ) const { return m_nWaveClassCounts.Count(); }
void StartUpgradesAlertTimer ( float flTime ) { m_GetUpgradesAlertTimer.Start( flTime ); }
void SetStartTime (float flTime) { m_flStartTime = flTime; }
// inline
bool IsCheckpoint( void ) const;
CWave *GetNextWave( void ) const;
void SetNextWave( CWave *wave );
const char *GetDescription( void ) const;
int GetTotalCurrency( void ) const;
int GetEnemyCount( void ) const;
int GetClassCount( int nIndex ) const;
string_t GetClassIconName( int nIndex ) const;
unsigned int GetClassFlags( int nIndex ) const;
int NumTanksSpawned( void ) const;
void IncrementTanksSpawned( void );
int NumSentryBustersSpawned( void ) const;
void IncrementSentryBustersSpawned( void );
int NumSentryBustersKilled( void ) const;
void IncrementSentryBustersKilled( void );
void ResetSentryBustersKilled( void );
int NumEngineersTeleportSpawned( void ) const;
void IncrementEngineerTeleportSpawned( void );
private:
bool IsDoneWithNonSupportWaves( void );
void ActiveWaveUpdate();
void WaveCompleteUpdate();
void WaveIntermissionUpdate();
CUtlVector< CWaveSpawnPopulator * > m_waveSpawnVector;
bool m_isStarted;
bool m_bFiredInitWaveOutput;
int m_iEnemyCount;
int m_nTanksSpawned;
int m_nSentryBustersSpawned;
int m_nNumEngineersTeleportSpawned;
int m_nNumSentryBustersKilled;
CUtlVector< WaveClassCount_t > m_nWaveClassCounts;
int m_totalCurrency;
EventInfo *m_startOutput;
EventInfo *m_doneOutput;
EventInfo *m_initOutput;
CFmtStr m_description;
CFmtStr m_soundName;
float m_waitWhenDone;
CountdownTimer m_doneTimer;
bool m_bCheckBonusCreditsMin;
bool m_bCheckBonusCreditsMax;
float m_flBonusCreditsTime;
bool m_bPlayedUpgradeAlert;
CountdownTimer m_GetUpgradesAlertTimer;
bool m_isEveryContainedWaveSpawnDone;
float m_flStartTime;
};
inline const char *CWave::GetDescription( void ) const
{
return m_description;
}
inline int CWave::GetTotalCurrency( void ) const
{
return m_totalCurrency;
}
inline int CWave::GetEnemyCount( void ) const
{
return m_iEnemyCount;
}
inline int CWave::GetClassCount( int nIndex ) const
{
return m_nWaveClassCounts[ nIndex ].nClassCount;
}
inline string_t CWave::GetClassIconName( int nIndex ) const
{
return m_nWaveClassCounts[ nIndex ].iszClassIconName;
}
inline unsigned int CWave::GetClassFlags( int nIndex ) const
{
return m_nWaveClassCounts[ nIndex ].iFlags;
}
inline int CWave::NumTanksSpawned( void ) const
{
return m_nTanksSpawned;
}
inline void CWave::IncrementTanksSpawned( void )
{
m_nTanksSpawned++;
}
inline int CWave::NumSentryBustersSpawned( void ) const
{
return m_nSentryBustersSpawned;
}
inline void CWave::IncrementSentryBustersSpawned( void )
{
m_nSentryBustersSpawned++;
}
inline int CWave::NumSentryBustersKilled( void ) const
{
return m_nNumSentryBustersKilled;
}
inline void CWave::IncrementSentryBustersKilled( void )
{
m_nNumSentryBustersKilled++;
}
inline void CWave::ResetSentryBustersKilled( void )
{
m_nNumSentryBustersKilled = 0;
}
inline int CWave::NumEngineersTeleportSpawned( void ) const
{
return m_nNumEngineersTeleportSpawned;
}
inline void CWave::IncrementEngineerTeleportSpawned( void )
{
m_nNumEngineersTeleportSpawned++;
}
#endif // TF_POPULATORS_H