source-engine/game/shared/swarm/asw_holdout_mode.cpp
2023-10-03 17:23:56 +03:00

754 lines
22 KiB
C++

#include "cbase.h"
#include "asw_shareddefs.h"
#include "asw_holdout_mode.h"
#include "asw_holdout_wave.h"
#include "filesystem.h"
#ifdef GAME_DLL
#include "asw_spawn_manager.h"
#include "asw_spawn_group.h"
#include "asw_game_resource.h"
#include "asw_marine_resource.h"
#include "asw_marine.h"
#include "asw_weapon.h"
#include "asw_gamerules.h"
#include "asw_equipment_list.h"
#include "asw_alien.h"
#include "asw_buzzer.h"
#include "entityinput.h"
#include "entityoutput.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
IMPLEMENT_NETWORKCLASS_ALIASED( ASW_Holdout_Mode, DT_ASW_Holdout_Mode )
ConVar asw_holdout_debug( "asw_holdout_debug", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "Show debug text for holdout mode" );
BEGIN_NETWORK_TABLE( CASW_Holdout_Mode, DT_ASW_Holdout_Mode )
#ifdef CLIENT_DLL
RecvPropInt( RECVINFO( m_nCurrentWave ) ),
RecvPropInt( RECVINFO( m_nCurrentScore ) ),
RecvPropInt( RECVINFO( m_nAliensKilledThisWave ) ),
RecvPropTime( RECVINFO( m_flCurrentWaveStartTime ) ),
RecvPropTime( RECVINFO( m_flResupplyEndTime ) ),
RecvPropString( RECVINFO( m_netHoldoutFilename ) ),
#else
SendPropInt( SENDINFO( m_nCurrentWave ) ),
SendPropInt( SENDINFO( m_nCurrentScore ) ),
SendPropInt( SENDINFO( m_nAliensKilledThisWave ) ),
SendPropTime( SENDINFO( m_flCurrentWaveStartTime ) ),
SendPropTime( SENDINFO( m_flResupplyEndTime ) ),
SendPropString( SENDINFO( m_netHoldoutFilename ) ),
#endif
END_NETWORK_TABLE()
#ifdef GAME_DLL
LINK_ENTITY_TO_CLASS( asw_holdout_mode, CASW_Holdout_Mode );
BEGIN_DATADESC( CASW_Holdout_Mode )
DEFINE_KEYFIELD( m_holdoutFilename, FIELD_STRING, "filename" ),
DEFINE_THINKFUNC( HoldoutThink ),
DEFINE_OUTPUT(m_OnWave[0], "OnWave01"),
DEFINE_OUTPUT(m_OnWave[1], "OnWave02"),
DEFINE_OUTPUT(m_OnWave[2], "OnWave03"),
DEFINE_OUTPUT(m_OnWave[3], "OnWave04"),
DEFINE_OUTPUT(m_OnWave[4], "OnWave05"),
DEFINE_OUTPUT(m_OnWave[5], "OnWave06"),
DEFINE_OUTPUT(m_OnWave[6], "OnWave07"),
DEFINE_OUTPUT(m_OnWave[7], "OnWave08"),
DEFINE_OUTPUT(m_OnWave[8], "OnWave09"),
DEFINE_OUTPUT(m_OnWave[9], "OnWave10"),
DEFINE_OUTPUT(m_OnAnnounceWave[0], "OnAnnounceWave01"),
DEFINE_OUTPUT(m_OnAnnounceWave[1], "OnAnnounceWave02"),
DEFINE_OUTPUT(m_OnAnnounceWave[2], "OnAnnounceWave03"),
DEFINE_OUTPUT(m_OnAnnounceWave[3], "OnAnnounceWave04"),
DEFINE_OUTPUT(m_OnAnnounceWave[4], "OnAnnounceWave05"),
DEFINE_OUTPUT(m_OnAnnounceWave[5], "OnAnnounceWave06"),
DEFINE_OUTPUT(m_OnAnnounceWave[6], "OnAnnounceWave07"),
DEFINE_OUTPUT(m_OnAnnounceWave[7], "OnAnnounceWave08"),
DEFINE_OUTPUT(m_OnAnnounceWave[8], "OnAnnounceWave09"),
DEFINE_OUTPUT(m_OnAnnounceWave[9], "OnAnnounceWave10"),
DEFINE_OUTPUT(m_OnWaveDefault, "OnWaveDefault"),
DEFINE_OUTPUT(m_OnAnnounceWaveDefault, "OnAnnounceWaveDefault"),
DEFINE_INPUTFUNC( FIELD_VOID, "UnlockResupply", InputUnlockResupply ),
END_DATADESC()
#endif
const char *HoldoutEventTypeAsString( ASW_Holdout_Event_t nEventType )
{
switch( nEventType )
{
case HOLDOUT_EVENT_START_WAVE_ENTRY: return "HOLDOUT_EVENT_START_WAVE_ENTRY";
case HOLDOUT_EVENT_SINGLE_SPAWN: return "HOLDOUT_EVENT_SINGLE_SPAWN";
case HOLDOUT_EVENT_STATE_CHANGE: return "HOLDOUT_EVENT_STATE_CHANGE";
}
return "Unknown";
}
const char *HoldoutStateAsString( ASW_Holdout_State_t nState )
{
switch( nState )
{
case HOLDOUT_STATE_BRIEFING: return "HOLDOUT_STATE_BRIEFING";
case HOLDOUT_STATE_ANNOUNCE_NEW_WAVE: return "HOLDOUT_STATE_ANNOUNCE_NEW_WAVE";
case HOLDOUT_STATE_WAVE_IN_PROGRESS: return "HOLDOUT_STATE_WAVE_IN_PROGRESS";
case HOLDOUT_STATE_SHOWING_WAVE_SCORE: return "HOLDOUT_STATE_SHOWING_WAVE_SCORE";
case HOLDOUT_STATE_RESUPPLY: return "HOLDOUT_STATE_RESUPPLY";
}
return "Unknown";
}
CASW_Holdout_Mode *g_pHoldoutMode = NULL;
CASW_Holdout_Mode* ASWHoldoutMode() { return g_pHoldoutMode; }
CASW_Holdout_Mode::CASW_Holdout_Mode()
{
Assert( !g_pHoldoutMode );
g_pHoldoutMode = this;
m_nCurrentWave = -1;
m_nCurrentScore = 0;
#ifdef GAME_DLL
m_holdoutFilename = NULL_STRING;
m_nUnlockedResupply = 0;
m_bResurrectingMarines = false;
#endif
m_netHoldoutFilename.GetForModify()[0] = 0;
}
CASW_Holdout_Mode::~CASW_Holdout_Mode()
{
m_Waves.PurgeAndDeleteElements();
Assert( g_pHoldoutMode == this );
g_pHoldoutMode = NULL;
}
#ifdef GAME_DLL
void CASW_Holdout_Mode::Spawn()
{
Precache();
BaseClass::Spawn();
}
void CASW_Holdout_Mode::Activate( void )
{
BaseClass::Activate();
Q_strncpy( m_netHoldoutFilename.GetForModify(), STRING( m_holdoutFilename ), MAX_PATH );
}
void CASW_Holdout_Mode::Precache()
{
BaseClass::Precache();
Assert( ASWSpawnManager() );
int nCount = ASWSpawnManager()->GetNumAlienClasses();
for ( int i = 0; i < nCount; i++ )
{
UTIL_PrecacheOther( ASWSpawnManager()->GetAlienClass(i)->m_pszAlienClass );
}
}
void CASW_Holdout_Mode::InputUnlockResupply( inputdata_t &inputdata )
{
m_nUnlockedResupply += 1;
hudtextparms_s tTextParam;
tTextParam.x = -1;
tTextParam.y = 0.25;
tTextParam.effect = 0;
tTextParam.r1 = 255;
tTextParam.g1 = 170;
tTextParam.b1 = 0;
tTextParam.a1 = 255;
tTextParam.r2 = 255;
tTextParam.g2 = 170;
tTextParam.b2 = 0;
tTextParam.a2 = 255;
tTextParam.fadeinTime = 0.1;
tTextParam.fadeoutTime = 0.5;
tTextParam.holdTime = 5.0;
tTextParam.fxTime = 0;
tTextParam.channel = 1;
if ( m_nHoldoutState == HOLDOUT_STATE_WAVE_IN_PROGRESS )
{
UTIL_HudMessageAll( tTextParam, "Resupply unlocked!\nYou will resupply at the end of THIS round\n" );
}
else
{
UTIL_HudMessageAll( tTextParam, "Resupply unlocked!\nYou will resupply at the end of NEXT round\n" );
}
}
void CASW_Holdout_Mode::HoldoutThink()
{
if ( asw_holdout_debug.GetBool() )
{
engine->Con_NPrintf( 1, "Holdout events:" );
for ( int i = 0; i < m_Events.Count(); i++ )
{
CASW_Holdout_Event *pEvent = m_Events[ i ];
if ( pEvent->m_EventType == HOLDOUT_EVENT_START_WAVE_ENTRY || pEvent->m_EventType == HOLDOUT_EVENT_SINGLE_SPAWN )
{
CASW_Holdout_Spawn_Event *pSpawnEvent = static_cast<CASW_Holdout_Spawn_Event*>( pEvent );
engine->Con_NPrintf( i + 1, "%f:%s %d x %s over %f group=%s",
gpGlobals->curtime - pEvent->m_flEventTime,
HoldoutEventTypeAsString( pEvent->m_EventType ),
pSpawnEvent->m_pWaveEntry->GetQuantity(),
STRING( pSpawnEvent->m_pWaveEntry->GetAlienClass() ),
pSpawnEvent->m_pWaveEntry->GetSpawnDuration(),
pSpawnEvent->m_pWaveEntry->GetSpawnGroupName()
);
}
else if ( pEvent->m_EventType == HOLDOUT_EVENT_STATE_CHANGE )
{
CASW_Holdout_State_Change_Event *pStateEvent = static_cast<CASW_Holdout_State_Change_Event*>( pEvent );
engine->Con_NPrintf( i + 1, "%f:%s to %d",
gpGlobals->curtime - pEvent->m_flEventTime,
HoldoutEventTypeAsString( pEvent->m_EventType ),
HoldoutStateAsString( pStateEvent->m_NewState )
);
}
else
{
engine->Con_NPrintf( i + 1, "%f:%s",
gpGlobals->curtime - pEvent->m_flEventTime,
HoldoutEventTypeAsString( pEvent->m_EventType )
);
}
}
engine->Con_NPrintf( m_Events.Count() + 2, " " );
}
// see if any events need to be processed
while ( m_Events.Count() > 0 )
{
CASW_Holdout_Event *pEvent = m_Events[ 0 ];
if ( pEvent->m_flEventTime > gpGlobals->curtime )
break;
m_Events.Remove( 0 );
ProcessEvent( pEvent );
}
SetThink( &CASW_Holdout_Mode::HoldoutThink );
if ( m_bResurrectingMarines )
{
ResurrectDeadMarines();
SetNextThink( gpGlobals->curtime + 0.25f );
}
else if ( m_Events.Count() <= 0 )
{
SetNextThink( gpGlobals->curtime + 1.0f );
}
else
{
SetNextThink( MIN( gpGlobals->curtime + 1.0f, m_Events[ 0 ]->m_flEventTime ) );
}
}
void CASW_Holdout_Mode::ProcessEvent( CASW_Holdout_Event *pEvent )
{
switch( pEvent->m_EventType )
{
case HOLDOUT_EVENT_START_WAVE_ENTRY: // start spawning aliens from a wave entry
{
// find the wave entry and spawngroup
CASW_Holdout_Spawn_Event *pSpawnEvent = static_cast<CASW_Holdout_Spawn_Event*>( pEvent );
CASW_Holdout_Wave_Entry *pEntry = pSpawnEvent->m_pWaveEntry;
CASW_Spawn_Group *pSpawnGroup = pEntry->GetSpawnGroup();
if ( !pSpawnGroup )
{
delete pEvent;
return;
}
// spawn any aliens that need to be spawned right now
int nToSpawnNow = ( pEntry->GetSpawnDuration() <= 0.0f ) ? pEntry->GetQuantity() : MIN( 1, pEntry->GetQuantity() );
SpawnAliens( nToSpawnNow, pEntry, pSpawnGroup );
// for spawns spread over a duration, add a single spawn event for each
int nToSpawnLater = pEntry->GetQuantity() - nToSpawnNow;
float flInterval = pEntry->GetSpawnDuration() / (float) nToSpawnLater;
for ( int i = 0; i < nToSpawnLater; i++ )
{
if ( asw_holdout_debug.GetBool() )
{
Msg( "Adding a single spawn from HOLDOUT_EVENT_START_WAVE_ENTRY as %d want to spawn over time\n", nToSpawnLater );
}
CASW_Holdout_Spawn_Event *pSingleSpawn = new CASW_Holdout_Spawn_Event;
pSingleSpawn->m_pWaveEntry = pEntry;
pSingleSpawn->m_EventType = HOLDOUT_EVENT_SINGLE_SPAWN;
pSingleSpawn->m_flEventTime = pEvent->m_flEventTime + flInterval * ( i + 1 );
AddEvent( pSingleSpawn );
}
}
break;
case HOLDOUT_EVENT_SINGLE_SPAWN: // single spawn from an entry that spawns its quantity over a duration
{
// find the wave entry and spawngroup
CASW_Holdout_Spawn_Event *pSpawnEvent = static_cast<CASW_Holdout_Spawn_Event*>( pEvent );
CASW_Holdout_Wave_Entry *pEntry = pSpawnEvent->m_pWaveEntry;
CASW_Spawn_Group *pSpawnGroup = pEntry->GetSpawnGroup();
if ( !pSpawnGroup )
{
delete pEvent;
return;
}
SpawnAliens( 1, pEntry, pSpawnGroup );
}
break;
case HOLDOUT_EVENT_STATE_CHANGE:
{
CASW_Holdout_State_Change_Event *pStateChangeEvent = static_cast<CASW_Holdout_State_Change_Event*>( pEvent );
ChangeHoldoutState( pStateChangeEvent->m_NewState );
}
break;
}
delete pEvent;
}
void CASW_Holdout_Mode::StartWave( int nWave )
{
m_Events.PurgeAndDeleteElements();
m_bResurrectingMarines = false;
if ( nWave < 0 || nWave >= m_Waves.Count() )
{
Warning( "StartWave called with wave out of range: %d\n", nWave );
return;
}
m_nCurrentWave = nWave;
m_nAliensKilledThisWave = 0;
m_flCurrentWaveStartTime = gpGlobals->curtime;
// add events to spawn each entry in this wave
CASW_Holdout_Wave *pWave = m_Waves[ m_nCurrentWave ];
for ( int i = 0; i < pWave->GetNumEntries(); i++ )
{
if ( asw_holdout_debug.GetBool() )
{
Msg( "Adding a spawn entry from StartWave. Entry %d\n", i );
}
CASW_Holdout_Spawn_Event *pEvent = new CASW_Holdout_Spawn_Event;
pEvent->m_pWaveEntry = pWave->GetEntry( i );
pEvent->m_EventType = HOLDOUT_EVENT_START_WAVE_ENTRY;
pEvent->m_flEventTime = m_flCurrentWaveStartTime + pEvent->m_pWaveEntry->GetSpawnDelay();
AddEvent( pEvent );
}
if ( m_nCurrentWave < MAX_HOLDOUT_WAVES )
{
m_OnWave[m_nCurrentWave].FireOutput( this, this );
}
m_OnWaveDefault.FireOutput( this, this );
}
void CASW_Holdout_Mode::AddEvent( CASW_Holdout_Event *pEvent )
{
m_Events.Insert( pEvent );
if ( pEvent->m_flEventTime < GetNextThink() )
{
SetNextThink( pEvent->m_flEventTime );
}
}
int CASW_Holdout_Mode::SpawnAliens( int nQuantity, CASW_Holdout_Wave_Entry *pEntry, CASW_Spawn_Group *pSpawnGroup )
{
Assert( ASWSpawnManager() );
// pick N spawners from the spawngroup
CUtlVector< CASW_Base_Spawner* > spawners;
pSpawnGroup->PickSpawnersRandomly( nQuantity, false, &spawners );
const char *szAlienClass = STRING( pEntry->GetAlienClass() );
int nSpawned = 0;
Vector vecHullMins, vecHullMaxs;
ASWSpawnManager()->GetAlienBounds( pEntry->GetAlienClass(), vecHullMins, vecHullMaxs );
// tell each spawner to spawn an alien of our class
for ( int i = 0; i < spawners.Count(); i++ )
{
IASW_Spawnable_NPC* pAlien = spawners[i]->SpawnAlien( szAlienClass, vecHullMins, vecHullMaxs );
if ( pAlien )
{
pAlien->SetHoldoutAlien();
nSpawned++;
}
}
// for each failure, add an event to try again
// TODO: keep track of failure count, so we give up eventually with a warning?
for ( int i = 0; i < ( nQuantity - nSpawned ); i++ )
{
if ( asw_holdout_debug.GetBool() )
{
Msg( "Adding a spawn entry from SpawnAliens. As some aliens failed to spawn %d/%d\n", i, ( nQuantity - nSpawned ) );
}
CASW_Holdout_Spawn_Event *pSingleSpawn = new CASW_Holdout_Spawn_Event;
pSingleSpawn->m_pWaveEntry = pEntry;
pSingleSpawn->m_EventType = HOLDOUT_EVENT_SINGLE_SPAWN;
pSingleSpawn->m_flEventTime = gpGlobals->curtime + 1.0f + 0.1f * i;
AddEvent( pSingleSpawn );
}
return nSpawned;
}
ConVar asw_holdout_announce_time( "asw_holdout_announce_time", "5.0f", FCVAR_CHEAT, "How many seconds between announcing a wave and actually starting a wave.");
ConVar asw_holdout_wave_score_time( "asw_holdout_wave_score_time", "5.0f", FCVAR_CHEAT, "How many seconds to show the end wave scores for.");
ConVar asw_holdout_resupply_time( "asw_holdout_resupply_time", "20.0f", FCVAR_CHEAT, "How many seconds marines have to pick new weapons in the resupply stage.");
void CASW_Holdout_Mode::ChangeHoldoutState( ASW_Holdout_State_t nNewState )
{
if ( asw_holdout_debug.GetBool() )
{
Msg( "%f: ChangeHoldoutState %s\n", gpGlobals->curtime, HoldoutStateAsString( nNewState ) );
}
//ASW_Holdout_State_t nOldState = GetHoldoutState();
m_nHoldoutState = (int) nNewState;
// States with a fixed duration schedule another state change here
switch( nNewState )
{
case HOLDOUT_STATE_ANNOUNCE_NEW_WAVE:
{
// advance to the next wave
SetCurrentWave( GetCurrentWave() + 1 );
m_bResurrectingMarines = false;
// send a message to all clients telling them to show the wave announce animation
CRecipientFilter filter;
filter.AddAllPlayers();
UserMessageBegin( filter, "ASWNewHoldoutWave" );
WRITE_BYTE( GetCurrentWave() );
WRITE_FLOAT( asw_holdout_announce_time.GetFloat() );
MessageEnd();
// actually start the wave after a short delay
CASW_Holdout_State_Change_Event *pStateEvent = new CASW_Holdout_State_Change_Event;
pStateEvent->m_EventType = HOLDOUT_EVENT_STATE_CHANGE;
pStateEvent->m_NewState = HOLDOUT_STATE_WAVE_IN_PROGRESS;
pStateEvent->m_flEventTime = gpGlobals->curtime + asw_holdout_announce_time.GetFloat();
AddEvent( pStateEvent );
if ( m_nCurrentWave < MAX_HOLDOUT_WAVES )
{
m_OnAnnounceWave[m_nCurrentWave].FireOutput( this, this );
}
m_OnAnnounceWaveDefault.FireOutput( this, this );
}
break;
case HOLDOUT_STATE_WAVE_IN_PROGRESS:
{
StartWave( GetCurrentWave() );
}
break;
case HOLDOUT_STATE_SHOWING_WAVE_SCORE:
{
CASW_Holdout_State_Change_Event *pStateEvent = new CASW_Holdout_State_Change_Event;
pStateEvent->m_EventType = HOLDOUT_EVENT_STATE_CHANGE;
pStateEvent->m_flEventTime = gpGlobals->curtime + asw_holdout_wave_score_time.GetFloat();
if ( GetCurrentWave() >= m_Waves.Count() - 1 )
{
pStateEvent->m_NewState = HOLDOUT_STATE_COMPLETE; // finished holdout mode!
}
else if ( m_nUnlockedResupply > 0 || m_Waves[ GetCurrentWave() ]->WaveHasResupply() )
{
pStateEvent->m_NewState = HOLDOUT_STATE_RESUPPLY;
}
else
{
pStateEvent->m_NewState = HOLDOUT_STATE_ANNOUNCE_NEW_WAVE;
}
AddEvent( pStateEvent );
// resurrect dead marines
m_bResurrectingMarines = true;
// tell clients to show the wave end scores:
CRecipientFilter filter;
filter.AddAllPlayers();
UserMessageBegin( filter, "ASWShowHoldoutWaveEnd" );
WRITE_BYTE( GetCurrentWave() );
WRITE_FLOAT( asw_holdout_wave_score_time.GetFloat() );
MessageEnd();
}
break;
case HOLDOUT_STATE_RESUPPLY:
{
if ( GetCurrentWave() < m_Waves.Count() - 1 )
{
if ( m_nUnlockedResupply > 0 )
{
m_nUnlockedResupply -= 1;
}
else
{
Warning( "Giving a resupply, but it has not been unlocked! (m_nUnlockedResupply <= 0)\n" );
}
RefillMarineAmmo();
CASW_Holdout_State_Change_Event *pStateEvent = new CASW_Holdout_State_Change_Event;
pStateEvent->m_EventType = HOLDOUT_EVENT_STATE_CHANGE;
pStateEvent->m_NewState = HOLDOUT_STATE_ANNOUNCE_NEW_WAVE;
pStateEvent->m_flEventTime = gpGlobals->curtime + asw_holdout_resupply_time.GetFloat();
AddEvent( pStateEvent );
// tell clients to show the resupply UI:
CRecipientFilter filter;
filter.AddAllPlayers();
UserMessageBegin( filter, "ASWShowHoldoutResupply" );
MessageEnd();
m_flResupplyEndTime = pStateEvent->m_flEventTime;
}
else
{
// completed all the waves!
if ( asw_holdout_debug.GetBool() )
{
Msg( "Finished all holdout waves!\n" );
}
}
}
break;
}
}
void CASW_Holdout_Mode::OnMissionStart()
{
// announce the first wave after a short delay
CASW_Holdout_State_Change_Event *pStateEvent = new CASW_Holdout_State_Change_Event;
pStateEvent->m_EventType = HOLDOUT_EVENT_STATE_CHANGE;
pStateEvent->m_NewState = HOLDOUT_STATE_ANNOUNCE_NEW_WAVE;
pStateEvent->m_flEventTime = gpGlobals->curtime + 3.0f;
AddEvent( pStateEvent );
}
void CASW_Holdout_Mode::OnAlienKilled( CBaseEntity *pAlien, const CTakeDamageInfo &info )
{
if ( !pAlien )
return;
IASW_Spawnable_NPC *pSpawnable = NULL;
if ( IsAlienClass( pAlien->Classify() ) )
{
CASW_Alien *pAlienNPC = static_cast<CASW_Alien*>( pAlien );
pSpawnable = pAlienNPC;
}
else if ( pAlien->Classify() == CLASS_ASW_BUZZER )
{
CASW_Buzzer *pBuzzer = static_cast<CASW_Buzzer*>( pAlien );
pSpawnable = pBuzzer;
}
if ( !pSpawnable || !pSpawnable->IsHoldoutAlien() )
return;
m_nAliensKilledThisWave++;
if ( m_nAliensKilledThisWave >= m_Waves[ GetCurrentWave() ]->GetTotalAliens() )
{
// all aliens have been killed - show the wave scores after a short delay
CASW_Holdout_State_Change_Event *pStateEvent = new CASW_Holdout_State_Change_Event;
pStateEvent->m_EventType = HOLDOUT_EVENT_STATE_CHANGE;
pStateEvent->m_NewState = HOLDOUT_STATE_SHOWING_WAVE_SCORE;
pStateEvent->m_flEventTime = gpGlobals->curtime + 2.0f;
AddEvent( pStateEvent );
}
m_nCurrentScore += 100; // TODO: different values per alien type
}
void CASW_Holdout_Mode::RefillMarineAmmo()
{
CASW_Game_Resource *pGameResource = ASWGameResource();
for (int i=0;i<pGameResource->GetMaxMarineResources();i++)
{
if (pGameResource->GetMarineResource(i) != NULL && pGameResource->GetMarineResource(i)->GetMarineEntity())
{
CASW_Marine *pMarine = pGameResource->GetMarineResource(i)->GetMarineEntity();
for (int k=0;k<3;k++)
{
CASW_Weapon *pWeapon = pMarine->GetASWWeapon(k);
if (!pWeapon)
continue;
// refill bullets in the gun
pWeapon->m_iClip1 = pWeapon->GetMaxClip1();
pWeapon->m_iClip2 = pWeapon->GetMaxClip2();
// give the marine a load of ammo of that type
pMarine->GiveAmmo(10000, pWeapon->GetPrimaryAmmoType());
pMarine->GiveAmmo(10000, pWeapon->GetSecondaryAmmoType());
}
}
}
}
void CASW_Holdout_Mode::ResurrectDeadMarines()
{
const int numMarineResources = ASWGameResource()->GetMaxMarineResources();
CASW_Marine *pAliveMarine = NULL;
for ( int i=0; i < numMarineResources ; i++ )
{
CASW_Marine_Resource *pMR = ASWGameResource()->GetMarineResource( i );
CASW_Marine *pMarine = pMR ? pMR->GetMarineEntity() : NULL;
if ( pMarine && pMR->GetHealthPercent() > 0 )
{
pAliveMarine = pMarine;
break;
}
}
for ( int i=0; i < numMarineResources ; i++ )
{
CASW_Marine_Resource *pMR = ASWGameResource()->GetMarineResource( i );
if ( pMR && pMR->GetHealthPercent() <= 0 ) // if marine exists, is dead
{
ASWGameRules()->Resurrect( pMR, pAliveMarine );
return; // don't do two in a frame
}
}
}
// player has picked a new weapon from the resupply panel
void CASW_Holdout_Mode::LoadoutSelect( CASW_Marine_Resource *pMarineResource, int nEquipIndex, int nInvSlot )
{
CASW_Marine *pMarine = pMarineResource->GetMarineEntity();
if ( !pMarine )
return;
// remove the old weapon in this slot, if any
CASW_Weapon *pOldWeapon = pMarine->GetASWWeapon( nInvSlot );
if ( pOldWeapon )
{
pMarine->DropWeapon( pOldWeapon, true );
UTIL_Remove( pOldWeapon );
}
// give them the new weapon
ASWGameRules()->GiveStartingWeaponToMarine( pMarine, nEquipIndex, nInvSlot );
pMarineResource->UpdateWeaponIndices();
}
CON_COMMAND( asw_holdout_start_wave, "Starts a holdout wave" )
{
if ( !ASWHoldoutMode() )
{
Msg( "Unable to start holdout wave as this isn't a holdout map\n" );
return;
}
if ( args.ArgC() != 2 )
{
Msg( "Usage: asw_holdout_start_wave [wave num]\n" );
return;
}
ASWHoldoutMode()->StartWave( atoi( args[1] ) );
}
#endif // GAME_DLL
void CASW_Holdout_Mode::LevelInitPostEntity()
{
#ifdef GAME_DLL
LoadWaves();
SetThink( &CASW_Holdout_Mode::HoldoutThink );
SetNextThink( gpGlobals->curtime + 1.0f );
#endif
}
#ifdef CLIENT_DLL
void CASW_Holdout_Mode::OnDataChanged(DataUpdateType_t updateType)
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
LoadWaves();
}
}
#endif
void CASW_Holdout_Mode::UpdateOnRemove()
{
BaseClass::UpdateOnRemove();
m_Waves.PurgeAndDeleteElements();
}
void CASW_Holdout_Mode::LoadWaves()
{
m_Waves.PurgeAndDeleteElements();
if ( asw_holdout_debug.GetBool() )
{
Msg( "CASW_Holdout_Mode::LoadWaves\n" );
}
char tempfile[MAX_PATH];
Q_snprintf( tempfile, sizeof( tempfile ), "resource/holdout/%s.txt", m_netHoldoutFilename.Get() );
KeyValues *pKV = new KeyValues( "HoldoutWaves" );
if ( !pKV->LoadFromFile( g_pFullFileSystem, tempfile, "GAME" ) )
{
Warning( "Failed to load holdout resource file: '%s' Attempting to load default.\n", tempfile );
Q_snprintf( tempfile, sizeof( tempfile ), "resource/holdout/%s.txt", "HoldoutWaves_Default" );
if ( !pKV->LoadFromFile( g_pFullFileSystem, tempfile, "GAME" ) )
{
Warning( "WARNING: Failed to load default holdout resource file. 'resource/holdout/HoldoutWaves_Default.txt' is missing!\n" );
return;
}
}
KeyValues *pKeys = pKV;
while ( pKeys )
{
if ( asw_holdout_debug.GetBool() )
{
Msg( " Loading a wave\n" );
}
CASW_Holdout_Wave* pWave = new CASW_Holdout_Wave;
pWave->LoadFromKeyValues( m_Waves.Count(), pKeys );
m_Waves.AddToTail( pWave );
pKeys = pKeys->GetNextKey();
}
pKV->deleteThis();
}
float CASW_Holdout_Mode::GetWaveProgress()
{
if ( GetCurrentWave() < 0 || GetCurrentWave() >= m_Waves.Count() )
return 1.0f;
return 1.0f - ( (float) GetAliensKilledThisWave() / (float) m_Waves[ GetCurrentWave() ]->GetTotalAliens() );
}