MAPEDSEL.CPP (19526B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 16 /* $Header: /CounterStrike/MAPEDSEL.CPP 1 3/03/97 10:25a 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 : April 30, 1996 [JLB] * 30 * * 31 *-------------------------------------------------------------------------* 32 * Object-selection & manipulation routines * 33 *-------------------------------------------------------------------------* 34 * Functions: * 35 * MapEditClass::Change_House -- changes CurrentObject's house * 36 * MapEditClass::Grab_Object -- grabs the current object * 37 * MapEditClass::Move_Grabbed_Object -- moves the grabbed object * 38 * MapEditClass::Popup_Controls -- shows/hides the pop-up object controls* 39 * MapEditClass::Select_Next -- selects next object on the map * 40 * MapEditClass::Select_Object -- selects an object for processing * 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 = Keyboard->MouseQX; 74 y = Keyboard->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 /* 99 ** Unselect all current objects 100 */ 101 Unselect_All(); 102 103 /* 104 ** Turn off object controls 105 */ 106 Popup_Controls(); 107 } 108 rc = -1; 109 } else { 110 111 /* 112 ** Select object only if it's different 113 */ 114 if (!CurrentObject.Count() || (CurrentObject.Count() && object != CurrentObject[0])) { 115 116 /* 117 ** Unselect all current objects 118 */ 119 Unselect_All(); 120 object->Select(); 121 122 /* 123 ** Set mouse shape back to normal 124 */ 125 Set_Default_Mouse(MOUSE_NORMAL); 126 Override_Mouse_Shape(MOUSE_NORMAL); 127 128 /* 129 ** Show the popup controls 130 */ 131 Popup_Controls(); 132 } 133 } 134 135 /* 136 ** Force map to redraw 137 */ 138 HidPage.Clear(); 139 Flag_To_Redraw(true); 140 141 return(rc); 142 } 143 144 145 /*************************************************************************** 146 * MapEditClass::Select_Next -- selects next object on the map * 147 * * 148 * INPUT: * 149 * none. * 150 * * 151 * OUTPUT: * 152 * none * 153 * * 154 * WARNINGS: * 155 * none. * 156 * * 157 * HISTORY: * 158 * 11/22/1994 BR : Created. * 159 *=========================================================================*/ 160 void MapEditClass::Select_Next(void) 161 { 162 ObjectClass * obj; 163 CELL obj_cell; 164 int smap_w; // screen map width in icons 165 int smap_h; // screen map height in icons 166 int cell_x; // cell-x of next object 167 int cell_y; // cell-y of next object 168 int tcell_x; // cell-x of TacticalCell 169 int tcell_y; // cell-y of TacticalCell 170 171 /* 172 ** Get next object on the map 173 */ 174 obj = Map.Next_Object(CurrentObject[0]); 175 176 if (obj) { 177 /* 178 ** Unselect current object if there is one 179 */ 180 Unselect_All(); 181 182 /* 183 ** Select this object 184 */ 185 obj->Select(); 186 } 187 188 /* 189 ** Restore mouse shape to normal 190 */ 191 Set_Default_Mouse(MOUSE_NORMAL); 192 Override_Mouse_Shape(MOUSE_NORMAL); 193 194 /* 195 ** Show pop-up controls 196 */ 197 Popup_Controls(); 198 199 /* 200 ** Make sure object is shown on the screen 201 */ 202 /* 203 ** compute screen map dimensions 204 */ 205 smap_w = Lepton_To_Cell(TacLeptonWidth); 206 smap_h = Lepton_To_Cell(TacLeptonHeight); 207 208 /* 209 ** compute x,y of object's cell 210 */ 211 obj_cell = Coord_Cell(CurrentObject[0]->Coord); 212 cell_x = Cell_X(obj_cell); 213 cell_y = Cell_Y(obj_cell); 214 tcell_x = Coord_XCell(TacticalCoord); 215 tcell_y = Coord_YCell(TacticalCoord); 216 217 /* 218 ** If object is off-screen, move map 219 */ 220 if (cell_x < tcell_x) { 221 tcell_x = cell_x; 222 } else { 223 if (cell_x >= tcell_x + smap_w) { 224 tcell_x = cell_x - smap_w + 1; 225 } 226 } 227 228 if (cell_y < tcell_y) { 229 tcell_y = cell_y; 230 } else { 231 if (cell_y >= tcell_y + smap_h) { 232 tcell_y = cell_y - smap_h + 1; 233 } 234 } 235 236 ScenarioInit++; 237 Set_Tactical_Position(XY_Coord(Cell_To_Lepton(tcell_x), Cell_To_Lepton(tcell_y))); 238 ScenarioInit--; 239 240 /* 241 ** Force map to redraw 242 */ 243 HidPage.Clear(); 244 Flag_To_Redraw(true); 245 } 246 247 248 /*************************************************************************** 249 * MapEditClass::Popup_Controls -- shows/hides the pop-up object controls * 250 * * 251 * Call this routine whenever the CurrentObject changes. The routine will * 252 * selectively enable or disable the popup controls based on whether * 253 * CurrentObject is NULL, or if it's a Techno object, or what type of * 254 * Techno object it is. * 255 * * 256 * INPUT: * 257 * none. * 258 * * 259 * OUTPUT: * 260 * none. * 261 * * 262 * WARNINGS: * 263 * none. * 264 * * 265 * HISTORY: * 266 * 11/22/1994 BR : Created. * 267 * 04/30/1996 JLB : Revamped for new buttons and stuff. * 268 *=========================================================================*/ 269 void MapEditClass::Popup_Controls(void) 270 { 271 const TechnoTypeClass * objtype = NULL; 272 HousesType owner; // object's current owner 273 int mission_index; // object's current mission 274 int strength; // object's 0-255 strength value 275 int i; 276 277 /* 278 ** Remove all buttons from GScreen's button list (so none of them provide 279 ** input any more); then, destroy the list by Zapping each button. Then, 280 ** we'll have to add at least the MapArea button back to the Input button 281 ** list before we return, plus any other buttons to process input for. We 282 ** always must add MapArea LAST in the list, so it doesn't intercept the 283 ** other buttons' input. 284 */ 285 Remove_A_Button(*HouseList); 286 Remove_A_Button(*MissionList); 287 Remove_A_Button(*HealthGauge); 288 Remove_A_Button(*HealthText); 289 Remove_A_Button(*FacingDial); 290 Remove_A_Button(*BaseGauge); 291 Remove_A_Button(*BaseLabel); 292 Remove_A_Button(*MapArea); 293 294 Remove_A_Button(*Sellable); 295 Remove_A_Button(*Rebuildable); 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()*256; 330 331 switch (objtype->What_Am_I()) { 332 case RTTI_VESSELTYPE: 333 case RTTI_UNITTYPE: 334 case RTTI_INFANTRYTYPE: 335 case RTTI_AIRCRAFTTYPE: 336 MissionList->Set_Selected_Index(mission_index); 337 HealthGauge->Set_Value(strength); 338 sprintf(HealthBuf, "%d", CurrentObject[0]->Strength); 339 FacingDial->Set_Direction(((TechnoClass *)CurrentObject[0])->PrimaryFacing); 340 341 /* 342 ** Make the list. 343 */ 344 Add_A_Button(*HealthGauge); 345 Add_A_Button(*HouseList); 346 HouseList->Set_Selected_Index(owner); 347 Add_A_Button(*MissionList); 348 Add_A_Button(*HealthText); 349 Add_A_Button(*FacingDial); 350 break; 351 352 case RTTI_BUILDINGTYPE: 353 HealthGauge->Set_Value(strength); 354 sprintf(HealthBuf, "%d", CurrentObject[0]->Strength); 355 Add_A_Button(*HealthGauge); 356 Add_A_Button(*HouseList); 357 HouseList->Set_Selected_Index(owner); 358 Add_A_Button(*HealthText); 359 360 Add_A_Button(*Sellable); 361 if (((BuildingClass*)CurrentObject[0])->IsAllowedToSell) { 362 Sellable->Turn_On(); 363 } else { 364 Sellable->Turn_Off(); 365 } 366 Add_A_Button(*Rebuildable); 367 if (((BuildingClass*)CurrentObject[0])->IsToRebuild) { 368 Rebuildable->Turn_On(); 369 } else { 370 Rebuildable->Turn_Off(); 371 } 372 373 if (objtype->IsTurretEquipped) { 374 FacingDial->Set_Direction(((TechnoClass *) CurrentObject[0])->PrimaryFacing); 375 Add_A_Button(*FacingDial); 376 } 377 break; 378 } 379 380 /* 381 ** Add the map area last, so it's "underneath" the other buttons, and won't 382 ** intercept input for those buttons. 383 */ 384 Add_A_Button(*BaseGauge); 385 Add_A_Button(*BaseLabel); 386 Add_A_Button(*MapArea); 387 } 388 389 390 /*************************************************************************** 391 * MapEditClass::Grab_Object -- grabs the current object * 392 * * 393 * INPUT: * 394 * none. * 395 * * 396 * OUTPUT: * 397 * none. * 398 * * 399 * WARNINGS: * 400 * none. * 401 * * 402 * HISTORY: * 403 * 11/07/1994 BR : Created. * 404 *=========================================================================*/ 405 void MapEditClass::Grab_Object(void) 406 { 407 CELL cell; 408 409 if (CurrentObject.Count()) { 410 GrabbedObject = CurrentObject[0]; 411 412 /* 413 ** Find out which cell 'ZoneCell' is in relation to the object's current cell 414 */ 415 cell = Coord_Cell(GrabbedObject->Coord); 416 GrabOffset = cell - ZoneCell; 417 } 418 } 419 420 421 /*************************************************************************** 422 * MapEditClass::Move_Grabbed_Object -- moves the grabbed object * 423 * * 424 * INPUT: * 425 * none. * 426 * * 427 * OUTPUT: * 428 * 0 = object moved, -1 = it didn't * 429 * * 430 * WARNINGS: * 431 * none. * 432 * * 433 * HISTORY: * 434 * 11/07/1994 BR : Created. * 435 *=========================================================================*/ 436 int MapEditClass::Move_Grabbed_Object(void) 437 { 438 COORDINATE new_coord = 0; 439 int retval = -1; 440 441 /* 442 ** Lift up the object 443 */ 444 GrabbedObject->Mark(MARK_UP); 445 446 /* 447 ** If infantry, use a free spot in this cell 448 */ 449 if (GrabbedObject->Is_Infantry()) { 450 451 if (Is_Spot_Free(Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()))) { 452 new_coord = Closest_Free_Spot(Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y())); 453 454 /* 455 ** Clear the occupied bit in this infantry's cell. 456 */ 457 ((InfantryClass *)GrabbedObject)->Clear_Occupy_Bit(GrabbedObject->Coord); 458 } else { 459 new_coord = NULL; 460 } 461 462 } else { 463 464 /* 465 ** Non-infantry: use cell's center coordinate 466 */ 467 new_coord = Cell_Coord(ZoneCell + GrabOffset); 468 469 if (GrabbedObject->What_Am_I() == RTTI_BUILDING || 470 GrabbedObject->What_Am_I() == RTTI_TERRAIN) { 471 472 new_coord = Coord_Whole(new_coord); 473 } 474 475 /* 476 ** Try to place object at new coordinate 477 */ 478 if (GrabbedObject->Can_Enter_Cell(Coord_Cell(new_coord)) != MOVE_OK) { 479 new_coord = NULL; 480 } 481 } 482 if (new_coord != NULL) { 483 484 /* 485 ** If this object is part of the AI's Base list, change the coordinate 486 ** in the Base's Node list. 487 */ 488 if (GrabbedObject->What_Am_I()==RTTI_BUILDING && 489 Base.Get_Node((BuildingClass *)GrabbedObject)) 490 Base.Get_Node((BuildingClass *)GrabbedObject)->Cell = Coord_Cell(new_coord); 491 492 GrabbedObject->Coord = new_coord; 493 retval = 0; 494 } 495 GrabbedObject->Mark(MARK_DOWN); 496 497 /* 498 ** For infantry, set the bit in its new cell marking that spot as occupied. 499 */ 500 if (GrabbedObject->Is_Infantry()) { 501 ((InfantryClass *)GrabbedObject)->Set_Occupy_Bit(new_coord); 502 } 503 504 /* 505 ** Re-select the object, and reset the mouse pointer 506 */ 507 Set_Default_Mouse(MOUSE_NORMAL); 508 Override_Mouse_Shape(MOUSE_NORMAL); 509 510 Flag_To_Redraw(true); 511 512 return(retval); 513 } 514 515 516 /*************************************************************************** 517 * MapEditClass::Change_House -- changes CurrentObject's house * 518 * * 519 * INPUT: * 520 * newhouse house to change to * 521 * * 522 * OUTPUT: * 523 * 1 = house was changed, 0 = it wasn't * 524 * * 525 * WARNINGS: * 526 * none. * 527 * * 528 * HISTORY: * 529 * 11/17/1994 BR : Created. * 530 *=========================================================================*/ 531 bool MapEditClass::Change_House(HousesType newhouse) 532 { 533 TechnoClass *tp; 534 535 /* 536 ** Return if no current object 537 */ 538 if (!CurrentObject.Count()) { 539 return(false); 540 } 541 542 /* 543 ** Only techno objects can be owned by a house; return if not a techno 544 */ 545 if (!CurrentObject[0]->Is_Techno()) { 546 return(false); 547 } 548 549 /* 550 ** You can't change the house if the object is part of the AI's Base. 551 */ 552 if (CurrentObject[0]->What_Am_I()==RTTI_BUILDING && Base.Is_Node((BuildingClass *)CurrentObject[0])) { 553 return(false); 554 } 555 556 /* 557 ** Verify that the target house exists 558 */ 559 if (HouseClass::As_Pointer(newhouse)==NULL) { 560 return(false); 561 } 562 563 /* 564 ** Verify that this is a valid owner 565 */ 566 // if (!Verify_House(newhouse, &CurrentObject[0]->Class_Of())) { 567 // return(false); 568 // } 569 570 /* 571 ** Change the house 572 */ 573 tp = (TechnoClass *)CurrentObject[0]; 574 tp->House = HouseClass::As_Pointer(newhouse); 575 576 tp->IsOwnedByPlayer = false; 577 if (tp->House == PlayerPtr) { 578 tp->IsOwnedByPlayer = true; 579 } 580 581 return(true); 582 } 583 584 585 #endif