SAVELOAD.CPP (59713B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 16 /* $Header: F:\projects\c&c\vcs\code\saveload.cpv 2.18 16 Oct 1995 16:48:44 JOE_BOSTIC $ */ 17 /*********************************************************************************************** 18 *** 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 *** 19 *********************************************************************************************** 20 * * 21 * Project Name : Command & Conquer * 22 * * 23 * File Name : SAVELOAD.CPP * 24 * * 25 * Programmer : Joe L. Bostic * 26 * * 27 * Start Date : August 23, 1994 * 28 * * 29 * Last Update : June 24, 1995 [JLB] * 30 * * 31 *---------------------------------------------------------------------------------------------* 32 * Functions: * 33 * Code_All_Pointers -- Code all pointers. * 34 * Decode_All_Pointers -- Decodes all pointers. * 35 * Get_Savefile_Info -- gets description, scenario #, house * 36 * Load_Game -- loads a saved game * 37 * Load_Misc_Values -- Loads miscellaneous variables. * 38 * Load_Misc_Values -- loads miscellaneous variables * 39 * Read_Object -- reads an object from disk, in a safe way * 40 * Save_Game -- saves a game to disk * 41 * Save_Misc_Values -- saves miscellaneous variables * 42 * Target_To_TechnoType -- converts TARGET to TechnoTypeClass * 43 * TechnoType_To_Target -- converts TechnoTypeClass to TARGET * 44 * Write_Object -- reads an object from disk, in a safe way * 45 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 46 47 #include "function.h" 48 49 extern bool DLLSave(FileClass &file); 50 extern bool DLLLoad(FileClass &file); 51 52 53 /* 54 ********************************** Defines ********************************** 55 */ 56 #define SAVEGAME_VERSION (DESCRIP_MAX + \ 57 0x01000003 + ( \ 58 sizeof(AircraftClass) + \ 59 sizeof(AircraftTypeClass) + \ 60 sizeof(AnimClass) + \ 61 sizeof(AnimTypeClass) + \ 62 sizeof(BuildingClass) + \ 63 sizeof(BuildingTypeClass) + \ 64 sizeof(BulletClass) + \ 65 sizeof(BulletTypeClass) + \ 66 sizeof(HouseClass) + \ 67 sizeof(HouseTypeClass) + \ 68 sizeof(InfantryClass) + \ 69 sizeof(InfantryTypeClass) + \ 70 sizeof(OverlayClass) + \ 71 sizeof(OverlayTypeClass) + \ 72 sizeof(SmudgeClass) + \ 73 sizeof(SmudgeTypeClass) + \ 74 sizeof(TeamClass) + \ 75 sizeof(TeamTypeClass) + \ 76 sizeof(TemplateClass) + \ 77 sizeof(TemplateTypeClass) + \ 78 sizeof(TerrainClass) + \ 79 sizeof(TerrainTypeClass) + \ 80 sizeof(UnitClass) + \ 81 sizeof(UnitTypeClass) + \ 82 sizeof(MouseClass) + \ 83 sizeof(CellClass) + \ 84 sizeof(FactoryClass) + \ 85 sizeof(BaseClass) + \ 86 sizeof(LayerClass) + \ 87 sizeof(BriefingText) + \ 88 sizeof(Waypoint))) 89 90 91 /*************************************************************************** 92 * Save_Game -- saves a game to disk * 93 * * 94 * Saving the Map: * 95 * DisplayClass::Save() invokes CellClass's Write() for every cell * 96 * that needs to be saved. A cell needs to be saved if it contains * 97 * any special data at all, such as a TIcon, or an Occupier. * 98 * The cell saves its own CellTrigger pointer, converted to a TARGET. * 99 * * 100 * Saving game objects: * 101 * - Any object stored in an ArrayOf class needs to be saved. The ArrayOf* 102 * Save() routine invokes each object's Write() routine, if that * 103 * object's IsActive is set. * 104 * * 105 * Saving the layers: * 106 * The Map's Layers (Ground, Air, etc) of things that are on the map, * 107 * and the Logic's Layer of things to process both need to be saved. * 108 * LayerClass::Save() writes the entire layer array to disk * 109 * * 110 * Saving the houses: * 111 * Each house needs to be saved, to record its Credits, Power, etc. * 112 * * 113 * Saving miscellaneous data: * 114 * There are a lot of miscellaneous variables to save, such as the * 115 * map's dimensions, the player's house, etc. * 116 * * 117 * INPUT: * 118 * id numerical ID, for the file extension * 119 * * 120 * OUTPUT: * 121 * true = OK, false = error * 122 * * 123 * WARNINGS: * 124 * none. * 125 * * 126 * HISTORY: * 127 * 12/28/1994 BR : Created. * 128 *=========================================================================*/ 129 bool Save_Game(int id,char *descr) 130 { 131 char name[_MAX_FNAME+_MAX_EXT]; 132 133 /* 134 ** Generate the filename to save 135 */ 136 sprintf(name, "SAVEGAME.%03d", id); 137 138 return Save_Game(name, descr); 139 } 140 141 142 /* 143 ** Version that takes file name. ST - 9/9/2019 11:10AM 144 */ 145 bool Save_Game(const char *file_name, const char *descr) 146 { 147 RawFileClass file; 148 int i; 149 unsigned long version; 150 unsigned scenario; 151 HousesType house; 152 char descr_buf[DESCRIP_MAX]; 153 154 scenario = Scenario; // get current scenario # 155 house = PlayerPtr->Class->House; // get current house 156 157 /* 158 ** Code everybody's pointers 159 */ 160 Code_All_Pointers(); 161 162 /* 163 ** Open the file 164 */ 165 if (!file.Open(file_name, WRITE)) { 166 Decode_All_Pointers(); 167 return(false); 168 } 169 170 /* 171 ** Save the DLLs variables first, so we can do a version check in the DLL when we begin the load 172 */ 173 if (RunningAsDLL) { 174 if (!DLLSave(file)) { 175 file.Close(); 176 Decode_All_Pointers(); 177 return false; 178 } 179 } 180 181 /* 182 ** Save the description, scenario #, and house 183 ** (scenario # & house are saved separately from the actual Scenario & 184 ** PlayerPtr globals for convenience; we can quickly find out which 185 ** house & scenario this save-game file is for by reading these values. 186 ** Also, PlayerPtr is stored in a coded form in Save_Misc_Values(), 187 ** which may or may not be a HousesType number; so, saving 'house' 188 ** here ensures we can always pull out the house for this file.) 189 */ 190 sprintf(descr_buf, "%s\r\n",descr); // put CR-LF after text 191 descr_buf[strlen(descr_buf) + 1] = 26; // put CTRL-Z after NULL 192 193 if (file.Write(descr_buf, DESCRIP_MAX) != DESCRIP_MAX) { 194 file.Close(); 195 return(false); 196 } 197 198 if (file.Write(&scenario, sizeof(scenario)) != sizeof(scenario)) { 199 file.Close(); 200 return(false); 201 } 202 203 if (file.Write(&house, sizeof(house)) != sizeof(house)) { 204 file.Close(); 205 return(false); 206 } 207 208 /* 209 ** Save the save-game version, for loading verification 210 */ 211 version = SAVEGAME_VERSION; 212 213 if (file.Write(&version, sizeof(version)) != sizeof(version)) { 214 file.Close(); 215 return(false); 216 } 217 218 Call_Back(); 219 /* 220 ** Save the map. The map must be saved first, since it saves the Theater. 221 */ 222 Map.Save(file); 223 224 Call_Back(); 225 /* 226 ** Save all game objects. This code saves every object that's stored in a 227 ** TFixedIHeap class. 228 */ 229 if (!Houses.Save(file) || 230 !TeamTypes.Save(file) || 231 !Teams.Save(file) || 232 !Triggers.Save(file) || 233 !Aircraft.Save(file) || 234 !Anims.Save(file) || 235 !Buildings.Save(file) || 236 !Bullets.Save(file) || 237 !Infantry.Save(file) || 238 !Overlays.Save(file) || 239 !Smudges.Save(file) || 240 !Templates.Save(file) || 241 !Terrains.Save(file) || 242 !Units.Save(file) || 243 !Factories.Save(file)) { 244 file.Close(); 245 246 Decode_All_Pointers(); 247 248 return(false); 249 } 250 251 Call_Back(); 252 /* 253 ** Save the Logic & Map layers 254 */ 255 if (!Logic.Save(file)) { 256 file.Close(); 257 Decode_All_Pointers(); 258 return(false); 259 } 260 261 for (i = 0; i < LAYER_COUNT; i++) { 262 if (!Map.Layer[i].Save(file)) { 263 file.Close(); 264 Decode_All_Pointers(); 265 return(false); 266 } 267 } 268 269 /* 270 ** Save the Score 271 */ 272 if (!Score.Save(file)) { 273 file.Close(); 274 Decode_All_Pointers(); 275 return(false); 276 } 277 278 /* 279 ** Save the AI Base 280 */ 281 if (!Base.Save(file)) { 282 file.Close(); 283 Decode_All_Pointers(); 284 return(false); 285 } 286 287 /* 288 ** Save miscellaneous variables. 289 */ 290 if (!Save_Misc_Values(file)) { 291 file.Close(); 292 Decode_All_Pointers(); 293 return(false); 294 } 295 296 Call_Back(); 297 298 /* 299 ** Close the file; we're done 300 */ 301 file.Close(); 302 Decode_All_Pointers(); 303 304 return(true); 305 } 306 307 308 /*************************************************************************** 309 * Load_Game -- loads a saved game * 310 * * 311 * This routine loads the data in the same way it was saved out. * 312 * * 313 * Loading the Map: * 314 * - DisplayClass::Load() invokes CellClass's Load() for every cell * 315 * that was saved. * 316 * - The cell loads its own CellTrigger pointer. * 317 * * 318 * Loading game objects: * 319 * - IHeap's Load() routine loads the # of objects stored, and loads * 320 * each object. * 321 * - Triggers: Add themselves to the HouseTriggers if they're associated * 322 * with a house * 323 * * 324 * Loading the layers: * 325 * LayerClass::Load() reads the entire layer array to disk * 326 * * 327 * Loading the houses: * 328 * Each house is loaded in its entirety. * 329 * * 330 * Loading miscellaneous data: * 331 * There are a lot of miscellaneous variables to load, such as the * 332 * map's dimensions, the player's house, etc. * 333 * * 334 * INPUT: * 335 * id numerical ID, for the file extension * 336 * * 337 * OUTPUT: * 338 * true = OK, false = error * 339 * * 340 * WARNINGS: * 341 * If this routine returns false, the entire game will be in an * 342 * unknown state, so the scenario will have to be re-initialized. * 343 * * 344 * HISTORY: * 345 * 12/28/1994 BR : Created. * 346 *=========================================================================*/ 347 bool Load_Game(int id) 348 { 349 char name[_MAX_FNAME+_MAX_EXT]; 350 351 /* 352 ** Generate the filename to load 353 */ 354 sprintf(name, "SAVEGAME.%03d", id); 355 356 return Load_Game(name); 357 } 358 359 /* 360 ** Version that takes a file name instead. ST - 9/9/2019 11:13AM 361 */ 362 bool Load_Game(const char *file_name) 363 { 364 RawFileClass file; 365 int i; 366 unsigned long version; 367 unsigned scenario; 368 HousesType house; 369 char descr_buf[DESCRIP_MAX]; 370 371 /* 372 ** Open the file 373 */ 374 if (!file.Open(file_name, READ)) { 375 return(false); 376 } 377 378 /* 379 ** Load the DLLs variables first, in case we need to do something different based on version 380 */ 381 if (RunningAsDLL) { 382 if (!DLLLoad(file)) { 383 file.Close(); 384 return false; 385 } 386 } 387 388 /* 389 ** Read & discard the save-game's header info 390 */ 391 if (file.Read(descr_buf, DESCRIP_MAX) != DESCRIP_MAX) { 392 file.Close(); 393 return(false); 394 } 395 396 if (file.Read(&scenario, sizeof(scenario)) != sizeof(scenario)) { 397 file.Close(); 398 return(false); 399 } 400 401 if (file.Read(&house, sizeof(house)) != sizeof(house)) { 402 file.Close(); 403 return(false); 404 } 405 406 Call_Back(); 407 /* 408 ** Clear the scenario so we start fresh; this calls the Init_Clear() routine 409 ** for the Map, and all object arrays. It has the following important 410 ** effects: 411 ** - Every cell is cleared to 0's, via MapClass::Init_Clear() 412 ** - All heap elements' are cleared 413 ** - The Houses are Initialized, which also clears their HouseTriggers 414 ** array 415 ** - The map's Layers & Logic Layer are cleared to empty 416 ** - The list of currently-selected objects is cleared 417 */ 418 Clear_Scenario(); 419 420 /* 421 ** Read in & verify the save-game ID code 422 */ 423 if (file.Read(&version,sizeof(version)) != sizeof(version)) { 424 file.Close(); 425 return(false); 426 } 427 428 if (version != SAVEGAME_VERSION) { 429 file.Close(); 430 return(false); 431 } 432 433 Call_Back(); 434 /* 435 ** Set the required CD to be in the drive according to the scenario 436 ** loaded. 437 */ 438 if (RequiredCD != -2) { 439 if (scenario >= 20 && scenario <60 && GameToPlay == GAME_NORMAL) { 440 RequiredCD = 2; 441 } else { 442 if (scenario >= 60){ 443 /* 444 ** This is a gateway bonus scenario 445 */ 446 RequiredCD = -1; 447 }else{ 448 if (house == HOUSE_GOOD) { 449 RequiredCD = 0; 450 } else { 451 RequiredCD = 1; 452 } 453 } 454 } 455 } 456 if(!Force_CD_Available(RequiredCD)) { 457 Prog_End("Load_Game - CD not found", true); 458 if (!RunningAsDLL) { 459 exit(EXIT_FAILURE); 460 } 461 return false; 462 } 463 464 Call_Back(); 465 466 /* 467 ** Load the map. The map comes first, since it loads the Theater & init's 468 ** mixfiles. The map calls all the type-class's Init routines, telling them 469 ** what the Theater is; this must be done before any objects are created, so 470 ** they'll be properly created. 471 */ 472 Map.Load(file); 473 474 Call_Back(); 475 /* 476 ** Load the object data. 477 */ 478 if (!Houses.Load(file) || 479 !TeamTypes.Load(file) || 480 !Teams.Load(file) || 481 !Triggers.Load(file) || 482 !Aircraft.Load(file) || 483 !Anims.Load(file) || 484 !Buildings.Load(file) || 485 !Bullets.Load(file) || 486 !Infantry.Load(file) || 487 !Overlays.Load(file) || 488 !Smudges.Load(file) || 489 !Templates.Load(file) || 490 !Terrains.Load(file) || 491 !Units.Load(file) || 492 !Factories.Load(file)) { 493 file.Close(); 494 return(false); 495 } 496 497 Call_Back(); 498 /* 499 ** Load the Logic & Map Layers 500 */ 501 if (!Logic.Load(file)) { 502 file.Close(); 503 return(false); 504 } 505 for (i = 0; i < LAYER_COUNT; i++) { 506 if (!Map.Layer[i].Load(file)) { 507 file.Close(); 508 return(false); 509 } 510 } 511 512 Call_Back(); 513 /* 514 ** Load the Score 515 */ 516 if (!Score.Load(file)) { 517 file.Close(); 518 return(false); 519 } 520 521 /* 522 ** Load the AI Base 523 */ 524 if (!Base.Load(file)) { 525 file.Close(); 526 return(false); 527 } 528 529 /* 530 ** Load miscellaneous variables, including the map size & the Theater 531 */ 532 if (!Load_Misc_Values(file)) { 533 file.Close(); 534 return(false); 535 } 536 537 file.Close(); 538 Decode_All_Pointers(); 539 Map.Init_IO(); 540 Map.Flag_To_Redraw(true); 541 542 Fixup_Scenario(); 543 544 ScenarioInit = 0; 545 546 /* 547 ** Fixup remap tables. ST - 2/28/2020 1:50PM 548 */ 549 for (HousesType house = HOUSE_FIRST; house < HOUSE_COUNT; house++) { 550 HouseClass * hptr = HouseClass::As_Pointer(house); 551 if (hptr && hptr->IsActive) { 552 hptr->Init_Data(hptr->RemapColor, hptr->ActLike, hptr->Credits); 553 } 554 } 555 556 /* 557 ** Re-init unit trackers. They will be garbage pointers after the load 558 */ 559 for (HousesType house = HOUSE_FIRST; house < HOUSE_COUNT; house++) { 560 HouseClass * hptr = HouseClass::As_Pointer(house); 561 if (hptr && hptr->IsActive) { 562 hptr->Init_Unit_Trackers(); 563 } 564 } 565 566 #ifdef DEMO 567 if (Scenario != 10 && Scenario != 1 && Scenario != 6) { 568 Clear_Scenario(); 569 return(false); 570 } 571 #endif 572 573 Call_Back(); 574 return(true); 575 } 576 577 578 /*************************************************************************** 579 * Save_Misc_Values -- saves miscellaneous variables * 580 * * 581 * INPUT: * 582 * file file to use for writing * 583 * * 584 * OUTPUT: * 585 * true = success, false = failure * 586 * * 587 * WARNINGS: * 588 * none. * 589 * * 590 * HISTORY: * 591 * 12/29/1994 BR : Created. * 592 *=========================================================================*/ 593 bool Save_Misc_Values(FileClass &file) 594 { 595 int i, j; 596 int count; // # ptrs in 'CurrentObject' 597 ObjectClass * ptr; // for saving 'CurrentObject' ptrs 598 599 /* 600 ** Player's House. 601 */ 602 if (file.Write(&PlayerPtr, sizeof(PlayerPtr)) != sizeof(PlayerPtr)) { 603 return(false); 604 } 605 606 /* 607 ** Save this scenario number. 608 */ 609 if (file.Write(&Scenario, sizeof(Scenario)) != sizeof(Scenario)) { 610 return(false); 611 } 612 613 /* 614 ** Save frame #. 615 */ 616 if (file.Write(&Frame, sizeof(Frame)) != sizeof(Frame)) { 617 return(false); 618 } 619 620 /* 621 ** Save VQ Movie names. 622 */ 623 if (file.Write(WinMovie, sizeof(WinMovie)) != sizeof(WinMovie)) { 624 return(false); 625 } 626 627 if (file.Write(LoseMovie, sizeof(LoseMovie)) != sizeof(LoseMovie)) { 628 return(false); 629 } 630 631 /* 632 ** Save currently-selected objects list. 633 ** Save the # of ptrs in the list. 634 */ 635 for (i = 0; i < SelectedObjectsType::COUNT; i++) { 636 DynamicVectorClass<ObjectClass *>& selection = CurrentObject.Raw(i); 637 count = selection.Count(); 638 if (file.Write(&count, sizeof(count)) != sizeof(count)) { 639 return(false); 640 } 641 642 /* 643 ** Save the pointers. 644 */ 645 for (j = 0; j < count; j++) { 646 ptr = selection[j]; 647 if (file.Write(&ptr, sizeof(ptr)) != sizeof(ptr)) { 648 return(false); 649 } 650 } 651 } 652 653 /* 654 ** Save the list of waypoints. 655 */ 656 if (file.Write(Waypoint, sizeof(Waypoint)) != sizeof(Waypoint)) { 657 return(false); 658 } 659 660 file.Write(&ScenDir, sizeof(ScenDir)); 661 file.Write(&ScenVar, sizeof(ScenVar)); 662 file.Write(&CarryOverMoney, sizeof(CarryOverMoney)); 663 file.Write(&CarryOverPercent, sizeof(CarryOverPercent)); 664 file.Write(&BuildLevel, sizeof(BuildLevel)); 665 file.Write(BriefMovie, sizeof(BriefMovie)); 666 file.Write(Views, sizeof(Views)); 667 file.Write(&EndCountDown, sizeof(EndCountDown)); 668 file.Write(BriefingText, sizeof(BriefingText)); 669 670 // This is new... 671 file.Write(ActionMovie, sizeof(ActionMovie)); 672 673 return(true); 674 } 675 676 677 /*********************************************************************************************** 678 * Load_Misc_Values -- Loads miscellaneous variables. * 679 * * 680 * INPUT: file -- The file to load the misc values from. * 681 * * 682 * OUTPUT: Was the misc load process successful? * 683 * * 684 * WARNINGS: none * 685 * * 686 * HISTORY: * 687 * 06/24/1995 BRR : Created. * 688 *=============================================================================================*/ 689 bool Load_Misc_Values(FileClass &file) 690 { 691 int i, j; 692 int count; // # ptrs in 'CurrentObject' 693 ObjectClass * ptr; // for loading 'CurrentObject' ptrs 694 695 /* 696 ** Player's House. 697 */ 698 if (file.Read(&PlayerPtr, sizeof(PlayerPtr)) != sizeof(PlayerPtr)) { 699 return(false); 700 } 701 702 /* 703 ** Read this scenario number. 704 */ 705 if (file.Read(&Scenario,sizeof(Scenario)) != sizeof(Scenario)) { 706 return(false); 707 } 708 709 /* 710 ** Load frame #. 711 */ 712 if (file.Read(&Frame, sizeof(Frame)) != sizeof(Frame)) { 713 return(false); 714 } 715 716 /* 717 ** Load VQ Movie names. 718 */ 719 if (file.Read(WinMovie, sizeof(WinMovie)) != sizeof(WinMovie)) { 720 return(false); 721 } 722 723 if (file.Read(LoseMovie, sizeof(LoseMovie)) != sizeof(LoseMovie)) { 724 return(false); 725 } 726 727 for (i = 0; i < SelectedObjectsType::COUNT; i++) { 728 /* 729 ** Load currently-selected objects list. 730 ** Load the # of ptrs in the list. 731 */ 732 DynamicVectorClass<ObjectClass *>& selection = CurrentObject.Raw(i); 733 if (file.Read(&count, sizeof(count)) != sizeof(count)) { 734 return(false); 735 } 736 737 /* 738 ** Load the pointers. 739 */ 740 for (j = 0; j < count; j++) { 741 if (file.Read(&ptr, sizeof(ptr)) != sizeof(ptr)) { 742 return(false); 743 } 744 selection.Add(ptr); // add to the list 745 } 746 } 747 748 /* 749 ** Save the list of waypoints. 750 */ 751 if (file.Read(Waypoint, sizeof(Waypoint)) != sizeof(Waypoint)) { 752 return(false); 753 } 754 755 file.Read(&ScenDir, sizeof(ScenDir)); 756 file.Read(&ScenVar, sizeof(ScenVar)); 757 file.Read(&CarryOverMoney, sizeof(CarryOverMoney)); 758 file.Read(&CarryOverPercent, sizeof(CarryOverPercent)); 759 file.Read(&BuildLevel, sizeof(BuildLevel)); 760 file.Read(BriefMovie, sizeof(BriefMovie)); 761 file.Read(Views, sizeof(Views)); 762 file.Read(&EndCountDown, sizeof(EndCountDown)); 763 file.Read(BriefingText, sizeof(BriefingText)); 764 765 if (file.Seek(0, SEEK_CUR) < file.Size()) { 766 file.Read(ActionMovie, sizeof(ActionMovie)); 767 } 768 769 return(true); 770 } 771 772 773 /* 774 ** ST - 9/26/2019 11:43AM 775 */ 776 extern void DLL_Code_Pointers(void); 777 extern void DLL_Decode_Pointers(void); 778 779 780 /*********************************************************************************************** 781 * Code_All_Pointers -- Code all pointers. * 782 * * 783 * INPUT: none * 784 * * 785 * OUTPUT: none * 786 * * 787 * WARNINGS: none * 788 * * 789 * HISTORY: * 790 * 06/24/1995 BRR : Created. * 791 *=============================================================================================*/ 792 void Code_All_Pointers(void) 793 { 794 int i, j; 795 796 /* 797 ** The Map. 798 */ 799 Map.Code_Pointers(); 800 801 /* 802 ** The ArrayOf's. 803 */ 804 TeamTypes.Code_Pointers(); 805 Teams.Code_Pointers(); 806 Triggers.Code_Pointers(); 807 Aircraft.Code_Pointers(); 808 Anims.Code_Pointers(); 809 Buildings.Code_Pointers(); 810 Bullets.Code_Pointers(); 811 Infantry.Code_Pointers(); 812 Overlays.Code_Pointers(); 813 Smudges.Code_Pointers(); 814 Templates.Code_Pointers(); 815 Terrains.Code_Pointers(); 816 Units.Code_Pointers(); 817 Factories.Code_Pointers(); 818 819 /* 820 ** The Layers. 821 */ 822 Logic.Code_Pointers(); 823 for (i = 0; i < LAYER_COUNT; i++) { 824 Map.Layer[i].Code_Pointers(); 825 } 826 827 /* 828 ** The Score. 829 */ 830 Score.Code_Pointers(); 831 832 /* 833 ** The Base. 834 */ 835 Base.Code_Pointers(); 836 837 /* 838 ** PlayerPtr. 839 */ 840 PlayerPtr = (HouseClass *)(PlayerPtr->Class->House); 841 842 /* 843 ** Currently-selected objects. 844 */ 845 for (i = 0; i < SelectedObjectsType::COUNT; i++) { 846 DynamicVectorClass<ObjectClass *>& selection = CurrentObject.Raw(i); 847 for (j = 0; j < selection.Count(); j++) { 848 selection[j] = (ObjectClass *)selection[j]->As_Target(); 849 } 850 } 851 852 /* 853 ** DLL data 854 */ 855 DLL_Code_Pointers(); 856 857 /* 858 ** Houses must be coded last, because the Class->House member of the HouseClass 859 ** is used to code HouseClass pointers for all other objects, and if Class is 860 ** coded, it will point to a meaningless value. 861 */ 862 Houses.Code_Pointers(); 863 } 864 865 866 /*********************************************************************************************** 867 * Decode_All_Pointers -- Decodes all pointers. * 868 * * 869 * INPUT: none * 870 * * 871 * OUTPUT: none * 872 * * 873 * WARNINGS: none * 874 * * 875 * HISTORY: * 876 * 06/24/1995 BRR : Created. * 877 *=============================================================================================*/ 878 void Decode_All_Pointers(void) 879 { 880 int i, j; 881 882 /* 883 ** The Map. 884 */ 885 Map.Decode_Pointers(); 886 887 /* 888 ** Decode houses first, so we can properly decode all other objects' 889 ** House pointers 890 */ 891 Houses.Decode_Pointers(); 892 893 /* 894 ** DLL data 895 */ 896 DLL_Decode_Pointers(); 897 898 /* 899 ** The ArrayOf's. 900 */ 901 TeamTypes.Decode_Pointers(); 902 Teams.Decode_Pointers(); 903 Triggers.Decode_Pointers(); 904 Aircraft.Decode_Pointers(); 905 Anims.Decode_Pointers(); 906 Buildings.Decode_Pointers(); 907 Bullets.Decode_Pointers(); 908 Infantry.Decode_Pointers(); 909 Overlays.Decode_Pointers(); 910 Smudges.Decode_Pointers(); 911 Templates.Decode_Pointers(); 912 Terrains.Decode_Pointers(); 913 Units.Decode_Pointers(); 914 Factories.Decode_Pointers(); 915 916 /* 917 ** The Layers. 918 */ 919 Logic.Decode_Pointers(); 920 for (i = 0; i < LAYER_COUNT; i++) { 921 Map.Layer[i].Decode_Pointers(); 922 } 923 924 /* 925 ** The Score. 926 */ 927 Score.Decode_Pointers(); 928 929 /* 930 ** The Base. 931 */ 932 Base.Decode_Pointers(); 933 934 /* 935 ** PlayerPtr. 936 */ 937 PlayerPtr = HouseClass::As_Pointer(*((HousesType*)&PlayerPtr)); 938 Whom = PlayerPtr->Class->House; 939 switch (PlayerPtr->Class->House) { 940 case HOUSE_GOOD: 941 ScenPlayer = SCEN_PLAYER_GDI; 942 break; 943 944 case HOUSE_BAD: 945 ScenPlayer = SCEN_PLAYER_NOD; 946 break; 947 948 case HOUSE_JP: 949 ScenPlayer = SCEN_PLAYER_JP; 950 break; 951 } 952 Check_Ptr(PlayerPtr,__FILE__,__LINE__); 953 954 if (PlayerPtr->ActLike == HOUSE_JP) { 955 ScenPlayer = SCEN_PLAYER_JP; 956 } 957 Set_Scenario_Name(ScenarioName, Scenario, ScenPlayer, ScenDir, ScenVar); 958 959 /* 960 ** Currently-selected objects. 961 */ 962 for (i = 0; i < SelectedObjectsType::COUNT; i++) { 963 DynamicVectorClass<ObjectClass *>& selection = CurrentObject.Raw(i); 964 for (j = 0; j < selection.Count(); j++) { 965 unsigned long target_as_object_ptr = reinterpret_cast<unsigned long>(selection[j]); 966 TARGET target = (TARGET)target_as_object_ptr; 967 selection[j] = As_Object(target); 968 Check_Ptr(selection[j],__FILE__,__LINE__); 969 } 970 } 971 972 /* 973 ** Last-Minute Fixups; to resolve these pointers properly requires all other 974 ** pointers to be loaded & decoded. 975 */ 976 if (Map.PendingObjectPtr) { 977 Map.PendingObject = &Map.PendingObjectPtr->Class_Of(); 978 Check_Ptr((void *)Map.PendingObject, __FILE__, __LINE__); 979 Map.Set_Cursor_Shape(Map.PendingObject->Occupy_List(true)); 980 } else { 981 Map.PendingObject = 0; 982 Map.Set_Cursor_Shape(0); 983 } 984 } 985 986 987 /*********************************************************************************************** 988 * Read_Object -- reads an object from a file * 989 * * 990 * Replacement for the original code below, which doesn't work with MSVC * 991 * We now assume that the vtable is 4 bytes, and is at the beginning of the class * 992 * It's the caller's responsibility to make sure the VTable is correct * 993 * * 994 * INPUT: none * 995 * * 996 * OUTPUT: none * 997 * * 998 * WARNINGS: none * 999 * * 1000 * HISTORY: * 1001 * 01/10/1995 BR : Created. * 1002 * 9/10/2019 12:34PM ST : Updated for MS compiler * 1003 *=============================================================================================*/ 1004 bool Read_Object(void *ptr, int class_size, FileClass & file, bool has_vtable) 1005 { 1006 int size; 1007 1008 /* 1009 ** Read size of this chunk. 1010 */ 1011 if (file.Read(&size,sizeof(size)) != sizeof(size)) { 1012 return(false); 1013 } 1014 1015 /* 1016 ** Error if incorrect size. 1017 */ 1018 if (size != class_size) { 1019 return false; 1020 } 1021 1022 int vtable_adjust = has_vtable ? 4 : 0; 1023 unsigned char *object_ptr = static_cast<unsigned char *>(ptr); 1024 1025 if (has_vtable) { 1026 /* 1027 ** Need to skip the vtable read. 1028 */ 1029 int dummy; 1030 file.Read(&dummy, vtable_adjust); 1031 } 1032 1033 /* 1034 ** Read object data. 1035 */ 1036 if (file.Read(object_ptr + vtable_adjust, class_size - vtable_adjust) != (class_size - vtable_adjust)) { 1037 return(false); 1038 } 1039 1040 return true; 1041 } 1042 1043 1044 #if (0) 1045 /*********************************************************************************************** 1046 * Write_Object -- writes an object to a file * 1047 * * 1048 * This routine writes an object, skipping the embedded virtual function table pointer. * 1049 * * 1050 * INPUT: * 1051 * ptr pointer to object to write * 1052 * class_size size of the class itself * 1053 * file file to use for I/O * 1054 * * 1055 * OUTPUT: * 1056 * true = OK, false = error * 1057 * * 1058 * WARNINGS: * 1059 * This routine ASSUMES the program modules are compiled with: * 1060 * -Vb- Always make the virtual function table ptr 2 bytes long * 1061 * -Vt Put the virtual function table after the 1st class's data * 1062 * * 1063 * Also see warnings for Read_Object(). * 1064 * * 1065 * HISTORY: * 1066 * 01/10/1995 BR : Created. * 1067 * 9/10/2019 12:34PM ST : Updated for MS compiler * 1068 *=============================================================================================*/ 1069 bool Write_Object(void *ptr, int class_size, FileClass & file) 1070 { 1071 /* 1072 ** Test assumptions about class size. 1073 */ 1074 class TestClass { 1075 virtual void Test(void) = 0; 1076 }; 1077 1078 if (sizeof(TestClass) != 4) { 1079 /* 1080 ** Crash. 1081 */ 1082 *((int*)0) = 0; 1083 } 1084 1085 /* 1086 ** Save size of this chunk. 1087 */ 1088 if (file.Write(&class_size,sizeof(class_size)) != sizeof(class_size)) { 1089 return(false); 1090 } 1091 1092 /* 1093 ** Save object data. 1094 */ 1095 if (file.Write(ptr, class_size) != (class_size)) { 1096 return(false); 1097 } 1098 1099 return(true); 1100 } 1101 1102 1103 #endif 1104 1105 1106 #if (0) //ST - 9/10/2019 12:43PM 1107 1108 /*********************************************************************************************** 1109 * Read_Object -- reads an object from disk * 1110 * * 1111 * This routine reads in an object and fills in the virtual function table pointer. * 1112 * * 1113 * INPUT: * 1114 * ptr pointer to object to read * 1115 * base_size size of object's absolute base class * 1116 * class_size size of the class itself * 1117 * file file to use for I/O * 1118 * vtable virtual function table pointer value, NULL if none * 1119 * * 1120 * OUTPUT: * 1121 * true = OK, false = error * 1122 * * 1123 * WARNINGS: * 1124 * This routine ASSUMES the program modules are compiled with: * 1125 * -Vb- Always make the virtual function table ptr 2 bytes long * 1126 * -Vt Put the virtual function table after the 1st class's data * 1127 * * 1128 * ALSO, the class used to compute 'base_size' must come first in a multiple-inheritence * 1129 * hierarchy. AND, if your class multiply-inherits from other classes, only ONE of those * 1130 * classes can contain virtual functions! If you include virtual functions in the other * 1131 * classes, the compiler will generate multiple virtual function tables, and this load/save * 1132 * technique will fail. * 1133 * * 1134 * Each class hierarchy is stored in memory as a chain: first the data for the base-est * 1135 * class, then the virtual function table pointer for this hierarchy, then the data for * 1136 * all derived classes. If any of these derived classes multiply-inherit, the base class * 1137 * for the multiple inheritance is stored as a separate chain following this chain. The * 1138 * new chain will contain its own virtual function table pointer, if the multiply- * 1139 * inherited hierarchy contains any virtual functions. Thus, the declaration * 1140 * class A * 1141 * class B: public A * 1142 * class C: public B, X * 1143 * is stored as: * 1144 * A data * 1145 * A's Virtual Table Pointer * 1146 * B data * 1147 * X data * 1148 * [X's Virtual Table Pointer] * 1149 * C data * 1150 * * 1151 * and * 1152 * class A * 1153 * class B: public A * 1154 * class C: public X, B * 1155 * is stored in memory as: * 1156 * X data * 1157 * [X's Virtual Table Pointer] * 1158 * A data * 1159 * A's Virtual Table Pointer * 1160 * B data * 1161 * C data * 1162 * * 1163 * * 1164 * HISTORY: * 1165 * 01/10/1995 BR : Created. * 1166 *=============================================================================================*/ 1167 bool Read_Object(void *ptr, int base_size, int class_size, FileClass & file, void * vtable) 1168 { 1169 int size; // object size in bytes 1170 1171 /* 1172 ** Read size of this chunk. 1173 */ 1174 if (file.Read(&size,sizeof(size)) != sizeof(size)) { 1175 return(false); 1176 } 1177 1178 /* 1179 ** Error if incorrect size. 1180 */ 1181 if (size != class_size) { 1182 return(false); 1183 } 1184 1185 /* 1186 ** Read object data. 1187 */ 1188 if (file.Read(ptr, class_size) != (class_size)) { 1189 return(false); 1190 } 1191 1192 /* 1193 ** Fill in VTable. 1194 */ 1195 if (vtable) { 1196 ((void **)(((char *)ptr) + base_size - 4))[0] = vtable; 1197 } 1198 1199 return(true); 1200 } 1201 1202 #endif 1203 1204 1205 1206 /*********************************************************************************************** 1207 * Write_Object -- reads an object from disk, in a safe way * 1208 * * 1209 * This routine writes an object in 2 pieces, skipping the embedded * 1210 * virtual function table pointer. * 1211 * * 1212 * INPUT: * 1213 * ptr pointer to object to write * 1214 * class_size size of the class itself * 1215 * file file to use for I/O * 1216 * * 1217 * OUTPUT: * 1218 * true = OK, false = error * 1219 * * 1220 * WARNINGS: * 1221 * This routine ASSUMES the program modules are compiled with: * 1222 * -Vb- Always make the virtual function table ptr 2 bytes long * 1223 * -Vt Put the virtual function table after the 1st class's data * 1224 * * 1225 * Also see warnings for Read_Object(). * 1226 * * 1227 * HISTORY: * 1228 * 01/10/1995 BR : Created. * 1229 *=============================================================================================*/ 1230 bool Write_Object(void *ptr, int class_size, FileClass & file) 1231 { 1232 /* 1233 ** Save size of this chunk. 1234 */ 1235 if (file.Write(&class_size,sizeof(class_size)) != sizeof(class_size)) { 1236 return(false); 1237 } 1238 1239 /* 1240 ** Save object data. 1241 */ 1242 if (file.Write(ptr, class_size) != (class_size)) { 1243 return(false); 1244 } 1245 1246 return(true); 1247 } 1248 1249 1250 /*************************************************************************** 1251 * Get_Savefile_Info -- gets description, scenario #, house * 1252 * * 1253 * INPUT: * 1254 * id numerical ID, for the file extension * 1255 * buf buffer to store description in * 1256 * scenp ptr to variable to hold scenario * 1257 * housep ptr to variable to hold house * 1258 * * 1259 * OUTPUT: * 1260 * true = OK, false = error (save-game file invalid) * 1261 * * 1262 * WARNINGS: * 1263 * none. * 1264 * * 1265 * HISTORY: * 1266 * 01/12/1995 BR : Created. * 1267 *=========================================================================*/ 1268 bool Get_Savefile_Info(int id, char *buf, unsigned *scenp, HousesType *housep) 1269 { 1270 RawFileClass file; 1271 char name[_MAX_FNAME+_MAX_EXT]; 1272 unsigned long version; 1273 char descr_buf[DESCRIP_MAX]; 1274 1275 /* 1276 ** Generate the filename to load 1277 */ 1278 sprintf(name, "SAVEGAME.%03d", id); 1279 1280 /* 1281 ** If the file opens OK, read the file 1282 */ 1283 if (file.Open(name, READ)) { 1284 1285 /* 1286 ** Read in the description, scenario #, and the house 1287 */ 1288 if (file.Read(descr_buf, DESCRIP_MAX) != DESCRIP_MAX) { 1289 file.Close(); 1290 return(false); 1291 } 1292 1293 descr_buf[strlen(descr_buf) - 2] = '\0'; // trim off CR/LF 1294 strcpy(buf, descr_buf); 1295 1296 if (file.Read(scenp, sizeof(unsigned)) != sizeof(unsigned)) { 1297 file.Close(); 1298 return(false); 1299 } 1300 1301 if (file.Read(housep, sizeof(HousesType)) != sizeof(HousesType)) { 1302 file.Close(); 1303 return(false); 1304 } 1305 1306 /* 1307 ** Read & verify the save-game version # 1308 */ 1309 if (file.Read(&version,sizeof(version)) != sizeof(version)) { 1310 file.Close(); 1311 return(false); 1312 } 1313 1314 if (version!=SAVEGAME_VERSION) { 1315 file.Close(); 1316 return(false); 1317 } 1318 1319 file.Close(); 1320 1321 return(true); 1322 } 1323 return(false); 1324 } 1325 1326 1327 /*************************************************************************** 1328 * TechnoType_To_Target -- converts TechnoTypeClass to TARGET * 1329 * * 1330 * INPUT: * 1331 * ptr pointer to convert * 1332 * * 1333 * OUTPUT: * 1334 * target value * 1335 * * 1336 * WARNINGS: * 1337 * Be certain that you only use the returned target value by passing * 1338 * it to Target_To_TechnoType; do NOT call As_Techno, or you'll get * 1339 * a totally invalid pointer. * 1340 * * 1341 * HISTORY: * 1342 * 01/12/1995 BR : Created. * 1343 *=========================================================================*/ 1344 TARGET TechnoType_To_Target(TechnoTypeClass const * ptr) 1345 { 1346 TARGET target; 1347 1348 switch (ptr->What_Am_I()) { 1349 case RTTI_INFANTRYTYPE: 1350 target = Build_Target(KIND_INFANTRY, ((InfantryTypeClass const *)ptr)->Type); 1351 break; 1352 1353 case RTTI_UNITTYPE: 1354 target = Build_Target(KIND_UNIT, ((UnitTypeClass const *)ptr)->Type); 1355 break; 1356 1357 case RTTI_AIRCRAFTTYPE: 1358 target = Build_Target(KIND_AIRCRAFT, ((AircraftTypeClass const *)ptr)->Type); 1359 break; 1360 1361 case RTTI_BUILDINGTYPE: 1362 target = Build_Target(KIND_BUILDING, ((BuildingTypeClass const *)ptr)->Type); 1363 break; 1364 1365 default: 1366 target = 0; 1367 break; 1368 } 1369 1370 return(target); 1371 } 1372 1373 1374 /*************************************************************************** 1375 * Target_To_TechnoType -- converts TARGET to TechnoTypeClass * 1376 * * 1377 * INPUT: * 1378 * target TARGET value to convert * 1379 * * 1380 * OUTPUT: * 1381 * pointer to the TechnoTypeClass for this target value * 1382 * * 1383 * WARNINGS: * 1384 * The TARGET value MUST have been generated with TechnoType_To_Target;* 1385 * If you give this routine a target generated by an As_Target() * 1386 * routine, it will return a bogus pointer. * 1387 * * 1388 * HISTORY: * 1389 * 01/12/1995 BR : Created. * 1390 *=========================================================================*/ 1391 TechnoTypeClass const * Target_To_TechnoType(TARGET target) 1392 { 1393 switch (Target_Kind(target)) { 1394 case KIND_INFANTRY: 1395 return(&InfantryTypeClass::As_Reference((InfantryType)Target_Value(target))); 1396 1397 case KIND_UNIT: 1398 return(&UnitTypeClass::As_Reference((UnitType)Target_Value(target))); 1399 1400 case KIND_AIRCRAFT: 1401 return(&AircraftTypeClass::As_Reference((AircraftType)Target_Value(target))); 1402 1403 case KIND_BUILDING: 1404 return(&BuildingTypeClass::As_Reference((StructType)Target_Value(target))); 1405 } 1406 return(NULL); 1407 } 1408 1409 1410 /*************************************************************************** 1411 * Get_VTable -- gets the VTable pointer for the given object * 1412 * * 1413 * INPUT: * 1414 * ptr pointer to check * 1415 * * 1416 * OUTPUT: * 1417 * none * 1418 * * 1419 * WARNINGS: * 1420 * none * 1421 * * 1422 * HISTORY: * 1423 * 01/12/1995 BR : Created. * 1424 *=========================================================================*/ 1425 void * Get_VTable(void *ptr, int base_size) 1426 { 1427 return(((void **)(((char *)ptr) + base_size - 4))[0]); 1428 } 1429 1430 1431 /*************************************************************************** 1432 * Set_VTable -- sets the VTable pointer for the given object * 1433 * * 1434 * INPUT: * 1435 * ptr pointer to check * 1436 * base_size size of base class * 1437 * vtable value of VTable to plug in * 1438 * * 1439 * OUTPUT: * 1440 * none * 1441 * * 1442 * WARNINGS: * 1443 * none * 1444 * * 1445 * HISTORY: * 1446 * 01/12/1995 BR : Created. * 1447 *=========================================================================*/ 1448 void Set_VTable(void *ptr, int base_size, void *vtable) 1449 { 1450 ((void **)(((char *)ptr) + base_size - 4))[0] = vtable; 1451 } 1452 1453 1454 #if 0 1455 /**************************************************************************** 1456 Dump routine: prints everything about everything related to the Save/Load 1457 process (OK, not exactly everything, but lots of stuff) 1458 ****************************************************************************/ 1459 void Dump(void) 1460 { 1461 int i,j; 1462 FILE *fp; 1463 char *layername[] = { 1464 "Ground", 1465 "Air", 1466 "Top" 1467 }; 1468 1469 /* 1470 ------------------------------- Open file -------------------------------- 1471 */ 1472 fp = fopen("dump.txt","wt"); 1473 1474 /* 1475 ------------------------------ Logic Layer ------------------------------- 1476 */ 1477 fprintf(fp,"--------------------- Logic Layer ---------------------\n"); 1478 fprintf(fp,"Count: %d\n",Logic.Count()); 1479 for (j = 0; j < Logic.Count(); j++) { 1480 fprintf(fp, "Entry %d: %x \n",j,Logic[j]); 1481 } 1482 fprintf(fp,"\n"); 1483 1484 /* 1485 ------------------------------- Map Layers ------------------------------- 1486 */ 1487 for (i = 0; i < LAYER_COUNT; i++) { 1488 fprintf(fp,"----------------- Map Layer %s ---------------------\n", 1489 layername[i]); 1490 fprintf(fp,"Count: %d\n",Map.Layer[i].Count()); 1491 for (j = 0; j < Map.Layer[i].Count(); j++) { 1492 fprintf(fp, "Entry %d: %x \n",j,Map.Layer[i][j]); 1493 } 1494 } 1495 fprintf(fp,"\n"); 1496 1497 fprintf(fp,"------------------ TeamTypes --------------------------\n"); 1498 fprintf(fp,"ActiveCount: %d\n",TeamTypes.ActiveCount); 1499 for (i = 0; i < TEAMTYPE_MAX; i++) { 1500 fprintf(fp,"Entry %d: Active:%d Name:%s\n",i,TeamTypes[i].IsActive, 1501 TeamTypes[i].Get_Name()); 1502 } 1503 fprintf(fp,"\n"); 1504 1505 fprintf(fp,"------------------ Teams --------------------------\n"); 1506 fprintf(fp,"ActiveCount: %d\n",Teams.ActiveCount); 1507 for (i = 0; i < TEAM_MAX; i++) { 1508 fprintf(fp,"Entry %d: Active:%d Name:%s\n",i,Teams[i].IsActive, 1509 Teams[i].Class->Get_Name()); 1510 } 1511 fprintf(fp,"\n"); 1512 1513 fprintf(fp,"------------------ Triggers --------------------------\n"); 1514 fprintf(fp,"ActiveCount: %d\n",Triggers.ActiveCount); 1515 for (i = 0; i < TRIGGER_MAX; i++) { 1516 fprintf(fp,"Entry %d: Active:%d Name:%s\n",i,Triggers[i].IsActive, 1517 Triggers[i].Get_Name()); 1518 } 1519 fprintf(fp,"\n"); 1520 1521 fprintf(fp,"------------------ Aircraft --------------------------\n"); 1522 fprintf(fp,"ActiveCount: %d\n",Aircraft.ActiveCount); 1523 for (i = 0; i < AIRCRAFT_MAX; i++) { 1524 fprintf(fp,"Entry %d: Active:%d \n",i,Aircraft[i].IsActive); 1525 } 1526 fprintf(fp,"\n"); 1527 1528 fprintf(fp,"------------------ Anims --------------------------\n"); 1529 fprintf(fp,"ActiveCount: %d\n",Anims.ActiveCount); 1530 for (i = 0; i < ANIM_MAX; i++) { 1531 fprintf(fp,"Entry %d: Active:%d \n",i,Anims[i].IsActive); 1532 } 1533 fprintf(fp,"\n"); 1534 1535 fprintf(fp,"------------------ Buildings --------------------------\n"); 1536 fprintf(fp,"ActiveCount: %d\n",Buildings.ActiveCount); 1537 for (i = 0; i < BUILDING_MAX; i++) { 1538 fprintf(fp,"Entry %d: Active:%d \n",i,Buildings[i].IsActive); 1539 } 1540 fprintf(fp,"\n"); 1541 1542 fprintf(fp,"------------------ Bullets --------------------------\n"); 1543 fprintf(fp,"ActiveCount: %d\n",Bullets.ActiveCount); 1544 for (i = 0; i < BULLET_MAX; i++) { 1545 fprintf(fp,"Entry %d: Active:%d \n",i,Bullets[i].IsActive); 1546 } 1547 fprintf(fp,"\n"); 1548 1549 fprintf(fp,"------------------ Infantry --------------------------\n"); 1550 fprintf(fp,"ActiveCount: %d\n",Infantry.ActiveCount); 1551 for (i = 0; i < INFANTRY_MAX; i++) { 1552 fprintf(fp,"Entry %d: Active:%d \n",i,Infantry[i].IsActive); 1553 } 1554 fprintf(fp,"\n"); 1555 1556 fprintf(fp,"------------------ Overlays --------------------------\n"); 1557 fprintf(fp,"ActiveCount: %d\n",Overlays.ActiveCount); 1558 for (i = 0; i < OVERLAY_MAX; i++) { 1559 fprintf(fp,"Entry %d: Active:%d \n",i,Overlays[i].IsActive); 1560 } 1561 fprintf(fp,"\n"); 1562 1563 fprintf(fp,"------------------ Reinforcements --------------------------\n"); 1564 fprintf(fp,"ActiveCount: %d\n",Reinforcements.ActiveCount); 1565 for (i = 0; i < REINFORCEMENT_MAX; i++) { 1566 fprintf(fp,"Entry %d: Active:%d \n",i,Reinforcements[i].IsActive); 1567 } 1568 fprintf(fp,"\n"); 1569 1570 fprintf(fp,"------------------ Smudges --------------------------\n"); 1571 fprintf(fp,"ActiveCount: %d\n",Smudges.ActiveCount); 1572 for (i = 0; i < SMUDGE_MAX; i++) { 1573 fprintf(fp,"Entry %d: Active:%d \n",i,Smudges[i].IsActive); 1574 } 1575 fprintf(fp,"\n"); 1576 1577 fprintf(fp,"------------------ Templates --------------------------\n"); 1578 fprintf(fp,"ActiveCount: %d\n",Templates.ActiveCount); 1579 for (i = 0; i < TEMPLATE_MAX; i++) { 1580 fprintf(fp,"Entry %d: Active:%d \n",i,Templates[i].IsActive); 1581 } 1582 fprintf(fp,"\n"); 1583 1584 fprintf(fp,"------------------ Terrains --------------------------\n"); 1585 fprintf(fp,"ActiveCount: %d\n",Terrains.ActiveCount); 1586 for (i = 0; i < TERRAIN_MAX; i++) { 1587 fprintf(fp,"Entry %d: Active:%d \n",i,Terrains[i].IsActive); 1588 } 1589 fprintf(fp,"\n"); 1590 1591 fprintf(fp,"------------------ Units --------------------------\n"); 1592 fprintf(fp,"ActiveCount: %d\n",Units.ActiveCount); 1593 for (i = 0; i < UNIT_MAX; i++) { 1594 fprintf(fp,"Entry %d: Active:%d \n",i,Units[i].IsActive); 1595 } 1596 fprintf(fp,"\n"); 1597 1598 fprintf(fp,"------------------ Factories --------------------------\n"); 1599 fprintf(fp,"ActiveCount: %d\n",Factories.ActiveCount); 1600 for (i = 0; i < FACTORY_MAX; i++) { 1601 fprintf(fp,"Entry %d: Active:%d \n",i,Factories[i].IsActive); 1602 } 1603 fprintf(fp,"\n"); 1604 1605 fclose(fp); 1606 1607 /* 1608 ---------------------------- Flush the cache ----------------------------- 1609 */ 1610 fp = fopen("dummy.bin","wt"); 1611 for (i = 0; i < 100; i++) { 1612 fprintf(fp,"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); 1613 } 1614 fclose(fp); 1615 } 1616 #endif