campaign.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commando *
  23. * *
  24. * $Archive:: /Commando/Code/Commando/campaign.cpp $*
  25. * *
  26. * $Author:: Ian_l $*
  27. * *
  28. * $Modtime:: 1/19/02 12:30p $*
  29. * *
  30. * $Revision:: 33 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "campaign.h"
  36. #include "debug.h"
  37. #include "gamemode.h"
  38. #include "gamedata.h"
  39. #include "singlepl.h"
  40. #include "gdsingleplayer.h"
  41. #include "cnetwork.h"
  42. #include "playertype.h"
  43. #include "gameinitmgr.h"
  44. #include "scorescreen.h"
  45. #include "assets.h"
  46. #include "movie.h"
  47. #include "consolefunction.h"
  48. #include "renegadedialogmgr.h"
  49. #include "registry.h"
  50. #include "_globals.h"
  51. #include "crandom.h"
  52. #include "god.h"
  53. #include "dlgloadspgame.h"
  54. #include "ccamera.h"
  55. /*
  56. **
  57. */
  58. int CampaignManager::State = 0;
  59. int CampaignManager::BackdropIndex = 0;
  60. #define CAMPAIGN_INI_FILENAME "campaign.ini"
  61. #define SECTION_CAMPAIGN "Campaign"
  62. #define NOT_IN_CAMPAIGN_STATE -10
  63. #define REPLAY_LEVEL -11
  64. #define REPLAY_SCORE -12
  65. DynamicVectorClass<StringClass> CampaignFlowDescriptions;
  66. struct BackdropDescriptionStruct {
  67. int State;
  68. DynamicVectorClass<StringClass> Lines;
  69. bool operator == (BackdropDescriptionStruct const & rec) const { return false; }
  70. bool operator != (BackdropDescriptionStruct const & rec) const { return true; }
  71. };
  72. DynamicVectorClass<BackdropDescriptionStruct> BackdropDescriptions;
  73. /*
  74. **
  75. */
  76. void CampaignManager::Init( void )
  77. {
  78. State = NOT_IN_CAMPAIGN_STATE;
  79. BackdropIndex = 0;
  80. // Load CAMPAIGN.INI to get campain flow
  81. INIClass * campaignINI = Get_INI( CAMPAIGN_INI_FILENAME );
  82. if (campaignINI != NULL) {
  83. WWASSERT( campaignINI && campaignINI->Section_Count() > 0 );
  84. int count = campaignINI->Entry_Count( SECTION_CAMPAIGN );
  85. for ( int entry = 0; entry < count; entry++ ) {
  86. StringClass description(0,true);
  87. campaignINI->Get_String(description, SECTION_CAMPAIGN, campaignINI->Get_Entry( SECTION_CAMPAIGN, entry) );
  88. CampaignFlowDescriptions.Add( description );
  89. }
  90. // Load Backdrop Descriptions
  91. // Load the first 100, because 90-95 are multiplay.. :)
  92. for ( int state = 0; state < 100; state++ ) {
  93. StringClass section_name;
  94. section_name.Format( "Backdrop%d", state );
  95. int count = campaignINI->Entry_Count( section_name );
  96. if ( count != 0 ) {
  97. int index = BackdropDescriptions.Count();
  98. BackdropDescriptions.Uninitialized_Add();
  99. BackdropDescriptions[index].State = state;
  100. for ( int entry = 0; entry < count; entry++ ) {
  101. StringClass description(0,true);
  102. campaignINI->Get_String(description, section_name, campaignINI->Get_Entry( section_name, entry) );
  103. BackdropDescriptions[index].Lines.Add( description );
  104. }
  105. }
  106. }
  107. Release_INI( campaignINI );
  108. } else {
  109. Debug_Say(("CampaignManager::Init - Unable to load %s\n", CAMPAIGN_INI_FILENAME));
  110. }
  111. }
  112. /*
  113. **
  114. */
  115. void CampaignManager::Shutdown( void )
  116. {
  117. CampaignFlowDescriptions.Clear();
  118. }
  119. /*
  120. **
  121. */
  122. //-----------------------------------------------------------------------------
  123. enum {
  124. CHUNKID_VARIABLES = 906011356,
  125. MICROCHUNK_STATE = 1,
  126. MICROCHUNK_BACKDROP_INDEX,
  127. };
  128. //-----------------------------------------------------------------------------
  129. bool CampaignManager::Save(ChunkSaveClass & csave)
  130. {
  131. csave.Begin_Chunk(CHUNKID_VARIABLES);
  132. WRITE_MICRO_CHUNK(csave, MICROCHUNK_STATE, State);
  133. WRITE_MICRO_CHUNK(csave, MICROCHUNK_BACKDROP_INDEX, BackdropIndex);
  134. csave.End_Chunk();
  135. return true;
  136. }
  137. //-----------------------------------------------------------------------------
  138. bool CampaignManager::Load(ChunkLoadClass &cload)
  139. {
  140. while (cload.Open_Chunk()) {
  141. switch(cload.Cur_Chunk_ID()) {
  142. case CHUNKID_VARIABLES:
  143. while (cload.Open_Micro_Chunk()) {
  144. switch(cload.Cur_Micro_Chunk_ID()) {
  145. READ_MICRO_CHUNK(cload, MICROCHUNK_STATE, State);
  146. READ_MICRO_CHUNK(cload, MICROCHUNK_BACKDROP_INDEX, BackdropIndex);
  147. default:
  148. Debug_Say(( "Unrecognized Campaign Variable chunkID\n" ));
  149. break;
  150. }
  151. cload.Close_Micro_Chunk();
  152. }
  153. break;
  154. default:
  155. Debug_Say(( "Unrecognized campaign chunkID\n" ));
  156. break;
  157. }
  158. cload.Close_Chunk();
  159. }
  160. return true;
  161. }
  162. /*
  163. **
  164. */
  165. void CampaignManager::Start_Campaign( int difficulty )
  166. {
  167. Debug_Say(( "CampaignManager::Start_Campaign( %d )\n", difficulty ));
  168. State = -1;
  169. BackdropIndex = 0;
  170. // Why was this commented out???
  171. CombatManager::Set_Difficulty_Level( difficulty );
  172. StringClass diff_string;
  173. diff_string.Format( "difficulty %d", difficulty );
  174. ConsoleFunctionManager::Parse_Input( diff_string );
  175. cGod::Reset_Inventory();
  176. Continue();
  177. }
  178. /*
  179. **
  180. */
  181. void CampaignManager::Continue( bool success )
  182. {
  183. BackdropIndex = 0;
  184. if ( State == REPLAY_LEVEL ) {
  185. State = REPLAY_SCORE;
  186. // Activeate the Score screen before the combat deactivates, so we can get the stats
  187. ScoreScreenGameModeClass * ss = (ScoreScreenGameModeClass *)GameModeManager::Find ("ScoreScreen");
  188. if ( ss != NULL ) {
  189. ss->Save_Stats();
  190. }
  191. GameModeManager::Find ("Movie")->Deactivate();
  192. GameModeManager::Find ("Combat")->Suspend();
  193. GameInitMgrClass::End_Game();
  194. GameModeManager::Find ("Menu")->Deactivate();
  195. if ( ss != NULL ) {
  196. ss->Activate();
  197. }
  198. return;
  199. }
  200. if ( State == NOT_IN_CAMPAIGN_STATE || State == REPLAY_SCORE || ( State >= CampaignFlowDescriptions.Count() - 1 ) ) {
  201. State = NOT_IN_CAMPAIGN_STATE;
  202. GameModeManager::Find ("Movie")->Deactivate();
  203. GameModeManager::Find ("ScoreScreen")->Deactivate(); // BMG???
  204. GameModeManager::Find ("Combat")->Suspend();
  205. GameInitMgrClass::End_Game();
  206. GameInitMgrClass::Display_End_Game_Menu();
  207. return;
  208. }
  209. State = State+1;
  210. Debug_Say(( "CampaignManager::Continue %d\n", State ));
  211. const char * state_description = CampaignFlowDescriptions[State];
  212. #define StringMatch(a,b) (!::strncmp( a,b,strlen(b) ))
  213. if ( StringMatch( state_description, "Message " ) ) {
  214. state_description += ::strlen( "Message " );
  215. GameModeManager::Find ("Movie")->Deactivate();
  216. GameModeManager::Find ("Combat")->Suspend();
  217. GameInitMgrClass::End_Game();
  218. GameModeManager::Find ("Menu")->Deactivate();
  219. GameModeManager::Find ("ScoreScreen")->Activate();
  220. } else if ( StringMatch( state_description, "Score" ) ) {
  221. state_description += ::strlen( "Score" );
  222. // Activeate the Score screen before the combat deactivates, so we can get the stats
  223. ScoreScreenGameModeClass * ss = (ScoreScreenGameModeClass *)GameModeManager::Find ("ScoreScreen");
  224. if ( ss != NULL ) {
  225. ss->Save_Stats();
  226. }
  227. GameModeManager::Find ("Movie")->Deactivate();
  228. GameModeManager::Find ("Combat")->Suspend();
  229. GameInitMgrClass::End_Game();
  230. GameModeManager::Find ("Menu")->Deactivate();
  231. if ( ss != NULL ) {
  232. ss->Activate();
  233. }
  234. } else if ( StringMatch( state_description, "Level " ) ) {
  235. GameModeManager::Find ("Combat")->Suspend();
  236. GameModeManager::Find ("Movie")->Deactivate();
  237. GameModeManager::Find ("ScoreScreen")->Deactivate ();
  238. GameInitMgrClass::End_Game();
  239. state_description += ::strlen( "Level " );
  240. int mission = cGameData::Get_Mission_Number_From_Map_Name( state_description );
  241. Select_Backdrop_Number( mission );
  242. GameInitMgrClass::Start_Game ( state_description, PLAYERTYPE_RENEGADE, 0 );
  243. // Hack to not autosave for Mission 0 (M13)
  244. if ( ::strnicmp( state_description, "M13", 3 ) != 0 ) {
  245. CombatManager::Request_Autosave();
  246. }
  247. } else if ( StringMatch( state_description, "Movie " ) ) {
  248. if (COMBAT_CAMERA != NULL) {
  249. COMBAT_CAMERA->Set_Host_Model (NULL);
  250. }
  251. GameModeManager::Find ("Combat")->Suspend();
  252. GameInitMgrClass::End_Game();
  253. GameModeManager::Find ("Menu")->Deactivate();
  254. GameModeManager::Find ("ScoreScreen")->Deactivate ();
  255. //
  256. // Parse the parameters
  257. //
  258. int len = ::strlen( state_description );
  259. StringClass foo( len + 1, true );
  260. StringClass filename( len + 1, true );
  261. StringClass description( len + 1, true );
  262. ::sscanf (state_description, "%s %s %s", foo.Peek_Buffer (), filename.Peek_Buffer (), description.Peek_Buffer ());
  263. MovieGameModeClass * mode = (MovieGameModeClass *)GameModeManager::Find ("Movie");
  264. if ( mode ) {
  265. mode->Activate();
  266. mode->Start_Movie( filename );
  267. //
  268. // Add this movie name to the registry (that way the user
  269. // can watch it later)
  270. //
  271. RegistryClass registry( APPLICATION_SUB_KEY_NAME_MOVIES );
  272. if ( registry.Is_Valid() ) {
  273. registry.Set_String( filename, description );
  274. }
  275. }
  276. } else {
  277. Debug_Say(( "Failed to Parse Campaign Description %s\n", state_description ));
  278. State = NOT_IN_CAMPAIGN_STATE;
  279. RenegadeDialogMgrClass::Goto_Location (RenegadeDialogMgrClass::LOC_MAIN_MENU);
  280. }
  281. }
  282. void CampaignManager::Reset()
  283. {
  284. State = NOT_IN_CAMPAIGN_STATE;
  285. }
  286. /*
  287. **
  288. */
  289. void CampaignManager::Replay_Level( const char * mission_name, int difficulty )
  290. {
  291. State = REPLAY_LEVEL;
  292. cGod::Reset_Inventory();
  293. CombatManager::Set_Difficulty_Level( difficulty );
  294. GameInitMgrClass::Start_Game( mission_name, PLAYERTYPE_RENEGADE, 0 );
  295. }
  296. /*
  297. **
  298. */
  299. int CampaignManager::Get_Backdrop_Description_Count( void )
  300. {
  301. if (BackdropDescriptions.Count() > 0) {
  302. return BackdropDescriptions[BackdropIndex].Lines.Count();
  303. }
  304. return 0;
  305. }
  306. const char * CampaignManager::Get_Backdrop_Description( int index )
  307. {
  308. return BackdropDescriptions[BackdropIndex].Lines[index];
  309. }
  310. void CampaignManager::Select_Backdrop_Number( int state_number )
  311. {
  312. // Find Backdrop Index
  313. BackdropIndex = 0;
  314. for ( int i = 0; i < BackdropDescriptions.Count(); i++ ) {
  315. if ( BackdropDescriptions[i].State == state_number ) {
  316. BackdropIndex = i;
  317. }
  318. }
  319. if ( BackdropIndex == 0 ) {
  320. Debug_Say(( "Failed to find load menu for state %d\n", state_number ));
  321. }
  322. }
  323. void CampaignManager::Select_Backdrop_Number_By_MP_Type( int type )
  324. {
  325. //
  326. // Setup Load Menu
  327. //
  328. /*
  329. #define MULTIPLAY_LOAD_MENU_NUMBER_DEATHMATCH 91
  330. #define MULTIPLAY_LOAD_MENU_NUMBER_TEAM_DEATHMATCH 92
  331. #define MULTIPLAY_LOAD_MENU_NUMBER_CTF 93
  332. #define MULTIPLAY_LOAD_MENU_NUMBER_CNC1 94
  333. #define MULTIPLAY_LOAD_MENU_NUMBER_CNC2 95
  334. int load_menu_number = 0;
  335. if ( type == cGameData::GAME_TYPE_DEATHMATCH ) {
  336. load_menu_number = MULTIPLAY_LOAD_MENU_NUMBER_DEATHMATCH;
  337. }
  338. if ( type == cGameData::GAME_TYPE_TEAM_DEATHMATCH ) {
  339. load_menu_number = MULTIPLAY_LOAD_MENU_NUMBER_TEAM_DEATHMATCH;
  340. }
  341. if ( type == cGameData::GAME_TYPE_CNC ) {
  342. load_menu_number = MULTIPLAY_LOAD_MENU_NUMBER_CNC1;
  343. if ( FreeRandom.Get_Int() & 1 ) {
  344. load_menu_number = MULTIPLAY_LOAD_MENU_NUMBER_CNC2;
  345. }
  346. }
  347. Select_Backdrop_Number( load_menu_number );
  348. */
  349. WWASSERT(type == cGameData::GAME_TYPE_CNC);
  350. #define MULTIPLAY_LOAD_MENU_NUMBER_CNC1 94
  351. #define MULTIPLAY_LOAD_MENU_NUMBER_CNC2 95
  352. int load_menu_number = 0;
  353. if (FreeRandom.Get_Int() & 1) {
  354. load_menu_number = MULTIPLAY_LOAD_MENU_NUMBER_CNC1;
  355. } else {
  356. load_menu_number = MULTIPLAY_LOAD_MENU_NUMBER_CNC2;
  357. }
  358. // Select_Backdrop_Number(load_menu_number);
  359. //forget the random screen, alwayds do 94 (BMG 11/24/01)
  360. Select_Backdrop_Number( MULTIPLAY_LOAD_MENU_NUMBER_CNC1 );
  361. }
  362. /*
  363. if ( type == cGameData::GAME_TYPE_CTF ) {
  364. load_menu_number = MULTIPLAY_LOAD_MENU_NUMBER_CTF;
  365. }
  366. */