CELL.CPP (122294B)
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\cell.cpv 2.18 16 Oct 1995 16:49:20 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 : CELL.CPP * 24 * * 25 * Programmer : Joe L. Bostic * 26 * * 27 * Start Date : April 29, 1994 * 28 * * 29 * Last Update : August 17, 1995 [JLB] * 30 * * 31 *---------------------------------------------------------------------------------------------* 32 * Functions: * 33 * CellClass::Adjacent_Cell -- Determines the adjacent cell according to facing. * 34 * CellClass::Adjust_Threat -- Allows adjustment of threat at cell level * 35 * CellClass::CellClass -- Constructor for cell objects. * 36 * CellClass::Cell_Building -- Return with building at specified cell. * 37 * CellClass::Cell_Color -- Determine what radar color to use for this cell. * 38 * CellClass::Cell_Coord -- Returns the coordinate of this cell. * 39 * CellClass::Cell_Find_Object -- Returns ptr to RTTI type occupying cell * 40 * CellClass::Cell_Infantry -- Returns with pointer of first infantry unit. * 41 * CellClass::Cell_Object -- Returns with clickable object in cell. * 42 * CellClass::Cell_Techno -- Return with the unit/building at specified cell. * 43 * CellClass::Cell_Terrain -- Determines terrain object in cell. * 44 * CellClass::Cell_Unit -- Returns with pointer to unit occupying cell. * 45 * CellClass::Clear_Icon -- Calculates what the clear icon number should be. * 46 * CellClass::Closest_Free_Spot -- returns free spot closest to given coord * 47 * CellClass::Concrete_Calc -- Calculates the concrete icon to use for the cell. * 48 * CellClass::Draw_It -- Draws the cell imagery at the location specified. * 49 * CellClass::Flag_Place -- Places a house flag down on the cell. * 50 * CellClass::Flag_Remove -- Removes the house flag from the cell. * 51 * CellClass::Cell_Occupier -- Fetches the occupier for the cell. * 52 * CellClass::Get_Trigger -- retrieves reference to the cell's trigger * 53 * CellClass::Goodie_Check -- Performs crate discovery logic. * 54 * CellClass::Incoming -- Causes objects in cell to "run for cover". * 55 * CellClass::Is_Generally_Clear -- Determines if cell can be built upon. * 56 * CellClass::Occupy_Down -- Flag occupation of specified cell. * 57 * CellClass::Occupy_Unit -- Marks cell as unit occupied. * 58 * CellClass::Occupy_Up -- Removes occupation flag from the specified cell. * 59 * CellClass::Overlap_Down -- This routine is used to mark a cell as being spilled over (overla* 60 * CellClass::Overlap_Unit -- Marks cell as being overlapped by unit. * 61 * CellClass::Overlap_Up -- Removes overlap flag for the cell. * 62 * CellClass::Read -- Reads a particular cell value from a save game file. * 63 * CellClass::Recalc_Attributes -- Recalculates the ground type attributes for the cell. * 64 * CellClass::Redraw_Objects -- Redraws all objects overlapping this cell. * 65 * CellClass::Reduce_Tiberium -- Reduces the tiberium in the cell by the amount specified. * 66 * CellClass::Reduce_Wall -- Damages a wall, if damage is high enough. * 67 * CellClass::Reserve_Cell -- Marks a cell as being occupied by the specified unit ID. * 68 * CellClass::Shimmer -- Causes all objects in the cell to shimmer. * 69 * CellClass::Spot_Index -- returns cell sub-coord index for given COORD * 70 * CellClass::Tiberium_Adjust -- Adjust the look of the Tiberium for smooth. * 71 * CellClass::Validate -- validates cell's number * 72 * CellClass::Wall_Update -- Updates the imagery for wall objects in cell. * 73 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 74 75 #include "function.h" 76 77 /* 78 ** New sidebar for GlyphX multiplayer. ST - 3/26/2019 12:24PM 79 */ 80 #include "SidebarGlyphx.h" 81 82 #define FIXUP 0 83 84 85 /*********************************************************************************************** 86 * CellClass::Validate -- validates cell's number * 87 * * 88 * INPUT: * 89 * none. * 90 * * 91 * OUTPUT: * 92 * 1 = ok, 0 = error * 93 * * 94 * WARNINGS: * 95 * none. * 96 * * 97 * HISTORY: * 98 * 08/09/1995 BRR : Created. * 99 *=============================================================================================*/ 100 #ifdef CHEAT_KEYS 101 int CellClass::Validate(void) const 102 { 103 int num; 104 105 num = Cell_Number(); 106 if (num < 0 || num > 4095) { 107 Validate_Error("CELL"); 108 return (0); 109 } 110 else 111 return (1); 112 } 113 #else 114 #define Validate() 115 #endif 116 117 118 /*********************************************************************************************** 119 * CellClass::CellClass -- Constructor for cell objects. * 120 * * 121 * A cell object is constructed into an empty state. It contains no specific objects, * 122 * templates, or overlays. * 123 * * 124 * INPUT: none * 125 * * 126 * OUTPUT: none * 127 * * 128 * WARNINGS: none * 129 * * 130 * HISTORY: * 131 * 08/09/1994 JLB : Created. * 132 *=============================================================================================*/ 133 CellClass::CellClass(void) 134 { 135 memset(this, 0, sizeof(CellClass)); 136 Overlay = OVERLAY_NONE; 137 Smudge = SMUDGE_NONE; 138 TType = TEMPLATE_NONE; 139 Owner = HOUSE_NONE; 140 InfType = HOUSE_NONE; 141 OverrideLand = LAND_COUNT; 142 } 143 144 145 /*********************************************************************************************** 146 * CellClass::Cell_Color -- Determine what radar color to use for this cell. * 147 * * 148 * Use this routine to determine what radar color to render a radar * 149 * pixel with. This routine is called many many times to render the * 150 * radar map, so it must be fast. * 151 * * 152 * INPUT: none * 153 * * 154 * OUTPUT: Returns with the color to display the radar pixel with. * 155 * * 156 * WARNINGS: none * 157 * * 158 * HISTORY: * 159 * 03/01/1994 JLB : Created. * 160 * 04/30/1994 JLB : Converted to member function. * 161 * 05/31/1994 JLB : Takes into account any stealth characteristics of object. * 162 *=============================================================================================*/ 163 int CellClass::Cell_Color(bool override) const 164 { 165 Validate(); 166 BuildingClass * object = Cell_Building(); 167 if (object) { 168 return(object->House->Class->Color); 169 } 170 171 if (override) { 172 return(TBLACK); 173 } 174 return(::Ground[Land_Type()].Color); 175 } 176 177 178 /*********************************************************************************************** 179 * CellClass::Cell_Techno -- Return with the unit/building at specified cell. * 180 * * 181 * Returns an object located in the cell. If there is a * 182 * building present, it returns a pointer to that, otherwise it returns * 183 * a pointer to one of the units there. If nothing is present in the * 184 * specified cell, then it returns NULL. * 185 * * 186 * INPUT: x,y -- Coordinate offset (from upper left corner) to use as an aid in selecting * 187 * the desired object within the cell. * 188 * * 189 * OUTPUT: Returns a pointer to a building or unit located in cell. If * 190 * nothing present, just returns NULL. * 191 * * 192 * WARNINGS: none * 193 * * 194 * HISTORY: * 195 * 08/05/1992 JLB : Created. * 196 * 04/30/1994 JLB : Converted to member function. * 197 *=============================================================================================*/ 198 TechnoClass * CellClass::Cell_Techno(int x, int y) const 199 { 200 Validate(); 201 ObjectClass * object; 202 COORDINATE click; // Coordinate of click relative to cell corner. 203 TechnoClass * close = NULL; 204 long distance = 0; // Recorded closest distance. 205 206 /* 207 ** Create a coordinate value that represent the pixel location within the cell. This is 208 ** actually the lower significant bits (leptons) of a regular coordinate value. 209 */ 210 click = XY_Coord(Pixel_To_Lepton(x), Pixel_To_Lepton(y)); 211 212 if (Cell_Occupier()) { 213 object = Cell_Occupier(); 214 while (object && object->IsActive) { 215 if (object->Is_Techno()) { 216 COORDINATE coord; // Coordinate relative to cell corner. 217 long dist; 218 219 coord = object->Center_Coord() & 0x00FF00FFL; 220 dist = Distance(coord, click); 221 if (!close || dist < distance) { 222 close = (TechnoClass *)object; 223 distance = dist; 224 } 225 } 226 object = object->Next; 227 } 228 } 229 return(close); 230 } 231 232 233 /*************************************************************************** 234 * CellClass::Cell_Find_Object -- Returns ptr to RTTI type occupying cell * 235 * * 236 * INPUT: RTTIType the RTTI type we are searching for * 237 * * 238 * OUTPUT: none * 239 * * 240 * WARNINGS: none * 241 * * 242 * HISTORY: * 243 * 03/17/1995 PWG : Created. * 244 * 06/12/1995 JLB : Returns object class pointer. * 245 *=========================================================================*/ 246 ObjectClass * CellClass::Cell_Find_Object(RTTIType rtti) const 247 { 248 Validate(); 249 ObjectClass * object = Cell_Occupier(); 250 251 while (object && object->IsActive) { 252 if (object->What_Am_I() == rtti) { 253 return(object); 254 } 255 object = object->Next; 256 } 257 return(NULL); 258 } 259 260 261 /*********************************************************************************************** 262 * CellClass::Cell_Building -- Return with building at specified cell. * 263 * * 264 * Given a cell, determine if there is a building associated * 265 * and return with a pointer to this building. * 266 * * 267 * INPUT: none * 268 * * 269 * OUTPUT: Returns with a pointer to the building associated with the * 270 * cell. If there is no building associated, then NULL is * 271 * returned. * 272 * * 273 * WARNINGS: none * 274 * * 275 * HISTORY: * 276 * 08/05/1992 JLB : Created. * 277 * 04/30/1994 JLB : Converted to member function. * 278 *=============================================================================================*/ 279 BuildingClass * CellClass::Cell_Building(void) const 280 { 281 Validate(); 282 return((BuildingClass *)Cell_Find_Object(RTTI_BUILDING)); 283 } 284 285 286 /*********************************************************************************************** 287 * CellClass::Cell_Terrain -- Determines terrain object in cell. * 288 * * 289 * This routine is used to determine the terrain object (if any) that * 290 * overlaps this cell. * 291 * * 292 * INPUT: none * 293 * * 294 * OUTPUT: Returns with a pointer to the terrain object that overlaps * 295 * this cell. If there is no terrain object present, then NULL * 296 * is returned. * 297 * * 298 * WARNINGS: none * 299 * * 300 * HISTORY: * 301 * 05/18/1994 JLB : Created. * 302 *=============================================================================================*/ 303 TerrainClass * CellClass::Cell_Terrain(void) const 304 { 305 Validate(); 306 return((TerrainClass *)Cell_Find_Object(RTTI_TERRAIN)); 307 } 308 309 310 /*********************************************************************************************** 311 * CellClass::Cell_Object -- Returns with clickable object in cell. * 312 * * 313 * This routine is used to determine which object is to be selected * 314 * by a player click upon the cell. Not all objects that overlap the * 315 * cell are selectable by the player. This routine sorts out which * 316 * is which and returns with the appropriate object pointer. * 317 * * 318 * INPUT: x,y -- Coordinate (from upper left corner of cell) to use as a guide when * 319 * selecting the object within the cell. This plays a role in those cases * 320 * where several objects (such as infantry) exist within the same cell. * 321 * * 322 * OUTPUT: Returns with pointer to the object clickable within the * 323 * cell. NULL is returned if there is no clickable object * 324 * present. * 325 * * 326 * WARNINGS: none * 327 * * 328 * HISTORY: * 329 * 05/13/1994 JLB : Created. * 330 *=============================================================================================*/ 331 ObjectClass * CellClass::Cell_Object(int x, int y) const 332 { 333 Validate(); 334 ObjectClass * ptr; 335 336 /* 337 ** Hack so that aircraft landed on helipads can still be selected if directly 338 ** clicked on. 339 */ 340 ptr = (ObjectClass *)Cell_Find_Object(RTTI_AIRCRAFT); 341 if (ptr) { 342 return(ptr); 343 } 344 345 ptr = Cell_Techno(x, y); 346 if (ptr) { 347 return(ptr); 348 } 349 ptr = Cell_Terrain(); 350 if (ptr) return(ptr); 351 return(ptr); 352 } 353 354 355 /*********************************************************************************************** 356 * CellClass::Redraw_Objects -- Redraws all objects overlapping this cell. * 357 * * 358 * This is a low level routine that marks all objects that overlap this * 359 * cell to be redrawn. It is necessary to call this routine whenever * 360 * the underlying icon has to be redrawn. * 361 * * 362 * INPUT: forced -- Should this redraw be forced even if flags * 363 * indicate that it would be redundant? * 364 * * 365 * OUTPUT: none * 366 * * 367 * WARNINGS: none * 368 * * 369 * HISTORY: * 370 * 05/18/1994 JLB : Created. * 371 * 06/20/1994 JLB : Simplified to use object pointers. * 372 * 12/24/1994 JLB : Only checks if cell is in view and not flagged already. * 373 *=============================================================================================*/ 374 void CellClass::Redraw_Objects(bool forced) 375 { 376 Validate(); 377 CELL cell = Cell_Number(); 378 379 if (Map.In_View(cell) && (forced || !Map.Is_Cell_Flagged(cell))) { 380 381 /* 382 ** Flag the icon to be redrawn. 383 */ 384 Map.Flag_Cell(cell); 385 386 /* 387 ** Flag the main object in the cell to be redrawn. 388 */ 389 if (Cell_Occupier()) { 390 ObjectClass * optr = Cell_Occupier(); 391 while (optr) { 392 if (optr->IsActive) { 393 optr->Mark(MARK_CHANGE); 394 } 395 optr = optr->Next; 396 } 397 } 398 399 /* 400 ** Flag any overlapping object in this cell to be redrawn. 401 */ 402 for (int index = 0; index < sizeof(Overlapper)/sizeof(Overlapper[0]); index++) { 403 if (Overlapper[index]) { 404 if (!Overlapper[index]->IsActive) { 405 Overlapper[index] = 0; 406 } else { 407 Overlapper[index]->Mark(MARK_CHANGE); 408 } 409 } 410 } 411 } 412 } 413 414 415 /*********************************************************************************************** 416 * CellClass::Is_Generally_Clear -- Determines if cell can be built upon. * 417 * * 418 * This determines if the cell can become a proper foundation for * 419 * building placement. * 420 * * 421 * INPUT: none * 422 * * 423 * OUTPUT: bool; Can the cell be built upon? * 424 * * 425 * WARNINGS: none * 426 * * 427 * HISTORY: * 428 * 05/18/1994 JLB : Created. * 429 *=============================================================================================*/ 430 bool CellClass::Is_Generally_Clear(bool ignore_cloaked) const 431 { 432 Validate(); 433 if (ScenarioInit) return(true); 434 if (Flag.Composite || IsFlagged || Cell_Occupier()) { 435 if (!ignore_cloaked || (Cell_Occupier() && Cell_Occupier()->Is_Techno() && ((TechnoClass *)Cell_Occupier())->Cloak != CLOAKED)) { 436 return(false); 437 } 438 } 439 if (Smudge != SMUDGE_NONE && SmudgeTypeClass::As_Reference(Smudge).IsBib && Owner != HOUSE_NONE) { 440 return(false); 441 } 442 if (Overlay != OVERLAY_NONE && (Overlay == OVERLAY_FLAG_SPOT || OverlayTypeClass::As_Reference(Overlay).IsWall)) { 443 return(false); 444 } 445 446 #ifdef ADVANCED 447 /* 448 ** Building certain kinds of terrain is prohibited -- bridges in particular. 449 */ 450 switch (TType) { 451 case TEMPLATE_BRIDGE1: 452 case TEMPLATE_BRIDGE1D: 453 case TEMPLATE_BRIDGE2: 454 case TEMPLATE_BRIDGE2D: 455 case TEMPLATE_BRIDGE3: 456 case TEMPLATE_BRIDGE3D: 457 case TEMPLATE_BRIDGE4: 458 case TEMPLATE_BRIDGE4D: 459 case TEMPLATE_FORD1: 460 case TEMPLATE_FORD2: 461 return(false); 462 463 default: 464 break; 465 } 466 #endif 467 468 return(::Ground[Land_Type()].Build); 469 } 470 471 472 /*********************************************************************************************** 473 * CellClass::Recalc_Attributes -- Recalculates the ground type attributes for the cell. * 474 * * 475 * This routine recalculates the ground type in the cell. The speeds the find path * 476 * algorithm and other determinations of the cell type. * 477 * * 478 * INPUT: none * 479 * * 480 * OUTPUT: none * 481 * * 482 * WARNINGS: none * 483 * * 484 * HISTORY: * 485 * 05/29/1994 JLB : Created. * 486 * 06/20/1994 JLB : Knows about template pointer in cell object. * 487 *=============================================================================================*/ 488 void CellClass::Recalc_Attributes(void) 489 { 490 Validate(); 491 /* 492 ** Check for wall effects. 493 */ 494 if (Overlay != OVERLAY_NONE) { 495 Land = OverlayTypeClass::As_Reference(Overlay).Land; 496 if (Land != LAND_CLEAR) return; 497 } 498 499 /* 500 ** If there is a template associated with this cell, then scan 501 ** through the template exception list checking to see if this cell 502 ** is one of the exception types. If it is, then return that ground type, 503 ** otherwise return the template's default type. 504 */ 505 if (TType != TEMPLATE_NONE) { 506 TemplateTypeClass const *ttype = &TemplateTypeClass::As_Reference(TType); 507 508 /* 509 ** If there is an exception type list for the icons of this template, then 510 ** find out if the current icon is one of them. If so, apply the exception 511 ** ground type to the cell. 512 */ 513 char const *ptr = ttype->AltIcons; 514 if (ptr) { 515 int icon = TIcon; 516 517 while (*ptr != -1) { 518 if (icon == *ptr++) { 519 Land = ttype->AltLand; 520 return; 521 } 522 } 523 } 524 525 /* 526 ** No exception found, so just return the default ground type for this template. 527 */ 528 Land = ttype->Land; 529 return; 530 } 531 532 /* 533 ** No template is the same as clear terrain. 534 */ 535 Land = TemplateTypeClass::As_Reference(TEMPLATE_CLEAR1).Land; 536 } 537 538 539 /*********************************************************************************************** 540 * CellClass::Occupy_Down -- Flag occupation of specified cell. * 541 * * 542 * This routine is used to mark the cell as being occupied by the specified object. * 543 * * 544 * INPUT: object -- The object that is to occupy the cell * 545 * * 546 * OUTPUT: none * 547 * * 548 * WARNINGS: none * 549 * * 550 * HISTORY: * 551 * 07/18/1994 JLB : Created. * 552 * 11/29/1994 JLB : Simplified. * 553 *=============================================================================================*/ 554 void CellClass::Occupy_Down(ObjectClass * object) 555 { 556 Validate(); 557 ObjectClass * optr; 558 559 /* 560 ** If the specified object is already part of the occupation list, then don't add 561 ** it again -- bail instead. 562 */ 563 if (Cell_Occupier()) { 564 optr = Cell_Occupier(); 565 while (optr) { 566 if (optr == object) { 567 return; 568 } 569 if (!optr->Next) break; 570 optr = optr->Next; 571 } 572 } 573 optr = Cell_Occupier(); 574 object->Next = optr; 575 576 OccupierPtr = object; 577 Map.Radar_Pixel(Cell_Number()); 578 579 /* 580 ** If being placed down on a visible square, then flag this 581 ** techno object as being revealed to the player. 582 */ 583 // Changes for GlyphX multiplayer. ST - 4/17/2019 3:02PM 584 //if (IsVisible || GameToPlay != GAME_NORMAL) { 585 // object->Revealed(PlayerPtr); 586 //} 587 if (GameToPlay != GAME_GLYPHX_MULTIPLAYER) { 588 if (IsVisible || GameToPlay != GAME_NORMAL) { 589 object->Revealed(PlayerPtr); 590 } 591 } else { 592 593 for (int i = 0; i < MPlayerCount; i++) { 594 HousesType house_type = MPlayerHouses[i]; 595 if (Is_Visible(house_type)) { 596 HouseClass *house = HouseClass::As_Pointer(house_type); 597 object->Revealed(house); 598 } 599 } 600 } 601 602 /* 603 ** Special occupy bit set. 604 */ 605 switch (object->What_Am_I()) { 606 case RTTI_BUILDING: 607 Flag.Occupy.Building = true; 608 break; 609 610 case RTTI_AIRCRAFT: 611 case RTTI_UNIT: 612 Flag.Occupy.Vehicle = true; 613 break; 614 615 case RTTI_TERRAIN: 616 Flag.Occupy.Monolith = true; 617 break; 618 619 default: 620 break; 621 } 622 } 623 624 625 /*********************************************************************************************** 626 * CellClass::Occupy_Up -- Removes occupation flag from the specified cell. * 627 * * 628 * This routine will lift the object from the cell and free the cell to be occupied by * 629 * another object. Only if the cell was previously marked with the object specified, will * 630 * the object be lifted off. This routine is the counterpart to Occupy_Down(). * 631 * * 632 * INPUT: object -- The object that is being lifted off. * 633 * * 634 * OUTPUT: none * 635 * * 636 * WARNINGS: none * 637 * * 638 * HISTORY: * 639 * 07/18/1994 JLB : Created. * 640 * 11/29/1994 JLB : Fixed to handle next pointer in previous object. * 641 *=============================================================================================*/ 642 void CellClass::Occupy_Up(ObjectClass * object) 643 { 644 Validate(); 645 ObjectClass * optr = NULL; // Working pointer to the objects in the chain. 646 647 if (Cell_Occupier()) { 648 optr = Cell_Occupier(); 649 } 650 if (optr == object) { 651 OccupierPtr = object->Next; 652 object->Next = 0; 653 } else { 654 while (optr) { 655 if (optr->Next == object) { 656 optr->Next = object->Next; 657 object->Next = 0; 658 break; 659 } 660 if (!optr->Next) break; 661 optr = optr->Next; 662 } 663 } 664 Map.Radar_Pixel(Cell_Number()); 665 666 /* 667 ** Special occupy bit clear. 668 */ 669 switch (object->What_Am_I()) { 670 case RTTI_BUILDING: 671 Flag.Occupy.Building = false; 672 break; 673 674 case RTTI_AIRCRAFT: 675 case RTTI_UNIT: 676 Flag.Occupy.Vehicle = false; 677 #ifdef NEVER 678 int x,y; 679 if (Map.Coord_To_Pixel(Cell_Coord(), x, y)) { 680 SeenBuff.Put_Pixel(x, y, BLUE); 681 } 682 #endif 683 break; 684 685 case RTTI_TERRAIN: 686 Flag.Occupy.Monolith = false; 687 break; 688 689 default: 690 break; 691 } 692 } 693 694 695 /*********************************************************************************************** 696 * CellClass::Overlap_Down -- This routine is used to mark a cell as being spilled over (overla* 697 * * 698 * Most game objects can often have their graphic imagery spill into more than one cell * 699 * even though they are considered to "occupy" only one cell. All cells overlapped are * 700 * flagged by this routine. Using this information it is possible to keep the tactical map * 701 * display correct. * 702 * * 703 * INPUT: object -- The object to mark as overlapping this cell. * 704 * * 705 * OUTPUT: none * 706 * * 707 * WARNINGS: none * 708 * * 709 * HISTORY: * 710 * 07/18/1994 JLB : Created. * 711 * 07/04/1995 JLB : Ensures that buildings are always marked down. * 712 *=============================================================================================*/ 713 void CellClass::Overlap_Down(ObjectClass * object) 714 { 715 Validate(); 716 ObjectClass **ptr = 0; 717 718 if (!object) return; 719 int index; 720 for (index = 0; index < sizeof(Overlapper)/sizeof(Overlapper[0]); index++) { 721 if (Overlapper[index] == object) return; 722 if (!Overlapper[index]) ptr = &Overlapper[index]; 723 } 724 725 /* 726 ** Buildings must ALWAYS succeed in marking the cell as overlapped. Bump somebody 727 ** else out in this case. 728 */ 729 if (!ptr && object->What_Am_I() == RTTI_BUILDING) { 730 for (index = 0; index < sizeof(Overlapper)/sizeof(Overlapper[0]); index++) { 731 switch (Overlapper[index]->What_Am_I()) { 732 case RTTI_BUILDING: 733 case RTTI_TERRAIN: 734 break; 735 736 default: 737 Overlapper[index] = object; 738 index = sizeof(Overlapper)/sizeof(Overlapper[0]); 739 break; 740 } 741 } 742 } 743 if (ptr) *ptr = object; 744 745 /* 746 ** If being placed down on a visible square, then flag this 747 ** techno object as being revealed to the player. 748 */ 749 // Changes for GlyphX multiplayer. ST - 4/18/2019 9:50AM 750 //if (IsVisible) { 751 // object->Revealed(PlayerPtr); 752 //} 753 if (GameToPlay != GAME_GLYPHX_MULTIPLAYER) { 754 if (IsVisible) { 755 object->Revealed(PlayerPtr); 756 } 757 } else { 758 759 if (object->Is_Techno()) { 760 TechnoClass *tech = static_cast<TechnoClass*>(object); 761 object->Revealed(tech->House); 762 } else { 763 764 for (int i = 0; i < MPlayerCount; i++) { 765 HousesType house_type = MPlayerHouses[i]; 766 HouseClass *house = HouseClass::As_Pointer(house_type); 767 object->Revealed(house); 768 } 769 } 770 } 771 } 772 773 774 /*********************************************************************************************** 775 * CellClass::Overlap_Up -- Removes overlap flag for the cell. * 776 * * 777 * This is the counterpart to Overlap_Down and is used to remove the overlap flag for the * 778 * specified unit on the cell. * 779 * * 780 * INPUT: object -- The object to remove the overlap flag for. * 781 * * 782 * OUTPUT: none * 783 * * 784 * WARNINGS: none * 785 * * 786 * HISTORY: * 787 * 07/18/1994 JLB : Created. * 788 *=============================================================================================*/ 789 void CellClass::Overlap_Up(ObjectClass *object) 790 { 791 Validate(); 792 for (int index = 0; index < sizeof(Overlapper)/sizeof(Overlapper[0]); index++) { 793 if (Overlapper[index] == object) { 794 Overlapper[index] = 0; 795 break; 796 } 797 } 798 799 //Map.Validate(); 800 } 801 802 803 /*********************************************************************************************** 804 * CellClass::Cell_Unit -- Returns with pointer to unit occupying cell. * 805 * * 806 * This routine will determine if a unit is occupying the cell and if so, return a pointer * 807 * to it. If there is no unit occupying the cell, then NULL is returned. * 808 * * 809 * INPUT: none * 810 * * 811 * OUTPUT: Returns with pointer to unit occupying cell, else NULL. * 812 * * 813 * WARNINGS: none * 814 * * 815 * HISTORY: * 816 * 07/18/1994 JLB : Created. * 817 *=============================================================================================*/ 818 UnitClass * CellClass::Cell_Unit(void) const 819 { 820 Validate(); 821 return((UnitClass*)Cell_Find_Object(RTTI_UNIT)); 822 } 823 824 825 /*********************************************************************************************** 826 * CellClass::Cell_Infantry -- Returns with pointer of first infantry unit occupying the cell. * 827 * * 828 * This routine examines the cell and returns a pointer to the first infantry unit * 829 * that occupies it. If there is no infantry unit in the cell, then NULL is returned. * 830 * * 831 * INPUT: none * 832 * * 833 * OUTPUT: Returns with pointer to infantry unit occupying the cell or NULL if none are * 834 * present. * 835 * * 836 * WARNINGS: none * 837 * * 838 * HISTORY: * 839 * 12/21/1994 JLB : Created. * 840 *=============================================================================================*/ 841 InfantryClass * CellClass::Cell_Infantry(void) const 842 { 843 Validate(); 844 return((InfantryClass*)Cell_Find_Object(RTTI_INFANTRY)); 845 } 846 847 848 849 /*********************************************************************************************** 850 * CellClass::Get_Template_Info -- Get some info about a template for external use * 851 * * 852 * * 853 * * 854 * * 855 * INPUT: Ref to info required * 856 * * 857 * OUTPUT: True if image info available * 858 * * 859 * * 860 * WARNINGS: none * 861 * * 862 * HISTORY: * 863 * 1/10/2019 5:57PM ST : Created. * 864 *=============================================================================================*/ 865 bool CellClass::Get_Template_Info(char *template_name, int &icon, void *&image_data) 866 { 867 TemplateTypeClass const *ttype = NULL; 868 869 if (TType != TEMPLATE_NONE) { 870 ttype = &TemplateTypeClass::As_Reference(TType); 871 icon = TIcon; 872 } else { 873 ttype = &TemplateTypeClass::As_Reference(TEMPLATE_CLEAR1); 874 icon = Clear_Icon(); 875 } 876 877 if (ttype) { 878 879 strcpy(template_name, ttype->IniName); 880 image_data = (void*) ttype->ImageData; 881 882 return true; 883 } 884 885 return false; 886 } 887 888 889 890 891 /*********************************************************************************************** 892 * CellClass::Draw_It -- Draws the cell imagery at the location specified. * 893 * * 894 * This is the gruntwork cell rendering code. It draws the cell at the screen location * 895 * specified. This routine doesn't draw any overlapping or occupying units. It only * 896 * deals with the ground (cell) layer -- icon level. * 897 * * 898 * INPUT: x,y -- The screen coordinates to render the cell imagery at. * 899 * * 900 * OUTPUT: none * 901 * * 902 * WARNINGS: none * 903 * * 904 * HISTORY: * 905 * 07/18/1994 JLB : Created. * 906 * 08/21/1994 JLB : Revised for simple template objects. * 907 * 11/01/1994 BRR : Updated placement cursor; draws actual object * 908 * 11/14/1994 BRR : Added remapping code to show passable areas * 909 * 12/02/1994 BRR : Added trigger display * 910 * 12/11/1994 JLB : Mixes up clear terrain through pseudo-random table. * 911 * 04/25/1995 JLB : Smudges drawn BELOW overlays. * 912 *=============================================================================================*/ 913 void CellClass::Draw_It(int x, int y, int draw_type) const 914 { 915 Validate(); 916 TemplateTypeClass const *ttype = 0; 917 int icon; // The icon number to use from the template set. 918 CELL cell = Cell_Number(); 919 void * remap = NULL; 920 #ifdef SCENARIO_EDITOR 921 TemplateTypeClass * tptr; 922 TriggerClass * trig; 923 int i; 924 char waypt[2]; 925 #endif 926 927 /* 928 ** Fetch a pointer to the template type associated with this cell. 929 */ 930 if (TType != TEMPLATE_NONE) { 931 ttype = &TemplateTypeClass::As_Reference(TType); 932 icon = TIcon; 933 } else { 934 ttype = &TemplateTypeClass::As_Reference(TEMPLATE_CLEAR1); 935 icon = Clear_Icon(); 936 } 937 938 939 /* 940 ** Draw the stamp of the template. 941 */ 942 if (Debug_Icon) { 943 LogicPage->Fill_Rect(Map.TacPixelX+x, Map.TacPixelY+y, Map.TacPixelX+x+ICON_PIXEL_W-1, Map.TacPixelY+y+ICON_PIXEL_H-1, Sim_Random_Pick(1, 254)); 944 FontXSpacing -= 2; 945 Fancy_Text_Print("%d\r%2X%c\r%02X.%02X", Map.TacPixelX+x+(ICON_PIXEL_W>>1), Map.TacPixelY+y, WHITE, TBLACK, TPF_6POINT|TPF_NOSHADOW|TPF_CENTER, cell, Flag.Composite, (Cell_Occupier() ? '*' : ' '), Overlay, OverlayData); 946 FontXSpacing += 2; 947 } else { 948 949 950 if (!draw_type || draw_type == CELL_BLIT_ONLY){ 951 952 953 #ifdef SCENARIO_EDITOR 954 /* 955 ** Set up the remap table for this icon. 956 */ 957 if (Debug_Map && Debug_Passable) { 958 if (::Ground[Land].Cost[0] == 0 || (Cell_Occupier() != NULL && 959 Cell_Occupier()->What_Am_I() != RTTI_INFANTRY)) { // impassable 960 remap = Map.FadingRed; 961 } else { 962 if (::Ground[Land].Cost[0] > 0x70) { // pretty passable 963 remap = Map.FadingGreen; 964 } else { 965 remap = Map.FadingYellow; // moderately passable 966 } 967 } 968 } 969 #endif 970 971 // ****** maybe this icon shouldn't be drawn if it is known that the cell will be covered 972 // with shadow. 973 /* 974 ** This is the underlying terrain icon. 975 */ 976 if (ttype->Get_Image_Data()) { 977 LogicPage->Draw_Stamp(ttype->Get_Image_Data(), icon, x, y, NULL, WINDOW_TACTICAL); 978 if (remap) { 979 LogicPage->Remap(x+Map.TacPixelX, y+Map.TacPixelY, ICON_PIXEL_W, ICON_PIXEL_H, remap); 980 } 981 } 982 983 984 #ifdef SCENARIO_EDITOR 985 /* 986 ** Draw the map editor's "current" cell. This is the cell that can be 987 ** assigned attributes such as tag labels. 988 ** This must be draw before the placement cursor, but after drawing the 989 ** objects in the cell. 990 */ 991 if (Debug_Map && CurrentCell == Cell_Number()) { 992 LogicPage->Draw_Rect(x+Map.TacPixelX, y+Map.TacPixelY, Map.TacPixelX + x + CELL_PIXEL_W - 1, Map.TacPixelY + y + CELL_PIXEL_H - 1, YELLOW); 993 } 994 #endif 995 996 #ifdef NEVER 997 /* 998 ** Special concrete render. It always renders over the underlying 999 ** terrain unless this concrete piece will cover the entire terrain 1000 ** piece. 1001 */ 1002 if (Concrete) { 1003 LogicPage->Draw_Stamp(TemplateTypeClass::As_Pointer(TEMPLATE_CONCRETE_GDI)->Get_Image_Data(), Concrete-1, x, y, NULL, WINDOW_TACTICAL); 1004 } 1005 #endif 1006 } 1007 1008 /* 1009 ** Redraw any smudge. 1010 */ 1011 if (Smudge != SMUDGE_NONE) { 1012 #ifdef NEVER 1013 switch (Smudge) { 1014 case SMUDGE_BIB1: 1015 CC_Draw_Shape(Bib1, SmudgeData, x, y, WINDOW_TACTICAL, SHAPE_WIN_REL); 1016 break; 1017 1018 case SMUDGE_BIB2: 1019 CC_Draw_Shape(Bib2, SmudgeData, x, y, WINDOW_TACTICAL, SHAPE_WIN_REL); 1020 break; 1021 1022 case SMUDGE_BIB3: 1023 CC_Draw_Shape(Bib3, SmudgeData, x, y, WINDOW_TACTICAL, SHAPE_WIN_REL); 1024 break; 1025 } 1026 #endif 1027 SmudgeTypeClass::As_Reference(Smudge).Draw_It(x, y, SmudgeData); 1028 } 1029 1030 1031 if (!draw_type || draw_type == CELL_DRAW_ONLY){ 1032 1033 /* 1034 ** Draw the overlay object. 1035 */ 1036 if (Overlay != OVERLAY_NONE) { 1037 OverlayTypeClass const & otype = OverlayTypeClass::As_Reference(Overlay); 1038 IsTheaterShape = (bool)otype.IsTheater; 1039 CC_Draw_Shape(otype.Get_Image_Data(), OverlayData, (x+(CELL_PIXEL_W>>1)), (y+(CELL_PIXEL_H>>1)), WINDOW_TACTICAL, SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_GHOST, NULL, Map.UnitShadow); 1040 IsTheaterShape = false; 1041 } 1042 1043 #ifdef SCENARIO_EDITOR 1044 if (Debug_Map) { 1045 /* 1046 ** Draw the cell's Trigger mnemonic, if it has a trigger 1047 */ 1048 if (IsTrigger) { 1049 trig = Get_Trigger(); 1050 Fancy_Text_Print(trig->Get_Name(), x+Map.TacPixelX, y+Map.TacPixelY, PINK, TBLACK, TPF_NOSHADOW|TPF_6POINT); 1051 } 1052 1053 /* 1054 ** Draw the cell's Waypoint designation if there is one. 1055 */ 1056 if (IsWaypoint) { 1057 for (i = 0; i < 26; i++) { 1058 if (Waypoint[i]==Cell_Number()) { 1059 waypt[0] = 'A' + i; 1060 waypt[1] = 0; 1061 Fancy_Text_Print(waypt, Map.TacPixelX + x + CELL_PIXEL_W / 2, 1062 Map.TacPixelY + y + (CELL_PIXEL_H / 2) - 3, YELLOW, TBLACK, 1063 TPF_NOSHADOW | TPF_6POINT | TPF_CENTER); 1064 break; 1065 } 1066 } 1067 if (Waypoint[WAYPT_HOME] == Cell_Number()) { 1068 Fancy_Text_Print("Home", Map.TacPixelX + x, Map.TacPixelY + y + (CELL_PIXEL_H) - 7, 1069 WHITE, TBLACK, TPF_NOSHADOW | TPF_6POINT); 1070 } 1071 if (Waypoint[WAYPT_REINF] == Cell_Number()) { 1072 Fancy_Text_Print("Reinf", Map.TacPixelX + x, Map.TacPixelY + y + (CELL_PIXEL_H) - 7, 1073 WHITE, TBLACK, TPF_NOSHADOW | TPF_6POINT); 1074 } 1075 } 1076 } 1077 #endif 1078 1079 /* 1080 ** Draw the placement cursor: 1081 ** - First, draw the hash-mark cursor, so it will appear underneath 1082 ** any cursor being drawn 1083 ** - If the PendingObject is a template, overlay, or smudge, draw it 1084 ** - Otherwise, it's up to the Display.Refresh_Map() routine to draw it 1085 */ 1086 if (IsCursorHere) { 1087 1088 /* 1089 ** Draw the hash-mark cursor: 1090 */ 1091 if (Map.ProximityCheck && Is_Generally_Clear()) { 1092 LogicPage->Draw_Stamp(Map.TransIconset, 0, x, y, NULL, WINDOW_TACTICAL); 1093 } else { 1094 LogicPage->Draw_Stamp(Map.TransIconset, 2, x, y, NULL, WINDOW_TACTICAL); 1095 } 1096 1097 #ifdef SCENARIO_EDITOR 1098 if (Debug_Map && Map.PendingObject) { 1099 1100 switch (Map.PendingObject->What_Am_I()) { 1101 1102 /* 1103 ** Draw a template: 1104 ** - Compute the icon offset of this cell for this template, using 1105 ** ZoneCell+ZoneOffset to get the upper-left corner of the placement 1106 ** cursor 1107 ** - Draw the icon 1108 */ 1109 case RTTI_TEMPLATETYPE: 1110 tptr = (TemplateTypeClass *)Map.PendingObject; 1111 if (tptr->Get_Image_Data()) { 1112 icon = (Cell_X(cell) - Cell_X(Map.ZoneCell + Map.ZoneOffset)) + 1113 (Cell_Y(cell) - Cell_Y(Map.ZoneCell + Map.ZoneOffset)) * 1114 tptr->Width; 1115 LogicPage->Draw_Stamp(tptr->Get_Image_Data(), icon, x, y, NULL, WINDOW_TACTICAL); 1116 } 1117 break; 1118 1119 /* 1120 ** Draw an overlay; just use the existing 'OverlayData' even though 1121 ** it means nothing. 1122 */ 1123 case RTTI_OVERLAYTYPE: 1124 OverlayTypeClass::As_Reference(((OverlayTypeClass *)Map.PendingObject)->Type).Draw_It(x, y, OverlayData); 1125 break; 1126 1127 /* 1128 ** Draw a smudge 1129 */ 1130 case RTTI_SMUDGETYPE: 1131 SmudgeTypeClass::As_Reference(((SmudgeTypeClass *)Map.PendingObject)->Type).Draw_It(x, y, 0); 1132 break; 1133 } 1134 } 1135 #endif 1136 } 1137 } 1138 } 1139 } 1140 1141 1142 /*********************************************************************************************** 1143 * CellClass::Concrete_Calc -- Calculates the concrete icon to use for the cell. * 1144 * * 1145 * This routine examines the cells around the current one and from this, determines what * 1146 * concrete icon shape to use (if any). The cell data is adjusted and the cell is marked * 1147 * for redraw if the icon changed. * 1148 * * 1149 * INPUT: none * 1150 * * 1151 * OUTPUT: none * 1152 * * 1153 * WARNINGS: none * 1154 * * 1155 * HISTORY: * 1156 * 08/01/1994 JLB : Created. * 1157 *=============================================================================================*/ 1158 void CellClass::Concrete_Calc(void) 1159 { 1160 Validate(); 1161 static FacingType _even[5] = {FACING_N, FACING_S, FACING_SW, FACING_W, FACING_NW}; 1162 static FacingType _odd[5] = {FACING_N, FACING_NE, FACING_E, FACING_SE, FACING_S}; 1163 FacingType *ptr; // Working pointer into adjacent cell list. 1164 int index; // Constructed bit index. 1165 int icon; // Icon number. 1166 bool isodd; // Is this for the odd column? 1167 1168 #define OF_N 0x01 1169 #define OF_NE 0x02 1170 #define OF_E 0x04 1171 #define OF_SE 0x08 1172 #define OF_S 0x10 1173 1174 #define EF_N 0x01 1175 #define EF_NW 0x10 1176 #define EF_W 0x08 1177 #define EF_SW 0x04 1178 #define EF_S 0x02 1179 1180 /* 1181 ** Determine if the even or odd row logic is necessary. 1182 */ 1183 isodd = ((Cell_Number() & 0x01) != 0); 1184 1185 /* 1186 ** Fetch correct pointer depending on whether this is for an 1187 ** odd or even row. 1188 */ 1189 ptr = (isodd) ? _odd : _even; 1190 1191 /* 1192 ** Build an index according to the presence of concrete in the special 1193 ** adjacent cells. This is a short list of adjacent cell flags since 1194 ** only 5 adjacent cells need to be examined. The choice of which 5 1195 ** depends on whether this is for an even or odd column. 1196 */ 1197 index = 0; 1198 for (int i = 0; i < (sizeof(_even)/sizeof(_even[0])); i++) { 1199 CellClass * cellptr = Adjacent_Cell(*ptr++); 1200 1201 // if ((cellptr->IsConcrete) || 1202 // cellptr->Concrete == C_UPDOWN_RIGHT || 1203 // cellptr->Concrete == C_UPDOWN_LEFT) { 1204 1205 if (cellptr && cellptr->Overlay == OVERLAY_CONCRETE) { 1206 index |= (1<<i); 1207 } 1208 } 1209 1210 /* 1211 ** Special logic occurs for cells that are concrete filled. 1212 */ 1213 if (Overlay == OVERLAY_CONCRETE) { 1214 1215 /* 1216 ** Process the index value and place the appropriate concrete icon 1217 ** in the cell. 1218 */ 1219 if (isodd) { 1220 switch (index) { 1221 case OF_NE: 1222 case OF_N|OF_NE: 1223 case OF_E|OF_N: 1224 case OF_E|OF_NE: 1225 case OF_N|OF_NE|OF_E: 1226 case OF_S|OF_N|OF_NE: 1227 icon = C_RIGHT_UP; // right - up 1228 break; 1229 1230 case OF_SE: 1231 case OF_E|OF_SE: 1232 case OF_S|OF_SE: 1233 case OF_S|OF_E: 1234 case OF_S|OF_SE|OF_E: 1235 case OF_S|OF_SE|OF_N: 1236 icon = C_RIGHT_DOWN; // right - down 1237 break; 1238 1239 case OF_SE|OF_NE: 1240 case OF_SE|OF_NE|OF_N: 1241 case OF_SE|OF_NE|OF_S: 1242 case OF_SE|OF_NE|OF_S|OF_N: 1243 case OF_SE|OF_E|OF_N: 1244 case OF_SE|OF_E|OF_NE|OF_N: 1245 case OF_S|OF_E|OF_N: 1246 case OF_S|OF_E|OF_NE: 1247 case OF_S|OF_E|OF_NE|OF_N: 1248 case OF_S|OF_SE|OF_E|OF_N: 1249 case OF_S|OF_SE|OF_E|OF_NE|OF_N: 1250 case OF_S|OF_SE|OF_E|OF_NE: 1251 icon = C_RIGHT_UPDOWN; // right - up - down 1252 break; 1253 1254 default: 1255 icon = C_RIGHT; // right 1256 break; 1257 } 1258 } else { 1259 switch (index) { 1260 case EF_NW: 1261 case EF_NW|EF_N: 1262 case EF_W|EF_N: 1263 case EF_NW|EF_W|EF_N: 1264 case EF_NW|EF_W: 1265 case EF_NW|EF_S|EF_N: 1266 icon = C_LEFT_UP; // left - up 1267 break; 1268 1269 case EF_SW: 1270 case EF_SW|EF_S: 1271 case EF_W|EF_S: 1272 case EF_W|EF_SW|EF_S: 1273 case EF_W|EF_SW: 1274 case EF_SW|EF_S|EF_N: 1275 icon = C_LEFT_DOWN; // left - down 1276 break; 1277 1278 case EF_NW|EF_SW: 1279 case EF_NW|EF_SW|EF_N: 1280 case EF_NW|EF_SW|EF_S: 1281 case EF_NW|EF_SW|EF_S|EF_N: 1282 case EF_W|EF_S|EF_N: 1283 case EF_W|EF_SW|EF_N: 1284 case EF_W|EF_SW|EF_S|EF_N: 1285 case EF_NW|EF_W|EF_S: 1286 case EF_NW|EF_W|EF_S|EF_N: 1287 case EF_NW|EF_W|EF_SW|EF_S|EF_N: 1288 case EF_NW|EF_W|EF_SW|EF_N: 1289 case EF_NW|EF_W|EF_SW|EF_S: 1290 icon = C_LEFT_UPDOWN; // left - up - down 1291 break; 1292 1293 default: 1294 icon = C_LEFT; // left 1295 break; 1296 } 1297 } 1298 1299 } else { 1300 1301 // Presume that no concrete piece is needed. 1302 icon = C_NONE; 1303 if (isodd) { 1304 index &= ~(OF_NE|OF_SE); // Ignore diagonals. 1305 switch (index) { 1306 case OF_N|OF_E: 1307 icon = C_UP_RIGHT; // up right 1308 break; 1309 1310 case OF_E|OF_S: 1311 icon = C_DOWN_RIGHT; // down right 1312 break; 1313 1314 case OF_N|OF_E|OF_S: 1315 icon = C_UPDOWN_RIGHT; // up/down right 1316 break; 1317 1318 default: 1319 break; 1320 } 1321 } else { 1322 index &= ~(EF_NW|EF_SW); // Ignore diagonals. 1323 switch (index) { 1324 case EF_N|EF_W: 1325 icon = C_UP_LEFT; // up left 1326 break; 1327 1328 case EF_W|EF_S: 1329 icon = C_DOWN_LEFT; // down left 1330 break; 1331 1332 case EF_N|EF_W|EF_S: 1333 icon = C_UPDOWN_LEFT; // up/down left 1334 break; 1335 1336 default: 1337 break; 1338 } 1339 } 1340 1341 /* 1342 ** If any kind of fixup piece is needed, then add concrete 1343 ** to this location RECURSIVELY! 1344 */ 1345 if (icon != C_NONE) { 1346 OverlayTypeClass::As_Reference(OVERLAY_CONCRETE).Create_And_Place(Cell_Number()); 1347 icon = C_NONE; 1348 } 1349 1350 } 1351 1352 /* 1353 ** Update the icon on the map. 1354 */ 1355 if (icon != C_NONE && OverlayData != icon) { 1356 OverlayData = icon; 1357 //Array[cell].Base = 0; 1358 Redraw_Objects(); 1359 } 1360 } 1361 1362 1363 /*********************************************************************************************** 1364 * CellClass::Wall_Update -- Updates the imagery for wall objects in cell. * 1365 * * 1366 * This routine will examine the cell and the adjacent cells to determine what the wall * 1367 * should look like with the cell. It will then update the wall's imagery value and flag * 1368 * the cell to be redrawn if necessary. This routine should be called whenever the wall * 1369 * or an adjacent wall is created or destroyed. * 1370 * * 1371 * INPUT: none * 1372 * * 1373 * OUTPUT: none * 1374 * * 1375 * WARNINGS: none * 1376 * * 1377 * HISTORY: * 1378 * 09/19/1994 JLB : Created. * 1379 * 09/19/1994 BWG : Updated to handle partially-damaged walls. * 1380 *=============================================================================================*/ 1381 void CellClass::Wall_Update(void) 1382 { 1383 Validate(); 1384 static FacingType _offsets[5] = {FACING_N, FACING_E, FACING_S, FACING_W, FACING_NONE}; 1385 1386 if (Overlay == OVERLAY_NONE) { 1387 return; 1388 } 1389 1390 OverlayTypeClass const & wall = OverlayTypeClass::As_Reference(Overlay); 1391 if (!wall.IsWall) { 1392 return; 1393 } 1394 1395 for (unsigned index = 0; index < (sizeof(_offsets)/sizeof(_offsets[0])); index++) { 1396 CellClass * newcell = Adjacent_Cell(_offsets[index]); 1397 1398 if (newcell && newcell->Overlay != OVERLAY_NONE && OverlayTypeClass::As_Reference(newcell->Overlay).IsWall) { 1399 int icon = 0; 1400 1401 /* 1402 ** Build the icon number according to walls located in the adjacent 1403 ** cells. 1404 */ 1405 for (unsigned i = 0; i < 4; i++) { 1406 CellClass * adjcell = newcell->Adjacent_Cell(_offsets[i]); 1407 if (adjcell && adjcell->Overlay == newcell->Overlay) { 1408 icon |= 1 << i; 1409 } 1410 } 1411 newcell->OverlayData = (newcell->OverlayData & 0xFFF0) | icon; 1412 // newcell->OverlayData = icon; 1413 1414 /* 1415 ** Handle special cases for the incomplete damaged wall sets. If a damage stage 1416 ** is calculated, but there is no artwork for it, then consider the wall to be 1417 ** completely destroyed. 1418 */ 1419 if (newcell->Overlay == OVERLAY_BRICK_WALL && newcell->OverlayData == 48) { 1420 newcell->Overlay = OVERLAY_NONE; 1421 newcell->OverlayData = 0; 1422 ObjectClass::Detach_This_From_All(::As_Target(newcell->Cell_Number()), true); 1423 } 1424 if (newcell->Overlay == OVERLAY_SANDBAG_WALL && newcell->OverlayData == 16) { 1425 newcell->Overlay = OVERLAY_NONE; 1426 newcell->OverlayData = 0; 1427 ObjectClass::Detach_This_From_All(::As_Target(newcell->Cell_Number()), true); 1428 } 1429 if (newcell->Overlay == OVERLAY_CYCLONE_WALL && newcell->OverlayData == 32) { 1430 newcell->Overlay = OVERLAY_NONE; 1431 newcell->OverlayData = 0; 1432 ObjectClass::Detach_This_From_All(::As_Target(newcell->Cell_Number()), true); 1433 } 1434 if (newcell->Overlay == OVERLAY_BARBWIRE_WALL && newcell->OverlayData == 16) { 1435 newcell->Overlay = OVERLAY_NONE; 1436 newcell->OverlayData = 0; 1437 ObjectClass::Detach_This_From_All(::As_Target(newcell->Cell_Number()), true); 1438 } 1439 1440 newcell->Recalc_Attributes(); 1441 newcell->Redraw_Objects(); 1442 } 1443 } 1444 } 1445 1446 1447 /*********************************************************************************************** 1448 * CellClass::Cell_Coord -- Returns the coordinate of this cell. * 1449 * * 1450 * This support function will determine the coordinate of this cell and return it. * 1451 * * 1452 * INPUT: none * 1453 * * 1454 * OUTPUT: Returns with coordinate value of cell. * 1455 * * 1456 * WARNINGS: none * 1457 * * 1458 * HISTORY: * 1459 * 09/19/1994 JLB : Created. * 1460 *=============================================================================================*/ 1461 COORDINATE CellClass::Cell_Coord(void) const 1462 { 1463 Validate(); 1464 return(::Cell_Coord(Cell_Number())); 1465 } 1466 1467 1468 /*********************************************************************************************** 1469 * CellClass::Reduce_Tiberium -- Reduces the tiberium in the cell by the amount specified. * 1470 * * 1471 * This routine will lower the tiberium level in the cell. It is used by the harvesting * 1472 * process as well as by combat damage to the tiberium fields. * 1473 * * 1474 * INPUT: levels -- The number of levels to reduce the tiberium. * 1475 * * 1476 * OUTPUT: bool; Was the tiberium level reduced by at least one level? * 1477 * * 1478 * WARNINGS: none * 1479 * * 1480 * HISTORY: * 1481 * 09/19/1994 JLB : Created. * 1482 *=============================================================================================*/ 1483 int CellClass::Reduce_Tiberium(int levels) 1484 { 1485 Validate(); 1486 int reducer = 0; 1487 1488 if (levels && Land == LAND_TIBERIUM) { 1489 if (OverlayData > levels) { 1490 OverlayData -= levels; 1491 reducer = levels; 1492 } else { 1493 Overlay = OVERLAY_NONE; 1494 reducer = OverlayData; 1495 OverlayData = 0; 1496 Recalc_Attributes(); 1497 } 1498 } 1499 return(reducer); 1500 } 1501 1502 1503 /*********************************************************************************************** 1504 * CellClass::Reduce_Wall -- Damages a wall, if damage is high enough. * 1505 * * 1506 * This routine will change the wall shape used for a wall if it's damaged. * 1507 * * 1508 * * 1509 * INPUT: damage -- The number of damage points the wall was hit with. * 1510 * * 1511 * OUTPUT: bool; Was the wall destroyed? * 1512 * * 1513 * WARNINGS: none * 1514 * * 1515 * HISTORY: * 1516 * 03/15/1995 BWG : Created. * 1517 * 03/19/1995 JLB : Updates cell information if wall was destroyed. * 1518 *=============================================================================================*/ 1519 int CellClass::Reduce_Wall(int damage) 1520 { 1521 Validate(); 1522 if (Overlay != OVERLAY_NONE) { 1523 bool destroyed = false; 1524 OverlayTypeClass const & wall = OverlayTypeClass::As_Reference(Overlay); 1525 1526 if (wall.IsWall) { 1527 1528 /* 1529 ** If the damage was great enough to ensure wall destruction, reduce the wall by one 1530 ** level (no more). Otherwise determine wall reduction based on a percentage chance 1531 ** proportional to the damage received and the wall's strength. 1532 */ 1533 if (damage >= wall.DamagePoints) { 1534 destroyed = true; 1535 } else { 1536 destroyed = Random_Pick(0, wall.DamagePoints) < damage; 1537 } 1538 1539 if (destroyed) { 1540 OverlayData+=16; 1541 if ((OverlayData>>4) >= wall.DamageLevels) { 1542 ObjectClass::Detach_This_From_All(As_Target()); 1543 Owner = HOUSE_NONE; 1544 Overlay = OVERLAY_NONE; 1545 OverlayData = 0; 1546 Recalc_Attributes(); 1547 Redraw_Objects(); 1548 CellClass * ncell = Adjacent_Cell(FACING_N); 1549 if (ncell) ncell->Wall_Update(); 1550 CellClass * wcell = Adjacent_Cell(FACING_W); 1551 if (wcell) wcell->Wall_Update(); 1552 CellClass * scell = Adjacent_Cell(FACING_S); 1553 if (scell) scell->Wall_Update(); 1554 CellClass * ecell = Adjacent_Cell(FACING_E); 1555 if (ecell) ecell->Wall_Update(); 1556 return(true); 1557 } 1558 } 1559 } 1560 } 1561 return(false); 1562 } 1563 1564 1565 /*********************************************************************************************** 1566 * CellClass::Get_Trigger -- retrieves reference to the cell's trigger * 1567 * * 1568 * INPUT: * 1569 * none. * 1570 * * 1571 * OUTPUT: * 1572 * TriggerClass reference * 1573 * * 1574 * WARNINGS: * 1575 * Never call this function unless the IsTrigger flag is set for the cell! * 1576 * * 1577 * HISTORY: * 1578 * 12/01/1994 BR : Created. * 1579 *=============================================================================================*/ 1580 TriggerClass * CellClass::Get_Trigger(void) const 1581 { 1582 Validate(); 1583 if (IsTrigger) { 1584 return(CellTriggers[Cell_Number()]); 1585 } 1586 return(NULL); 1587 } 1588 1589 1590 /*********************************************************************************************** 1591 * CellClass::Spot_Index -- returns cell sub-coord index for given COORD * 1592 * * 1593 * INPUT: * 1594 * coord COORD to compute index for * 1595 * * 1596 * OUTPUT: * 1597 * index into StoppingCoord that's closest to this coord * 1598 * * 1599 * WARNINGS: * 1600 * none. * 1601 * * 1602 * HISTORY: * 1603 * 11/21/1994 BR : Created. * 1604 * 12/10/1994 JLB : Uses alternate sub-position algorithm. * 1605 *=============================================================================================*/ 1606 int CellClass::Spot_Index(COORDINATE coord) 1607 { 1608 COORDINATE rel = coord & 0x00FF00FFL; // Sub coordinate value within cell. 1609 1610 /* 1611 ** If the coordinate is close enough to the center of the cell, then return 1612 ** the center position index. 1613 */ 1614 if (Distance(rel, 0x00800080L) < 60) { 1615 return(0); 1616 } 1617 1618 /* 1619 ** Since the center cell position has been eliminated, a simple comparison 1620 ** as related to the center of the cell can be used to determine the sub 1621 ** position. Take advantage of the fact that the sub positions are organized 1622 ** from left to right, top to bottom. 1623 */ 1624 int index = 0; 1625 if (Coord_X(rel) > 0x80) index |= 0x01; 1626 if (Coord_Y(rel) > 0x80) index |= 0x02; 1627 return(index+1); 1628 } 1629 1630 1631 /*********************************************************************************************** 1632 * CellClass::Closest_Free_Spot -- returns free spot closest to given coord * 1633 * * 1634 * Similar to the CellClass::Free_Spot; this routine finds the spot in * 1635 * the cell closest to the given coordinate, and returns the COORD of * 1636 * that spot if it's available, NULL if it's not. * 1637 * * 1638 * INPUT: * 1639 * coord coordinate to check (only sub cell position examined) * 1640 * * 1641 * any -- If only the closest spot is desired regardless of whether it is free or * 1642 * not, then this parameter will be true. * 1643 * * 1644 * OUTPUT: * 1645 * COORD of free spot, NULL if none. The coordinate return value does not alter the cell * 1646 * coordinate data portions of the coordinate passed in. Only the lower sub-cell * 1647 * data is altered. * 1648 * * 1649 * WARNINGS: * 1650 * none. * 1651 * * 1652 * HISTORY: * 1653 * 11/08/1994 BR : Created. * 1654 * 12/10/1994 JLB : Picks best of closest stopping positions. * 1655 * 12/21/1994 JLB : Adds a mix-up factor if center location is occupied. * 1656 *=============================================================================================*/ 1657 COORDINATE CellClass::Closest_Free_Spot(COORDINATE coord, bool any) const 1658 { 1659 Validate(); 1660 int spot_index = Spot_Index(coord); 1661 1662 /* 1663 ** This precalculated sequence table records the closest spots to any given spot. Sequential 1664 ** examination of these spots for availability ensures that the closes available one is 1665 ** discovered first. 1666 */ 1667 static unsigned char _sequence[5][4] = { 1668 {1,2,3,4}, 1669 {0,2,3,4}, 1670 {0,1,4,3}, 1671 {0,1,4,2}, 1672 {0,2,3,1} 1673 }; 1674 1675 /* 1676 ** In the case of the center coordinate being requested, but is occupied, then all other 1677 ** sublocations are equidistant. Instead of picking a static sequence of examination, the 1678 ** order is mixed up by way of this table. 1679 */ 1680 static unsigned char _alternate[4][4] = { 1681 {1,2,3,4}, 1682 {2,3,4,1}, 1683 {3,4,1,2}, 1684 {4,1,2,3}, 1685 }; 1686 coord &= 0xFF00FF00L; 1687 1688 /* 1689 ** Cells occupied by buildings or vehicles don't have any free spots. 1690 */ 1691 if (!any && (Flag.Occupy.Vehicle || Flag.Occupy.Monolith)) { 1692 return(NULL); 1693 } 1694 1695 /* 1696 ** If just the nearest position is desired regardless of whether occupied or not, 1697 ** then just return with the stopping coordinate value. 1698 */ 1699 if (any || Is_Spot_Free(spot_index)) { 1700 return(Coord_Add(coord, StoppingCoordAbs[spot_index])); 1701 } 1702 1703 /* 1704 ** Scan through all available sub-locations in the cell in order to determine 1705 ** the closest one to the coordinate requested. Use precalculated table so that 1706 ** when the first free position is found, bail. 1707 */ 1708 unsigned char *sequence; 1709 if (spot_index == 0) { 1710 sequence = &_alternate[Random_Pick(0,3)][0]; 1711 } else { 1712 sequence = &_sequence[spot_index][0]; 1713 } 1714 for (int index = 0; index < 4; index++) { 1715 int pos = *sequence++; 1716 1717 if (Is_Spot_Free(pos)) { 1718 return(Coord_Add(coord, StoppingCoordAbs[pos])); 1719 } 1720 } 1721 1722 /* 1723 ** No free spot could be found so return a NULL coordinate. 1724 */ 1725 return(0x00000000L); 1726 } 1727 1728 1729 /*********************************************************************************************** 1730 * CellClass::Clear_Icon -- Calculates what the clear icon number should be. * 1731 * * 1732 * This support routine will determine what the clear icon number would be for the cell. * 1733 * The icon number is determined by converting the cell number into an index into a * 1734 * lookup table. This yields what appears to be a randomized map without the necessity of * 1735 * generating and recording randomized map numbers. * 1736 * * 1737 * INPUT: none * 1738 * * 1739 * OUTPUT: Returns with the icon number for clear terrain if it were displayed at the * 1740 * cell. * 1741 * * 1742 * WARNINGS: none * 1743 * * 1744 * HISTORY: * 1745 * 12/26/1994 JLB : Created. * 1746 * 06/09/1995 JLB : Uses 16 entry scramble algorithm. * 1747 *=============================================================================================*/ 1748 int CellClass::Clear_Icon(void) const 1749 { 1750 Validate(); 1751 CELL cell = Cell_Number(); 1752 return((cell & 0x03) | ((cell>>4) & 0x0C)); 1753 } 1754 1755 1756 /*********************************************************************************************** 1757 * CellClass::Incoming -- Causes objects in cell to "run for cover". * 1758 * * 1759 * This routine is called whenever a great, but slow moving, threat is presented to the * 1760 * occupants of a cell. The occupants will, in most cases, stop what they are doing and * 1761 * try to get out of the way. * 1762 * * 1763 * INPUT: threat -- The coordinate source of the threat. * 1764 * * 1765 * forced -- If this threat is so major that the occupants should stop what * 1766 * they are doing, then this parameter should be set to true. * 1767 * * 1768 * nokidding -- Override the scatter to also affect human controlled objects. * 1769 * * 1770 * OUTPUT: none * 1771 * * 1772 * WARNINGS: none * 1773 * * 1774 * HISTORY: * 1775 * 01/10/1995 JLB : Created. * 1776 *=============================================================================================*/ 1777 void CellClass::Incoming(COORDINATE threat, bool forced, bool nokidding) 1778 { 1779 Validate(); 1780 ObjectClass * object = NULL; 1781 1782 object = Cell_Occupier(); 1783 while (object) { 1784 1785 /* 1786 ** Special check to make sure that friendly units never scatter. 1787 */ 1788 if (nokidding || Special.IsScatter || (object->Is_Techno() && !((TechnoClass *)object)->House->IsHuman)) { 1789 if (object->What_Am_I() == RTTI_INFANTRY) { 1790 object->Scatter(threat, forced, nokidding); 1791 } else { 1792 object->Scatter(threat, forced, nokidding); 1793 // object->Scatter(threat, false); 1794 } 1795 } 1796 object = object->Next; 1797 } 1798 } 1799 1800 1801 /*********************************************************************************************** 1802 * CellClass::Adjacent_Cell -- Determines the adjacent cell according to facing. * 1803 * * 1804 * Use this routine to return a reference to the adjacent cell in the direction specified. * 1805 * * 1806 * INPUT: face -- The direction to use when determining the adjacent cell. * 1807 * * 1808 * OUTPUT: Returns with a reference to the adjacent cell. * 1809 * * 1810 * WARNINGS: If the facing value is invalid, then a reference to the same cell is returned. * 1811 * * 1812 * HISTORY: * 1813 * 03/19/1995 JLB : Created. * 1814 *=============================================================================================*/ 1815 CellClass const * CellClass::Adjacent_Cell(FacingType face) const 1816 { 1817 Validate(); 1818 if (face == FACING_NONE) { 1819 return(this); 1820 } 1821 1822 if ((unsigned)face >= FACING_COUNT) { 1823 return(NULL); 1824 } 1825 1826 CELL newcell = ::Adjacent_Cell(Cell_Number(), face); 1827 if ((unsigned)newcell >= MAP_CELL_TOTAL) { 1828 return(NULL); 1829 } 1830 1831 return &Map[newcell]; 1832 } 1833 1834 1835 /*************************************************************************** 1836 * CellClass::Adjust_Threat -- Allows adjustment of threat at cell level * 1837 * * 1838 * INPUT: * 1839 * * 1840 * OUTPUT: * 1841 * * 1842 * WARNINGS: * 1843 * * 1844 * HISTORY: * 1845 * 04/24/1995 PWG : Created. * 1846 *=========================================================================*/ 1847 void CellClass::Adjust_Threat(HousesType house, int threat_value) 1848 { 1849 Validate(); 1850 int region = Map.Cell_Region(Cell_Number()); 1851 1852 for (HousesType lp = HOUSE_FIRST; lp < HOUSE_COUNT; lp ++) { 1853 if (lp == house) continue; 1854 1855 HouseClass *house_ptr = HouseClass::As_Pointer(lp); 1856 if (house_ptr && (!house_ptr->IsHuman || !house_ptr->Is_Ally(house))) { 1857 house_ptr->Adjust_Threat(region, threat_value); 1858 } 1859 } 1860 if (Debug_Threat) { 1861 Map.Flag_To_Redraw(true); 1862 } 1863 } 1864 1865 1866 /*********************************************************************************************** 1867 * CellClass::Tiberium_Adjust -- Adjust the look of the Tiberium for smoothing purposes. * 1868 * * 1869 * This routine will adjust the level of the Tiberium in the cell so that it will * 1870 * smoothly blend with the adjacent Tiberium. This routine should only be called for * 1871 * new Tiberium cells. Existing cells that contain Tiberium follow a different growth * 1872 * pattern. * 1873 * * 1874 * INPUT: pregame -- Is this a pregame call? Such a call will mixup the Tiberium overlay * 1875 * used. * 1876 * * 1877 * OUTPUT: Returns with the added Tiberium value that is now available for harvesting. * 1878 * * 1879 * WARNINGS: The return value is only valid for the initial placement. Tiberium growth will * 1880 * increase the net worth of the existing Tiberium. * 1881 * * 1882 * HISTORY: * 1883 * 05/16/1995 JLB : Created. * 1884 *=============================================================================================*/ 1885 long CellClass::Tiberium_Adjust(bool pregame) 1886 { 1887 Validate(); 1888 if (Overlay != OVERLAY_NONE) { 1889 if (OverlayTypeClass::As_Reference(Overlay).Land == LAND_TIBERIUM) { 1890 static int _adj[9] = {0,1,3,4,6,7,8,10,11}; 1891 int count = 0; 1892 1893 /* 1894 ** Mixup the Tiberium overlays so that they don't look the same. 1895 */ 1896 if (pregame) { 1897 Overlay = Random_Pick(OVERLAY_TIBERIUM1, OVERLAY_TIBERIUM12); 1898 } 1899 1900 /* 1901 ** Add up all adjacent cells that contain tiberium. 1902 ** (Skip those cells which aren't on the map) 1903 */ 1904 for (FacingType face = FACING_FIRST; face < FACING_COUNT; face++) { 1905 CELL cell = Cell_Number() + AdjacentCell[face]; 1906 if ((unsigned)cell >= MAP_CELL_TOTAL) continue; 1907 1908 CellClass * adj = Adjacent_Cell(face); 1909 1910 if (adj && adj->Overlay != OVERLAY_NONE && 1911 OverlayTypeClass::As_Reference(adj->Overlay).Land == LAND_TIBERIUM) { 1912 count++; 1913 } 1914 } 1915 1916 OverlayData = _adj[count]; 1917 return((OverlayData+1) * UnitTypeClass::TIBERIUM_STEP); 1918 } 1919 } 1920 return(0); 1921 } 1922 1923 1924 /*********************************************************************************************** 1925 * CellClass::Goodie_Check -- Performs crate discovery logic. * 1926 * * 1927 * Call this routine whenever an object enters a cell. It will check for the existance * 1928 * of a crate and generate any "goodie" it might contain. * 1929 * * 1930 * INPUT: object -- Pointer to the object that is triggering this crate. * 1931 * * 1932 * OUTPUT: Can the object continue to enter this cell? A false return value means that the * 1933 * cell is now occupied and must not be entered. * 1934 * * 1935 * WARNINGS: none * 1936 * * 1937 * HISTORY: * 1938 * 05/22/1995 JLB : Created. * 1939 * 07/08/1995 JLB : Added a bunch of goodies to the crates. * 1940 *=============================================================================================*/ 1941 bool CellClass::Goodie_Check(FootClass * object, bool check_steel) 1942 { 1943 Validate(); 1944 enum { 1945 MONEY, // Cash award. 1946 UNIT, // A free unit. 1947 NUKE, // A nuclear device that explodes. 1948 ION, // Calls forth an ion blast on discoverer. 1949 NUKE_MISSILE, // Gets a one time nuclear missile options. 1950 ION_BLAST, // Gets a one time ion blast option. 1951 AIR_STRIKE, // Gets a one time air strike option. 1952 HEAL_BASE, // Heals the player's entire base. 1953 CLOAK, // Units in region gain cloak ability. 1954 EXPLOSION, // Conventional explosion. 1955 NAPALM, // A napalm explosion. 1956 SQUAD, // A mixed squad of friendly infantry appear. 1957 VISCEROID, // A visceroid appears! 1958 DARKNESS, // Shroud the entire map. 1959 REVEAL, // Reveal the entire map. 1960 TOTAL_CRATES, 1961 }; 1962 static int _what[] = { 1963 DARKNESS,DARKNESS, 1964 REVEAL,REVEAL, 1965 NUKE, 1966 // ION,ION, 1967 NUKE_MISSILE, 1968 ION_BLAST,ION_BLAST, 1969 AIR_STRIKE,AIR_STRIKE,AIR_STRIKE,AIR_STRIKE, 1970 HEAL_BASE,HEAL_BASE, 1971 CLOAK,CLOAK, 1972 EXPLOSION,EXPLOSION,EXPLOSION,EXPLOSION, 1973 NAPALM,NAPALM,NAPALM, 1974 SQUAD,SQUAD,SQUAD,SQUAD,SQUAD, 1975 UNIT,UNIT,UNIT,UNIT,UNIT, 1976 VISCEROID 1977 }; 1978 1979 1980 /* 1981 ** Crate types are only defined here so it needs to match my new global crate total ST - 6/4/96 2:16PM 1982 */ 1983 #if (TOTAL_CRATES) == (TOTAL_CRATE_TYPES) 1984 1985 #else 1986 //Huge_Errrrror..... Oh NO! 1987 1988 #endif 1989 1990 1991 if (object && Overlay != OVERLAY_NONE && OverlayTypeClass::As_Reference(Overlay).IsCrate) { 1992 bool steel = (Overlay == OVERLAY_STEEL_CRATE); 1993 COORDINATE coord; // Temporary working coordinate value. 1994 1995 if (check_steel && steel) { 1996 1997 /* 1998 ** A triggered crate is automatically destroyed regardless of who or how 1999 ** it was triggered. 2000 */ 2001 Redraw_Objects(); 2002 Overlay = OVERLAY_NONE; 2003 OverlayData = 0; 2004 2005 if (object->Owner() == HOUSE_BAD) { 2006 object->House->Add_Nuke_Piece(); 2007 new AnimClass(ANIM_CRATE_EMPULSE, Cell_Coord()); 2008 } 2009 2010 } else if(!check_steel && !steel) { 2011 2012 /* 2013 ** A triggered crate is automatically destroyed regardless of who or how 2014 ** it was triggered. 2015 */ 2016 Redraw_Objects(); 2017 Overlay = OVERLAY_NONE; 2018 OverlayData = 0; 2019 2020 int index; 2021 UnitClass * unit = 0; 2022 unsigned damage = 0; 2023 int what = MONEY; 2024 2025 if (GameToPlay != GAME_NORMAL && (Random_Pick(1, 2) == 1 || !object->House->BScan)) { 2026 what = -1; 2027 2028 /* 2029 ** If the player has a construction yeard and practically no money and no legitmate means 2030 ** to make any more money, then give money to build a refinery. 2031 */ 2032 if ((object->House->BScan & (STRUCTF_CONST|STRUCTF_REFINERY)) == STRUCTF_CONST && 2033 object->House->Available_Money() < BuildingTypeClass::As_Reference(STRUCT_REFINERY).Cost) { 2034 2035 what = MONEY; 2036 } 2037 2038 /* 2039 ** If the player should get an MCV replacement, then give it now (probably). 2040 */ 2041 if (Random_Pick(0, 1) == 0 && 2042 MPlayerBases && 2043 !(object->House->UScan & UNITF_MCV) && 2044 object->House->BScan == 0 && 2045 object->House->Available_Money() > ((BuildingTypeClass::As_Reference(STRUCT_REFINERY).Cost + BuildingTypeClass::As_Reference(STRUCT_POWER).Cost) * object->House->CostBias)) { 2046 2047 what = UNIT; 2048 } 2049 2050 bool allow_super = true; 2051 if (GameToPlay == GAME_GLYPHX_MULTIPLAYER && !Rule.AllowSuperWeapons) { 2052 allow_super = false; 2053 } 2054 2055 while (what == -1) { 2056 what = _what[Random_Pick((unsigned)0, sizeof(_what)/sizeof(_what[0])-1)]; 2057 2058 if (what == REVEAL && object->House->IsVisionary) what = -1; 2059 if (what == AIR_STRIKE && (!allow_super || object->House->AirStrike.Is_Present())) what = -1; 2060 if (what == NUKE_MISSILE && (!allow_super || object->House->NukeStrike.Is_Present())) what = -1; 2061 if (what == ION_BLAST && (!allow_super || object->House->IonCannon.Is_Present())) what = -1; 2062 if (what == CLOAK && object->IsCloakable) what = -1; 2063 } 2064 } 2065 2066 /* 2067 ** Keep track of the number of each type of crate found 2068 */ 2069 if (GameToPlay == GAME_INTERNET){ 2070 object->House->TotalCrates->Increment_Unit_Total(what); 2071 } 2072 2073 /* 2074 ** Update the crate count and when all the crates have been discovered, flag 2075 ** to generate a new one. 2076 */ 2077 CrateCount--; 2078 if (!CrateMaker && CrateCount <= 0 && GameToPlay != GAME_NORMAL) { 2079 CrateMaker = true; 2080 CrateTimer = 1; 2081 } 2082 2083 /* 2084 ** Create the effect requested. 2085 */ 2086 switch (what) { 2087 default: 2088 2089 /* 2090 ** Give the player money. 2091 */ 2092 case MONEY: 2093 new AnimClass(ANIM_CRATE_DOLLAR, Cell_Coord()); 2094 if (GameToPlay == GAME_NORMAL) { 2095 HouseClass::As_Pointer(object->Owner())->Refund_Money(2000); 2096 } else { 2097 HouseClass::As_Pointer(object->Owner())->Refund_Money(100 + (Random_Pick(0,19)*100)); 2098 } 2099 break; 2100 2101 /* 2102 ** Shroud the world in blackness. 2103 */ 2104 case DARKNESS: 2105 { 2106 new AnimClass(ANIM_CRATE_EMPULSE, Cell_Coord()); 2107 bool shroud = false; 2108 if (GameToPlay != GAME_GLYPHX_MULTIPLAYER) { 2109 if (object->House == PlayerPtr) { 2110 shroud = true; 2111 } 2112 } else { 2113 if (object->House->IsHuman) { 2114 shroud = true; 2115 } 2116 } 2117 if (shroud) { 2118 for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) { 2119 CellClass * cellptr = &Map[cell]; 2120 if (cellptr->Is_Mapped(object->House) || cellptr->Is_Visible(object->House)) { 2121 cellptr->Redraw_Objects(); 2122 cellptr->Set_Mapped(object->House, false); 2123 cellptr->Set_Visible(object->House, false); 2124 } 2125 } 2126 HouseClass *find_house = object->House; 2127 for (int index = 0; index < Map.Layer[LAYER_GROUND].Count(); index++) { 2128 ObjectClass * object = Map.Layer[LAYER_GROUND][index]; 2129 if (object && object->Is_Techno() && ((TechnoClass *)object)->House == find_house) { 2130 object->Look(); 2131 } 2132 } 2133 Map.Flag_To_Redraw(true); 2134 } 2135 break; 2136 } 2137 /* 2138 ** Reveal the entire map. 2139 */ 2140 case REVEAL: 2141 { 2142 bool reveal = false; 2143 if (GameToPlay != GAME_GLYPHX_MULTIPLAYER) { 2144 if (object->House == PlayerPtr) { 2145 reveal = true; 2146 } 2147 } else { 2148 if (object->House->IsHuman) { 2149 reveal = true; 2150 } 2151 } 2152 2153 new AnimClass(ANIM_CRATE_EMPULSE, Cell_Coord()); 2154 object->House->IsVisionary = true; 2155 if (reveal) { 2156 for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) { 2157 Map.Map_Cell(cell, object->House, true); 2158 } 2159 } 2160 break; 2161 } 2162 /* 2163 ** Try to create a unit where the crate was. 2164 */ 2165 case UNIT: { 2166 UnitTypeClass const * utp = NULL; 2167 2168 /* 2169 ** Give the player an MCV if he has no base left but does have more than enough 2170 ** money to rebuild a new base. Of course, if he already has an MCV, then don't 2171 ** give him another one. 2172 */ 2173 if (MPlayerBases && 2174 !(object->House->UScan & UNITF_MCV) && 2175 object->House->BScan == 0 && 2176 object->House->Available_Money() > (BuildingTypeClass::As_Reference(STRUCT_REFINERY).Cost + BuildingTypeClass::As_Reference(STRUCT_POWER).Cost)) { 2177 2178 utp = &UnitTypeClass::As_Reference(UNIT_MCV); 2179 } 2180 2181 /* 2182 ** If the player has a base and a refinery, but no harvester, then give him 2183 ** a free one. 2184 */ 2185 if (!utp && (object->House->BScan & STRUCTF_REFINERY) && !(object->House->UScan & UNITF_HARVESTER)) { 2186 utp = &UnitTypeClass::As_Reference(UNIT_HARVESTER); 2187 } 2188 2189 while (!utp) { 2190 UnitType utype = Random_Pick(UNIT_FIRST, (UnitType)(UNIT_COUNT-1)); 2191 if (utype != UNIT_MCV || MPlayerBases) { 2192 utp = &UnitTypeClass::As_Reference(utype); 2193 if (utp->IsCrateGoodie && (utp->Ownable & (1 << object->Owner())) && utp->Level <= BuildLevel+2) break; 2194 utp = NULL; 2195 } 2196 } 2197 2198 UnitClass * unit = (UnitClass *)utp->Create_One_Of(object->House); 2199 if (unit) { 2200 if (unit->Unlimbo(Cell_Coord())) { 2201 return(false); 2202 } 2203 delete unit; 2204 } 2205 } 2206 break; 2207 2208 /* 2209 ** Create a squad of miscellanous composition. 2210 */ 2211 case SQUAD: 2212 for (index = 0; index < 5; index++) { 2213 static InfantryType _inf[] = { 2214 INFANTRY_E1,INFANTRY_E1,INFANTRY_E1,INFANTRY_E1,INFANTRY_E1,INFANTRY_E1, 2215 INFANTRY_E2, 2216 INFANTRY_E3, 2217 INFANTRY_E4, 2218 INFANTRY_E5, 2219 INFANTRY_E7, 2220 INFANTRY_RAMBO 2221 }; 2222 InfantryTypeClass::As_Reference(_inf[Random_Pick((unsigned)0, sizeof(_inf)/sizeof(_inf[0])-1)]).Create_And_Place(Cell_Number(), object->Owner()); 2223 } 2224 return(false); 2225 2226 /* 2227 ** Sometimes an explosion of great magnitude occurs. 2228 */ 2229 case NUKE: 2230 new AnimClass(ANIM_ATOM_BLAST, Cell_Coord()); 2231 break; 2232 2233 /* 2234 ** Sometimes an explosion of great magnitude occurs. 2235 */ 2236 case ION: 2237 new AnimClass(ANIM_ION_CANNON, Cell_Coord()); 2238 break; 2239 2240 /* 2241 ** A nuclear missile was discovered. Add it to the sidebar. 2242 */ 2243 case NUKE_MISSILE: 2244 new AnimClass(ANIM_CRATE_MISSILE, Cell_Coord()); 2245 if (object->House->NukeStrike.Enable(true)) { 2246 // Add to Glyphx multiplayer sidebar. ST - 3/22/2019 1:50PM 2247 if (GameToPlay == GAME_GLYPHX_MULTIPLAYER) { 2248 if (object->House->IsHuman) { 2249 Sidebar_Glyphx_Add(RTTI_SPECIAL, SPC_NUCLEAR_BOMB, object->House); 2250 } 2251 } else { 2252 if (object->IsOwnedByPlayer) { 2253 Map.Add(RTTI_SPECIAL, SPC_NUCLEAR_BOMB); 2254 Map.Column[1].Flag_To_Redraw(); 2255 } 2256 } 2257 } 2258 break; 2259 2260 /* 2261 ** A one time ion blast was discovered. Add it to the sidebar. 2262 */ 2263 case ION_BLAST: 2264 new AnimClass(ANIM_CRATE_EARTH, Cell_Coord()); 2265 if (object->House->IonCannon.Enable(true)) { 2266 // Add to Glyphx multiplayer sidebar. ST - 3/22/2019 1:50PM 2267 if (GameToPlay == GAME_GLYPHX_MULTIPLAYER) { 2268 if (object->House->IsHuman) { 2269 Sidebar_Glyphx_Add(RTTI_SPECIAL, SPC_ION_CANNON, object->House); 2270 } 2271 } else { 2272 if (object->IsOwnedByPlayer) { 2273 Map.Add(RTTI_SPECIAL, SPC_ION_CANNON); 2274 Map.Column[1].Flag_To_Redraw(); 2275 } 2276 } 2277 } 2278 break; 2279 2280 /* 2281 ** A one time air strike can be called int. Add it to the sidebar. 2282 */ 2283 case AIR_STRIKE: 2284 new AnimClass(ANIM_CRATE_DEVIATOR, Cell_Coord()); 2285 if (object->House->AirStrike.Enable(true)) { 2286 // Add to Glyphx multiplayer sidebar. ST - 3/22/2019 1:50PM 2287 if (GameToPlay == GAME_GLYPHX_MULTIPLAYER) { 2288 if (object->House->IsHuman) { 2289 Sidebar_Glyphx_Add(RTTI_SPECIAL, SPC_AIR_STRIKE, object->House); 2290 } 2291 } else { 2292 if (object->IsOwnedByPlayer) { 2293 Map.Add(RTTI_SPECIAL, SPC_AIR_STRIKE); 2294 Map.Column[1].Flag_To_Redraw(); 2295 } 2296 } 2297 } 2298 break; 2299 2300 /* 2301 ** A group of explosions are triggered around the crate. 2302 */ 2303 case EXPLOSION: 2304 damage = 400; 2305 object->Take_Damage((int&)damage, 0, WARHEAD_HE); 2306 for (index = 0; index < 5; index++) { 2307 COORDINATE coord = Coord_Scatter(Cell_Coord(), Random_Pick(0, 0x0200)); 2308 new AnimClass(ANIM_FBALL1, coord); 2309 damage = 400; 2310 Explosion_Damage(coord, damage, NULL, WARHEAD_HE); 2311 } 2312 break; 2313 2314 /* 2315 ** A napalm blast is triggered. 2316 */ 2317 case NAPALM: 2318 coord = Coord_Mid(Cell_Coord(), object->Center_Coord()); 2319 new AnimClass(ANIM_NAPALM3, coord); 2320 damage = 600; 2321 Explosion_Damage(coord, damage, NULL, WARHEAD_FIRE); 2322 break; 2323 2324 /* 2325 ** A visceroid appears and, boy, he's angry! 2326 */ 2327 case VISCEROID: 2328 unit = new UnitClass(UNIT_VICE, HOUSE_JP); 2329 if (unit) { 2330 if (unit->Unlimbo(Cell_Coord())) { 2331 return(false); 2332 } 2333 delete unit; 2334 } 2335 break; 2336 2337 /* 2338 ** All objects within a certain range will gain the ability to cloak. 2339 */ 2340 case CLOAK: 2341 new AnimClass(ANIM_CRATE_STEALTH, Cell_Coord()); 2342 for (index = 0; index < Map.Layer[LAYER_GROUND].Count(); index++) { 2343 ObjectClass * obj = Map.Layer[LAYER_GROUND][index]; 2344 2345 if (obj && obj->Is_Techno() && Distance(Cell_Coord(), obj->Center_Coord()) < 0x0300) { 2346 ((TechnoClass *)obj)->IsCloakable = true; 2347 } 2348 } 2349 break; 2350 2351 /* 2352 ** All of the player's objects heal up. 2353 */ 2354 case HEAL_BASE: 2355 new AnimClass(ANIM_CRATE_INVUN, Cell_Coord()); 2356 for (index = 0; index < Logic.Count(); index++) { 2357 ObjectClass * obj = Logic[index]; 2358 2359 if (obj && object->Is_Techno() && object->House->Class->House == obj->Owner()) { 2360 obj->Strength = obj->Class_Of().MaxStrength; 2361 } 2362 } 2363 break; 2364 2365 } 2366 } 2367 } 2368 return(true); 2369 } 2370 2371 2372 /*********************************************************************************************** 2373 * CellClass::Flag_Place -- Places a house flag down on the cell. * 2374 * * 2375 * This routine will place the house flag at this cell location. * 2376 * * 2377 * INPUT: house -- The house that is having its flag placed here. * 2378 * * 2379 * OUTPUT: Was the flag successfully placed here? * 2380 * * 2381 * WARNINGS: Failure to place means that the cell is impassable for some reason. * 2382 * * 2383 * HISTORY: * 2384 * 05/23/1995 JLB : Created. * 2385 *=============================================================================================*/ 2386 bool CellClass::Flag_Place(HousesType house) 2387 { 2388 Validate(); 2389 if (!IsFlagged && Is_Generally_Clear()) { 2390 IsFlagged = true; 2391 Owner = house; 2392 Flag_Update(); 2393 Redraw_Objects(); 2394 return(true); 2395 } 2396 return(false); 2397 } 2398 2399 2400 /*********************************************************************************************** 2401 * CellClass::Flag_Remove -- Removes the house flag from the cell. * 2402 * * 2403 * This routine will free the cell of any house flag that may be located there. * 2404 * * 2405 * INPUT: none * 2406 * * 2407 * OUTPUT: Was there a flag here that was removed? * 2408 * * 2409 * WARNINGS: none * 2410 * * 2411 * HISTORY: * 2412 * 05/23/1995 JLB : Created. * 2413 *=============================================================================================*/ 2414 bool CellClass::Flag_Remove(void) 2415 { 2416 Validate(); 2417 if (IsFlagged) { 2418 IsFlagged = false; 2419 Owner = HOUSE_NONE; 2420 Flag_Update(); 2421 Redraw_Objects(); 2422 return(true); 2423 } 2424 return(false); 2425 } 2426 2427 2428 void CellClass::Flag_Update(void) 2429 { 2430 if (IsFlagged && !CTFFlag) { 2431 Flag_Create(); 2432 } else if (!IsFlagged && CTFFlag) { 2433 Flag_Destroy(); 2434 } 2435 } 2436 2437 2438 void CellClass::Flag_Create(void) 2439 { 2440 if (!CTFFlag) { 2441 CTFFlag = new AnimClass(ANIM_FLAG, Cell_Coord(), 0, 1, true); 2442 if (CTFFlag == NULL) { 2443 for (int i = 0; i < Anims.Count(); ++i) { 2444 AnimClass* anim = Anims.Ptr(i); 2445 if (*anim != ANIM_FLAG) { 2446 anim->Delete_This(); 2447 break; 2448 } 2449 } 2450 CTFFlag = new AnimClass(ANIM_FLAG, Cell_Coord(), 0, 1, true); 2451 } 2452 assert(CTFFlag != NULL); 2453 CTFFlag->Set_Owner(Owner); 2454 } 2455 } 2456 2457 2458 void CellClass::Flag_Destroy(void) 2459 { 2460 delete CTFFlag; 2461 CTFFlag = NULL; 2462 } 2463 2464 2465 /*********************************************************************************************** 2466 * CellClass::Shimmer -- Causes all objects in the cell to shimmer. * 2467 * * 2468 * This routine is called when some event would cause a momentary disruption in the * 2469 * cloaking device. All objects that are cloaked in the cell will have their cloaking * 2470 * device shimmer. * 2471 * * 2472 * INPUT: none * 2473 * * 2474 * OUTPUT: none * 2475 * * 2476 * WARNINGS: none * 2477 * * 2478 * HISTORY: * 2479 * 07/29/1995 JLB : Created. * 2480 *=============================================================================================*/ 2481 void CellClass::Shimmer(void) 2482 { 2483 Validate(); 2484 ObjectClass * object = Cell_Occupier(); 2485 2486 while (object) { 2487 object->Do_Shimmer(); 2488 object = object->Next; 2489 } 2490 } 2491 2492 2493 /*********************************************************************************************** 2494 * CellClass::Cell_Occupier -- Fetches the occupier for the cell. * 2495 * * 2496 * This routine returns with the first recorded occupier of this cell. A special validity * 2497 * check is performed to ensure that there are no dead objects still marked on the * 2498 * map. * 2499 * * 2500 * INPUT: none * 2501 * * 2502 * OUTPUT: Returns with a pointer to the first occupier object. * 2503 * * 2504 * WARNINGS: none * 2505 * * 2506 * HISTORY: * 2507 * 08/17/1995 JLB : Created. * 2508 *=============================================================================================*/ 2509 ObjectClass * CellClass::Cell_Occupier(void) const 2510 { 2511 ObjectClass * ptr = OccupierPtr; 2512 2513 while (ptr && !ptr->IsActive) { 2514 ptr = ptr->Next; 2515 ((ObjectClass *&)OccupierPtr) = 0; 2516 } 2517 2518 return(ptr); 2519 } 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 /* 2530 ** Additions to CellClass to track visibility per-player. ST - 3/5/2019 3:08PM 2531 ** 2532 ** 2533 ** 2534 ** 2535 ** 2536 */ 2537 2538 /*********************************************************************************************** 2539 * CellClass::Set_Mapped -- Set the cell mapped for the given player * 2540 * * 2541 * * 2542 * HISTORY: * 2543 * 3/5/2019 3:09PM - ST * 2544 *=============================================================================================*/ 2545 void CellClass::Set_Mapped(HousesType house, bool set) 2546 { 2547 int shift = (int) house; 2548 if (set) { 2549 IsMappedByPlayerMask |= (1 << shift); 2550 } else { 2551 IsMappedByPlayerMask &= ~(1 << shift); 2552 } 2553 } 2554 2555 2556 /*********************************************************************************************** 2557 * CellClass::Set_Mapped -- Set the cell mapped for the given player * 2558 * * 2559 * * 2560 * HISTORY: * 2561 * 3/5/2019 3:09PM - ST * 2562 *=============================================================================================*/ 2563 void CellClass::Set_Mapped(HouseClass *player, bool set) 2564 { 2565 if (player && player->Class) { 2566 Set_Mapped(player->Class->House, set); 2567 if (GameToPlay == GAME_NORMAL && player->IsHuman) { 2568 IsMapped = set; // Also set the regular flag in single player 2569 } 2570 } 2571 } 2572 2573 /*********************************************************************************************** 2574 * CellClass::Is_Mapped -- Is the cell mapped for the given player * 2575 * * 2576 * * 2577 * HISTORY: * 2578 * 3/5/2019 3:13PM - ST * 2579 *=============================================================================================*/ 2580 bool CellClass::Is_Mapped(HousesType house) const 2581 { 2582 int shift = (int) house; 2583 return (IsMappedByPlayerMask & (1 << shift)) ? true : false; 2584 } 2585 2586 /*********************************************************************************************** 2587 * CellClass::Is_Mapped -- Is the cell mapped for the given player * 2588 * * 2589 * * 2590 * HISTORY: * 2591 * 3/5/2019 3:13PM - ST * 2592 *=============================================================================================*/ 2593 bool CellClass::Is_Mapped(HouseClass *player) const 2594 { 2595 if (player && player->Class) { 2596 return Is_Mapped(player->Class->House); 2597 } 2598 return false; 2599 } 2600 2601 /*********************************************************************************************** 2602 * CellClass::Set_Visible -- Set the cell visible for the given player * 2603 * * 2604 * * 2605 * HISTORY: * 2606 * 3/5/2019 3:16PM - ST * 2607 *=============================================================================================*/ 2608 void CellClass::Set_Visible(HousesType house, bool set) 2609 { 2610 int shift = (int) house; 2611 if (set) { 2612 IsVisibleByPlayerMask |= (1 << shift); 2613 } else { 2614 IsVisibleByPlayerMask &= ~(1 << shift); 2615 } 2616 } 2617 2618 2619 /*********************************************************************************************** 2620 * CellClass::Set_Visible -- Set the cell visible for the given player * 2621 * * 2622 * * 2623 * HISTORY: * 2624 * 3/5/2019 3:16PM - ST * 2625 *=============================================================================================*/ 2626 void CellClass::Set_Visible(HouseClass *player, bool set) 2627 { 2628 if (player && player->Class) { 2629 Set_Visible(player->Class->House, set); 2630 if (GameToPlay == GAME_NORMAL && player->IsHuman) { 2631 IsVisible = set; // Also set the regular flag in single player. This is needed for rendering 2632 } 2633 } 2634 } 2635 2636 /*********************************************************************************************** 2637 * CellClass::Is_Visible -- Is the cell visible for the given player * 2638 * * 2639 * * 2640 * HISTORY: * 2641 * 3/5/2019 3:16PM - ST * 2642 *=============================================================================================*/ 2643 bool CellClass::Is_Visible(HousesType house) const 2644 { 2645 int shift = (int) house; 2646 return (IsVisibleByPlayerMask & (1 << shift)) ? true : false; 2647 } 2648 2649 /*********************************************************************************************** 2650 * CellClass::Is_Visible -- Is the cell visible for the given player * 2651 * * 2652 * * 2653 * HISTORY: * 2654 * 3/5/2019 3:16PM - ST * 2655 *=============================================================================================*/ 2656 bool CellClass::Is_Visible(HouseClass *player) const 2657 { 2658 if (player && player->Class) { 2659 return Is_Visible(player->Class->House); 2660 } 2661 return false; 2662 } 2663 2664 void CellClass::Override_Land_Type(LandType type) 2665 { 2666 OverrideLand = type; 2667 } 2668 2669 #ifdef USE_RA_AI 2670 2671 /* 2672 ** Addition from Red Alert for AI. ST - 7/24/2019 5:33PM 2673 */ 2674 /*********************************************************************************************** 2675 * CellClass::Is_Clear_To_Move -- Determines if the cell is generally clear for travel * 2676 * * 2677 * This routine is called when determining general passability for purposes of zone * 2678 * calculation. Only blockages that cannot be circumvented are considered to make a cell * 2679 * impassable. All other obstructions can either be destroyed or are temporary. * 2680 * * 2681 * INPUT: loco -- The locomotion type to use when determining passablility. * 2682 * * 2683 * ignoreinfantry -- Should infantry in the cell be ignored for movement purposes? * 2684 * * 2685 * ignorevehicles -- If vehicles should be ignored, then this flag will be true. * 2686 * * 2687 * zone -- If specified, the zone must match this value or else movement is * 2688 * presumed disallowed. * 2689 * * 2690 * check -- This specifies the zone type that this check applies to. * 2691 * * 2692 * OUTPUT: Is the cell generally passable to ground targeting? * 2693 * * 2694 * WARNINGS: none * 2695 * * 2696 * HISTORY: * 2697 * 09/25/1995 JLB : Created. * 2698 * 06/25/1996 JLB : Uses tracked vehicles as a basis for zone check. * 2699 * 10/05/1996 JLB : Allows checking for crushable blockages. * 2700 *=============================================================================================*/ 2701 bool CellClass::Is_Clear_To_Move(bool ignoreinfantry, bool ignorevehicles) const 2702 { 2703 //assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL); 2704 2705 /* 2706 ** Flying objects always consider every cell passable since they can fly over everything. 2707 */ 2708 //if (loco == SPEED_WINGED) { 2709 // return(true); 2710 //} 2711 2712 /* 2713 ** If a zone was specified, then see if the cell is in a legal 2714 ** zone to allow movement. 2715 */ 2716 //if (zone != -1) { 2717 // if (zone != Zones[check]) { 2718 // return(false); 2719 // } 2720 //} 2721 2722 /* 2723 ** Check the occupy bits for passable legality. If ignore infantry is true, then 2724 ** don't consider infnatry. 2725 */ 2726 int composite = Flag.Composite; 2727 if (ignoreinfantry) { 2728 composite &= 0xE0; // Drop the infantry occupation bits. 2729 } 2730 if (ignorevehicles) { 2731 composite &= 0x5F; // Drop the vehicle/building bit. 2732 } 2733 if (composite != 0) { 2734 return(false); 2735 } 2736 2737 /* 2738 ** Fetch the land type of the cell -- to be modified and used later. 2739 */ 2740 //LandType land = Land_Type(); 2741 2742 /* 2743 ** Walls are always considered to block the terrain for general passability 2744 ** purposes unless this is a wall crushing check or if the checking object 2745 ** can destroy walls. 2746 */ 2747 OverlayTypeClass const * overlay = NULL; 2748 if (Overlay != OVERLAY_NONE) { 2749 overlay = &OverlayTypeClass::As_Reference(Overlay); 2750 } 2751 if (overlay != NULL && overlay->IsWall) { 2752 //if (check != MZONE_DESTROYER && (check != MZONE_CRUSHER || !overlay->IsCrushable)) { 2753 return(false); 2754 //} 2755 2756 /* 2757 ** Crushing objects consider crushable walls as clear rather than the 2758 ** typical LAND_WALL setting. 2759 */ 2760 //land = LAND_CLEAR; 2761 } 2762 2763 /* 2764 ** See if the ground type is impassable to this locomotion type and if 2765 ** so, return the error condition. 2766 */ 2767 //if (::Ground[land].Cost[loco] == 0) { 2768 // return(false); 2769 //} 2770 2771 /* 2772 ** All checks passed, so this cell must be passable. 2773 */ 2774 return(true); 2775 } 2776 2777 #endif //USE_RA_AI