SIDEBAR.CPP (113668B)
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/SIDEBAR.CPP 2 3/17/97 1:05a 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 : SIDEBAR.CPP * 24 * * 25 * Programmer : Joe L. Bostic * 26 * * 27 * Start Date : October 20, 1994 * 28 * * 29 * Last Update : October 9, 1996 [JLB] * 30 * * 31 *---------------------------------------------------------------------------------------------* 32 * Functions: * 33 * SidebarClass::AI -- Handles player clicking on sidebar area. * 34 * SidebarClass::Abandon_Production -- Stops production of the object specified. * 35 * SidebarClass::Activate -- Controls the sidebar activation. * 36 * SidebarClass::Activate_Demolish -- Controls the demolish button on the sidebar. * 37 * SidebarClass::Activate_Repair -- Controls the repair button on the sidebar. * 38 * SidebarClass::Activate_Upgrade -- Controls the upgrade button on the sidebar. * 39 * SidebarClass::Add -- Adds a game object to the sidebar list. * 40 * SidebarClass::Draw_It -- Renders the sidebar display. * 41 * SidebarClass::Factory_Link -- Links a factory to a sidebar strip. * 42 * SidebarClass::Init_Clear -- Sets sidebar to a known (and deactivated) state * 43 * SidebarClass::Init_IO -- Adds buttons to the button list * 44 * SidebarClass::Init_Theater -- Performs theater-specific initialization * 45 * SidebarClass::One_Time -- Handles the one time game initializations. * 46 * SidebarClass::One_Time -- Handles the one time game initializations. * 47 * SidebarClass::Recalc -- Examines the sidebar data and updates it as necessary. * 48 * SidebarClass::Refresh_Cells -- Intercepts the refresh, looking for sidebar controls. * 49 * SidebarClass::SBGadgetClass::Action -- Special function that controls the mouse over the s* 50 * SidebarClass::Scroll -- Handles scrolling the sidebar object strip. * 51 * SidebarClass::Set_Current -- Sets a specified object that controls the sidebar display. * 52 * SidebarClass::SidebarClass -- Default constructor for the sidebar. * 53 * SidebarClass::SidebarClass -- This is the no initialization constructor for the sidebar. * 54 * SidebarClass::StripClass::AI -- Input and AI processing for the side strip. * 55 * SidebarClass::StripClass::Abandon_Produ -- Abandons production associated with sidebar. * 56 * SidebarClass::StripClass::Activate -- Adds the strip buttons to the input system. * 57 * SidebarClass::StripClass::Add -- Add an object to the side strip. * 58 * SidebarClass::StripClass::Deactivate -- Removes the side strip buttons from the input syst* 59 * SidebarClass::StripClass::Draw_It -- Render the sidebar display. * 60 * SidebarClass::StripClass::Factory_Link -- Links a factory to a sidebar button. * 61 * SidebarClass::StripClass::Flag_To_Redra -- Flags the sidebar strip to be redrawn. * 62 * SidebarClass::StripClass::Get_Special_Cameo -- Fetches the special event cameo shape. * 63 * SidebarClass::StripClass::Init_Clear -- Sets sidebar to a known (and deactivated) state * 64 * SidebarClass::StripClass::Init_IO -- Adds buttons to the button list * 65 * SidebarClass::StripClass::Init_Theater -- Performs theater-specific initialization * 66 * SidebarClass::StripClass::One_Time -- Performs one time actions necessary for the side str* 67 * SidebarClass::StripClass::Recalc -- Revalidates the current sidebar list of objects. * 68 * SidebarClass::StripClass::Scroll -- Causes the side strip to scroll. * 69 * SidebarClass::StripClass::SelectClass:: -- Action function when buildable cameo is selecte* 70 * SidebarClass::StripClass::SelectClass:: -- Assigns special values to a buildable select bu* 71 * SidebarClass::StripClass::SelectClass::SelectClass -- Default constructor. * 72 * SidebarClass::StripClass::StripClass -- Default constructor for the side strip class. * 73 * SidebarClass::Which_Column -- Determines which column a given type should appear. * 74 * SidebarClass::Zoom_Mode_Control -- Handles the zoom mode toggle operation. * 75 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 76 77 #include "function.h" 78 79 80 void * SidebarClass::SidebarShape = NULL; 81 void * SidebarClass::SidebarMiddleShape = NULL; 82 void * SidebarClass::SidebarBottomShape = NULL; 83 84 85 /*************************************************************************** 86 ** This holds the translucent table for use with the construction clock 87 ** animation. 88 */ 89 char SidebarClass::StripClass::ClockTranslucentTable[(1+1)*256]; 90 91 92 /*************************************************************************** 93 ** This points to the main sidebar shapes. These include the upgrade and 94 ** repair buttons. 95 */ 96 //TheaterType SidebarClass::StripClass::LastTheater = THEATER_NONE; 97 98 typedef enum ButtonNumberType { 99 BUTTON_RADAR = 100, 100 BUTTON_REPAIR, 101 BUTTON_DEMOLISH, 102 BUTTON_UPGRADE, 103 BUTTON_SELECT, 104 BUTTON_ZOOM 105 } ButtonNumberType; 106 107 /* 108 ** Sidebar buttons 109 */ 110 SidebarClass::SBGadgetClass SidebarClass::Background; 111 ShapeButtonClass SidebarClass::Repair; 112 ShapeButtonClass SidebarClass::Upgrade; 113 ShapeButtonClass SidebarClass::Zoom; 114 ShapeButtonClass SidebarClass::StripClass::UpButton[COLUMNS]; 115 ShapeButtonClass SidebarClass::StripClass::DownButton[COLUMNS]; 116 SidebarClass::StripClass::SelectClass 117 SidebarClass::StripClass::SelectButton[COLUMNS][MAX_VISIBLE]; 118 119 /* 120 ** Shape data pointers 121 */ 122 void * SidebarClass::StripClass::LogoShapes = NULL; 123 void const * SidebarClass::StripClass::ClockShapes; 124 void const * SidebarClass::StripClass::SpecialShapes[SPC_COUNT]; 125 126 127 /*********************************************************************************************** 128 * SidebarClass::SidebarClass -- Default constructor for the sidebar. * 129 * * 130 * Constructor for the sidebar handler. It basically sets up the sidebar to the empty * 131 * condition. * 132 * * 133 * INPUT: none * 134 * * 135 * OUTPUT: none * 136 * * 137 * WARNINGS: none * 138 * * 139 * HISTORY: * 140 * 11/17/1994 JLB : Created. * 141 *=============================================================================================*/ 142 SidebarClass::SidebarClass(void) : 143 IsSidebarActive(false), 144 IsToRedraw(true), 145 IsRepairActive(false), 146 IsUpgradeActive(false), 147 IsDemolishActive(false) 148 { 149 /* 150 ** This sets up the clipping window. This window is used by the shape drawing 151 ** code so that as the sidebar buildable buttons scroll, they get properly 152 ** clipped at the top and bottom edges. 153 */ 154 WindowList[WINDOW_SIDEBAR][WINDOWX] = (SIDE_X+8); 155 WindowList[WINDOW_SIDEBAR][WINDOWY] = SIDE_Y + 1 + TOP_HEIGHT; 156 WindowList[WINDOW_SIDEBAR][WINDOWWIDTH] = SIDE_WIDTH; 157 WindowList[WINDOW_SIDEBAR][WINDOWHEIGHT] = StripClass::MAX_VISIBLE * StripClass::OBJECT_HEIGHT; 158 // WindowList[WINDOW_SIDEBAR][WINDOWHEIGHT] = StripClass::MAX_VISIBLE * StripClass::OBJECT_HEIGHT-1; 159 160 /* 161 ** Set up the coordinates for the sidebar strips. These coordinates are for 162 ** the upper left corner. 163 */ 164 new (&Column[0]) StripClass(InitClass()); 165 new (&Column[1]) StripClass(InitClass()); 166 167 Column[0].X = COLUMN_ONE_X * RESFACTOR; 168 Column[0].Y = COLUMN_ONE_Y * RESFACTOR; 169 Column[1].X = COLUMN_TWO_X * RESFACTOR; 170 Column[1].Y = COLUMN_TWO_Y * RESFACTOR; 171 } 172 173 174 /*********************************************************************************************** 175 * SidebarClass::SidebarClass -- This is the no initialization constructor for the sidebar. * 176 * * 177 * Unlike the normal constructor, this one doesn't do any initialization. There is one * 178 * exception to this. The stip classes can't call an explicit NoInitClass constructor * 179 * since they are an array. Since the default constructor is called for these strips, we * 180 * must reset the X and Y location to what we know they should be. * 181 * * 182 * INPUT: flag to indicate that this is a no initialization constructor. * 183 * * 184 * OUTPUT: none * 185 * * 186 * WARNINGS: none * 187 * * 188 * HISTORY: * 189 * 08/06/1996 JLB : Created. * 190 *=============================================================================================*/ 191 SidebarClass::SidebarClass(NoInitClass const & x) : PowerClass(x) 192 { 193 /* 194 ** Set up the coordinates for the sidebar strips. These coordinates are for 195 ** the upper left corner. 196 */ 197 // Column[0].X = COLUMN_ONE_X * RESFACTOR; 198 // Column[0].Y = COLUMN_ONE_Y * RESFACTOR; 199 // Column[1].X = COLUMN_TWO_X * RESFACTOR; 200 // Column[1].Y = COLUMN_TWO_Y * RESFACTOR; 201 } 202 203 204 /*********************************************************************************************** 205 * SidebarClass::One_Time -- Handles the one time game initializations. * 206 * * 207 * This routine is used to load the graphic data that is needed by the sidebar display. It * 208 * should only be called ONCE. * 209 * * 210 * INPUT: none * 211 * * 212 * OUTPUT: none * 213 * * 214 * WARNINGS: Only call this routine once when the game first starts. * 215 * * 216 * HISTORY: * 217 * 10/28/94 JLB : Created. * 218 *=============================================================================================*/ 219 void SidebarClass::One_Time(void) 220 { 221 PowerClass::One_Time(); 222 223 /* 224 ** This sets up the clipping window. This window is used by the shape drawing 225 ** code so that as the sidebar buildable buttons scroll, they get properly 226 ** clipped at the top and bottom edges. 227 */ 228 WindowList[WINDOW_SIDEBAR][WINDOWX] = ((SIDE_X+8)) * RESFACTOR; 229 WindowList[WINDOW_SIDEBAR][WINDOWY] = (SIDE_Y + 1 + TOP_HEIGHT) * RESFACTOR; 230 WindowList[WINDOW_SIDEBAR][WINDOWWIDTH] = (SIDE_WIDTH) * RESFACTOR; 231 WindowList[WINDOW_SIDEBAR][WINDOWHEIGHT] = (StripClass::MAX_VISIBLE * StripClass::OBJECT_HEIGHT) * RESFACTOR; 232 // WindowList[WINDOW_SIDEBAR][WINDOWHEIGHT] = (StripClass::MAX_VISIBLE * StripClass::OBJECT_HEIGHT-1) * RESFACTOR; 233 234 /* 235 ** Top of the window seems to be wrong for the new sidebar. ST - 5/2/96 2:49AM 236 */ 237 WindowList[WINDOW_SIDEBAR][WINDOWY] -= 1*RESFACTOR; 238 239 /* 240 ** Set up the coordinates for the sidebar strips. These coordinates are for 241 ** the upper left corner. 242 */ 243 // Column[0].X = COLUMN_ONE_X * RESFACTOR; 244 // Column[0].Y = COLUMN_ONE_Y * RESFACTOR; 245 // Column[1].X = COLUMN_TWO_X * RESFACTOR; 246 // Column[1].Y = COLUMN_TWO_Y * RESFACTOR; 247 Column[0].One_Time(0); 248 Column[1].One_Time(1); 249 250 /* 251 ** Load the sidebar shape in at this time. (Hi-Res sidebar is theater dependant) 252 */ 253 if (SidebarShape == NULL) { 254 SidebarShape = (void*)MFCD::Retrieve("SIDEBAR.SHP"); 255 } 256 } 257 258 259 /*********************************************************************************************** 260 * SidebarClass::Init_Clear -- Sets sidebar to a known (and deactivated) state * 261 * * 262 * INPUT: none * 263 * * 264 * OUTPUT: none * 265 * * 266 * WARNINGS: none * 267 * * 268 * HISTORY: * 269 * 12/24/1994 JLB : Created. * 270 *=============================================================================================*/ 271 void SidebarClass::Init_Clear(void) 272 { 273 274 PowerClass::Init_Clear(); 275 276 IsToRedraw = true; 277 IsRepairActive = false; 278 IsUpgradeActive = false; 279 IsDemolishActive = false; 280 281 Column[0].Init_Clear(); 282 Column[1].Init_Clear(); 283 284 Activate(false); 285 } 286 287 288 /*********************************************************************************************** 289 * SidebarClass::Init_IO -- Adds buttons to the button list * 290 * * 291 * INPUT: none * 292 * * 293 * OUTPUT: none * 294 * * 295 * WARNINGS: none * 296 * * 297 * HISTORY: * 298 * 12/24/1994 JLB : Created. * 299 *=============================================================================================*/ 300 void SidebarClass::Init_IO(void) 301 { 302 PowerClass::Init_IO(); 303 304 /* 305 ** Add the sidebar's buttons only if we're not in editor mode. 306 */ 307 if (!Debug_Map) { 308 309 Repair.IsSticky = true; 310 Repair.ID = BUTTON_REPAIR; 311 Repair.X = (0x1f2/2)*RESFACTOR; 312 Repair.Y = (0x96/2)*RESFACTOR; 313 Repair.IsPressed = false; 314 Repair.IsToggleType = true; 315 Repair.ReflectButtonState = true; 316 Repair.Set_Shape(MFCD::Retrieve("REPAIR.SHP")); 317 318 Upgrade.IsSticky = true; 319 Upgrade.ID = BUTTON_UPGRADE; 320 #ifdef WIN32 321 Upgrade.X = 0x21f; 322 #else 323 Upgrade.X = ((0x21f/2)+1)*RESFACTOR; 324 #endif 325 Upgrade.Y = (0x96/2)*RESFACTOR; 326 Upgrade.IsPressed = false; 327 Upgrade.IsToggleType = true; 328 Upgrade.ReflectButtonState = true; 329 Upgrade.Set_Shape(MFCD::Retrieve("SELL.SHP")); 330 331 Zoom.IsSticky = true; 332 Zoom.ID = BUTTON_ZOOM; 333 Zoom.X = (0x24c/2)*RESFACTOR; 334 Zoom.Y = (0x96/2)*RESFACTOR; 335 Zoom.IsPressed = false; 336 Zoom.Set_Shape(MFCD::Retrieve("MAP.SHP")); 337 338 if ((IsRadarActive && Is_Zoomable()) || Session.Type != GAME_NORMAL) { 339 Zoom.Enable(); 340 } else { 341 Zoom.Disable(); 342 } 343 Column[0].Init_IO(0); 344 Column[1].Init_IO(1); 345 346 /* 347 ** If a game was loaded & the sidebar was enabled, pop it up now 348 */ 349 if (IsSidebarActive) { 350 IsSidebarActive = false; 351 Activate(1); 352 // Background.Zap(); 353 // Add_A_Button(Background); 354 } 355 } 356 } 357 358 359 /*********************************************************************************************** 360 * SidebarClass::Init_Theater -- Performs theater-specific initialization * 361 * * 362 * INPUT: theater -- The theater that is being initialized. Sometimes this has an effect on * 363 * the data that is loaded. * 364 * * 365 * OUTPUT: none * 366 * * 367 * WARNINGS: none * 368 * * 369 * HISTORY: * 370 * 12/24/1994 JLB : Created. * 371 *=============================================================================================*/ 372 void SidebarClass::Init_Theater(TheaterType theater) 373 { 374 Reload_Sidebar(); 375 376 PowerClass::Init_Theater(theater); 377 378 Column[0].Init_Theater(theater); 379 Column[1].Init_Theater(theater); 380 } 381 382 /*********************************************************************************************** 383 * SidebarClass::Reload_Sidebar -- Loads appropriate sidebar shapes depending on house * 384 * * 385 * INPUT: none * 386 * * 387 * OUTPUT: none * 388 * * 389 * WARNINGS: none * 390 * * 391 * HISTORY: * 392 * 9/18/1996 BWG : Created. * 393 *=============================================================================================*/ 394 void SidebarClass::Reload_Sidebar(void) 395 { 396 static char * sidebarnames[]={ 397 "SIDE?NA.SHP", //NATO 398 "SIDE?NA.SHP", 399 "SIDE?US.SHP", //USSR 400 "SIDE?NA.SHP", 401 "SIDE?US.SHP", //UKRAINE 402 "SIDE?NA.SHP", 403 "SIDE?NA.SHP", 404 "SIDE?NA.SHP", 405 "SIDE?NA.SHP", //HOUSE_GOOD 406 "SIDE?US.SHP" //HOUSE_BAD 407 }; 408 int houseloaded = 0; 409 410 if(PlayerPtr) { 411 houseloaded = PlayerPtr->ActLike; 412 } 413 414 /* Don't have write access to the static char array. ST - 5/20/2019 */ 415 #if (0) 416 char * sidename = sidebarnames[houseloaded]; 417 *(sidename+4) = '1'; 418 SidebarShape = (void*)MFCD::Retrieve(sidename); 419 *(sidename+4) = '2'; 420 SidebarMiddleShape = (void*)MFCD::Retrieve(sidename); 421 *(sidename+4) = '3'; 422 SidebarBottomShape = (void*)MFCD::Retrieve(sidename); 423 #else 424 char sb_name[16]; 425 strcpy(sb_name, sidebarnames[houseloaded]); 426 sb_name[4] = '1'; 427 SidebarShape = (void*)MFCD::Retrieve(sb_name); 428 sb_name[4] = '2'; 429 SidebarMiddleShape = (void*)MFCD::Retrieve(sb_name); 430 sb_name[4] = '3'; 431 SidebarBottomShape = (void*)MFCD::Retrieve(sb_name); 432 433 #endif 434 435 436 437 438 Column[0].Reload_LogoShapes(); 439 Column[1].Reload_LogoShapes(); 440 } 441 442 /*********************************************************************************************** 443 * SidebarClass::Which_Column -- Determines which column a given type should appear. * 444 * * 445 * Use this function to resolve what column the specified object type should be placed * 446 * into. * 447 * * 448 * INPUT: otype -- Pointer to the object type class of the object in question. * 449 * * 450 * OUTPUT: Returns with the column number that the object should be placed in. * 451 * * 452 * WARNINGS: none * 453 * * 454 * HISTORY: * 455 * 01/01/1995 JLB : Created. * 456 *=============================================================================================*/ 457 int SidebarClass::Which_Column(RTTIType type) 458 { 459 if (type == RTTI_BUILDINGTYPE || type == RTTI_BUILDING) { 460 return(0); 461 } 462 return(1); 463 } 464 465 466 /*********************************************************************************************** 467 * SidebarClass::Factory_Link -- Links a factory to a sidebar strip. * 468 * * 469 * This routine will link the specified factory to the sidebar strip. A factory must be * 470 * linked to the sidebar so that as the factory production progresses, the sidebar will * 471 * show the production progress. * 472 * * 473 * INPUT: factory -- The factory number to attach. * 474 * * 475 * type -- The object type number. * 476 * * 477 * id -- The object sub-type number. * 478 * * 479 * OUTPUT: Was the factory successfully attached to the sidebar strip? * 480 * * 481 * WARNINGS: none * 482 * * 483 * HISTORY: * 484 * 05/19/1995 JLB : Created. * 485 *=============================================================================================*/ 486 bool SidebarClass::Factory_Link(int factory, RTTIType type, int id) 487 { 488 assert((unsigned)type < RTTI_COUNT); 489 assert(id >= 0); 490 491 return(Column[Which_Column(type)].Factory_Link(factory, type, id)); 492 } 493 494 495 /*********************************************************************************************** 496 * SidebarClass::Refresh_Cells -- Intercepts the refresh, looking for sidebar controls. * 497 * * 498 * This routine intercepts the Refresh_Cells call in order to see if the sidebar needs * 499 * to be refreshed as well. If the special code to refresh the sidebar was found, it * 500 * flags the sidebar to be redrawn and then removes the code from the list. * 501 * * 502 * INPUT: cell -- The cell to base the refresh list on. * 503 * * 504 * list -- Pointer to the cell offset list that elaborates all the cells that * 505 * need to be flagged for redraw. * 506 * * 507 * OUTPUT: none * 508 * * 509 * WARNINGS: none * 510 * * 511 * HISTORY: * 512 * 01/19/1995 JLB : Created. * 513 *=============================================================================================*/ 514 void SidebarClass::Refresh_Cells(CELL cell, short const * list) 515 { 516 if (*list == REFRESH_SIDEBAR) { 517 IsToRedraw = true; 518 Column[0].IsToRedraw = true; 519 Column[1].IsToRedraw = true; 520 Flag_To_Redraw(false); 521 } 522 PowerClass::Refresh_Cells(cell, list); 523 } 524 525 526 /*********************************************************************************************** 527 * SidebarClass::Activate_Repair -- Controls the repair button on the sidebar. * 528 * * 529 * Use this routine to turn the repair sidebar button on and off. Typically, the button * 530 * is enabled when the currently selected structure is friendly and damaged. * 531 * * 532 * INPUT: control -- The controls how the button is to be activated or deactivated; * 533 * 0 -- Turn button off. * 534 * 1 -- Turn button on. * 535 * -1 -- Toggle button state. * 536 * * 537 * OUTPUT: bool; Was the button previously activated? * 538 * * 539 * WARNINGS: none * 540 * * 541 * HISTORY: * 542 * 12/24/1994 JLB : Created. * 543 *=============================================================================================*/ 544 bool SidebarClass::Activate_Repair(int control) 545 { 546 bool old = IsRepairActive; 547 548 if (control == -1) { 549 control = IsRepairActive ? 0 : 1; 550 } 551 switch (control) { 552 case 1: 553 IsRepairActive = true; 554 break; 555 556 default: 557 case 0: 558 IsRepairActive = false; 559 break; 560 } 561 if (old != IsRepairActive) { 562 Flag_To_Redraw(false); 563 IsToRedraw = true; 564 565 if (!IsRepairActive) { 566 Help_Text(TXT_NONE); 567 Set_Default_Mouse(MOUSE_NORMAL, false); 568 } 569 } 570 return(old); 571 } 572 573 574 /*********************************************************************************************** 575 * SidebarClass::Activate_Upgrade -- Controls the upgrade button on the sidebar. * 576 * * 577 * Use this routine to turn the upgrade sidebar button on and off. Typically, the button * 578 * is enabled when the currently selected structure can be upgraded and disabled otherwise. * 579 * * 580 * INPUT: control -- The controls how the button is to be activated or deactivated; * 581 * 0 -- Turn button off. * 582 * 1 -- Turn button on. * 583 * -1 -- Toggle button state. * 584 * * 585 * OUTPUT: bool; Was the button previously activated? * 586 * * 587 * WARNINGS: none * 588 * * 589 * HISTORY: * 590 * 12/24/1994 JLB : Created. * 591 *=============================================================================================*/ 592 bool SidebarClass::Activate_Upgrade(int control) 593 { 594 bool old = IsUpgradeActive; 595 if (control == -1) { 596 control = IsUpgradeActive ? 0 : 1; 597 } 598 switch (control) { 599 case 1: 600 IsUpgradeActive = true; 601 break; 602 603 default: 604 case 0: 605 IsUpgradeActive = false; 606 break; 607 } 608 if (old != IsUpgradeActive) { 609 Flag_To_Redraw(false); 610 IsToRedraw = true; 611 if (!IsUpgradeActive) { 612 Set_Default_Mouse(MOUSE_NORMAL, false); 613 } 614 } 615 return(old); 616 } 617 618 619 /*********************************************************************************************** 620 * SidebarClass::Activate_Demolish -- Controls the demolish button on the sidebar. * 621 * * 622 * Use this routine to turn the demolish/dismantle sidebar button on and off. Typically, * 623 * the button is enabled when a friendly building is selected and disabled otherwise. * 624 * * 625 * INPUT: control -- The controls how the button is to be activated or deactivated; * 626 * 0 -- Turn button off. * 627 * 1 -- Turn button on. * 628 * -1 -- Toggle button state. * 629 * * 630 * OUTPUT: bool; Was the button previously activated? * 631 * * 632 * WARNINGS: none * 633 * * 634 * HISTORY: * 635 * 12/24/1994 JLB : Created. * 636 *=============================================================================================*/ 637 bool SidebarClass::Activate_Demolish(int control) 638 { 639 bool old = IsDemolishActive; 640 641 if (control == -1) { 642 control = IsDemolishActive ? 0 : 1; 643 } 644 switch (control) { 645 case 1: 646 IsDemolishActive = true; 647 break; 648 649 default: 650 case 0: 651 IsDemolishActive = false; 652 break; 653 } 654 if (old != IsDemolishActive) { 655 Flag_To_Redraw(false); 656 IsToRedraw = true; 657 if (!IsDemolishActive) { 658 Set_Default_Mouse(MOUSE_NORMAL, false); 659 } 660 } 661 return(old); 662 } 663 664 665 /*********************************************************************************************** 666 * SidebarClass::Add -- Adds a game object to the sidebar list. * 667 * * 668 * This routine is used to add a game object to the sidebar. Call this routine when a * 669 * factory type building is created. It handles the case of adding an item that has already * 670 * been added -- it just ignores it. * 671 * * 672 * INPUT: object -- Pointer to the object that is being added. * 673 * * 674 * OUTPUT: bool; Was the object added to the sidebar? * 675 * * 676 * WARNINGS: none * 677 * * 678 * HISTORY: * 679 * 11/17/1994 JLB : Created. * 680 * 9/24/2019 3:17PM : Added via capture parameter for new sidebar functionality * 681 *=============================================================================================*/ 682 bool SidebarClass::Add(RTTIType type, int id, bool via_capture) 683 { 684 assert((unsigned)type < RTTI_COUNT); 685 686 /* 687 ** Add the sidebar only if we're not in editor mode. 688 */ 689 if (!Debug_Map) { 690 int column = Which_Column(type); 691 692 if (Column[column].Add(type, id, via_capture)) { 693 Activate(1); 694 IsToRedraw = true; 695 Flag_To_Redraw(false); 696 return(true); 697 } 698 return(false); 699 } 700 701 return(false); 702 } 703 704 705 /*********************************************************************************************** 706 * SidebarClass::Scroll -- Handles scrolling the sidebar object strip. * 707 * * 708 * This routine is used to scroll the sidebar strip of objects. The strip appears whenever * 709 * a building is selected that can produce units. If the number of units to produce is * 710 * greater than what the sidebar can hold, this routine is used to scroll the other object * 711 * into view so they can be selected. * 712 * * 713 * INPUT: up -- Should the scroll be upwards? Upward scrolling reveals object that are * 714 * later in the list of objects. * 715 * * 716 * OUTPUT: bool; Did scrolling occur? * 717 * * 718 * WARNINGS: none * 719 * * 720 * HISTORY: * 721 * 10/28/94 JLB : Created. * 722 *=============================================================================================*/ 723 bool SidebarClass::Scroll(bool up, int column) 724 { 725 if (column == -1) { 726 bool scr = false; 727 scr |= Column[0].Scroll(up); 728 scr |= Column[1].Scroll(up); 729 if (!scr) { 730 Sound_Effect(VOC_SCOLD); 731 } 732 if (scr) { 733 IsToRedraw = true; 734 Flag_To_Redraw(false); 735 return(true); 736 } 737 return(false); 738 } 739 740 if (Column[column].Scroll(up)) { 741 // No need to redraw the whole sidebar juts because we scrolled a strip is there? ST - 10/15/96 7:29PM 742 //IsToRedraw = true; 743 Flag_To_Redraw(false); 744 return(true); 745 } 746 return(false); 747 } 748 749 750 /*********************************************************************************************** 751 * SidebarClass::Draw_It -- Renders the sidebar display. * 752 * * 753 * This routine performs the actual drawing of the sidebar display. * 754 * * 755 * INPUT: none * 756 * * 757 * OUTPUT: bool; Was the sidebar imagery changed at all? * 758 * * 759 * WARNINGS: none * 760 * * 761 * HISTORY: * 762 * 10/28/94 JLB : Created. * 763 * 12/31/1994 JLB : Split rendering off into the sidebar strip class. * 764 *=============================================================================================*/ 765 void SidebarClass::Draw_It(bool complete) 766 { 767 PowerClass::Draw_It(complete); 768 769 BStart(BENCH_SIDEBAR); 770 771 if (IsSidebarActive && (IsToRedraw || complete) && !Debug_Map) { 772 IsToRedraw = false; 773 774 if (LogicPage->Lock()) { 775 /* 776 ** Draw the outline box around the sidebar buttons. 777 */ 778 int shape = complete ? 0 : 1; 779 780 /* 781 ** The sidebar shape is too big in 640x400 so it needs to be drawn in three chunks. 782 */ 783 CC_Draw_Shape(SidebarShape, 0, SIDE_X * RESFACTOR, 8*RESFACTOR, WINDOW_MAIN, SHAPE_WIN_REL); 784 CC_Draw_Shape(SidebarMiddleShape, shape, SIDE_X * RESFACTOR, (8+80)*RESFACTOR, WINDOW_MAIN, SHAPE_WIN_REL); 785 CC_Draw_Shape(SidebarBottomShape, shape, SIDE_X * RESFACTOR, (8+80+50)*RESFACTOR, WINDOW_MAIN, SHAPE_WIN_REL); 786 787 Repair.Draw_Me(true); 788 Upgrade.Draw_Me(true); 789 Zoom.Draw_Me(true); 790 LogicPage->Unlock(); 791 } 792 } 793 794 /* 795 ** Draw the side strip elements by calling their respective draw functions. 796 */ 797 if (IsSidebarActive) { 798 Column[0].Draw_It(complete); 799 Column[1].Draw_It(complete); 800 801 if (complete || IsToRedraw) { 802 Repair.Draw_Me(true); 803 Upgrade.Draw_Me(true); 804 Zoom.Draw_Me(true); 805 } 806 } 807 IsToRedraw = false; 808 809 BEnd(BENCH_SIDEBAR); 810 } 811 812 813 /*********************************************************************************************** 814 * SidebarClass::AI -- Handles player clicking on sidebar area. * 815 * * 816 * This routine handles the processing necessary when the player clicks on the sidebar. * 817 * Typically, this is selection of the item to build. * 818 * * 819 * INPUT: input -- Reference to the keyboard input value. * 820 * * 821 * x,y -- Mouse coordinates at time of input. * 822 * * 823 * OUTPUT: bool; Was the click handled? * 824 * * 825 * WARNINGS: none * 826 * * 827 * HISTORY: * 828 * 10/28/94 JLB : Created. * 829 * 11/11/1994 JLB : Processes input directly. * 830 * 12/26/1994 JLB : Uses factory manager class for construction handling. * 831 * 12/31/1994 JLB : Simplified to use the sidebar strip class handlers. * 832 * 12/31/1994 JLB : Uses mouse coordinate parameters. * 833 * 06/27/1995 JLB : <TAB> key toggles sidebar. * 834 *=============================================================================================*/ 835 void SidebarClass::AI(KeyNumType & input, int x, int y) 836 { 837 bool redraw = false; 838 839 // 840 // We need to process the sidebar differently in multiplayer. ST - 8/7/2019 10:48AM 841 // 842 if (Session.Type == GAME_GLYPHX_MULTIPLAYER) { 843 PowerClass::AI(input, x, y); 844 return; 845 } 846 847 /* 848 ** Toggle the sidebar in and out with the <TAB> key. 849 */ 850 #ifndef WIN32 851 if (input == KN_TAB) { 852 Activate(-1); 853 } 854 #else 855 if (!Debug_Map) { 856 Activate(1); // Force the sidebar always on in Win95 mode 857 } 858 #endif //WIN32 859 if (!Debug_Map) { 860 Column[0].AI(input, x, y); 861 Column[1].AI(input, x, y); 862 } 863 864 #ifdef NEVER 865 if (IsSidebarActive && !Debug_Map) { 866 867 if (input == KN_DOWN) { 868 int scr = 0; 869 scr |= Column[0].Scroll(false); 870 scr |= Column[1].Scroll(false); 871 if (!scr) { 872 Sound_Effect(VOC_SCOLD); 873 } 874 redraw |= scr; 875 input = KN_NONE; 876 } 877 if (input == KN_UP) { 878 int scr = 0; 879 scr |= Column[0].Scroll(true); 880 scr |= Column[1].Scroll(true); 881 if (!scr) { 882 Sound_Effect(VOC_SCOLD); 883 } 884 redraw |= scr; 885 input = KN_NONE; 886 } 887 } 888 #endif 889 890 891 if (IsSidebarActive) { 892 893 /* 894 ** If there are any buildings in the payer's inventory, then allow the repair 895 ** option. 896 */ 897 if (PlayerPtr->BScan) { 898 Activate_Repair(true); 899 } else { 900 Activate_Repair(false); 901 } 902 903 if (input == (BUTTON_REPAIR|KN_BUTTON)) { 904 Repair_Mode_Control(-1); 905 } 906 907 if (input == (BUTTON_ZOOM|KN_BUTTON)) { 908 Zoom_Mode_Control(); 909 } 910 911 if (input == (BUTTON_UPGRADE|KN_BUTTON)) { 912 Sell_Mode_Control(-1); 913 } 914 915 if (redraw) { 916 //IsToRedraw = true; 917 Column[0].Flag_To_Redraw(); 918 Column[1].Flag_To_Redraw(); 919 920 Flag_To_Redraw(false); 921 } 922 } 923 924 if ((!IsRepairMode) && Repair.IsOn) { 925 Repair.Turn_Off(); 926 } 927 928 if ((!IsSellMode) && Upgrade.IsOn) { 929 Upgrade.Turn_Off(); 930 } 931 932 PowerClass::AI(input, x, y); 933 } 934 935 936 /*********************************************************************************************** 937 * SidebarClass::Recalc -- Examines the sidebar data and updates it as necessary. * 938 * * 939 * Occasionally a factory gets destroyed. This routine must be called in such a case * 940 * because it might be possible that sidebar object need to be removed. This routine will * 941 * examine all existing objects in the sidebar class and if no possible factory can * 942 * produce it, then it will be removed. * 943 * * 944 * INPUT: none * 945 * * 946 * OUTPUT: none * 947 * * 948 * WARNINGS: This routine is exhaustive and thus time consuming. Only call it when really * 949 * necessary. Such as when a factory is destroyed rather than when a non-factory * 950 * is destroyed. * 951 * * 952 * HISTORY: * 953 * 11/30/1994 JLB : Created. * 954 *=============================================================================================*/ 955 void SidebarClass::Recalc(void) 956 { 957 bool redraw = false; 958 959 // Done elsewhere for new multiplayer. ST - 8/7/2019 10:49AM 960 if (Session.Type == GAME_GLYPHX_MULTIPLAYER) { 961 return; 962 } 963 964 redraw |= Column[0].Recalc(); 965 redraw |= Column[1].Recalc(); 966 967 if (redraw) { 968 IsToRedraw = true; 969 Flag_To_Redraw(false); 970 } 971 } 972 973 974 /*********************************************************************************************** 975 * SidebarClass::Activate -- Controls the sidebar activation. * 976 * * 977 * Use this routine to turn the sidebar on or off. This routine handles updating the * 978 * necessary flags. * 979 * * 980 * INPUT: control -- Tells what to do with the sidebar according to the following: * 981 * 0 = Turn sidebar off. * 982 * 1 = Turn sidebar on. * 983 * -1= Toggle sidebar on or off. * 984 * * 985 * OUTPUT: bool; Was the sidebar already on? * 986 * * 987 * WARNINGS: none * 988 * * 989 * HISTORY: * 990 * 12/09/1994 JLB : Created. * 991 *=============================================================================================*/ 992 bool SidebarClass::Activate(int control) 993 { 994 // 995 // We don't want the original sidebar to be visible. ST - 1/31/2019 11:28AM 996 // 997 if (control < 100) { 998 return IsSidebarActive; 999 } 1000 1001 bool old = IsSidebarActive; 1002 1003 if (Session.Play) 1004 return (old); 1005 1006 /* 1007 ** Determine the new state of the sidebar. 1008 */ 1009 switch (control) { 1010 case -1: 1011 IsSidebarActive = IsSidebarActive == false; 1012 break; 1013 1014 case 1: 1015 IsSidebarActive = true; 1016 break; 1017 1018 default: 1019 case 0: 1020 IsSidebarActive = false; 1021 break; 1022 } 1023 1024 /* 1025 ** Only if there is a change in the state of the sidebar will anything 1026 ** be done to change it. 1027 */ 1028 if (IsSidebarActive != old) { 1029 1030 /* 1031 ** If the sidebar is activated but was on the right side of the screen, then 1032 ** activate it on the left side of the screen. 1033 */ 1034 if (IsSidebarActive /*&& X*/) { 1035 Set_View_Dimensions(0, 8 * RESFACTOR, ((320-SIDE_WIDTH)/ICON_PIXEL_W) * RESFACTOR); 1036 IsToRedraw = true; 1037 Help_Text(TXT_NONE); 1038 Repair.Zap(); 1039 Add_A_Button(Repair); 1040 Upgrade.Zap(); 1041 Add_A_Button(Upgrade); 1042 Zoom.Zap(); 1043 Add_A_Button(Zoom); 1044 Column[0].Activate(); 1045 Column[1].Activate(); 1046 Background.Zap(); 1047 Add_A_Button(Background); 1048 Map.RadarButton.Zap(); 1049 Add_A_Button(Map.RadarButton); 1050 Map.PowerButton.Zap(); 1051 Add_A_Button(Map.PowerButton); 1052 } else { 1053 Help_Text(TXT_NONE); 1054 Set_View_Dimensions(0, 8 * RESFACTOR); 1055 Remove_A_Button(Repair); 1056 Remove_A_Button(Upgrade); 1057 Remove_A_Button(Zoom); 1058 Remove_A_Button(Background); 1059 Column[0].Deactivate(); 1060 Column[1].Deactivate(); 1061 Remove_A_Button(Map.RadarButton); 1062 Remove_A_Button(Map.PowerButton); 1063 } 1064 1065 /* 1066 ** Since the sidebar status has changed, update the map so that the graphics 1067 ** will be rendered correctly. 1068 */ 1069 Flag_To_Redraw(true); 1070 } 1071 1072 return(old); 1073 } 1074 1075 1076 /*********************************************************************************************** 1077 * SidebarClass::StripClass::StripClass -- Default constructor for the side strip class. * 1078 * * 1079 * This constructor is used to reset the side strip to default empty state. * 1080 * * 1081 * INPUT: none * 1082 * * 1083 * OUTPUT: none * 1084 * * 1085 * WARNINGS: none * 1086 * * 1087 * HISTORY: * 1088 * 12/31/1994 JLB : Created. * 1089 *=============================================================================================*/ 1090 SidebarClass::StripClass::StripClass(InitClass const & ) : 1091 X(0), 1092 Y(0), 1093 ID(0), 1094 IsToRedraw(true), 1095 IsBuilding(false), 1096 IsScrollingDown(false), 1097 IsScrolling(false), 1098 Flasher(-1), 1099 TopIndex(0), 1100 Scroller(0), 1101 Slid(0), 1102 BuildableCount(0) 1103 { 1104 for (int index = 0; index < MAX_BUILDABLES; index++) { 1105 Buildables[index].BuildableID = 0; 1106 Buildables[index].BuildableType = RTTI_NONE; 1107 Buildables[index].Factory = -1; 1108 Buildables[index].BuildableViaCapture = false; // Added for new sidebar functionality. ST - 9/24/2019 3:10PM 1109 } 1110 } 1111 1112 1113 /*********************************************************************************************** 1114 * SidebarClass::StripClass::One_Time -- Performs one time actions necessary for the side stri * 1115 * * 1116 * Call this routine ONCE at the beginning of the game. It handles retrieving pointers to * 1117 * the shape files it needs for rendering. * 1118 * * 1119 * INPUT: none * 1120 * * 1121 * OUTPUT: none * 1122 * * 1123 * WARNINGS: none * 1124 * * 1125 * HISTORY: * 1126 * 12/31/1994 JLB : Created. * 1127 *=============================================================================================*/ 1128 void SidebarClass::StripClass::One_Time(int ) 1129 { 1130 /* 1131 ** Sidebar is player team specific in Hires 1132 */ 1133 ClockShapes = MFCD::Retrieve("CLOCK.SHP"); 1134 1135 for (SpecialWeaponType lp = SPC_FIRST; lp < SPC_COUNT; lp++) { 1136 char buffer[_MAX_FNAME]; 1137 sprintf(buffer, "%sICON", SpecialWeaponFile[lp]); 1138 1139 char fullname[_MAX_FNAME+_MAX_EXT]; 1140 _makepath(fullname, NULL, NULL, buffer, ".SHP"); 1141 SpecialShapes[lp] = MFCD::Retrieve(fullname); 1142 } 1143 } 1144 1145 1146 /*********************************************************************************************** 1147 * SidebarClass::StripClass::Get_Special_Cameo -- Fetches the special event cameo shape. * 1148 * * 1149 * This routine will return with a pointer to the cameo data for the special objects that * 1150 * can appear on the sidebar (e.g., nuclear bomb). * 1151 * * 1152 * INPUT: type -- The special type to fetch the cameo imagery for. * 1153 * * 1154 * OUTPUT: Returns with a pointer to the cameo imagery for the specified special object. * 1155 * * 1156 * WARNINGS: none * 1157 * * 1158 * HISTORY: * 1159 * 05/19/1995 JLB : commented * 1160 *=============================================================================================*/ 1161 void const * SidebarClass::StripClass::Get_Special_Cameo(SpecialWeaponType type) 1162 { 1163 if ((unsigned)type < SPC_COUNT) { 1164 return(SpecialShapes[type]); 1165 } 1166 return(0); 1167 } 1168 1169 1170 /*********************************************************************************************** 1171 * SidebarClass::StripClass::Init_Clear -- Sets sidebar to a known (and deactivated) state * 1172 * * 1173 * INPUT: none * 1174 * * 1175 * OUTPUT: none * 1176 * * 1177 * WARNINGS: none * 1178 * * 1179 * HISTORY: * 1180 * 12/24/1994 JLB : Created. * 1181 *=============================================================================================*/ 1182 void SidebarClass::StripClass::Init_Clear(void) 1183 { 1184 IsScrollingDown = false; 1185 IsScrolling = false; 1186 IsBuilding = false; 1187 Flasher = -1; 1188 TopIndex = 0; 1189 Slid = 0; 1190 BuildableCount = 0; 1191 1192 /* 1193 ** Since we're resetting the strips, clear out all the buildables & factory pointers. 1194 */ 1195 for (int index = 0; index < MAX_BUILDABLES; index++) { 1196 Buildables[index].BuildableID = 0; 1197 Buildables[index].BuildableType = RTTI_NONE; 1198 Buildables[index].Factory = -1; 1199 Buildables[index].BuildableViaCapture = false; // Added for new sidebar functionality. ST - 9/24/2019 3:10PM 1200 } 1201 } 1202 1203 1204 /*********************************************************************************************** 1205 * SidebarClass::StripClass::Init_IO -- Initializes the strip's buttons * 1206 * * 1207 * This routine doesn't actually add any buttons to the list. * 1208 * * 1209 * INPUT: none * 1210 * * 1211 * OUTPUT: none * 1212 * * 1213 * WARNINGS: none * 1214 * * 1215 * HISTORY: * 1216 * 12/24/1994 JLB : Created. * 1217 *=============================================================================================*/ 1218 void SidebarClass::StripClass::Init_IO(int id) 1219 { 1220 ID = id; 1221 1222 UpButton[ID].IsSticky = true; 1223 UpButton[ID].ID = BUTTON_UP+id; 1224 UpButton[ID].X = X+(UP_X_OFFSET * RESFACTOR); 1225 UpButton[ID].Y = Y+(UP_Y_OFFSET * RESFACTOR); 1226 1227 #if (FRENCH) 1228 #ifdef WIN32 1229 UpButton[ID].Set_Shape(MFCD::Retrieve("STRIPUP.SHP")); 1230 #else 1231 UpButton[ID].Set_Shape(MFCD::Retrieve("STUP_FIX.SHP")); 1232 #endif 1233 #else //FRENCH 1234 UpButton[ID].Set_Shape(MFCD::Retrieve("STRIPUP.SHP")); 1235 #endif //FRENCH 1236 1237 DownButton[ID].IsSticky = true; 1238 DownButton[ID].ID = BUTTON_DOWN+id; 1239 DownButton[ID].X = X+(DOWN_X_OFFSET * RESFACTOR); 1240 DownButton[ID].Y = Y+(DOWN_Y_OFFSET * RESFACTOR); 1241 1242 /* 1243 ** Buttons are in a slightly different position in the new sidebar 1244 */ 1245 UpButton[ID].Y--; 1246 DownButton[ID].Y--; 1247 1248 DownButton[ID].Set_Shape(MFCD::Retrieve("STRIPDN.SHP")); 1249 1250 for (int index = 0; index < MAX_VISIBLE; index++) { 1251 SelectClass & g = SelectButton[ID][index]; 1252 g.ID = BUTTON_SELECT; 1253 g.X = X; 1254 g.Y = Y + ((OBJECT_HEIGHT*index) * RESFACTOR); 1255 g.Width = OBJECT_WIDTH * RESFACTOR; 1256 g.Height = OBJECT_HEIGHT * RESFACTOR; 1257 g.Set_Owner(*this, index); 1258 } 1259 1260 } 1261 1262 1263 /*********************************************************************************************** 1264 * SidebarClass::StripClass::Init_Theater -- Performs theater-specific initialization * 1265 * * 1266 * INPUT: theater * 1267 * * 1268 * OUTPUT: none * 1269 * * 1270 * WARNINGS: none * 1271 * * 1272 * HISTORY: * 1273 * 12/24/1994 JLB : Created. * 1274 *=============================================================================================*/ 1275 void SidebarClass::StripClass::Init_Theater(TheaterType theater) 1276 { 1277 1278 Reload_LogoShapes(); 1279 1280 if ( (theater != THEATER_NONE) && (theater != ::LastTheater)) { 1281 1282 static TLucentType const ClockCols[1] = { 1283 {GREEN, BLACK, 100, 0} 1284 // {GREEN, LTGREY, 180, 0} 1285 }; 1286 1287 /* 1288 ** Make sure that remapping doesn't occur on the colors that cycle. 1289 */ 1290 PaletteClass pal = OriginalPalette; 1291 memset(&pal[CYCLE_COLOR_START*3], 0x3f, CYCLE_COLOR_COUNT*3); 1292 Build_Translucent_Table(pal, &ClockCols[0], 1, (void*)ClockTranslucentTable); 1293 1294 // Mem_Copy(GamePalette, OriginalPalette, 768); 1295 // memset(&GamePalette[CYCLE_COLOR_START*3], 0x3f, CYCLE_COLOR_COUNT*3); 1296 1297 /* 1298 ** Create the translucent table used for the sidebar. 1299 */ 1300 // Build_Translucent_Table(GamePalette, &ClockCols[0], 1, (void*)ClockTranslucentTable); 1301 // GamePalette = OriginalPalette; 1302 1303 Conquer_Build_Fading_Table(GamePalette, &ClockTranslucentTable[256], BLACK, 100); 1304 } 1305 } 1306 1307 void SidebarClass::StripClass::Reload_LogoShapes(void) 1308 { 1309 /* 1310 ** Load hi-res strip art here since it is player side specific 1311 */ 1312 static char * stripnames[]={ 1313 "stripna.shp", //Nato 1314 "stripna.shp", 1315 "stripus.shp", //USSR 1316 "stripna.shp", 1317 "stripus.shp", //UKRAINE 1318 "stripna.shp", 1319 "stripna.shp", 1320 "stripna.shp", 1321 "stripna.shp", //HOUSE_GOOD 1322 "stripus.shp", //HOUSE_BAD 1323 }; 1324 int houseloaded = 0; 1325 1326 /* 1327 ** Sidebar art is dependent on the side of the player 1328 */ 1329 1330 if(PlayerPtr) { 1331 houseloaded = PlayerPtr->ActLike; 1332 } 1333 LogoShapes = (void*)MFCD::Retrieve(stripnames[houseloaded]); 1334 } 1335 1336 /*********************************************************************************************** 1337 * SidebarClass::StripClass::Activate -- Adds the strip buttons to the input system. * 1338 * * 1339 * This routine will add the side strip buttons to the map's input system. This routine * 1340 * should be called once when the sidebar activates. * 1341 * * 1342 * INPUT: none * 1343 * * 1344 * OUTPUT: none * 1345 * * 1346 * WARNINGS: Never call this routine a second time without first calling Deactivate(). * 1347 * * 1348 * HISTORY: * 1349 * 01/19/1995 JLB : Created. * 1350 *=============================================================================================*/ 1351 void SidebarClass::StripClass::Activate(void) 1352 { 1353 UpButton[ID].Zap(); 1354 Map.Add_A_Button(UpButton[ID]); 1355 1356 DownButton[ID].Zap(); 1357 Map.Add_A_Button(DownButton[ID]); 1358 1359 for (int index = 0; index < MAX_VISIBLE; index++) { 1360 SelectButton[ID][index].Zap(); 1361 Map.Add_A_Button(SelectButton[ID][index]); 1362 } 1363 } 1364 1365 1366 /*********************************************************************************************** 1367 * SidebarClass::StripClass::Deactivate -- Removes the side strip buttons from the input syste * 1368 * * 1369 * Call this routine to remove all the buttons on the side strip from the map's input * 1370 * system. * 1371 * * 1372 * INPUT: none * 1373 * * 1374 * OUTPUT: none * 1375 * * 1376 * WARNINGS: Never call this routine unless the Activate() function was previously called. * 1377 * * 1378 * HISTORY: * 1379 * 01/19/1995 JLB : Created. * 1380 *=============================================================================================*/ 1381 void SidebarClass::StripClass::Deactivate(void) 1382 { 1383 Map.Remove_A_Button(UpButton[ID]); 1384 Map.Remove_A_Button(DownButton[ID]); 1385 for (int index = 0; index < MAX_VISIBLE; index++) { 1386 Map.Remove_A_Button(SelectButton[ID][index]); 1387 } 1388 } 1389 1390 1391 /*********************************************************************************************** 1392 * SidebarClass::StripClass::Add -- Add an object to the side strip. * 1393 * * 1394 * Use this routine to add a buildable object to the side strip. * 1395 * * 1396 * INPUT: object -- Pointer to the object type that can be built and is to be added to * 1397 * the side strip. * 1398 * * 1399 * OUTPUT: bool; Was the object successfully added to the side strip? Failure could be the * 1400 * result of running out of room in the side strip array or the object might * 1401 * already be in the list. * 1402 * * 1403 * WARNINGS: none. * 1404 * * 1405 * HISTORY: * 1406 * 12/31/1994 JLB : Created. * 1407 * 9/24/2019 3:17PM : Added via capture parameter for new sidebar functionality * 1408 *=============================================================================================*/ 1409 bool SidebarClass::StripClass::Add(RTTIType type, int id, bool via_capture) 1410 { 1411 if (BuildableCount <= MAX_BUILDABLES) { 1412 for (int index = 0; index < BuildableCount; index++) { 1413 if (Buildables[index].BuildableType == type && Buildables[index].BuildableID == id) { 1414 return(false); 1415 } 1416 } 1417 if (!ScenarioInit && type != RTTI_SPECIAL) { 1418 Speak(VOX_NEW_CONSTRUCT); 1419 } 1420 Buildables[BuildableCount].BuildableType = type; 1421 Buildables[BuildableCount].BuildableID = id; 1422 Buildables[BuildableCount].BuildableViaCapture = via_capture; 1423 BuildableCount++; 1424 IsToRedraw = true; 1425 return(true); 1426 } 1427 return(false); 1428 } 1429 1430 1431 /*********************************************************************************************** 1432 * SidebarClass::StripClass::Scroll -- Causes the side strip to scroll. * 1433 * * 1434 * Use this routine to flag the side strip to scroll. The direction scrolled is controlled * 1435 * by the parameter. Scrolling is merely initiated by this routine. Subsequent calls to * 1436 * the AI function and the Draw_It function are required to properly give the appearance * 1437 * of scrolling. * 1438 * * 1439 * INPUT: bool; Should the side strip scroll UP? If it is to scroll down then pass false. * 1440 * * 1441 * OUTPUT: bool; Was the side strip started to scroll in the desired direction? * 1442 * * 1443 * WARNINGS: none * 1444 * * 1445 * HISTORY: * 1446 * 12/31/1994 JLB : Created. * 1447 * 07/29/1995 JLB : Simplified scrolling logic. * 1448 *=============================================================================================*/ 1449 bool SidebarClass::StripClass::Scroll(bool up) 1450 { 1451 if (up) { 1452 if (!TopIndex) return(false); 1453 Scroller--; 1454 } else { 1455 if (TopIndex+MAX_VISIBLE >= BuildableCount) return(false); 1456 Scroller++; 1457 } 1458 return(true); 1459 } 1460 1461 1462 /*********************************************************************************************** 1463 * SidebarClass::StripClass::Flag_To_Redra -- Flags the sidebar strip to be redrawn. * 1464 * * 1465 * This utility routine is called when something changes on the sidebar and it must be * 1466 * reflected the next time drawing is performed. * 1467 * * 1468 * INPUT: none * 1469 * * 1470 * OUTPUT: none * 1471 * * 1472 * WARNINGS: none * 1473 * * 1474 * HISTORY: * 1475 * 05/18/1995 JLB : Created. * 1476 *=============================================================================================*/ 1477 void SidebarClass::StripClass::Flag_To_Redraw(void) 1478 { 1479 IsToRedraw = true; 1480 //Map.SidebarClass::IsToRedraw = true; 1481 Map.Flag_To_Redraw(false); 1482 } 1483 1484 1485 /*********************************************************************************************** 1486 * SidebarClass::StripClass::AI -- Input and AI processing for the side strip. * 1487 * * 1488 * The side strip AI processing is performed by this function. This function not only * 1489 * checks for player input, but also handles any graphic logic updating necessary as a * 1490 * result of flashing or construction animation. * 1491 * * 1492 * INPUT: input -- The player input code. * 1493 * * 1494 * x,y -- Mouse coordinate to use. * 1495 * * 1496 * OUTPUT: bool; Did the AI detect that it will need a rendering change? If this routine * 1497 * returns true, then the Draw_It function should be called at the * 1498 * earliest opportunity. * 1499 * * 1500 * WARNINGS: none * 1501 * * 1502 * HISTORY: * 1503 * 12/31/1994 JLB : Created. * 1504 * 12/31/1994 JLB : Uses mouse coordinate parameters. * 1505 *=============================================================================================*/ 1506 bool SidebarClass::StripClass::AI(KeyNumType & input, int , int ) 1507 { 1508 bool redraw = false; 1509 1510 /* 1511 ** If this is scroll button for this side strip, then scroll the strip as 1512 ** indicated. 1513 */ 1514 if (input == (UpButton[ID].ID|KN_BUTTON)) { // && !IsScrolling 1515 UpButton[ID].IsPressed = false; 1516 if (!Scroll(true)) { 1517 Sound_Effect(VOC_SCOLD); 1518 } 1519 } 1520 if (input == (DownButton[ID].ID|KN_BUTTON)) { // && !IsScrolling 1521 DownButton[ID].IsPressed = false; 1522 if (!Scroll(false)) { 1523 Sound_Effect(VOC_SCOLD); 1524 } 1525 } 1526 1527 /* 1528 ** Reflect the scroll desired direction/value into the scroll 1529 ** logic handler. This might result in up or down scrolling. 1530 */ 1531 if (!IsScrolling && Scroller) { 1532 if (BuildableCount <= MAX_VISIBLE) { 1533 Scroller = 0; 1534 } else { 1535 1536 /* 1537 ** Top of list is moving toward lower ordered entries in the object list. It looks like 1538 ** the "window" to the object list is moving up even though the actual object images are 1539 ** scrolling downward. 1540 */ 1541 if (Scroller < 0) { 1542 if (!TopIndex) { 1543 Scroller = 0; 1544 } else { 1545 Scroller++; 1546 IsScrollingDown = false; 1547 IsScrolling = true; 1548 TopIndex--; 1549 Slid = 0; 1550 } 1551 1552 } else { 1553 if (TopIndex+MAX_VISIBLE >= BuildableCount) { 1554 Scroller = 0; 1555 } else { 1556 Scroller--; 1557 Slid = OBJECT_HEIGHT; 1558 IsScrollingDown = true; 1559 IsScrolling = true; 1560 } 1561 } 1562 } 1563 } 1564 1565 /* 1566 ** Scroll logic is handled here. 1567 */ 1568 if (IsScrolling) { 1569 if (IsScrollingDown) { 1570 Slid -= SCROLL_RATE; 1571 if (Slid <= 0) { 1572 IsScrolling = false; 1573 Slid = 0; 1574 TopIndex++; 1575 } 1576 } else { 1577 Slid += SCROLL_RATE; 1578 if (Slid >= OBJECT_HEIGHT) { 1579 IsScrolling = false; 1580 Slid = 0; 1581 } 1582 } 1583 redraw = true; 1584 } 1585 1586 /* 1587 ** Handle any flashing logic. Flashing occurs when the player selects an object 1588 ** and provides the visual feedback of a recognized and legal selection. 1589 */ 1590 if (Flasher != -1) { 1591 if (Graphic_Logic()) { 1592 redraw = true; 1593 if (Fetch_Stage() >= 7) { 1594 Set_Rate(0); 1595 Set_Stage(0); 1596 Flasher = -1; 1597 } 1598 } 1599 } 1600 1601 /* 1602 ** Handle any building clock animation logic. 1603 */ 1604 if (IsBuilding) { 1605 for (int index = 0; index < BuildableCount; index++) { 1606 int factoryid = Buildables[index].Factory; 1607 1608 if (factoryid != -1) { 1609 FactoryClass * factory = Factories.Raw_Ptr(factoryid); 1610 1611 if (factory && (factory->Has_Changed() || factory->Is_Blocked())) { 1612 redraw = true; 1613 if (factory->Has_Completed()) { 1614 1615 /* 1616 ** Construction has been completed. Announce this fact to the player and 1617 ** try to get the object to automatically leave the factory. Buildings are 1618 ** the main exception to the ability to leave the factory under their own 1619 ** power. 1620 */ 1621 TechnoClass * pending = factory->Get_Object(); 1622 if (pending != NULL) { 1623 switch (pending->What_Am_I()) { 1624 case RTTI_VESSEL: 1625 case RTTI_UNIT: 1626 case RTTI_AIRCRAFT: 1627 OutList.Add(EventClass(EventClass::PLACE, pending->What_Am_I(), -1)); 1628 if (!factory->Is_Blocked()) { 1629 Speak(VOX_UNIT_READY); 1630 } 1631 break; 1632 1633 case RTTI_BUILDING: 1634 Speak(VOX_CONSTRUCTION); 1635 break; 1636 1637 case RTTI_INFANTRY: 1638 OutList.Add(EventClass(EventClass::PLACE, pending->What_Am_I(), -1)); 1639 if (!factory->Is_Blocked()) { 1640 Speak(VOX_UNIT_READY); 1641 } 1642 break; 1643 } 1644 } 1645 } 1646 } 1647 } 1648 } 1649 } 1650 1651 /* 1652 ** If any of the logic determined that this side strip needs to be redrawn, then 1653 ** set the redraw flag for this side strip. 1654 */ 1655 if (redraw) { 1656 Flag_To_Redraw(); 1657 } 1658 return(redraw); 1659 } 1660 1661 1662 /*********************************************************************************************** 1663 * SidebarClass::StripClass::Draw_It -- Render the sidebar display. * 1664 * * 1665 * Use this routine to render the sidebar display. It checks to see if it needs to be * 1666 * redrawn and only redraw if necessary. If the "complete" parameter is true, then it * 1667 * will force redraw the entire strip. * 1668 * * 1669 * INPUT: complete -- Should the redraw be forced? A force redraw will ignore the redraw * 1670 * flag. * 1671 * * 1672 * OUTPUT: none * 1673 * * 1674 * WARNINGS: none * 1675 * * 1676 * HISTORY: * 1677 * 12/31/1994 JLB : Created. * 1678 * 08/06/1995 JLB : Handles multi factory tracking in same strip. * 1679 *=============================================================================================*/ 1680 void SidebarClass::StripClass::Draw_It(bool complete) 1681 { 1682 if (IsToRedraw || complete) { 1683 IsToRedraw = false; 1684 1685 if (RunningAsDLL) { 1686 return; 1687 } 1688 1689 SidebarRedraws++; 1690 1691 /* 1692 ** Fills the background to the side strip. We shouldnt need to do this if the strip 1693 ** has a full complement of icons. 1694 */ 1695 /* 1696 ** New sidebar needs to be drawn not filled 1697 */ 1698 if (BuildableCount < MAX_VISIBLE) { 1699 CC_Draw_Shape(LogoShapes, ID, X+(2*RESFACTOR), Y, WINDOW_MAIN, SHAPE_WIN_REL|SHAPE_NORMAL, 0); 1700 } 1701 1702 /* 1703 ** Redraw the scroll buttons. 1704 */ 1705 UpButton[ID].Draw_Me(true); 1706 DownButton[ID].Draw_Me(true); 1707 1708 /* 1709 ** Loop through all the buildable objects that are visible in the strip and render 1710 ** them. Their Y offset may be adjusted if the strip is in the process of scrolling. 1711 */ 1712 for (int i = 0; i < MAX_VISIBLE + (IsScrolling ? 1 : 0); i++) { 1713 bool production; 1714 bool completed; 1715 int stage; 1716 bool darken = false; 1717 void const * shapefile = 0; 1718 int shapenum = 0; 1719 void const * remapper = 0; 1720 FactoryClass * factory = 0; 1721 int index = i+TopIndex; 1722 int x = X; 1723 int y = Y + (i*OBJECT_HEIGHT * RESFACTOR); 1724 1725 /* 1726 ** If the strip is scrolling, then the offset is adjusted accordingly. 1727 */ 1728 if (IsScrolling) { 1729 y -= (OBJECT_HEIGHT - Slid) * RESFACTOR; 1730 // y -= OBJECT_HEIGHT - Slid; 1731 } 1732 1733 /* 1734 ** Fetch the shape number for the object type located at this current working 1735 ** slot. This shape pointer is used to draw the underlying graphic there. 1736 */ 1737 if (index < BuildableCount) { 1738 ObjectTypeClass const * obj = NULL; 1739 SpecialWeaponType spc = SPC_NONE; 1740 1741 if (Buildables[index].BuildableType != RTTI_SPECIAL) { 1742 1743 obj = Fetch_Techno_Type(Buildables[index].BuildableType, Buildables[index].BuildableID); 1744 if (obj != NULL) { 1745 1746 /* 1747 ** Fetch the remap table that is appropriate for this object 1748 ** type. 1749 */ 1750 remapper = PlayerPtr->Remap_Table(false, ((TechnoTypeClass const *)obj)->Remap); 1751 1752 /* 1753 ** If there is already a factory producing this kind of object, then all 1754 ** objects of this type are displays in a disabled state. 1755 */ 1756 bool isbusy = (PlayerPtr->Fetch_Factory(Buildables[index].BuildableType) != NULL); 1757 if (!isbusy && PlayerPtr->Is_Hack_Prevented(Buildables[index].BuildableType, Buildables[index].BuildableID)) { 1758 isbusy = true; 1759 } 1760 1761 /* 1762 ** Infantry don't get remapped in the sidebar (special case). 1763 */ 1764 if (Buildables[index].BuildableType == RTTI_INFANTRYTYPE) { 1765 remapper = 0; 1766 } 1767 1768 shapefile = obj->Get_Cameo_Data(); 1769 shapenum = 0; 1770 if (Buildables[index].Factory != -1) { 1771 factory = Factories.Raw_Ptr(Buildables[index].Factory); 1772 production = true; 1773 completed = factory->Has_Completed(); 1774 stage = factory->Completion(); 1775 darken = false; 1776 } else { 1777 production = false; 1778 // darken = IsBuilding; 1779 1780 /* 1781 ** Darken the imagery if a factory of a matching type is 1782 ** already busy. 1783 */ 1784 darken = isbusy; 1785 } 1786 } else { 1787 darken = PlayerPtr->Is_Hack_Prevented(Buildables[index].BuildableType, Buildables[index].BuildableID); 1788 } 1789 1790 } else { 1791 1792 spc = SpecialWeaponType(Buildables[index].BuildableID); 1793 shapefile = Get_Special_Cameo(spc); 1794 shapenum = 0; 1795 1796 production = true; 1797 completed = PlayerPtr->SuperWeapon[spc].Is_Ready(); 1798 stage = PlayerPtr->SuperWeapon[spc].Anim_Stage(); 1799 darken = false; 1800 } 1801 1802 if (obj != NULL || spc != SPC_NONE) { 1803 /* 1804 ** If this item is flashing then take care of it. 1805 ** 1806 */ 1807 if (Flasher == index && (Fetch_Stage() & 0x01)) { 1808 remapper = Map.FadingLight; 1809 } 1810 1811 } else { 1812 shapefile = LogoShapes; 1813 if (!darken) { 1814 shapenum = SB_BLANK; 1815 } 1816 } 1817 } else { 1818 shapefile = LogoShapes; 1819 shapenum = SB_BLANK; 1820 production = false; 1821 } 1822 1823 remapper = 0; 1824 /* 1825 ** Now that the shape of the object at the current working slot has been found, 1826 ** draw it and any graphic overlays as necessary. 1827 ** 1828 ** Don't draw blank shapes over the new 640x400 sidebar art - ST 5/1/96 6:01PM 1829 */ 1830 if (shapenum != SB_BLANK || shapefile != LogoShapes) { 1831 CC_Draw_Shape(shapefile, shapenum, 1832 x-(WindowList[WINDOW_SIDEBAR][WINDOWX])+(LEFT_EDGE_OFFSET * RESFACTOR), 1833 y-WindowList[WINDOW_SIDEBAR][WINDOWY], 1834 WINDOW_SIDEBAR, 1835 SHAPE_NORMAL|SHAPE_WIN_REL| (remapper ? SHAPE_FADING : SHAPE_NORMAL), 1836 remapper); 1837 1838 /* 1839 ** Darken this object because it cannot be produced or is otherwise 1840 ** unavailable. 1841 */ 1842 if (darken) { 1843 CC_Draw_Shape(ClockShapes, 0, 1844 x-(WindowList[WINDOW_SIDEBAR][WINDOWX])+(LEFT_EDGE_OFFSET * RESFACTOR), 1845 y-WindowList[WINDOW_SIDEBAR][WINDOWY], 1846 WINDOW_SIDEBAR, 1847 SHAPE_NORMAL|SHAPE_WIN_REL|SHAPE_GHOST, 1848 NULL, ClockTranslucentTable); 1849 } 1850 } 1851 1852 /* 1853 ** Draw the overlapping clock shape if this is object is being constructed. 1854 ** If the object is completed, then display "Ready" with no clock shape. 1855 */ 1856 if (production) { 1857 if (completed) { 1858 1859 /* 1860 ** Display text showing that the object is ready to place. 1861 */ 1862 CC_Draw_Shape(ObjectTypeClass::PipShapes, PIP_READY, 1863 (x-(WindowList[WINDOW_SIDEBAR][WINDOWX]))+(LEFT_EDGE_OFFSET+15) * RESFACTOR, 1864 (y-WindowList[WINDOW_SIDEBAR][WINDOWY])+(4 * RESFACTOR), 1865 WINDOW_SIDEBAR, SHAPE_CENTER); 1866 } else { 1867 1868 CC_Draw_Shape(ClockShapes, stage+1, 1869 x-(WindowList[WINDOW_SIDEBAR][WINDOWX])+(LEFT_EDGE_OFFSET * RESFACTOR), 1870 y-WindowList[WINDOW_SIDEBAR][WINDOWY], 1871 WINDOW_SIDEBAR, 1872 SHAPE_NORMAL|SHAPE_WIN_REL|SHAPE_GHOST, 1873 NULL, ClockTranslucentTable); 1874 1875 /* 1876 ** Display text showing that the construction is temporarily on hold. 1877 */ 1878 if (factory && !factory->Is_Building()) { 1879 CC_Draw_Shape(ObjectTypeClass::PipShapes, PIP_HOLDING, 1880 (x-(WindowList[WINDOW_SIDEBAR][WINDOWX])) + ((LEFT_EDGE_OFFSET+15) * RESFACTOR), 1881 (y-WindowList[WINDOW_SIDEBAR][WINDOWY])+(4 * RESFACTOR), 1882 WINDOW_SIDEBAR, SHAPE_CENTER); 1883 } 1884 } 1885 } 1886 1887 } 1888 1889 LastSlid = Slid; 1890 } 1891 } 1892 1893 1894 /*********************************************************************************************** 1895 * SidebarClass::StripClass::Recalc -- Revalidates the current sidebar list of objects. * 1896 * * 1897 * This routine will revalidate all the buildable objects in the sidebar. This routine * 1898 * comes in handy when a factory has been destroyed, and the sidebar needs to reflect any * 1899 * change that this requires. It checks every object to see if there is a factory available * 1900 * that could produce it. If none can be found, then the object is removed from the * 1901 * sidebar. * 1902 * * 1903 * INPUT: none * 1904 * * 1905 * OUTPUT: bool; The sidebar has changed as a result of this call? * 1906 * * 1907 * WARNINGS: none * 1908 * * 1909 * HISTORY: * 1910 * 01/19/1995 JLB : Created. * 1911 * 06/26/1995 JLB : Doesn't collapse sidebar when buildables removed. * 1912 *=============================================================================================*/ 1913 bool SidebarClass::StripClass::Recalc(void) 1914 { 1915 int ok; 1916 1917 if (Debug_Map || !BuildableCount) { 1918 return(false); 1919 } 1920 1921 /* 1922 ** Sweep through all objects listed in the sidebar. If any of those object can 1923 ** not be created -- even in theory -- then they must be removed form the sidebar and 1924 ** any current production must be abandoned. 1925 */ 1926 bool redraw = false; 1927 for (int index = 0; index < BuildableCount; index++) { 1928 TechnoTypeClass const * tech = Fetch_Techno_Type(Buildables[index].BuildableType, Buildables[index].BuildableID); 1929 if (tech != NULL) { 1930 ok = tech->Who_Can_Build_Me(true, false, PlayerPtr->Class->House) != NULL; 1931 } else { 1932 if ((unsigned)Buildables[index].BuildableID < SPC_COUNT) { 1933 ok = PlayerPtr->SuperWeapon[Buildables[index].BuildableID].Is_Present(); 1934 } else { 1935 ok = false; 1936 } 1937 } 1938 1939 if (!ok) { 1940 1941 /* 1942 ** Removes this entry from the list. 1943 */ 1944 if (BuildableCount > 1 && index < BuildableCount-1) { 1945 memcpy(&Buildables[index], &Buildables[index+1], sizeof(Buildables[0])*((BuildableCount-index)-1)); 1946 } 1947 TopIndex = 0; 1948 IsToRedraw = true; 1949 redraw = true; 1950 BuildableCount--; 1951 index--; 1952 } 1953 } 1954 1955 #ifdef NEVER 1956 /* 1957 ** If there are no more buildable objects to display, make the sidebar go away. 1958 */ 1959 if (!BuildableCount) { 1960 Map.SidebarClass::Activate(0); 1961 } 1962 #endif 1963 return(redraw); 1964 } 1965 1966 1967 /*********************************************************************************************** 1968 * SidebarClass::StripClass::SelectClass::SelectClass -- Default constructor. * 1969 * * 1970 * This is the default constructor for the button that controls the buildable cameos on * 1971 * the sidebar strip. * 1972 * * 1973 * INPUT: none * 1974 * * 1975 * OUTPUT: none * 1976 * * 1977 * WARNINGS: The coordinates are set to zero by this routine. They must be set to the * 1978 * correct values before this button will function. * 1979 * * 1980 * HISTORY: * 1981 * 01/19/1995 JLB : Created. * 1982 *=============================================================================================*/ 1983 SidebarClass::StripClass::SelectClass::SelectClass(void) : 1984 ControlClass(0, 0, 0, (OBJECT_WIDTH-1) * RESFACTOR, OBJECT_HEIGHT * RESFACTOR, LEFTPRESS|RIGHTPRESS|LEFTUP), 1985 Strip(0), 1986 Index(0) 1987 { 1988 } 1989 1990 1991 /*********************************************************************************************** 1992 * SidebarClass::StripClass::SelectClass:: -- Assigns special values to a buildable select but * 1993 * * 1994 * Use this routine to set custom buildable vars for this particular select button. It * 1995 * uses this information to properly know what buildable object to start or stop production * 1996 * on. * 1997 * * 1998 * INPUT: strip -- Reference to the strip that owns this buildable button. * 1999 * * 2000 * index -- The index (0 .. MAX_VISIBLE-1) of this button. This is used to let * 2001 * the owning strip know what index this button refers to. * 2002 * * 2003 * OUTPUT: none * 2004 * * 2005 * WARNINGS: none * 2006 * * 2007 * HISTORY: * 2008 * 01/19/1995 JLB : Created. * 2009 *=============================================================================================*/ 2010 void SidebarClass::StripClass::SelectClass::Set_Owner(StripClass & strip, int index) 2011 { 2012 Strip = &strip; 2013 Index = index; 2014 X = strip.X; 2015 Y = strip.Y + ((index * OBJECT_HEIGHT) * RESFACTOR); 2016 } 2017 2018 2019 /*********************************************************************************************** 2020 * SidebarClass::StripClass::SelectClass:: -- Action function when buildable cameo is selected * 2021 * * 2022 * This function is called when the buildable icon (cameo) is clicked on. It handles * 2023 * starting and stopping production as indicated. * 2024 * * 2025 * INPUT: flags -- The input event that triggered the call. * 2026 * * 2027 * key -- The keyboard value at the time of the input. * 2028 * * 2029 * OUTPUT: Returns with whether the input list should be scanned further. * 2030 * * 2031 * WARNINGS: none * 2032 * * 2033 * HISTORY: * 2034 * 01/19/1995 JLB : Created. * 2035 * 10/09/1996 JLB : Sonar pulse converted to regular event type. * 2036 *=============================================================================================*/ 2037 int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & key) 2038 { 2039 int index = Strip->TopIndex + Index; 2040 RTTIType otype = Strip->Buildables[index].BuildableType; 2041 int oid = Strip->Buildables[index].BuildableID; 2042 int fnumber = Strip->Buildables[index].Factory; 2043 RemapControlType * scheme = GadgetClass::Get_Color_Scheme(); 2044 2045 ObjectTypeClass const * choice = NULL; 2046 SpecialWeaponType spc = SPC_NONE; 2047 2048 /* 2049 ** Determine the factory number that would apply to objects of the type 2050 ** the mouse is currently addressing. This doesn't mean that the factory number 2051 ** fetched is actually producing the indicated object, merely that that particular 2052 ** kind of factory is specified by the "genfactory" value. This can be used to see 2053 ** if the factory type is currently busy or not. 2054 */ 2055 FactoryClass * factory = PlayerPtr->Fetch_Factory(otype); 2056 2057 Map.Override_Mouse_Shape(MOUSE_NORMAL); 2058 2059 if (index < Strip->BuildableCount) { 2060 if (otype != RTTI_SPECIAL) { 2061 choice = Fetch_Techno_Type(otype, oid); 2062 } else { 2063 spc = SpecialWeaponType(oid); 2064 } 2065 2066 if (fnumber != -1) { 2067 factory = Factories.Raw_Ptr(fnumber); 2068 } 2069 2070 } else { 2071 Map.Help_Text(TXT_NONE); 2072 } 2073 2074 if (spc != SPC_NONE) { 2075 2076 /* 2077 ** Display the help text if the mouse is over the button. 2078 */ 2079 if (flags & LEFTUP) { 2080 Map.Help_Text(SpecialWeaponHelp[spc], X, Y, scheme->Color, true); 2081 flags &= ~LEFTUP; 2082 } 2083 2084 /* 2085 ** A right mouse button signals "cancel". If we are in targeting 2086 ** mode then we don't want to be any more. 2087 */ 2088 if (flags & RIGHTPRESS) { 2089 Map.IsTargettingMode = SPC_NONE; 2090 } 2091 /* 2092 ** A left mouse press signal "activate". If our weapon type is 2093 ** available then we should activate it. 2094 */ 2095 if (flags & LEFTPRESS) { 2096 2097 if ((unsigned)spc < SPC_COUNT) { 2098 if (PlayerPtr->SuperWeapon[spc].Is_Ready()) { 2099 if (spc != SPC_SONAR_PULSE) { 2100 Map.IsTargettingMode = spc; 2101 Unselect_All(); 2102 Speak(VOX_SELECT_TARGET); 2103 } else { 2104 OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_SONAR_PULSE, 0)); 2105 } 2106 } else { 2107 PlayerPtr->SuperWeapon[spc].Impatient_Click(); 2108 } 2109 } 2110 } 2111 2112 } else { 2113 2114 if (choice != NULL) { 2115 2116 /* 2117 ** Display the help text if the mouse is over the button. 2118 */ 2119 if (flags & LEFTUP) { 2120 Map.Help_Text(choice->Full_Name(), X, Y, scheme->Color, true); 2121 Map.Set_Cost(choice->Cost_Of() * PlayerPtr->CostBias); 2122 flags &= ~LEFTUP; 2123 } 2124 2125 /* 2126 ** A right mouse button signals "cancel". 2127 */ 2128 if (flags & RIGHTPRESS) { 2129 2130 /* 2131 ** If production is in progress, put it on hold. If production is already 2132 ** on hold, then abandon it. Money will be refunded, the factory 2133 ** manager deleted, and the object under construction is returned to 2134 ** the free pool. 2135 */ 2136 if (factory != NULL) { 2137 2138 /* 2139 ** Cancels placement mode if the sidebar factory is abandoned or 2140 ** suspended. 2141 */ 2142 if (Map.PendingObjectPtr && Map.PendingObjectPtr->Is_Techno()) { 2143 Map.PendingObjectPtr = 0; 2144 Map.PendingObject = 0; 2145 Map.PendingHouse = HOUSE_NONE; 2146 Map.Set_Cursor_Shape(0); 2147 } 2148 2149 if (!factory->Is_Building()) { 2150 Speak(VOX_CANCELED); 2151 OutList.Add(EventClass(EventClass::ABANDON, otype, oid)); 2152 } else { 2153 Speak(VOX_SUSPENDED); 2154 OutList.Add(EventClass(EventClass::SUSPEND, otype, oid)); 2155 Map.Column[0].IsToRedraw = true; 2156 Map.Column[1].IsToRedraw = true; 2157 } 2158 } 2159 } 2160 2161 if (flags & LEFTPRESS) { 2162 2163 /* 2164 ** If there is already a factory attached to this strip but the player didn't click 2165 ** on the icon that has the attached factory, then say that the factory is busy and 2166 ** ignore the click. 2167 */ 2168 if (fnumber == -1 && factory != NULL) { 2169 Speak(VOX_NO_FACTORY); 2170 ControlClass::Action(flags, key); 2171 return(true); 2172 } 2173 2174 if (factory != NULL) { 2175 2176 /* 2177 ** If this object is currently being built, then give a scold sound and text and then 2178 ** bail. 2179 */ 2180 if (factory->Is_Building()) { 2181 Speak(VOX_NO_FACTORY); 2182 } else { 2183 2184 /* 2185 ** If production has completed, then attempt to have the object exit 2186 ** the factory or go into placement mode. 2187 */ 2188 if (factory->Has_Completed()) { 2189 2190 TechnoClass * pending = factory->Get_Object(); 2191 if (!pending && factory->Get_Special_Item()) { 2192 Map.IsTargettingMode = SPC_ANY; 2193 } else { 2194 BuildingClass * builder = pending->Who_Can_Build_Me(false, false); 2195 if (!builder) { 2196 OutList.Add(EventClass(EventClass::ABANDON, otype, oid)); 2197 Speak(VOX_NO_FACTORY); 2198 } else { 2199 2200 /* 2201 ** If the completed object is a building, then change the 2202 ** game state into building placement mode. This fact is 2203 ** not transmitted to any linked computers until the moment 2204 ** the building is actually placed down. 2205 */ 2206 if (pending->What_Am_I() == RTTI_BUILDING) { 2207 PlayerPtr->Manual_Place(builder, (BuildingClass *)pending); 2208 } else { 2209 2210 /* 2211 ** For objects that can leave the factory under their own 2212 ** power, queue this event and process through normal house 2213 ** production channels. 2214 */ 2215 OutList.Add(EventClass(EventClass::PLACE, otype, -1)); 2216 } 2217 } 2218 } 2219 } else { 2220 2221 if (PlayerPtr->Is_Hack_Prevented(otype, oid)) { 2222 // Eva scolds the player here. 2223 } else { 2224 /* 2225 ** The factory must have been in a suspended state. Resume construction 2226 ** normally. 2227 */ 2228 if (otype == RTTI_INFANTRYTYPE) { 2229 Speak(VOX_TRAINING); 2230 } else { 2231 Speak(VOX_BUILDING); 2232 } 2233 OutList.Add(EventClass(EventClass::PRODUCE, Strip->Buildables[index].BuildableType, Strip->Buildables[index].BuildableID)); 2234 } 2235 } 2236 } 2237 2238 } else { 2239 2240 if (PlayerPtr->Is_Hack_Prevented(otype, oid)) { 2241 // Eva scolds the player here. 2242 } else { 2243 2244 /* 2245 ** If this side strip is already busy with production, then ignore the 2246 ** input and announce this fact. 2247 */ 2248 if (otype == RTTI_INFANTRYTYPE) { 2249 Speak(VOX_TRAINING); 2250 } else { 2251 Speak(VOX_BUILDING); 2252 } 2253 OutList.Add(EventClass(EventClass::PRODUCE, Strip->Buildables[index].BuildableType, Strip->Buildables[index].BuildableID)); 2254 } 2255 } 2256 } 2257 } else { 2258 flags = 0; 2259 } 2260 } 2261 2262 ControlClass::Action(flags, key); 2263 return(true); 2264 } 2265 2266 2267 /*********************************************************************************************** 2268 * SidebarClass::SBGadgetClass::Action -- Special function that controls the mouse over the si * 2269 * * 2270 * This routine is called whenever the mouse is over the sidebar. It makes sure that the * 2271 * mouse is always the normal shape while over the sidebar. * 2272 * * 2273 * INPUT: flags -- The event flags that resulted in this routine being called. * 2274 * * 2275 * key -- Reference the keyboard code that may be present. * 2276 * * 2277 * OUTPUT: Returns that no further keyboard processing is necessary. * 2278 * * 2279 * WARNINGS: none * 2280 * * 2281 * HISTORY: * 2282 * 03/28/1995 JLB : Created. * 2283 *=============================================================================================*/ 2284 int SidebarClass::SBGadgetClass::Action(unsigned , KeyNumType & ) 2285 { 2286 Map.Help_Text(TXT_NONE); 2287 Map.Override_Mouse_Shape(MOUSE_NORMAL, false); 2288 return(true); 2289 } 2290 2291 2292 /*********************************************************************************************** 2293 * SidebarClass::StripClass::Factory_Link -- Links a factory to a sidebar button. * 2294 * * 2295 * This routine will link the specified factory to this sidebar strip. The exact button to * 2296 * link to is determined from the object type and id specified. A linked button is one that * 2297 * will show appropriate construction animation (clock shape) that matches the state of * 2298 * the factory. * 2299 * * 2300 * INPUT: factory -- The factory number to link to the sidebar. * 2301 * * 2302 * type -- The object type that this factory refers to. * 2303 * * 2304 * id -- The object sub-type that this factory refers to. * 2305 * * 2306 * OUTPUT: Was the factory successfully attached? Failure would indicate that there is no * 2307 * object of the specified type and sub-type in the sidebar list. * 2308 * * 2309 * WARNINGS: none * 2310 * * 2311 * HISTORY: * 2312 * 05/18/1995 JLB : Created. * 2313 *=============================================================================================*/ 2314 bool SidebarClass::StripClass::Factory_Link(int factory, RTTIType type, int id) 2315 { 2316 for (int index = 0; index < BuildableCount; index++) { 2317 if (Buildables[index].BuildableType == type && Buildables[index].BuildableID == id) { 2318 Buildables[index].Factory = factory; 2319 IsBuilding = true; 2320 /* 2321 ** Flag that all the icons on this strip need to be redrawn 2322 */ 2323 Flag_To_Redraw(); 2324 return(true); 2325 } 2326 } 2327 return(false); 2328 } 2329 2330 2331 /*********************************************************************************************** 2332 * SidebarClass::Abandon_Production -- Stops production of the object specified. * 2333 * * 2334 * This routine is used to abandon production of the object specified. The factory will * 2335 * be completely disabled by this call. * 2336 * * 2337 * INPUT: type -- The object type that is to be abandoned. The sub-type is not needed * 2338 * since it is presumed there can be only one type in production at any * 2339 * one time. * 2340 * * 2341 * factory -- The factory number that is doing the production. * 2342 * * 2343 * OUTPUT: Was the factory successfully abandoned? * 2344 * * 2345 * WARNINGS: none * 2346 * * 2347 * HISTORY: * 2348 * 05/18/1995 JLB : Created. * 2349 *=============================================================================================*/ 2350 bool SidebarClass::Abandon_Production(RTTIType type, int factory) 2351 { 2352 return(Column[Which_Column(type)].Abandon_Production(factory)); 2353 } 2354 2355 2356 /*********************************************************************************************** 2357 * SidebarClass::StripClass::Abandon_Produ -- Abandons production associated with sidebar. * 2358 * * 2359 * Production of the object associated with this sidebar is abandoned when this routine is * 2360 * called. * 2361 * * 2362 * INPUT: factory -- The factory index that is to be suspended. * 2363 * * 2364 * OUTPUT: Was the production abandonment successful? * 2365 * * 2366 * WARNINGS: none * 2367 * * 2368 * HISTORY: * 2369 * 05/18/1995 JLB : Created. * 2370 * 08/06/1995 JLB : More intelligent abandon logic for multiple factories. * 2371 *=============================================================================================*/ 2372 bool SidebarClass::StripClass::Abandon_Production(int factory) 2373 { 2374 bool noprod = true; 2375 bool abandon = false; 2376 for (int index = 0; index < BuildableCount; index++) { 2377 if (Buildables[index].Factory == factory) { 2378 Factories.Raw_Ptr(factory)->Abandon(); 2379 Buildables[index].Factory = -1; 2380 abandon = true; 2381 } else { 2382 if (Buildables[index].Factory != -1) { 2383 noprod = false; 2384 } 2385 } 2386 } 2387 2388 /* 2389 ** If there was a change to the strip, then flag the strip to be redrawn. 2390 */ 2391 if (abandon) { 2392 Flag_To_Redraw(); 2393 } 2394 2395 /* 2396 ** If there is no production whatsoever on this strip, then flag it so. 2397 */ 2398 if (noprod) { 2399 IsBuilding = false; 2400 } 2401 return(abandon); 2402 } 2403 2404 2405 /*********************************************************************************************** 2406 * SidebarClass::Zoom_Mode_Control -- Handles the zoom mode toggle operation. * 2407 * * 2408 * This is the function that is called when the map button is pressed. It will toggle * 2409 * between the different modes that the radar map can assume. * 2410 * * 2411 * INPUT: none * 2412 * * 2413 * OUTPUT: none * 2414 * * 2415 * WARNINGS: none * 2416 * * 2417 * HISTORY: * 2418 * 07/31/1996 JLB : Created. * 2419 *=============================================================================================*/ 2420 void SidebarClass::Zoom_Mode_Control(void) 2421 { 2422 #ifdef WIN32 2423 /* 2424 ** If radar is active, cycle as follows: 2425 ** Zoomed => not zoomed 2426 ** not zoomed => player status (multiplayer only) 2427 ** player status => radar spying readout 2428 ** radar spying readout => zoomed 2429 */ 2430 if (IsRadarActive) { 2431 if (Is_Zoomed() || Session.Type==GAME_NORMAL) { 2432 if (Is_Zoomed() || !Spy_Next_House()) { 2433 Zoom_Mode(Coord_Cell(TacticalCoord)); 2434 } 2435 } else { 2436 if (!Spying_On_House() && !Is_Player_Names()) { 2437 Player_Names(1); 2438 } else { 2439 Player_Names(0); 2440 if (!Spy_Next_House()) { 2441 Zoom_Mode(Coord_Cell(TacticalCoord)); 2442 } 2443 } 2444 } 2445 } else { 2446 if (Session.Type!=GAME_NORMAL) { 2447 Player_Names(Is_Player_Names()==0); 2448 } 2449 } 2450 #else 2451 /* 2452 ** If radar is active, cycle as follows: 2453 ** not zoomed => player status (multiplayer only) 2454 ** player status => radar spying readout 2455 ** radar spying readout => not zoomed 2456 */ 2457 if (IsRadarActive) { 2458 if (Session.Type==GAME_NORMAL) { 2459 if (!Spy_Next_House()) { 2460 Zoom_Mode(Coord_Cell(TacticalCoord)); 2461 } 2462 } else { 2463 if (!Spying_On_House() && !Is_Player_Names()) { 2464 Player_Names(1); 2465 } else { 2466 Player_Names(0); 2467 if (!Spy_Next_House()) { 2468 Zoom_Mode(Coord_Cell(TacticalCoord)); 2469 } 2470 } 2471 } 2472 } else { 2473 if (Session.Type!=GAME_NORMAL) { 2474 Player_Names(Is_Player_Names()==0); 2475 } 2476 } 2477 #endif 2478 }