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