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