SCENARIO.CPP (31898B)
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\scenario.cpv 2.17 16 Oct 1995 16:52:08 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 : SCENARIO.CPP * 24 * * 25 * Programmer : Joe L. Bostic * 26 * * 27 * Start Date : September 10, 1993 * 28 * * 29 * Last Update : August 24, 1995 [JLB] * 30 * * 31 * This module handles the scenario reading and writing. Scenario related * 32 * code that is executed between scenario play can also be here. * 33 * * 34 *---------------------------------------------------------------------------------------------* 35 * Functions: * 36 * Clear_Scenario -- Clears all data in preparation for scenario load. * 37 * Do_Lose -- Display losing comments. * 38 * Do_Restart -- Handle the restart mission process. * 39 * Do_Win -- Display winning congratulations. * 40 * Fill_In_Data -- Recreate all data that is not loaded with scenario. * 41 * Read_Scenario -- Reads a scenario from disk. * 42 * Restate_Mission -- Handles restating the mission objective. * 43 * Start_Scenario -- Starts the scenario. * 44 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 45 46 #include "function.h" 47 extern int PreserveVQAScreen; 48 49 50 /*********************************************************************************************** 51 * Start_Scenario -- Starts the scenario. * 52 * * 53 * This routine will start the scenario. In addition to loading the scenario data, it will * 54 * play the briefing and action movies. * 55 * * 56 * INPUT: root -- Pointer to the filename root for this scenario (e.g., "SCG01EA"). * 57 * * 58 * briefing -- Should the briefing be played? Normally this is true except when the * 59 * scenario is restarting. * 60 * * 61 * OUTPUT: Was the scenario started without error? * 62 * * 63 * WARNINGS: none * 64 * * 65 * HISTORY: * 66 * 07/04/1995 JLB : Created. * 67 *=============================================================================================*/ 68 bool Start_Scenario(char *root, bool briefing) 69 { 70 71 if (!Read_Scenario(root)) { 72 CCDebugString ("C&C95 - Failed to read scenario.\n"); 73 return(false); 74 } 75 CCDebugString ("C&C95 - Scenario read OK.\n"); 76 77 #ifdef DEMO 78 79 if (briefing) { 80 Play_Movie(BriefMovie); 81 Play_Movie(ActionMovie, TransitTheme); 82 } 83 Theme.Queue_Song(THEME_AOI); 84 85 #else 86 87 /* 88 ** Install some hacks around the movie playing to account for the choose- 89 ** sides introduction. We don't want an intro movie on scenario 1, and 90 ** we don't want a briefing movie on GDI scenario 1. 91 */ 92 if (Scenario < 20 && (!Special.IsJurassic || !AreThingiesEnabled)) { 93 if (Scenario != 1 || Whom == HOUSE_GOOD) { 94 Play_Movie(IntroMovie); 95 } 96 97 if (briefing) { 98 PreserveVQAScreen = (Scenario == 1); 99 Play_Movie(BriefMovie); 100 } 101 Play_Movie(ActionMovie, TransitTheme); 102 if (TransitTheme == THEME_NONE) { 103 Theme.Queue_Song(THEME_AOI); 104 } 105 } else { 106 Play_Movie(BriefMovie); 107 Play_Movie(ActionMovie, TransitTheme); 108 109 #ifdef NEWMENU 110 111 char buffer[25]; 112 sprintf(buffer, "%s.VQA", BriefMovie); 113 CCFileClass file(buffer); 114 115 if (GameToPlay == GAME_NORMAL && !file.Is_Available()) { 116 VisiblePage.Clear(); 117 Set_Palette(GamePalette); 118 // Show_Mouse(); 119 /* 120 ** Show the mission briefing. Pretend we are inside the main loop so the palette 121 ** will be correct on the textured buttons. 122 */ 123 bool oldinmain = InMainLoop; 124 InMainLoop = true; 125 126 // TO_FIX - Covert ops missions want to pop up a dialog box. ST - 9/6/2019 1:48PM 127 //Restate_Mission(ScenarioName, TXT_OK, TXT_NONE); 128 129 130 InMainLoop = oldinmain; 131 // Hide_Mouse(); 132 if (TransitTheme == THEME_NONE) { 133 Theme.Queue_Song(THEME_AOI); 134 } 135 } 136 137 #endif 138 } 139 #endif 140 141 /* 142 ** Set the options values, since the palette has been initialized by Read_Scenario 143 */ 144 CCDebugString ("C&C95 - About to call Options.Set.\n"); 145 Options.Set(); 146 CCDebugString ("C&C95 - About to return from Start_Scenario.\n"); 147 return(true); 148 } 149 150 151 /*********************************************************************************************** 152 * Set_Scenario_Difficulty -- Sets the difficulty of the scenario. * 153 * * 154 * Updates the player's difficulty in single-player mode. * 155 * * 156 * INPUT: difficulty -- Scenario difficulty * 157 * * 158 * OUTPUT: none * 159 * * 160 * WARNINGS: Only works in single-player. * 161 * Must call Start_Scenario first to initialize the player. * 162 * * 163 * HISTORY: * 164 * 10/02/2019 SKY : Created. * 165 *=============================================================================================*/ 166 void Set_Scenario_Difficulty(int difficulty) 167 { 168 if (GameToPlay == GAME_NORMAL) { 169 switch (difficulty) { 170 case 0: 171 PlayerPtr->Assign_Handicap(DIFF_EASY); 172 break; 173 case 1: 174 PlayerPtr->Assign_Handicap(DIFF_NORMAL); 175 break; 176 case 2: 177 PlayerPtr->Assign_Handicap(DIFF_HARD); 178 break; 179 default: 180 break; 181 } 182 } 183 } 184 185 186 /*********************************************************************************************** 187 * Read_Scenario -- Reads a scenario from disk. * 188 * * 189 * This will read a scenario from disk. Use this to begin a scenario. * 190 * It doesn't perform any rendering, it merely sets up the system * 191 * with the proper data. Setting of the right game state will start * 192 * the scenario running. * 193 * * 194 * INPUT: root -- Scenario root filename * 195 * * 196 * OUTPUT: none * 197 * * 198 * WARNINGS: You must clear out the system variables before calling * 199 * this function. Use the Clear_Scenario() function. * 200 * It is assumed that Scenario is set to the current scenario number. * 201 * * 202 * HISTORY: * 203 * 07/22/1991 : Created. * 204 * 02/03/1992 JLB : Uses house identification. * 205 *=============================================================================================*/ 206 bool Read_Scenario(char *root) 207 { 208 CCDebugString ("C&C95 - In Read_Scenario.\n"); 209 Clear_Scenario(); 210 ScenarioInit++; 211 if (Read_Scenario_Ini(root)) { 212 213 Fill_In_Data(); 214 215 Map.Set_View_Dimensions(0, Map.Get_Tab_Height(), Map.MapCellWidth, Map.MapCellHeight); 216 217 218 /* 219 ** SPECIAL CASE: 220 ** Clear out the tutor flags for scenarios one and two. This is designed 221 ** so that tutorial message will reappear in scenario two. 222 */ 223 if (Scenario < 5) { 224 TutorFlags[0] = 0L; 225 TutorFlags[1] = 0L; 226 } 227 228 } else { 229 230 #if (1) 231 char message[200]; 232 if (root) { 233 sprintf(message, "Failed to load scenario %s", root); 234 GlyphX_Debug_Print(message); 235 } else { 236 GlyphX_Debug_Print("Failed to load scenario"); 237 } 238 #else 239 Fade_Palette_To(GamePalette, FADE_PALETTE_FAST, Call_Back); 240 Show_Mouse(); 241 CCMessageBox().Process(TXT_UNABLE_READ_SCENARIO); 242 Hide_Mouse(); 243 #endif 244 return(false); 245 } 246 ScenarioInit--; 247 CCDebugString ("C&C95 - Leaving Read_Scenario.\n"); 248 return(true); 249 } 250 251 252 /*********************************************************************************************** 253 * Fill_In_Data -- Recreate all data that is not loaded with scenario. * 254 * * 255 * This routine is called after the INI file for the scenario has been processed. It will * 256 * infer the game state from the scenario INI data. * 257 * * 258 * INPUT: none * 259 * * 260 * OUTPUT: none * 261 * * 262 * WARNINGS: none * 263 * * 264 * HISTORY: * 265 * 10/07/1992 JLB : Created. * 266 *=============================================================================================*/ 267 void Fill_In_Data(void) 268 { 269 /* 270 ** The basic scenario data load does not contain the full set of 271 ** game data. We now must fill in the missing pieces. 272 */ 273 ScenarioInit++; 274 275 for (int index = 0; index < Buildings.Count(); index++) { 276 Buildings.Ptr(index)->Update_Buildables(); 277 } 278 279 Map.Flag_To_Redraw(true); 280 281 /* 282 ** Bring up the score display on the radar map when starting a multiplayer 283 ** game. 284 */ 285 if (GameToPlay != GAME_NORMAL) { 286 Map.Player_Names(1); 287 } 288 289 ScenarioInit--; 290 } 291 292 293 /*********************************************************************************************** 294 * Clear_Scenario -- Clears all data in preparation for scenario load. * 295 * * 296 * This routine will clear out all data specific to a scenario in * 297 * preparation for a subsequent scenario data load. This will free * 298 * all units, animations, and icon maps. * 299 * * 300 * INPUT: none * 301 * * 302 * OUTPUT: none * 303 * * 304 * WARNINGS: none * 305 * * 306 * HISTORY: * 307 * 07/22/1991 : Created. * 308 * 03/21/1992 JLB : Changed buffer allocations, so changes memset code. * 309 * 07/13/1995 JLB : End count down moved here. * 310 *=============================================================================================*/ 311 void Clear_Scenario(void) 312 { 313 EndCountDown = TICKS_PER_SECOND * 30; 314 CrateCount = 0; 315 CrateTimer = 0; 316 CrateMaker = false; 317 318 /* 319 ** Call everyone's Init routine, except the Map's; for the Map, only call 320 ** MapClass::Init, which clears the Cell array. The Display::Init requires 321 ** a Theater argument, and the theater is not known at this point; also, it 322 ** would reload MixFiles, which isn't desired. Display::Read_INI calls its 323 ** own Init, which will Init the entire Map hierarchy. 324 */ 325 Map.Init_Clear(); 326 Score.Init(); 327 Logic.Init(); 328 329 HouseClass::Init(); 330 ObjectClass::Init(); 331 TeamTypeClass::Init(); 332 TeamClass::Init(); 333 TriggerClass::Init(); 334 AircraftClass::Init(); 335 AnimClass::Init(); 336 BuildingClass::Init(); 337 BulletClass::Init(); 338 InfantryClass::Init(); 339 OverlayClass::Init(); 340 SmudgeClass::Init(); 341 TemplateClass::Init(); 342 TerrainClass::Init(); 343 UnitClass::Init(); 344 345 FactoryClass::Init(); 346 347 Base.Init(); 348 349 CurrentObject.Clear_All(); 350 351 Invalidate_Cached_Icons(); 352 } 353 354 355 /*********************************************************************************************** 356 * Do_Win -- Display winning congratulations. * 357 * * 358 * * 359 * * 360 * INPUT: * 361 * * 362 * OUTPUT: * 363 * * 364 * WARNINGS: * 365 * * 366 * HISTORY: * 367 * 08/05/1992 JLB : Created. * 368 * 01/01/1995 JLB : Carries money forward into next scenario. * 369 *=============================================================================================*/ 370 void Do_Win(void) 371 { 372 Map.Set_Default_Mouse(MOUSE_NORMAL); 373 Hide_Mouse(); 374 375 /* 376 ** If this is a multiplayer game, clear the game's name so we won't respond 377 ** to game queries any more (in Call_Back) 378 */ 379 if (GameToPlay != GAME_NORMAL) { 380 MPlayerGameName[0] = 0; 381 } 382 383 /* 384 ** Determine a cosmetic center point for the text. 385 */ 386 int x = Map.TacPixelX + (Lepton_To_Pixel(Map.TacLeptonWidth)/2); 387 int y = Map.TacPixelY + (Lepton_To_Pixel(Map.TacLeptonHeight)/2) -32; 388 389 /* 390 ** Announce win to player. 391 */ 392 Set_Logic_Page(SeenBuff); 393 #if !(GERMAN | FRENCH) 394 Fancy_Text_Print(TXT_MISSION, x, y, WHITE, TBLACK, TPF_CENTER|TPF_VCR); 395 #endif 396 Fancy_Text_Print(TXT_SCENARIO_WON, x, y+30, WHITE, TBLACK, TPF_CENTER|TPF_VCR); 397 CountDownTimer.Set(TIMER_SECOND * 3); 398 Stop_Speaking(); 399 Speak(VOX_ACCOMPLISHED); 400 while (CountDownTimer.Time() || Is_Speaking()) { 401 Call_Back(); 402 } 403 404 /* 405 ** Stop here if this is a multiplayer game. 406 */ 407 if (GameToPlay != GAME_NORMAL) { 408 if (!PlaybackGame) { 409 MPlayerGamesPlayed++; 410 Multi_Score_Presentation(); 411 MPlayerCurGame++; 412 if (MPlayerCurGame >= MAX_MULTI_GAMES) { 413 MPlayerCurGame = MAX_MULTI_GAMES - 1; 414 } 415 } 416 GameActive = 0; 417 Show_Mouse(); 418 return; 419 } 420 421 /* 422 ** Play the winning movie and then start the next scenario. 423 */ 424 if (RequiredCD != -2) { 425 if (Scenario >= 20 && Scenario <60 && GameToPlay == GAME_NORMAL) { 426 RequiredCD = 2; 427 } else { 428 if (Scenario >=60){ 429 RequiredCD = -1; 430 }else{ 431 if (PlayerPtr->Class->House == HOUSE_GOOD) { 432 RequiredCD = 0; 433 } else { 434 RequiredCD = 1; 435 } 436 } 437 } 438 } 439 440 #ifndef DEMO 441 Play_Movie(WinMovie); 442 #endif 443 444 Keyboard::Clear(); 445 446 /* 447 ** Do the ending screens only if not playing back a recorded game. 448 */ 449 if (!PlaybackGame) { 450 451 #ifdef DEMO 452 453 switch (Scenario) { 454 case 1: 455 Score.Presentation(); 456 Scenario = 10; 457 break; 458 459 case 10: 460 Score.Presentation(); 461 Scenario = 6; 462 break; 463 464 default: 465 Score.Presentation(); 466 GDI_Ending(); 467 GameActive = false; 468 Show_Mouse(); 469 return; 470 // Prog_End(); 471 // exit(0); 472 // break; 473 } 474 475 #else 476 477 #ifdef NEWMENU 478 if (Scenario >= 20) { 479 Keyboard::Clear(); 480 Score.Presentation(); 481 GameActive = false; 482 Show_Mouse(); 483 return; 484 } 485 #endif 486 487 if (PlayerPtr->Class->House == HOUSE_BAD && Scenario == 13) { 488 Nod_Ending(); 489 //Prog_End(); 490 //exit(0); 491 SeenBuff.Clear(); 492 Show_Mouse(); 493 GameActive = false; 494 return; 495 } 496 if (PlayerPtr->Class->House == HOUSE_GOOD && Scenario == 15) { 497 GDI_Ending(); 498 //Prog_End(); 499 //exit(0); 500 SeenBuff.Clear(); 501 Show_Mouse(); 502 GameActive = false; 503 return; 504 } 505 506 if ( (Special.IsJurassic && AreThingiesEnabled) && Scenario == 5) { 507 Prog_End("Do_Win - Last Jurassic mission complete"); 508 if (!RunningAsDLL) { 509 exit(0); 510 } 511 return; 512 } 513 514 if (!Special.IsJurassic || !AreThingiesEnabled) { 515 Keyboard::Clear(); 516 InterpolationPaletteChanged = TRUE; 517 InterpolationPalette = Palette; 518 Score.Presentation(); 519 520 /* 521 ** Skip scenario #7 if the airfield was blown up. 522 */ 523 if (Scenario == 6 && PlayerPtr->Class->House == HOUSE_GOOD && SabotagedType == STRUCT_AIRSTRIP) { 524 Scenario++; 525 } 526 527 Map_Selection(); 528 } 529 Scenario++; 530 #endif 531 Keyboard::Clear(); 532 } 533 534 CarryOverMoney = PlayerPtr->Credits; 535 536 int pieces = PlayerPtr->NukePieces; 537 538 /* 539 ** Generate a new scenario filename 540 */ 541 Set_Scenario_Name(ScenarioName, Scenario, ScenPlayer, ScenDir, ScenVar); 542 Start_Scenario(ScenarioName); 543 544 PlayerPtr->NukePieces = pieces; 545 546 /* 547 ** Destroy the building that was sabotaged in the previous scenario. This only 548 ** applies to GDI mission #7. 549 */ 550 int index; 551 if (SabotagedType != STRUCT_NONE && Scenario == 7 && PlayerPtr->Class->House == HOUSE_GOOD) { 552 for (index = 0; index < Buildings.Count(); index++) { 553 BuildingClass * building = Buildings.Ptr(index); 554 555 if (building && !building->IsInLimbo && building->House != PlayerPtr && building->Class->Type == SabotagedType) { 556 building->Limbo(); 557 delete building; 558 break; 559 } 560 } 561 562 /* 563 ** Remove the building from the prebuild list. 564 */ 565 for (index = 0; index < Base.Nodes.Count(); index++) { 566 BaseNodeClass * node = Base.Get_Node(index); 567 568 if (node && node->Type == SabotagedType) { 569 Base.Nodes.Delete(index); 570 break; 571 } 572 } 573 } 574 SabotagedType = STRUCT_NONE; 575 576 Map.Render(); 577 Fade_Palette_To(GamePalette, FADE_PALETTE_FAST, Call_Back); 578 Show_Mouse(); 579 } 580 581 582 /*********************************************************************************************** 583 * Do_Lose -- Display losing comments. * 584 * * 585 * * 586 * * 587 * INPUT: * 588 * * 589 * OUTPUT: * 590 * * 591 * WARNINGS: * 592 * * 593 * HISTORY: * 594 * 08/05/1992 JLB : Created. * 595 *=============================================================================================*/ 596 void Do_Lose(void) 597 { 598 Map.Set_Default_Mouse(MOUSE_NORMAL); 599 Hide_Mouse(); 600 601 /* 602 ** If this is a multiplayer game, clear the game's name so we won't respond 603 ** to game queries any more (in Call_Back) 604 */ 605 if (GameToPlay != GAME_NORMAL) { 606 MPlayerGameName[0] = 0; 607 } 608 609 /* 610 ** Determine a cosmetic center point for the text. 611 */ 612 int x = Map.TacPixelX + (Lepton_To_Pixel(Map.TacLeptonWidth)/2); 613 int y = Map.TacPixelY + (Lepton_To_Pixel(Map.TacLeptonHeight)/2) -32; 614 615 /* 616 ** Announce win to player. 617 */ 618 Set_Logic_Page(SeenBuff); 619 Fancy_Text_Print(TXT_MISSION, x, y, WHITE, TBLACK, TPF_CENTER|TPF_VCR); 620 Fancy_Text_Print(TXT_SCENARIO_LOST, x, y+30, WHITE, TBLACK, TPF_CENTER|TPF_VCR); 621 CountDownTimer.Set(TIMER_SECOND * 3); 622 Stop_Speaking(); 623 Speak(VOX_FAIL); 624 while (CountDownTimer.Time() || Is_Speaking()) { 625 Call_Back(); 626 } 627 628 #ifdef OBSOLETE 629 if (Debug_Play_Map) { 630 Go_Editor(true); 631 Show_Mouse(); 632 return; 633 } 634 #endif 635 636 /* 637 ** Stop here if this is a multiplayer game. 638 */ 639 if (GameToPlay != GAME_NORMAL) { 640 if (!PlaybackGame) { 641 MPlayerGamesPlayed++; 642 Multi_Score_Presentation(); 643 MPlayerCurGame++; 644 if (MPlayerCurGame >= MAX_MULTI_GAMES) { 645 MPlayerCurGame = MAX_MULTI_GAMES - 1; 646 } 647 } 648 GameActive = 0; 649 Show_Mouse(); 650 return; 651 } 652 653 Play_Movie(LoseMovie); 654 655 /* 656 ** Start same scenario again 657 */ 658 Set_Palette(GamePalette); 659 Show_Mouse(); 660 if (!PlaybackGame && !CCMessageBox().Process(TXT_TO_REPLAY, TXT_YES, TXT_NO)) { 661 Hide_Mouse(); 662 Keyboard::Clear(); 663 Start_Scenario(ScenarioName, false); 664 Map.Render(); 665 } else { 666 Hide_Mouse(); 667 GameActive = 0; 668 } 669 670 Fade_Palette_To(GamePalette, FADE_PALETTE_FAST, Call_Back); 671 Show_Mouse(); 672 } 673 674 675 /*********************************************************************************************** 676 * Do_Restart -- Handle the restart mission process. * 677 * * 678 * This routine is called in the main game loop when the mission must be restarted. This * 679 * routine will throw away the current game and reload the appropriate mission. The * 680 * game will "resume" at the start of the mission. * 681 * * 682 * INPUT: none * 683 * * 684 * OUTPUT: none * 685 * * 686 * WARNINGS: none * 687 * * 688 * HISTORY: * 689 * 08/24/1995 JLB : Created. * 690 *=============================================================================================*/ 691 void Do_Restart(void) 692 { 693 bool hidden = Get_Mouse_State(); 694 695 if (hidden) Show_Mouse(); 696 CCMessageBox().Process(TXT_RESTARTING, TXT_NONE); 697 Map.Set_Default_Mouse(MOUSE_NORMAL); 698 Keyboard::Clear(); 699 Start_Scenario(ScenarioName, false); 700 if (hidden) Hide_Mouse(); 701 Keyboard::Clear(); 702 Map.Render(); 703 } 704 705 706 /*********************************************************************************************** 707 * Restate_Mission -- Handles restating the mission objective. * 708 * * 709 * This routine will display the mission objective (as text). It will also give the * 710 * option to redisplay the mission briefing video. * 711 * * 712 * INPUT: name -- The scenario name. This is the unique identifier for the scenario * 713 * briefing text as it appears in the "MISSION.INI" file. * 714 * * 715 * OUTPUT: Returns the response from the dialog. This will either be 1 if the video was * 716 * requested, or 0 if the return to game options button was selected. * 717 * * 718 * WARNINGS: none * 719 * * 720 * HISTORY: * 721 * 06/23/1995 JLB : Created. * 722 * 08/06/1995 JLB : Uses preloaded briefing text. * 723 *=============================================================================================*/ 724 bool Restate_Mission(char const * name, int button1, int button2) 725 { 726 if (name) { 727 #ifdef JAPANESE 728 char fname[14]; 729 strcpy(fname, name); 730 strcat(fname,".CPS"); 731 732 if(CCFileClass(fname).Is_Available()) { 733 CCMessageBox box(TXT_NONE, true); 734 return(box.Process(fname, button1, button2)); 735 } 736 #else 737 /* 738 ** Make sure that if there is no briefing movie, that the briefing text is 739 ** the only option available. 740 */ 741 bool brief = true; 742 #ifdef NEWMENU 743 char buffer[25]; 744 char buffer1[25]; 745 sprintf(buffer, "%s.VQA", BriefMovie); 746 sprintf(buffer1, "%s.VQA", ActionMovie); 747 CCFileClass file1(buffer); 748 CCFileClass file2(buffer1); 749 if (!file1.Is_Available() && !file2.Is_Available()) { 750 button1 = TXT_OK; 751 button2 = TXT_NONE; 752 brief = false; 753 } 754 #endif 755 756 /* 757 ** If mission object text was found, then display it. 758 */ 759 if (strlen(BriefingText)) { 760 static char _buff[512]; 761 762 strcpy(_buff, BriefingText); 763 // strcpy(_ShapeBuffer, BriefingText); 764 765 bool hidden = Get_Mouse_State(); 766 if (hidden) Show_Mouse(); 767 768 if (CCMessageBox(TXT_OBJECTIVE).Process(_buff, button1, button2)) { 769 if (hidden) Hide_Mouse(); 770 return(true); 771 } 772 if (hidden) Hide_Mouse(); 773 if (!brief) return(true); 774 return(false); 775 } 776 #endif 777 } 778 return(false); 779 } 780 781 void Fixup_Scenario(void) 782 { 783 /* 784 ** "Fraidycat" civilians avoid wandering into Tiberium for SCG08EB, since they're mission-critical. 785 */ 786 bool is_scg08ea = GameToPlay == GAME_NORMAL && PlayerPtr->ActLike == HOUSE_GOOD && Scenario == 8 && ScenVar == SCEN_VAR_B; 787 for (InfantryType index = INFANTRY_FIRST; index < INFANTRY_COUNT; index++) { 788 InfantryTypeClass& infantry_type = (InfantryTypeClass&)InfantryTypeClass::As_Reference(index); 789 if (infantry_type.IsFraidyCat) { 790 infantry_type.IsAvoidingTiberium = is_scg08ea; 791 } 792 } 793 794 /* 795 ** Laser-firing Orcas in the PATSUX secret mission 796 */ 797 if (GameToPlay == GAME_NORMAL && Scenario == 72) { 798 ((AircraftTypeClass&)AircraftTypeClass::As_Reference(AIRCRAFT_ORCA)).Primary = WEAPON_OBELISK_LASER; 799 } else { 800 ((AircraftTypeClass&)AircraftTypeClass::As_Reference(AIRCRAFT_ORCA)).Primary = WEAPON_DRAGON; 801 } 802 803 /* 804 ** Modern Balance 805 */ 806 if (Special.ModernBalance) { 807 /* 808 ** GDI Weapons Factory has 30% more health. 809 */ 810 ((BuildingTypeClass&)BuildingTypeClass::As_Reference(STRUCT_WEAP)).MaxStrength = 520; 811 812 /* 813 ** Repair Pad is a pre-requisite for the APC. 814 */ 815 ((UnitTypeClass&)UnitTypeClass::As_Reference(UNIT_APC)).Pre |= STRUCTF_REPAIR; 816 } else { 817 ((BuildingTypeClass&)BuildingTypeClass::As_Reference(STRUCT_WEAP)).MaxStrength = 400; 818 ((UnitTypeClass&)UnitTypeClass::As_Reference(UNIT_APC)).Pre &= ~STRUCTF_REPAIR; 819 } 820 }