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