SAVELOAD.CPP 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392
  1. /*
  2. ** Command & Conquer(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: F:\projects\c&c\vcs\code\saveload.cpv 2.18 16 Oct 1995 16:48:44 JOE_BOSTIC $ */
  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 : June 24, 1995 [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_Misc_Values -- Loads miscellaneous variables. *
  40. * Load_Misc_Values -- loads miscellaneous variables *
  41. * Read_Object -- reads an object from disk, in a safe way *
  42. * Save_Game -- saves a game to disk *
  43. * Save_Misc_Values -- saves miscellaneous variables *
  44. * Target_To_TechnoType -- converts TARGET to TechnoTypeClass *
  45. * TechnoType_To_Target -- converts TechnoTypeClass to TARGET *
  46. * Write_Object -- reads an object from disk, in a safe way *
  47. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  48. #include "function.h"
  49. /*
  50. ********************************** Defines **********************************
  51. */
  52. #define SAVEGAME_VERSION (DESCRIP_MAX + \
  53. 0x01000003 + ( \
  54. sizeof(AircraftClass) + \
  55. sizeof(AircraftTypeClass) + \
  56. sizeof(AnimClass) + \
  57. sizeof(AnimTypeClass) + \
  58. sizeof(BuildingClass) + \
  59. sizeof(BuildingTypeClass) + \
  60. sizeof(BulletClass) + \
  61. sizeof(BulletTypeClass) + \
  62. sizeof(HouseClass) + \
  63. sizeof(HouseTypeClass) + \
  64. sizeof(InfantryClass) + \
  65. sizeof(InfantryTypeClass) + \
  66. sizeof(OverlayClass) + \
  67. sizeof(OverlayTypeClass) + \
  68. sizeof(SmudgeClass) + \
  69. sizeof(SmudgeTypeClass) + \
  70. sizeof(TeamClass) + \
  71. sizeof(TeamTypeClass) + \
  72. sizeof(TemplateClass) + \
  73. sizeof(TemplateTypeClass) + \
  74. sizeof(TerrainClass) + \
  75. sizeof(TerrainTypeClass) + \
  76. sizeof(UnitClass) + \
  77. sizeof(UnitTypeClass) + \
  78. sizeof(MouseClass) + \
  79. sizeof(CellClass) + \
  80. sizeof(FactoryClass) + \
  81. sizeof(BaseClass) + \
  82. sizeof(LayerClass) + \
  83. sizeof(BriefingText) + \
  84. sizeof(Waypoint)))
  85. /***************************************************************************
  86. * Save_Game -- saves a game to disk *
  87. * *
  88. * Saving the Map: *
  89. * DisplayClass::Save() invokes CellClass's Write() for every cell *
  90. * that needs to be saved. A cell needs to be saved if it contains *
  91. * any special data at all, such as a TIcon, or an Occupier. *
  92. * The cell saves its own CellTrigger pointer, converted to a TARGET. *
  93. * *
  94. * Saving game objects: *
  95. * - Any object stored in an ArrayOf class needs to be saved. The ArrayOf*
  96. * Save() routine invokes each object's Write() routine, if that *
  97. * object's IsActive is set. *
  98. * *
  99. * Saving the layers: *
  100. * The Map's Layers (Ground, Air, etc) of things that are on the map, *
  101. * and the Logic's Layer of things to process both need to be saved. *
  102. * LayerClass::Save() writes the entire layer array to disk *
  103. * *
  104. * Saving the houses: *
  105. * Each house needs to be saved, to record its Credits, Power, etc. *
  106. * *
  107. * Saving miscellaneous data: *
  108. * There are a lot of miscellaneous variables to save, such as the *
  109. * map's dimensions, the player's house, etc. *
  110. * *
  111. * INPUT: *
  112. * id numerical ID, for the file extension *
  113. * *
  114. * OUTPUT: *
  115. * true = OK, false = error *
  116. * *
  117. * WARNINGS: *
  118. * none. *
  119. * *
  120. * HISTORY: *
  121. * 12/28/1994 BR : Created. *
  122. *=========================================================================*/
  123. bool Save_Game(int id,char *descr)
  124. {
  125. RawFileClass file;
  126. char name[_MAX_FNAME+_MAX_EXT];
  127. int i;
  128. unsigned long version;
  129. unsigned scenario;
  130. HousesType house;
  131. char descr_buf[DESCRIP_MAX];
  132. scenario = Scenario; // get current scenario #
  133. house = PlayerPtr->Class->House; // get current house
  134. /*
  135. ** Generate the filename to save
  136. */
  137. sprintf(name, "SAVEGAME.%03d", id);
  138. /*
  139. ** Code everybody's pointers
  140. */
  141. Code_All_Pointers();
  142. /*
  143. ** Open the file
  144. */
  145. if (!file.Open(name, WRITE)) {
  146. Decode_All_Pointers();
  147. return(false);
  148. }
  149. /*
  150. ** Save the description, scenario #, and house
  151. ** (scenario # & house are saved separately from the actual Scenario &
  152. ** PlayerPtr globals for convenience; we can quickly find out which
  153. ** house & scenario this save-game file is for by reading these values.
  154. ** Also, PlayerPtr is stored in a coded form in Save_Misc_Values(),
  155. ** which may or may not be a HousesType number; so, saving 'house'
  156. ** here ensures we can always pull out the house for this file.)
  157. */
  158. sprintf(descr_buf, "%s\r\n",descr); // put CR-LF after text
  159. descr_buf[strlen(descr_buf) + 1] = 26; // put CTRL-Z after NULL
  160. if (file.Write(descr_buf, DESCRIP_MAX) != DESCRIP_MAX) {
  161. file.Close();
  162. return(false);
  163. }
  164. if (file.Write(&scenario, sizeof(scenario)) != sizeof(scenario)) {
  165. file.Close();
  166. return(false);
  167. }
  168. if (file.Write(&house, sizeof(house)) != sizeof(house)) {
  169. file.Close();
  170. return(false);
  171. }
  172. /*
  173. ** Save the save-game version, for loading verification
  174. */
  175. version = SAVEGAME_VERSION;
  176. if (file.Write(&version, sizeof(version)) != sizeof(version)) {
  177. file.Close();
  178. return(false);
  179. }
  180. Call_Back();
  181. /*
  182. ** Save the map. The map must be saved first, since it saves the Theater.
  183. */
  184. Map.Save(file);
  185. Call_Back();
  186. /*
  187. ** Save all game objects. This code saves every object that's stored in a
  188. ** TFixedIHeap class.
  189. */
  190. if (!Houses.Save(file) ||
  191. !TeamTypes.Save(file) ||
  192. !Teams.Save(file) ||
  193. !Triggers.Save(file) ||
  194. !Aircraft.Save(file) ||
  195. !Anims.Save(file) ||
  196. !Buildings.Save(file) ||
  197. !Bullets.Save(file) ||
  198. !Infantry.Save(file) ||
  199. !Overlays.Save(file) ||
  200. !Smudges.Save(file) ||
  201. !Templates.Save(file) ||
  202. !Terrains.Save(file) ||
  203. !Units.Save(file) ||
  204. !Factories.Save(file)) {
  205. file.Close();
  206. Decode_All_Pointers();
  207. return(false);
  208. }
  209. Call_Back();
  210. /*
  211. ** Save the Logic & Map layers
  212. */
  213. if (!Logic.Save(file)) {
  214. file.Close();
  215. Decode_All_Pointers();
  216. return(false);
  217. }
  218. for (i = 0; i < LAYER_COUNT; i++) {
  219. if (!Map.Layer[i].Save(file)) {
  220. file.Close();
  221. Decode_All_Pointers();
  222. return(false);
  223. }
  224. }
  225. /*
  226. ** Save the Score
  227. */
  228. if (!Score.Save(file)) {
  229. file.Close();
  230. Decode_All_Pointers();
  231. return(false);
  232. }
  233. /*
  234. ** Save the AI Base
  235. */
  236. if (!Base.Save(file)) {
  237. file.Close();
  238. Decode_All_Pointers();
  239. return(false);
  240. }
  241. /*
  242. ** Save miscellaneous variables.
  243. */
  244. if (!Save_Misc_Values(file)) {
  245. file.Close();
  246. Decode_All_Pointers();
  247. return(false);
  248. }
  249. Call_Back();
  250. /*
  251. ** Close the file; we're done
  252. */
  253. file.Close();
  254. Decode_All_Pointers();
  255. return(true);
  256. }
  257. /***************************************************************************
  258. * Load_Game -- loads a saved game *
  259. * *
  260. * This routine loads the data in the same way it was saved out. *
  261. * *
  262. * Loading the Map: *
  263. * - DisplayClass::Load() invokes CellClass's Load() for every cell *
  264. * that was saved. *
  265. * - The cell loads its own CellTrigger pointer. *
  266. * *
  267. * Loading game objects: *
  268. * - IHeap's Load() routine loads the # of objects stored, and loads *
  269. * each object. *
  270. * - Triggers: Add themselves to the HouseTriggers if they're associated *
  271. * with a house *
  272. * *
  273. * Loading the layers: *
  274. * LayerClass::Load() reads the entire layer array to disk *
  275. * *
  276. * Loading the houses: *
  277. * Each house is loaded in its entirety. *
  278. * *
  279. * Loading miscellaneous data: *
  280. * There are a lot of miscellaneous variables to load, such as the *
  281. * map's dimensions, the player's house, etc. *
  282. * *
  283. * INPUT: *
  284. * id numerical ID, for the file extension *
  285. * *
  286. * OUTPUT: *
  287. * true = OK, false = error *
  288. * *
  289. * WARNINGS: *
  290. * If this routine returns false, the entire game will be in an *
  291. * unknown state, so the scenario will have to be re-initialized. *
  292. * *
  293. * HISTORY: *
  294. * 12/28/1994 BR : Created. *
  295. *=========================================================================*/
  296. bool Load_Game(int id)
  297. {
  298. RawFileClass file;
  299. char name[_MAX_FNAME+_MAX_EXT];
  300. int i;
  301. unsigned long version;
  302. unsigned scenario;
  303. HousesType house;
  304. char descr_buf[DESCRIP_MAX];
  305. /*
  306. ** Generate the filename to load
  307. */
  308. sprintf(name, "SAVEGAME.%03d", id);
  309. /*
  310. ** Open the file
  311. */
  312. if (!file.Open(name, READ)) {
  313. return(false);
  314. }
  315. /*
  316. ** Read & discard the save-game's header info
  317. */
  318. if (file.Read(descr_buf, DESCRIP_MAX) != DESCRIP_MAX) {
  319. file.Close();
  320. return(false);
  321. }
  322. if (file.Read(&scenario, sizeof(scenario)) != sizeof(scenario)) {
  323. file.Close();
  324. return(false);
  325. }
  326. if (file.Read(&house, sizeof(house)) != sizeof(house)) {
  327. file.Close();
  328. return(false);
  329. }
  330. Call_Back();
  331. /*
  332. ** Clear the scenario so we start fresh; this calls the Init_Clear() routine
  333. ** for the Map, and all object arrays. It has the following important
  334. ** effects:
  335. ** - Every cell is cleared to 0's, via MapClass::Init_Clear()
  336. ** - All heap elements' are cleared
  337. ** - The Houses are Initialized, which also clears their HouseTriggers
  338. ** array
  339. ** - The map's Layers & Logic Layer are cleared to empty
  340. ** - The list of currently-selected objects is cleared
  341. */
  342. Clear_Scenario();
  343. /*
  344. ** Read in & verify the save-game ID code
  345. */
  346. if (file.Read(&version,sizeof(version)) != sizeof(version)) {
  347. file.Close();
  348. return(false);
  349. }
  350. if (version != SAVEGAME_VERSION) {
  351. file.Close();
  352. return(false);
  353. }
  354. Call_Back();
  355. /*
  356. ** Set the required CD to be in the drive according to the scenario
  357. ** loaded.
  358. */
  359. if (RequiredCD != -2) {
  360. if (scenario >= 20 && scenario <60 && GameToPlay == GAME_NORMAL) {
  361. RequiredCD = 2;
  362. } else {
  363. if (scenario >= 60){
  364. /*
  365. ** This is a gateway bonus scenario
  366. */
  367. RequiredCD = -1;
  368. }else{
  369. if (house == HOUSE_GOOD) {
  370. RequiredCD = 0;
  371. } else {
  372. RequiredCD = 1;
  373. }
  374. }
  375. }
  376. }
  377. if(!Force_CD_Available(RequiredCD)) {
  378. Prog_End();
  379. exit(EXIT_FAILURE);
  380. }
  381. Call_Back();
  382. /*
  383. ** Load the map. The map comes first, since it loads the Theater & init's
  384. ** mixfiles. The map calls all the type-class's Init routines, telling them
  385. ** what the Theater is; this must be done before any objects are created, so
  386. ** they'll be properly created.
  387. */
  388. Map.Load(file);
  389. Call_Back();
  390. /*
  391. ** Load the object data.
  392. */
  393. if (!Houses.Load(file) ||
  394. !TeamTypes.Load(file) ||
  395. !Teams.Load(file) ||
  396. !Triggers.Load(file) ||
  397. !Aircraft.Load(file) ||
  398. !Anims.Load(file) ||
  399. !Buildings.Load(file) ||
  400. !Bullets.Load(file) ||
  401. !Infantry.Load(file) ||
  402. !Overlays.Load(file) ||
  403. !Smudges.Load(file) ||
  404. !Templates.Load(file) ||
  405. !Terrains.Load(file) ||
  406. !Units.Load(file) ||
  407. !Factories.Load(file)) {
  408. file.Close();
  409. return(false);
  410. }
  411. Call_Back();
  412. /*
  413. ** Load the Logic & Map Layers
  414. */
  415. if (!Logic.Load(file)) {
  416. file.Close();
  417. return(false);
  418. }
  419. for (i = 0; i < LAYER_COUNT; i++) {
  420. if (!Map.Layer[i].Load(file)) {
  421. file.Close();
  422. return(false);
  423. }
  424. }
  425. Call_Back();
  426. /*
  427. ** Load the Score
  428. */
  429. if (!Score.Load(file)) {
  430. file.Close();
  431. return(false);
  432. }
  433. /*
  434. ** Load the AI Base
  435. */
  436. if (!Base.Load(file)) {
  437. file.Close();
  438. return(false);
  439. }
  440. /*
  441. ** Load miscellaneous variables, including the map size & the Theater
  442. */
  443. if (!Load_Misc_Values(file)) {
  444. file.Close();
  445. return(false);
  446. }
  447. file.Close();
  448. Decode_All_Pointers();
  449. Map.Init_IO();
  450. Map.Flag_To_Redraw(true);
  451. ScenarioInit = 0;
  452. #ifdef DEMO
  453. if (Scenario != 10 && Scenario != 1 && Scenario != 6) {
  454. Clear_Scenario();
  455. return(false);
  456. }
  457. #endif
  458. Call_Back();
  459. return(true);
  460. }
  461. /***************************************************************************
  462. * Save_Misc_Values -- saves miscellaneous variables *
  463. * *
  464. * INPUT: *
  465. * file file to use for writing *
  466. * *
  467. * OUTPUT: *
  468. * true = success, false = failure *
  469. * *
  470. * WARNINGS: *
  471. * none. *
  472. * *
  473. * HISTORY: *
  474. * 12/29/1994 BR : Created. *
  475. *=========================================================================*/
  476. bool Save_Misc_Values(FileClass &file)
  477. {
  478. int i;
  479. int count; // # ptrs in 'CurrentObject'
  480. ObjectClass * ptr; // for saving 'CurrentObject' ptrs
  481. /*
  482. ** Player's House.
  483. */
  484. if (file.Write(&PlayerPtr, sizeof(PlayerPtr)) != sizeof(PlayerPtr)) {
  485. return(false);
  486. }
  487. /*
  488. ** Save this scenario number.
  489. */
  490. if (file.Write(&Scenario, sizeof(Scenario)) != sizeof(Scenario)) {
  491. return(false);
  492. }
  493. /*
  494. ** Save frame #.
  495. */
  496. if (file.Write(&Frame, sizeof(Frame)) != sizeof(Frame)) {
  497. return(false);
  498. }
  499. /*
  500. ** Save VQ Movie names.
  501. */
  502. if (file.Write(WinMovie, sizeof(WinMovie)) != sizeof(WinMovie)) {
  503. return(false);
  504. }
  505. if (file.Write(LoseMovie, sizeof(LoseMovie)) != sizeof(LoseMovie)) {
  506. return(false);
  507. }
  508. /*
  509. ** Save currently-selected objects list.
  510. ** Save the # of ptrs in the list.
  511. */
  512. count = CurrentObject.Count();
  513. if (file.Write(&count, sizeof(count)) != sizeof(count)) {
  514. return(false);
  515. }
  516. /*
  517. ** Save the pointers.
  518. */
  519. for (i = 0; i < count; i++) {
  520. ptr = CurrentObject[i];
  521. if (file.Write(&ptr, sizeof(ptr)) != sizeof(ptr)) {
  522. return(false);
  523. }
  524. }
  525. /*
  526. ** Save the list of waypoints.
  527. */
  528. if (file.Write(Waypoint, sizeof(Waypoint)) != sizeof(Waypoint)) {
  529. return(false);
  530. }
  531. file.Write(&ScenDir, sizeof(ScenDir));
  532. file.Write(&ScenVar, sizeof(ScenVar));
  533. file.Write(&CarryOverMoney, sizeof(CarryOverMoney));
  534. file.Write(&CarryOverPercent, sizeof(CarryOverPercent));
  535. file.Write(&BuildLevel, sizeof(BuildLevel));
  536. file.Write(BriefMovie, sizeof(BriefMovie));
  537. file.Write(Views, sizeof(Views));
  538. file.Write(&EndCountDown, sizeof(EndCountDown));
  539. file.Write(BriefingText, sizeof(BriefingText));
  540. // This is new...
  541. file.Write(ActionMovie, sizeof(ActionMovie));
  542. return(true);
  543. }
  544. /***********************************************************************************************
  545. * Load_Misc_Values -- Loads miscellaneous variables. *
  546. * *
  547. * INPUT: file -- The file to load the misc values from. *
  548. * *
  549. * OUTPUT: Was the misc load process successful? *
  550. * *
  551. * WARNINGS: none *
  552. * *
  553. * HISTORY: *
  554. * 06/24/1995 BRR : Created. *
  555. *=============================================================================================*/
  556. bool Load_Misc_Values(FileClass &file)
  557. {
  558. int i;
  559. int count; // # ptrs in 'CurrentObject'
  560. ObjectClass * ptr; // for loading 'CurrentObject' ptrs
  561. /*
  562. ** Player's House.
  563. */
  564. if (file.Read(&PlayerPtr, sizeof(PlayerPtr)) != sizeof(PlayerPtr)) {
  565. return(false);
  566. }
  567. /*
  568. ** Read this scenario number.
  569. */
  570. if (file.Read(&Scenario,sizeof(Scenario)) != sizeof(Scenario)) {
  571. return(false);
  572. }
  573. /*
  574. ** Load frame #.
  575. */
  576. if (file.Read(&Frame, sizeof(Frame)) != sizeof(Frame)) {
  577. return(false);
  578. }
  579. /*
  580. ** Load VQ Movie names.
  581. */
  582. if (file.Read(WinMovie, sizeof(WinMovie)) != sizeof(WinMovie)) {
  583. return(false);
  584. }
  585. if (file.Read(LoseMovie, sizeof(LoseMovie)) != sizeof(LoseMovie)) {
  586. return(false);
  587. }
  588. /*
  589. ** Load currently-selected objects list.
  590. ** Load the # of ptrs in the list.
  591. */
  592. if (file.Read(&count, sizeof(count)) != sizeof(count)) {
  593. return(false);
  594. }
  595. /*
  596. ** Load the pointers.
  597. */
  598. for (i = 0; i < count; i++) {
  599. if (file.Read(&ptr, sizeof(ptr)) != sizeof(ptr)) {
  600. return(false);
  601. }
  602. CurrentObject.Add(ptr); // add to the list
  603. }
  604. /*
  605. ** Save the list of waypoints.
  606. */
  607. if (file.Read(Waypoint, sizeof(Waypoint)) != sizeof(Waypoint)) {
  608. return(false);
  609. }
  610. file.Read(&ScenDir, sizeof(ScenDir));
  611. file.Read(&ScenVar, sizeof(ScenVar));
  612. file.Read(&CarryOverMoney, sizeof(CarryOverMoney));
  613. file.Read(&CarryOverPercent, sizeof(CarryOverPercent));
  614. file.Read(&BuildLevel, sizeof(BuildLevel));
  615. file.Read(BriefMovie, sizeof(BriefMovie));
  616. file.Read(Views, sizeof(Views));
  617. file.Read(&EndCountDown, sizeof(EndCountDown));
  618. file.Read(BriefingText, sizeof(BriefingText));
  619. if (file.Seek(0, SEEK_CUR) < file.Size()) {
  620. file.Read(ActionMovie, sizeof(ActionMovie));
  621. }
  622. return(true);
  623. }
  624. /***********************************************************************************************
  625. * Code_All_Pointers -- Code all pointers. *
  626. * *
  627. * INPUT: none *
  628. * *
  629. * OUTPUT: none *
  630. * *
  631. * WARNINGS: none *
  632. * *
  633. * HISTORY: *
  634. * 06/24/1995 BRR : Created. *
  635. *=============================================================================================*/
  636. void Code_All_Pointers(void)
  637. {
  638. int i;
  639. /*
  640. ** The Map.
  641. */
  642. Map.Code_Pointers();
  643. /*
  644. ** The ArrayOf's.
  645. */
  646. TeamTypes.Code_Pointers();
  647. Teams.Code_Pointers();
  648. Triggers.Code_Pointers();
  649. Aircraft.Code_Pointers();
  650. Anims.Code_Pointers();
  651. Buildings.Code_Pointers();
  652. Bullets.Code_Pointers();
  653. Infantry.Code_Pointers();
  654. Overlays.Code_Pointers();
  655. Smudges.Code_Pointers();
  656. Templates.Code_Pointers();
  657. Terrains.Code_Pointers();
  658. Units.Code_Pointers();
  659. Factories.Code_Pointers();
  660. /*
  661. ** The Layers.
  662. */
  663. Logic.Code_Pointers();
  664. for (i = 0; i < LAYER_COUNT; i++) {
  665. Map.Layer[i].Code_Pointers();
  666. }
  667. /*
  668. ** The Score.
  669. */
  670. Score.Code_Pointers();
  671. /*
  672. ** The Base.
  673. */
  674. Base.Code_Pointers();
  675. /*
  676. ** PlayerPtr.
  677. */
  678. PlayerPtr = (HouseClass *)(PlayerPtr->Class->House);
  679. /*
  680. ** Currently-selected objects.
  681. */
  682. for (i = 0; i < CurrentObject.Count(); i++) {
  683. CurrentObject[i] = (ObjectClass *)CurrentObject[i]->As_Target();
  684. }
  685. /*
  686. ** Houses must be coded last, because the Class->House member of the HouseClass
  687. ** is used to code HouseClass pointers for all other objects, and if Class is
  688. ** coded, it will point to a meaningless value.
  689. */
  690. Houses.Code_Pointers();
  691. }
  692. /***********************************************************************************************
  693. * Decode_All_Pointers -- Decodes all pointers. *
  694. * *
  695. * INPUT: none *
  696. * *
  697. * OUTPUT: none *
  698. * *
  699. * WARNINGS: none *
  700. * *
  701. * HISTORY: *
  702. * 06/24/1995 BRR : Created. *
  703. *=============================================================================================*/
  704. void Decode_All_Pointers(void)
  705. {
  706. int i;
  707. /*
  708. ** The Map.
  709. */
  710. Map.Decode_Pointers();
  711. /*
  712. ** Decode houses first, so we can properly decode all other objects'
  713. ** House pointers
  714. */
  715. Houses.Decode_Pointers();
  716. /*
  717. ** The ArrayOf's.
  718. */
  719. TeamTypes.Decode_Pointers();
  720. Teams.Decode_Pointers();
  721. Triggers.Decode_Pointers();
  722. Aircraft.Decode_Pointers();
  723. Anims.Decode_Pointers();
  724. Buildings.Decode_Pointers();
  725. Bullets.Decode_Pointers();
  726. Infantry.Decode_Pointers();
  727. Overlays.Decode_Pointers();
  728. Smudges.Decode_Pointers();
  729. Templates.Decode_Pointers();
  730. Terrains.Decode_Pointers();
  731. Units.Decode_Pointers();
  732. Factories.Decode_Pointers();
  733. /*
  734. ** The Layers.
  735. */
  736. Logic.Decode_Pointers();
  737. for (i = 0; i < LAYER_COUNT; i++) {
  738. Map.Layer[i].Decode_Pointers();
  739. }
  740. /*
  741. ** The Score.
  742. */
  743. Score.Decode_Pointers();
  744. /*
  745. ** The Base.
  746. */
  747. Base.Decode_Pointers();
  748. /*
  749. ** PlayerPtr.
  750. */
  751. PlayerPtr = HouseClass::As_Pointer((HousesType)PlayerPtr);
  752. Whom = PlayerPtr->Class->House;
  753. switch (PlayerPtr->Class->House) {
  754. case HOUSE_GOOD:
  755. ScenPlayer = SCEN_PLAYER_GDI;
  756. break;
  757. case HOUSE_BAD:
  758. ScenPlayer = SCEN_PLAYER_NOD;
  759. break;
  760. case HOUSE_JP:
  761. ScenPlayer = SCEN_PLAYER_JP;
  762. break;
  763. }
  764. Check_Ptr(PlayerPtr,__FILE__,__LINE__);
  765. Set_Scenario_Name(ScenarioName, Scenario, ScenPlayer, ScenDir, ScenVar);
  766. /*
  767. ** Currently-selected objects.
  768. */
  769. for (i = 0; i < CurrentObject.Count(); i++) {
  770. CurrentObject[i] = As_Object((TARGET)CurrentObject[i]);
  771. Check_Ptr(CurrentObject[i],__FILE__,__LINE__);
  772. }
  773. /*
  774. ** Last-Minute Fixups; to resolve these pointers properly requires all other
  775. ** pointers to be loaded & decoded.
  776. */
  777. if (Map.PendingObjectPtr) {
  778. Map.PendingObject = &Map.PendingObjectPtr->Class_Of();
  779. Check_Ptr((void *)Map.PendingObject, __FILE__, __LINE__);
  780. Map.Set_Cursor_Shape(Map.PendingObject->Occupy_List(true));
  781. } else {
  782. Map.PendingObject = 0;
  783. Map.Set_Cursor_Shape(0);
  784. }
  785. }
  786. /***********************************************************************************************
  787. * Read_Object -- reads an object from disk *
  788. * *
  789. * This routine reads in an object and fills in the virtual function table pointer. *
  790. * *
  791. * INPUT: *
  792. * ptr pointer to object to read *
  793. * base_size size of object's absolute base class *
  794. * class_size size of the class itself *
  795. * file file to use for I/O *
  796. * vtable virtual function table pointer value, NULL if none *
  797. * *
  798. * OUTPUT: *
  799. * true = OK, false = error *
  800. * *
  801. * WARNINGS: *
  802. * This routine ASSUMES the program modules are compiled with: *
  803. * -Vb- Always make the virtual function table ptr 2 bytes long *
  804. * -Vt Put the virtual function table after the 1st class's data *
  805. * *
  806. * ALSO, the class used to compute 'base_size' must come first in a multiple-inheritence *
  807. * hierarchy. AND, if your class multiply-inherits from other classes, only ONE of those *
  808. * classes can contain virtual functions! If you include virtual functions in the other *
  809. * classes, the compiler will generate multiple virtual function tables, and this load/save *
  810. * technique will fail. *
  811. * *
  812. * Each class hierarchy is stored in memory as a chain: first the data for the base-est *
  813. * class, then the virtual function table pointer for this hierarchy, then the data for *
  814. * all derived classes. If any of these derived classes multiply-inherit, the base class *
  815. * for the multiple inheritance is stored as a separate chain following this chain. The *
  816. * new chain will contain its own virtual function table pointer, if the multiply- *
  817. * inherited hierarchy contains any virtual functions. Thus, the declaration *
  818. * class A *
  819. * class B: public A *
  820. * class C: public B, X *
  821. * is stored as: *
  822. * A data *
  823. * A's Virtual Table Pointer *
  824. * B data *
  825. * X data *
  826. * [X's Virtual Table Pointer] *
  827. * C data *
  828. * *
  829. * and *
  830. * class A *
  831. * class B: public A *
  832. * class C: public X, B *
  833. * is stored in memory as: *
  834. * X data *
  835. * [X's Virtual Table Pointer] *
  836. * A data *
  837. * A's Virtual Table Pointer *
  838. * B data *
  839. * C data *
  840. * *
  841. * *
  842. * HISTORY: *
  843. * 01/10/1995 BR : Created. *
  844. *=============================================================================================*/
  845. bool Read_Object(void *ptr, int base_size, int class_size, FileClass & file, void * vtable)
  846. {
  847. int size; // object size in bytes
  848. /*
  849. ** Read size of this chunk.
  850. */
  851. if (file.Read(&size,sizeof(size)) != sizeof(size)) {
  852. return(false);
  853. }
  854. /*
  855. ** Error if incorrect size.
  856. */
  857. if (size != class_size) {
  858. return(false);
  859. }
  860. /*
  861. ** Read object data.
  862. */
  863. if (file.Read(ptr, class_size) != (class_size)) {
  864. return(false);
  865. }
  866. /*
  867. ** Fill in VTable.
  868. */
  869. if (vtable) {
  870. ((void **)(((char *)ptr) + base_size - 4))[0] = vtable;
  871. }
  872. return(true);
  873. }
  874. /***********************************************************************************************
  875. * Write_Object -- reads an object from disk, in a safe way *
  876. * *
  877. * This routine writes an object in 2 pieces, skipping the embedded *
  878. * virtual function table pointer. *
  879. * *
  880. * INPUT: *
  881. * ptr pointer to object to write *
  882. * class_size size of the class itself *
  883. * file file to use for I/O *
  884. * *
  885. * OUTPUT: *
  886. * true = OK, false = error *
  887. * *
  888. * WARNINGS: *
  889. * This routine ASSUMES the program modules are compiled with: *
  890. * -Vb- Always make the virtual function table ptr 2 bytes long *
  891. * -Vt Put the virtual function table after the 1st class's data *
  892. * *
  893. * Also see warnings for Read_Object(). *
  894. * *
  895. * HISTORY: *
  896. * 01/10/1995 BR : Created. *
  897. *=============================================================================================*/
  898. bool Write_Object(void *ptr, int class_size, FileClass & file)
  899. {
  900. /*
  901. ** Save size of this chunk.
  902. */
  903. if (file.Write(&class_size,sizeof(class_size)) != sizeof(class_size)) {
  904. return(false);
  905. }
  906. /*
  907. ** Save object data.
  908. */
  909. if (file.Write(ptr, class_size) != (class_size)) {
  910. return(false);
  911. }
  912. return(true);
  913. }
  914. /***************************************************************************
  915. * Get_Savefile_Info -- gets description, scenario #, house *
  916. * *
  917. * INPUT: *
  918. * id numerical ID, for the file extension *
  919. * buf buffer to store description in *
  920. * scenp ptr to variable to hold scenario *
  921. * housep ptr to variable to hold house *
  922. * *
  923. * OUTPUT: *
  924. * true = OK, false = error (save-game file invalid) *
  925. * *
  926. * WARNINGS: *
  927. * none. *
  928. * *
  929. * HISTORY: *
  930. * 01/12/1995 BR : Created. *
  931. *=========================================================================*/
  932. bool Get_Savefile_Info(int id, char *buf, unsigned *scenp, HousesType *housep)
  933. {
  934. RawFileClass file;
  935. char name[_MAX_FNAME+_MAX_EXT];
  936. unsigned long version;
  937. char descr_buf[DESCRIP_MAX];
  938. /*
  939. ** Generate the filename to load
  940. */
  941. sprintf(name, "SAVEGAME.%03d", id);
  942. /*
  943. ** If the file opens OK, read the file
  944. */
  945. if (file.Open(name, READ)) {
  946. /*
  947. ** Read in the description, scenario #, and the house
  948. */
  949. if (file.Read(descr_buf, DESCRIP_MAX) != DESCRIP_MAX) {
  950. file.Close();
  951. return(false);
  952. }
  953. descr_buf[strlen(descr_buf) - 2] = '\0'; // trim off CR/LF
  954. strcpy(buf, descr_buf);
  955. if (file.Read(scenp, sizeof(unsigned)) != sizeof(unsigned)) {
  956. file.Close();
  957. return(false);
  958. }
  959. if (file.Read(housep, sizeof(HousesType)) != sizeof(HousesType)) {
  960. file.Close();
  961. return(false);
  962. }
  963. /*
  964. ** Read & verify the save-game version #
  965. */
  966. if (file.Read(&version,sizeof(version)) != sizeof(version)) {
  967. file.Close();
  968. return(false);
  969. }
  970. if (version!=SAVEGAME_VERSION) {
  971. file.Close();
  972. return(false);
  973. }
  974. file.Close();
  975. return(true);
  976. }
  977. return(false);
  978. }
  979. /***************************************************************************
  980. * TechnoType_To_Target -- converts TechnoTypeClass to TARGET *
  981. * *
  982. * INPUT: *
  983. * ptr pointer to convert *
  984. * *
  985. * OUTPUT: *
  986. * target value *
  987. * *
  988. * WARNINGS: *
  989. * Be certain that you only use the returned target value by passing *
  990. * it to Target_To_TechnoType; do NOT call As_Techno, or you'll get *
  991. * a totally invalid pointer. *
  992. * *
  993. * HISTORY: *
  994. * 01/12/1995 BR : Created. *
  995. *=========================================================================*/
  996. TARGET TechnoType_To_Target(TechnoTypeClass const * ptr)
  997. {
  998. TARGET target;
  999. switch (ptr->What_Am_I()) {
  1000. case RTTI_INFANTRYTYPE:
  1001. target = Build_Target(KIND_INFANTRY, ((InfantryTypeClass const *)ptr)->Type);
  1002. break;
  1003. case RTTI_UNITTYPE:
  1004. target = Build_Target(KIND_UNIT, ((UnitTypeClass const *)ptr)->Type);
  1005. break;
  1006. case RTTI_AIRCRAFTTYPE:
  1007. target = Build_Target(KIND_AIRCRAFT, ((AircraftTypeClass const *)ptr)->Type);
  1008. break;
  1009. case RTTI_BUILDINGTYPE:
  1010. target = Build_Target(KIND_BUILDING, ((BuildingTypeClass const *)ptr)->Type);
  1011. break;
  1012. default:
  1013. target = 0;
  1014. break;
  1015. }
  1016. return(target);
  1017. }
  1018. /***************************************************************************
  1019. * Target_To_TechnoType -- converts TARGET to TechnoTypeClass *
  1020. * *
  1021. * INPUT: *
  1022. * target TARGET value to convert *
  1023. * *
  1024. * OUTPUT: *
  1025. * pointer to the TechnoTypeClass for this target value *
  1026. * *
  1027. * WARNINGS: *
  1028. * The TARGET value MUST have been generated with TechnoType_To_Target;*
  1029. * If you give this routine a target generated by an As_Target() *
  1030. * routine, it will return a bogus pointer. *
  1031. * *
  1032. * HISTORY: *
  1033. * 01/12/1995 BR : Created. *
  1034. *=========================================================================*/
  1035. TechnoTypeClass const * Target_To_TechnoType(TARGET target)
  1036. {
  1037. switch (Target_Kind(target)) {
  1038. case KIND_INFANTRY:
  1039. return(&InfantryTypeClass::As_Reference((InfantryType)Target_Value(target)));
  1040. case KIND_UNIT:
  1041. return(&UnitTypeClass::As_Reference((UnitType)Target_Value(target)));
  1042. case KIND_AIRCRAFT:
  1043. return(&AircraftTypeClass::As_Reference((AircraftType)Target_Value(target)));
  1044. case KIND_BUILDING:
  1045. return(&BuildingTypeClass::As_Reference((StructType)Target_Value(target)));
  1046. }
  1047. return(NULL);
  1048. }
  1049. /***************************************************************************
  1050. * Get_VTable -- gets the VTable pointer for the given object *
  1051. * *
  1052. * INPUT: *
  1053. * ptr pointer to check *
  1054. * *
  1055. * OUTPUT: *
  1056. * none *
  1057. * *
  1058. * WARNINGS: *
  1059. * none *
  1060. * *
  1061. * HISTORY: *
  1062. * 01/12/1995 BR : Created. *
  1063. *=========================================================================*/
  1064. void * Get_VTable(void *ptr, int base_size)
  1065. {
  1066. return(((void **)(((char *)ptr) + base_size - 4))[0]);
  1067. }
  1068. /***************************************************************************
  1069. * Set_VTable -- sets the VTable pointer for the given object *
  1070. * *
  1071. * INPUT: *
  1072. * ptr pointer to check *
  1073. * base_size size of base class *
  1074. * vtable value of VTable to plug in *
  1075. * *
  1076. * OUTPUT: *
  1077. * none *
  1078. * *
  1079. * WARNINGS: *
  1080. * none *
  1081. * *
  1082. * HISTORY: *
  1083. * 01/12/1995 BR : Created. *
  1084. *=========================================================================*/
  1085. void Set_VTable(void *ptr, int base_size, void *vtable)
  1086. {
  1087. ((void **)(((char *)ptr) + base_size - 4))[0] = vtable;
  1088. }
  1089. #if 0
  1090. /****************************************************************************
  1091. Dump routine: prints everything about everything related to the Save/Load
  1092. process (OK, not exactly everything, but lots of stuff)
  1093. ****************************************************************************/
  1094. void Dump(void)
  1095. {
  1096. int i,j;
  1097. FILE *fp;
  1098. char *layername[] = {
  1099. "Ground",
  1100. "Air",
  1101. "Top"
  1102. };
  1103. /*
  1104. ------------------------------- Open file --------------------------------
  1105. */
  1106. fp = fopen("dump.txt","wt");
  1107. /*
  1108. ------------------------------ Logic Layer -------------------------------
  1109. */
  1110. fprintf(fp,"--------------------- Logic Layer ---------------------\n");
  1111. fprintf(fp,"Count: %d\n",Logic.Count());
  1112. for (j = 0; j < Logic.Count(); j++) {
  1113. fprintf(fp, "Entry %d: %x \n",j,Logic[j]);
  1114. }
  1115. fprintf(fp,"\n");
  1116. /*
  1117. ------------------------------- Map Layers -------------------------------
  1118. */
  1119. for (i = 0; i < LAYER_COUNT; i++) {
  1120. fprintf(fp,"----------------- Map Layer %s ---------------------\n",
  1121. layername[i]);
  1122. fprintf(fp,"Count: %d\n",Map.Layer[i].Count());
  1123. for (j = 0; j < Map.Layer[i].Count(); j++) {
  1124. fprintf(fp, "Entry %d: %x \n",j,Map.Layer[i][j]);
  1125. }
  1126. }
  1127. fprintf(fp,"\n");
  1128. fprintf(fp,"------------------ TeamTypes --------------------------\n");
  1129. fprintf(fp,"ActiveCount: %d\n",TeamTypes.ActiveCount);
  1130. for (i = 0; i < TEAMTYPE_MAX; i++) {
  1131. fprintf(fp,"Entry %d: Active:%d Name:%s\n",i,TeamTypes[i].IsActive,
  1132. TeamTypes[i].Get_Name());
  1133. }
  1134. fprintf(fp,"\n");
  1135. fprintf(fp,"------------------ Teams --------------------------\n");
  1136. fprintf(fp,"ActiveCount: %d\n",Teams.ActiveCount);
  1137. for (i = 0; i < TEAM_MAX; i++) {
  1138. fprintf(fp,"Entry %d: Active:%d Name:%s\n",i,Teams[i].IsActive,
  1139. Teams[i].Class->Get_Name());
  1140. }
  1141. fprintf(fp,"\n");
  1142. fprintf(fp,"------------------ Triggers --------------------------\n");
  1143. fprintf(fp,"ActiveCount: %d\n",Triggers.ActiveCount);
  1144. for (i = 0; i < TRIGGER_MAX; i++) {
  1145. fprintf(fp,"Entry %d: Active:%d Name:%s\n",i,Triggers[i].IsActive,
  1146. Triggers[i].Get_Name());
  1147. }
  1148. fprintf(fp,"\n");
  1149. fprintf(fp,"------------------ Aircraft --------------------------\n");
  1150. fprintf(fp,"ActiveCount: %d\n",Aircraft.ActiveCount);
  1151. for (i = 0; i < AIRCRAFT_MAX; i++) {
  1152. fprintf(fp,"Entry %d: Active:%d \n",i,Aircraft[i].IsActive);
  1153. }
  1154. fprintf(fp,"\n");
  1155. fprintf(fp,"------------------ Anims --------------------------\n");
  1156. fprintf(fp,"ActiveCount: %d\n",Anims.ActiveCount);
  1157. for (i = 0; i < ANIM_MAX; i++) {
  1158. fprintf(fp,"Entry %d: Active:%d \n",i,Anims[i].IsActive);
  1159. }
  1160. fprintf(fp,"\n");
  1161. fprintf(fp,"------------------ Buildings --------------------------\n");
  1162. fprintf(fp,"ActiveCount: %d\n",Buildings.ActiveCount);
  1163. for (i = 0; i < BUILDING_MAX; i++) {
  1164. fprintf(fp,"Entry %d: Active:%d \n",i,Buildings[i].IsActive);
  1165. }
  1166. fprintf(fp,"\n");
  1167. fprintf(fp,"------------------ Bullets --------------------------\n");
  1168. fprintf(fp,"ActiveCount: %d\n",Bullets.ActiveCount);
  1169. for (i = 0; i < BULLET_MAX; i++) {
  1170. fprintf(fp,"Entry %d: Active:%d \n",i,Bullets[i].IsActive);
  1171. }
  1172. fprintf(fp,"\n");
  1173. fprintf(fp,"------------------ Infantry --------------------------\n");
  1174. fprintf(fp,"ActiveCount: %d\n",Infantry.ActiveCount);
  1175. for (i = 0; i < INFANTRY_MAX; i++) {
  1176. fprintf(fp,"Entry %d: Active:%d \n",i,Infantry[i].IsActive);
  1177. }
  1178. fprintf(fp,"\n");
  1179. fprintf(fp,"------------------ Overlays --------------------------\n");
  1180. fprintf(fp,"ActiveCount: %d\n",Overlays.ActiveCount);
  1181. for (i = 0; i < OVERLAY_MAX; i++) {
  1182. fprintf(fp,"Entry %d: Active:%d \n",i,Overlays[i].IsActive);
  1183. }
  1184. fprintf(fp,"\n");
  1185. fprintf(fp,"------------------ Reinforcements --------------------------\n");
  1186. fprintf(fp,"ActiveCount: %d\n",Reinforcements.ActiveCount);
  1187. for (i = 0; i < REINFORCEMENT_MAX; i++) {
  1188. fprintf(fp,"Entry %d: Active:%d \n",i,Reinforcements[i].IsActive);
  1189. }
  1190. fprintf(fp,"\n");
  1191. fprintf(fp,"------------------ Smudges --------------------------\n");
  1192. fprintf(fp,"ActiveCount: %d\n",Smudges.ActiveCount);
  1193. for (i = 0; i < SMUDGE_MAX; i++) {
  1194. fprintf(fp,"Entry %d: Active:%d \n",i,Smudges[i].IsActive);
  1195. }
  1196. fprintf(fp,"\n");
  1197. fprintf(fp,"------------------ Templates --------------------------\n");
  1198. fprintf(fp,"ActiveCount: %d\n",Templates.ActiveCount);
  1199. for (i = 0; i < TEMPLATE_MAX; i++) {
  1200. fprintf(fp,"Entry %d: Active:%d \n",i,Templates[i].IsActive);
  1201. }
  1202. fprintf(fp,"\n");
  1203. fprintf(fp,"------------------ Terrains --------------------------\n");
  1204. fprintf(fp,"ActiveCount: %d\n",Terrains.ActiveCount);
  1205. for (i = 0; i < TERRAIN_MAX; i++) {
  1206. fprintf(fp,"Entry %d: Active:%d \n",i,Terrains[i].IsActive);
  1207. }
  1208. fprintf(fp,"\n");
  1209. fprintf(fp,"------------------ Units --------------------------\n");
  1210. fprintf(fp,"ActiveCount: %d\n",Units.ActiveCount);
  1211. for (i = 0; i < UNIT_MAX; i++) {
  1212. fprintf(fp,"Entry %d: Active:%d \n",i,Units[i].IsActive);
  1213. }
  1214. fprintf(fp,"\n");
  1215. fprintf(fp,"------------------ Factories --------------------------\n");
  1216. fprintf(fp,"ActiveCount: %d\n",Factories.ActiveCount);
  1217. for (i = 0; i < FACTORY_MAX; i++) {
  1218. fprintf(fp,"Entry %d: Active:%d \n",i,Factories[i].IsActive);
  1219. }
  1220. fprintf(fp,"\n");
  1221. fclose(fp);
  1222. /*
  1223. ---------------------------- Flush the cache -----------------------------
  1224. */
  1225. fp = fopen("dummy.bin","wt");
  1226. for (i = 0; i < 100; i++) {
  1227. fprintf(fp,"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
  1228. }
  1229. fclose(fp);
  1230. }
  1231. #endif