MAPEDIT.CPP (70638B)
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\mapedit.cpv 2.18 16 Oct 1995 16:48:40 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 : MAPEDIT.CPP * 24 * * 25 * Programmer : Bill Randolph * 26 * * 27 * Start Date : October 20, 1994 * 28 * * 29 * Last Update : February 2, 1995 [BR] * 30 * * 31 *-------------------------------------------------------------------------* 32 * Map Editor overloaded routines & utility routines * 33 *-------------------------------------------------------------------------* 34 * Map Editor modules: * 35 * (Yes, they're all one huge class.) * 36 * mapedit.cpp: overloaded routines, utility routines * 37 * mapeddlg.cpp: map editor dialogs, most of the main menu options * 38 * mapedplc.cpp: object-placing routines * 39 * mapedsel.cpp: object-selection & manipulation routines * 40 * mapedtm.cpp: team-editing routines * 41 *-------------------------------------------------------------------------* 42 * Functions: * 43 * MapEditClass::MapEditClass -- class constructor * 44 * MapEditClass::One_Time -- one-time initialization * 45 * MapEditClass::Read_INI -- overloaded Read_INI function * 46 * MapEditClass::Clear_List -- clears the internal choosable object list * 47 * MapEditClass::Add_To_List -- adds a TypeClass to the choosable list * 48 * MapEditClass::AI -- The map editor's main logic * 49 * MapEditClass::Draw_It -- overloaded Redraw routine * 50 * MapEditClass::Main_Menu -- main menu processor for map editor * 51 * MapEditClass::AI_Menu -- menu of AI options * 52 * MapEditClass::Mouse_Moved -- checks for mouse motion * 53 * MapEditClass::Verify_House -- sees if given house can own given obj * 54 * MapEditClass::Cycle_House -- finds next valid house for object type * 55 * MapEditClass::Trigger_Needs_Team -- tells if a trigger needs a team * 56 * MapEditClass::Fatal -- exits with error message * 57 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 58 59 #include "function.h" 60 61 #ifdef SCENARIO_EDITOR 62 63 /* 64 ****************************** Globals/Externs ****************************** 65 */ 66 /*........................................................................... 67 Array of all missions supported by the map editor 68 ...........................................................................*/ 69 MissionType MapEditClass::MapEditMissions[] = { 70 MISSION_GUARD, 71 MISSION_STICKY, 72 MISSION_HARVEST, 73 MISSION_GUARD_AREA, 74 MISSION_RETURN, 75 MISSION_AMBUSH, 76 MISSION_HUNT, 77 MISSION_SLEEP, 78 }; 79 #define NUM_EDIT_MISSIONS (sizeof(MapEditClass::MapEditMissions) / sizeof(MapEditClass::MapEditMissions[0])) 80 81 82 /*........................................................................... 83 For menu processing 84 ...........................................................................*/ 85 extern int UnknownKey; // in menus.cpp 86 87 char MapEditClass::HealthBuf[20]; 88 89 90 /*************************************************************************** 91 * MapEditClass::MapEditClass -- class constructor * 92 * * 93 * INPUT: * 94 * none. * 95 * * 96 * OUTPUT: * 97 * none. * 98 * * 99 * WARNINGS: * 100 * none. * 101 * * 102 * HISTORY: * 103 * 10/20/1994 BR : Created. * 104 *=========================================================================*/ 105 MapEditClass::MapEditClass(void) 106 { 107 /* 108 ** Init data members. 109 */ 110 ScenVar = SCEN_VAR_A; 111 ObjCount = 0; 112 LastChoice = 0; 113 LastHouse = HOUSE_GOOD; 114 GrabbedObject = 0; 115 for (int i=0; i < NUM_EDIT_CLASSES; i++) { 116 NumType[i] = 0; 117 TypeOffset[i] = 0; 118 } 119 Waypoint[WAYPT_HOME] = 0; 120 CurrentCell = 0; 121 CurTrigger = NULL; 122 Changed = 0; 123 LMouseDown = 0; 124 BaseBuilding = 0; 125 BasePercent = 100; 126 } 127 128 129 /*************************************************************************** 130 * MapEditClass::One_Time -- one-time initialization * 131 * * 132 * INPUT: * 133 * none. * 134 * * 135 * OUTPUT: * 136 * none. * 137 * * 138 * WARNINGS: * 139 * none. * 140 * * 141 * HISTORY: * 142 * 02/02/1995 BR : Created. * 143 *=========================================================================*/ 144 void MapEditClass::One_Time(void) 145 { 146 MouseClass::One_Time(); 147 148 /*------------------------------------------------------------------------ 149 Create the pop-up controls 150 ------------------------------------------------------------------------*/ 151 /*........................................................................ 152 The map: a single large "button" 153 ........................................................................*/ 154 //MapArea = new ControlClass(MAP_AREA,0,8,312,192, GadgetClass::LEFTPRESS | 155 //GadgetClass::LEFTRELEASE, false); 156 MapArea = new ControlClass(MAP_AREA,0,16,624,384, GadgetClass::LEFTPRESS | 157 GadgetClass::LEFTRELEASE, false); 158 159 /*........................................................................ 160 House buttons 161 ........................................................................*/ 162 GDIButton = new TextButtonClass (POPUP_GDI, "GDI", 163 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 164 POPUP_GDI_X, POPUP_GDI_Y, POPUP_GDI_W, POPUP_GDI_H); 165 166 NODButton = new TextButtonClass (POPUP_NOD, "NOD", 167 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 168 POPUP_NOD_X, POPUP_NOD_Y, POPUP_NOD_W, POPUP_NOD_H); 169 170 NeutralButton = new TextButtonClass (POPUP_NEUTRAL, "Neutral", 171 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 172 POPUP_NEUTRAL_X, POPUP_NEUTRAL_Y, POPUP_NEUTRAL_W, POPUP_NEUTRAL_H); 173 174 Multi1Button = new TextButtonClass (POPUP_MULTI1, "M1", 175 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 176 POPUP_MULTI1_X, POPUP_MULTI1_Y, POPUP_MULTI1_W, POPUP_MULTI1_H); 177 178 Multi2Button = new TextButtonClass (POPUP_MULTI2, "M2", 179 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 180 POPUP_MULTI2_X, POPUP_MULTI2_Y, POPUP_MULTI2_W, POPUP_MULTI2_H); 181 182 Multi3Button = new TextButtonClass (POPUP_MULTI3, "M3", 183 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 184 POPUP_MULTI3_X, POPUP_MULTI3_Y, POPUP_MULTI3_W, POPUP_MULTI3_H); 185 186 Multi4Button = new TextButtonClass (POPUP_MULTI4, "M4", 187 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 188 POPUP_MULTI4_X, POPUP_MULTI4_Y, POPUP_MULTI4_W, POPUP_MULTI4_H); 189 190 /*........................................................................ 191 The mission list box 192 ........................................................................*/ 193 MissionList = new ListClass (POPUP_MISSIONLIST, 194 POPUP_MISSION_X, POPUP_MISSION_Y, POPUP_MISSION_W, POPUP_MISSION_H, 195 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 196 Hires_Retrieve("BTN-UP.SHP"), 197 Hires_Retrieve("BTN-DN.SHP")); 198 199 for (int i = 0; i < NUM_EDIT_MISSIONS; i++) { 200 MissionList->Add_Item (MissionClass::Mission_Name(MapEditMissions[i])); 201 } 202 203 /*........................................................................ 204 The health bar 205 ........................................................................*/ 206 HealthGauge = new TriColorGaugeClass (POPUP_HEALTHGAUGE, 207 POPUP_HEALTH_X, POPUP_HEALTH_Y, POPUP_HEALTH_W, POPUP_HEALTH_H); 208 HealthGauge->Use_Thumb(true); 209 HealthGauge->Set_Maximum(0x100); 210 HealthGauge->Set_Red_Limit(0x3f - 1); 211 HealthGauge->Set_Yellow_Limit(0x7f - 1); 212 213 /*........................................................................ 214 The health text label 215 ........................................................................*/ 216 HealthBuf[0] = 0; 217 HealthText = new TextLabelClass (HealthBuf, 218 POPUP_HEALTH_X + POPUP_HEALTH_W / 2, 219 POPUP_HEALTH_Y + POPUP_HEALTH_H + 1, 220 CC_GREEN, TPF_CENTER | TPF_FULLSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL); 221 222 /*........................................................................ 223 The facing dial 224 ........................................................................*/ 225 FacingDial = new Dial8Class (POPUP_FACINGDIAL, POPUP_FACEBOX_X, 226 POPUP_FACEBOX_Y, POPUP_FACEBOX_W, POPUP_FACEBOX_H, (DirType)0); 227 228 /*........................................................................ 229 The base percent-built slider & its label 230 ........................................................................*/ 231 BaseGauge = new GaugeClass (POPUP_BASEPERCENT, 232 POPUP_BASE_X, POPUP_BASE_Y, POPUP_BASE_W, POPUP_BASE_H); 233 BaseLabel = new TextLabelClass ("Base:", POPUP_BASE_X - 3, POPUP_BASE_Y, 234 CC_GREEN, TPF_RIGHT | TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL); 235 BaseGauge->Set_Maximum(100); 236 BaseGauge->Set_Value(BasePercent); 237 } 238 239 240 /*********************************************************************************************** 241 * MapeditClass::Init_IO -- Reinitializes the radar map at scenario start. * 242 * * 243 * INPUT: none * 244 * * 245 * OUTPUT: none * 246 * * 247 * WARNINGS: none * 248 * * 249 * HISTORY: * 250 * 12/22/1994 JLB : Created. * 251 *=============================================================================================*/ 252 void MapEditClass::Init_IO(void) 253 { 254 /*------------------------------------------------------------------------ 255 For normal game mode, jump to the parent's Init routine. 256 ------------------------------------------------------------------------*/ 257 if (!Debug_Map) { 258 259 MouseClass::Init_IO(); 260 261 } else { 262 263 /*------------------------------------------------------------------------ 264 For editor mode, add the map area to the button input list 265 ------------------------------------------------------------------------*/ 266 Buttons = 0; 267 Add_A_Button(*BaseGauge); 268 Add_A_Button(*BaseLabel); 269 Add_A_Button(*MapArea); 270 } 271 } 272 273 274 /*************************************************************************** 275 * MapEditClass::Read_INI -- overloaded Read_INI function * 276 * * 277 * Overloading this function gives the map editor a chance to initialize * 278 * certain values every time a new INI is read. * 279 * * 280 * INPUT: * 281 * buffer INI staging area * 282 * * 283 * OUTPUT: * 284 * none. * 285 * * 286 * WARNINGS: * 287 * none. * 288 * * 289 * HISTORY: * 290 * 11/16/1994 BR : Created. * 291 *=========================================================================*/ 292 void MapEditClass::Read_INI(char *buffer) 293 { 294 /* 295 ------------------------ Invoke parent's Read_INI ------------------------ 296 */ 297 MouseClass::Read_INI(buffer); 298 299 BasePercent = WWGetPrivateProfileInt("Basic","Percent",0,buffer); 300 BaseGauge->Set_Value(BasePercent); 301 } 302 303 304 /*************************************************************************** 305 * MapEditClass::Write_INI -- overloaded Read_INI function * 306 * * 307 * INPUT: * 308 * buffer INI staging area * 309 * * 310 * OUTPUT: * 311 * none. * 312 * * 313 * WARNINGS: * 314 * none. * 315 * * 316 * HISTORY: * 317 * 11/16/1994 BR : Created. * 318 *=========================================================================*/ 319 void MapEditClass::Write_INI(char *buffer) 320 { 321 /* 322 ----------------------- Invoke parent's Write_INI ------------------------ 323 */ 324 MouseClass::Write_INI(buffer); 325 326 /* 327 ** Save the base's percent-built value; this must be saved into the BASIC 328 ** section of the INI, since the Base section will be entirely erased 329 ** by the Base's Write_INI routine. 330 */ 331 WWWritePrivateProfileInt("Basic", "Percent", BasePercent, buffer); 332 } 333 334 335 /*************************************************************************** 336 * MapEditClass::Clear_List -- clears the internal choosable object list * 337 * * 338 * INPUT: * 339 * none. * 340 * * 341 * OUTPUT: * 342 * none. * 343 * * 344 * WARNINGS: * 345 * none. * 346 * * 347 * HISTORY: * 348 * 10/20/1994 BR : Created. * 349 *=========================================================================*/ 350 void MapEditClass::Clear_List(void) 351 { 352 /*------------------------------------------------------------------------ 353 Set # object type ptrs to 0, set NumType for each type to 0 354 ------------------------------------------------------------------------*/ 355 ObjCount = 0; 356 for (int i = 0; i < NUM_EDIT_CLASSES; i++) { 357 NumType[i] = 0; 358 } 359 } 360 361 362 /*************************************************************************** 363 * MapEditClass::Add_To_List -- adds a TypeClass to the choosable list * 364 * * 365 * Use this routine to add an object to the game object selection list. * 366 * This list is used by the Add_Object function. All items located in the * 367 * list will appear and be chooseable by that function. Make sure to * 368 * clear the list before adding a sequence of items to it. Clearing * 369 * the list is accomplished by the Clear_List() function. * 370 * * 371 * INPUT: * 372 * object ptr to ObjectTypeClass to add * 373 * * 374 * OUTPUT: * 375 * bool: was the object added to the list? A failure could occur if * 376 * NULL were passed in or the list is full. * 377 * * 378 * WARNINGS: * 379 * none. * 380 * * 381 * HISTORY: * 382 * 06/04/1994 JLB : Created. * 383 *=========================================================================*/ 384 bool MapEditClass::Add_To_List(ObjectTypeClass const *object) 385 { 386 /* 387 ** Add the object if there's room. 388 */ 389 if (object && ObjCount < MAX_EDIT_OBJECTS) { 390 Objects[ObjCount++] = object; 391 392 /* 393 ** Update type counters. 394 */ 395 switch (object->What_Am_I()) { 396 case RTTI_TEMPLATETYPE: 397 NumType[0]++; 398 break; 399 400 case RTTI_OVERLAYTYPE: 401 NumType[1]++; 402 break; 403 404 case RTTI_SMUDGETYPE: 405 NumType[2]++; 406 break; 407 408 case RTTI_TERRAINTYPE: 409 NumType[3]++; 410 break; 411 412 case RTTI_UNITTYPE: 413 NumType[4]++; 414 break; 415 416 case RTTI_INFANTRYTYPE: 417 NumType[5]++; 418 break; 419 420 case RTTI_AIRCRAFTTYPE: 421 NumType[6]++; 422 break; 423 424 case RTTI_BUILDINGTYPE: 425 NumType[7]++; 426 break; 427 } 428 return(true); 429 } 430 431 return(false); 432 } 433 434 435 /*************************************************************************** 436 * MapEditClass::AI -- The map editor's main logic * 437 * * 438 * This routine overloads the parent's (DisplayClass) AI function. * 439 * It checks for any input specific to map editing, and calls the parent * 440 * AI routine to handle scrolling and other mainstream map stuff. * 441 * * 442 * If this detects one of its special input keys, it sets 'input' to 0 * 443 * before calling the parent AI routine; this prevents input conflict. * 444 * * 445 * SUPPORTED INPUT: * 446 * General: * 447 * F2/RMOUSE: main menu * 448 * F6: toggles show-passable mode * 449 * HOME: go to the Home Cell (scenario's start position)* 450 * SHIFT-HOME: set the Home Cell to the current TacticalCell* 451 * ESC: exits to DOS * 452 * Object Placement: * 453 * INSERT: go into placement mode * 454 * ESC: exit placement mode * 455 * LEFT/RIGHT: prev/next placement object * 456 * PGUP/PGDN: prev/next placement category * 457 * HOME: 1st placement object (clear template) * 458 * h/H: toggle house of placement object * 459 * LMOUSE: place the placement object * 460 * MOUSE MOTION: "paint" with the placement object * 461 * Object selection: * 462 * LMOUSE: select & "grab" current object * 463 * If no object is present where the mouse is * 464 * clicked, the current object is de-selected * 465 * If the same object is clicked on, it stays * 466 * selected. Also displays the object-editing * 467 * gadgets. * 468 * LMOUSE RLSE: release currently-grabbed object * 469 * MOUSE MOTION: if an object is grabbed, moves the object * 470 * SHIFT|ALT|ARROW: moves object in that direction * 471 * DELETE deletes currently-selected object * 472 * Object-editing controls: * 473 * POPUP_GDI: makes GDI the owner of this object * 474 * POPUP_NOD: makes NOD the owner of this object * 475 * POPUP_MISSIONLIST: sets that mission for this object * 476 * POPUP_HEALTHGAUGE: sets that health value for this object * 477 * POPUP_FACINGDIAL: sets the object's facing * 478 * * 479 * Changed is set when you: * 480 * - place an object * 481 * - move a grabbed object * 482 * - delete an object * 483 * - size the map * 484 * - create a new scenario * 485 * Changed is cleared when you: * 486 * - Save the scenario * 487 * - Load a scenario * 488 * - Play the scenario * 489 * * 490 * INPUT: * 491 * input KN_ value, 0 if none * 492 * * 493 * OUTPUT: * 494 * none. * 495 * * 496 * WARNINGS: * 497 * none. * 498 * * 499 * HISTORY: * 500 * 10/20/1994 BR : Created. * 501 *=========================================================================*/ 502 void MapEditClass::AI(KeyNumType &input, int x, int y) 503 { 504 int rc; 505 MissionType mission; 506 int strength; 507 CELL cell; 508 int i; 509 int found; // for removing a waypoint label 510 int waypt_idx; // for labelling a waypoint 511 BaseNodeClass *node; // for removing from an AI Base 512 HousesType house; 513 514 /*------------------------------------------------------------------------ 515 Trap 'F2' regardless of whether we're in game or editor mode 516 ------------------------------------------------------------------------*/ 517 if (Debug_Flag) { 518 if (/*(input == KN_F2 && Session == GAME_SOLO) ||*/ input == (KN_F2 | KN_CTRL_BIT)) { 519 ScenarioInit = 0; 520 521 /* 522 ** If we're in editor mode & Changed is set, prompt for saving changes 523 */ 524 if (Debug_Map && Changed) { 525 rc = CCMessageBox().Process("Save Changes?", TXT_YES, TXT_NO); 526 HiddenPage.Clear(); 527 Flag_To_Redraw(true); 528 Render(); 529 /* 530 ........................ User wants to save ........................ 531 */ 532 if (rc == 0) { 533 534 /* 535 ................ If save cancelled, abort game .................. 536 */ 537 if (Save_Scenario()!=0) { 538 input = KN_NONE; 539 } else { 540 Changed = 0; 541 Go_Editor(!Debug_Map); 542 } 543 } else { 544 545 /* 546 .................... User doesn't want to save ..................... 547 */ 548 Go_Editor(!Debug_Map); 549 } 550 } else { 551 /* 552 ** If we're in game mode, set Changed to 0 (so if we didn't save our 553 ** changes above, they won't keep coming back to haunt us with continual 554 ** Save Changes? prompts!) 555 */ 556 if (!Debug_Map) { 557 Changed = 0; 558 } 559 Go_Editor(!Debug_Map); 560 } 561 } 562 } 563 564 /*------------------------------------------------------------------------ 565 For normal game mode, jump to the parent's AI routine. 566 ------------------------------------------------------------------------*/ 567 if (!Debug_Map) { 568 MouseClass::AI(input, x, y); 569 return; 570 } 571 572 ::Frame++; 573 574 /*------------------------------------------------------------------------ 575 Do special mouse processing if the mouse is over the map 576 ------------------------------------------------------------------------*/ 577 if (Get_Mouse_X() > TacPixelX && Get_Mouse_X() < 578 TacPixelX + Lepton_To_Pixel(TacLeptonWidth) && 579 Get_Mouse_Y() > TacPixelY && Get_Mouse_Y() < 580 TacPixelY + Lepton_To_Pixel(TacLeptonHeight)) { 581 /*..................................................................... 582 When the mouse moves over a scrolling edge, ScrollClass changes its 583 shape to the appropriate arrow or NO symbol; it's our job to change it 584 back to normal (or whatever the shape is set to by Set_Default_Mouse()) 585 when it re-enters the map area. 586 .....................................................................*/ 587 if (CurTrigger) { 588 Override_Mouse_Shape(MOUSE_CAN_MOVE); 589 } else { 590 Override_Mouse_Shape(MOUSE_NORMAL); 591 } 592 } 593 594 /*..................................................................... 595 Set 'ZoneCell' to track the mouse cursor around over the map. Do this 596 even if the map is scrolling. 597 .....................................................................*/ 598 if (Get_Mouse_X() >= TacPixelX && Get_Mouse_X() <= 599 TacPixelX + Lepton_To_Pixel(TacLeptonWidth) && 600 Get_Mouse_Y() >= TacPixelY && Get_Mouse_Y() <= 601 TacPixelY + Lepton_To_Pixel(TacLeptonHeight)) { 602 603 cell = Click_Cell_Calc(Get_Mouse_X(), Get_Mouse_Y()); 604 if (cell != -1) { 605 Set_Cursor_Pos(cell); 606 if (PendingObject) { 607 Flag_To_Redraw(true); 608 } 609 } 610 } 611 612 /*------------------------------------------------------------------------ 613 Check for mouse motion while left button is down. 614 ------------------------------------------------------------------------*/ 615 rc = Mouse_Moved(); 616 if (LMouseDown && rc) { 617 /*..................................................................... 618 "Paint" mode: place current object, and restart placement 619 .....................................................................*/ 620 if (PendingObject) { 621 Flag_To_Redraw(true); 622 if (Place_Object() == 0) { 623 Changed = 1; 624 Start_Placement(); 625 } 626 } else { 627 /*..................................................................... 628 Move the currently-grabbed object 629 .....................................................................*/ 630 if (GrabbedObject) { 631 GrabbedObject->Mark(MARK_CHANGE); 632 if (Move_Grabbed_Object() == 0) { 633 Changed = 1; 634 } 635 } 636 } 637 } 638 639 /*------------------------------------------------------------------------ 640 Trap special editing keys; if one is detected, set 'input' to 0 to 641 prevent a conflict with parent's AI(). 642 ------------------------------------------------------------------------*/ 643 switch (input) { 644 /*--------------------------------------------------------------------- 645 F2/RMOUSE = pop up main menu 646 ---------------------------------------------------------------------*/ 647 case KN_RMOUSE: 648 /* 649 ..................... Turn off placement mode ...................... 650 */ 651 if (PendingObject) { 652 if (BaseBuilding) { 653 Cancel_Base_Building(); 654 } else { 655 Cancel_Placement(); 656 } 657 } 658 659 /* 660 ................. Turn off trigger placement mode .................. 661 */ 662 if (CurTrigger) { 663 Stop_Trigger_Placement(); 664 } 665 666 /* 667 .............. Unselect object & hide popup controls ............... 668 */ 669 if (CurrentObject.Count()) { 670 CurrentObject[0]->Unselect(); 671 Popup_Controls(); 672 } 673 Main_Menu(); 674 input = KN_NONE; 675 break; 676 677 /*--------------------------------------------------------------------- 678 F6 = toggle passable/impassable display 679 ---------------------------------------------------------------------*/ 680 case KN_F6: 681 Debug_Passable = (Debug_Passable == false); 682 HiddenPage.Clear(); 683 Flag_To_Redraw(true); 684 input = KN_NONE; 685 break; 686 687 /*--------------------------------------------------------------------- 688 INSERT = go into object-placement mode 689 ---------------------------------------------------------------------*/ 690 case KN_INSERT: 691 if (!PendingObject) { 692 /* 693 ......... Unselect current object, hide popup controls .......... 694 */ 695 if (CurrentObject.Count()) { 696 CurrentObject[0]->Unselect(); 697 Popup_Controls(); 698 } 699 /* 700 .................... Go into placement mode ..................... 701 */ 702 Start_Placement(); 703 } 704 input = KN_NONE; 705 break; 706 707 /*--------------------------------------------------------------------- 708 ESC = exit placement mode, or exit to DOS 709 ---------------------------------------------------------------------*/ 710 case KN_ESC: 711 712 /* 713 .................... Exit object placement mode .................... 714 */ 715 if (PendingObject) { 716 if (BaseBuilding) { 717 Cancel_Base_Building(); 718 } else { 719 Cancel_Placement(); 720 } 721 input = KN_NONE; 722 break; 723 } else { 724 725 /* 726 ................... Exit trigger placement mode .................... 727 */ 728 if (CurTrigger) { 729 Stop_Trigger_Placement(); 730 input = KN_NONE; 731 break; 732 } else { 733 rc = CCMessageBox().Process("Exit Scenario Editor?", TXT_YES, TXT_NO); 734 HiddenPage.Clear(); 735 Flag_To_Redraw(true); 736 Render(); 737 738 /* 739 .......... User doesn't want to exit; return to editor .......... 740 */ 741 if (rc==1) { 742 input = KN_NONE; 743 break; 744 } 745 746 /* 747 ................. If changed, prompt for saving ................. 748 */ 749 if (Changed) { 750 rc = CCMessageBox().Process("Save Changes?", TXT_YES, TXT_NO); 751 HiddenPage.Clear(); 752 Flag_To_Redraw(true); 753 Render(); 754 755 /* 756 ..................... User wants to save ..................... 757 */ 758 if (rc == 0) { 759 760 /* 761 .............. If save cancelled, abort exit .............. 762 */ 763 if (Save_Scenario()!=0) { 764 input = KN_NONE; 765 break; 766 } else { 767 Changed = 0; 768 } 769 } 770 } 771 } 772 } 773 Prog_End(); 774 exit (0); 775 break; 776 777 /*--------------------------------------------------------------------- 778 LEFT = go to previous placement object 779 ---------------------------------------------------------------------*/ 780 case KN_LEFT: 781 if (PendingObject) { 782 Place_Prev(); 783 } 784 input = KN_NONE; 785 break; 786 787 /*--------------------------------------------------------------------- 788 RIGHT = go to next placement object 789 ---------------------------------------------------------------------*/ 790 case KN_RIGHT: 791 if (PendingObject) { 792 Place_Next(); 793 } 794 input = KN_NONE; 795 break; 796 797 /*--------------------------------------------------------------------- 798 PGUP = go to previous placement category 799 ---------------------------------------------------------------------*/ 800 case KN_PGUP: 801 if (PendingObject) { 802 Place_Prev_Category(); 803 } 804 input = KN_NONE; 805 break; 806 807 /*--------------------------------------------------------------------- 808 PGDN = go to next placement category 809 ---------------------------------------------------------------------*/ 810 case KN_PGDN: 811 if (PendingObject) { 812 Place_Next_Category(); 813 } 814 input = KN_NONE; 815 break; 816 817 /*--------------------------------------------------------------------- 818 HOME = jump to first placement object, or go to Home Cell 819 ---------------------------------------------------------------------*/ 820 case KN_HOME: 821 if (PendingObject) { 822 Place_Home(); 823 } else { 824 825 /* 826 ....................... Set map position ........................ 827 */ 828 ScenarioInit++; 829 Set_Tactical_Position(Waypoint[WAYPT_HOME]); 830 ScenarioInit--; 831 832 /* 833 ...................... Force map to redraw ...................... 834 */ 835 HiddenPage.Clear(); 836 Flag_To_Redraw(true); 837 Render(); 838 } 839 input = KN_NONE; 840 break; 841 842 /*--------------------------------------------------------------------- 843 SHIFT-HOME: set new Home Cell position 844 ---------------------------------------------------------------------*/ 845 case ((int)KN_HOME | (int)KN_SHIFT_BIT): 846 /* 847 ** Unflag the old Home Cell, if there are no other waypoints 848 ** pointing to it 849 */ 850 cell = Waypoint[WAYPT_HOME]; 851 852 if (cell != -1) { 853 found = 0; 854 for (i = 0; i < WAYPT_COUNT; i++) { 855 if (i != WAYPT_HOME && Waypoint[i]==cell) { 856 found = 1; 857 } 858 } 859 860 if (found==0) { 861 (*this)[cell].IsWaypoint = 0; 862 Flag_Cell(cell); 863 } 864 865 } 866 867 /* 868 ** Now set the new Home cell 869 */ 870 Waypoint[WAYPT_HOME] = Coord_Cell(TacticalCoord); 871 (*this)[Coord_Cell(TacticalCoord)].IsWaypoint = 1; 872 Flag_Cell(Coord_Cell(TacticalCoord)); 873 Changed = 1; 874 input = KN_NONE; 875 break; 876 877 /*--------------------------------------------------------------------- 878 SHIFT-R: set new Reinforcement Cell position. Don't allow setting 879 the Reinf. Cell to the same as the Home Cell (for display purposes.) 880 ---------------------------------------------------------------------*/ 881 case ((int)KN_R | (int)KN_SHIFT_BIT): 882 if (CurrentCell==0 || CurrentCell==Waypoint[WAYPT_HOME]) { 883 break; 884 } 885 886 /* 887 ** Unflag the old Reinforcement Cell, if there are no other waypoints 888 ** pointing to it 889 */ 890 cell = Waypoint[WAYPT_REINF]; 891 892 if (cell != -1) { 893 found = 0; 894 for (i = 0; i < WAYPT_COUNT; i++) { 895 if (i != WAYPT_REINF && Waypoint[i]==cell) { 896 found = 1; 897 } 898 } 899 900 if (found==0) { 901 (*this)[cell].IsWaypoint = 0; 902 Flag_Cell(cell); 903 } 904 905 } 906 /* 907 ** Now set the new Reinforcement cell 908 */ 909 Waypoint[WAYPT_REINF] = CurrentCell; 910 (*this)[CurrentCell].IsWaypoint = 1; 911 Flag_Cell(CurrentCell); 912 Changed = 1; 913 input = KN_NONE; 914 break; 915 916 /*--------------------------------------------------------------------- 917 ALT-Letter: Label a waypoint cell 918 ---------------------------------------------------------------------*/ 919 case ((int)KN_A | (int)KN_ALT_BIT): 920 case ((int)KN_B | (int)KN_ALT_BIT): 921 case ((int)KN_C | (int)KN_ALT_BIT): 922 case ((int)KN_D | (int)KN_ALT_BIT): 923 case ((int)KN_E | (int)KN_ALT_BIT): 924 case ((int)KN_F | (int)KN_ALT_BIT): 925 case ((int)KN_G | (int)KN_ALT_BIT): 926 case ((int)KN_H | (int)KN_ALT_BIT): 927 case ((int)KN_I | (int)KN_ALT_BIT): 928 case ((int)KN_J | (int)KN_ALT_BIT): 929 case ((int)KN_K | (int)KN_ALT_BIT): 930 case ((int)KN_L | (int)KN_ALT_BIT): 931 case ((int)KN_M | (int)KN_ALT_BIT): 932 case ((int)KN_N | (int)KN_ALT_BIT): 933 case ((int)KN_O | (int)KN_ALT_BIT): 934 case ((int)KN_P | (int)KN_ALT_BIT): 935 case ((int)KN_Q | (int)KN_ALT_BIT): 936 case ((int)KN_R | (int)KN_ALT_BIT): 937 case ((int)KN_S | (int)KN_ALT_BIT): 938 case ((int)KN_T | (int)KN_ALT_BIT): 939 case ((int)KN_U | (int)KN_ALT_BIT): 940 case ((int)KN_V | (int)KN_ALT_BIT): 941 case ((int)KN_W | (int)KN_ALT_BIT): 942 case ((int)KN_X | (int)KN_ALT_BIT): 943 case ((int)KN_Y | (int)KN_ALT_BIT): 944 case ((int)KN_Z | (int)KN_ALT_BIT): 945 if (CurrentCell != 0) { 946 waypt_idx = KN_To_KA(input & 0xff) - KA_a; 947 /*............................................................... 948 Unflag cell for this waypoint if there is one 949 ...............................................................*/ 950 cell = Waypoint[waypt_idx]; 951 if (cell != -1) { 952 if (Waypoint[WAYPT_HOME] != cell && 953 Waypoint[WAYPT_REINF] != cell) 954 (*this)[cell].IsWaypoint = 0; 955 Flag_Cell(cell); 956 } 957 Waypoint[waypt_idx] = CurrentCell; 958 (*this)[CurrentCell].IsWaypoint = 1; 959 Changed = 1; 960 Flag_Cell(CurrentCell); 961 } 962 input = KN_NONE; 963 break; 964 965 /*--------------------------------------------------------------------- 966 ALT-1-4: Designate a cell as a capture-the-flag cell. 967 ---------------------------------------------------------------------*/ 968 case ((int)KN_1 | (int)KN_ALT_BIT): 969 case ((int)KN_2 | (int)KN_ALT_BIT): 970 case ((int)KN_3 | (int)KN_ALT_BIT): 971 case ((int)KN_4 | (int)KN_ALT_BIT): 972 /*------------------------------------------------------------------ 973 If there's a current cell, place the flag & waypoint there. 974 ------------------------------------------------------------------*/ 975 if (CurrentCell != 0) { 976 waypt_idx = (KN_To_KA(input & 0xff) - KA_1); 977 house = (HousesType)(HOUSE_MULTI1 + waypt_idx); 978 if (HouseClass::As_Pointer(house)) { 979 HouseClass::As_Pointer(house)->Flag_Attach(CurrentCell,true); 980 } 981 } else { 982 /*------------------------------------------------------------------ 983 If there's a current object, attach the flag to it and clear the 984 waypoint. 985 ------------------------------------------------------------------*/ 986 if (CurrentObject[0] != 0) { 987 waypt_idx = (KN_To_KA(input & 0xff) - KA_1); 988 house = (HousesType)(HOUSE_MULTI1 + waypt_idx); 989 if (HouseClass::As_Pointer(house) && CurrentObject[0]->What_Am_I() == RTTI_UNIT) { 990 HouseClass::As_Pointer(house)->Flag_Attach((UnitClass *)CurrentObject[0], true); 991 } 992 } 993 } 994 input = KN_NONE; 995 break; 996 997 /*--------------------------------------------------------------------- 998 ALT-Space: Remove a waypoint designation 999 ---------------------------------------------------------------------*/ 1000 case ((int)KN_SPACE | (int)KN_ALT_BIT): 1001 if (CurrentCell != 0) { 1002 /*............................................................... 1003 Loop through letter waypoints; if this cell is one of them, 1004 clear that waypoint. 1005 ...............................................................*/ 1006 for (i = 0 ; i < 26; i++) { 1007 if (Waypoint[i]==CurrentCell) 1008 Waypoint[i] = -1; 1009 } 1010 1011 /*............................................................... 1012 Loop through flag home values; if this cell is one of them, clear 1013 that waypoint. 1014 ...............................................................*/ 1015 for (i = 0; i < MAX_PLAYERS; i++) { 1016 house = (HousesType)(HOUSE_MULTI1 + i); 1017 if (HouseClass::As_Pointer(house) && 1018 CurrentCell == HouseClass::As_Pointer(house)->FlagHome) 1019 HouseClass::As_Pointer(house)->Flag_Remove(As_Target(CurrentCell),true); 1020 } 1021 1022 /*............................................................... 1023 If there are no more waypoints on this cell, clear the cell's 1024 waypoint designation. 1025 ...............................................................*/ 1026 if (Waypoint[WAYPT_HOME]!=CurrentCell && 1027 Waypoint[WAYPT_REINF]!=CurrentCell) 1028 (*this)[CurrentCell].IsWaypoint = 0; 1029 Changed = 1; 1030 Flag_Cell(CurrentCell); 1031 } 1032 input = KN_NONE; 1033 break; 1034 1035 /*--------------------------------------------------------------------- 1036 'H' = toggle current placement object's house 1037 ---------------------------------------------------------------------*/ 1038 case KN_H: 1039 case ((int)KN_H | (int)KN_SHIFT_BIT): 1040 if (PendingObject) { 1041 Toggle_House(); 1042 } 1043 input = KN_NONE; 1044 break; 1045 1046 /*--------------------------------------------------------------------- 1047 Left-mouse click: 1048 Button DOWN: 1049 - Toggle LMouseDown 1050 - If we're in placement mode, try to place the current object 1051 - If success, re-enter placement mode 1052 - Otherwise, try to select an object, and "grab" it if there is one 1053 - If no object, then select that cell as the "current" cell 1054 Button UP: 1055 - Toggle LMouseDown 1056 - release any grabbed object 1057 ---------------------------------------------------------------------*/ 1058 case ((int)MAP_AREA | (int)KN_BUTTON): 1059 /* 1060 ------------------------- Left Button DOWN ------------------------- 1061 */ 1062 if (Keyboard::Down(KN_LMOUSE)) { 1063 LMouseDown = 1; 1064 /* 1065 ............... Placement mode: place an object ................. 1066 */ 1067 if (PendingObject) { 1068 if (Place_Object()==0) { 1069 Changed = 1; 1070 Start_Placement(); 1071 } 1072 } else { 1073 /* 1074 ....................... Place a trigger ......................... 1075 */ 1076 if (CurTrigger) { 1077 Place_Trigger(); 1078 Changed = 1; 1079 } else { 1080 /* 1081 ................. Select an object or a cell ................. 1082 .................. Check for double-click .................... 1083 */ 1084 if (CurrentObject.Count() && 1085 ( (TickCount.Time() - LastClickTime) < 15)) { 1086 ; // stub 1087 1088 } else { 1089 /* 1090 ................ Single-click: select object ................. 1091 */ 1092 if (Select_Object()==0) { 1093 CurrentCell = 0; 1094 Grab_Object(); 1095 } else { 1096 /* 1097 ................ No object: select the cell .................. 1098 */ 1099 CurrentCell = Click_Cell_Calc(_Kbd->MouseQX,_Kbd->MouseQY); 1100 HiddenPage.Clear(); 1101 Flag_To_Redraw(true); 1102 Render(); 1103 } 1104 } 1105 } 1106 } 1107 LastClickTime = TickCount.Time(); 1108 input = KN_NONE; 1109 } else { 1110 1111 /* 1112 -------------------------- Left Button UP -------------------------- 1113 */ 1114 LMouseDown = 0; 1115 GrabbedObject = 0; 1116 input = KN_NONE; 1117 } 1118 break; 1119 1120 /*--------------------------------------------------------------------- 1121 SHIFT-ALT-Arrow: move the current object 1122 ---------------------------------------------------------------------*/ 1123 case (int)KN_UP | (int)KN_ALT_BIT | (int)KN_SHIFT_BIT: 1124 case (int)KN_DOWN | (int)KN_ALT_BIT | (int)KN_SHIFT_BIT: 1125 case (int)KN_LEFT | (int)KN_ALT_BIT | (int)KN_SHIFT_BIT: 1126 case (int)KN_RIGHT | (int)KN_ALT_BIT | (int)KN_SHIFT_BIT: 1127 if (CurrentObject.Count()) { 1128 CurrentObject[0]->Move(KN_To_Facing(input)); 1129 Changed = 1; 1130 } 1131 input = KN_NONE; 1132 break; 1133 1134 /*--------------------------------------------------------------------- 1135 DELETE: delete currently-selected object 1136 ---------------------------------------------------------------------*/ 1137 case KN_DELETE: 1138 /*.................................................................. 1139 Delete currently-selected object's trigger, or the object 1140 ..................................................................*/ 1141 if (CurrentObject.Count()) { 1142 1143 /* 1144 ........................ Delete trigger ......................... 1145 */ 1146 if (CurrentObject[0]->Trigger) { 1147 CurrentObject[0]->Trigger = NULL; 1148 } else { 1149 /* 1150 ** If the current object is part of the AI's Base, remove it 1151 ** from the Base's Node list. 1152 */ 1153 if (CurrentObject[0]->What_Am_I()==RTTI_BUILDING && 1154 Base.Is_Node((BuildingClass *)CurrentObject[0])) { 1155 node = Base.Get_Node((BuildingClass *)CurrentObject[0]); 1156 Base.Nodes.Delete(*node); 1157 } 1158 1159 /* 1160 ................... Delete current object .................... 1161 */ 1162 delete CurrentObject[0]; 1163 1164 /* 1165 .................. Hide the popup controls ................... 1166 */ 1167 Popup_Controls(); 1168 } 1169 1170 /* 1171 ........................ Force a redraw ......................... 1172 */ 1173 HiddenPage.Clear(); 1174 Flag_To_Redraw(true); 1175 Changed = 1; 1176 } else { 1177 /* 1178 ................. Remove trigger from current cell ................. 1179 */ 1180 if (CurrentCell) { 1181 if ((*this)[CurrentCell].IsTrigger) { 1182 (*this)[CurrentCell].IsTrigger = 0; 1183 CellTriggers[CurrentCell] = NULL; 1184 /* 1185 ...................... Force a redraw ........................ 1186 */ 1187 HiddenPage.Clear(); 1188 Flag_To_Redraw(true); 1189 Changed = 1; 1190 } 1191 } 1192 } 1193 input = KN_NONE; 1194 break; 1195 1196 /*--------------------------------------------------------------------- 1197 TAB: select next object on the map 1198 ---------------------------------------------------------------------*/ 1199 case KN_TAB: 1200 Select_Next(); 1201 input = KN_NONE; 1202 break; 1203 1204 /*--------------------------------------------------------------------- 1205 Object-Editing button: House Button 1206 ---------------------------------------------------------------------*/ 1207 case (POPUP_GDI | KN_BUTTON): 1208 case (POPUP_NOD | KN_BUTTON): 1209 case (POPUP_NEUTRAL | KN_BUTTON): 1210 case (POPUP_MULTI1 | KN_BUTTON): 1211 case (POPUP_MULTI2 | KN_BUTTON): 1212 case (POPUP_MULTI3 | KN_BUTTON): 1213 case (POPUP_MULTI4 | KN_BUTTON): 1214 /*.................................................................. 1215 Convert input value into a house value; assume HOUSE_GOOD is 0 1216 ..................................................................*/ 1217 house = (HousesType)( (input & (~KN_BUTTON)) - POPUP_GDI); 1218 /*.................................................................. 1219 If that house doesn't own this object, try to transfer it 1220 ..................................................................*/ 1221 if (CurrentObject[0]->Owner()!=house) { 1222 if (Change_House(house)) { 1223 Changed = 1; 1224 } 1225 } 1226 Set_House_Buttons(CurrentObject[0]->Owner(), Buttons, POPUP_GDI); 1227 HiddenPage.Clear(); 1228 Flag_To_Redraw(true); 1229 input = KN_NONE; 1230 break; 1231 1232 /*--------------------------------------------------------------------- 1233 Object-Editing button: Mission 1234 ---------------------------------------------------------------------*/ 1235 case (POPUP_MISSIONLIST | KN_BUTTON): 1236 if (CurrentObject[0]->Is_Techno()) { 1237 /* 1238 ........................ Set new mission ........................ 1239 */ 1240 mission = MapEditMissions[MissionList->Current_Index()]; 1241 if (CurrentObject[0]->Get_Mission() != mission) { 1242 ((TechnoClass *)CurrentObject[0])->Set_Mission(mission); 1243 Changed = 1; 1244 } 1245 } 1246 Flag_To_Redraw(true); 1247 input = KN_NONE; 1248 break; 1249 1250 /*--------------------------------------------------------------------- 1251 Object-Editing button: Health 1252 ---------------------------------------------------------------------*/ 1253 case (POPUP_HEALTHGAUGE | KN_BUTTON): 1254 if (CurrentObject[0]->Is_Techno()) { 1255 /* 1256 .......... Derive strength from current gauge reading ........... 1257 */ 1258 strength = Fixed_To_Cardinal( 1259 (unsigned)CurrentObject[0]->Class_Of().MaxStrength, 1260 (unsigned)HealthGauge->Get_Value()); 1261 1262 /* 1263 ........................... Clip to 1 ........................... 1264 */ 1265 if (strength <= 0) { 1266 strength = 1; 1267 } 1268 1269 /* 1270 ....................... Set new strength ........................ 1271 */ 1272 if (strength != CurrentObject[0]->Strength) { 1273 CurrentObject[0]->Strength = strength; 1274 HiddenPage.Clear(); 1275 Flag_To_Redraw(true); 1276 Changed = 1; 1277 } 1278 1279 /* 1280 ....................... Update text label ....................... 1281 */ 1282 sprintf(HealthBuf,"%d",strength); 1283 } 1284 input = KN_NONE; 1285 break; 1286 1287 /*--------------------------------------------------------------------- 1288 Object-Editing button: Facing 1289 ---------------------------------------------------------------------*/ 1290 case (POPUP_FACINGDIAL | KN_BUTTON): 1291 if (CurrentObject[0]->Is_Techno()) { 1292 /* 1293 ........................ Set new facing ......................... 1294 */ 1295 if (FacingDial->Get_Direction() != 1296 ((TechnoClass *)CurrentObject[0])->PrimaryFacing.Get()) { 1297 /* 1298 ..................... Set body's facing ...................... 1299 */ 1300 ((TechnoClass *)CurrentObject[0])->PrimaryFacing.Set(FacingDial->Get_Direction()); 1301 1302 /* 1303 ............. Set turret facing, if there is one ............. 1304 */ 1305 if (CurrentObject[0]->What_Am_I()==RTTI_UNIT) { 1306 ((UnitClass *)CurrentObject[0])->SecondaryFacing.Set(FacingDial->Get_Direction()); 1307 } 1308 1309 HiddenPage.Clear(); 1310 Flag_To_Redraw(true); 1311 Changed = 1; 1312 } 1313 } 1314 input = KN_NONE; 1315 break; 1316 1317 /*--------------------------------------------------------------------- 1318 Object-Editing button: Facing 1319 ---------------------------------------------------------------------*/ 1320 case (POPUP_BASEPERCENT | KN_BUTTON): 1321 if (BaseGauge->Get_Value() != BasePercent) { 1322 BasePercent = BaseGauge->Get_Value(); 1323 Build_Base_To(BasePercent); 1324 HiddenPage.Clear(); 1325 Flag_To_Redraw(true); 1326 } 1327 input = KN_NONE; 1328 break; 1329 1330 case (KN_LMOUSE): 1331 input = KN_NONE; 1332 break; 1333 1334 default: 1335 break; 1336 } 1337 1338 /* 1339 ------------------------ Call parent's AI routine ------------------------ 1340 */ 1341 MouseClass::AI(input, x, y); 1342 } 1343 1344 1345 /*************************************************************************** 1346 * MapEditClass::Draw_It -- overloaded Redraw routine * 1347 * * 1348 * INPUT: * 1349 * * 1350 * OUTPUT: * 1351 * * 1352 * WARNINGS: * 1353 * * 1354 * HISTORY: * 1355 * 11/17/1994 BR : Created. * 1356 *=========================================================================*/ 1357 void MapEditClass::Draw_It(bool forced) 1358 { 1359 char const *label; 1360 char buf[40]; 1361 char const *tptr; 1362 1363 MouseClass::Draw_It(forced); 1364 1365 if (!Debug_Map) { 1366 return; 1367 } 1368 1369 // 1370 // Erase scrags at top of screen 1371 // 1372 LogicPage->Fill_Rect(0, 0, 640, 16, BLACK); 1373 1374 /* 1375 ** Display the total value of all Tiberium on the map. 1376 */ 1377 Fancy_Text_Print("Tiberium=%ld ", 0, 0, CC_GREEN, BLACK, 1378 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, TotalValue); 1379 1380 /*------------------------------------------------------------------------ 1381 If there are no object controls displayed, just invoke parent's Redraw 1382 and return. 1383 ------------------------------------------------------------------------*/ 1384 if (!Buttons) { 1385 return; 1386 } 1387 1388 /*------------------------------------------------------------------------ 1389 Otherwise, if 'display' is set, invoke the parent's Redraw to refresh 1390 the HIDPAGE; then, update the buttons & text labels onto HIDPAGE; 1391 then invoke the parent's Redraw to blit the HIDPAGE to SEENPAGE. 1392 ------------------------------------------------------------------------*/ 1393 if (forced) { 1394 1395 /* 1396 ....................... Update the text labels ........................ 1397 */ 1398 if (CurrentObject.Count()) { 1399 /* 1400 ------------------ Display the object's name & ID ------------------ 1401 */ 1402 label = Text_String(CurrentObject[0]->Full_Name()); 1403 tptr = label; 1404 sprintf(buf,"%s (%d)",tptr,CurrentObject[0]->As_Target()); 1405 1406 /* 1407 ......................... print the label .......................... 1408 */ 1409 Fancy_Text_Print (buf, 320, 0, CC_TAN, TBLACK, 1410 TPF_CENTER | TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL); 1411 } 1412 } 1413 } 1414 1415 1416 /*************************************************************************** 1417 * MapEditClass::Mouse_Moved -- checks for mouse motion * 1418 * * 1419 * Reports whether the mouse has moved or not. This varies based on the * 1420 * type of object currently selected. If there's an infantry object * 1421 * selected, mouse motion counts even within a cell; for all other types,* 1422 * mouse motion counts only if the mouse changes cells. * 1423 * * 1424 * The reason this routine is needed is to prevent Paint-Mode from putting* 1425 * gobs of trees and such into the same cell if the mouse moves just * 1426 * a little bit. * 1427 * * 1428 * INPUT: * 1429 * * 1430 * OUTPUT: * 1431 * * 1432 * WARNINGS: * 1433 * * 1434 * HISTORY: * 1435 * 11/08/1994 BR : Created. * 1436 *=========================================================================*/ 1437 bool MapEditClass::Mouse_Moved(void) 1438 { 1439 static int old_mx = 0; 1440 static int old_my = 0; 1441 static CELL old_zonecell = 0; 1442 const ObjectTypeClass * objtype = NULL; 1443 bool retcode = false; 1444 1445 /* 1446 -------------------------- Return if no motion --------------------------- 1447 */ 1448 if (old_mx == Get_Mouse_X() && old_my == Get_Mouse_Y()) { 1449 return(false); 1450 } 1451 1452 /* 1453 ---------------------- Get a ptr to ObjectTypeClass ---------------------- 1454 */ 1455 if (PendingObject) { 1456 objtype = PendingObject; 1457 } else { 1458 if (GrabbedObject) { 1459 objtype = &GrabbedObject->Class_Of(); 1460 } else { 1461 old_mx = Get_Mouse_X(); 1462 old_my = Get_Mouse_Y(); 1463 old_zonecell = ZoneCell; 1464 return(false); 1465 } 1466 } 1467 1468 /* 1469 --------------------- Check for motion based on type --------------------- 1470 */ 1471 /* 1472 ............... Infantry: mouse moved if any motion at all ............... 1473 */ 1474 if (objtype->What_Am_I() == RTTI_INFANTRYTYPE) { 1475 retcode = true; 1476 } else { 1477 /* 1478 ................ Others: mouse moved only if cell changed ................ 1479 */ 1480 if (old_zonecell!=ZoneCell) { 1481 retcode = true; 1482 } else { 1483 retcode = false; 1484 } 1485 } 1486 1487 old_mx = Get_Mouse_X(); 1488 old_my = Get_Mouse_Y(); 1489 old_zonecell = ZoneCell; 1490 return(retcode); 1491 } 1492 1493 1494 /*************************************************************************** 1495 * MapEditClass::Main_Menu -- main menu processor for map editor * 1496 * * 1497 * INPUT: * 1498 * none. * 1499 * * 1500 * OUTPUT: * 1501 * none. * 1502 * * 1503 * WARNINGS: * 1504 * none. * 1505 * * 1506 * HISTORY: * 1507 * 10/20/1994 BR : Created. * 1508 *=========================================================================*/ 1509 void MapEditClass::Main_Menu(void) 1510 { 1511 char const *_menus[MAX_MAIN_MENU_NUM + 1]; 1512 int selection; // option the user picks 1513 bool process; // menu stays up while true 1514 int rc; 1515 1516 /* 1517 --------------------------- Fill in menu items --------------------------- 1518 */ 1519 _menus[0] = "New Scenario"; 1520 _menus[1] = "Load Scenario"; 1521 _menus[2] = "Save Scenario"; 1522 _menus[3] = "Size Map"; 1523 _menus[4] = "Add Game Object"; 1524 _menus[5] = "Scenario Options"; 1525 _menus[6] = "AI Options"; 1526 _menus[7] = "Play Scenario"; 1527 _menus[8] = NULL; 1528 1529 /* 1530 ----------------------------- Main Menu loop ----------------------------- 1531 */ 1532 Override_Mouse_Shape(MOUSE_NORMAL); // display default mouse cursor 1533 process = true; 1534 while (process) { 1535 1536 /* 1537 ................ Invoke game callback, to update music ................ 1538 */ 1539 Call_Back(); 1540 1541 /* 1542 ............................. Invoke menu ............................. 1543 */ 1544 Hide_Mouse(); // Do_Menu assumes the mouse is already hidden 1545 selection = Do_Menu(&_menus[0], true); 1546 Show_Mouse(); 1547 if (UnknownKey==KN_ESC || UnknownKey==KN_LMOUSE || UnknownKey==KN_RMOUSE) { 1548 break; 1549 } 1550 1551 /* 1552 .......................... Process selection .......................... 1553 */ 1554 switch (selection) { 1555 /* 1556 ........................... New scenario ........................... 1557 */ 1558 case 0: 1559 if (Changed) { 1560 rc = CCMessageBox().Process("Save Changes?", TXT_YES, TXT_NO); 1561 HiddenPage.Clear(); 1562 Flag_To_Redraw(true); 1563 Render(); 1564 if (rc==0) { 1565 if (Save_Scenario()!=0) { 1566 break; 1567 } else { 1568 Changed = 0; 1569 } 1570 } 1571 } 1572 if (New_Scenario()==0) { 1573 CarryOverMoney = 0; 1574 Changed = 1; 1575 } 1576 process = false; 1577 break; 1578 1579 /* 1580 .......................... Load scenario ........................... 1581 */ 1582 case 1: 1583 if (Changed) { 1584 rc = CCMessageBox().Process("Save Changes?", TXT_YES, TXT_NO); 1585 HiddenPage.Clear(); 1586 Flag_To_Redraw(true); 1587 Render(); 1588 if (rc==0) { 1589 if (Save_Scenario()!=0) { 1590 break; 1591 } else { 1592 Changed = 0; 1593 } 1594 } 1595 } 1596 if (Load_Scenario()==0) { 1597 CarryOverMoney = 0; 1598 Changed = 0; 1599 } 1600 process = false; 1601 break; 1602 1603 /* 1604 .......................... Save scenario ........................... 1605 */ 1606 case 2: 1607 if (Save_Scenario() == 0) { 1608 Changed = 0; 1609 } 1610 process = false; 1611 break; 1612 1613 /* 1614 .......................... Edit map size ........................... 1615 */ 1616 case 3: 1617 if (Size_Map(MapCellX, MapCellY, MapCellWidth, MapCellHeight)==0) { 1618 process = false; 1619 Changed = 1; 1620 } 1621 break; 1622 1623 /* 1624 .......................... Add an object ........................... 1625 */ 1626 case 4: 1627 if (Placement_Dialog() == 0) { 1628 Start_Placement(); 1629 process = false; 1630 } 1631 break; 1632 1633 /* 1634 ......................... Scenario options ......................... 1635 */ 1636 case 5: 1637 if (Scenario_Dialog() == 0) { 1638 Changed = 1; 1639 process = false; 1640 } 1641 break; 1642 1643 /* 1644 .......................... Other options ........................... 1645 */ 1646 case 6: 1647 AI_Menu(); 1648 process = false; 1649 break; 1650 1651 /* 1652 ...................... Test-drive this scenario .................... 1653 */ 1654 case 7: 1655 if (Changed) { 1656 rc = CCMessageBox().Process("Save Changes?", TXT_YES, TXT_NO); 1657 HiddenPage.Clear(); 1658 Flag_To_Redraw(true); 1659 Render(); 1660 if (rc==0) { 1661 if (Save_Scenario()!=0) { 1662 break; 1663 } else { 1664 Changed = 0; 1665 } 1666 } 1667 } 1668 Changed = 0; 1669 Debug_Map = false; 1670 Start_Scenario(ScenarioName); 1671 return; 1672 } 1673 } 1674 1675 /*------------------------------------------------------------------------ 1676 Restore the display: 1677 - Clear HIDPAGE to erase any spurious drawing done by the menu system 1678 - Invoke Flag_To_Redraw to tell DisplayClass to re-render the whole screen 1679 - Invoke Redraw() to update the display 1680 ------------------------------------------------------------------------*/ 1681 HiddenPage.Clear(); 1682 Flag_To_Redraw(true); 1683 Render(); 1684 } 1685 1686 1687 /*************************************************************************** 1688 * MapEditClass::AI_Menu -- menu of AI options * 1689 * * 1690 * INPUT: * 1691 * * 1692 * OUTPUT: * 1693 * * 1694 * WARNINGS: * 1695 * * 1696 * HISTORY: * 1697 * 11/29/1994 BR : Created. * 1698 *=========================================================================*/ 1699 void MapEditClass::AI_Menu(void) 1700 { 1701 int selection; // option the user picks 1702 bool process; // menu stays up while true 1703 char const *_menus[MAX_AI_MENU_NUM + 1]; 1704 1705 /* 1706 -------------------------- Fill in menu strings -------------------------- 1707 */ 1708 _menus[0] = "Pre-Build a Base"; 1709 _menus[1] = "Import Triggers"; 1710 _menus[2] = "Edit Triggers"; 1711 _menus[3] = "Import Teams"; 1712 _menus[4] = "Edit Teams"; 1713 _menus[5] = NULL; 1714 1715 /* 1716 ----------------------------- Main Menu loop ----------------------------- 1717 */ 1718 Override_Mouse_Shape(MOUSE_NORMAL); // display default mouse cursor 1719 process = true; 1720 while (process) { 1721 1722 /* 1723 ................ Invoke game callback, to update music ................ 1724 */ 1725 Call_Back(); 1726 1727 /* 1728 ............................. Invoke menu ............................. 1729 */ 1730 Hide_Mouse(); // Do_Menu assumes the mouse is already hidden 1731 selection = Do_Menu(&_menus[0], true); 1732 Show_Mouse(); 1733 if (UnknownKey==KN_ESC || UnknownKey==KN_LMOUSE || UnknownKey==KN_RMOUSE) { 1734 break; 1735 } 1736 1737 /* 1738 .......................... Process selection .......................... 1739 */ 1740 switch (selection) { 1741 /* 1742 ......................... Pre-Build a Base ......................... 1743 */ 1744 case 0: 1745 Start_Base_Building(); 1746 process = false; 1747 break; 1748 1749 /* 1750 ......................... Import Triggers .......................... 1751 */ 1752 case 1: 1753 if (Import_Triggers()==0) 1754 process = false; 1755 break; 1756 1757 /* 1758 ......................... Trigger Editing .......................... 1759 */ 1760 case 2: 1761 Handle_Triggers(); 1762 /* 1763 ................ Go into trigger placement mode ................. 1764 */ 1765 if (CurTrigger) { 1766 Start_Trigger_Placement(); 1767 } 1768 process = false; 1769 break; 1770 1771 /* 1772 ........................... Import Teams ........................... 1773 */ 1774 case 3: 1775 if (Import_Teams()==0) 1776 process = false; 1777 break; 1778 1779 /* 1780 ........................... Team Editing ........................... 1781 */ 1782 case 4: 1783 Handle_Teams("Teams"); 1784 process = false; 1785 break; 1786 } 1787 } 1788 } 1789 1790 1791 /*************************************************************************** 1792 * MapEditClass::Verify_House -- is this objtype ownable by this house? * 1793 * * 1794 * INPUT: * 1795 * house house to check * 1796 * objtype ObjectTypeClass to check * 1797 * * 1798 * OUTPUT: * 1799 * 0 = isn't ownable, 1 = it is * 1800 * * 1801 * WARNINGS: * 1802 * none. * 1803 * * 1804 * HISTORY: * 1805 * 11/16/1994 BR : Created. * 1806 *=========================================================================*/ 1807 bool MapEditClass::Verify_House(HousesType house, ObjectTypeClass const *objtype) 1808 { 1809 /* 1810 --------------- Verify that new house can own this object ---------------- 1811 */ 1812 return((objtype->Get_Ownable() & (1 << house)) != 0); 1813 } 1814 1815 1816 /*************************************************************************** 1817 * MapEditClass::Cycle_House -- finds next valid house for object type * 1818 * * 1819 * INPUT: * 1820 * objtype ObjectTypeClass ptr to get house for * 1821 * curhouse current house value to start with * 1822 * * 1823 * OUTPUT: * 1824 * HousesType that's valid for this object type * 1825 * * 1826 * WARNINGS: * 1827 * none. * 1828 * * 1829 * HISTORY: * 1830 * 11/23/1994 BR : Created. * 1831 *=========================================================================*/ 1832 HousesType MapEditClass::Cycle_House(HousesType curhouse, 1833 ObjectTypeClass const *objtype) 1834 { 1835 HousesType count; // prevents an infinite loop 1836 1837 /*------------------------------------------------------------------------ 1838 Loop through all house types, starting with the one after 'curhouse'; 1839 return the first one that's valid 1840 ------------------------------------------------------------------------*/ 1841 count = HOUSE_NONE; 1842 while (1) { 1843 1844 /* 1845 .......................... Go to next house ........................... 1846 */ 1847 curhouse++; 1848 if (curhouse == HOUSE_COUNT) { 1849 curhouse = HOUSE_FIRST; 1850 } 1851 1852 /* 1853 ................ Count # iterations; don't go forever ................. 1854 */ 1855 count++; 1856 if (count == HOUSE_COUNT) { 1857 curhouse = HOUSE_NONE; 1858 break; 1859 } 1860 1861 /* 1862 ................... Break if this is a valid house .................... 1863 */ 1864 if (HouseClass::As_Pointer(curhouse) && Verify_House(curhouse,objtype)) { 1865 break; 1866 } 1867 } 1868 1869 return(curhouse); 1870 } 1871 1872 1873 /*************************************************************************** 1874 * MapEditClass::Fatal -- exits with error message * 1875 * * 1876 * INPUT: * 1877 * code tells which message to display; this minimizes the * 1878 * use of character strings in the code. * 1879 * * 1880 * OUTPUT: * 1881 * none. * 1882 * * 1883 * WARNINGS: * 1884 * none. * 1885 * * 1886 * HISTORY: * 1887 * 12/12/1994 BR : Created. * 1888 *=========================================================================*/ 1889 void MapEditClass::Fatal(int txt) 1890 { 1891 Prog_End(); 1892 printf("%s\n",txt); 1893 if (!RunningAsDLL) { 1894 exit(EXIT_FAILURE); 1895 } 1896 } 1897 1898 1899 bool MapEditClass::Scroll_Map(DirType facing, int & distance, bool really) 1900 { 1901 if (Debug_Map) { 1902 /* 1903 ** The popup gadgets require the entire map to be redrawn if we scroll. 1904 */ 1905 if (really) { 1906 Flag_To_Redraw(true); 1907 } 1908 } 1909 return(MouseClass::Scroll_Map(facing, distance, really)); 1910 } 1911 1912 1913 void MapEditClass::Detach(ObjectClass * object) 1914 { 1915 if (GrabbedObject == object) { 1916 GrabbedObject = 0; 1917 } 1918 } 1919 1920 1921 #endif 1922 1923 #include "mapedsel.cpp"