1091 lines
32 KiB
C++
1091 lines
32 KiB
C++
|
/*
|
||
|
** Command & Conquer Renegade(tm)
|
||
|
** Copyright 2025 Electronic Arts Inc.
|
||
|
**
|
||
|
** This program is free software: you can redistribute it and/or modify
|
||
|
** it under the terms of the GNU General Public License as published by
|
||
|
** the Free Software Foundation, either version 3 of the License, or
|
||
|
** (at your option) any later version.
|
||
|
**
|
||
|
** This program is distributed in the hope that it will be useful,
|
||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
** GNU General Public License for more details.
|
||
|
**
|
||
|
** You should have received a copy of the GNU General Public License
|
||
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
*** Confidential - Westwood Studios ***
|
||
|
***********************************************************************************************
|
||
|
* *
|
||
|
* Project Name : Commando *
|
||
|
* *
|
||
|
* $Archive:: /Commando/Code/Combat/spawn.cpp $*
|
||
|
* *
|
||
|
* $Author:: Tom_s $*
|
||
|
* *
|
||
|
* $Modtime:: 11/19/01 10:25a $*
|
||
|
* *
|
||
|
* $Revision:: 107 $*
|
||
|
* *
|
||
|
*---------------------------------------------------------------------------------------------*
|
||
|
* Functions: *
|
||
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||
|
|
||
|
#include "spawn.h"
|
||
|
#include "wwhack.h"
|
||
|
#include "persistfactory.h"
|
||
|
#include "combatchunkid.h"
|
||
|
#include "simpledefinitionfactory.h"
|
||
|
#include "debug.h"
|
||
|
#include "definitionmgr.h"
|
||
|
#include "soldier.h"
|
||
|
#include "combat.h"
|
||
|
#include "playertype.h"
|
||
|
#include "gameobjmanager.h"
|
||
|
#include "soldierobserver.h"
|
||
|
#include "crandom.h"
|
||
|
#include "wwaudio.h"
|
||
|
#include "assets.h"
|
||
|
#include "objlibrary.h"
|
||
|
#include "movephys.h"
|
||
|
#include "scripts.h"
|
||
|
#include "wwmemlog.h"
|
||
|
#include "gametype.h"
|
||
|
#include "combatmaterialeffectmanager.h"
|
||
|
#include "transitioneffect.h"
|
||
|
#include "humanphys.h"
|
||
|
|
||
|
|
||
|
//
|
||
|
// Class statics
|
||
|
//
|
||
|
bool _Allow_Killing_Hibernating_Spawn = true;
|
||
|
|
||
|
#define AUTO_SPAWN_CHECK_DELAY 2.0f
|
||
|
|
||
|
|
||
|
/*
|
||
|
** SpawnDefClass
|
||
|
*/
|
||
|
DECLARE_FORCE_LINK( Spawner )
|
||
|
|
||
|
SimplePersistFactoryClass<SpawnerDefClass, CHUNKID_SPAWNER_DEF> _SpawnerDefPersistFactory;
|
||
|
|
||
|
DECLARE_DEFINITION_FACTORY(SpawnerDefClass, CLASSID_SPAWNER_DEF, "Spawner") _SpawnerDefDefFactory;
|
||
|
|
||
|
|
||
|
SpawnerDefClass::SpawnerDefClass( void ) :
|
||
|
PlayerType( PLAYERTYPE_NEUTRAL ),
|
||
|
SpawnMax( -1 ), // unlimited
|
||
|
SpawnDelay( 10 ),
|
||
|
SpawnDelayVariation( 0 ),
|
||
|
IsPrimary( false ),
|
||
|
IsSoldierStartup( false ),
|
||
|
PostVisualSpawnDelay( 0 ),
|
||
|
SpecialEffectsObjID( 0 ),
|
||
|
GotoSpawnerPos( false ),
|
||
|
GotoSpawnerPosPriority( 30 ),
|
||
|
TeleportFirstSpawn( true ),
|
||
|
StartsDisabled( false ),
|
||
|
KillHibernatingSpawn( true ),
|
||
|
ApplySpawnMaterialEffect( true ),
|
||
|
IsMultiplayWeaponSpawner( false )
|
||
|
{
|
||
|
DEFIDLIST_PARAM( SpawnerDefClass, SpawnDefinitionIDList, CLASSID_GAME_OBJECTS );
|
||
|
|
||
|
#ifdef PARAM_EDITING_ON
|
||
|
EnumParameterClass *param;
|
||
|
param = new EnumParameterClass( (int*)&PlayerType );
|
||
|
param->Set_Name ("PlayerType");
|
||
|
param->Add_Value ( "Unteamed", PLAYERTYPE_RENEGADE );
|
||
|
param->Add_Value ( "Nod", PLAYERTYPE_NOD );
|
||
|
param->Add_Value ( "GDI", PLAYERTYPE_GDI );
|
||
|
|
||
|
GENERIC_EDITABLE_PARAM(SpawnerDefClass,param)
|
||
|
#endif
|
||
|
|
||
|
EDITABLE_PARAM( SpawnerDefClass, ParameterClass::TYPE_INT, SpawnMax );
|
||
|
EDITABLE_PARAM( SpawnerDefClass, ParameterClass::TYPE_FLOAT, SpawnDelay );
|
||
|
EDITABLE_PARAM( SpawnerDefClass, ParameterClass::TYPE_FLOAT, SpawnDelayVariation );
|
||
|
EDITABLE_PARAM( SpawnerDefClass, ParameterClass::TYPE_BOOL, IsPrimary );
|
||
|
EDITABLE_PARAM( SpawnerDefClass, ParameterClass::TYPE_BOOL, IsSoldierStartup );
|
||
|
EDITABLE_PARAM( SpawnerDefClass, ParameterClass::TYPE_BOOL, GotoSpawnerPos );
|
||
|
EDITABLE_PARAM( SpawnerDefClass, ParameterClass::TYPE_FLOAT, GotoSpawnerPosPriority );
|
||
|
EDITABLE_PARAM( SpawnerDefClass, ParameterClass::TYPE_BOOL, TeleportFirstSpawn );
|
||
|
EDITABLE_PARAM( SpawnerDefClass, ParameterClass::TYPE_BOOL, StartsDisabled );
|
||
|
EDITABLE_PARAM( SpawnerDefClass, ParameterClass::TYPE_BOOL, KillHibernatingSpawn );
|
||
|
EDITABLE_PARAM( SpawnerDefClass, ParameterClass::TYPE_BOOL, ApplySpawnMaterialEffect );
|
||
|
EDITABLE_PARAM( SpawnerDefClass, ParameterClass::TYPE_BOOL, IsMultiplayWeaponSpawner );
|
||
|
|
||
|
GENERIC_DEFID_PARAM( SpawnerDefClass, SpecialEffectsObjID, CLASSID_GAME_OBJECT_DEF_SPECIAL_EFFECTS);
|
||
|
EDITABLE_PARAM( SpawnerDefClass, ParameterClass::TYPE_FLOAT, PostVisualSpawnDelay );
|
||
|
|
||
|
SCRIPTLIST_PARAM (SpawnerDefClass, "Scripts", ScriptNameList, ScriptParameterList);
|
||
|
}
|
||
|
|
||
|
uint32 SpawnerDefClass::Get_Class_ID( void ) const
|
||
|
{
|
||
|
return CLASSID_SPAWNER_DEF;
|
||
|
}
|
||
|
|
||
|
|
||
|
PersistClass * SpawnerDefClass::Create( void ) const
|
||
|
{
|
||
|
SpawnerClass * obj = new SpawnerClass;
|
||
|
obj->Init( *this );
|
||
|
return obj;
|
||
|
}
|
||
|
|
||
|
enum {
|
||
|
CHUNKID_DEF_PARENT = 1013991542,
|
||
|
CHUNKID_DEF_VARIABLES,
|
||
|
|
||
|
MICROCHUNKID_DEF_DEFINITION_ID = 1,
|
||
|
XXXMICROCHUNKID_DEF_IS_COMMANDO_STARTING_POINT,
|
||
|
MICROCHUNKID_DEF_PLAYER_TYPE,
|
||
|
MICROCHUNKID_DEF_SPAWN_MAX,
|
||
|
MICROCHUNKID_DEF_SPAWN_DELAY,
|
||
|
XXXMICROCHUNKID_DEF_AUTO_SPAWN_RADIUS,
|
||
|
XXXMICROCHUNKID_DEF_ONE_AT_A_TIME,
|
||
|
MICROCHUNKID_DEF_SPAWN_DELAY_VARIATION,
|
||
|
MICROCHUNKID_DEF_IS_PRIMARY,
|
||
|
XXXMICROCHUNKID_DEF_EFFECT_MODEL_NAME,
|
||
|
XXXMICROCHUNKID_DEF_EFFECT_ANIMATION_NAME,
|
||
|
XXXMICROCHUNKID_DEF_SOUND_ID,
|
||
|
MICROCHUNKID_DEF_POST_EFFECT_SPAWN_DELAY,
|
||
|
MICROCHUNKID_DEF_SPECIAL_EFFECTS_OBJ_ID,
|
||
|
MICROCHUNKID_DEF_IS_SOLDIER_STARTUP,
|
||
|
MICROCHUNKID_DEF_GOTO_SPAWNER_POS,
|
||
|
MICROCHUNKID_DEF_TELEPORT_FIRST_SPAWN,
|
||
|
MICROCHUNKID_DEF_SCRIPT_NAME,
|
||
|
MICROCHUNKID_DEF_SCRIPT_PARAMETERS,
|
||
|
MICROCHUNKID_DEF_STARTS_DISABLED,
|
||
|
MICROCHUNKID_DEF_KILL_HIBERNATING_SPAWN,
|
||
|
MICROCHUNKID_DEF_GOTO_SPAWNER_POS_PRIORITY,
|
||
|
MICROCHUNKID_DEF_APPLY_SPAWN_MATERIAL_EFFECT,
|
||
|
MICROCHUNKID_DEF_IS_MULTIPLAY_WEAPON_SPAWNER
|
||
|
};
|
||
|
|
||
|
bool SpawnerDefClass::Save( ChunkSaveClass &csave )
|
||
|
{
|
||
|
int i;
|
||
|
csave.Begin_Chunk( CHUNKID_DEF_PARENT );
|
||
|
DefinitionClass::Save( csave );
|
||
|
csave.End_Chunk();
|
||
|
|
||
|
csave.Begin_Chunk( CHUNKID_DEF_VARIABLES );
|
||
|
for ( i = 0; i < SpawnDefinitionIDList.Count(); i++ ) {
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_DEFINITION_ID, SpawnDefinitionIDList[i] );
|
||
|
}
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_PLAYER_TYPE, PlayerType );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_SPAWN_MAX, SpawnMax );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_SPAWN_DELAY, SpawnDelay );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_SPAWN_DELAY_VARIATION, SpawnDelayVariation );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_IS_PRIMARY, IsPrimary );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_IS_SOLDIER_STARTUP, IsSoldierStartup );
|
||
|
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_SPECIAL_EFFECTS_OBJ_ID, SpecialEffectsObjID );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_POST_EFFECT_SPAWN_DELAY, PostVisualSpawnDelay );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GOTO_SPAWNER_POS, GotoSpawnerPos );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GOTO_SPAWNER_POS_PRIORITY,GotoSpawnerPosPriority );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_TELEPORT_FIRST_SPAWN, TeleportFirstSpawn );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_STARTS_DISABLED, StartsDisabled );
|
||
|
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_KILL_HIBERNATING_SPAWN, KillHibernatingSpawn );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_APPLY_SPAWN_MATERIAL_EFFECT, ApplySpawnMaterialEffect );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_IS_MULTIPLAY_WEAPON_SPAWNER, IsMultiplayWeaponSpawner );
|
||
|
|
||
|
WWASSERT( ScriptNameList.Count() == ScriptParameterList.Count() );
|
||
|
for ( i = 0; i < ScriptNameList.Count(); i++ ) {
|
||
|
WRITE_MICRO_CHUNK_WWSTRING( csave, MICROCHUNKID_DEF_SCRIPT_NAME, ScriptNameList[i] );
|
||
|
WRITE_MICRO_CHUNK_WWSTRING( csave, MICROCHUNKID_DEF_SCRIPT_PARAMETERS, ScriptParameterList[i] );
|
||
|
}
|
||
|
|
||
|
csave.End_Chunk();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool SpawnerDefClass::Load( ChunkLoadClass &cload )
|
||
|
{
|
||
|
WWASSERT( ScriptNameList.Count() == ScriptParameterList.Count() );
|
||
|
WWASSERT( SpawnDefinitionIDList.Count() == 0 );
|
||
|
StringClass str;
|
||
|
|
||
|
while (cload.Open_Chunk()) {
|
||
|
switch(cload.Cur_Chunk_ID()) {
|
||
|
|
||
|
case CHUNKID_DEF_PARENT:
|
||
|
DefinitionClass::Load( cload );
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_DEF_VARIABLES:
|
||
|
while (cload.Open_Micro_Chunk()) {
|
||
|
switch(cload.Cur_Micro_Chunk_ID()) {
|
||
|
case MICROCHUNKID_DEF_DEFINITION_ID:
|
||
|
{
|
||
|
int def_id;
|
||
|
cload.Read(&def_id,sizeof(def_id));
|
||
|
SpawnDefinitionIDList.Add( def_id );
|
||
|
}
|
||
|
break;
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_PLAYER_TYPE, PlayerType );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_SPAWN_MAX, SpawnMax );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_SPAWN_DELAY, SpawnDelay );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_SPAWN_DELAY_VARIATION, SpawnDelayVariation );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_IS_PRIMARY, IsPrimary );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_IS_SOLDIER_STARTUP, IsSoldierStartup );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_POST_EFFECT_SPAWN_DELAY, PostVisualSpawnDelay );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_SPECIAL_EFFECTS_OBJ_ID, SpecialEffectsObjID );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GOTO_SPAWNER_POS, GotoSpawnerPos );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GOTO_SPAWNER_POS_PRIORITY, GotoSpawnerPosPriority );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_TELEPORT_FIRST_SPAWN, TeleportFirstSpawn );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_STARTS_DISABLED, StartsDisabled );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_KILL_HIBERNATING_SPAWN, KillHibernatingSpawn );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_APPLY_SPAWN_MATERIAL_EFFECT, ApplySpawnMaterialEffect );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_IS_MULTIPLAY_WEAPON_SPAWNER, IsMultiplayWeaponSpawner );
|
||
|
|
||
|
case MICROCHUNKID_DEF_SCRIPT_NAME:
|
||
|
LOAD_MICRO_CHUNK_WWSTRING( cload, str );
|
||
|
ScriptNameList.Add( str );
|
||
|
break;
|
||
|
|
||
|
case MICROCHUNKID_DEF_SCRIPT_PARAMETERS:
|
||
|
LOAD_MICRO_CHUNK_WWSTRING( cload, str );
|
||
|
ScriptParameterList.Add( str );
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
Debug_Say(("Unhandled Micro Chunk:%d File:%s Line:%d\r\n",cload.Cur_Micro_Chunk_ID(),__FILE__,__LINE__));
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
cload.Close_Micro_Chunk();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
Debug_Say(("Unhandled Chunk:%d File:%s Line:%d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
cload.Close_Chunk();
|
||
|
}
|
||
|
|
||
|
WWASSERT( ScriptNameList.Count() == ScriptParameterList.Count() );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
const PersistFactoryClass & SpawnerDefClass::Get_Factory( void ) const
|
||
|
{
|
||
|
return _SpawnerDefPersistFactory;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
** SpawnClass
|
||
|
*/
|
||
|
SimplePersistFactoryClass<SpawnerClass, CHUNKID_SPAWNER> _SpawnerPersistFactory;
|
||
|
|
||
|
const PersistFactoryClass & SpawnerClass::Get_Factory (void) const
|
||
|
{
|
||
|
return _SpawnerPersistFactory;
|
||
|
}
|
||
|
|
||
|
SpawnerClass::SpawnerClass( void ) :
|
||
|
ID( 0 ),
|
||
|
TM( 1 ),
|
||
|
SpawnTM( 1 ),
|
||
|
Definition( NULL ),
|
||
|
SpawnCount( 0 ),
|
||
|
SpawnDelayTimer( 0 ),
|
||
|
Enabled( true )
|
||
|
{
|
||
|
SpawnManager::Add_Spawner( this );
|
||
|
}
|
||
|
|
||
|
SpawnerClass::~SpawnerClass( void )
|
||
|
{
|
||
|
SpawnManager::Remove_Spawner( this );
|
||
|
}
|
||
|
|
||
|
void SpawnerClass::Init( const SpawnerDefClass & definition )
|
||
|
{
|
||
|
Definition = &definition;
|
||
|
Enabled = !definition.StartsDisabled;
|
||
|
}
|
||
|
|
||
|
enum {
|
||
|
CHUNKID_PARENT = 1014991053,
|
||
|
CHUNKID_VARIABLES,
|
||
|
CHUNKID_LAST_SPAWN,
|
||
|
|
||
|
MICROCHUNKID_ID = 1,
|
||
|
MICROCHUNKID_TM,
|
||
|
MICROCHUNKID_DEFINITION_ID,
|
||
|
MICROCHUNKID_SPAWN_COUNT,
|
||
|
MICROCHUNKID_SPAWN_DELAY_TIMER,
|
||
|
MICROCHUNKID_ENABLED,
|
||
|
MICROCHUNKID_SPAWN_POINT_ENTRY,
|
||
|
XXXMICROCHUNKID_REAL_SPAWN_TIMER,
|
||
|
MICROCHUNKID_SPAWN_TM,
|
||
|
MICROCHUNKID_SCRIPT_NAME,
|
||
|
MICROCHUNKID_SCRIPT_PARAMETERS,
|
||
|
};
|
||
|
|
||
|
bool SpawnerClass::Save( ChunkSaveClass & csave )
|
||
|
{
|
||
|
csave.Begin_Chunk( CHUNKID_PARENT );
|
||
|
PersistClass::Save( csave );
|
||
|
csave.End_Chunk();
|
||
|
|
||
|
csave.Begin_Chunk( CHUNKID_VARIABLES );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_ID, ID );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_TM, TM );
|
||
|
int id = Get_Definition().Get_ID();
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEFINITION_ID, id );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_SPAWN_COUNT, SpawnCount );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_SPAWN_DELAY_TIMER, SpawnDelayTimer );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_ENABLED, Enabled );
|
||
|
for ( int i = 0; i < SpawnPointList.Count(); i++ ) {
|
||
|
Matrix3D tm = SpawnPointList[i];
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_SPAWN_POINT_ENTRY, tm );
|
||
|
}
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_SPAWN_TM, SpawnTM );
|
||
|
|
||
|
WWASSERT( ScriptNameList.Count() == ScriptParameterList.Count() );
|
||
|
for ( i = 0; i < ScriptNameList.Count(); i++ ) {
|
||
|
WRITE_MICRO_CHUNK_WWSTRING( csave, MICROCHUNKID_SCRIPT_NAME, ScriptNameList[i] );
|
||
|
WRITE_MICRO_CHUNK_WWSTRING( csave, MICROCHUNKID_SCRIPT_PARAMETERS, ScriptParameterList[i] );
|
||
|
}
|
||
|
|
||
|
csave.End_Chunk();
|
||
|
|
||
|
if ( LastSpawn.Get_Ptr() != NULL ) {
|
||
|
csave.Begin_Chunk( CHUNKID_LAST_SPAWN );
|
||
|
LastSpawn.Save( csave );
|
||
|
csave.End_Chunk();
|
||
|
}
|
||
|
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool SpawnerClass::Load( ChunkLoadClass & cload )
|
||
|
{
|
||
|
WWASSERT( ScriptNameList.Count() == ScriptParameterList.Count() );
|
||
|
StringClass str;
|
||
|
|
||
|
Matrix3D tm;
|
||
|
WWASSERT( SpawnPointList.Length() == 0 );
|
||
|
|
||
|
while (cload.Open_Chunk()) {
|
||
|
switch(cload.Cur_Chunk_ID()) {
|
||
|
|
||
|
case CHUNKID_PARENT:
|
||
|
PersistClass::Load( cload );
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_VARIABLES:
|
||
|
while (cload.Open_Micro_Chunk()) {
|
||
|
switch(cload.Cur_Micro_Chunk_ID()) {
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_ID, ID );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_TM, TM );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_SPAWN_COUNT, SpawnCount );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_SPAWN_DELAY_TIMER, SpawnDelayTimer );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_ENABLED, Enabled );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_SPAWN_TM, SpawnTM );
|
||
|
|
||
|
case MICROCHUNKID_DEFINITION_ID:
|
||
|
int definition_id;
|
||
|
LOAD_MICRO_CHUNK( cload, definition_id );
|
||
|
WWASSERT( Definition == NULL );
|
||
|
Definition = (const SpawnerDefClass *)DefinitionMgrClass::Find_Definition( definition_id );
|
||
|
WWASSERT( Definition != NULL );
|
||
|
break;
|
||
|
|
||
|
case MICROCHUNKID_SPAWN_POINT_ENTRY:
|
||
|
LOAD_MICRO_CHUNK( cload, tm );
|
||
|
SpawnPointList.Add( tm );
|
||
|
break;
|
||
|
|
||
|
case MICROCHUNKID_SCRIPT_NAME:
|
||
|
LOAD_MICRO_CHUNK_WWSTRING( cload, str );
|
||
|
ScriptNameList.Add( str );
|
||
|
break;
|
||
|
|
||
|
case MICROCHUNKID_SCRIPT_PARAMETERS:
|
||
|
LOAD_MICRO_CHUNK_WWSTRING( cload, str );
|
||
|
ScriptParameterList.Add( str );
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
Debug_Say(("Unhandled Micro Chunk:%d File:%s Line:%d\r\n",cload.Cur_Micro_Chunk_ID(),__FILE__,__LINE__));
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
cload.Close_Micro_Chunk();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_LAST_SPAWN:
|
||
|
LastSpawn.Load( cload );
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
Debug_Say(("Unhandled Chunk:%d File:%s Line:%d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
cload.Close_Chunk();
|
||
|
}
|
||
|
|
||
|
WWASSERT( ScriptNameList.Count() == ScriptParameterList.Count() );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool SpawnerClass::Determine_Spawn_TM( PhysicalGameObj * obj )
|
||
|
{
|
||
|
bool spawnable = false;
|
||
|
|
||
|
MoveablePhysClass * phys_obj = NULL;
|
||
|
if ( obj->Peek_Physical_Object() ) {
|
||
|
phys_obj = obj->Peek_Physical_Object()->As_MoveablePhysClass();
|
||
|
}
|
||
|
|
||
|
// If we have spawn points, try and find one where the object can be placed
|
||
|
if ( SpawnPointList.Count() > 0 ) {
|
||
|
|
||
|
// Find human player nearest spawner
|
||
|
Vector3 nearest_human_player_pos( 0,0,0 );
|
||
|
float commando_range = 10000000;
|
||
|
SLNode<SmartGameObj> *objnode;
|
||
|
for ( objnode = GameObjManager::Get_Smart_Game_Obj_List()->Head(); objnode; objnode = objnode->Next()) {
|
||
|
SoldierGameObj * soldier = objnode->Data()->As_SoldierGameObj();
|
||
|
if ( soldier && soldier->Is_Human_Controlled() ) {
|
||
|
Vector3 pos;
|
||
|
soldier->Get_Position( &pos );
|
||
|
pos -= TM.Get_Translation();
|
||
|
float range = pos.Length();
|
||
|
if ( range < commando_range ) {
|
||
|
soldier->Get_Position( &nearest_human_player_pos );
|
||
|
commando_range = range;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Find a safe spawnable point furthest from the commando
|
||
|
float best_range = 0;
|
||
|
|
||
|
// For every spawn point
|
||
|
for ( int index = 0; index < SpawnPointList.Count(); index++ ) {
|
||
|
|
||
|
bool is_safe = true; // Assume safe
|
||
|
Matrix3D safe_spot = SpawnPointList[index];
|
||
|
if ( phys_obj ) {
|
||
|
is_safe = phys_obj->Can_Teleport_And_Stand( SpawnPointList[index], &safe_spot );
|
||
|
}
|
||
|
|
||
|
if ( is_safe ) {
|
||
|
// check range for furthest from commando
|
||
|
Vector3 diff = safe_spot.Get_Translation() - nearest_human_player_pos;
|
||
|
float range = diff.Length();
|
||
|
if ( range > best_range ) {
|
||
|
best_range = range;
|
||
|
SpawnTM = safe_spot;
|
||
|
spawnable = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
// Lets see if we can spawn at TM..
|
||
|
|
||
|
// Only check teleport for armed objs
|
||
|
if ( phys_obj && obj->As_ArmedGameObj() != NULL ) {
|
||
|
Matrix3D safe_spot = TM;
|
||
|
if ( phys_obj->Can_Teleport_And_Stand( TM, &safe_spot ) ) {
|
||
|
SpawnTM = safe_spot;
|
||
|
spawnable = true;
|
||
|
}
|
||
|
} else {
|
||
|
SpawnTM = TM;
|
||
|
spawnable = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( spawnable ) {
|
||
|
obj->Set_Transform( SpawnTM );
|
||
|
}
|
||
|
|
||
|
return spawnable;
|
||
|
}
|
||
|
|
||
|
PhysicalGameObj * SpawnerClass::Create_Spawned_Object( int obj_id )
|
||
|
{
|
||
|
WWMEMLOG(MEM_GAMEDATA);
|
||
|
|
||
|
int spawn_id = obj_id;
|
||
|
if ( obj_id == -1 ) {
|
||
|
|
||
|
/*
|
||
|
** Randomly select an object to spawn
|
||
|
*/
|
||
|
int spawn_count = Get_Definition().SpawnDefinitionIDList.Count();
|
||
|
if ( spawn_count > 0 ) {
|
||
|
int spawn_index = FreeRandom.Get_Int( spawn_count );
|
||
|
spawn_id = Get_Definition().SpawnDefinitionIDList[ spawn_index ];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Create the object
|
||
|
*/
|
||
|
PhysicalGameObj * obj = NULL;
|
||
|
if ( spawn_id != -1 ) {
|
||
|
PhysicalGameObjDef * def = (PhysicalGameObjDef *)DefinitionMgrClass::Find_Definition( spawn_id );
|
||
|
if ( def == NULL ) {
|
||
|
Debug_Say(( "Spawner %s failed to create a spawn id %d\n", Get_Definition().Get_Name(), spawn_id ));
|
||
|
}
|
||
|
WWASSERT( def );
|
||
|
if ( def != NULL ) {
|
||
|
obj = (PhysicalGameObj *)def->Create();
|
||
|
|
||
|
if ( obj == NULL ) {
|
||
|
Debug_Say(( "Spawner Failed to create %s\n", def->Get_Name() ));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** If the definition calls for it, add a material effect to the object
|
||
|
*/
|
||
|
if ((obj != NULL) && (Get_Definition().ApplySpawnMaterialEffect)) {
|
||
|
PhysClass * physobj = obj->Peek_Physical_Object();
|
||
|
if (physobj != NULL) {
|
||
|
TransitionEffectClass * effect = CombatMaterialEffectManager::Get_Spawn_Effect();
|
||
|
physobj->Add_Effect_To_Me(effect);
|
||
|
REF_PTR_RELEASE(effect);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return obj;
|
||
|
}
|
||
|
|
||
|
void SpawnerClass::Check_Auto_Spawn( float dtime )
|
||
|
{
|
||
|
if ( LastSpawn.Get_Ptr() == NULL ) { // If our last spawn is gone
|
||
|
|
||
|
bool spawn_ok = false;
|
||
|
|
||
|
if ( Get_Definition().SpawnMax < 0 ||
|
||
|
SpawnCount < Get_Definition().SpawnMax ) {
|
||
|
spawn_ok = true;
|
||
|
}
|
||
|
|
||
|
if ( Enabled && spawn_ok ) {
|
||
|
if ( SpawnDelayTimer > 0 ) {
|
||
|
SpawnDelayTimer -= dtime;
|
||
|
}
|
||
|
if ( SpawnDelayTimer <= 0 ) {
|
||
|
Spawn();
|
||
|
}
|
||
|
}
|
||
|
} else if ( Get_Definition().KillHibernatingSpawn && _Allow_Killing_Hibernating_Spawn ) {
|
||
|
// If our last spawn is alive, but hibernating
|
||
|
PhysicalGameObj * spawn = (PhysicalGameObj *)LastSpawn.Get_Ptr();
|
||
|
if ( spawn->Is_Hibernating() ) {
|
||
|
spawn->Set_Delete_Pending(); // Kill em
|
||
|
SpawnCount--;
|
||
|
SpawnDelayTimer = 0; // no delay to bring him back
|
||
|
|
||
|
#if 0
|
||
|
if ( Enabled ) {
|
||
|
Debug_Say(( "Killing Hibernating Spawn from an Enabled spawner (id %d)\n", Get_ID() ));
|
||
|
} else {
|
||
|
Debug_Say(( "Killing Hibernating Spawn (spawner id %d)\n", Get_ID() ));
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PhysicalGameObj * SpawnerClass::Spawn_Object( int obj_def_id )
|
||
|
{
|
||
|
return Spawn( obj_def_id );
|
||
|
}
|
||
|
|
||
|
bool SpawnerClass::Can_Spawn_Object( int obj_def_id )
|
||
|
{
|
||
|
bool retval = false;
|
||
|
|
||
|
//
|
||
|
// Loop over all the objects this spawner can create
|
||
|
//
|
||
|
const DynamicVectorClass<int> &def_list = Definition->Get_Spawn_Definition_ID_List ();
|
||
|
for (int index = 0; index < def_list.Count (); index ++) {
|
||
|
|
||
|
//
|
||
|
// Is this the object we're looking for?
|
||
|
//
|
||
|
if ( def_list[index] == obj_def_id ) {
|
||
|
retval = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
|
||
|
PhysicalGameObj * SpawnerClass::Spawn( int obj_id )
|
||
|
{
|
||
|
WWASSERT( CombatManager::I_Am_Server() );
|
||
|
|
||
|
// Pick what will be spawned
|
||
|
PhysicalGameObj * obj = Create_Spawned_Object( obj_id );
|
||
|
WWASSERT( obj );
|
||
|
|
||
|
// Choose a spawn location
|
||
|
bool spawnable = Determine_Spawn_TM( obj );
|
||
|
|
||
|
if ( !spawnable ) {
|
||
|
Debug_Say(( "Couldn't find a place to spawn this object ID %d\n", Get_ID() ));
|
||
|
obj->Set_Delete_Pending();
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
obj->Start_Observers();
|
||
|
|
||
|
if ( Get_Definition().GotoSpawnerPos ) {
|
||
|
|
||
|
// Teleport the first spawn
|
||
|
if ( Get_Definition().TeleportFirstSpawn && SpawnCount == 0 ) {
|
||
|
obj->Set_Transform( TM );
|
||
|
} else {
|
||
|
// Give initial goto command / don't let him hibernate
|
||
|
SoldierGameObj * soldier = obj->As_SoldierGameObj();
|
||
|
if ( soldier != NULL ) {
|
||
|
ActionParamsStruct parameters;
|
||
|
parameters.Priority = Get_Definition().GotoSpawnerPosPriority;
|
||
|
parameters.ObserverID = 0;
|
||
|
parameters.MoveLocation = TM.Get_Translation();
|
||
|
parameters.MoveSpeed = 1;
|
||
|
parameters.MoveCrouched = false;
|
||
|
parameters.MoveArrivedDistance = 1;
|
||
|
soldier->Get_Action()->Goto( parameters );
|
||
|
soldier->Reset_Hibernating();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Keep track of the last spawned object
|
||
|
LastSpawn = obj;
|
||
|
|
||
|
// Create the special effects game object that will be responsible for playing
|
||
|
// an animation and sound
|
||
|
if ( Get_Definition().SpecialEffectsObjID != 0 ) {
|
||
|
PhysicalGameObj *effect_obj = ObjectLibraryManager::Create_Object( Get_Definition().SpecialEffectsObjID );
|
||
|
if ( effect_obj != NULL ) {
|
||
|
effect_obj->Set_Transform( SpawnTM );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Setup the spawning variables
|
||
|
SpawnCount++;
|
||
|
|
||
|
float variation = Get_Definition().SpawnDelayVariation/2;
|
||
|
SpawnDelayTimer = Get_Definition().SpawnDelay + FreeRandom.Get_Float( -variation, variation );
|
||
|
|
||
|
int i;
|
||
|
|
||
|
// Start Def Scripts
|
||
|
WWASSERT( Get_Definition().ScriptNameList.Count() == Get_Definition().ScriptParameterList.Count() );
|
||
|
for ( i = 0; i < Get_Definition().ScriptNameList.Count(); i++ ) {
|
||
|
ScriptClass* script = ScriptManager::Create_Script( Get_Definition().ScriptNameList[i] );
|
||
|
if (script) {
|
||
|
script->Set_Parameters_String( Get_Definition().ScriptParameterList[i] );
|
||
|
obj->Add_Observer(script);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Start Instance Scripts
|
||
|
WWASSERT( ScriptNameList.Count() == ScriptParameterList.Count() );
|
||
|
for ( i = 0; i < ScriptNameList.Count(); i++ ) {
|
||
|
ScriptClass* script = ScriptManager::Create_Script( ScriptNameList[i] );
|
||
|
if (script) {
|
||
|
script->Set_Parameters_String( ScriptParameterList[i] );
|
||
|
obj->Add_Observer(script);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return obj;
|
||
|
}
|
||
|
|
||
|
void SpawnerClass::Add_Script( const char * script_name, const char * script_parameter )
|
||
|
{
|
||
|
WWASSERT( ScriptNameList.Count() == ScriptParameterList.Count() );
|
||
|
ScriptNameList.Add( script_name );
|
||
|
ScriptParameterList.Add( script_parameter );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** SpawnManager
|
||
|
*/
|
||
|
DynamicVectorClass<SpawnerClass*> SpawnManager::SpawnerList;
|
||
|
float SpawnManager::AutoSpawnTimer = AUTO_SPAWN_CHECK_DELAY;
|
||
|
|
||
|
/*
|
||
|
** Instance of SpawnManager that exists just to free memory at game end when it gets destructed.
|
||
|
*/
|
||
|
static SpawnManager JustForLeaks;
|
||
|
|
||
|
|
||
|
void SpawnManager::Add_Spawner( SpawnerClass * spawner )
|
||
|
{
|
||
|
WWASSERT(spawner != NULL);
|
||
|
SpawnerList.Add( spawner );
|
||
|
}
|
||
|
|
||
|
void SpawnManager::Remove_Spawner( SpawnerClass * spawner )
|
||
|
{
|
||
|
SpawnerList.Delete( spawner );
|
||
|
}
|
||
|
|
||
|
void SpawnManager::Remove_All_Spawners( void )
|
||
|
{
|
||
|
while ( SpawnerList.Count() ) {
|
||
|
delete SpawnerList[0];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
**
|
||
|
*/
|
||
|
enum {
|
||
|
CHUNKID_SPAWNER_DATA = 1014991133,
|
||
|
CHUNKID_SPAWNER_VARIABLES,
|
||
|
|
||
|
MICROCHUNKID_SPAWNER_AUTO_SPAWN_TIMER = 1,
|
||
|
};
|
||
|
|
||
|
bool SpawnManager::Save( ChunkSaveClass &csave )
|
||
|
{
|
||
|
csave.Begin_Chunk( CHUNKID_SPAWNER_VARIABLES );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_SPAWNER_AUTO_SPAWN_TIMER, AutoSpawnTimer );
|
||
|
csave.End_Chunk();
|
||
|
|
||
|
for ( int i = 0; i < SpawnerList.Count(); i++ ) {
|
||
|
csave.Begin_Chunk( CHUNKID_SPAWNER_DATA );
|
||
|
SpawnerList[i]->Save( csave );
|
||
|
csave.End_Chunk();
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool SpawnManager::Load( ChunkLoadClass &cload )
|
||
|
{
|
||
|
Remove_All_Spawners();
|
||
|
|
||
|
while (cload.Open_Chunk()) {
|
||
|
switch(cload.Cur_Chunk_ID()) {
|
||
|
|
||
|
case CHUNKID_SPAWNER_VARIABLES:
|
||
|
while (cload.Open_Micro_Chunk()) {
|
||
|
switch(cload.Cur_Micro_Chunk_ID()) {
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_SPAWNER_AUTO_SPAWN_TIMER, AutoSpawnTimer );
|
||
|
|
||
|
default:
|
||
|
Debug_Say(("Unhandled Micro Chunk:%d File:%s Line:%d\r\n",cload.Cur_Micro_Chunk_ID(),__FILE__,__LINE__));
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
cload.Close_Micro_Chunk();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_SPAWNER_DATA:
|
||
|
{
|
||
|
SpawnerClass * spawner = new SpawnerClass();
|
||
|
spawner->Load( cload );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
Debug_Say(("Unhandled Chunk:%d File:%s Line:%d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
cload.Close_Chunk();
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
**
|
||
|
*/
|
||
|
bool SpawnManager::Spawner_Exists( int player_type )
|
||
|
{
|
||
|
for ( int i = 0; i < SpawnerList.Count(); i++ ) {
|
||
|
if ( SpawnerList[i]->Get_Definition().PlayerType == player_type ) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
Matrix3D SpawnManager::Get_Primary_Spawn_Location( void )
|
||
|
{
|
||
|
int index = -1;
|
||
|
for (int i = 0; i < SpawnerList.Count(); i++) {
|
||
|
if ( SpawnerList[i]->Get_Definition().IsPrimary &&
|
||
|
SpawnerList[i]->Get_Definition().IsSoldierStartup ) {
|
||
|
|
||
|
index = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (index == -1) {
|
||
|
Debug_Say(("Get_Primary_Spawn_Location: failed to find suitable spawner, return origin.\n"));
|
||
|
return Matrix3D(1);
|
||
|
} else {
|
||
|
return SpawnerList[index]->Get_TM();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Matrix3D SpawnManager::Get_Multiplayer_Spawn_Location( int player_type, SoldierGameObj * soldier )
|
||
|
{
|
||
|
if (player_type == PLAYERTYPE_NEUTRAL) {
|
||
|
//
|
||
|
// Use renegade spawner
|
||
|
//
|
||
|
player_type = PLAYERTYPE_RENEGADE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Find out how many suitable spawners there are
|
||
|
//
|
||
|
int suitable_spawners = 0;
|
||
|
for ( int i = 0; i < SpawnerList.Count(); i++ ) {
|
||
|
if ( !SpawnerList[i]->Get_Definition().IsPrimary &&
|
||
|
SpawnerList[i]->Get_Definition().IsSoldierStartup &&
|
||
|
SpawnerList[i]->Get_Definition().PlayerType == player_type ) {
|
||
|
|
||
|
suitable_spawners++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Matrix3D tm;
|
||
|
|
||
|
if (suitable_spawners == 0) {
|
||
|
Debug_Say(("Get_Multiplayer_Spawn_Location: failed to find suitable spawner, return origin.\n"));
|
||
|
tm = Matrix3D(1);
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Randomly choose one of the suitable spawners
|
||
|
//
|
||
|
int i;
|
||
|
int selected_spawner = rand() % suitable_spawners;
|
||
|
int start_index = 0;
|
||
|
int count = 0;
|
||
|
|
||
|
for ( i = 0; i < SpawnerList.Count(); i++ )
|
||
|
{
|
||
|
if ( !SpawnerList[i]->Get_Definition().IsPrimary &&
|
||
|
SpawnerList[i]->Get_Definition().IsSoldierStartup &&
|
||
|
SpawnerList[i]->Get_Definition().PlayerType == player_type )
|
||
|
{
|
||
|
if (count == selected_spawner)
|
||
|
{
|
||
|
// As a fallback, we will always return the first transform
|
||
|
// that was selected.
|
||
|
tm = SpawnerList[i]->Get_TM();
|
||
|
start_index = i;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
count++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Loop through the entire list of spawners, starting with the one
|
||
|
// we just selected, until we find a clear spawn point for this soldier
|
||
|
//
|
||
|
Phys3Class * phys_obj = soldier->Peek_Human_Phys();
|
||
|
if (phys_obj != NULL) {
|
||
|
for ( i = 0; i < SpawnerList.Count(); i++) {
|
||
|
|
||
|
// Wrap around the list if needed:
|
||
|
int index = (i + start_index) % SpawnerList.Count();
|
||
|
|
||
|
if ( !SpawnerList[index]->Get_Definition().IsPrimary &&
|
||
|
SpawnerList[index]->Get_Definition().IsSoldierStartup &&
|
||
|
SpawnerList[index]->Get_Definition().PlayerType == player_type )
|
||
|
{
|
||
|
if (phys_obj->Can_Teleport(SpawnerList[index]->Get_TM(),true)) {
|
||
|
|
||
|
// Return the first good spawn point we find!
|
||
|
return SpawnerList[index]->Get_TM();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// If we fall through to here, no clear spawn points were found, need more spawners!
|
||
|
WWDEBUG_SAY(("Failed to find clear multiplayer spawn point for object: %s\r\n",phys_obj->Peek_Model()->Get_Name()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Fallback - return the spawn point we randomly chose.
|
||
|
return tm;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
Matrix3D SpawnManager::Get_Ctf_Spawn_Location(int team)
|
||
|
{
|
||
|
WWASSERT(team == PLAYERTYPE_NOD || team == PLAYERTYPE_GDI);
|
||
|
|
||
|
StringClass spawner_name;
|
||
|
if (team == PLAYERTYPE_NOD) {
|
||
|
spawner_name = "Ctf_Pedestal_Nod";
|
||
|
} else {
|
||
|
spawner_name = "Ctf_Pedestal_GDI";
|
||
|
}
|
||
|
|
||
|
int index = -1;
|
||
|
|
||
|
for (int i = 0; i < SpawnerList.Count(); i++) {
|
||
|
if ( !spawner_name.Compare(SpawnerList[i]->Get_Definition().Get_Name()) ) {
|
||
|
index = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//WWASSERT(index != -1);
|
||
|
if (index == -1)
|
||
|
{
|
||
|
Debug_Say(("*** Fatal Media Error: CTF spawner(s) missing from level.\n"));
|
||
|
DIE;
|
||
|
}
|
||
|
|
||
|
return SpawnerList[index]->Get_TM();
|
||
|
}
|
||
|
|
||
|
SpawnerClass * SpawnManager::Get_Primary_Spawner( void )
|
||
|
{
|
||
|
int index = -1;
|
||
|
for (int i = 0; i < SpawnerList.Count(); i++) {
|
||
|
if ( SpawnerList[i]->Get_Definition().IsPrimary &&
|
||
|
SpawnerList[i]->Get_Definition().IsSoldierStartup ) {
|
||
|
|
||
|
index = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (index == -1) {
|
||
|
Debug_Say(("Get_Primary_Spawner: failed to find suitable spawner, returning NULL.\n"));
|
||
|
return NULL;
|
||
|
} else {
|
||
|
return SpawnerList[index];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SpawnManager::Update( void )
|
||
|
{
|
||
|
AutoSpawnTimer += TimeManager::Get_Frame_Seconds();
|
||
|
|
||
|
if ( CombatManager::I_Am_Server() ) {
|
||
|
|
||
|
if (AutoSpawnTimer >= AUTO_SPAWN_CHECK_DELAY ) {
|
||
|
|
||
|
// Let each Spawner Check for Auto Spwan
|
||
|
for ( int i = 0; i < SpawnerList.Count(); i++ ) {
|
||
|
//
|
||
|
// Soldiers are only spawned in missions (SP, coop)
|
||
|
//
|
||
|
if (!SpawnerList[i]->Get_Definition().IsSoldierStartup ||
|
||
|
//CombatManager::Is_Mission()) {
|
||
|
IS_SOLOPLAY) {
|
||
|
SpawnerList[i]->Check_Auto_Spawn( AutoSpawnTimer );
|
||
|
}
|
||
|
}
|
||
|
AutoSpawnTimer = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PhysicalGameObj * SpawnManager::Spawner_Trigger( int id )
|
||
|
{
|
||
|
for ( int i = 0; i < SpawnerList.Count(); i++ ) {
|
||
|
if ( SpawnerList[i]->Get_ID() == id ) {
|
||
|
return SpawnerList[i]->Spawn();
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void SpawnManager::Spawner_Enable( int id, bool enable )
|
||
|
{
|
||
|
for ( int i = 0; i < SpawnerList.Count(); i++ ) {
|
||
|
if ( SpawnerList[i]->Get_ID() == id ) {
|
||
|
if ( enable ) {
|
||
|
// force an immeadiate spawn check
|
||
|
AutoSpawnTimer = AUTO_SPAWN_CHECK_DELAY;
|
||
|
}
|
||
|
SpawnerList[i]->Enable( enable );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SpawnManager::Display_Unused_Spawners( void )
|
||
|
{
|
||
|
Debug_Say(( "Unused Spawner Display....\n" ));
|
||
|
for ( int i = 0; i < SpawnerList.Count(); i++ ) {
|
||
|
if ( SpawnerList[i]->SpawnCount == 0 ) {
|
||
|
Debug_Say(( "Spawner %d never Spawned\n", SpawnerList[i]->Get_ID() ));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool SpawnManager::Toggle_Allow_Killing_Hibernating_Spawn( void )
|
||
|
{
|
||
|
_Allow_Killing_Hibernating_Spawn = !_Allow_Killing_Hibernating_Spawn;
|
||
|
return _Allow_Killing_Hibernating_Spawn;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
* SpawnManager::~SpawnManager -- Class destructor *
|
||
|
* *
|
||
|
* *
|
||
|
* *
|
||
|
* INPUT: Nothing *
|
||
|
* *
|
||
|
* OUTPUT: Nothing *
|
||
|
* *
|
||
|
* WARNINGS: None *
|
||
|
* *
|
||
|
* HISTORY: *
|
||
|
* 6/14/2001 2:27PM ST : Created *
|
||
|
*=============================================================================================*/
|
||
|
SpawnManager::~SpawnManager(void)
|
||
|
{
|
||
|
Remove_All_Spawners();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|