SAVELOAD.CPP 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563
  1. /*
  2. ** Command & Conquer Red Alert(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. /* $Header: /counterstrike/SAVELOAD.CPP 9 3/17/97 1:04a Steve_tall $ */
  19. /***********************************************************************************************
  20. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Command & Conquer *
  24. * *
  25. * File Name : SAVELOAD.CPP *
  26. * *
  27. * Programmer : Joe L. Bostic *
  28. * *
  29. * Start Date : August 23, 1994 *
  30. * *
  31. * Last Update : July 8, 1996 [JLB] *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * Code_All_Pointers -- Code all pointers. *
  36. * Decode_All_Pointers -- Decodes all pointers. *
  37. * Get_Savefile_Info -- gets description, scenario #, house *
  38. * Load_Game -- loads a saved game *
  39. * Load_MPlayer_Values -- Loads multiplayer-specific values *
  40. * Load_Misc_Values -- loads miscellaneous variables *
  41. * MPlayer_Save_Message -- pops up a "saving..." message *
  42. * Put_All -- Store all save game data to the pipe. *
  43. * Reconcile_Players -- Reconciles loaded data with the 'Players' vector *
  44. * Save_Game -- saves a game to disk *
  45. * Save_MPlayer_Values -- Saves multiplayer-specific values *
  46. * Save_Misc_Values -- saves miscellaneous variables *
  47. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  48. #include "function.h"
  49. #include "vortex.h"
  50. #ifdef WIN32
  51. #include "tcpip.h"
  52. #include "ccdde.h"
  53. //#include "WolDebug.h"
  54. extern bool SpawnedFromWChat;
  55. #endif
  56. //#define SAVE_BLOCK_SIZE 512
  57. #define SAVE_BLOCK_SIZE 4096
  58. //#define SAVE_BLOCK_SIZE 1024
  59. /*
  60. ********************************** Defines **********************************
  61. */
  62. #define SAVEGAME_VERSION (DESCRIP_MAX + \
  63. 0x01000006 + ( \
  64. sizeof(AircraftClass) + \
  65. sizeof(AircraftTypeClass) + \
  66. sizeof(AnimClass) + \
  67. sizeof(AnimTypeClass) + \
  68. sizeof(BaseClass) + \
  69. sizeof(BuildingClass) + \
  70. sizeof(BuildingTypeClass) + \
  71. sizeof(BulletClass) + \
  72. sizeof(BulletTypeClass) + \
  73. sizeof(CellClass) + \
  74. sizeof(FactoryClass) + \
  75. sizeof(HouseClass) + \
  76. sizeof(HouseTypeClass) + \
  77. sizeof(InfantryClass) + \
  78. sizeof(InfantryTypeClass) + \
  79. sizeof(LayerClass) + \
  80. sizeof(MouseClass) + \
  81. sizeof(OverlayClass) + \
  82. sizeof(OverlayTypeClass) + \
  83. sizeof(SmudgeClass) + \
  84. sizeof(SmudgeTypeClass) + \
  85. sizeof(TeamClass) + \
  86. sizeof(TeamTypeClass) + \
  87. sizeof(TemplateClass) + \
  88. sizeof(TemplateTypeClass) + \
  89. sizeof(TerrainClass) + \
  90. sizeof(TerrainTypeClass) + \
  91. sizeof(TriggerClass) + \
  92. sizeof(TriggerTypeClass) + \
  93. sizeof(UnitClass) + \
  94. sizeof(UnitTypeClass) + \
  95. sizeof(VesselClass) + \
  96. sizeof(ScenarioClass) + \
  97. sizeof(ChronalVortexClass)))
  98. // sizeof(Waypoint)))
  99. static int Reconcile_Players(void);
  100. extern bool Is_Mission_Counterstrike (char *file_name);
  101. #ifdef FIXIT_CSII // checked - ajw 9/28/98
  102. extern bool Is_Mission_Aftermath (char *file_name);
  103. #endif
  104. /***********************************************************************************************
  105. * Put_All -- Store all save game data to the pipe. *
  106. * *
  107. * This is the bulk processor of the game related save game data. All the game object *
  108. * and state data is stored to the pipe specified. *
  109. * *
  110. * INPUT: pipe -- Reference to the pipe that will receive the save game data. *
  111. * *
  112. * OUTPUT: none *
  113. * *
  114. * WARNINGS: none *
  115. * *
  116. * HISTORY: *
  117. * 07/08/1996 JLB : Created. *
  118. *=============================================================================================*/
  119. static void Put_All(Pipe & pipe, int save_net)
  120. {
  121. /*
  122. ** Save the scenario global information.
  123. */
  124. pipe.Put(&Scen, sizeof(Scen));
  125. /*
  126. ** Save the map. The map must be saved first, since it saves the Theater.
  127. */
  128. if (!save_net) Call_Back();
  129. Map.Save(pipe);
  130. if (!save_net) Call_Back();
  131. /*
  132. ** Save all game objects. This code saves every object that's stored in a
  133. ** TFixedIHeap class.
  134. */
  135. Houses.Save(pipe);
  136. if (!save_net) Call_Back();
  137. TeamTypes.Save(pipe);
  138. if (!save_net) Call_Back();
  139. Teams.Save(pipe);
  140. if (!save_net) Call_Back();
  141. TriggerTypes.Save(pipe);
  142. if (!save_net) Call_Back();
  143. Triggers.Save(pipe);
  144. if (!save_net) Call_Back();
  145. Aircraft.Save(pipe);
  146. if (!save_net) Call_Back();
  147. Anims.Save(pipe);
  148. if (!save_net) Call_Back();
  149. Buildings.Save(pipe);
  150. if (!save_net) Call_Back();
  151. Bullets.Save(pipe);
  152. if (!save_net) Call_Back();
  153. Infantry.Save(pipe);
  154. if (!save_net) Call_Back();
  155. Overlays.Save(pipe);
  156. if (!save_net) Call_Back();
  157. Smudges.Save(pipe);
  158. if (!save_net) Call_Back();
  159. Templates.Save(pipe);
  160. if (!save_net) Call_Back();
  161. Terrains.Save(pipe);
  162. if (!save_net) Call_Back();
  163. Units.Save(pipe);
  164. if (!save_net) Call_Back();
  165. Factories.Save(pipe);
  166. if (!save_net) Call_Back();
  167. Vessels.Save(pipe);
  168. if (!save_net) Call_Back();
  169. /*
  170. ** Save the Logic & Map layers
  171. */
  172. Logic.Save(pipe);
  173. int count = MapTriggers.Count();
  174. pipe.Put(&count, sizeof(count));
  175. for (int index = 0; index < MapTriggers.Count(); index++) {
  176. TARGET target = MapTriggers[index]->As_Target();
  177. pipe.Put(&target, sizeof(target));
  178. }
  179. if (!save_net) Call_Back();
  180. count = LogicTriggers.Count();
  181. pipe.Put(&count, sizeof(count));
  182. for (index = 0; index < LogicTriggers.Count(); index++) {
  183. TARGET target = LogicTriggers[index]->As_Target();
  184. pipe.Put(&target, sizeof(target));
  185. }
  186. if (!save_net) Call_Back();
  187. for (HousesType h = HOUSE_FIRST; h < HOUSE_COUNT; h++) {
  188. count = HouseTriggers[h].Count();
  189. pipe.Put(&count, sizeof(count));
  190. for (index = 0; index < HouseTriggers[h].Count(); index++) {
  191. TARGET target = HouseTriggers[h][index]->As_Target();
  192. pipe.Put(&target, sizeof(target));
  193. }
  194. }
  195. if (!save_net) Call_Back();
  196. for (int i = 0; i < LAYER_COUNT; i++) {
  197. Map.Layer[i].Save(pipe);
  198. }
  199. if (!save_net) Call_Back();
  200. /*
  201. ** Save the Score
  202. */
  203. pipe.Put(&Score, sizeof(Score));
  204. if (!save_net) Call_Back();
  205. /*
  206. ** Save the AI Base
  207. */
  208. Base.Save(pipe);
  209. if (!save_net) Call_Back();
  210. /*
  211. ** Save out the carry over list (if present). First see how
  212. ** many carry over objects are in the list.
  213. */
  214. int carry_count = 0;
  215. CarryoverClass const * cptr = Carryover;
  216. while (cptr != NULL) {
  217. carry_count++;
  218. cptr = (CarryoverClass const *)cptr->Get_Next();
  219. }
  220. if (!save_net) Call_Back();
  221. /*
  222. ** Save out the number of objects in the list.
  223. */
  224. pipe.Put(&carry_count, sizeof(carry_count));
  225. if (!save_net) Call_Back();
  226. /*
  227. ** Now write out the objects themselves.
  228. */
  229. CarryoverClass const * object_to_write = Carryover;
  230. while (object_to_write != NULL) {
  231. pipe.Put(object_to_write, sizeof(*object_to_write));
  232. object_to_write = (CarryoverClass const *)object_to_write->Get_Next();
  233. }
  234. if (!save_net) Call_Back();
  235. /*
  236. ** Save miscellaneous variables.
  237. */
  238. Save_Misc_Values(pipe);
  239. if (!save_net) Call_Back();
  240. /*
  241. ** Save multiplayer values
  242. */
  243. if (save_net) {
  244. Save_MPlayer_Values(pipe);
  245. }
  246. pipe.Flush();
  247. }
  248. /***************************************************************************
  249. * Save_Game -- saves a game to disk *
  250. * *
  251. * Saving the Map: *
  252. * DisplayClass::Save() invokes CellClass's Write() for every cell *
  253. * that needs to be saved. A cell needs to be saved if it contains *
  254. * any special data at all, such as a TIcon, or an Occupier. *
  255. * The cell saves its own CellTrigger pointer, converted to a TARGET. *
  256. * *
  257. * Saving game objects: *
  258. * - Any object stored in an ArrayOf class needs to be saved. The ArrayOf*
  259. * Save() routine invokes each object's Write() routine, if that *
  260. * object's IsActive is set. *
  261. * *
  262. * Saving the layers: *
  263. * The Map's Layers (Ground, Air, etc) of things that are on the map, *
  264. * and the Logic's Layer of things to process both need to be saved. *
  265. * LayerClass::Save() writes the entire layer array to disk *
  266. * *
  267. * Saving the houses: *
  268. * Each house needs to be saved, to record its Credits, Power, etc. *
  269. * *
  270. * Saving miscellaneous data: *
  271. * There are a lot of miscellaneous variables to save, such as the *
  272. * map's dimensions, the player's house, etc. *
  273. * *
  274. * INPUT: *
  275. * id numerical ID, for the file extension *
  276. * *
  277. * OUTPUT: *
  278. * true = OK, false = error *
  279. * *
  280. * WARNINGS: *
  281. * none. *
  282. * *
  283. * HISTORY: *
  284. * 12/28/1994 BR : Created. *
  285. * 02/27/1996 JLB : Uses simpler game control value save operation. *
  286. *=========================================================================*/
  287. bool Save_Game(int id, char const * descr, bool )
  288. {
  289. char name[_MAX_FNAME+_MAX_EXT];
  290. unsigned scenario;
  291. HousesType house;
  292. int save_net = 0; // 1 = save network/modem game
  293. scenario = Scen.Scenario; // get current scenario #
  294. house = PlayerPtr->Class->House; // get current house
  295. /*
  296. ** Generate the filename to save. If 'id' is -1, it means save a
  297. ** network/modem game; otherwise, use 'id' as the file extension.
  298. */
  299. if (id==-1) {
  300. strcpy(name, NET_SAVE_FILE_NAME);
  301. save_net = 1;
  302. } else {
  303. sprintf(name, "SAVEGAME.%03d", id);
  304. }
  305. /*
  306. ** Code everybody's pointers
  307. */
  308. Code_All_Pointers();
  309. /*
  310. ** Open the file
  311. */
  312. BufferIOFileClass file(name);
  313. FilePipe fpipe(&file);
  314. /*
  315. ** Save the description, scenario #, and house
  316. ** (scenario # & house are saved separately from the actual Scenario &
  317. ** PlayerPtr globals for convenience; we can quickly find out which
  318. ** house & scenario this save-game file is for by reading these values.
  319. ** Also, PlayerPtr is stored in a coded form in Save_Misc_Values(),
  320. ** which may or may not be a HousesType number; so, saving 'house'
  321. ** here ensures we can always pull out the house for this file.)
  322. */
  323. char descr_buf[DESCRIP_MAX];
  324. memset(descr_buf, '\0', sizeof(descr_buf));
  325. sprintf(descr_buf, "%s\r\n", descr); // put CR-LF after text
  326. descr_buf[strlen(descr_buf) + 1] = 26; // put CTRL-Z after NULL
  327. fpipe.Put(descr_buf, DESCRIP_MAX);
  328. fpipe.Put(&scenario, sizeof(scenario));
  329. fpipe.Put(&house, sizeof(house));
  330. /*
  331. ** Save the save-game version, for loading verification
  332. */
  333. unsigned long version = SAVEGAME_VERSION;
  334. #ifdef FIXIT_CSII // checked - ajw 9/28/98
  335. version++;
  336. #endif
  337. fpipe.Put(&version, sizeof(version));
  338. int pos = file.Seek(0, SEEK_CUR);
  339. /*
  340. ** Store a dummy message digest.
  341. */
  342. char digest[20];
  343. fpipe.Put(digest, sizeof(digest));
  344. /*
  345. ** Dump the save game data to the file. The data is compressed
  346. ** and then encrypted. The message digest is calculated in the
  347. ** process by using the data just as it is written to disk.
  348. */
  349. SHAPipe sha;
  350. BlowPipe bpipe(BlowPipe::ENCRYPT);
  351. LZOPipe pipe(LZOPipe::COMPRESS, SAVE_BLOCK_SIZE);
  352. // LZWPipe pipe(LZWPipe::COMPRESS, SAVE_BLOCK_SIZE);
  353. // LCWPipe pipe(LCWPipe::COMPRESS, SAVE_BLOCK_SIZE);
  354. bpipe.Key(&FastKey, BlowfishEngine::MAX_KEY_LENGTH);
  355. sha.Put_To(fpipe);
  356. bpipe.Put_To(sha);
  357. pipe.Put_To(bpipe);
  358. Put_All(pipe, save_net);
  359. /*
  360. ** Output the real final message digest. This is the one that is of
  361. ** the data image as it exists on the disk.
  362. */
  363. pipe.Flush();
  364. file.Seek(pos, SEEK_SET);
  365. sha.Result(digest);
  366. fpipe.Put(digest, sizeof(digest));
  367. pipe.End();
  368. Decode_All_Pointers();
  369. return(true);
  370. }
  371. /***************************************************************************
  372. * Load_Game -- loads a saved game *
  373. * *
  374. * This routine loads the data in the same way it was saved out. *
  375. * *
  376. * Loading the Map: *
  377. * - DisplayClass::Load() invokes CellClass's Load() for every cell *
  378. * that was saved. *
  379. * - The cell loads its own CellTrigger pointer. *
  380. * *
  381. * Loading game objects: *
  382. * - IHeap's Load() routine loads the # of objects stored, and loads *
  383. * each object. *
  384. * - Triggers: Add themselves to the HouseTriggers if they're associated *
  385. * with a house *
  386. * *
  387. * Loading the layers: *
  388. * LayerClass::Load() reads the entire layer array to disk *
  389. * *
  390. * Loading the houses: *
  391. * Each house is loaded in its entirety. *
  392. * *
  393. * Loading miscellaneous data: *
  394. * There are a lot of miscellaneous variables to load, such as the *
  395. * map's dimensions, the player's house, etc. *
  396. * *
  397. * INPUT: *
  398. * id numerical ID, for the file extension *
  399. * *
  400. * OUTPUT: *
  401. * true = OK, false = error *
  402. * *
  403. * WARNINGS: *
  404. * If this routine returns false, the entire game will be in an *
  405. * unknown state, so the scenario will have to be re-initialized. *
  406. * *
  407. * HISTORY: *
  408. * 12/28/1994 BR : Created. *
  409. * 1/20/97 V.Grippi Added expansion CD check *
  410. *=========================================================================*/
  411. bool Load_Game(int id)
  412. {
  413. char name[_MAX_FNAME+_MAX_EXT];
  414. int i;
  415. unsigned scenario;
  416. HousesType house;
  417. char descr_buf[DESCRIP_MAX];
  418. int load_net = 0; // 1 = save network/modem game
  419. /*
  420. ** Generate the filename to load. If 'id' is -1, it means save a
  421. ** network/modem game; otherwise, use 'id' as the file extension.
  422. */
  423. if (id == -1) {
  424. strcpy(name, NET_SAVE_FILE_NAME);
  425. load_net = 1;
  426. } else {
  427. sprintf(name, "SAVEGAME.%03d", id);
  428. }
  429. /*
  430. ** Open the file
  431. */
  432. RawFileClass file(name);
  433. if (!file.Is_Available()) {
  434. return(false);
  435. }
  436. FileStraw fstraw(file);
  437. Call_Back();
  438. /*
  439. ** Read & discard the save-game's header info
  440. */
  441. if (fstraw.Get(descr_buf, DESCRIP_MAX) != DESCRIP_MAX) {
  442. return(false);
  443. }
  444. if (fstraw.Get(&scenario, sizeof(scenario)) != sizeof(scenario)) {
  445. return(false);
  446. }
  447. if (fstraw.Get(&house, sizeof(house)) != sizeof(house)) {
  448. return(false);
  449. }
  450. /*
  451. ** Read in & verify the save-game ID code
  452. */
  453. unsigned long version;
  454. if (fstraw.Get(&version, sizeof(version)) != sizeof(version)) {
  455. return(false);
  456. }
  457. GameVersion = version;
  458. #ifdef FIXIT_CSII // checked - ajw 9/28/98
  459. if (version != SAVEGAME_VERSION && ((version-1) != SAVEGAME_VERSION) ) {
  460. return(false);
  461. }
  462. #else
  463. if (version != SAVEGAME_VERSION /*&& version != 0x0100616D*/){
  464. return(false);
  465. }
  466. #endif
  467. /*
  468. ** Get the message digest that is embedded in the file.
  469. */
  470. char digest[20];
  471. fstraw.Get(digest, sizeof(digest));
  472. /*
  473. ** Remember the file position since we must seek back here to
  474. ** perform the real saved game read.
  475. */
  476. long pos = file.Seek(0, SEEK_CUR);
  477. /*
  478. ** Pass the rest of the file through the hash straw so that
  479. ** the digest can be compaired to the one in the file.
  480. */
  481. SHAStraw sha;
  482. sha.Get_From(fstraw);
  483. for (;;) {
  484. if (sha.Get(_staging_buffer, sizeof(_staging_buffer)) != sizeof(_staging_buffer)) break;
  485. }
  486. char actual[20];
  487. sha.Result(actual);
  488. sha.Get_From(NULL);
  489. Call_Back();
  490. /*
  491. ** Compare the two digests. If they differ then return a failure condition
  492. ** before any damage could be done.
  493. */
  494. if (memcmp(actual, digest, sizeof(digest)) != 0) {
  495. return(false);
  496. }
  497. /*
  498. ** Set up the pipe so that the scenario data can be read.
  499. */
  500. file.Seek(pos, SEEK_SET);
  501. BlowStraw bstraw(BlowStraw::DECRYPT);
  502. LZOStraw straw(LZOStraw::DECOMPRESS, SAVE_BLOCK_SIZE);
  503. // LZWStraw straw(LZWStraw::DECOMPRESS, SAVE_BLOCK_SIZE);
  504. // LCWStraw straw(LCWStraw::DECOMPRESS, SAVE_BLOCK_SIZE);
  505. bstraw.Key(&FastKey, BlowfishEngine::MAX_KEY_LENGTH);
  506. bstraw.Get_From(fstraw);
  507. straw.Get_From(bstraw);
  508. /*
  509. ** Clear the scenario so we start fresh; this calls the Init_Clear() routine
  510. ** for the Map, and all object arrays. It has the following important
  511. ** effects:
  512. ** - Every cell is cleared to 0's, via MapClass::Init_Clear()
  513. ** - All heap elements' are cleared
  514. ** - The Houses are Initialized, which also clears their HouseTriggers
  515. ** array
  516. ** - The map's Layers & Logic Layer are cleared to empty
  517. ** - The list of currently-selected objects is cleared
  518. */
  519. Clear_Scenario();
  520. /*
  521. ** Load the scenario global information.
  522. */
  523. straw.Get(&Scen, sizeof(Scen));
  524. /*
  525. ** Fixup the Sessionclass scenario info so we can work out which
  526. ** CD to request later
  527. */
  528. if ( load_net ){
  529. CCFileClass scenario_file (Scen.ScenarioName);
  530. if ( !scenario_file.Is_Available() ){
  531. int cd = -1;
  532. if (Is_Mission_Counterstrike (Scen.ScenarioName)) {
  533. cd = 2;
  534. #ifdef FIXIT_CSII // checked - ajw 9/28/98
  535. if (Expansion_AM_Present()) {
  536. int current_drive = CCFileClass::Get_CD_Drive();
  537. int index = Get_CD_Index(current_drive, 1*60);
  538. if (index == 3) cd = 3;
  539. }
  540. #endif
  541. }
  542. #ifdef FIXIT_CSII // checked - ajw 9/28/98
  543. if (Is_Mission_Aftermath (Scen.ScenarioName)) {
  544. cd = 3;
  545. #ifdef BOGUSCD
  546. cd = -1;
  547. #endif
  548. }
  549. #endif
  550. RequiredCD = cd;
  551. if (!Force_CD_Available (RequiredCD)) {
  552. Emergency_Exit(EXIT_FAILURE);
  553. }
  554. /*
  555. ** Update the internal list of scenarios to include the counterstrike
  556. ** list.
  557. */
  558. Session.Read_Scenario_Descriptions();
  559. } else {
  560. /*
  561. ** The scenario is available so set RequiredCD to whatever is currently
  562. ** in the drive.
  563. */
  564. int current_drive = CCFileClass::Get_CD_Drive();
  565. RequiredCD = Get_CD_Index(current_drive, 1*60);
  566. }
  567. }
  568. /*
  569. ** Load the map. The map comes first, since it loads the Theater & init's
  570. ** mixfiles. The map calls all the type-class's Init routines, telling them
  571. ** what the Theater is; this must be done before any objects are created, so
  572. ** they'll be properly created.
  573. */
  574. Map.Load(straw);
  575. Call_Back();
  576. /*
  577. ** Load the object data.
  578. */
  579. Houses.Load(straw);
  580. TeamTypes.Load(straw);
  581. Teams.Load(straw);
  582. TriggerTypes.Load(straw);
  583. Triggers.Load(straw);
  584. Aircraft.Load(straw);
  585. Anims.Load(straw);
  586. Buildings.Load(straw);
  587. Bullets.Load(straw);
  588. Call_Back();
  589. Infantry.Load(straw);
  590. Overlays.Load(straw);
  591. Smudges.Load(straw);
  592. Templates.Load(straw);
  593. Terrains.Load(straw);
  594. Units.Load(straw);
  595. Factories.Load(straw);
  596. Vessels.Load(straw);
  597. /*
  598. ** Load the Logic & Map Layers
  599. */
  600. Logic.Load(straw);
  601. int count;
  602. straw.Get(&count, sizeof(count));
  603. MapTriggers.Clear();
  604. for (int index = 0; index < count; index++) {
  605. TARGET target;
  606. straw.Get(&target, sizeof(target));
  607. MapTriggers.Add(As_Trigger(target));
  608. }
  609. straw.Get(&count, sizeof(count));
  610. LogicTriggers.Clear();
  611. for (index = 0; index < count; index++) {
  612. TARGET target;
  613. straw.Get(&target, sizeof(target));
  614. LogicTriggers.Add(As_Trigger(target));
  615. }
  616. for (HousesType h = HOUSE_FIRST; h < HOUSE_COUNT; h++) {
  617. straw.Get(&count, sizeof(count));
  618. HouseTriggers[h].Clear();
  619. for (index = 0; index < count; index++) {
  620. TARGET target;
  621. straw.Get(&target, sizeof(target));
  622. HouseTriggers[h].Add(As_Trigger(target));
  623. }
  624. }
  625. for (i = 0; i < LAYER_COUNT; i++) {
  626. Map.Layer[i].Load(straw);
  627. }
  628. Call_Back();
  629. /*
  630. ** Load the Score
  631. */
  632. straw.Get(&Score, sizeof(Score));
  633. new(&Score) ScoreClass(NoInitClass());
  634. /*
  635. ** Load the AI Base
  636. */
  637. Base.Load(straw);
  638. /*
  639. ** Delete any carryover pseudo-saved game list.
  640. */
  641. while (Carryover != NULL) {
  642. CarryoverClass * cptr = (CarryoverClass *)Carryover->Get_Next();
  643. Carryover->Remove();
  644. delete Carryover;
  645. Carryover = cptr;
  646. }
  647. /*
  648. ** Load any carryover pseudo-saved game list.
  649. */
  650. int carry_count = 0;
  651. straw.Get(&carry_count, sizeof(carry_count));
  652. while (carry_count) {
  653. CarryoverClass * cptr = new CarryoverClass;
  654. assert(cptr != NULL);
  655. straw.Get(cptr, sizeof(CarryoverClass));
  656. new (cptr) CarryoverClass(NoInitClass());
  657. cptr->Zap();
  658. if (!Carryover) {
  659. Carryover = cptr;
  660. } else {
  661. cptr->Add_Tail(*Carryover);
  662. }
  663. carry_count--;
  664. }
  665. Call_Back();
  666. /*
  667. ** Load miscellaneous variables, including the map size & the Theater
  668. */
  669. Load_Misc_Values(straw);
  670. /*
  671. ** Load multiplayer values
  672. */
  673. if (load_net) {
  674. Load_MPlayer_Values(straw);
  675. }
  676. file.Close();
  677. Decode_All_Pointers();
  678. Map.Init_IO();
  679. Map.Flag_To_Redraw(true);
  680. /*
  681. ** Fixup any expediency data that can be inferred from the physical
  682. ** data loaded.
  683. */
  684. Post_Load_Game(load_net);
  685. Call_Back();
  686. /*
  687. ** Set the required CD to be in the drive according to the scenario
  688. ** loaded.
  689. */
  690. if (RequiredCD != -2 && !load_net) {
  691. #ifdef FIXIT_ANTS
  692. /*
  693. ** Determines if this an ant mission. Since the ant mission looks no different from
  694. ** a regular mission, examining of the scenario name is the only way to tell.
  695. */
  696. if (toupper(Scen.ScenarioName[0]) == 'S' &&
  697. toupper(Scen.ScenarioName[1]) == 'C' &&
  698. toupper(Scen.ScenarioName[2]) == 'A' &&
  699. toupper(Scen.ScenarioName[3]) == '0' &&
  700. toupper(Scen.ScenarioName[5]) == 'E' &&
  701. toupper(Scen.ScenarioName[6]) == 'A') {
  702. AntsEnabled = true;
  703. } else{
  704. AntsEnabled = false;
  705. }
  706. #endif
  707. if (Scen.Scenario == 1) {
  708. RequiredCD = -1;
  709. } else {
  710. #ifdef FIXIT_ANTS
  711. if (Scen.Scenario > 19 || AntsEnabled) {
  712. RequiredCD = 2;
  713. #ifdef FIXIT_CSII // checked - ajw 9/28/98
  714. if(Scen.Scenario >= 36) {
  715. RequiredCD = 3;
  716. #ifdef BOGUSCD
  717. RequiredCD = -1;
  718. #endif
  719. }
  720. #endif
  721. } else {
  722. #endif //FIXIT_ANTS
  723. if (PlayerPtr->Class->House != HOUSE_USSR && PlayerPtr->Class->House != HOUSE_UKRAINE) {
  724. RequiredCD = 0;
  725. } else {
  726. RequiredCD = 1;
  727. }
  728. #ifdef FIXIT_ANTS
  729. }
  730. #endif //FIXIT_ANTS
  731. }
  732. }else{
  733. if ( load_net ){
  734. CCFileClass scenario_file (Scen.ScenarioName);
  735. /*
  736. ** Fix up the session class variables
  737. */
  738. for ( int s=0 ; s<Session.Scenarios.Count() ; s++ ) {
  739. if (Session.Scenarios[s]->Description() == Scen.Description){
  740. memcpy (Session.Options.ScenarioDescription, Scen.Description,
  741. sizeof (Session.Options.ScenarioDescription));
  742. memcpy (Session.ScenarioFileName, Scen.ScenarioName,
  743. sizeof (Session.ScenarioFileName));
  744. Session.ScenarioFileLength = scenario_file.Size();
  745. memcpy (Session.ScenarioDigest, Session.Scenarios[s]->Get_Digest(),
  746. sizeof (Session.ScenarioDigest));
  747. Session.ScenarioIsOfficial = Session.Scenarios[s]->Get_Official();
  748. Scen.Scenario = s;
  749. Session.Options.ScenarioIndex = s;
  750. break;
  751. }
  752. }
  753. }
  754. }
  755. if (!Force_CD_Available(RequiredCD)) {
  756. //Prog_End();
  757. Emergency_Exit(EXIT_FAILURE);
  758. }
  759. ScenarioInit = 0;
  760. if (load_net) {
  761. if (!Reconcile_Players()) { // (must do after Decode pointers)
  762. return(false);
  763. }
  764. //!!!!!!!!!! put Fixup_Player_Units() here
  765. Session.LoadGame = true;
  766. }
  767. Map.Reload_Sidebar(); // re-load sidebar art.
  768. /*
  769. ** Rescan the scenario file for any rules updates.
  770. */
  771. CCINIClass ini;
  772. int result = ini.Load(CCFileClass(Scen.ScenarioName), true);
  773. /*
  774. ** Reset the rules values to their initial settings.
  775. */
  776. Rule.General(RuleINI);
  777. Rule.Recharge(RuleINI);
  778. Rule.AI(RuleINI);
  779. Rule.Powerups(RuleINI);
  780. Rule.Land_Types(RuleINI);
  781. Rule.Themes(RuleINI);
  782. Rule.IQ(RuleINI);
  783. Rule.Objects(RuleINI);
  784. Rule.Difficulty(RuleINI);
  785. #ifdef FIXIT_CSII // checked - ajw 9/28/98 - But does this incorporate *changes*? - NO.
  786. Rule.General(AftermathINI);
  787. Rule.Recharge(AftermathINI);
  788. Rule.AI(AftermathINI);
  789. Rule.Powerups(AftermathINI);
  790. Rule.Land_Types(AftermathINI);
  791. Rule.Themes(AftermathINI);
  792. Rule.IQ(AftermathINI);
  793. Rule.Objects(AftermathINI);
  794. Rule.Difficulty(AftermathINI);
  795. #endif
  796. /*
  797. ** Override any rules values specified in this
  798. ** particular scenario file.
  799. */
  800. Rule.General(ini);
  801. Rule.Recharge(ini);
  802. Rule.AI(ini);
  803. Rule.Powerups(ini);
  804. Rule.Land_Types(ini); \
  805. Rule.Themes(ini);
  806. Rule.IQ(ini);
  807. Rule.Objects(ini);
  808. Rule.Difficulty(ini);
  809. #ifdef FIXIT_CSII // ajw - Added runtime check for Aftermath to skirmish mode.
  810. if (load_net) {
  811. bool readini = false;
  812. switch(Session.Type) {
  813. case GAME_NORMAL:
  814. readini = false;
  815. break;
  816. case GAME_SKIRMISH:
  817. readini = Is_Aftermath_Installed();
  818. break;
  819. default:
  820. #ifdef FIXIT_VERSION_3
  821. readini = bAftermathMultiplayer;
  822. #else
  823. if (PlayingAgainstVersion >= VERSION_AFTERMATH_CS) {
  824. readini = true;
  825. }
  826. #endif
  827. break;
  828. }
  829. if(readini) {
  830. /*
  831. ** Find out if the CD in the current drive is the Aftermath disc.
  832. */
  833. if(Get_CD_Index(CCFileClass::Get_CD_Drive(), 1*60) != 3) {
  834. GamePalette.Set(FADE_PALETTE_FAST, Call_Back);
  835. if (!Force_CD_Available(3)) { // force Aftermath CD in drive.
  836. //Prog_End();
  837. #ifndef FIXIT_VERSION_3 // WChat eliminated.
  838. #ifdef WIN32
  839. if(Special.IsFromWChat || SpawnedFromWChat) {
  840. char packet[10] = {"Hello"};
  841. Send_Data_To_DDE_Server (packet, strlen(packet), DDEServerClass::DDE_CONNECTION_FAILED);
  842. }
  843. #endif
  844. #endif
  845. Emergency_Exit(EXIT_FAILURE);
  846. }
  847. }
  848. CCINIClass mpini;
  849. if (mpini.Load(CCFileClass("MPLAYER.INI"), false)) {
  850. Rule.General(mpini);
  851. Rule.Recharge(mpini);
  852. Rule.AI(mpini);
  853. Rule.Powerups(mpini);
  854. Rule.Land_Types(mpini);
  855. Rule.Themes(mpini);
  856. Rule.IQ(mpini);
  857. Rule.Objects(mpini);
  858. Rule.Difficulty(mpini);
  859. }
  860. }
  861. }
  862. #endif
  863. if (Scen.TransitTheme == THEME_NONE) {
  864. Theme.Queue_Song(THEME_FIRST);
  865. } else {
  866. Theme.Queue_Song(Scen.TransitTheme);
  867. }
  868. return(true);
  869. }
  870. /***************************************************************************
  871. * Save_Misc_Values -- saves miscellaneous variables *
  872. * *
  873. * INPUT: *
  874. * file file to use for writing *
  875. * *
  876. * OUTPUT: *
  877. * true = success, false = failure *
  878. * *
  879. * WARNINGS: *
  880. * none. *
  881. * *
  882. * HISTORY: *
  883. * 12/29/1994 BR : Created. *
  884. * 03/12/1996 JLB : Simplified. *
  885. *=========================================================================*/
  886. bool Save_Misc_Values(Pipe & file)
  887. {
  888. int i;
  889. int count; // # ptrs in 'CurrentObject'
  890. ObjectClass * ptr; // for saving 'CurrentObject' ptrs
  891. /*
  892. ** Player's House.
  893. */
  894. int x = PlayerPtr->Class->House;
  895. file.Put(&x, sizeof(x));
  896. /*
  897. ** Save frame #.
  898. */
  899. file.Put(&Frame, sizeof(Frame));
  900. /*
  901. ** Save currently-selected objects list.
  902. ** Save the # of ptrs in the list.
  903. */
  904. count = CurrentObject.Count();
  905. file.Put(&count, sizeof(count));
  906. /*
  907. ** Save the pointers.
  908. */
  909. for (i = 0; i < count; i++) {
  910. ptr = CurrentObject[i];
  911. file.Put(&ptr, sizeof(ptr));
  912. }
  913. /*
  914. ** Save the chronal vortex
  915. */
  916. ChronalVortex.Save(file);
  917. /*
  918. ** Save Tanya flags.
  919. */
  920. file.Put(&IsTanyaDead, sizeof(IsTanyaDead));
  921. file.Put(&SaveTanya, sizeof(SaveTanya));
  922. return(true);
  923. }
  924. /***********************************************************************************************
  925. * Load_Misc_Values -- Loads miscellaneous variables. *
  926. * *
  927. * INPUT: file -- The file to load the misc values from. *
  928. * *
  929. * OUTPUT: Was the misc load process successful? *
  930. * *
  931. * WARNINGS: none *
  932. * *
  933. * HISTORY: *
  934. * 06/24/1995 BRR : Created. *
  935. * 03/12/1996 JLB : Simplified. *
  936. *=============================================================================================*/
  937. bool Load_Misc_Values(Straw & file)
  938. {
  939. ObjectClass * ptr; // for loading 'CurrentObject' ptrs
  940. /*
  941. ** Player's House.
  942. */
  943. int x;
  944. file.Get(&x, sizeof(x));
  945. // file.Get(&PlayerPtr, sizeof(PlayerPtr));
  946. PlayerPtr = HouseClass::As_Pointer((HousesType)x);
  947. /*
  948. ** Load frame #.
  949. */
  950. file.Get(&Frame, sizeof(Frame));
  951. /*
  952. ** Load currently-selected objects list.
  953. ** Load the # of ptrs in the list.
  954. */
  955. int count; // # ptrs in 'CurrentObject'
  956. file.Get(&count, sizeof(count));
  957. /*
  958. ** Load the pointers.
  959. */
  960. for (int i = 0; i < count; i++) {
  961. file.Get(&ptr, sizeof(ptr));
  962. CurrentObject.Add(ptr); // add to the list
  963. }
  964. /*
  965. ** Load the chronal vortex
  966. */
  967. ChronalVortex.Load(file);
  968. /*
  969. ** Save Tanya flags.
  970. */
  971. file.Get(&IsTanyaDead, sizeof(IsTanyaDead));
  972. file.Get(&SaveTanya, sizeof(SaveTanya));
  973. return(true);
  974. }
  975. /***************************************************************************
  976. * Save_MPlayer_Values -- Saves multiplayer-specific values *
  977. * *
  978. * This routine saves multiplayer values that need to be restored for a *
  979. * save game. In addition to saving the random # seed for this scenario, *
  980. * it saves the contents of the actual random number generator; this *
  981. * ensures that the random # sequencer will pick up where it left off when *
  982. * the game was saved. *
  983. * This routine also saves the header for a Recording file, so it must *
  984. * save some data not needed specifically by a save-game file (ie Seed). *
  985. * *
  986. * INPUT: *
  987. * file file to save to *
  988. * *
  989. * OUTPUT: *
  990. * true = success, false = failure *
  991. * *
  992. * WARNINGS: *
  993. * none. *
  994. * *
  995. * HISTORY: *
  996. * 09/28/1995 BRR : Created. *
  997. *=========================================================================*/
  998. bool Save_MPlayer_Values(Pipe & file)
  999. {
  1000. Session.Save(file);
  1001. file.Put(&BuildLevel, sizeof(BuildLevel));
  1002. file.Put(&Debug_Unshroud, sizeof(Debug_Unshroud));
  1003. file.Put(&Seed, sizeof(Seed));
  1004. file.Put(&Whom, sizeof(Whom));
  1005. file.Put(&Special, sizeof(SpecialClass));
  1006. file.Put(&Options, sizeof(GameOptionsClass));
  1007. return (true);
  1008. }
  1009. /***************************************************************************
  1010. * Load_MPlayer_Values -- Loads multiplayer-specific values *
  1011. * *
  1012. * INPUT: *
  1013. * file file to load from *
  1014. * *
  1015. * OUTPUT: *
  1016. * true = success, false = failure *
  1017. * *
  1018. * WARNINGS: *
  1019. * none. *
  1020. * *
  1021. * HISTORY: *
  1022. * 09/28/1995 BRR : Created. *
  1023. *=========================================================================*/
  1024. bool Load_MPlayer_Values(Straw & file)
  1025. {
  1026. Session.Load(file);
  1027. file.Get(&BuildLevel, sizeof(BuildLevel));
  1028. file.Get(&Debug_Unshroud, sizeof(Debug_Unshroud));
  1029. file.Get(&Seed, sizeof(Seed));
  1030. file.Get(&Whom, sizeof(Whom));
  1031. file.Get(&Special, sizeof(SpecialClass));
  1032. file.Get(&Options, sizeof(GameOptionsClass));
  1033. return (true);
  1034. }
  1035. /***********************************************************************************************
  1036. * Code_All_Pointers -- Code all pointers. *
  1037. * *
  1038. * INPUT: none *
  1039. * *
  1040. * OUTPUT: none *
  1041. * *
  1042. * WARNINGS: none *
  1043. * *
  1044. * HISTORY: *
  1045. * 06/24/1995 BRR : Created. *
  1046. *=============================================================================================*/
  1047. void Code_All_Pointers(void)
  1048. {
  1049. int i;
  1050. /*
  1051. ** The Map.
  1052. */
  1053. Map.Code_Pointers();
  1054. /*
  1055. ** The ArrayOf's.
  1056. */
  1057. TeamTypes.Code_Pointers();
  1058. Teams.Code_Pointers();
  1059. Triggers.Code_Pointers();
  1060. Aircraft.Code_Pointers();
  1061. Anims.Code_Pointers();
  1062. Buildings.Code_Pointers();
  1063. Bullets.Code_Pointers();
  1064. Infantry.Code_Pointers();
  1065. Overlays.Code_Pointers();
  1066. Smudges.Code_Pointers();
  1067. Templates.Code_Pointers();
  1068. Terrains.Code_Pointers();
  1069. Units.Code_Pointers();
  1070. Factories.Code_Pointers();
  1071. Vessels.Code_Pointers();
  1072. /*
  1073. ** The Layers.
  1074. */
  1075. Logic.Code_Pointers();
  1076. for (i = 0; i < LAYER_COUNT; i++) {
  1077. Map.Layer[i].Code_Pointers();
  1078. }
  1079. /*
  1080. ** The Score.
  1081. */
  1082. Score.Code_Pointers();
  1083. /*
  1084. ** The Base.
  1085. */
  1086. Base.Code_Pointers();
  1087. /*
  1088. ** PlayerPtr.
  1089. */
  1090. // PlayerPtr = (HouseClass *)(PlayerPtr->Class->House);
  1091. /*
  1092. ** Currently-selected objects.
  1093. */
  1094. for (i = 0; i < CurrentObject.Count(); i++) {
  1095. CurrentObject[i] = (ObjectClass *)CurrentObject[i]->As_Target();
  1096. }
  1097. /*
  1098. ** Houses must be coded last, because the Class->House member of the HouseClass
  1099. ** is used to code HouseClass pointers for all other objects, and if Class is
  1100. ** coded, it will point to a meaningless value.
  1101. */
  1102. Houses.Code_Pointers();
  1103. }
  1104. /***********************************************************************************************
  1105. * Decode_All_Pointers -- Decodes all pointers. *
  1106. * *
  1107. * INPUT: none *
  1108. * *
  1109. * OUTPUT: none *
  1110. * *
  1111. * WARNINGS: none *
  1112. * *
  1113. * HISTORY: *
  1114. * 06/24/1995 BRR : Created. *
  1115. *=============================================================================================*/
  1116. void Decode_All_Pointers(void)
  1117. {
  1118. /*
  1119. ** The Map.
  1120. */
  1121. Map.Decode_Pointers();
  1122. /*
  1123. ** Decode houses first, so we can properly decode all other objects'
  1124. ** House pointers
  1125. */
  1126. Houses.Decode_Pointers();
  1127. /*
  1128. ** The ArrayOf's.
  1129. */
  1130. TeamTypes.Decode_Pointers();
  1131. Teams.Decode_Pointers();
  1132. Triggers.Decode_Pointers();
  1133. Aircraft.Decode_Pointers();
  1134. Anims.Decode_Pointers();
  1135. Buildings.Decode_Pointers();
  1136. Bullets.Decode_Pointers();
  1137. Infantry.Decode_Pointers();
  1138. Overlays.Decode_Pointers();
  1139. Smudges.Decode_Pointers();
  1140. Templates.Decode_Pointers();
  1141. Terrains.Decode_Pointers();
  1142. Units.Decode_Pointers();
  1143. Factories.Decode_Pointers();
  1144. Vessels.Decode_Pointers();
  1145. /*
  1146. ** The Layers.
  1147. */
  1148. Logic.Decode_Pointers();
  1149. for (int i = 0; i < LAYER_COUNT; i++) {
  1150. Map.Layer[i].Decode_Pointers();
  1151. }
  1152. /*
  1153. ** The Score.
  1154. */
  1155. Score.Decode_Pointers();
  1156. /*
  1157. ** The Base.
  1158. */
  1159. Base.Decode_Pointers();
  1160. /*
  1161. ** PlayerPtr.
  1162. */
  1163. // PlayerPtr = HouseClass::As_Pointer((HousesType)PlayerPtr);
  1164. Whom = PlayerPtr->Class->House;
  1165. assert(PlayerPtr != NULL);
  1166. /*
  1167. ** Currently-selected objects.
  1168. */
  1169. for (int index = 0; index < CurrentObject.Count(); index++) {
  1170. CurrentObject[index] = As_Object((TARGET)CurrentObject[index]);
  1171. assert(CurrentObject[index] != NULL);
  1172. }
  1173. /*
  1174. ** Last-Minute Fixups; to resolve these pointers properly requires all other
  1175. ** pointers to be loaded & decoded.
  1176. */
  1177. if (Map.PendingObjectPtr) {
  1178. Map.PendingObject = &Map.PendingObjectPtr->Class_Of();
  1179. assert(Map.PendingObject != NULL);
  1180. Map.Set_Cursor_Shape(Map.PendingObject->Occupy_List(true));
  1181. #ifdef BG
  1182. Map.Set_Placement_List(Map.PendingObject->Placement_List(true));
  1183. #endif
  1184. } else {
  1185. Map.PendingObject = 0;
  1186. Map.Set_Cursor_Shape(0);
  1187. }
  1188. }
  1189. /***************************************************************************
  1190. * Get_Savefile_Info -- gets description, scenario #, house *
  1191. * *
  1192. * INPUT: *
  1193. * id numerical ID, for the file extension *
  1194. * buf buffer to store description in *
  1195. * scenp ptr to variable to hold scenario *
  1196. * housep ptr to variable to hold house *
  1197. * *
  1198. * OUTPUT: *
  1199. * true = OK, false = error (save-game file invalid) *
  1200. * *
  1201. * WARNINGS: *
  1202. * none. *
  1203. * *
  1204. * HISTORY: *
  1205. * 01/12/1995 BR : Created. *
  1206. *=========================================================================*/
  1207. bool Get_Savefile_Info(int id, char * buf, unsigned * scenp, HousesType * housep)
  1208. {
  1209. char name[_MAX_FNAME+_MAX_EXT];
  1210. unsigned long version;
  1211. char descr_buf[DESCRIP_MAX];
  1212. /*
  1213. ** Generate the filename to load
  1214. */
  1215. sprintf(name, "SAVEGAME.%03d", id);
  1216. BufferIOFileClass file(name);
  1217. FileStraw straw(file);
  1218. /*
  1219. ** Read in the description, scenario #, and the house
  1220. */
  1221. if (straw.Get(descr_buf, DESCRIP_MAX) != DESCRIP_MAX) {
  1222. return(false);
  1223. }
  1224. descr_buf[strlen(descr_buf) - 2] = '\0'; // trim off CR/LF
  1225. strcpy(buf, descr_buf);
  1226. if (straw.Get(scenp, sizeof(unsigned)) != sizeof(unsigned)) {
  1227. return(false);
  1228. }
  1229. if (straw.Get(housep, sizeof(HousesType)) != sizeof(HousesType)) {
  1230. return(false);
  1231. }
  1232. /*
  1233. ** Read & verify the save-game version #
  1234. */
  1235. if (straw.Get(&version, sizeof(version)) != sizeof(version)) {
  1236. return(false);
  1237. }
  1238. #ifdef FIXIT_CSII // checked - ajw 9/28/98
  1239. if (version != SAVEGAME_VERSION && ((version-1 != SAVEGAME_VERSION)) ) {
  1240. #else
  1241. if (version != SAVEGAME_VERSION) {
  1242. #endif
  1243. return(false);
  1244. }
  1245. return(true);
  1246. }
  1247. /***************************************************************************
  1248. * Reconcile_Players -- Reconciles loaded data with the 'Players' vector *
  1249. * *
  1250. * This function is for supporting loading a saved multiplayer game. *
  1251. * When the game is loaded, we have to figure out which house goes with *
  1252. * which entry in the Players vector. We also have to figure out if *
  1253. * everyone who was originally in the game is still with us, and if not, *
  1254. * turn their stuff over to the computer. *
  1255. * *
  1256. * So, this function does the following: *
  1257. * - For every name in 'Players', makes sure that name is in the House *
  1258. * array; if not, it's a fatal error. *
  1259. * - For every human-controlled house, makes sure there's a player *
  1260. * with that name; if not, it turns that house over to the computer. *
  1261. * - Fills in the Player's house ID *
  1262. * *
  1263. * This assumes that each player MUST keep their name the same as it was *
  1264. * when the game was saved! It's also assumed that the network *
  1265. * connections have not been formed yet, since Player[i]->Player.ID will *
  1266. * be invalid until this routine has been called. *
  1267. * *
  1268. * INPUT: *
  1269. * none. *
  1270. * *
  1271. * OUTPUT: *
  1272. * true = OK, false = error *
  1273. * *
  1274. * WARNINGS: *
  1275. * none. *
  1276. * *
  1277. * HISTORY: *
  1278. * 09/29/1995 BRR : Created. *
  1279. *=========================================================================*/
  1280. static int Reconcile_Players(void)
  1281. {
  1282. int i;
  1283. int found;
  1284. HousesType house;
  1285. HouseClass * housep;
  1286. /*
  1287. ** If there are no players, there's nothing to do.
  1288. */
  1289. if (Session.Players.Count()==0)
  1290. return (true);
  1291. /*
  1292. ** Make sure every name we're connected to can be found in a House
  1293. */
  1294. for (i = 0; i < Session.Players.Count(); i++) {
  1295. found = 0;
  1296. for (house = HOUSE_MULTI1; house < HOUSE_MULTI1 +
  1297. Session.MaxPlayers; house++) {
  1298. housep = HouseClass::As_Pointer(house);
  1299. if (!housep) {
  1300. continue;
  1301. }
  1302. if (!stricmp(Session.Players[i]->Name, housep->IniName)) {
  1303. found = 1;
  1304. break;
  1305. }
  1306. }
  1307. if (!found)
  1308. return (false);
  1309. }
  1310. //
  1311. // Loop through all Houses; if we find a human-owned house that we're
  1312. // not connected to, turn it over to the computer.
  1313. //
  1314. for (house = HOUSE_MULTI1; house < HOUSE_MULTI1 +
  1315. Session.MaxPlayers; house++) {
  1316. housep = HouseClass::As_Pointer(house);
  1317. if (!housep) {
  1318. continue;
  1319. }
  1320. //
  1321. // Skip this house if it wasn't human to start with.
  1322. //
  1323. if (!housep->IsHuman) {
  1324. continue;
  1325. }
  1326. //
  1327. // Try to find this name in the Players vector; if it's found, set
  1328. // its ID to this house.
  1329. //
  1330. found = 0;
  1331. for (i = 0; i < Session.Players.Count(); i++) {
  1332. if (!stricmp(Session.Players[i]->Name, housep->IniName)) {
  1333. found = 1;
  1334. Session.Players[i]->Player.ID = house;
  1335. break;
  1336. }
  1337. }
  1338. /*
  1339. ** If this name wasn't found, remove it
  1340. */
  1341. if (!found) {
  1342. /*
  1343. ** Turn the player's house over to the computer's AI
  1344. */
  1345. housep->IsHuman = false;
  1346. housep->IsStarted = true;
  1347. // housep->Smartness = IQ_MENSA;
  1348. housep->IQ = Rule.MaxIQ;
  1349. strcpy (housep->IniName, Text_String(TXT_COMPUTER));
  1350. Session.NumPlayers--;
  1351. }
  1352. }
  1353. //
  1354. // If all went well, our Session.NumPlayers value should now equal the value
  1355. // from the saved game, minus any players we removed.
  1356. //
  1357. if (Session.NumPlayers == Session.Players.Count()) {
  1358. return (true);
  1359. } else {
  1360. return (false);
  1361. }
  1362. }
  1363. /***************************************************************************
  1364. * MPlayer_Save_Message -- pops up a "saving..." message *
  1365. * *
  1366. * INPUT: *
  1367. * none. *
  1368. * *
  1369. * OUTPUT: *
  1370. * none. *
  1371. * *
  1372. * WARNINGS: *
  1373. * none. *
  1374. * *
  1375. * HISTORY: *
  1376. * 10/30/1995 BRR : Created. *
  1377. *=========================================================================*/
  1378. void MPlayer_Save_Message(void)
  1379. {
  1380. //char *txt = Text_String(
  1381. }