| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586 |
- /*
- ** 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/>.
- */
- //
- // Filename: god.cpp
- // Author: Tom Spencer-Smith
- // Date: Dec 1998
- // Description: This class handles the creations of players and soldiers.
- //
- #include "god.h"
- #include "cnetwork.h"
- #include "playermanager.h"
- #include "gameobjmanager.h"
- #include "spawn.h"
- #include "playertype.h"
- #include "objlibrary.h"
- #include "soldierobserver.h"
- #include "gametype.h"
- #include "dialogtests.h"
- #include "combatgmode.h"
- #include "gameinitmgr.h"
- #include "scripts.h"
- #include "debug.h"
- #include "renegadedialogmgr.h"
- #include "cheatmgr.h"
- #include "wwmemlog.h"
- #include "dialogmgr.h"
- #include "encyclopediamgr.h"
- #include "wolgmode.h"
- #include "specialbuilds.h"
- #include "demosupport.h"
- /*
- **
- */
- typedef enum {
- GOD_STATE_UNINITIALIZED,
- GOD_STATE_MULTIPLAYER,
- GOD_STATE_EXITING,
- GOD_STATE_SINGLE_INIT,
- GOD_STATE_SINGLE_RUNNING,
- GOD_STATE_SINGLE_DEAD,
- } GodState;
- int cGod::State = GOD_STATE_UNINITIALIZED;
- InventoryClass cGod::LevelStartInventory;
- //-----------------------------------------------------------------------------
- enum {
- CHUNKID_VARIABLES = 112374,
- MICROCHUNK_STATE = 1,
- };
- //-----------------------------------------------------------------------------
- bool cGod::Save(ChunkSaveClass & csave)
- {
- csave.Begin_Chunk(CHUNKID_VARIABLES);
- WRITE_MICRO_CHUNK(csave, MICROCHUNK_STATE, State);
- csave.End_Chunk();
- return true;
- }
- //-----------------------------------------------------------------------------
- bool cGod::Load(ChunkLoadClass &cload)
- {
- while (cload.Open_Chunk()) {
- switch(cload.Cur_Chunk_ID()) {
- case CHUNKID_VARIABLES:
- while (cload.Open_Micro_Chunk()) {
- switch(cload.Cur_Micro_Chunk_ID()) {
- READ_MICRO_CHUNK(cload, MICROCHUNK_STATE, State);
- default:
- Debug_Say(( "Unrecognized cGod Variable chunkID\n" ));
- break;
- }
- cload.Close_Micro_Chunk();
- }
- break;
- default:
- Debug_Say(( "Unrecognized cPlayer chunkID\n" ));
- break;
- }
- cload.Close_Chunk();
- }
- return true;
- }
- //-----------------------------------------------------------------------------
- void cGod::Think(void)
- {
- WWASSERT(cNetwork::I_Am_Server());
- //if (The_Game()->IsIntermission.Is_True()) {
- WWASSERT(PTheGameData != NULL);
- if (The_Game()->IsIntermission.Is_True() ||
- cPlayerManager::Get_Player_Object_List()->Head() == NULL) {
- return;
- }
- if ( State == GOD_STATE_UNINITIALIZED ) {
- //XXX
- State = ( IS_MISSION ) ? GOD_STATE_SINGLE_INIT : GOD_STATE_MULTIPLAYER;
- }
- if ( State == GOD_STATE_SINGLE_INIT ) {
- WWASSERT( cPlayerManager::Get_Player_Object_List()->Head() != NULL );
- // Create a Commando for the Player
- SoldierGameObj * soldier = Create_Commando( cPlayerManager::Get_Player_Object_List()->Head()->Data() );
- const char * script_name = CombatManager::Get_Start_Script();
- ScriptClass* script = ScriptManager::Create_Script( script_name );
- if (script) {
- soldier->Add_Observer( script );
- }
- State = GOD_STATE_SINGLE_RUNNING;
- }
- // This code may need to get cleaned up
- if ( State == GOD_STATE_SINGLE_RUNNING ) {
- //If we just loaded, we may have a play and a solder, but they will not be linked.
- if (cPlayerManager::Get_Player_Object_List() != NULL &&
- cPlayerManager::Get_Player_Object_List()->Head() != NULL ) {
- cPlayer * p_player = cPlayerManager::Get_Player_Object_List()->Head()->Data();
- if ( p_player != NULL ) {
- SmartGameObj * p_soldier = GameObjManager::Find_Soldier_Of_Client_ID(p_player->Get_Id());
- if ( p_soldier && p_player->Get_GameObj() == NULL ) {
- // Remap
- p_soldier->Set_Player_Data( p_player );
- Debug_Say(( "Fixing up player data after load\n" ));
- }
- }
- }
- }
- DEMO_SECURITY_CHECK;
- //
- // Take a look through the player list and create commando bodies
- // for anyone who merits one
- //
- if ( State == GOD_STATE_MULTIPLAYER ) {
- for (
- SLNode<cPlayer> * objnode = cPlayerManager::Get_Player_Object_List()->Head();
- objnode;
- objnode = objnode->Next()) {
- cPlayer * p_player = objnode->Data();
- WWASSERT(p_player != NULL);
- if (p_player->Get_Is_Active().Is_False()) {
- continue;
- }
- if (p_player->Get_Is_In_Game().Is_False()) {
- continue;
- }
- SmartGameObj * p_soldier = GameObjManager::Find_Soldier_Of_Client_ID(p_player->Get_Id());
- if (p_soldier == NULL) {
- //
- // A disembodied player... give him a body
- //
- Create_Commando(p_player);
- }
- }
- }
- }
- //-----------------------------------------------------------------------------
- cPlayer * cGod::Create_Player(int client_id, const WideStringClass & name,
- int team_choice, unsigned long clanID, bool is_invulnerable)
- {
- WWMEMLOG(MEM_NETWORK);
- WWASSERT(cNetwork::I_Am_Server());
- WWASSERT(PTheGameData != NULL);
- WWASSERT(cPlayerManager::Count() < The_Game()->Get_Max_Players());
- //
- // Assign a player type
- //
- cPlayer * p_player = cPlayerManager::Find_Player(name);
- if (p_player != NULL) {
- //
- // I think this can happen when a player crashes out and then rejoins
- // before the server breaks his connection...
- //
- cNetwork::Delete_Player_Objects(p_player->Get_Id());
- } else {
- p_player = cPlayerManager::Find_Inactive_Player(name);
- }
- bool is_new = false;
- if (p_player == NULL) {
- p_player = new cPlayer();
- WWASSERT(p_player != NULL);
- is_new = true;
- p_player->Set_Name(name);
- p_player->Set_Id(client_id);
- p_player->Set_WOL_ClanID(clanID);
- int player_type = The_Game()->Choose_Player_Type(p_player, team_choice, false);
- p_player->Set_Player_Type(player_type);
- } else {
- p_player->Set_Id(client_id);
- p_player->Set_Is_In_Game(true);
- p_player->Set_Is_Waiting_For_Intermission(false);
- }
- p_player->Reset_Join_Time();
- p_player->Invulnerable.Set(is_invulnerable);
- p_player->Set_Is_Active(true);
- //
- // Tell everyone about this guy
- //
- if (is_new) {
- p_player->Init();
- GameModeClass* gameMode = GameModeManager::Find("WOL");
- if (gameMode && gameMode->Is_Active()) {
- WolGameModeClass* wolGame = reinterpret_cast<WolGameModeClass*>(gameMode);
- wolGame->Init_WOL_Player(p_player);
- }
- }
- return p_player;
- }
- //-----------------------------------------------------------------------------
- void cGod::Create_Ai_Player(void)
- {
- WWASSERT(PTheGameData != NULL);
- WWASSERT(cPlayerManager::Count() < The_Game()->Get_Max_Players());
- WWASSERT(cNetwork::I_Am_Server());
- //
- // For id, count downwards from -2.
- //
- int client_id = -1;//SmartGameObj::MOBIUS_CONTROL_OWNER;
- WideStringClass name;
- do {
- client_id--;
- WWASSERT(client_id > cPlayer::INVALID_ID);
- name.Format(L"Guard%d", -client_id);
- } while (cPlayerManager::Is_Player_Present(name));
- Create_Player(client_id, name, -1, 0);
- }
- //-----------------------------------------------------------------------------
- SoldierGameObj * cGod::Create_Commando(int client_id, int player_type/*, int model_num*/)
- {
- WWASSERT(cNetwork::I_Am_Server());
- WWASSERT(player_type >= PLAYERTYPE_NEUTRAL && player_type <= PLAYERTYPE_LAST);
- WWASSERT(PTheGameData != NULL);
- StringClass preset_name;
- preset_name.Format("Commando");
- if (IS_MISSION) {
- #ifndef MULTIPLAYERDEMO
- SpawnerClass * p_spawner = SpawnManager::Get_Primary_Spawner();
- if (p_spawner != NULL) {
- const DynamicVectorClass<int> & def_list = p_spawner->Get_Definition().Get_Spawn_Definition_ID_List();
- WWASSERT(def_list.Count() >= 1);
- PhysicalGameObjDef * p_def = (PhysicalGameObjDef *)DefinitionMgrClass::Find_Definition(def_list[0]);
- if (p_def != NULL) {
- preset_name.Format("%s", p_def->Get_Name());
- }
- }
- #endif // !MULTIPLAYERDEMO
- } else if (The_Game()->Is_Cnc() || The_Game()->Is_Skirmish()) {
- if (player_type == PLAYERTYPE_NOD) {
- preset_name.Format("CnC_Nod_Minigunner_0");
- } else {
- preset_name.Format("CnC_GDI_MiniGunner_0");
- }
- }
- WWASSERT(!preset_name.Is_Empty());
- PhysicalGameObj * p_phys_obj = ObjectLibraryManager::Create_Object(preset_name);
- WWASSERT(p_phys_obj != NULL);
- SoldierGameObj * p_soldier = p_phys_obj->As_SoldierGameObj();
- WWASSERT(p_soldier != NULL);
- WWASSERT(p_soldier->Peek_Physical_Object() != NULL);
- if (IS_SOLOPLAY) {
- // Setup initial health depending on difficulty level
- float max = 100.0f;
- switch ( CombatManager::Get_Difficulty_Level() ) {
- case 0: max = 200; break;
- case 1: max = 100; break;
- case 2: max = 75; break;
- };
- p_soldier->Get_Defense_Object()->Set_Health_Max( max );
- p_soldier->Get_Defense_Object()->Set_Health( max );
- p_soldier->Get_Defense_Object()->Set_Shield_Strength_Max( max );
- p_soldier->Get_Defense_Object()->Set_Shield_Strength( max );
- }
- Matrix3D transform;
- if (IS_MISSION && player_type == PLAYERTYPE_GDI) {
- transform = SpawnManager::Get_Primary_Spawn_Location();
- } else {
- transform = SpawnManager::Get_Multiplayer_Spawn_Location(player_type,p_soldier);
- }
- p_soldier->Set_Transform(transform);
- p_soldier->Set_Control_Owner(client_id);
- cPlayer * player = cPlayerManager::Find_Player( client_id );
- p_soldier->Set_Player_Data( player );
- if ( The_Game()->Remember_Inventory() ) {
- if (IS_MISSION) {
- cGod::Restore_Inventory( p_soldier );
- }
- }
- p_soldier->Set_Player_Type(player_type);
- //
- // TSS082901 - We cannot remove all observers - there may be scripts granting
- // initial weapons. Instead, make sure the presets don't UseInnateBehavior
- //
- //p_soldier->Remove_All_Observers();
- if (!p_soldier->Is_Human_Controlled()) {
- //
- // Add an observer to do innate AI
- //
- p_soldier->Set_Innate_Observer(new SoldierObserverClass);
- p_soldier->Add_Observer(p_soldier->Get_Innate_Observer());
- }
- //
- // Added this 090401
- //
- p_soldier->Start_Observers();
- The_Game()->Soldier_Added(p_soldier);
- if (cNetwork::I_Am_Client() && client_id == cNetwork::Get_My_Id()) {
- ActionParamsStruct parameters;
- WWASSERT(p_soldier->Get_Action() != NULL);
- p_soldier->Get_Action()->Follow_Input(parameters);
- CombatManager::Set_The_Star(p_soldier);
- //
- // Let the cheat manager apply its cheats to the new player
- //
- CheatMgrClass::Get_Instance()->Apply_Cheats();
- #ifdef WWDEBUG
- Reinitialize_Ai_On_Star();
- #endif // WWDEBUG
- }
- return p_soldier;
- }
- //-----------------------------------------------------------------------------
- SoldierGameObj * cGod::Create_Commando(cPlayer * p_player)
- {
- WWASSERT(cNetwork::I_Am_Server());
- WWASSERT(p_player != NULL);
- int client_id = p_player->Get_Id();
- int player_type = p_player->Get_Player_Type();
- //int model_num = p_player->Get_Model();
- return Create_Commando(client_id, player_type/*, model_num*/);
- }
- //-----------------------------------------------------------------------------
- void cGod::Create_Grunt(Vector3 & pos)
- {
- WWASSERT(cNetwork::I_Am_Server());
- int client_id = SmartGameObj::SERVER_CONTROL_OWNER;
- WWASSERT(PTheGameData != NULL);
- int player_type = The_Game()->Choose_Player_Type(NULL, -1, true);
- //int model_num = rand() % NUM_MP_PLAYABLE_MODELS;
- SoldierGameObj * p_soldier = Create_Commando(
- client_id, player_type/*, model_num*/);
- WWASSERT(p_soldier != NULL);
- p_soldier->Set_Position(pos);
- p_soldier->Perturb_Position();
- }
- //-----------------------------------------------------------------------------
- #ifdef WWDEBUG
- void cGod::Reinitialize_Ai_On_Star(void)
- {
- WWASSERT(cNetwork::I_Am_Client());
- SmartGameObj * p_my_soldier = GameObjManager::Find_Soldier_Of_Client_ID(cNetwork::Get_My_Id());
- if (p_my_soldier != NULL) {
- //
- // Remove any innate observers
- //
- const GameObjObserverList & observer_list = p_my_soldier->Get_Observers();
- for (int index = 0; index < observer_list.Count(); index++) {
- if (!stricmp(observer_list[index]->Get_Name(), "Innate Soldier")) {
- p_my_soldier->Remove_Observer(observer_list[index]);
- break; // probably not safe to continue
- }
- }
- cPlayer * p_player = cNetwork::Get_My_Player_Object();
- WWASSERT(p_player != NULL);
- ActionParamsStruct parameters;
- WWASSERT(p_my_soldier->Get_Action() != NULL);
- p_my_soldier->Get_Action()->Follow_Input(parameters);
- CombatManager::Set_Is_Star_Determining_Target(true);
- }
- }
- #endif // WWDEBUG
- //-----------------------------------------------------------------------------
- Matrix3D _StarRespawnTM;
- InventoryClass _DeathInventory;
- void cGod::Reset( void )
- {
- State = GOD_STATE_UNINITIALIZED;
- }
- void cGod::Exit( void )
- {
- State = GOD_STATE_EXITING;
- }
- void cGod::Star_Killed( void )
- {
- if ( State == GOD_STATE_SINGLE_RUNNING ) {
- State = GOD_STATE_SINGLE_DEAD;
- WWDEBUG_SAY(( "Star Killed\n" ));
- _DeathInventory.Store_Inventory( COMBAT_STAR );
- _StarRespawnTM = COMBAT_STAR->Get_Transform();
- DeathOptionsPopupClass * popup = new DeathOptionsPopupClass;
- popup->Start_Dialog();
- popup->Release_Ref();
- } else if ( State == GOD_STATE_MULTIPLAYER ) {
- if (GameModeManager::Find ("Combat")->Is_Active ()) {
- if (GameModeManager::Find ("Menu")->Is_Active ()) {
- GameModeManager::Find ("Menu")->Deactivate ();
- } else {
- DialogMgrClass::Flush_Dialogs ();
- }
- }
- }
- }
- void cGod::Respawn( void )
- {
- WWASSERT( State == GOD_STATE_SINGLE_DEAD );
- SoldierGameObj * soldier = Create_Commando( cPlayerManager::Get_Player_Object_List()->Head()->Data() );
- soldier->Set_Transform( _StarRespawnTM );
- _DeathInventory.Restore_Inventory( soldier );
- const char * script_name = CombatManager::Get_Respawn_Script();
- ScriptClass* script = ScriptManager::Create_Script( script_name );
- if (script) {
- soldier->Add_Observer( script );
- }
- State = GOD_STATE_SINGLE_RUNNING;
- }
- void cGod::Restart( void )
- {
- if ( State == GOD_STATE_SINGLE_DEAD ) {
- // WWASSERT( State == GOD_STATE_SINGLE_DEAD );
- State = GOD_STATE_SINGLE_RUNNING; // Incase we get a second call!
- ((CombatGameModeClass *)GameModeManager::Find("Combat"))->Core_Restart();
- //
- // Reset the player's stats
- //
- cPlayer *player_info = cPlayerManager::Get_Player_Object_List()->Head()->Data();
- if ( player_info != NULL ) {
- player_info->Stats_Reset();
- }
- SoldierGameObj * soldier = Create_Commando( player_info );
- const char * script_name = CombatManager::Get_Start_Script();
- ScriptClass* script = ScriptManager::Create_Script( script_name );
- if (script) {
- soldier->Add_Observer( script );
- }
- State = GOD_STATE_SINGLE_RUNNING; // restart makes it exit
- }
- }
- void cGod::Load_Game( void )
- {
- WWASSERT( State == GOD_STATE_SINGLE_DEAD );
- GameInitMgrClass::End_Game();
- RenegadeDialogMgrClass::Goto_Location (RenegadeDialogMgrClass::LOC_LOAD_GAME);
- }
- void cGod::Mission_Failed( void )
- {
- if ( State == GOD_STATE_SINGLE_RUNNING ) {
- State = GOD_STATE_SINGLE_DEAD;
- WWDEBUG_SAY(( "Mission Failed\n" ));
- FailedOptionsPopupClass * popup = new FailedOptionsPopupClass;
- popup->Start_Dialog();
- popup->Release_Ref();
- }
- }
- void cGod::Store_Inventory( SoldierGameObj * soldier )
- {
- LevelStartInventory.Store_Inventory( soldier );
- EncyclopediaMgrClass::Store_Data();
- return ;
- }
- void cGod::Restore_Inventory( SoldierGameObj * soldier )
- {
- LevelStartInventory.Restore_Inventory( soldier );
- EncyclopediaMgrClass::Restore_Data();
- return ;
- }
- void cGod::Reset_Inventory( void )
- {
- LevelStartInventory.Reset();
- }
|