CampaignManager.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. /*
  2. ** Command & Conquer Generals(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. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: CampaignManager.cpp /////////////////////////////////////////////////
  24. //-----------------------------------------------------------------------------
  25. //
  26. // Electronic Arts Pacific.
  27. //
  28. // Confidential Information
  29. // Copyright (C) 2002 - All Rights Reserved
  30. //
  31. //-----------------------------------------------------------------------------
  32. //
  33. // created: Jul 2002
  34. //
  35. // Filename: CampaignManager.cpp
  36. //
  37. // author: Chris Huybregts
  38. //
  39. // purpose: The flow of the campaigns are stored up in here!
  40. //
  41. //-----------------------------------------------------------------------------
  42. ///////////////////////////////////////////////////////////////////////////////
  43. //-----------------------------------------------------------------------------
  44. // SYSTEM INCLUDES ////////////////////////////////////////////////////////////
  45. //-----------------------------------------------------------------------------
  46. //-----------------------------------------------------------------------------
  47. // USER INCLUDES //////////////////////////////////////////////////////////////
  48. //-----------------------------------------------------------------------------
  49. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  50. #include "Common/INI.h"
  51. #include "Common/Xfer.h"
  52. #include "GameClient/CampaignManager.h"
  53. #include "GameClient/GameClient.h"
  54. //-----------------------------------------------------------------------------
  55. // DEFINES ////////////////////////////////////////////////////////////////////
  56. //-----------------------------------------------------------------------------
  57. CampaignManager *TheCampaignManager = NULL;
  58. const FieldParse CampaignManager::m_campaignFieldParseTable[] =
  59. {
  60. { "Mission", CampaignManager::parseMissionPart, NULL, NULL },
  61. { "FirstMission", INI::parseAsciiString, NULL, offsetof( Campaign, m_firstMission ) },
  62. { "CampaignNameLabel", INI::parseAsciiString, NULL, offsetof( Campaign, m_campaignNameLabel ) },
  63. { "FinalVictoryMovie", INI::parseAsciiString, NULL, offsetof( Campaign, m_finalMovieName ) },
  64. { NULL, NULL, NULL, 0 } // keep this last
  65. };
  66. //-----------------------------------------------------------------------------
  67. // PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
  68. //-----------------------------------------------------------------------------
  69. //-----------------------------------------------------------------------------
  70. void INI::parseCampaignDefinition( INI *ini )
  71. {
  72. AsciiString name;
  73. Campaign *campaign;
  74. // read the name
  75. const char* c = ini->getNextToken();
  76. name.set( c );
  77. // find existing item if present
  78. DEBUG_ASSERTCRASH( TheCampaignManager, ("parseCampaignDefinition: Unable to Get TheCampaignManager\n") );
  79. if( !TheCampaignManager )
  80. return;
  81. // If we have a previously allocated Campaign
  82. campaign = TheCampaignManager->newCampaign( name );
  83. // sanity
  84. DEBUG_ASSERTCRASH( campaign, ("parseCampaignDefinition: Unable to allocate campaign '%s'\n", name.str()) );
  85. // parse the ini definition
  86. ini->initFromINI( campaign, TheCampaignManager->getFieldParse() );
  87. } // end parseCampaignDefinition
  88. //-----------------------------------------------------------------------------
  89. Campaign::Campaign( void )
  90. {
  91. m_missions.clear();
  92. m_firstMission.clear();
  93. m_name.clear();
  94. m_finalMovieName.clear();
  95. }
  96. //-----------------------------------------------------------------------------
  97. Campaign::~Campaign( void )
  98. {
  99. MissionListIt it = m_missions.begin();
  100. while(it != m_missions.end())
  101. {
  102. Mission *mission = *it;
  103. it = m_missions.erase( it );
  104. if(mission)
  105. mission->deleteInstance();
  106. }
  107. }
  108. AsciiString Campaign::getFinalVictoryMovie( void )
  109. {
  110. return m_finalMovieName;
  111. }
  112. //-----------------------------------------------------------------------------
  113. Mission *Campaign::newMission( AsciiString name )
  114. {
  115. MissionListIt it;
  116. it = m_missions.begin();
  117. name.toLower();
  118. while(it != m_missions.end())
  119. {
  120. Mission *mission = *it;
  121. if(mission->m_name.compare(name) == 0)
  122. {
  123. m_missions.erase( it );
  124. mission->deleteInstance();
  125. break;
  126. }
  127. else
  128. ++it;
  129. }
  130. Mission *newMission = newInstance(Mission);
  131. newMission->m_name.set(name);
  132. m_missions.push_back(newMission);
  133. return newMission;
  134. }
  135. //-----------------------------------------------------------------------------
  136. Mission *Campaign::getMission( AsciiString missionName )
  137. {
  138. if(missionName.isEmpty())
  139. return NULL;
  140. MissionListIt it;
  141. it = m_missions.begin();
  142. // we've reached the end of the campaign
  143. while(it != m_missions.end())
  144. {
  145. Mission *mission = *it;
  146. if(mission->m_name.compare(missionName) == 0)
  147. return mission;
  148. ++it;
  149. }
  150. DEBUG_ASSERTCRASH(FALSE, ("getMission couldn't find %s", missionName.str()));
  151. return NULL;
  152. }
  153. //-----------------------------------------------------------------------------
  154. Mission *Campaign::getNextMission( Mission *current)
  155. {
  156. AsciiString name;
  157. //if passed a Null pointer, load the first mission
  158. if(!current)
  159. {
  160. name = m_firstMission;
  161. }
  162. else
  163. name = current->m_nextMission;
  164. name.toLower();
  165. MissionListIt it;
  166. it = m_missions.begin();
  167. // we've reached the end of the campaign
  168. if(name.isEmpty())
  169. return NULL;
  170. while(it != m_missions.end())
  171. {
  172. Mission *mission = *it;
  173. if(mission->m_name.compare(name) == 0)
  174. return mission;
  175. ++it;
  176. }
  177. // DEBUG_ASSERTCRASH(FALSE, ("GetNextMission couldn't find %s", current->m_nextMission.str()));
  178. return NULL;
  179. }
  180. //-----------------------------------------------------------------------------
  181. CampaignManager::CampaignManager( void )
  182. {
  183. m_campaignList.clear();
  184. m_currentCampaign = NULL;
  185. m_currentMission = NULL;
  186. m_victorious = FALSE;
  187. m_currentRankPoints = 0;
  188. m_difficulty = DIFFICULTY_NORMAL;
  189. }
  190. //-----------------------------------------------------------------------------
  191. CampaignManager::~CampaignManager( void )
  192. {
  193. m_currentCampaign = NULL;
  194. m_currentMission = NULL;
  195. CampaignListIt it = m_campaignList.begin();
  196. while(it != m_campaignList.end())
  197. {
  198. Campaign *campaign = *it;
  199. it = m_campaignList.erase( it );
  200. if(campaign)
  201. campaign->deleteInstance();
  202. }
  203. }
  204. //-----------------------------------------------------------------------------
  205. void CampaignManager::init( void )
  206. {
  207. INI ini;
  208. // Read from INI all the CampaignManager
  209. ini.load( AsciiString( "Data\\INI\\Campaign.ini" ), INI_LOAD_OVERWRITE, NULL );
  210. }
  211. //-----------------------------------------------------------------------------
  212. Campaign *CampaignManager::getCurrentCampaign( void )
  213. {
  214. return m_currentCampaign;
  215. }
  216. //-----------------------------------------------------------------------------
  217. Mission *CampaignManager::getCurrentMission( void )
  218. {
  219. return m_currentMission;
  220. }
  221. //-----------------------------------------------------------------------------
  222. Mission *CampaignManager::gotoNextMission( void )
  223. {
  224. if (!m_currentCampaign || !m_currentMission)
  225. return NULL;
  226. m_currentMission = m_currentCampaign->getNextMission(m_currentMission);
  227. return m_currentMission;
  228. }
  229. //-----------------------------------------------------------------------------
  230. void CampaignManager::setCampaignAndMission( AsciiString campaign, AsciiString mission )
  231. {
  232. if(mission.isEmpty())
  233. {
  234. setCampaign(campaign);
  235. return;
  236. }
  237. CampaignListIt it;
  238. it = m_campaignList.begin();
  239. campaign.toLower();
  240. while ( it != m_campaignList.end())
  241. {
  242. Campaign *camp = *it;
  243. if(camp->m_name.compare(campaign) == 0)
  244. {
  245. m_currentCampaign = camp;
  246. m_currentMission = camp->getMission( mission );
  247. return;
  248. }
  249. ++it;
  250. }
  251. }
  252. //-----------------------------------------------------------------------------
  253. void CampaignManager::setCampaign( AsciiString campaign )
  254. {
  255. CampaignListIt it;
  256. it = m_campaignList.begin();
  257. campaign.toLower();
  258. while ( it != m_campaignList.end())
  259. {
  260. Campaign *camp = *it;
  261. if(camp->m_name.compare(campaign) == 0)
  262. {
  263. m_currentCampaign = camp;
  264. m_currentMission = camp->getNextMission( NULL );
  265. return;
  266. }
  267. ++it;
  268. }
  269. // could not find the mission. we are resetting the missions to nothing.
  270. m_currentCampaign = NULL;
  271. m_currentMission = NULL;
  272. m_currentRankPoints = 0;
  273. m_difficulty = DIFFICULTY_NORMAL;
  274. }
  275. //-----------------------------------------------------------------------------
  276. AsciiString CampaignManager::getCurrentMap( void )
  277. {
  278. if(!m_currentMission)
  279. return AsciiString::TheEmptyString;
  280. return m_currentMission->m_mapName;
  281. }
  282. // ------------------------------------------------------------------------------------------------
  283. /** Return the 0 based mission number */
  284. // ------------------------------------------------------------------------------------------------
  285. Int CampaignManager::getCurrentMissionNumber( void )
  286. {
  287. Int number = INVALID_MISSION_NUMBER;
  288. if( m_currentCampaign )
  289. {
  290. Campaign::MissionListIt it;
  291. for( it = m_currentCampaign->m_missions.begin();
  292. it != m_currentCampaign->m_missions.end();
  293. ++it )
  294. {
  295. number++;
  296. if( *it == m_currentMission )
  297. return number;
  298. }
  299. }
  300. return number;
  301. }
  302. //-----------------------------------------------------------------------------
  303. void CampaignManager::parseMissionPart( INI* ini, void *instance, void *store, const void *userData )
  304. {
  305. static const FieldParse myFieldParse[] =
  306. {
  307. { "Map", INI::parseAsciiString, NULL, offsetof( Mission, m_mapName ) },
  308. { "NextMission", INI::parseAsciiString, NULL, offsetof( Mission, m_nextMission ) },
  309. { "IntroMovie", INI::parseAsciiString, NULL, offsetof( Mission, m_movieLabel ) },
  310. { "ObjectiveLine0", INI::parseAsciiString, NULL, offsetof( Mission, m_missionObjectivesLabel[0] ) },
  311. { "ObjectiveLine1", INI::parseAsciiString, NULL, offsetof( Mission, m_missionObjectivesLabel[1] ) },
  312. { "ObjectiveLine2", INI::parseAsciiString, NULL, offsetof( Mission, m_missionObjectivesLabel[2] ) },
  313. { "ObjectiveLine3", INI::parseAsciiString, NULL, offsetof( Mission, m_missionObjectivesLabel[3] ) },
  314. { "ObjectiveLine4", INI::parseAsciiString, NULL, offsetof( Mission, m_missionObjectivesLabel[4] ) },
  315. { "BriefingVoice", INI::parseAudioEventRTS, NULL, offsetof( Mission, m_briefingVoice ) },
  316. { "UnitNames0", INI::parseAsciiString, NULL, offsetof( Mission, m_unitNames[0] ) },
  317. { "UnitNames1", INI::parseAsciiString, NULL, offsetof( Mission, m_unitNames[1] ) },
  318. { "UnitNames2", INI::parseAsciiString, NULL, offsetof( Mission, m_unitNames[2] ) },
  319. { "LocationNameLabel",INI::parseAsciiString, NULL, offsetof( Mission, m_locationNameLabel ) },
  320. { "VoiceLength", INI::parseInt , NULL, offsetof( Mission, m_voiceLength ) },
  321. { NULL, NULL, NULL, 0 } // keep this last
  322. };
  323. AsciiString name;
  324. const char* c = ini->getNextToken();
  325. name.set( c );
  326. Mission *mission = ((Campaign*)instance)->newMission(name );
  327. ini->initFromINI(mission, myFieldParse);
  328. }
  329. //-----------------------------------------------------------------------------
  330. Campaign *CampaignManager::newCampaign(AsciiString name)
  331. {
  332. CampaignListIt it;
  333. it = m_campaignList.begin();
  334. name.toLower();
  335. while(it != m_campaignList.end())
  336. {
  337. Campaign *campaign = *it;
  338. if(campaign->m_name.compare(name) == 0)
  339. {
  340. m_campaignList.erase( it );
  341. campaign->deleteInstance();
  342. break;
  343. }
  344. else
  345. ++it;
  346. }
  347. Campaign *newCampaign = newInstance(Campaign);
  348. newCampaign->m_name.set(name);
  349. m_campaignList.push_back(newCampaign);
  350. return newCampaign;
  351. }
  352. // ------------------------------------------------------------------------------------------------
  353. /** Xfer method
  354. * Version Info
  355. * 1: Initial version
  356. * 2: Added RankPoints Saving*/
  357. // ------------------------------------------------------------------------------------------------
  358. void CampaignManager::xfer( Xfer *xfer )
  359. {
  360. // version
  361. const XferVersion currentVersion = 3;
  362. XferVersion version = currentVersion;
  363. xfer->xferVersion( &version, currentVersion );
  364. // current campaign
  365. AsciiString currentCampaign;
  366. if( m_currentCampaign )
  367. currentCampaign = m_currentCampaign->m_name;
  368. xfer->xferAsciiString( &currentCampaign );
  369. // current mission
  370. AsciiString currentMission;
  371. if( m_currentMission )
  372. currentMission = m_currentMission->m_name;
  373. xfer->xferAsciiString( &currentMission );
  374. // version 2 and above has rank points!
  375. if(version >= 2)
  376. xfer->xferInt( &m_currentRankPoints );
  377. if(version >= 3)
  378. xfer->xferUser( &m_difficulty, sizeof(m_difficulty) );
  379. // when loading, need to set the current campaign and mission
  380. if( xfer->getXferMode() == XFER_LOAD )
  381. setCampaignAndMission( currentCampaign, currentMission );
  382. } // end xfer
  383. //-----------------------------------------------------------------------------
  384. // PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
  385. //-----------------------------------------------------------------------------
  386. //-----------------------------------------------------------------------------
  387. Mission::Mission( void )
  388. {
  389. m_voiceLength = 0;
  390. }
  391. //-----------------------------------------------------------------------------
  392. Mission::~Mission( void )
  393. {
  394. }