| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090 |
- /*
- ** 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();
- }
|