MAPEDPLC.CPP (59083B)
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/MAPEDPLC.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 : MAPEDPLC.CPP * 24 * * 25 * Programmer : Bill Randolph * 26 * * 27 * Start Date : November 18, 1994 * 28 * * 29 * Last Update : May 12, 1996 [JLB] * 30 * * 31 *-------------------------------------------------------------------------* 32 * Object-placement routines * 33 *-------------------------------------------------------------------------* 34 * Functions: * 35 * MapEditClass::Build_Base_To -- builds the AI base to the given percent* 36 * MapEditClass::Cancel_Base_Building -- stops base-building mode * 37 * MapEditClass::Cancel_Placement -- cancels placement mode * 38 * MapEditClass::Place_Home -- homes the placement object * 39 * MapEditClass::Place_Next -- while placing object, goes to next * 40 * MapEditClass::Place_Next_Category -- places next object category * 41 * MapEditClass::Place_Object -- attempts to place the current object * 42 * MapEditClass::Place_Prev -- while placing object, goes to previous * 43 * MapEditClass::Place_Prev_Category -- places previous object category * 44 * MapEditClass::Place_Trigger -- assigns trigger to object or cell * 45 * MapEditClass::Placement_Dialog -- adds an object to the scenario * 46 * MapEditClass::Set_House_Buttons -- toggles house buttons for btn list * 47 * MapEditClass::Start_Base_Building -- starts base-building mode * 48 * MapEditClass::Start_Placement -- enters placement mode * 49 * MapEditClass::Start_Trigger_Placement -- enters trigger placement mode* 50 * MapEditClass::Stop_Trigger_Placement -- exits trigger placement mode * 51 * MapEditClass::Toggle_House -- toggles current placement object's house* 52 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 53 54 #include "function.h" 55 56 #ifdef SCENARIO_EDITOR 57 58 59 /*************************************************************************** 60 * MapEditClass::Placement_Dialog -- adds an object to the scenario * 61 * * 62 * This function sets LastChoice & LastHouse to the values chosen * 63 * by the user. It's up to the caller to call Start_Placement to enter * 64 * placement mode. * 65 * This routine does not modify PendingObject or PendingHouse. * 66 * * 67 * ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ * 68 * ³ [GDI] [NOD] [Neutral] ³ * 69 * ³ ³ * 70 * ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ * 71 * ³ ³ ³ [Template] ³ * 72 * ³ ³ ³ [Overlay ] ³ * 73 * ³ ³ ³ [Smudge ] ³ * 74 * ³ ³ ³ [Terrain ] ³ * 75 * ³ ³ (Object picture) ³ [Unit ] ³ * 76 * ³ ³ ³ [Infantry] ³ * 77 * ³ ³ ³ [Aircraft] ³ * 78 * ³ ³ ³ [Building] ³ * 79 * ³ ³ ³ ³ * 80 * ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÚÄÄÄÄÄÄ¿ ³ * 81 * ³ [<-] [->] ³(Grid)³ ³ * 82 * ³ ³ ³ ³ * 83 * ³ [OK] [Cancel] ÀÄÄÄÄÄÄÙ ³ * 84 * ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ * 85 * * 86 * INPUT: * 87 * none. * 88 * * 89 * OUTPUT: * 90 * 0 = OK, -1 = cancel * 91 * * 92 * WARNINGS: * 93 * none. * 94 * * 95 * HISTORY: * 96 * 10/21/1994 BR : Created. * 97 * 12/13/1995 JLB : Fixed house buttons to handle expanded house list. * 98 * 05/12/1996 JLB : Handles hi-res. * 99 *=========================================================================*/ 100 int MapEditClass::Placement_Dialog(void) 101 { 102 HousesType house; 103 RemapControlType * scheme = GadgetClass::Get_Color_Scheme(); 104 105 /* 106 ** Dialog & button dimensions 107 */ 108 enum { 109 D_DIALOG_W = 400, 110 D_DIALOG_H = 180, 111 D_DIALOG_X = 0, 112 D_DIALOG_Y = 0, 113 D_DIALOG_CX = D_DIALOG_X + (D_DIALOG_W / 2), 114 115 D_TXT8_H = 11, 116 D_MARGIN = 7, 117 118 D_PICTURE_W = 152, // must be divisible by 8! 119 D_PICTURE_H = 105, 120 D_PICTURE_X = D_DIALOG_X + 35, // must start on a byte boundary! 121 D_PICTURE_Y = D_DIALOG_Y + D_MARGIN + D_TXT8_H + D_MARGIN, 122 D_PICTURE_CX = D_PICTURE_X + D_PICTURE_W / 2, 123 124 D_GDI_W = 65, 125 D_GDI_H = 9, 126 D_GDI_X = D_PICTURE_X+D_PICTURE_W+5, 127 D_GDI_Y = D_PICTURE_Y, 128 129 D_LEFT_W = 45, 130 D_LEFT_H = 9, 131 D_LEFT_X = D_PICTURE_CX - 5 - D_LEFT_W, 132 D_LEFT_Y = D_PICTURE_Y + D_PICTURE_H + D_MARGIN, 133 134 D_RIGHT_W = 45, 135 D_RIGHT_H = 9, 136 D_RIGHT_X = D_PICTURE_CX + 5, 137 D_RIGHT_Y = D_PICTURE_Y + D_PICTURE_H + D_MARGIN, 138 139 D_TEMPLATE_W = 70, 140 D_TEMPLATE_H = 9, 141 D_TEMPLATE_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_TEMPLATE_W - 30, 142 D_TEMPLATE_Y = D_PICTURE_Y, 143 144 D_OVERLAY_W = 70, 145 D_OVERLAY_H = 9, 146 D_OVERLAY_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_OVERLAY_W - 30, 147 D_OVERLAY_Y = D_TEMPLATE_Y + D_TEMPLATE_H, 148 149 D_SMUDGE_W = 70, 150 D_SMUDGE_H = 9, 151 D_SMUDGE_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_SMUDGE_W - 30, 152 D_SMUDGE_Y = D_OVERLAY_Y + D_OVERLAY_H, 153 154 D_TERRAIN_W = 70, 155 D_TERRAIN_H = 9, 156 D_TERRAIN_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_TERRAIN_W - 30, 157 D_TERRAIN_Y = D_SMUDGE_Y + D_SMUDGE_H, 158 159 D_UNIT_W = 70, 160 D_UNIT_H = 9, 161 D_UNIT_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_UNIT_W - 30, 162 D_UNIT_Y = D_TERRAIN_Y + D_TERRAIN_H, 163 164 D_INFANTRY_W = 70, 165 D_INFANTRY_H = 9, 166 D_INFANTRY_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_INFANTRY_W - 30, 167 D_INFANTRY_Y = D_UNIT_Y + D_UNIT_H, 168 169 D_AIRCRAFT_W = 70, 170 D_AIRCRAFT_H = 9, 171 D_AIRCRAFT_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_AIRCRAFT_W - 30, 172 D_AIRCRAFT_Y = D_INFANTRY_Y + D_INFANTRY_H, 173 174 D_BUILDING_W = 70, 175 D_BUILDING_H = 9, 176 D_BUILDING_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_BUILDING_W - 30, 177 D_BUILDING_Y = D_AIRCRAFT_Y + D_AIRCRAFT_H, 178 179 D_AIR_W = 70, 180 D_AIR_H = 9, 181 D_AIR_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_AIR_W - 30, 182 D_AIR_Y = D_BUILDING_Y + D_BUILDING_H, 183 184 D_OK_W = 45, 185 D_OK_H = 9, 186 D_OK_X = D_PICTURE_CX - D_OK_W - 5, 187 D_OK_Y = D_DIALOG_Y + D_DIALOG_H - D_OK_H - D_MARGIN - 15, 188 189 D_CANCEL_W = 45, 190 D_CANCEL_H = 9, 191 D_CANCEL_X = D_PICTURE_CX + 5, 192 D_CANCEL_Y = D_DIALOG_Y + D_DIALOG_H - D_CANCEL_H - D_MARGIN - 15, 193 194 GRIDSIZE = 10, 195 GRIDBLOCK_W = 3, 196 GRIDBLOCK_H = 3, 197 D_GRID_X = D_DIALOG_X + D_DIALOG_W - (GRIDSIZE * GRIDBLOCK_W) - D_MARGIN - 35, 198 D_GRID_Y = D_DIALOG_Y + D_DIALOG_H - (GRIDSIZE * GRIDBLOCK_H) - D_MARGIN - 35, 199 }; 200 201 /* 202 ** Button enumerations: 203 */ 204 enum { 205 BUTTON_GDI=100, 206 BUTTON_HOUSE, 207 BUTTON_NEXT, 208 BUTTON_PREV, 209 BUTTON_OK, 210 BUTTON_CANCEL, 211 BUTTON_TEMPLATE, 212 BUTTON_OVERLAY, 213 BUTTON_SMUDGE, 214 BUTTON_TERRAIN, 215 BUTTON_UNIT, 216 BUTTON_INFANTRY, 217 BUTTON_AIRCRAFT, 218 BUTTON_BUILDING, 219 BUTTON_AIR, 220 }; 221 222 /* 223 ** Dialog variables 224 */ 225 bool cancel = false; // true = user cancels 226 const ObjectTypeClass * curobj; // Working object pointer. 227 int x,y; // for drawing the grid 228 KeyNumType input; // user input 229 short const * occupy; // ptr into object's OccupyList 230 int cell; // cell index for parsing OccupyList 231 int i; 232 int typeindex; // index of class type 233 234 /* 235 ** Buttons 236 */ 237 ControlClass * commands; 238 239 ListClass housebtn(BUTTON_HOUSE, 240 D_GDI_X, D_GDI_Y, 60, 8*16, 241 TPF_EFNT | TPF_NOSHADOW, 242 MFCD::Retrieve("EBTN-UP.SHP"), 243 MFCD::Retrieve("EBTN-DN.SHP")); 244 for (house = HOUSE_FIRST; house < HOUSE_COUNT; house++) { 245 housebtn.Add_Item(HouseTypeClass::As_Reference(house).IniName); 246 } 247 house = HOUSE_FIRST; 248 249 TextButtonClass nextbtn(BUTTON_NEXT, TXT_RIGHT, TPF_EBUTTON, D_RIGHT_X, D_RIGHT_Y, D_RIGHT_W, D_RIGHT_H); 250 TextButtonClass prevbtn(BUTTON_PREV, TXT_LEFT, TPF_EBUTTON, D_LEFT_X, D_LEFT_Y, D_LEFT_W, D_LEFT_H); 251 TextButtonClass okbtn(BUTTON_OK, "OK", TPF_EBUTTON, D_OK_X, D_OK_Y, D_OK_W, D_OK_H); 252 TextButtonClass cancelbtn(BUTTON_CANCEL, "Cancel", TPF_EBUTTON, D_CANCEL_X, D_CANCEL_Y, D_CANCEL_W, D_CANCEL_H); 253 TextButtonClass templatebtn(BUTTON_TEMPLATE, "Template", TPF_EBUTTON, D_TEMPLATE_X, D_TEMPLATE_Y, D_TEMPLATE_W, D_TEMPLATE_H); 254 TextButtonClass overlaybtn(BUTTON_OVERLAY, "Overlay", TPF_EBUTTON, D_OVERLAY_X, D_OVERLAY_Y, D_OVERLAY_W, D_OVERLAY_H); 255 TextButtonClass smudgebtn(BUTTON_SMUDGE, "Smudge", TPF_EBUTTON, D_SMUDGE_X, D_SMUDGE_Y, D_SMUDGE_W, D_SMUDGE_H); 256 TextButtonClass terrainbtn(BUTTON_TERRAIN, "Terrain", TPF_EBUTTON, D_TERRAIN_X, D_TERRAIN_Y, D_TERRAIN_W, D_TERRAIN_H); 257 TextButtonClass unitbtn(BUTTON_UNIT, "Unit", TPF_EBUTTON, D_UNIT_X, D_UNIT_Y, D_UNIT_W, D_UNIT_H); 258 TextButtonClass infantrybtn(BUTTON_INFANTRY, "Infantry", TPF_EBUTTON, D_INFANTRY_X, D_INFANTRY_Y, D_INFANTRY_W, D_INFANTRY_H); 259 TextButtonClass aircraftbtn(BUTTON_AIRCRAFT, "Ships", TPF_EBUTTON, D_AIRCRAFT_X, D_AIRCRAFT_Y, D_AIRCRAFT_W, D_AIRCRAFT_H); 260 TextButtonClass buildingbtn(BUTTON_BUILDING, "Building", TPF_EBUTTON, D_BUILDING_X, D_BUILDING_Y, D_BUILDING_W, D_BUILDING_H); 261 TextButtonClass airbtn(BUTTON_AIR, "Aircraft", TPF_EBUTTON, D_AIR_X, D_AIR_Y, D_AIR_W, D_AIR_H); 262 263 /* 264 ** Initialize addable objects list; we must do this every time in case one 265 ** of the object pools has become exhausted; that object won't be available 266 ** for adding. (Skip aircraft, since they won't be used in the editor.) 267 */ 268 Clear_List(); 269 TemplateTypeClass::Prep_For_Add(); 270 OverlayTypeClass::Prep_For_Add(); 271 SmudgeTypeClass::Prep_For_Add(); 272 TerrainTypeClass::Prep_For_Add(); 273 UnitTypeClass::Prep_For_Add(); 274 InfantryTypeClass::Prep_For_Add(); 275 VesselTypeClass::Prep_For_Add(); 276 BuildingTypeClass::Prep_For_Add(); 277 AircraftTypeClass::Prep_For_Add(); 278 279 /* 280 ** Compute offset of each class type in the Objects array 281 */ 282 TypeOffset[0] = 0; 283 for (i = 1; i < NUM_EDIT_CLASSES; i++) { 284 TypeOffset[i] = TypeOffset[i-1] + NumType[i-1]; 285 } 286 287 /* 288 ** Return if no objects to place 289 */ 290 if (!ObjCount) { 291 return(-1); 292 } 293 294 /* 295 ** Initialize 296 */ 297 Set_Logic_Page(SeenBuff); 298 if (LastChoice >= ObjCount) { 299 LastChoice = 0; 300 } 301 curobj = Objects[LastChoice]; // current object to choose 302 303 commands = &nextbtn; 304 housebtn.Add_Tail(*commands); 305 prevbtn.Add_Tail(*commands); 306 okbtn.Add_Tail(*commands); 307 cancelbtn.Add_Tail(*commands); 308 templatebtn.Add_Tail(*commands); 309 overlaybtn.Add_Tail(*commands); 310 smudgebtn.Add_Tail(*commands); 311 terrainbtn.Add_Tail(*commands); 312 unitbtn.Add_Tail(*commands); 313 infantrybtn.Add_Tail(*commands); 314 aircraftbtn.Add_Tail(*commands); 315 buildingbtn.Add_Tail(*commands); 316 airbtn.Add_Tail(*commands); 317 318 /* 319 ** Make sure the recorded house selection matches the house list 320 ** box selection. 321 */ 322 LastHouse = HousesType(housebtn.Current_Index()); 323 324 /* 325 ** Main processing loop 326 */ 327 bool display = true; 328 bool process = true; 329 while (process) { 330 331 /* 332 ** Invoke game callback 333 */ 334 Call_Back(); 335 336 /* 337 ** Refresh display if needed 338 */ 339 if (display) { 340 341 /* 342 ** Display the dialog box 343 */ 344 Hide_Mouse(); 345 Dialog_Box(D_DIALOG_X, D_DIALOG_Y, D_DIALOG_W, D_DIALOG_H); 346 Draw_Caption(TXT_PLACE_OBJECT, D_DIALOG_X, D_DIALOG_Y, D_DIALOG_W); 347 348 /* 349 ** Display the current object: 350 ** - save the current window dimensions 351 ** - adjust the window size to the actual drawable area 352 ** - draw the shape 353 ** - reset the window dimensions 354 */ 355 WindowList[WINDOW_EDITOR][WINDOWX] = D_PICTURE_X; 356 WindowList[WINDOW_EDITOR][WINDOWY] = D_PICTURE_Y; 357 WindowList[WINDOW_EDITOR][WINDOWWIDTH] = D_PICTURE_W; 358 WindowList[WINDOW_EDITOR][WINDOWHEIGHT] = D_PICTURE_H; 359 Change_Window((int)WINDOW_EDITOR); 360 Draw_Box(D_PICTURE_X, D_PICTURE_Y, D_PICTURE_W, D_PICTURE_H, BOXSTYLE_DOWN, false); 361 curobj->Display(WinW/2, WinH>>1, WINDOW_EDITOR, LastHouse); 362 // curobj->Display(WinW<<2, WinH>>1, WINDOW_EDITOR, LastHouse); 363 364 /* 365 ** Erase the grid 366 */ 367 LogicPage->Fill_Rect(D_GRID_X - GRIDBLOCK_W * 2, D_GRID_Y, 368 D_GRID_X + GRIDSIZE * GRIDBLOCK_W, 369 D_GRID_Y + GRIDSIZE * GRIDBLOCK_H, BLACK); 370 371 /* 372 ** Draw a box for every cell occupied 373 */ 374 occupy = curobj->Occupy_List(); 375 while ( (*occupy) != REFRESH_EOL) { 376 cell = (*occupy); 377 occupy++; 378 x = D_GRID_X + ((cell % MAP_CELL_W) * GRIDBLOCK_W); 379 y = D_GRID_Y + ((cell / MAP_CELL_W) * GRIDBLOCK_H); 380 LogicPage->Fill_Rect(x, y, x + GRIDBLOCK_W - 1, y + GRIDBLOCK_H - 1, scheme->Bright); 381 } 382 383 /* 384 ** Draw the grid itself 385 */ 386 for (y = 0; y <= GRIDSIZE; y++) { 387 for (x = 0; x <= GRIDSIZE; x++) { 388 LogicPage->Draw_Line(D_GRID_X + x * GRIDBLOCK_W, D_GRID_Y, 389 D_GRID_X + x * GRIDBLOCK_W, 390 D_GRID_Y + GRIDSIZE * GRIDBLOCK_H, scheme->Shadow); 391 } 392 LogicPage->Draw_Line(D_GRID_X, D_GRID_Y + y * GRIDBLOCK_H, 393 D_GRID_X + GRIDSIZE * GRIDBLOCK_W, D_GRID_Y + y * GRIDBLOCK_H, 394 scheme->Shadow); 395 } 396 397 /* 398 ** Print the object's label from the class's Full_Name(). 399 ** Warning: Text_String returns an EMS pointer, so standard string 400 ** functions won't work! 401 */ 402 Fancy_Text_Print (curobj->Full_Name(), 403 D_PICTURE_CX, D_PICTURE_Y + D_MARGIN, scheme, TBLACK, 404 TPF_CENTER | TPF_EFNT | TPF_NOSHADOW); 405 406 /* 407 ** Redraw buttons 408 ** Figure out which class category we're in & highlight that button 409 ** This updates 'typeindex', which is used below, and it also updates 410 ** the category button states. 411 */ 412 i = 0; 413 for (typeindex = 0; typeindex < NUM_EDIT_CLASSES; typeindex++) { 414 i += NumType[typeindex]; 415 if (LastChoice < i) break; 416 } 417 templatebtn.Turn_Off(); 418 overlaybtn.Turn_Off(); 419 smudgebtn.Turn_Off(); 420 terrainbtn.Turn_Off(); 421 unitbtn.Turn_Off(); 422 infantrybtn.Turn_Off(); 423 aircraftbtn.Turn_Off(); 424 airbtn.Turn_Off(); 425 buildingbtn.Turn_Off(); 426 switch (typeindex + BUTTON_TEMPLATE) { 427 case BUTTON_TEMPLATE: 428 templatebtn.Turn_On(); 429 break; 430 431 case BUTTON_OVERLAY: 432 overlaybtn.Turn_On(); 433 break; 434 435 case BUTTON_SMUDGE: 436 smudgebtn.Turn_On(); 437 break; 438 439 case BUTTON_TERRAIN: 440 terrainbtn.Turn_On(); 441 break; 442 443 case BUTTON_UNIT: 444 unitbtn.Turn_On(); 445 break; 446 447 case BUTTON_INFANTRY: 448 infantrybtn.Turn_On(); 449 break; 450 451 case BUTTON_AIRCRAFT: 452 aircraftbtn.Turn_On(); 453 break; 454 455 case BUTTON_AIR: 456 airbtn.Turn_On(); 457 break; 458 459 case BUTTON_BUILDING: 460 buildingbtn.Turn_On(); 461 break; 462 } 463 464 /* 465 ** Redraw buttons 466 */ 467 commands->Draw_All(); 468 Show_Mouse(); 469 display = false; 470 471 } 472 473 /* 474 ** Get user input 475 */ 476 input = commands->Input(); 477 478 /* 479 ** Process user input 480 */ 481 switch (input) { 482 483 /* 484 ** GDI House 485 */ 486 case (BUTTON_HOUSE | KN_BUTTON): 487 house = HousesType(housebtn.Current_Index()); 488 489 /* 490 ** Set flags & buttons 491 */ 492 LastHouse = house; 493 display = true; 494 break; 495 496 /* 497 ** Next in list 498 */ 499 case (KN_RIGHT): 500 case (BUTTON_NEXT | KN_BUTTON): 501 /* 502 ** Increment to next obj 503 */ 504 LastChoice++; 505 if (LastChoice == ObjCount) { 506 LastChoice = 0; 507 } 508 curobj = Objects[LastChoice]; 509 510 nextbtn.Turn_Off(); 511 display = true; 512 break; 513 514 /* 515 ** Previous in list 516 */ 517 case (KN_LEFT): 518 case (BUTTON_PREV | KN_BUTTON): 519 520 /* 521 ** Decrement to prev obj 522 */ 523 LastChoice--; 524 if (LastChoice < 0) { 525 LastChoice = ObjCount-1; 526 } 527 curobj = Objects[LastChoice]; 528 prevbtn.Turn_Off(); 529 display = true; 530 break; 531 532 /* 533 ** Select a class type 534 */ 535 case (BUTTON_TEMPLATE | KN_BUTTON): 536 case (BUTTON_OVERLAY | KN_BUTTON): 537 case (BUTTON_SMUDGE | KN_BUTTON): 538 case (BUTTON_TERRAIN | KN_BUTTON): 539 case (BUTTON_UNIT | KN_BUTTON): 540 case (BUTTON_INFANTRY | KN_BUTTON): 541 case (BUTTON_AIRCRAFT | KN_BUTTON): 542 case (BUTTON_BUILDING | KN_BUTTON): 543 case (BUTTON_AIR | KN_BUTTON): 544 545 /* 546 ** Find index of class 547 */ 548 typeindex = input - (BUTTON_TEMPLATE | KN_BUTTON); 549 550 /* 551 ** If no objects of that type, do nothing 552 */ 553 if (NumType[typeindex]==0) { 554 display = true; 555 break; 556 } 557 558 /* 559 ** Set current object 560 */ 561 LastChoice = TypeOffset[typeindex]; 562 curobj = Objects[LastChoice]; 563 display = true; 564 break; 565 566 /* 567 ** Next category 568 */ 569 case KN_PGDN: 570 typeindex++; 571 if (typeindex==NUM_EDIT_CLASSES) { 572 typeindex = 0; 573 } 574 575 /* 576 ** Set current object 577 */ 578 LastChoice = TypeOffset[typeindex]; 579 curobj = Objects[LastChoice]; 580 display = true; 581 break; 582 583 /* 584 ** Previous category 585 */ 586 case KN_PGUP: 587 typeindex--; 588 if (typeindex < 0) { 589 typeindex = NUM_EDIT_CLASSES - 1; 590 } 591 592 /* 593 ** Set current object 594 */ 595 LastChoice = TypeOffset[typeindex]; 596 curobj = Objects[LastChoice]; 597 display = true; 598 break; 599 600 /* 601 ** Jump to 1st choice 602 */ 603 case KN_HOME: 604 LastChoice = 0; 605 606 /* 607 ** Set current object 608 */ 609 curobj = Objects[LastChoice]; 610 display = true; 611 break; 612 613 /* 614 ** OK 615 */ 616 case (KN_RETURN): 617 case (BUTTON_OK | KN_BUTTON): 618 cancel = false; 619 process = false; 620 break; 621 622 /* 623 ** Cancel 624 */ 625 case (KN_ESC): 626 case (BUTTON_CANCEL | KN_BUTTON): 627 cancel = true; 628 process = false; 629 break; 630 631 default: 632 break; 633 } 634 635 } 636 637 /* 638 ** Redraw the display 639 */ 640 HidPage.Clear(); 641 Flag_To_Redraw(true); 642 Render(); 643 644 if (cancel) { 645 return(-1); 646 } 647 648 return(0); 649 } 650 651 652 /*************************************************************************** 653 * MapEditClass::Start_Placement -- enters placement mode * 654 * * 655 * INPUT: * 656 * none. * 657 * * 658 * OUTPUT: * 659 * none. * 660 * * 661 * WARNINGS: * 662 * none. * 663 * * 664 * HISTORY: * 665 * 11/04/1994 BR : Created. * 666 *=========================================================================*/ 667 void MapEditClass::Start_Placement(void) 668 { 669 670 /* 671 ** Initialize addable objects list; we must do this every time in case one 672 ** of the object pools has become exhausted; that object won't be available 673 ** for adding. These must be added in the same order expected by the 674 ** object selection dialog (same as button order). 675 */ 676 Clear_List(); 677 TemplateTypeClass::Prep_For_Add(); 678 OverlayTypeClass::Prep_For_Add(); 679 SmudgeTypeClass::Prep_For_Add(); 680 TerrainTypeClass::Prep_For_Add(); 681 UnitTypeClass::Prep_For_Add(); 682 InfantryTypeClass::Prep_For_Add(); 683 VesselTypeClass::Prep_For_Add(); 684 BuildingTypeClass::Prep_For_Add(); 685 AircraftTypeClass::Prep_For_Add(); 686 687 /* 688 ** Compute offset of each class type in the Objects array 689 */ 690 TypeOffset[0] = 0; 691 for (int i = 1; i < NUM_EDIT_CLASSES; i++) { 692 TypeOffset[i] = TypeOffset[i-1] + NumType[i-1]; 693 } 694 695 /* 696 ** Create the placement object: 697 ** - For normal placement mode, use the last-used index into Objects 698 ** (LastChoice), and the last-used house (LastHouse). 699 ** - For base-building mode, force the object to be a building, and use the 700 ** House specified in the Base object 701 */ 702 if (!BaseBuilding) { 703 if (LastChoice >= ObjCount) { 704 LastChoice = ObjCount - 1; 705 } 706 PendingObject = Objects[LastChoice]; 707 PendingHouse = LastHouse; 708 PendingObjectPtr = PendingObject->Create_One_Of(HouseClass::As_Pointer(LastHouse)); 709 } else { 710 if (LastChoice < TypeOffset[7]) { 711 LastChoice = TypeOffset[7]; 712 } 713 if (LastChoice >= ObjCount) { 714 LastChoice = ObjCount - 1; 715 } 716 PendingObject = Objects[LastChoice]; 717 PendingHouse = LastHouse = Base.House; 718 PendingObjectPtr = PendingObject->Create_One_Of(HouseClass::As_Pointer(LastHouse)); 719 } 720 721 /* 722 ** Error if no more objects available 723 */ 724 if (!PendingObjectPtr) { 725 WWMessageBox().Process("No more objects of this type available."); 726 HidPage.Clear(); 727 Flag_To_Redraw(true); 728 Render(); 729 PendingObject = NULL; 730 if (BaseBuilding) { 731 Cancel_Base_Building(); 732 } 733 return; 734 } 735 736 /* 737 ** Set the placement cursor 738 */ 739 Set_Cursor_Pos(); 740 Set_Cursor_Shape(PendingObject->Occupy_List()); 741 } 742 743 744 /*************************************************************************** 745 * MapEditClass::Place_Object -- attempts to place the current object * 746 * * 747 * Placement of "real" objects is simply checked via their Unlimbo routine.* 748 * Placement of templates is more complex: * 749 * - for every cell in the template's OccupyList, check for objects * 750 * already in that cell by looking at the cell's OccupyList & * 751 * OverlapList * 752 * - "lift" all the objects in the cell by Mark'ing them * 753 * - temporarily place the template in that cell * 754 * - try to Unlimbo all the objects that were in the cell. If any * 755 * objects fail to Unlimbo onto that template, the template cannot * 756 * be placed here * 757 * * 758 * It is assumed that the object being placed is a "new" object; the * 759 * object's strength & mission are not set during Unlimbo. * 760 * * 761 * INPUT: * 762 * none. * 763 * * 764 * OUTPUT: * 765 * 0 = OK, -1 = unable to place * 766 * * 767 * WARNINGS: * 768 * none. * 769 * * 770 * HISTORY: * 771 * 11/04/1994 BR : Created. * 772 *=========================================================================*/ 773 int MapEditClass::Place_Object(void) 774 { 775 CELL template_cell; // cell being checked for template 776 COORDINATE obj_coord; // coord of occupier object 777 int okflag; // OK to place a template? 778 short const * occupy; // ptr into template's OccupyList 779 ObjectClass * occupier; // occupying object 780 TemplateType save_ttype; // for saving cell's TType 781 unsigned char save_ticon; // for saving cell's TIcon 782 // BaseNodeClass node; // for adding to an AI Base 783 784 /* 785 ** Placing a template: 786 ** - first lift up any objects in the cell 787 ** - place the template, and try to replace the objects; if they won't go 788 ** back, the template can't go there 789 */ 790 //ScenarioInit++; 791 if (PendingObject->What_Am_I() == RTTI_TEMPLATETYPE) { 792 793 /* 794 ** Loop through all cells this template will occupy 795 */ 796 okflag = true; 797 occupy = PendingObject->Occupy_List(); 798 while ((*occupy) != REFRESH_EOL) { 799 800 /* 801 ** Check this cell for an occupier 802 */ 803 template_cell = (ZoneCell+ZoneOffset) + (*occupy); 804 if ((*this)[template_cell].Cell_Occupier()) { 805 occupier = (*this)[template_cell].Cell_Occupier(); 806 807 /* 808 ** Save object's coordinates 809 */ 810 obj_coord = occupier->Coord; 811 812 /* 813 ** Place the object in limbo 814 */ 815 occupier->Mark(MARK_UP); 816 817 /* 818 ** Set the cell's template values 819 */ 820 save_ttype = (*this)[template_cell].TType; 821 save_ticon = (*this)[template_cell].TIcon; 822 (*this)[template_cell].TType = 823 ((TemplateTypeClass *)PendingObject)->Type; 824 (*this)[template_cell].TIcon = Cell_X(*occupy) + Cell_Y(*occupy) * 825 ((TemplateTypeClass *)PendingObject)->Width; 826 (*this)[template_cell].Recalc_Attributes(); 827 828 /* 829 ** Try to put the object back down 830 */ 831 if (occupier->Can_Enter_Cell(Coord_Cell(obj_coord)) != MOVE_OK) { 832 okflag = false; 833 } 834 835 /* 836 ** Put everything back the way it was 837 */ 838 (*this)[template_cell].TType = save_ttype; 839 (*this)[template_cell].TIcon = save_ticon; 840 (*this)[template_cell].Recalc_Attributes(); 841 842 /* 843 ** Major error if can't replace the object now 844 */ 845 occupier->Mark(MARK_DOWN); 846 } 847 occupy++; 848 } 849 850 /* 851 ** If it's still OK after ALL THAT, place the template 852 */ 853 if (okflag) { 854 if (PendingObjectPtr->Unlimbo(Cell_Coord(ZoneCell + ZoneOffset))) { 855 856 /* 857 ** Loop through all cells occupied by this template, and clear the 858 ** smudge & overlay. 859 */ 860 occupy = PendingObject->Occupy_List(); 861 while ((*occupy) != REFRESH_EOL) { 862 863 /* 864 ** Get cell for this occupy item 865 */ 866 template_cell = (ZoneCell+ZoneOffset) + (*occupy); 867 868 /* 869 ** Clear smudge & overlay 870 */ 871 (*this)[template_cell].Overlay = OVERLAY_NONE; 872 (*this)[template_cell].OverlayData = 0; 873 (*this)[template_cell].Smudge = SMUDGE_NONE; 874 875 /* 876 ** make adjacent cells recalc attrib's 877 */ 878 (*this)[template_cell].Recalc_Attributes(); 879 (*this)[template_cell].Wall_Update(); 880 (*this)[template_cell].Concrete_Calc(); 881 882 occupy++; 883 } 884 885 /* 886 ** Set flags etc 887 */ 888 PendingObjectPtr = 0; 889 PendingObject = 0; 890 PendingHouse = HOUSE_NONE; 891 Set_Cursor_Shape(0); 892 //ScenarioInit--; 893 TotalValue = Overpass(); 894 Flag_To_Redraw(false); 895 return(0); 896 } 897 898 /* 899 ** Failure to deploy results in a returned failure code. 900 */ 901 //ScenarioInit--; 902 return(-1); 903 } 904 905 /* 906 ** Not OK; return error 907 */ 908 //ScenarioInit--; 909 return(-1); 910 } 911 912 /* 913 ** Placing infantry: Infantry can go into cell sub-positions, so find the 914 ** sub-position closest to the mouse & put him there 915 */ 916 if (PendingObject->What_Am_I() == RTTI_INFANTRYTYPE) { 917 918 /* 919 ** Find cell sub-position 920 */ 921 if (Is_Spot_Free(Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()))) { 922 obj_coord = Closest_Free_Spot(Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y())); 923 } else { 924 obj_coord = NULL; 925 } 926 927 /* 928 ** No free spots; don't place the object 929 */ 930 if (obj_coord == NULL) { 931 //ScenarioInit--; 932 return(-1); 933 } 934 935 /* 936 ** Unlimbo the object 937 */ 938 if (PendingObjectPtr->Unlimbo(obj_coord)) { 939 ((InfantryClass *)PendingObjectPtr)->Set_Occupy_Bit(obj_coord); 940 // Map[obj_coord].Flag.Composite |= 941 // (1 << CellClass::Spot_Index(obj_coord)); 942 PendingObjectPtr = 0; 943 PendingObject = 0; 944 PendingHouse = HOUSE_NONE; 945 Set_Cursor_Shape(0); 946 //ScenarioInit--; 947 return(0); 948 } 949 950 //ScenarioInit--; 951 return(-1); 952 } 953 954 /* 955 ** Placing an object 956 */ 957 if (PendingObjectPtr->Unlimbo(Cell_Coord(ZoneCell + ZoneOffset))) { 958 959 /* 960 ** Update the Tiberium computation if we're placing an overlay 961 */ 962 if (PendingObject->What_Am_I() == RTTI_OVERLAYTYPE && 963 ((OverlayTypeClass *)PendingObject)->IsTiberium) { 964 TotalValue = Overpass(); 965 Flag_To_Redraw(false); 966 } 967 968 /* 969 ** If we're building a base, add this building to the base's Node list. 970 */ 971 if (BaseBuilding && PendingObject->What_Am_I() == RTTI_BUILDINGTYPE) { 972 // node.Type = ((BuildingTypeClass *)PendingObject)->Type; 973 // node.Cell = Coord_Cell(PendingObjectPtr->Coord); 974 Base.Nodes.Add(BaseNodeClass(((BuildingTypeClass *)PendingObject)->Type, Coord_Cell(PendingObjectPtr->Coord))); 975 } 976 977 PendingObjectPtr = 0; 978 PendingObject = 0; 979 PendingHouse = HOUSE_NONE; 980 Set_Cursor_Shape(0); 981 //ScenarioInit--; 982 return(0); 983 } 984 985 return(-1); 986 } 987 988 989 /*************************************************************************** 990 * MapEditClass::Cancel_Placement -- cancels placement mode * 991 * * 992 * INPUT: * 993 * none. * 994 * * 995 * OUTPUT: * 996 * none. * 997 * * 998 * WARNINGS: * 999 * none. * 1000 * * 1001 * HISTORY: * 1002 * 11/04/1994 BR : Created. * 1003 *=========================================================================*/ 1004 void MapEditClass::Cancel_Placement(void) 1005 { 1006 /* 1007 ** Delete the placement object 1008 */ 1009 delete PendingObjectPtr; 1010 PendingObject = 0; 1011 PendingObjectPtr = 0; 1012 PendingHouse = HOUSE_NONE; 1013 1014 /* 1015 ** Restore cursor shape 1016 */ 1017 Set_Cursor_Shape(0); 1018 1019 /* 1020 ** Redraw the map to erase old leftovers 1021 */ 1022 HidPage.Clear(); 1023 Flag_To_Redraw(true); 1024 Render(); 1025 } 1026 1027 1028 /*************************************************************************** 1029 * MapEditClass::Place_Next -- while placing object, goes to next * 1030 * * 1031 * - Deletes the current 'PendingObjectPtr' * 1032 * - Increments LastChoice * 1033 * - Tries to create a new 'PendingObjectPtr'; if fails, keeps * 1034 * incrementing until it gets it * 1035 * * 1036 * INPUT: * 1037 * none. * 1038 * * 1039 * OUTPUT: * 1040 * none. * 1041 * * 1042 * WARNINGS: * 1043 * none. * 1044 * * 1045 * HISTORY: * 1046 * 11/03/1994 BR : Created. * 1047 *=========================================================================*/ 1048 void MapEditClass::Place_Next(void) 1049 { 1050 delete PendingObjectPtr; 1051 PendingObjectPtr = NULL; 1052 PendingObject = NULL; 1053 1054 /* 1055 ** Loop until we create a valid object 1056 */ 1057 while (!PendingObjectPtr) { 1058 /* 1059 ** Go to next object in Objects list 1060 */ 1061 LastChoice++; 1062 if (LastChoice == ObjCount) { 1063 1064 /* 1065 ** If we're in normal placement mode, wrap to the 1st object; 1066 ** if we're in base-building mode, wrap to the 1st building 1067 */ 1068 if (!BaseBuilding) { 1069 LastChoice = 0; 1070 } else { 1071 LastChoice = TypeOffset[7]; 1072 } 1073 } 1074 1075 /* 1076 ** Create placement object 1077 */ 1078 PendingObject = Objects[LastChoice]; 1079 PendingHouse = LastHouse; 1080 PendingObjectPtr = PendingObject->Create_One_Of(HouseClass::As_Pointer(PendingHouse)); 1081 if (!PendingObjectPtr) { 1082 PendingObject = NULL; 1083 } 1084 } 1085 1086 /* 1087 ** Set the new cursor shape 1088 */ 1089 Set_Cursor_Pos(); 1090 Set_Cursor_Shape(0); 1091 Set_Cursor_Shape(PendingObject->Occupy_List()); 1092 1093 /* 1094 ** Redraw the map to erase old leftovers 1095 */ 1096 HidPage.Clear(); 1097 Flag_To_Redraw(true); 1098 Render(); 1099 } 1100 1101 1102 /*************************************************************************** 1103 * MapEditClass::Place_Prev -- while placing object, goes to previous * 1104 * * 1105 * - Deletes the current 'PendingObjectPtr' * 1106 * - Decrements LastChoice * 1107 * - Tries to create a new 'PendingObjectPtr'; if fails, keeps * 1108 * decrementing until it gets it * 1109 * * 1110 * INPUT: * 1111 * none. * 1112 * * 1113 * OUTPUT: * 1114 * none. * 1115 * * 1116 * WARNINGS: * 1117 * none. * 1118 * * 1119 * HISTORY: * 1120 * 11/03/1994 BR : Created. * 1121 *=========================================================================*/ 1122 void MapEditClass::Place_Prev(void) 1123 { 1124 delete PendingObjectPtr; 1125 PendingObjectPtr = NULL; 1126 PendingObject = NULL; 1127 1128 /* 1129 ** Loop until we create a valid object 1130 */ 1131 while (!PendingObjectPtr) { 1132 1133 /* 1134 ** Go to prev object in Objects list 1135 */ 1136 LastChoice--; 1137 1138 /* 1139 ** If we're in normal placement mode, wrap at the 1st object. 1140 ** If we're building a base, wrap at the 1st building. 1141 */ 1142 if (!BaseBuilding) { 1143 if (LastChoice < 0) { 1144 LastChoice = ObjCount - 1; 1145 } 1146 } else { 1147 if (LastChoice < TypeOffset[7]) { 1148 LastChoice = ObjCount - 1; 1149 } 1150 } 1151 1152 /* 1153 ** Create placement object 1154 */ 1155 PendingObject = Objects[LastChoice]; 1156 PendingHouse = LastHouse; 1157 PendingObjectPtr = PendingObject->Create_One_Of(HouseClass::As_Pointer(PendingHouse)); 1158 if (!PendingObjectPtr) { 1159 PendingObject = NULL; 1160 } 1161 } 1162 1163 /* 1164 ** Set the new cursor shape 1165 */ 1166 Set_Cursor_Pos(); 1167 Set_Cursor_Shape(0); 1168 Set_Cursor_Shape(PendingObject->Occupy_List()); 1169 1170 /* 1171 ** Redraw the map to erase old leftovers 1172 */ 1173 HidPage.Clear(); 1174 Flag_To_Redraw(true); 1175 Render(); 1176 } 1177 1178 1179 /*************************************************************************** 1180 * MapEditClass::Place_Next_Category -- places next category of object * 1181 * * 1182 * INPUT: * 1183 * none. * 1184 * * 1185 * OUTPUT: * 1186 * none. * 1187 * * 1188 * WARNINGS: * 1189 * none. * 1190 * * 1191 * HISTORY: * 1192 * 11/03/1994 BR : Created. * 1193 *=========================================================================*/ 1194 void MapEditClass::Place_Next_Category(void) 1195 { 1196 int i; 1197 1198 /* 1199 ** Don't allow this command if we're building a base; the only valid 1200 ** category for base-building is buildings. 1201 */ 1202 if (BaseBuilding) { 1203 return; 1204 } 1205 1206 delete PendingObjectPtr; 1207 PendingObjectPtr = NULL; 1208 PendingObject = NULL; 1209 1210 /* 1211 ** Go to next category in Objects list 1212 */ 1213 i = LastChoice; 1214 while (Objects[i]->What_Am_I() == Objects[LastChoice]->What_Am_I()) { 1215 i++; 1216 if (i == ObjCount) { 1217 i = 0; 1218 } 1219 } 1220 LastChoice = i; 1221 1222 /* 1223 ** Loop until we create a valid object 1224 */ 1225 while (!PendingObjectPtr) { 1226 1227 /* 1228 ** Get house for this object type 1229 */ 1230 // if (!Verify_House(LastHouse, Objects[LastChoice])) { 1231 // LastHouse = Cycle_House(LastHouse, Objects[LastChoice]); 1232 // } 1233 1234 /* 1235 ** Create placement object 1236 */ 1237 PendingObject = Objects[LastChoice]; 1238 PendingHouse = LastHouse; 1239 PendingObjectPtr = PendingObject->Create_One_Of(HouseClass::As_Pointer(PendingHouse)); 1240 1241 /* 1242 ** If this one failed, try the next 1243 */ 1244 if (!PendingObjectPtr) { 1245 PendingObject = NULL; 1246 LastChoice++; 1247 if (LastChoice == ObjCount) { 1248 LastChoice = 0; 1249 } 1250 } 1251 } 1252 1253 /* 1254 ** Set the new cursor shape 1255 */ 1256 Set_Cursor_Pos(); 1257 Set_Cursor_Shape(0); 1258 Set_Cursor_Shape(PendingObject->Occupy_List()); 1259 1260 /* 1261 ** Redraw the map to erase old leftovers 1262 */ 1263 HidPage.Clear(); 1264 Flag_To_Redraw(true); 1265 Render(); 1266 } 1267 1268 1269 /*************************************************************************** 1270 * MapEditClass::Place_Prev_Category -- places previous category of object * 1271 * * 1272 * INPUT: * 1273 * none. * 1274 * * 1275 * OUTPUT: * 1276 * none. * 1277 * * 1278 * WARNINGS: * 1279 * none. * 1280 * * 1281 * HISTORY: * 1282 * 11/03/1994 BR : Created. * 1283 *=========================================================================*/ 1284 void MapEditClass::Place_Prev_Category(void) 1285 { 1286 int i; 1287 1288 /* 1289 ** Don't allow this command if we're building a base; the only valid 1290 ** category for base-building is buildings. 1291 */ 1292 if (BaseBuilding) { 1293 return; 1294 } 1295 1296 delete PendingObjectPtr; 1297 PendingObjectPtr = NULL; 1298 PendingObject = NULL; 1299 1300 /* 1301 ** Go to prev category in Objects list 1302 */ 1303 i = LastChoice; 1304 1305 /* 1306 ** Scan for start of this category 1307 */ 1308 while (Objects[i]->What_Am_I() == Objects[LastChoice]->What_Am_I()) { 1309 i--; 1310 if (i < 0) { 1311 i = ObjCount - 1; 1312 } 1313 } 1314 1315 i--; 1316 if (i < 0) i = ObjCount-1; 1317 LastChoice = i; 1318 1319 /* 1320 ** Scan for the previous category 1321 */ 1322 while (Objects[i]->What_Am_I() == Objects[LastChoice]->What_Am_I()) { 1323 i--; 1324 if (i < 0) { 1325 i = ObjCount - 1; 1326 } 1327 } 1328 1329 i++; 1330 if (i >= ObjCount) i = 0; 1331 LastChoice = i; 1332 1333 /* 1334 ** Loop until we create a valid object 1335 */ 1336 while (!PendingObjectPtr) { 1337 1338 /* 1339 ** Get house for this object type 1340 */ 1341 // if (!Verify_House(LastHouse, Objects[LastChoice])) { 1342 // LastHouse = Cycle_House(LastHouse, Objects[LastChoice]); 1343 // } 1344 1345 /* 1346 ** Create placement object 1347 */ 1348 PendingObject = Objects[LastChoice]; 1349 PendingHouse = LastHouse; 1350 PendingObjectPtr = PendingObject->Create_One_Of(HouseClass::As_Pointer(PendingHouse)); 1351 1352 /* 1353 ** If this one failed, try the next 1354 */ 1355 if (!PendingObjectPtr) { 1356 PendingObject = NULL; 1357 LastChoice--; 1358 if (LastChoice < 0) { 1359 LastChoice = ObjCount - 1; 1360 } 1361 } 1362 } 1363 1364 /* 1365 ** Set the new cursor shape 1366 */ 1367 Set_Cursor_Pos(); 1368 Set_Cursor_Shape(0); 1369 Set_Cursor_Shape(PendingObject->Occupy_List()); 1370 1371 /* 1372 ** Redraw the map to erase old leftovers 1373 */ 1374 HidPage.Clear(); 1375 Flag_To_Redraw(true); 1376 Render(); 1377 } 1378 1379 1380 /*************************************************************************** 1381 * MapEditClass::Place_Home -- homes the placement object * 1382 * * 1383 * INPUT: * 1384 * none. * 1385 * * 1386 * OUTPUT: * 1387 * none. * 1388 * * 1389 * WARNINGS: * 1390 * none. * 1391 * * 1392 * HISTORY: * 1393 * 11/03/1994 BR : Created. * 1394 *=========================================================================*/ 1395 void MapEditClass::Place_Home(void) 1396 { 1397 delete PendingObjectPtr; 1398 PendingObjectPtr = NULL; 1399 PendingObject = NULL; 1400 1401 /* 1402 ** Don't allow this command if we're building a base; the only valid 1403 ** category for base-building is buildings. 1404 */ 1405 if (BaseBuilding) { 1406 return; 1407 } 1408 1409 /* 1410 ** Loop until we create a valid object 1411 */ 1412 LastChoice = 0; 1413 while (!PendingObjectPtr) { 1414 1415 /* 1416 ** Get house for this object type 1417 */ 1418 if (!Verify_House(LastHouse, Objects[LastChoice])) { 1419 LastHouse = Cycle_House(LastHouse, Objects[LastChoice]); 1420 } 1421 1422 /* 1423 ** Create placement object 1424 */ 1425 PendingObject = Objects[LastChoice]; 1426 PendingHouse = LastHouse; 1427 PendingObjectPtr = PendingObject->Create_One_Of(HouseClass::As_Pointer(PendingHouse)); 1428 1429 /* 1430 ** If this one failed, try the next 1431 */ 1432 if (!PendingObjectPtr) { 1433 PendingObject = NULL; 1434 LastChoice++; 1435 if (LastChoice == ObjCount) { 1436 LastChoice = 0; 1437 } 1438 } 1439 } 1440 1441 /* 1442 ** Set the new cursor shape 1443 */ 1444 Set_Cursor_Pos(); 1445 Set_Cursor_Shape(0); 1446 Set_Cursor_Shape(PendingObject->Occupy_List()); 1447 1448 /* 1449 ** Redraw the map to erase old leftovers 1450 */ 1451 HidPage.Clear(); 1452 Flag_To_Redraw(true); 1453 Render(); 1454 } 1455 1456 1457 /*************************************************************************** 1458 * MapEditClass::Toggle_House -- toggles current placement object's house * 1459 * * 1460 * INPUT: * 1461 * * 1462 * OUTPUT: * 1463 * * 1464 * WARNINGS: * 1465 * * 1466 * HISTORY: * 1467 * 11/04/1994 BR : Created. * 1468 *=========================================================================*/ 1469 void MapEditClass::Toggle_House(void) 1470 { 1471 TechnoClass *tp; 1472 1473 /* 1474 ** Don't allow this command if we're building a base; the only valid 1475 ** house for base-building is the one assigned to the base. 1476 */ 1477 if (BaseBuilding) { 1478 return; 1479 } 1480 1481 /* 1482 ** Only techno objects can be owned by a house; return if not a techno 1483 */ 1484 if (!PendingObjectPtr->Is_Techno()) { 1485 return; 1486 } 1487 1488 /* 1489 ** Select the house that will own this object 1490 */ 1491 LastHouse = Cycle_House(PendingObjectPtr->Owner(), PendingObject); 1492 1493 /* 1494 ** Change the house 1495 */ 1496 tp = (TechnoClass *)PendingObjectPtr; 1497 tp->House = HouseClass::As_Pointer(LastHouse); 1498 1499 /* 1500 ** Set house variables to new house 1501 */ 1502 PendingHouse = LastHouse; 1503 } 1504 1505 1506 /*************************************************************************** 1507 * MapEditClass::Set_House_Buttons -- toggles house buttons for btn list * 1508 * * 1509 * Looks in the given button list for the given GDI, NOD & Neutral button * 1510 * id's. Sets the On/Off state of the buttons based on the given house, * 1511 * only if that button is found in the list. * 1512 * * 1513 * INPUT: * 1514 * house house to set buttons to * 1515 * btnlist ptr to button list to search * 1516 * base_id button ID for GDI; assumes other id's are sequential* 1517 * * 1518 * OUTPUT: * 1519 * none. * 1520 * * 1521 * WARNINGS: * 1522 * none. * 1523 * * 1524 * HISTORY: * 1525 * 11/23/1994 BR : Created. * 1526 * 01/26/1996 JLB : Uses new house selection list method. * 1527 *=========================================================================*/ 1528 void MapEditClass::Set_House_Buttons(HousesType house, GadgetClass *, int ) 1529 //void MapEditClass::Set_House_Buttons(HousesType house, GadgetClass * btnlist, int base_id) 1530 { 1531 HouseList->Set_Selected_Index(house); 1532 1533 #ifdef NEVER 1534 HousesType h; 1535 int id; 1536 TextButtonClass * btn; 1537 1538 /* 1539 ** Loop through all houses, searching the button list for each one. 1540 */ 1541 for (h = HOUSE_FIRST; h < HOUSE_COUNT; h++) { 1542 1543 /* 1544 ** Compute the desired button ID; get a pointer to the button 1545 */ 1546 id = (int)h + base_id; 1547 btn = (TextButtonClass *)btnlist->Extract_Gadget(id); 1548 if (btn) { 1549 1550 /* 1551 ** If this house value is the desired one, turn the button on; 1552 ** otherwise, turn it off. 1553 */ 1554 if (h == house) { 1555 btn->Turn_On(); 1556 } else { 1557 btn->Turn_Off(); 1558 } 1559 } 1560 } 1561 #endif 1562 } 1563 1564 1565 /*************************************************************************** 1566 * MapEditClass::Start_Trigger_Placement -- enters trigger placement mode * 1567 * * 1568 * INPUT: * 1569 * * 1570 * OUTPUT: * 1571 * * 1572 * WARNINGS: * 1573 * * 1574 * HISTORY: * 1575 * 12/01/1994 BR : Created. * 1576 *=========================================================================*/ 1577 void MapEditClass::Start_Trigger_Placement(void) 1578 { 1579 Set_Default_Mouse(MOUSE_CAN_MOVE); 1580 Override_Mouse_Shape(MOUSE_CAN_MOVE); 1581 } 1582 1583 1584 /*************************************************************************** 1585 * MapEditClass::Stop_Trigger_Placement -- exits trigger placement mode * 1586 * * 1587 * INPUT: * 1588 * none. * 1589 * * 1590 * OUTPUT: * 1591 * none. * 1592 * * 1593 * WARNINGS: * 1594 * none. * 1595 * * 1596 * HISTORY: * 1597 * 12/01/1994 BR : Created. * 1598 *=========================================================================*/ 1599 void MapEditClass::Stop_Trigger_Placement(void) 1600 { 1601 CurTrigger = NULL; 1602 Set_Default_Mouse(MOUSE_NORMAL); 1603 Override_Mouse_Shape(MOUSE_NORMAL); 1604 } 1605 1606 1607 /*************************************************************************** 1608 * MapEditClass::Place_Trigger -- assigns trigger to object or cell * 1609 * * 1610 * INPUT: * 1611 * none. * 1612 * * 1613 * OUTPUT: * 1614 * none. * 1615 * * 1616 * WARNINGS: * 1617 * none. * 1618 * * 1619 * HISTORY: * 1620 * 12/01/1994 BR : Created. * 1621 *=========================================================================*/ 1622 void MapEditClass::Place_Trigger(void) 1623 { 1624 ObjectClass * object=NULL; // Generic object clicked on. 1625 int x,y; 1626 CELL cell; // Cell that was selected. 1627 1628 /* 1629 ** See if an object was clicked on 1630 */ 1631 x = Keyboard->MouseQX; 1632 y = Keyboard->MouseQY; 1633 1634 /* 1635 ** Get cell for x,y 1636 */ 1637 cell = Click_Cell_Calc(x, y); 1638 1639 /* 1640 ** Convert x,y to offset from cell upper-left 1641 */ 1642 x = (x-TacPixelX) % ICON_PIXEL_W; 1643 y = (y-TacPixelY) % ICON_PIXEL_H; 1644 1645 /* 1646 ** Get object at that x,y 1647 */ 1648 object = Cell_Object(cell, x, y); 1649 1650 /* 1651 ** Assign trigger to an object 1652 */ 1653 AttachType a1 = CurTrigger->Attaches_To(); 1654 if (object && (a1 & ATTACH_OBJECT) != 0) { 1655 if (CurTrigger) { 1656 TriggerClass * tt = Find_Or_Make(CurTrigger); 1657 if (tt) { 1658 object->Trigger = tt; 1659 } 1660 } 1661 } else { 1662 1663 /* 1664 ** Assign trigger to a cell 1665 */ 1666 if ((a1 & ATTACH_CELL) != 0) { 1667 if (CurTrigger) { 1668 TriggerClass * tt = Find_Or_Make(CurTrigger); 1669 Map[cell].Trigger = tt; 1670 } 1671 // CellTriggers[cell] = CurTrigger; 1672 } 1673 } 1674 1675 /* 1676 ** Force map to redraw 1677 */ 1678 HidPage.Clear(); 1679 Flag_To_Redraw(true); 1680 } 1681 1682 1683 /*************************************************************************** 1684 * MapEditClass::Start_Base_Building -- starts base-building mode * 1685 * * 1686 * INPUT: * 1687 * none. * 1688 * * 1689 * OUTPUT: * 1690 * none. * 1691 * * 1692 * WARNINGS: * 1693 * none. * 1694 * * 1695 * HISTORY: * 1696 * 12/01/1994 BR : Created. * 1697 *=========================================================================*/ 1698 void MapEditClass::Start_Base_Building(void) 1699 { 1700 /* 1701 ** Fully build the base so the user can edit it 1702 */ 1703 Build_Base_To(100); 1704 1705 /* 1706 ** Start placement mode 1707 */ 1708 BaseBuilding = true; 1709 Start_Placement(); 1710 1711 /* 1712 ** Force map to redraw 1713 */ 1714 HidPage.Clear(); 1715 Flag_To_Redraw(true); 1716 } 1717 1718 1719 /*************************************************************************** 1720 * MapEditClass::Cancel_Base_Building -- stops base-building mode * 1721 * * 1722 * INPUT: * 1723 * none. * 1724 * * 1725 * OUTPUT: * 1726 * none. * 1727 * * 1728 * WARNINGS: * 1729 * none. * 1730 * * 1731 * HISTORY: * 1732 * 12/01/1994 BR : Created. * 1733 *=========================================================================*/ 1734 void MapEditClass::Cancel_Base_Building(void) 1735 { 1736 /* 1737 ** Build the base to the proper amount 1738 */ 1739 Build_Base_To(Scen.Percent); 1740 1741 /* 1742 ** Cancel placement mode 1743 */ 1744 Cancel_Placement(); 1745 BaseBuilding = false; 1746 1747 /* 1748 ** Force map to redraw 1749 */ 1750 HidPage.Clear(); 1751 Flag_To_Redraw(true); 1752 } 1753 1754 1755 /*************************************************************************** 1756 * MapEditClass::Build_Base_To -- builds the AI base to the given percent * 1757 * * 1758 * INPUT: * 1759 * percent percentage to build base to * 1760 * * 1761 * OUTPUT: * 1762 * none. * 1763 * * 1764 * WARNINGS: * 1765 * none. * 1766 * * 1767 * HISTORY: * 1768 * 12/01/1994 BR : Created. * 1769 *=========================================================================*/ 1770 void MapEditClass::Build_Base_To(int percent) 1771 { 1772 int i; 1773 int num_buildings; 1774 BuildingTypeClass const * objtype; 1775 BuildingClass * obj; 1776 1777 //ScenarioInit++; 1778 1779 /* 1780 ** Completely dismantle the base, so we start at a known point 1781 */ 1782 for (i = 0; i < Base.Nodes.Count(); i++) { 1783 if (Base.Is_Built(i)) { 1784 obj = Base.Get_Building(i); 1785 delete obj; 1786 } 1787 } 1788 1789 /* 1790 ** Compute number of buildings to build 1791 */ 1792 num_buildings = (Base.Nodes.Count() * percent) / 100; 1793 1794 /* 1795 ** Build the base to the desired amount 1796 */ 1797 for (i = 0; i < num_buildings; i++) { 1798 /* 1799 ** Get a ptr to the type of building to build, create one, and unlimbo it. 1800 */ 1801 objtype = &BuildingTypeClass::As_Reference(Base.Nodes[i].Type); 1802 obj = (BuildingClass *)objtype->Create_One_Of(HouseClass::As_Pointer(Base.House)); 1803 1804 /* 1805 ** If unlimbo fails, error out 1806 */ 1807 ScenarioInit++; 1808 if (!obj->Unlimbo(Cell_Coord(Base.Nodes[i].Cell))) { 1809 delete obj; 1810 WWMessageBox().Process("Unable to build base!"); 1811 ScenarioInit--; 1812 return; 1813 } 1814 ScenarioInit--; 1815 } 1816 1817 //ScenarioInit--; 1818 } 1819 1820 1821 #endif