IOMAP.CPP (28358B)
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: /CounterStrike/IOMAP.CPP 1 3/03/97 10:24a 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 : IOMAP.CPP * 24 * * 25 * Programmer : Bill Randolph * 26 * * 27 * Start Date : January 16, 1995 * 28 * * 29 * Last Update : March 12, 1996 [JLB] * 30 * * 31 *---------------------------------------------------------------------------------------------* 32 * All map-related loading/saving routines should go in this module, so it can be overlayed. * 33 *---------------------------------------------------------------------------------------------* 34 * Functions: * 35 * CellClass::Code_Pointers -- codes class's pointers for load/save * 36 * CellClass::Decode_Pointers -- decodes pointers for load/save * 37 * CellClass::Load -- Reads from a save game file. * 38 * CellClass::Save -- Write to a save game file. * 39 * CellClass::Should_Save -- Should the cell be written to disk? * 40 * DisplayClass::Code_Pointers -- codes class's pointers for load/save * 41 * DisplayClass::Decode_Pointers -- decodes pointers for load/save * 42 * MapClass::Code_Pointers -- codes class's pointers for load/save * 43 * MapClass::Decode_Pointers -- decodes pointers for load/save * 44 * MouseClass::Load -- Loads from a save game file. * 45 * MouseClass::Save -- Saves to a save game file. * 46 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 47 48 #include "function.h" 49 50 51 /*********************************************************************************************** 52 * CellClass::Should_Save -- Should the cell be written to disk? * 53 * * 54 * This function will determine if the cell needs to be written to disk. Any cell that * 55 * contains special data should be written to disk. * 56 * * 57 * INPUT: none * 58 * * 59 * OUTPUT: bool; Should this cell's data be written to disk? * 60 * * 61 * WARNINGS: none * 62 * * 63 * HISTORY: * 64 * 09/19/1994 JLB : Created. * 65 *=============================================================================================*/ 66 bool CellClass::Should_Save(void) const 67 { 68 static CellClass const _identity_cell; 69 70 return(memcmp(&_identity_cell, this, sizeof(*this)) != 0); 71 } 72 73 74 /*********************************************************************************************** 75 * CellClass::Load -- Loads from a save game file. * 76 * * 77 * INPUT: file -- The file to read the cell's data from. * 78 * * 79 * OUTPUT: true = success, false = failure * 80 * * 81 * WARNINGS: none * 82 * * 83 * HISTORY: * 84 * 09/19/1994 JLB : Created. * 85 *=============================================================================================*/ 86 bool CellClass::Load(Straw & file) 87 { 88 file.Get(this, sizeof(*this)); 89 return(true); 90 } 91 92 93 /*********************************************************************************************** 94 * CellClass::Save -- Write to a save game file. * 95 * * 96 * INPUT: file -- The file to write the cell's data to. * 97 * * 98 * OUTPUT: true = success, false = failure * 99 * * 100 * WARNINGS: none * 101 * * 102 * HISTORY: * 103 * 09/19/1994 JLB : Created. * 104 *=============================================================================================*/ 105 bool CellClass::Save(Pipe & file) const 106 { 107 file.Put(this, sizeof(*this)); 108 return(true); 109 } 110 111 112 /*********************************************************************************************** 113 * CellClass::Code_Pointers -- codes class's pointers for load/save * 114 * * 115 * This routine "codes" the pointers in the class by converting them to a number * 116 * that still represents the object pointed to, but isn't actually a pointer. This * 117 * allows a saved game to properly load without relying on the games data still * 118 * being in the exact same location. * 119 * * 120 * INPUT: * 121 * none. * 122 * * 123 * OUTPUT: * 124 * none. * 125 * * 126 * WARNINGS: * 127 * none. * 128 * * 129 * HISTORY: * 130 * 01/02/1995 BR : Created. * 131 *=============================================================================================*/ 132 void CellClass::Code_Pointers(void) 133 { 134 if (Cell_Occupier() != NULL) { 135 OccupierPtr = (ObjectClass *)OccupierPtr->As_Target(); 136 } 137 138 for (int index = 0; index < ARRAY_SIZE(Overlapper); index++) { 139 if (Overlapper[index] != NULL && Overlapper[index]->IsActive) { 140 Overlapper[index] = (ObjectClass *)Overlapper[index]->As_Target(); 141 } else { 142 Overlapper[index] = NULL; 143 } 144 } 145 146 assert(CTFFlag == NULL); 147 } 148 149 150 /*********************************************************************************************** 151 * CellClass::Decode_Pointers -- decodes pointers for load/save * 152 * * 153 * This routine "decodes" the pointers coded in Code_Pointers by converting the * 154 * code values back into object pointers. * 155 * * 156 * INPUT: * 157 * none. * 158 * * 159 * OUTPUT: * 160 * none. * 161 * * 162 * WARNINGS: * 163 * none. * 164 * * 165 * HISTORY: * 166 * 01/02/1995 BR : Created. * 167 * 03/12/1996 JLB : Simplified. * 168 *=============================================================================================*/ 169 void CellClass::Decode_Pointers(void) 170 { 171 if (OccupierPtr != NULL) { 172 OccupierPtr = As_Object((TARGET)OccupierPtr, false); 173 assert(OccupierPtr != NULL); 174 } 175 176 for (int index = 0; index < ARRAY_SIZE(Overlapper); index++) { 177 if (Overlapper[index] != NULL) { 178 Overlapper[index] = As_Object((TARGET)Overlapper[index], false); 179 assert(Overlapper[index] != NULL); 180 } 181 } 182 183 CTFFlag = NULL; 184 } 185 186 187 /*********************************************************************************************** 188 * MouseClass::Load -- Loads from a save game file. * 189 * * 190 * Loading the map is very complicated. Here are the steps: * 191 * - Read the Theater for this save-game * 192 * - call Init_Theater to perform theater-specific inits * 193 * - call Free_Cells to free the cell array, because loading the map object will overwrite * 194 * the pointer to the cell array * 195 * - read the map object from disk * 196 * - call Alloc_Cells to re-allocate the cell array * 197 * - call Init_Cells to set the cells to a known state, because not every cell will be loaded * 198 * - read the cell objects into the cell array * 199 * - After the map & all objects have been loaded & the pointers decoded, Init_IO() >MUST< be * 200 * called to restore the map's button list to the proper state. * 201 * * 202 * INPUT: file -- The file to read the cell's data from. * 203 * * 204 * OUTPUT: true = success, false = failure * 205 * * 206 * WARNINGS: none * 207 * * 208 * HISTORY: * 209 * 09/19/1994 JLB : Created. * 210 * 03/12/1996 JLB : Simplified. * 211 *=============================================================================================*/ 212 bool MouseClass::Load(Straw & file) 213 { 214 /* 215 ** Load Theater: Even though this value is located in the DisplayClass, 216 ** it must be loaded first so initialization can be done before any other 217 ** map data is loaded. If initialization isn't done first, data read from 218 ** disk will be over-written when initialization occurs. This code must 219 ** go in the most-derived Map class. 220 */ 221 TheaterType theater; 222 if (file.Get(&theater, sizeof(theater)) != sizeof(theater)) { 223 return(false); 224 } 225 226 #ifdef WIN32 227 LastTheater = THEATER_NONE; 228 #endif 229 230 /* 231 ** Remove any old theater specific uncompressed shapes 232 */ 233 #ifdef WIN32 234 // if (theater != LastTheater) { 235 Reset_Theater_Shapes(); 236 // } 237 #endif //WIN32 238 239 /* 240 ** Init display mixfiles 241 */ 242 Init_Theater(theater); 243 TerrainTypeClass::Init(Scen.Theater); 244 TemplateTypeClass::Init(Scen.Theater); 245 OverlayTypeClass::Init(Scen.Theater); 246 UnitTypeClass::Init(Scen.Theater); 247 InfantryTypeClass::Init(Scen.Theater); 248 BuildingTypeClass::Init(Scen.Theater); 249 BulletTypeClass::Init(Scen.Theater); 250 AnimTypeClass::Init(Scen.Theater); 251 AircraftTypeClass::Init(Scen.Theater); 252 VesselTypeClass::Init(Scen.Theater); 253 SmudgeTypeClass::Init(Scen.Theater); 254 255 //LastTheater = Scen.Theater; 256 257 /* 258 ** Free the cell array, because we're about to overwrite its pointers 259 */ 260 Free_Cells(); 261 262 /* 263 ** Read the entire map object in. Only read in sizeof(MouseClass), so if we're 264 ** in editor mode, none of the map editor object is read in. 265 */ 266 file.Get(this, sizeof(*this)); 267 #ifdef SCENARIO_EDITOR 268 new(this) MapEditClass(NoInitClass()); 269 #else 270 new(this) MouseClass(NoInitClass()); 271 #endif 272 273 /* 274 ** Reallocate the cell array 275 */ 276 Alloc_Cells(); 277 278 /* 279 ** Init all cells to empty 280 */ 281 Init_Cells(); 282 283 /* 284 ** Read # cells saved 285 */ 286 int count; 287 if (file.Get(&count, sizeof(count)) != sizeof(count)) { 288 return(false); 289 } 290 291 /* 292 ** Read cells 293 */ 294 for (int index = 0; index < count; index++) { 295 CELL cell = 0; 296 if (file.Get(&cell, sizeof(cell)) != sizeof(cell)) { 297 return(false); 298 } 299 300 if (!(*this)[cell].Load(file)) { 301 return(false); 302 } 303 } 304 305 LastTheater = Scen.Theater; 306 return(true); 307 } 308 309 310 /*********************************************************************************************** 311 * MouseClass::Save -- Save to a save game file. * 312 * * 313 * INPUT: file -- The file to write the cell's data to. * 314 * * 315 * OUTPUT: true = success, false = failure * 316 * * 317 * WARNINGS: none * 318 * * 319 * HISTORY: * 320 * 09/19/1994 JLB : Created. * 321 * 02/26/1996 JLB : Cleaned up. * 322 *=============================================================================================*/ 323 bool MouseClass::Save(Pipe & file) const 324 { 325 /* 326 ** Save Theater >first< 327 */ 328 TheaterType theater = Scen.Theater; 329 file.Put(&theater, sizeof(theater)); 330 331 file.Put(this, sizeof(*this)); 332 333 /* 334 ** Count how many cells will be saved. 335 */ 336 int count = 0; 337 CellClass const * cellptr = &(*this)[(CELL)0]; 338 for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) { 339 if (cellptr->Should_Save()) { 340 count++; 341 } 342 cellptr++; 343 } 344 345 /* 346 ** write out count of the cells. 347 */ 348 file.Put(&count, sizeof(count)); 349 350 /* 351 ** Save cells that need it 352 */ 353 cellptr = &(*this)[(CELL)0]; 354 for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) { 355 if (cellptr->Should_Save()) { 356 file.Put(&cell, sizeof(cell)); 357 cellptr->Save(file); 358 count--; 359 } 360 cellptr++; 361 } 362 363 if (count != 0) return(false); 364 365 return(true); 366 } 367 368 369 /*********************************************************************************************** 370 * DisplayClass::Code_Pointers -- codes class's pointers for load/save * 371 * * 372 * This routine "codes" the pointers in the class by converting them to a number * 373 * that still represents the object pointed to, but isn't actually a pointer. This * 374 * allows a saved game to properly load without relying on the games data still * 375 * being in the exact same location. * 376 * * 377 * INPUT: * 378 * none. * 379 * * 380 * OUTPUT: * 381 * none. * 382 * * 383 * WARNINGS: * 384 * none. * 385 * * 386 * HISTORY: * 387 * 01/02/1995 BR : Created. * 388 *=============================================================================================*/ 389 void DisplayClass::Code_Pointers(void) 390 { 391 /* 392 ** Code PendingObjectPtr. 393 */ 394 if (PendingObjectPtr) { 395 PendingObjectPtr = (ObjectClass *)PendingObjectPtr->As_Target(); 396 } 397 398 /* 399 ** Fix for saving game while in structure placement mode. ST - 4/15/2020 2:41PM 400 */ 401 memset(CursorShapeSave, 0, sizeof(CursorShapeSave)); 402 if (CursorSize && CursorSize != CursorShapeSave) { 403 404 int save_buffer_element_size = sizeof(CursorShapeSave) / sizeof(CursorShapeSave[0]); 405 406 int index = 0; 407 408 while (index < save_buffer_element_size - 2 && CursorSize[index] != REFRESH_EOL) { 409 CursorShapeSave[index] = CursorSize[index]; 410 index++; 411 } 412 CursorShapeSave[index] = REFRESH_EOL; 413 } 414 415 /* 416 ** Chain to parent. 417 */ 418 MapClass::Code_Pointers(); 419 } 420 421 422 /*********************************************************************************************** 423 * DisplayClass::Decode_Pointers -- decodes pointers for load/save * 424 * * 425 * This routine "decodes" the pointers coded in Code_Pointers by converting the * 426 * code values back into object pointers. * 427 * * 428 * INPUT: * 429 * none. * 430 * * 431 * OUTPUT: * 432 * none. * 433 * * 434 * WARNINGS: * 435 * none. * 436 * * 437 * HISTORY: * 438 * 01/02/1995 BR : Created. * 439 *=============================================================================================*/ 440 void DisplayClass::Decode_Pointers(void) 441 { 442 /* 443 ** Decode PendingObjectPtr. We can't decode PendingObject here, because we'd 444 ** have to reference PendingObjectPtr->Class_Of(), and the object that 445 ** PendingObjectPtr is pointing to hasn't been decoded yet. Since we can't 446 ** decode PendingObjectPtr, we can't set the placement cursor shape here 447 ** either. These have to be done as last-minute fixups. 448 */ 449 if (PendingObjectPtr) { 450 PendingObjectPtr = As_Object((TARGET)PendingObjectPtr, false); 451 assert(PendingObjectPtr != NULL); 452 } 453 454 if (CursorSize) { 455 CursorSize = CursorShapeSave; 456 } 457 458 /* 459 ** Chain to parent. 460 */ 461 MapClass::Decode_Pointers(); 462 } 463 464 465 /*********************************************************************************************** 466 * MapClass::Code_Pointers -- codes class's pointers for load/save * 467 * * 468 * This routine "codes" the pointers in the class by converting them to a number * 469 * that still represents the object pointed to, but isn't actually a pointer. This * 470 * allows a saved game to properly load without relying on the games data still * 471 * being in the exact same location. * 472 * * 473 * INPUT: * 474 * none. * 475 * * 476 * OUTPUT: * 477 * none. * 478 * * 479 * WARNINGS: * 480 * none. * 481 * * 482 * HISTORY: * 483 * 01/02/1995 BR : Created. * 484 *=============================================================================================*/ 485 void MapClass::Code_Pointers(void) 486 { 487 CELL cell; 488 489 for (cell = 0; cell < MAP_CELL_TOTAL; cell++) { 490 (*this)[cell].Flag_Destroy(); 491 } 492 493 CellClass * cellptr = &(*this)[(CELL)0]; 494 for (cell = 0; cell < MAP_CELL_TOTAL; cell++) { 495 cellptr->Code_Pointers(); 496 cellptr++; 497 } 498 } 499 500 501 /*********************************************************************************************** 502 * MapClass::Decode_Pointers -- decodes pointers for load/save * 503 * * 504 * This routine "decodes" the pointers coded in Code_Pointers by converting the * 505 * code values back into object pointers. * 506 * * 507 * INPUT: * 508 * none. * 509 * * 510 * OUTPUT: * 511 * none. * 512 * * 513 * WARNINGS: * 514 * none. * 515 * * 516 * HISTORY: * 517 * 01/02/1995 BR : Created. * 518 *=============================================================================================*/ 519 void MapClass::Decode_Pointers(void) 520 { 521 CellClass * cellptr = &(*this)[(CELL)0]; 522 for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) { 523 cellptr->Decode_Pointers(); 524 cellptr++; 525 } 526 } 527