MAPEDSEL.CPP (23372B)
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\mapedsel.cpv 2.18 16 Oct 1995 16:49:58 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 : MAPEDSEL.CPP * 24 * * 25 * Programmer : Bill Randolph * 26 * * 27 * Start Date : November 18, 1994 * 28 * * 29 * Last Update : February 2, 1995 [BR] * 30 * * 31 *-------------------------------------------------------------------------* 32 * Object-selection & manipulation routines * 33 *-------------------------------------------------------------------------* 34 * Functions: * 35 * MapEditClass::Select_Object -- selects an object for processing * 36 * MapEditClass::Select_Next -- selects next object on the map * 37 * MapEditClass::Popup_Controls -- shows/hides the pop-up object controls* 38 * MapEditClass::Grab_Object -- grabs the current object * 39 * MapEditClass::Move_Grabbed_Object -- moves the grabbed object * 40 * MapEditClass::Change_House -- changes CurrentObject's house * 41 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 42 43 #include "function.h" 44 45 #ifdef SCENARIO_EDITOR 46 47 48 /*************************************************************************** 49 * Select_Object -- selects an object for processing * 50 * * 51 * INPUT: * 52 * none. * 53 * * 54 * OUTPUT: * 55 * 0 = object selected, -1 = none * 56 * * 57 * WARNINGS: * 58 * none. * 59 * * 60 * HISTORY: * 61 * 11/04/1994 BR : Created. * 62 *=========================================================================*/ 63 int MapEditClass::Select_Object(void) 64 { 65 ObjectClass *object=NULL; // Generic object clicked on. 66 int x,y; 67 CELL cell; // Cell that was selected. 68 int rc=0; 69 70 /* 71 -------------------- See if an object was clicked on --------------------- 72 */ 73 x = _Kbd->MouseQX; 74 y = _Kbd->MouseQY; 75 76 /* 77 ............................ Get cell for x,y ............................ 78 */ 79 cell = Click_Cell_Calc(x, y); 80 81 /* 82 ............... Convert x,y to offset from cell upper-left ............... 83 */ 84 x = (x-TacPixelX) % ICON_PIXEL_W; 85 y = (y-TacPixelY) % ICON_PIXEL_H; 86 87 /* 88 ......................... Get object at that x,y ......................... 89 */ 90 object = Cell_Object(cell, x, y); 91 92 /* 93 ----------------- If no object, unselect the current one ----------------- 94 */ 95 if (!object) { 96 if (CurrentObject.Count()) { 97 /* 98 ................... Unselect all current objects ................... 99 */ 100 Unselect_All(); 101 102 /* 103 ..................... Turn off object controls ..................... 104 */ 105 Popup_Controls(); 106 } 107 rc = -1; 108 } else { 109 110 /* 111 ------------------ Select object only if it's different ------------------ 112 */ 113 if (!CurrentObject.Count() || (CurrentObject.Count() && object != CurrentObject[0])) { 114 /* 115 ..................... Unselect all current objects .................... 116 */ 117 Unselect_All(); 118 object->Select(); 119 120 /* 121 ................... Set mouse shape back to normal .................... 122 */ 123 Set_Default_Mouse(MOUSE_NORMAL); 124 Override_Mouse_Shape(MOUSE_NORMAL); 125 126 /* 127 ....................... Show the popup controls ....................... 128 */ 129 Popup_Controls(); 130 } 131 } 132 133 /* 134 -------------------------- Force map to redraw --------------------------- 135 */ 136 HiddenPage.Clear(); 137 Flag_To_Redraw(true); 138 139 return(rc); 140 } 141 142 143 /*************************************************************************** 144 * MapEditClass::Select_Next -- selects next object on the map * 145 * * 146 * INPUT: * 147 * none. * 148 * * 149 * OUTPUT: * 150 * none * 151 * * 152 * WARNINGS: * 153 * none. * 154 * * 155 * HISTORY: * 156 * 11/22/1994 BR : Created. * 157 *=========================================================================*/ 158 void MapEditClass::Select_Next(void) 159 { 160 ObjectClass * obj; 161 CELL obj_cell; 162 int smap_w; // screen map width in icons 163 int smap_h; // screen map height in icons 164 int cell_x; // cell-x of next object 165 int cell_y; // cell-y of next object 166 int tcell_x; // cell-x of TacticalCell 167 int tcell_y; // cell-y of TacticalCell 168 169 /* 170 ----------------------- Get next object on the map ----------------------- 171 */ 172 obj = Map.Next_Object(CurrentObject[0]); 173 174 if (obj) { 175 /* 176 ............... Unselect current object if there is one ............... 177 */ 178 Unselect_All(); 179 180 /* 181 ......................... Select this object .......................... 182 */ 183 obj->Select(); 184 } 185 186 /* 187 --------------------- Restore mouse shape to normal ---------------------- 188 */ 189 Set_Default_Mouse(MOUSE_NORMAL); 190 Override_Mouse_Shape(MOUSE_NORMAL); 191 192 /* 193 -------------------------- Show pop-up controls -------------------------- 194 */ 195 Popup_Controls(); 196 197 /* 198 ---------------- Make sure object is shown on the screen ----------------- 199 */ 200 /* 201 ..................... compute screen map dimensions ...................... 202 */ 203 smap_w = Lepton_To_Cell(TacLeptonWidth); 204 smap_h = Lepton_To_Cell(TacLeptonHeight); 205 206 /* 207 ...................... compute x,y of object's cell ...................... 208 */ 209 obj_cell = Coord_Cell(CurrentObject[0]->Coord); 210 cell_x = Cell_X(obj_cell); 211 cell_y = Cell_Y(obj_cell); 212 tcell_x = Coord_XCell(TacticalCoord); 213 tcell_y = Coord_YCell(TacticalCoord); 214 215 /* 216 ................... If object is off-screen, move map .................... 217 */ 218 if (cell_x < tcell_x) { 219 tcell_x = cell_x; 220 } else { 221 if (cell_x >= tcell_x + smap_w) { 222 tcell_x = cell_x - smap_w + 1; 223 } 224 } 225 226 if (cell_y < tcell_y) { 227 tcell_y = cell_y; 228 } else { 229 if (cell_y >= tcell_y + smap_h) { 230 tcell_y = cell_y - smap_h + 1; 231 } 232 } 233 234 ScenarioInit++; 235 Set_Tactical_Position(XY_Coord(Cell_To_Lepton(tcell_x), Cell_To_Lepton(tcell_y))); 236 ScenarioInit--; 237 238 /* 239 -------------------------- Force map to redraw --------------------------- 240 */ 241 HiddenPage.Clear(); 242 Flag_To_Redraw(true); 243 } 244 245 246 /*************************************************************************** 247 * MapEditClass::Popup_Controls -- shows/hides the pop-up object controls * 248 * * 249 * Call this routine whenever the CurrentObject changes. The routine will * 250 * selectively enable or disable the popup controls based on whether * 251 * CurrentObject is NULL, or if it's a Techno object, or what type of * 252 * Techno object it is. * 253 * * 254 * INPUT: * 255 * none. * 256 * * 257 * OUTPUT: * 258 * none. * 259 * * 260 * WARNINGS: * 261 * none. * 262 * * 263 * HISTORY: * 264 * 11/22/1994 BR : Created. * 265 *=========================================================================*/ 266 void MapEditClass::Popup_Controls(void) 267 { 268 const TechnoTypeClass * objtype = NULL; 269 HousesType owner; // object's current owner 270 int mission_index; // object's current mission 271 int strength; // object's 0-255 strength value 272 int i; 273 274 /*------------------------------------------------------------------------ 275 Remove all buttons from GScreen's button list (so none of them provide 276 input any more); then, destroy the list by Zapping each button. Then, 277 we'll have to add at least the MapArea button back to the Input button 278 list before we return, plus any other buttons to process input for. We 279 always must add MapArea LAST in the list, so it doesn't intercept the 280 other buttons' input. 281 ------------------------------------------------------------------------*/ 282 Remove_A_Button(*GDIButton); 283 Remove_A_Button(*NODButton); 284 Remove_A_Button(*NeutralButton); 285 Remove_A_Button(*Multi1Button); 286 Remove_A_Button(*Multi2Button); 287 Remove_A_Button(*Multi3Button); 288 Remove_A_Button(*Multi4Button); 289 Remove_A_Button(*MissionList); 290 Remove_A_Button(*HealthGauge); 291 Remove_A_Button(*HealthText); 292 Remove_A_Button(*FacingDial); 293 Remove_A_Button(*BaseGauge); 294 Remove_A_Button(*BaseLabel); 295 Remove_A_Button(*MapArea); 296 297 /* 298 ------------------ If no current object, hide the list ------------------- 299 */ 300 if (!CurrentObject.Count()) { 301 Add_A_Button(*BaseGauge); 302 Add_A_Button(*BaseLabel); 303 Add_A_Button(*MapArea); 304 return; 305 } 306 307 /* 308 --------------- If not Techno, no need for editing buttons --------------- 309 */ 310 if (!CurrentObject[0]->Is_Techno()) { 311 Add_A_Button(*BaseGauge); 312 Add_A_Button(*BaseLabel); 313 Add_A_Button(*MapArea); 314 return; 315 } 316 317 objtype = (TechnoTypeClass const *)&CurrentObject[0]->Class_Of(); 318 319 /* 320 ---------------------- Get object's current values ----------------------- 321 */ 322 owner = CurrentObject[0]->Owner(); 323 mission_index = 0; 324 for (i = 0; i < NUM_EDIT_MISSIONS; i++) { 325 if (CurrentObject[0]->Get_Mission() == MapEditMissions[i]) { 326 mission_index = i; 327 } 328 } 329 strength = CurrentObject[0]->Health_Ratio(); 330 331 332 /* 333 ----------------------------- House buttons ------------------------------ 334 */ 335 if (ScenPlayer == SCEN_PLAYER_MPLAYER) { 336 if (Verify_House(HOUSE_NEUTRAL, &CurrentObject[0]->Class_Of())) { 337 Add_A_Button(*NeutralButton); 338 } 339 if (Verify_House(HOUSE_MULTI1, &CurrentObject[0]->Class_Of())) { 340 Add_A_Button(*Multi1Button); 341 } 342 if (Verify_House(HOUSE_MULTI2, &CurrentObject[0]->Class_Of())) { 343 Add_A_Button(*Multi2Button); 344 } 345 if (Verify_House(HOUSE_MULTI3, &CurrentObject[0]->Class_Of())) { 346 Add_A_Button(*Multi3Button); 347 } 348 if (Verify_House(HOUSE_MULTI4, &CurrentObject[0]->Class_Of())) { 349 Add_A_Button(*Multi4Button); 350 } 351 } else { 352 if (Verify_House(HOUSE_NEUTRAL, &CurrentObject[0]->Class_Of())) { 353 Add_A_Button(*NeutralButton); 354 } 355 if (Verify_House(HOUSE_BAD, &CurrentObject[0]->Class_Of())) { 356 Add_A_Button(*NODButton); 357 } 358 if (Verify_House(HOUSE_GOOD, &CurrentObject[0]->Class_Of())) { 359 Add_A_Button(*GDIButton); 360 } 361 } 362 363 /* 364 ........................ Set house button states ......................... 365 */ 366 if (Buttons) { 367 Set_House_Buttons(owner, Buttons, POPUP_GDI); 368 } 369 370 switch (objtype->What_Am_I()) { 371 case RTTI_UNITTYPE: 372 case RTTI_INFANTRYTYPE: 373 case RTTI_AIRCRAFTTYPE: 374 MissionList->Set_Selected_Index(mission_index); 375 HealthGauge->Set_Value(strength); 376 sprintf(HealthBuf, "%d", CurrentObject[0]->Strength); 377 FacingDial->Set_Direction(((TechnoClass *)CurrentObject[0])->PrimaryFacing); 378 379 /* 380 ** Make the list. 381 */ 382 Add_A_Button(*MissionList); 383 Add_A_Button(*HealthGauge); 384 Add_A_Button(*HealthText); 385 Add_A_Button(*FacingDial); 386 break; 387 388 case RTTI_BUILDINGTYPE: 389 HealthGauge->Set_Value(strength); 390 sprintf(HealthBuf, "%d", CurrentObject[0]->Strength); 391 Add_A_Button(*HealthGauge); 392 Add_A_Button(*HealthText); 393 394 if (objtype->IsTurretEquipped) { 395 FacingDial->Set_Direction(((TechnoClass *) CurrentObject[0])->PrimaryFacing); 396 Add_A_Button(*FacingDial); 397 } 398 break; 399 } 400 401 /*------------------------------------------------------------------------ 402 Add the map area last, so it's "underneath" the other buttons, and won't 403 intercept input for those buttons. 404 ------------------------------------------------------------------------*/ 405 Add_A_Button(*BaseGauge); 406 Add_A_Button(*BaseLabel); 407 Add_A_Button(*MapArea); 408 } 409 410 411 /*************************************************************************** 412 * MapEditClass::Grab_Object -- grabs the current object * 413 * * 414 * INPUT: * 415 * none. * 416 * * 417 * OUTPUT: * 418 * none. * 419 * * 420 * WARNINGS: * 421 * none. * 422 * * 423 * HISTORY: * 424 * 11/07/1994 BR : Created. * 425 *=========================================================================*/ 426 void MapEditClass::Grab_Object(void) 427 { 428 CELL cell; 429 430 if (CurrentObject.Count()) { 431 GrabbedObject = CurrentObject[0]; 432 433 /*------------------------------------------------------------------------ 434 Find out which cell 'ZoneCell' is in relation to the object's current cell 435 ------------------------------------------------------------------------*/ 436 cell = Coord_Cell(GrabbedObject->Coord); 437 GrabOffset = cell - ZoneCell; 438 } 439 } 440 441 442 /*************************************************************************** 443 * MapEditClass::Move_Grabbed_Object -- moves the grabbed object * 444 * * 445 * INPUT: * 446 * none. * 447 * * 448 * OUTPUT: * 449 * 0 = object moved, -1 = it didn't * 450 * * 451 * WARNINGS: * 452 * none. * 453 * * 454 * HISTORY: * 455 * 11/07/1994 BR : Created. * 456 *=========================================================================*/ 457 int MapEditClass::Move_Grabbed_Object(void) 458 { 459 COORDINATE new_coord = 0; 460 int retval = -1; 461 462 /* 463 --------------------------- Lift up the object --------------------------- 464 */ 465 GrabbedObject->Mark(MARK_UP); 466 467 /*------------------------------------------------------------------------ 468 If infantry, use a free spot in this cell 469 ------------------------------------------------------------------------*/ 470 if (GrabbedObject->Is_Infantry()) { 471 472 if (Is_Spot_Free(Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()))) { 473 new_coord = Closest_Free_Spot(Pixel_To_Coord(Get_Mouse_X(), 474 Get_Mouse_Y())); 475 /*.................................................................. 476 Clear the occupied bit in this infantry's cell. 477 ..................................................................*/ 478 ((InfantryClass *)GrabbedObject)->Clear_Occupy_Bit(GrabbedObject->Coord); 479 // Map[Coord_Cell(GrabbedObject->Coord)].Flag.Composite &= 480 // ~(1 << CellClass::Spot_Index(GrabbedObject->Coord)); 481 } else { 482 new_coord = NULL; 483 } 484 485 } else { 486 487 /*------------------------------------------------------------------------ 488 Non-infantry: use cell's center coordinate 489 ------------------------------------------------------------------------*/ 490 new_coord = Cell_Coord(ZoneCell + GrabOffset); 491 492 if (GrabbedObject->What_Am_I() == RTTI_BUILDING || 493 GrabbedObject->What_Am_I() == RTTI_TERRAIN) { 494 495 new_coord &= 0xFF00FF00L; 496 } 497 498 /* 499 ................ Try to place object at new coordinate ................ 500 */ 501 if (GrabbedObject->Can_Enter_Cell(Coord_Cell(new_coord)) != MOVE_OK) { 502 new_coord = NULL; 503 } 504 } 505 if (new_coord != NULL) { 506 /* 507 ** If this object is part of the AI's Base list, change the coordinate 508 ** in the Base's Node list. 509 */ 510 if (GrabbedObject->What_Am_I()==RTTI_BUILDING && 511 Base.Get_Node((BuildingClass *)GrabbedObject)) 512 Base.Get_Node((BuildingClass *)GrabbedObject)->Coord = new_coord; 513 514 GrabbedObject->Coord = new_coord; 515 retval = 0; 516 } 517 GrabbedObject->Mark(MARK_DOWN); 518 519 /*------------------------------------------------------------------------ 520 For infantry, set the bit in its new cell marking that spot as occupied. 521 ------------------------------------------------------------------------*/ 522 if (GrabbedObject->Is_Infantry()) { 523 ((InfantryClass *)GrabbedObject)->Set_Occupy_Bit(new_coord); 524 // Map[Coord_Cell(new_coord)].Flag.Composite |= 525 // (1 << CellClass::Spot_Index(new_coord)); 526 } 527 528 /*------------------------------------------------------------------------ 529 Re-select the object, and reset the mouse pointer 530 ------------------------------------------------------------------------*/ 531 Set_Default_Mouse(MOUSE_NORMAL); 532 Override_Mouse_Shape(MOUSE_NORMAL); 533 534 Flag_To_Redraw(true); 535 536 return(retval); 537 } 538 539 540 /*************************************************************************** 541 * MapEditClass::Change_House -- changes CurrentObject's house * 542 * * 543 * INPUT: * 544 * newhouse house to change to * 545 * * 546 * OUTPUT: * 547 * 1 = house was changed, 0 = it wasn't * 548 * * 549 * WARNINGS: * 550 * none. * 551 * * 552 * HISTORY: * 553 * 11/17/1994 BR : Created. * 554 *=========================================================================*/ 555 bool MapEditClass::Change_House(HousesType newhouse) 556 { 557 TechnoClass *tp; 558 559 /*------------------------------------------------------------------------ 560 Return if no current object 561 ------------------------------------------------------------------------*/ 562 if (!CurrentObject.Count()) { 563 return(false); 564 } 565 566 /*------------------------------------------------------------------------ 567 Only techno objects can be owned by a house; return if not a techno 568 ------------------------------------------------------------------------*/ 569 if (!CurrentObject[0]->Is_Techno()) { 570 return(false); 571 } 572 573 /*------------------------------------------------------------------------ 574 You can't change the house if the object is part of the AI's Base. 575 ------------------------------------------------------------------------*/ 576 if (CurrentObject[0]->What_Am_I()==RTTI_BUILDING && Base.Is_Node((BuildingClass *)CurrentObject[0])) { 577 return(false); 578 } 579 580 /*------------------------------------------------------------------------ 581 Verify that the target house exists 582 ------------------------------------------------------------------------*/ 583 if (HouseClass::As_Pointer(newhouse)==NULL) { 584 return(false); 585 } 586 587 /*------------------------------------------------------------------------ 588 Verify that this is a valid owner 589 ------------------------------------------------------------------------*/ 590 if (!Verify_House(newhouse, &CurrentObject[0]->Class_Of())) { 591 return(false); 592 } 593 594 /*------------------------------------------------------------------------ 595 Change the house 596 ------------------------------------------------------------------------*/ 597 tp = (TechnoClass *)CurrentObject[0]; 598 tp->House = HouseClass::As_Pointer(newhouse); 599 600 return(true); 601 } 602 603 604 #endif