INIT.CPP (129987B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 16 /* $Header: /CounterStrike/INIT.CPP 8 3/14/97 5:15p Joe_b $ */ 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 : INIT.CPP * 24 * * 25 * Programmer : Joe L. Bostic * 26 * * 27 * Start Date : January 20, 1992 * 28 * * 29 *---------------------------------------------------------------------------------------------* 30 * Functions: * 31 * Anim_Init -- Initialize the VQ animation control structure. * 32 * Bootstrap -- Perform the initial bootstrap procedure. * 33 * Calculate_CRC -- Calculates a one-way hash from a data block. * 34 * Init_Authorization -- Verifies that the player is authorized to play the game. * 35 * Init_Bootstrap_Mixfiles -- Registers and caches any mixfiles needed for bootstrapping. * 36 * Init_Bulk_Data -- Initialize the time-consuming mixfile caching. * 37 * Init_CDROM_Access -- Initialize the CD-ROM access handler. * 38 * Init_Color_Remaps -- Initialize the text remap tables. * 39 * Init_Expansion_Files -- Fetch any override expansion mixfiles. * 40 * Init_Fonts -- Initialize all the game font pointers. * 41 * Init_Game -- Main game initialization routine. * 42 * Init_Heaps -- Initialize the game heaps and buffers. * 43 * Init_Keys -- Initialize the cryptographic keys. * 44 * Init_Mouse -- Initialize the mouse system. * 45 * Init_One_Time_Systems -- Initialize internal pointers to the bulk data. * 46 * Init_Random -- Initializes the random-number generator * 47 * Init_Secondary_Mixfiles -- Register and cache secondary mixfiles. * 48 * Load_Recording_Values -- Loads recording values from recording file * 49 * Load_Title_Page -- Load the background art for the title page. * 50 * Obfuscate -- Sufficiently transform parameter to thwart casual hackers. * 51 * Parse_Command_Line -- Parses the command line parameters. * 52 * Parse_INI_File -- Parses CONQUER.INI for special options * 53 * Play_Intro -- plays the introduction & logo movies * 54 * Save_Recording_Values -- Saves recording values to a recording file * 55 * Select_Game -- The game's main menu * 56 * Load_Prolog_Page -- Loads the special pre-prolog "please wait" page. * 57 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 58 59 #include "function.h" 60 #include "loaddlg.h" 61 #ifdef WIN32 62 #ifdef WINSOCK_IPX 63 #include "WSProto.h" 64 #include "WSPUDP.h" 65 #include "WSPIPX.h" 66 #include "internet.h" 67 #else //WINSOCK_IPX 68 #include "tcpip.h" 69 #endif //WINSOCK_IPX 70 71 #endif 72 #include <conio.h> 73 #include <dos.h> 74 #ifndef WIN32 75 #include <sys\timeb.h> 76 #endif 77 #include "ccdde.h" 78 79 #include <time.h> 80 81 #ifdef DONGLE 82 #include "cbn_.h" 83 #endif 84 85 #ifdef MPEGMOVIE // Denzil 6/25/98 86 #include "mpgset.h" 87 #endif 88 89 RemapControlType SidebarScheme; 90 91 //#include "WolDebug.h" 92 93 #ifdef CHEAT_KEYS 94 extern bool bNoMovies; 95 #endif 96 97 /**************************************** 98 ** Function prototypes for this module ** 99 *****************************************/ 100 static void Play_Intro(bool sequenced=false); 101 static void Init_Color_Remaps(void); 102 static void Init_Heaps(void); 103 static void Init_Expansion_Files(void); 104 static void Init_One_Time_Systems(void); 105 static void Init_Fonts(void); 106 static void Init_CDROM_Access(void); 107 static void Init_Bootstrap_Mixfiles(void); 108 static void Init_Secondary_Mixfiles(void); 109 static void Init_Mouse(void); 110 static void Bootstrap(void); 111 //static void Init_Authorization(void); 112 static void Init_Bulk_Data(void); 113 static void Init_Keys(void); 114 115 extern int UnitBuildPenalty; 116 117 extern "C" { 118 extern long RandNumb; 119 } 120 #ifndef WIN32 121 static int UsePageFaultHandler = 1; // 1 = install PFH 122 #endif //WIN32 123 124 //extern int SimRandIndex; 125 void Init_Random(void); 126 127 #define ATTRACT_MODE_TIMEOUT 3600 // timeout for attract mode 128 129 bool Load_Recording_Values(CCFileClass & file); 130 bool Save_Recording_Values(CCFileClass & file); 131 132 #ifdef WOLAPI_INTEGRATION 133 extern int WOL_Main(); 134 #include "WolapiOb.h" 135 extern WolapiObject* pWolapi; 136 #endif 137 138 #ifdef FIXIT_VERSION_3 139 bool Expansion_Dialog( bool bCounterstrike ); 140 #endif 141 142 extern bool Is_Mission_Counterstrike (char *file_name); 143 144 /*********************************************************************************************** 145 * Load_Prolog_Page -- Loads the special pre-prolog "please wait" page. * 146 * * 147 * This loads and displays the prolog page that is displayed before the prolog movie * 148 * is played. This page is necessary because there is much loading that occurs before * 149 * the prolog movie is played and looking at a picture is better than looking at a blank * 150 * screen. * 151 * * 152 * INPUT: none * 153 * * 154 * OUTPUT: none * 155 * * 156 * WARNINGS: none * 157 * * 158 * HISTORY: * 159 * 11/03/1996 JLB : Created. * 160 *=============================================================================================*/ 161 static void Load_Prolog_Page(void) 162 { 163 Hide_Mouse(); 164 #ifdef WIN32 165 Load_Title_Screen("PROLOG.PCX", &HidPage, (unsigned char*)CCPalette.Get_Data()); 166 HidPage.Blit(SeenPage); 167 #else 168 Load_Picture("PROLOG.CPS", HidPage, HidPage, CCPalette, BM_DEFAULT); 169 HidPage.Blit(SeenPage); 170 #endif 171 CCPalette.Set(); 172 Show_Mouse(); 173 } 174 175 176 /*********************************************************************************************** 177 * Init_Game -- Main game initialization routine. * 178 * * 179 * Perform all one-time game initializations here. This includes all * 180 * allocations and table setups. The intro and other one-time startup * 181 * tasks are also performed here. * 182 * * 183 * INPUT: argc,argv -- Command line arguments. * 184 * * 185 * OUTPUT: none * 186 * * 187 * WARNINGS: Only call this ONCE! * 188 * * 189 * HISTORY: * 190 * 10/07/1992 JLB : Created. * 191 *=============================================================================================*/ 192 #include "sha.h" 193 //#include <locale.h> 194 bool Init_Game(int , char * []) 195 { 196 /* 197 ** Allocate the benchmark tracking objects only if the machine and 198 ** compile flags indicate. 199 */ 200 #ifdef CHEAT_KEYS 201 if (Processor() >= 2) { 202 Benches = new Benchmark [BENCH_COUNT]; 203 } 204 #endif 205 206 /* 207 ** Initialize the encryption keys. 208 */ 209 Init_Keys(); 210 211 /* 212 ** Bootstrap as much as possible before error-prone initializations are 213 ** performed. This bootstrap process will enable the error message 214 ** handler to function. 215 */ 216 Bootstrap(); 217 218 //////////////////////////////////////// 219 // The editor needs to not start the mouse up. - 7/22/2019 JAS 220 if (!RunningFromEditor) 221 { 222 /* 223 ** Check for an initialize a working mouse pointer. Display error and bail if 224 ** no mouse driver is installed. 225 */ 226 Init_Mouse(); 227 } 228 /* 229 ** Initialize access to the CD-ROM and ensure that the CD is inserted. This can, and 230 ** most likely will, result in a visible prompt. 231 */ 232 #if (0) //PG 233 Init_CDROM_Access(); 234 #endif 235 236 if (Special.IsFromInstall) { 237 Load_Prolog_Page(); 238 } 239 240 /* 241 ** Register and cache any secondary mixfiles. 242 */ 243 Init_Secondary_Mixfiles(); 244 245 /* 246 ** This is a special hack to initialize the heaps that must be in place before the 247 ** rules file is processed. These heaps should properly be allocated as a consequence 248 ** of processing the rules.ini file, but that is a bit beyond the capabilities of 249 ** the rule parser routine (currently). 250 */ 251 HouseTypes.Set_Heap(HOUSE_COUNT); 252 BuildingTypes.Set_Heap(STRUCT_COUNT); 253 AircraftTypes.Set_Heap(AIRCRAFT_COUNT); 254 InfantryTypes.Set_Heap(INFANTRY_COUNT); 255 BulletTypes.Set_Heap(BULLET_COUNT); 256 AnimTypes.Set_Heap(ANIM_COUNT); 257 UnitTypes.Set_Heap(UNIT_COUNT); 258 VesselTypes.Set_Heap(VESSEL_COUNT); 259 TemplateTypes.Set_Heap(TEMPLATE_COUNT); 260 TerrainTypes.Set_Heap(TERRAIN_COUNT); 261 OverlayTypes.Set_Heap(OVERLAY_COUNT); 262 SmudgeTypes.Set_Heap(SMUDGE_COUNT); 263 264 HouseTypeClass::Init_Heap(); 265 BuildingTypeClass::Init_Heap(); 266 AircraftTypeClass::Init_Heap(); 267 InfantryTypeClass::Init_Heap(); 268 BulletTypeClass::Init_Heap(); 269 AnimTypeClass::Init_Heap(); 270 UnitTypeClass::Init_Heap(); 271 VesselTypeClass::Init_Heap(); 272 TemplateTypeClass::Init_Heap(); 273 TerrainTypeClass::Init_Heap(); 274 OverlayTypeClass::Init_Heap(); 275 SmudgeTypeClass::Init_Heap(); 276 277 // Heap init moved here from globals.cpp. ST - 5/20/2019 278 CCPtr<AircraftClass>::Set_Heap(&Aircraft); 279 CCPtr<AnimClass>::Set_Heap(&Anims); 280 CCPtr<BuildingClass>::Set_Heap(&Buildings); 281 CCPtr<BulletClass>::Set_Heap(&Bullets); 282 CCPtr<FactoryClass>::Set_Heap(&Factories); 283 CCPtr<HouseClass>::Set_Heap(&Houses); 284 CCPtr<InfantryClass>::Set_Heap(&Infantry); 285 CCPtr<OverlayClass>::Set_Heap(&Overlays); 286 CCPtr<SmudgeClass>::Set_Heap(&Smudges); 287 CCPtr<TeamClass>::Set_Heap(&Teams); 288 CCPtr<TeamTypeClass>::Set_Heap(&TeamTypes); 289 CCPtr<TemplateClass>::Set_Heap(&Templates); 290 CCPtr<TerrainClass>::Set_Heap(&Terrains); 291 CCPtr<TriggerClass>::Set_Heap(&Triggers); 292 CCPtr<TriggerTypeClass>::Set_Heap(&TriggerTypes); 293 294 CCPtr<HouseTypeClass>::Set_Heap(&HouseTypes); 295 CCPtr<BuildingTypeClass>::Set_Heap(&BuildingTypes); 296 CCPtr<AircraftTypeClass>::Set_Heap(&AircraftTypes); 297 CCPtr<InfantryTypeClass>::Set_Heap(&InfantryTypes); 298 CCPtr<BulletTypeClass>::Set_Heap(&BulletTypes); 299 CCPtr<AnimTypeClass>::Set_Heap(&AnimTypes); 300 CCPtr<UnitTypeClass>::Set_Heap(&UnitTypes); 301 CCPtr<VesselTypeClass>::Set_Heap(&VesselTypes); 302 CCPtr<TemplateTypeClass>::Set_Heap(&TemplateTypes); 303 CCPtr<TerrainTypeClass>::Set_Heap(&TerrainTypes); 304 CCPtr<OverlayTypeClass>::Set_Heap(&OverlayTypes); 305 CCPtr<SmudgeTypeClass>::Set_Heap(&SmudgeTypes); 306 307 /* 308 ** Find and process any rules for this game. 309 */ 310 if (RuleINI.Load(CCFileClass("RULES.INI"), false)) { 311 Rule.Process(RuleINI); 312 } 313 #ifdef FIXIT_CSII // checked - ajw 9/28/98 314 // Aftermath runtime change 9/29/98 315 // This is safe to do, as only rules for aftermath units are included in this ini. 316 if (Is_Aftermath_Installed() == true) { 317 if (AftermathINI.Load(CCFileClass("AFTRMATH.INI"), false)) { 318 Rule.Process(AftermathINI); 319 } 320 } 321 #endif 322 323 Session.MaxPlayers = Rule.MaxPlayers; 324 325 /* 326 ** Initialize the game object heaps as well as other rules-dependant buffer allocations. 327 */ 328 Init_Heaps(); 329 330 /* 331 ** Initialize the animation system. 332 */ 333 Anim_Init(); 334 335 #ifndef FIXIT_VERSION_3 // WChat eliminated. 336 #ifdef WIN32 337 if (SpawnedFromWChat){ 338 Special.IsFromWChat = true; 339 } 340 #endif 341 #endif 342 343 #ifdef MPEGMOVIE // Denzil 6/15/98 344 if( Using_DVD() ) 345 { 346 #ifdef MCIMPEG 347 MciMovie = new MCIMovie(MainWindow); 348 #endif 349 MpgSettings = new MPGSettings(NULL); //RawFileClass(CONFIG_FILE_NAME)); 350 } 351 #endif 352 353 /* 354 ** Play the startup animation. 355 */ 356 if (!Special.IsFromInstall && !Special.IsFromWChat) { 357 VisiblePage.Clear(); 358 // Mono_Printf("Playing Intro\n"); 359 Play_Intro(); 360 memset(CurrentPalette, 0x01, 768); 361 WhitePalette.Set(); 362 } else { 363 memset(CurrentPalette, 0x01, 768); 364 } 365 366 /* 367 ** Initialize the text remap tables. 368 */ 369 Init_Color_Remaps(); 370 371 /* 372 ** Get authorization to access the game. 373 */ 374 // Init_Authorization(); 375 // Show_Mouse(); 376 377 /* 378 ** Set the logic page to the seenpage. 379 */ 380 Set_Logic_Page(SeenBuff); 381 382 /* 383 ** If not automatically launching into the intro, then display the title 384 ** page while the bulk data is cached. 385 */ 386 if (!Special.IsFromInstall) { 387 Load_Title_Page(true); 388 389 Hide_Mouse(); 390 Fancy_Text_Print(TXT_STAND_BY, 160*RESFACTOR, 120*RESFACTOR, &ColorRemaps[PCOLOR_DIALOG_BLUE], TBLACK, TPF_CENTER|TPF_TEXT|TPF_DROPSHADOW); 391 Show_Mouse(); 392 393 CCPalette.Set(FADE_PALETTE_SLOW); 394 Call_Back(); 395 } 396 397 /* 398 ** Initialize the bulk data. This takes the longest time and must be performed once 399 ** before the regular game starts. 400 */ 401 Init_Bulk_Data(); 402 403 /* 404 ** Initialize the multiplayer score values 405 */ 406 Session.GamesPlayed = 0; 407 Session.NumScores = 0; 408 Session.CurGame = 0; 409 for (int i = 0; i < MAX_MULTI_NAMES; i++) { 410 Session.Score[i].Name[0] = '\0'; 411 Session.Score[i].Wins = 0; 412 for (int j = 0; j < MAX_MULTI_GAMES; j++) { 413 Session.Score[i].Kills[j] = -1; // -1 = this player didn't play this round 414 } 415 } 416 417 /* 418 ** Copy the title screen's palette into the GamePalette & OriginalPalette, 419 ** because the options Load routine uses these palettes to set the brightness, etc. 420 */ 421 GamePalette = CCPalette; 422 // InGamePalette = CCPalette; 423 OriginalPalette = CCPalette; 424 425 /* 426 ** Read game options, so the GameSpeed is initialized when multiplayer 427 ** dialogs are invoked. (GameSpeed must be synchronized between systems.) 428 */ 429 Options.Load_Settings(); 430 431 /* 432 ** Initialise the color lookup tables for the chronal vortex 433 */ 434 ChronalVortex.Stop(); 435 ChronalVortex.Setup_Remap_Tables(Scen.Theater); 436 437 /* 438 ** Clear out name overrides array 439 */ 440 #ifdef FIXIT_NAME_OVERRIDE 441 for (int index = 0; index < ARRAY_SIZE(NameOverride); index++) { 442 NameOverride[index] = NULL; 443 NameIDOverride[index] = 0; 444 } 445 #endif //FIXIT_NAME_OVERRIDE 446 447 return(true); 448 } 449 450 #ifdef WINSOCK_IPX // Steve Tall missed this one - ajw 451 extern bool Get_Broadcast_Addresses (void); 452 #endif 453 454 /*********************************************************************************************** 455 * Select_Game -- The game's main menu * 456 * * 457 * INPUT: * 458 * fade if true, will fade the palette in gradually * 459 * * 460 * OUTPUT: * 461 * none. * 462 * * 463 * WARNINGS: * 464 * none. * 465 * * 466 * HISTORY: * 467 * 06/05/1995 BRR : Created. * 468 *=============================================================================================*/ 469 bool Select_Game(bool fade) 470 { 471 // Enums in Select_Game() must match order of buttons in Main_Menu(). 472 #ifdef FIXIT_VERSION_3 473 enum { 474 SEL_TIMEOUT = -1, // main menu timeout--go into attract mode 475 SEL_NEW_SCENARIO_CS, // Expansion scenario to play. 476 SEL_NEW_SCENARIO_AM, // Expansion scenario to play. 477 SEL_START_NEW_GAME, // start a new game 478 SEL_LOAD_MISSION, // load a saved game 479 SEL_MULTIPLAYER_GAME, // play modem/null-modem/network game 480 SEL_INTRO, // couch-potato mode 481 SEL_EXIT, // exit to DOS 482 SEL_FAME, // view the hall o' fame 483 SEL_NONE, // placeholder default value 484 }; 485 #else // FIXIT_VERSION_3 486 enum { 487 SEL_TIMEOUT = -1, // main menu timeout--go into attract mode 488 SEL_NEW_SCENARIO, // Expansion scenario to play. 489 SEL_START_NEW_GAME, // start a new game 490 #if defined(WIN32) && !defined(INTERNET_OFF) // Denzil 5/1/98 - Internet play 491 SEL_INTERNET, 492 #endif //WIN32 493 //#if defined(MPEGMOVIE) // Denzil 6/25/98 494 // SEL_MOVIESETTINGS, 495 //#endif 496 SEL_LOAD_MISSION, // load a saved game 497 SEL_MULTIPLAYER_GAME, // play modem/null-modem/network game 498 SEL_INTRO, // couch-potato mode 499 SEL_EXIT, // exit to DOS 500 SEL_FAME, // view the hall o' fame 501 SEL_NONE, // placeholder default value 502 }; 503 #endif // FIXIT_VERSION_3 504 505 bool gameloaded=false; // Has the game been loaded from the menu? 506 int selection; // the default selection 507 bool process = true; // false = break out of while loop 508 bool display = true; 509 510 #ifdef DONGLE 511 /* These where added by ColinM for the dongle checking */ 512 short iRet = 0; 513 unsigned short iPortNr = 1; /* automatic port scan enabled */ 514 unsigned char cSCodeSER[] = "\x41\x42"; 515 unsigned long ulIdRet = 0; 516 unsigned char cBoxName[]= "\x00\x00"; 517 #endif 518 519 #ifdef FIXIT_CSII // checked - ajw 9/28/98 520 int cdcheck = 0; 521 bool cs = Is_Counterstrike_Installed(); 522 #endif 523 524 // #ifndef DVD // Denzil - We want the menu screen ajw No we don't 525 // if (Special.IsFromInstall) { 526 // display = false; 527 // } 528 // #endif 529 530 Show_Mouse(); 531 532 #ifdef FIXIT_CSII // checked - ajw 9/28/98 533 NewUnitsEnabled = SecretUnitsEnabled = 0; // Assume new units disabled, unless specifically .INI enabled or multiplayer negotiations enable it. 534 #endif 535 536 #ifndef WOLAPI_INTEGRATION 537 #ifdef WIN32 538 /* 539 ** Enable the DDE Server so we can get internet start game packets from WChat 540 */ 541 DDEServer.Enable(); 542 #endif //WIN32 543 #endif // !WOLAPI_INTEGRATION 544 545 /* 546 ** [Re]set any globals that need it, in preparation for a new scenario 547 */ 548 GameActive = true; 549 DoList.Init(); 550 #ifdef MIRROR_QUEUE 551 MirrorList.Init(); 552 #endif 553 OutList.Init(); 554 Frame = 0; 555 Scen.MissionTimer = 0; 556 Scen.MissionTimer.Stop(); 557 Scen.CDifficulty = DIFF_NORMAL; 558 Scen.Difficulty = DIFF_NORMAL; 559 PlayerWins = false; 560 PlayerLoses = false; 561 Session.ObiWan = false; 562 Debug_Unshroud = false; 563 Map.Set_Cursor_Shape(0); 564 Map.PendingObjectPtr = 0; 565 Map.PendingObject = 0; 566 Map.PendingHouse = HOUSE_NONE; 567 568 Session.ProcessTicks = 0; 569 Session.ProcessFrames = 0; 570 Session.DesiredFrameRate = 30; 571 #if(TIMING_FIX) 572 NewMaxAheadFrame1 = 0; 573 NewMaxAheadFrame2 = 0; 574 #endif 575 576 /* ColinM added to check for dongle */ 577 #ifdef DONGLE 578 iRet = CbN_BoxReady( iPortNr , cBoxName); 579 if (cBoxName[0] != 0xc5 && cBoxName[0] != 0xc9) 580 { 581 WWMessageBox().Process("Please ensure dongle is attached. Run the dongle batch file too.", TXT_OK); 582 Emergency_Exit(EXIT_FAILURE); 583 } 584 585 iRet = CbN_ReadSER( iPortNr, cSCodeSER, &ulIdRet); 586 if (ulIdRet != 0xa0095) 587 { 588 WWMessageBox().Process("Please ensure dongle is attached. Run the dongle batch file too.", TXT_OK); 589 Emergency_Exit(EXIT_FAILURE); 590 } 591 #endif 592 593 /* 594 ** Init multiplayer game scores. Let Wins accumulate; just init the current 595 ** Kills for this game. Kills of -1 means this player didn't play this round. 596 */ 597 for (int i = 0 ; i < MAX_MULTI_GAMES; i++) { 598 Session.Score[i].Kills[Session.CurGame] = -1; 599 } 600 601 /* 602 ** Set default mouse shape 603 */ 604 Map.Set_Default_Mouse(MOUSE_NORMAL, false); 605 606 /* 607 ** If the last game we played was a multiplayer game, jump right to that 608 ** menu by pre-setting 'selection'. 609 */ 610 if (Session.Type == GAME_NORMAL) { 611 selection = SEL_NONE; 612 } else { 613 selection = SEL_MULTIPLAYER_GAME; 614 } 615 616 /* 617 ** Main menu processing; only do this if we're not in editor mode. 618 */ 619 if (!Debug_Map) { 620 621 /* 622 ** Menu selection processing loop 623 */ 624 Theme.Queue_Song(THEME_CRUS); 625 626 /* 627 ** If we're playing back a recording, load all pertinent values & skip 628 ** the menu loop. Hide the now-useless mouse pointer. 629 */ 630 if (Session.Play && Session.RecordFile.Is_Available()) { 631 if (Session.RecordFile.Open(READ)) { 632 Load_Recording_Values(Session.RecordFile); 633 process = false; 634 Theme.Fade_Out(); 635 } else 636 Session.Play = false; 637 } 638 639 #ifndef FIXIT_VERSION_3 640 #if defined(WIN32) && !defined(INTERNET_OFF) // Denzil 5/1/98 - Internet play 641 /* 642 ** Handle case where we were spawned from Wchat 643 */ 644 if (SpawnedFromWChat) { 645 Special.IsFromInstall = false; //Dont play intro if we were spawned from wchat 646 selection = SEL_INTERNET; 647 Theme.Queue_Song(THEME_QUIET); 648 Session.Type = GAME_INTERNET; 649 display = false; 650 Set_Logic_Page(SeenBuff); 651 } 652 #endif //WIN32 653 #endif 654 655 while (process) { 656 657 /* 658 ** Redraw the title page if needed 659 */ 660 if (display) { 661 Hide_Mouse(); 662 663 /* 664 ** Display the title page; fade it in if this is the first time 665 ** through the loop, and the 'fade' flag is true 666 */ 667 Load_Title_Page(); 668 GamePalette = CCPalette; 669 670 HidPage.Blit(SeenPage); 671 // if (fade) { 672 // WhitePalette.Set(); 673 // CCPalette.Set(FADE_PALETTE_SLOW, Call_Back); 674 // fade = false; 675 // } else { 676 CCPalette.Set(); 677 // } 678 679 Set_Logic_Page(SeenBuff); 680 display = false; 681 Show_Mouse(); 682 } 683 else { 684 if (RunningAsDLL) { //PG 685 return true;; 686 } 687 } 688 689 /* 690 ** Display menu and fetch selection from player. 691 */ 692 if (Special.IsFromInstall) selection = SEL_START_NEW_GAME; 693 694 #ifndef WOLAPI_INTEGRATION 695 #if defined(WIN32) && !defined(INTERNET_OFF) // Denzil 5/1/98 - Internet play 696 /* 697 ** Handle case where we were spawned from Wchat and our start game 698 ** packet has already arrived 699 */ 700 if (Special.IsFromWChat && DDEServer.Get_MPlayer_Game_Info()) { 701 Check_From_WChat(NULL); 702 selection = SEL_MULTIPLAYER_GAME; 703 Theme.Queue_Song(THEME_QUIET); 704 Session.Type = GAME_INTERNET; 705 } else { 706 /* 707 ** We werent spawned but we could still receive a DDE packet from wchat 708 */ 709 if (DDEServer.Get_MPlayer_Game_Info()) { 710 Check_From_WChat(NULL); 711 /* 712 ** Make sure top and bottom of screen are clear in 640x480 mode 713 */ 714 if (ScreenHeight == 480) { 715 VisiblePage.Fill_Rect (0, 0, 639, 40, 0); 716 VisiblePage.Fill_Rect (0, 440, 639, 479, 0); 717 } 718 } 719 } 720 #endif //WIN32 721 #endif 722 723 #ifdef WOLAPI_INTEGRATION 724 if( pWolapi ) 725 selection = SEL_MULTIPLAYER_GAME; // We are returning from a game. 726 #endif 727 728 if (selection == SEL_NONE) { 729 #ifdef FIXIT_ANTS 730 AntsEnabled = false; 731 #endif 732 selection = Main_Menu(ATTRACT_MODE_TIMEOUT); 733 } 734 Call_Back(); 735 736 switch (selection) { 737 738 /* 739 ** Pick an expansion scenario. 740 */ 741 #ifdef FIXIT_VERSION_3 742 case SEL_NEW_SCENARIO_CS: 743 case SEL_NEW_SCENARIO_AM: 744 #else // FIXIT_VERSION_3 745 case SEL_NEW_SCENARIO: 746 #endif // FIXIT_VERSION_3 747 Scen.CarryOverMoney = 0; 748 IsTanyaDead = false; 749 SaveTanya = false; 750 751 #ifdef FIXIT_VERSION_3 752 if( selection == SEL_NEW_SCENARIO_CS ) 753 { 754 if(!Force_CD_Available(2)) { 755 selection = SEL_NONE; 756 break; 757 } 758 if(!Expansion_Dialog( true )){ 759 selection = SEL_NONE; 760 break; 761 } 762 } 763 else 764 { 765 if(!Force_CD_Available(3)) { 766 selection = SEL_NONE; 767 break; 768 } 769 if(!Expansion_Dialog( false )){ 770 selection = SEL_NONE; 771 break; 772 } 773 } 774 #else // FIXIT_VERSION_3 775 #ifdef FIXIT_CSII // checked - ajw 9/28/98 776 if (cs) { 777 cdcheck = 2; 778 } 779 if (Is_Aftermath_Installed()) { 780 if (!cdcheck) { 781 cdcheck = 3; 782 } else { 783 cdcheck = 4; // special case: means check for 3 or 4 784 } 785 } 786 if(!Force_CD_Available(cdcheck)) { 787 return(false); 788 } 789 #else 790 if(!Force_CD_Available(2)) { 791 return(false); 792 } 793 #endif 794 if(!Expansion_Dialog()){ 795 selection = SEL_NONE; 796 break; 797 } 798 #endif // FIXIT_VERSION_3 799 800 #ifdef FIXIT_DIFFICULTY 801 #ifdef FIXIT_CSII // checked - ajw 9/28/98 802 switch (Fetch_Difficulty(cdcheck >= 3)) { 803 #else 804 switch (Fetch_Difficulty()) { 805 #endif 806 case 0: 807 Scen.CDifficulty = DIFF_HARD; 808 Scen.Difficulty = DIFF_EASY; 809 break; 810 811 case 1: 812 Scen.CDifficulty = DIFF_HARD; 813 Scen.Difficulty = DIFF_NORMAL; 814 break; 815 816 case 2: 817 Scen.CDifficulty = DIFF_NORMAL; 818 Scen.Difficulty = DIFF_NORMAL; 819 break; 820 821 case 3: 822 Scen.CDifficulty = DIFF_EASY; 823 Scen.Difficulty = DIFF_NORMAL; 824 break; 825 826 case 4: 827 Scen.CDifficulty = DIFF_EASY; 828 Scen.Difficulty = DIFF_HARD; 829 break; 830 } 831 #endif 832 Theme.Fade_Out(); 833 Theme.Queue_Song(THEME_FIRST); 834 Session.Type = GAME_NORMAL; 835 process = false; 836 break; 837 838 /* 839 ** SEL_START_NEW_GAME: Play the game 840 */ 841 case SEL_START_NEW_GAME: 842 if (Special.IsFromInstall) { 843 Scen.CDifficulty = DIFF_NORMAL; 844 Scen.Difficulty = DIFF_NORMAL; 845 } else { 846 switch (Fetch_Difficulty()) { 847 case 0: 848 Scen.CDifficulty = DIFF_HARD; 849 Scen.Difficulty = DIFF_EASY; 850 break; 851 852 case 1: 853 Scen.CDifficulty = DIFF_HARD; 854 Scen.Difficulty = DIFF_NORMAL; 855 break; 856 857 case 2: 858 Scen.CDifficulty = DIFF_NORMAL; 859 Scen.Difficulty = DIFF_NORMAL; 860 break; 861 862 case 3: 863 Scen.CDifficulty = DIFF_EASY; 864 Scen.Difficulty = DIFF_NORMAL; 865 break; 866 867 case 4: 868 Scen.CDifficulty = DIFF_EASY; 869 Scen.Difficulty = DIFF_HARD; 870 break; 871 } 872 } 873 Scen.CarryOverMoney = 0; 874 BuildLevel = 10; 875 IsTanyaDead = false; 876 SaveTanya = false; 877 Whom = HOUSE_GOOD; 878 879 if (!Special.IsFromInstall) { 880 #ifdef FIXIT_ANTS 881 if (AntsEnabled) { 882 Scen.Set_Scenario_Name("SCA01EA.INI"); 883 } else { 884 #endif 885 #ifdef FIXIT_VERSION_3 886 switch (WWMessageBox().Process(TXT_CHOOSE, TXT_ALLIES, TXT_CANCEL, TXT_SOVIET)) { 887 case 2: 888 Scen.Set_Scenario_Name("SCU01EA.INI"); 889 break; 890 default: 891 selection = SEL_NONE; 892 continue; 893 #else 894 switch (WWMessageBox().Process(TXT_CHOOSE, TXT_ALLIES, TXT_SOVIET)) { 895 case 1: 896 Scen.Set_Scenario_Name("SCU01EA.INI"); 897 break; 898 default: 899 #endif 900 case 0: 901 Scen.Set_Scenario_Name("SCG01EA.INI"); 902 break; 903 904 } 905 #ifdef FIXIT_ANTS 906 } 907 #endif 908 Theme.Fade_Out(); 909 Load_Title_Page(); 910 } else { 911 Theme.Fade_Out(); 912 #ifdef DVD // Denzil ajw Presumably a bug fix. 913 Choose_Side(); 914 Hide_Mouse(); 915 #else 916 Hide_Mouse(); 917 Choose_Side(); 918 #endif 919 if (CurrentCD == 0) { 920 Scen.Set_Scenario_Name("SCG01EA.INI"); 921 } else { 922 Scen.Set_Scenario_Name("SCU01EA.INI"); 923 } 924 } 925 926 Session.Type = GAME_NORMAL; 927 process = false; 928 break; 929 930 #ifndef FIXIT_VERSION_3 // Removed button from main menu. 931 #if defined(WIN32) && !defined(INTERNET_OFF) // Denzil 5/1/98 - Internet play 932 /* 933 ** Internet game is requested 934 */ 935 case SEL_INTERNET: 936 /* 937 ** Only call up the internet menu code if we dont already have connect info from WChat 938 */ 939 if (!DDEServer.Get_MPlayer_Game_Info()) { 940 if (Do_The_Internet_Menu_Thang() && DDEServer.Get_MPlayer_Game_Info()) { 941 Check_From_WChat(NULL); 942 selection = SEL_MULTIPLAYER_GAME; 943 display = false; 944 Session.Type = GAME_INTERNET; 945 } else { 946 selection = SEL_NONE; 947 display = true; 948 } 949 } else { 950 Check_From_WChat(NULL); 951 display = false; 952 Session.Type = GAME_INTERNET; 953 selection = SEL_MULTIPLAYER_GAME; 954 } 955 break; 956 #endif //WIN32 957 #endif 958 959 // #if defined(MPEGMOVIE) // Denzil 6/25/98 960 // case SEL_MOVIESETTINGS: 961 // MpgSettings->Dialog(); 962 // display = true; 963 // selection = SEL_NONE; 964 // break; 965 // #endif 966 967 /* 968 ** Load a saved game. 969 */ 970 case SEL_LOAD_MISSION: 971 if (LoadOptionsClass(LoadOptionsClass::LOAD).Process()) { 972 Theme.Queue_Song(THEME_FIRST); 973 process = false; 974 gameloaded = true; 975 } else { 976 display = true; 977 selection = SEL_NONE; 978 } 979 break; 980 981 /* 982 ** SEL_MULTIPLAYER_GAME: set 'Session.Type' to NULL-modem, modem, or 983 ** network play. 984 */ 985 case SEL_MULTIPLAYER_GAME: 986 #ifdef WOLAPI_INTEGRATION 987 if( !pWolapi ) 988 { 989 #endif 990 switch (Session.Type) { 991 992 /* 993 ** If 'Session.Type' isn't already set up for a multiplayer game, 994 ** we must prompt the user for which type of multiplayer game 995 ** they want. 996 */ 997 case GAME_NORMAL: 998 Session.Type = Select_MPlayer_Game(); 999 if (Session.Type == GAME_NORMAL) { // 'Cancel' 1000 display = true; 1001 selection = SEL_NONE; 1002 } 1003 break; 1004 1005 case GAME_SKIRMISH: 1006 #if (0)//PG 1007 if ( !Com_Scenario_Dialog(true) ) { 1008 Session.Type = Select_MPlayer_Game(); 1009 if (Session.Type == GAME_NORMAL) { // user hit Cancel 1010 display = true; 1011 selection = SEL_NONE; 1012 } 1013 } 1014 else 1015 { 1016 // Ever hits? Session.Type set to GAME_SKIRMISH without user selecting in Select_MPlayer_Game()? 1017 #ifdef FIXIT_VERSION_3 1018 // If mission is Counterstrike, CS CD will be required. But aftermath units require AM CD. 1019 bAftermathMultiplayer = Is_Aftermath_Installed() && !Is_Mission_Counterstrike( Scen.ScenarioName ); 1020 // ajw I'll bet this was needed before also... 1021 Session.ScenarioIsOfficial = Session.Scenarios[Session.Options.ScenarioIndex]->Get_Official(); 1022 #endif 1023 } 1024 #endif//PG 1025 break; 1026 1027 case GAME_NULL_MODEM: 1028 case GAME_MODEM: 1029 #if (0) 1030 if ( Session.Type != GAME_SKIRMISH && NullModem.Num_Connections() ) { 1031 NullModem.Init_Send_Queue(); 1032 1033 if ((Session.Type == GAME_NULL_MODEM && 1034 Session.ModemType == MODEM_NULL_HOST) || 1035 (Session.Type == GAME_MODEM && 1036 Session.ModemType == MODEM_DIALER) ) { 1037 1038 if ( !Com_Scenario_Dialog() ) { 1039 Session.Type = Select_Serial_Dialog(); 1040 if (Session.Type == GAME_NORMAL) { // user hit Cancel 1041 display = true; 1042 selection = SEL_NONE; 1043 } 1044 } 1045 } else { 1046 if ( !Com_Show_Scenario_Dialog() ) { 1047 Session.Type = Select_Serial_Dialog(); 1048 if (Session.Type == GAME_NORMAL) { // user hit Cancel 1049 display = true; 1050 selection = SEL_NONE; 1051 } 1052 } 1053 } 1054 } else { 1055 Session.Type = Select_MPlayer_Game(); 1056 if (Session.Type == GAME_NORMAL) { // 'Cancel' 1057 display = true; 1058 selection = SEL_NONE; 1059 } 1060 } 1061 #endif 1062 break; 1063 1064 #ifndef WOLAPI_INTEGRATION 1065 #if defined(WIN32) && !defined(INTERNET_OFF) // Denzil 5/1/98 - Internet play 1066 /* 1067 ** Handle being spawned from WChat. Internet play based on IPX code. 1068 */ 1069 case GAME_INTERNET: // ajw No longer hit. 1070 if (Special.IsFromWChat) { 1071 /* 1072 ** Give myself focus. 1073 */ 1074 SetForegroundWindow ( MainWindow ); 1075 ShowWindow ( MainWindow, ShowCommand ); 1076 1077 #ifdef WINSOCK_IPX 1078 1079 if (PacketTransport ) delete PacketTransport; 1080 PacketTransport = new UDPInterfaceClass; 1081 assert ( PacketTransport != NULL); 1082 1083 if (PacketTransport->Init()) { 1084 WWDebugString ("RA95 - About to read multiplayer settings.\n"); 1085 Session.Read_MultiPlayer_Settings (); 1086 1087 WWDebugString ("RA95 - About to call Start_Server or Start_Client.\n"); 1088 PacketTransport->Start_Listening(); 1089 1090 /* 1091 ** Flush out any pending packets from a previous game. 1092 */ 1093 PacketTransport->Discard_In_Buffers(); 1094 PacketTransport->Discard_Out_Buffers(); 1095 1096 } else { 1097 delete PacketTransport; 1098 PacketTransport = NULL; 1099 WWDebugString ("RA95 - Winsock failed to initialise.\n"); 1100 Session.Type = GAME_NORMAL; 1101 selection = SEL_EXIT; 1102 Special.IsFromWChat = false; 1103 break; 1104 } 1105 1106 WWDebugString ("RA95 - About to call Init_Network.\n"); 1107 Init_Network(); 1108 1109 1110 #else //WINSOCK_IPX 1111 1112 WWDebugString ("RA95 - About to initialise Winsock.\n"); 1113 if (Winsock.Init()) { 1114 WWDebugString ("RA95 - About to read multiplayer settings.\n"); 1115 Session.Read_MultiPlayer_Settings (); 1116 Server = PlanetWestwoodIsHost; 1117 1118 WWDebugString ("RA95 - About to set addresses.\n"); 1119 Winsock.Set_Host_Address(PlanetWestwoodIPAddress); 1120 1121 WWDebugString ("RA95 - About to call Start_Server or Start_Client.\n"); 1122 if (Server) { 1123 Winsock.Start_Server(); 1124 } else { 1125 Winsock.Start_Client(); 1126 } 1127 1128 1129 /* 1130 ** Flush out any pending packets from a previous game. 1131 */ 1132 WWDebugString ("RA95 - About to flush packet queue.\n"); 1133 WWDebugString ("RA95 - Allocating scrap memory.\n"); 1134 char *temp_buffer = new char[1024]; 1135 1136 WWDebugString ("RA95 - Creating timer class instance.\n"); 1137 CountDownTimerClass ptimer; 1138 1139 WWDebugString ("RA95 - Entering read loop.\n"); 1140 while (Winsock.Read(temp_buffer, 1024)) { 1141 1142 WWDebugString ("RA95 - Discarding a packet.\n"); 1143 ptimer.Set (30, true); 1144 while (ptimer.Time()) {}; 1145 WWDebugString ("RA95 - Ready to check for more packets.\n"); 1146 1147 } 1148 WWDebugString ("RA95 - About to delete scrap memory.\n"); 1149 delete temp_buffer; 1150 1151 1152 1153 } else { 1154 WWDebugString ("RA95 - Winsock failed to initialise.\n"); 1155 Session.Type = GAME_NORMAL; 1156 selection = SEL_EXIT; 1157 Special.IsFromWChat = false; 1158 break; 1159 } 1160 #endif //WINSOCK_IPX 1161 WWDebugString ("RA95 - About to call Init_Network.\n"); 1162 Init_Network(); 1163 1164 if (DDEServer.Get_MPlayer_Game_Info()) { 1165 WWDebugString ("RA95 - About to call Read_Game_Options.\n"); 1166 Read_Game_Options( NULL ); 1167 } else { 1168 Read_Game_Options( "C&CSPAWN.INI" ); 1169 } 1170 #ifdef WINSOCK_IPX 1171 WWDebugString ("RA95 - About to set addresses.\n"); 1172 PacketTransport->Set_Broadcast_Address (PlanetWestwoodIPAddress); 1173 #endif //WINSOCK_IPX 1174 if (PlanetWestwoodIsHost) { 1175 1176 WWDebugString ("RA95 - About to call Server_Remote_Connect.\n"); 1177 if (Server_Remote_Connect()) { 1178 WWDebugString ("RA95 - Server_Remote_Connect returned success.\n"); 1179 break; 1180 } else { 1181 /* 1182 ** We failed to connect to the other player 1183 */ 1184 #ifdef WINSOCK_IPX 1185 delete PacketTransport; 1186 PacketTransport = NULL; 1187 #else //WINSOCK_IPX 1188 Winsock.Close(); 1189 #endif //WINSOCK_IPX 1190 Session.Type = GAME_NORMAL; 1191 selection = SEL_NONE; 1192 DDEServer.Delete_MPlayer_Game_Info(); // Make sure we dont go round in an infinite loop 1193 break; 1194 } 1195 } else { 1196 WWDebugString ("RA95 - About to call Client_Remote_Connect.\n"); 1197 if (Client_Remote_Connect()) { 1198 WWDebugString ("RA95 - Client_Remote_Connect returned success.\n"); 1199 break; 1200 } else { 1201 /* 1202 ** We failed to connect to the other player 1203 */ 1204 #ifdef WINSOCK_IPX 1205 delete PacketTransport; 1206 PacketTransport = NULL; 1207 #else //WINSOCK_IPX 1208 Winsock.Close(); 1209 #endif //WINSOCK_IPX 1210 Session.Type = GAME_NORMAL; 1211 selection = SEL_NONE; 1212 DDEServer.Delete_MPlayer_Game_Info(); // Make sure we dont go round in an infinite loop 1213 break; 1214 } 1215 } 1216 1217 } else { 1218 Session.Type = Select_MPlayer_Game(); 1219 if (Session.Type == GAME_NORMAL) { // 'Cancel' 1220 display = true; 1221 selection = SEL_NONE; 1222 } 1223 } 1224 break; 1225 1226 #endif //WIN32 1227 #endif // !WOLAPI_INTEGRATION 1228 1229 } 1230 #ifdef WOLAPI_INTEGRATION 1231 } // if( !pWolapi ) 1232 1233 if( pWolapi ) 1234 Session.Type = GAME_INTERNET; 1235 #endif 1236 //debugprint( "Session.Type = %i\n", Session.Type ); 1237 switch (Session.Type) { 1238 /* 1239 ** Modem, Null-Modem or internet 1240 */ 1241 case GAME_MODEM: 1242 case GAME_NULL_MODEM: 1243 #ifndef WOLAPI_INTEGRATION 1244 case GAME_INTERNET: 1245 #endif 1246 case GAME_SKIRMISH: 1247 Theme.Fade_Out(); 1248 process = false; 1249 #ifdef FIXIT_VERSION_3 1250 Options.ScoreVolume = Options.MultiScoreVolume; 1251 #else 1252 Options.ScoreVolume = 0; 1253 #endif 1254 break; 1255 1256 #ifdef WOLAPI_INTEGRATION // implies also WINSOCK_IPX 1257 case GAME_INTERNET: 1258 if( PacketTransport ) 1259 delete PacketTransport; 1260 PacketTransport = new UDPInterfaceClass; 1261 assert( PacketTransport != NULL ); 1262 if( PacketTransport->Init() ) 1263 { 1264 switch( WOL_Main() ) 1265 { 1266 case 1: 1267 // Start game. 1268 #ifdef FIXIT_VERSION_3 1269 Options.ScoreVolume = Options.MultiScoreVolume; 1270 #else 1271 Options.ScoreVolume = 0; 1272 #endif 1273 process = false; 1274 Theme.Fade_Out(); 1275 break; 1276 case 0: 1277 // User cancelled. 1278 Session.Type = GAME_NORMAL; 1279 display = true; 1280 selection = SEL_MULTIPLAYER_GAME; //SEL_NONE; 1281 delete PacketTransport; 1282 PacketTransport = NULL; 1283 break; 1284 case -1: 1285 // Patch was downloaded. Exit app. 1286 Theme.Fade_Out(); 1287 BlackPalette.Set( FADE_PALETTE_SLOW ); 1288 return false; 1289 } 1290 } 1291 else 1292 { 1293 Session.Type = GAME_NORMAL; 1294 display = true; 1295 selection = SEL_MULTIPLAYER_GAME; //SEL_NONE; 1296 delete PacketTransport; 1297 PacketTransport = NULL; 1298 } 1299 break; 1300 #endif 1301 1302 /* 1303 ** Network (IPX): start a new network game. 1304 */ 1305 case GAME_IPX: 1306 WWDebugString ("RA95 - Game type is IPX.\n"); 1307 /* 1308 ** Init network system & remote-connect 1309 */ 1310 #ifdef WINSOCK_IPX 1311 if (PacketTransport ) delete PacketTransport; 1312 // if (WWMessageBox().Process("Select a protocol to use for network play.", "UDP", "IPX")) { 1313 PacketTransport = new IPXInterfaceClass; 1314 assert ( PacketTransport != NULL); 1315 // }else{ 1316 // PacketTransport = new UDPInterfaceClass; //IPXInterfaceClass; 1317 // assert ( PacketTransport != NULL); 1318 // if (!Get_Broadcast_Addresses()) { 1319 // Session.Type = GAME_NORMAL; 1320 // display = true; 1321 // selection = SEL_NONE; 1322 // delete PacketTransport; 1323 // PacketTransport = NULL; 1324 // break; 1325 // } 1326 // } 1327 1328 #endif //WINSOCK_IPX 1329 WWDebugString ("RA95 - About to call Init_Network.\n"); 1330 if (Session.Type == GAME_IPX && Init_Network() && Remote_Connect()) { 1331 #ifdef FIXIT_VERSION_3 1332 Options.ScoreVolume = Options.MultiScoreVolume; 1333 #else 1334 Options.ScoreVolume = 0; 1335 #endif 1336 process = false; 1337 Theme.Fade_Out(); 1338 } else { // user hit cancel, or init failed 1339 Session.Type = GAME_NORMAL; 1340 display = true; 1341 selection = SEL_NONE; 1342 #ifdef WINSOCK_IPX 1343 delete PacketTransport; 1344 PacketTransport = NULL; 1345 #endif //WINSOCK_IPX 1346 } 1347 break; 1348 1349 #if(TEN) 1350 /* 1351 ** TEN: jump straight into the game 1352 */ 1353 case GAME_TEN: 1354 if (Init_TEN()) { 1355 #ifdef FIXIT_VERSION_3 1356 Options.ScoreVolume = Options.MultiScoreVolume; 1357 #else 1358 Options.ScoreVolume = 0; 1359 #endif 1360 process = false; 1361 Theme.Fade_Out(); 1362 } else { 1363 WWMessageBox().Process("Unable to initialize TEN!"); 1364 //Prog_End(); 1365 Emergency_Exit(1); 1366 } 1367 break; 1368 #endif // TEN 1369 1370 #if(MPATH) 1371 /* 1372 ** MPATH: jump straight into the game 1373 */ 1374 case GAME_MPATH: 1375 if (Init_MPATH()) { 1376 #ifdef FIXIT_VERSION_3 1377 Options.ScoreVolume = Options.MultiScoreVolume; 1378 #else 1379 Options.ScoreVolume = 0; 1380 #endif 1381 process = false; 1382 Theme.Fade_Out(); 1383 } else { 1384 WWMessageBox().Process("Unable to initialize MPATH!"); 1385 //Prog_End(); 1386 Emergency_Exit(1); 1387 } 1388 break; 1389 #endif // MPATH 1390 1391 } 1392 break; 1393 1394 /* 1395 ** Play a VQ 1396 */ 1397 case SEL_INTRO: 1398 Theme.Fade_Out(); 1399 if (Debug_Flag) { 1400 Play_Intro(Debug_Flag); 1401 } else { 1402 Hide_Mouse(); 1403 VisiblePage.Clear(); 1404 Show_Mouse(); 1405 Play_Movie(VQ_INTRO_MOVIE, THEME_NONE, true); // no transition picture to briefing 1406 Keyboard->Clear(); 1407 Play_Movie(VQ_SIZZLE, THEME_NONE, true); 1408 Play_Movie(VQ_SIZZLE2, THEME_NONE, true); 1409 // Play_Movie(VQ_INTRO_MOVIE, THEME_NONE, false); // has transitino picture to briefing 1410 } 1411 Theme.Queue_Song(THEME_CRUS); 1412 display = true; 1413 fade = true; 1414 selection = SEL_NONE; 1415 break; 1416 1417 /* 1418 ** Exit to DOS. 1419 */ 1420 case SEL_EXIT: 1421 Theme.Fade_Out(); 1422 BlackPalette.Set(FADE_PALETTE_SLOW); 1423 return(false); 1424 1425 /* 1426 ** Display the hall of fame. 1427 */ 1428 case SEL_FAME: 1429 break; 1430 1431 case SEL_TIMEOUT: 1432 if (Session.Attract && Session.RecordFile.Is_Available()) { 1433 Session.Play = true; 1434 if (Session.RecordFile.Open(READ)) { 1435 Load_Recording_Values(Session.RecordFile); 1436 process = false; 1437 Theme.Fade_Out(); 1438 } else { 1439 Session.Play = false; 1440 selection = SEL_NONE; 1441 } 1442 } else { 1443 selection = SEL_NONE; 1444 } 1445 break; 1446 1447 default: 1448 break; 1449 } 1450 } 1451 } else { 1452 1453 /* 1454 ** For Debug_Map (editor) mode to load scenario 1455 */ 1456 Scen.Set_Scenario_Name("SCG01EA.INI"); 1457 } 1458 1459 /* 1460 ** Don't carry stray keystrokes into game. 1461 */ 1462 Keyboard->Clear(); 1463 1464 /* 1465 ** Initialize the random number generator(s) 1466 */ 1467 Init_Random(); 1468 1469 /* 1470 ** Save initialization values if we're recording this game. 1471 */ 1472 if (Session.Record) { 1473 if (Session.RecordFile.Open(WRITE)) { 1474 Save_Recording_Values(Session.RecordFile); 1475 } else { 1476 Session.Record = false; 1477 } 1478 } 1479 1480 #ifdef FIXIT_CSII // checked - ajw 9/28/98 1481 switch(Session.Type) { 1482 case GAME_MODEM: 1483 case GAME_NULL_MODEM: 1484 case GAME_IPX: 1485 #ifdef FIXIT_VERSION_3 1486 if( !bAftermathMultiplayer ) { 1487 #else 1488 if (PlayingAgainstVersion < VERSION_AFTERMATH_CS) { 1489 #endif 1490 NewUnitsEnabled = SecretUnitsEnabled = false; 1491 } else { 1492 NewUnitsEnabled = true; 1493 } 1494 // debugprint( "Non Internet game: NewUnitsEnabled = %i\n", NewUnitsEnabled ); 1495 break; 1496 case GAME_INTERNET: 1497 #if (0) 1498 if( !pWolapi ) 1499 { 1500 // debugprint( "pWolapi is null on internet game!" ); 1501 Fatal( "pWolapi is null on internet game!" ); 1502 } 1503 //if( pWolapi->bEnableNewAftermathUnits ) 1504 if( bAftermathMultiplayer ) 1505 NewUnitsEnabled = true; 1506 else 1507 NewUnitsEnabled = SecretUnitsEnabled = false; 1508 // debugprint( "Internet game: NewUnitsEnabled = %i\n", NewUnitsEnabled ); 1509 #endif 1510 break; 1511 default: 1512 break; 1513 } 1514 #endif 1515 /* 1516 ** Load the scenario. Specify variation 'A' for the editor; for the game, 1517 ** don't specify a variation, to make 'Set_Scenario_Name()' pick a random one. 1518 ** Skip this if we've already loaded a save-game. 1519 */ 1520 if (!gameloaded && !Session.LoadGame) { 1521 // if (Debug_Map) { 1522 // Set_Scenario_Name(Scen.ScenarioName, Scen.Scenario, Scen.ScenPlayer, Scen.ScenDir, SCEN_VAR_A); 1523 // } else { 1524 // Set_Scenario_Name(Scen.ScenarioName, Scen.Scenario, Scen.ScenPlayer, Scen.ScenDir); 1525 // } 1526 1527 /* 1528 ** Start_Scenario() changes the palette; so, fade out & clear the screen 1529 ** before calling it. 1530 */ 1531 Hide_Mouse(); 1532 1533 if (selection != SEL_START_NEW_GAME) { 1534 BlackPalette.Set(FADE_PALETTE_MEDIUM, Call_Back); 1535 #ifdef WIN32 1536 HiddenPage.Clear(); 1537 VisiblePage.Clear(); 1538 #else 1539 HidPage.Clear(); 1540 SeenPage.Clear(); 1541 #endif //WIN32 1542 } 1543 Show_Mouse(); 1544 //Mono_Printf("About to call Start Scenario with %s\n", Scen.ScenarioName); 1545 if (!Start_Scenario(Scen.ScenarioName)) { 1546 return(false); 1547 } 1548 if (Special.IsFromInstall) Show_Mouse(); 1549 Special.IsFromInstall = false; 1550 } 1551 1552 /* 1553 ** For multiplayer games, initialize the inter-player message system. 1554 ** Do this after loading the scenario, so the map's upper-left corner is 1555 ** properly set. 1556 */ 1557 Session.Messages.Init( 1558 Map.TacPixelX, Map.TacPixelY, // x,y for messages 1559 6, // max # msgs 1560 MAX_MESSAGE_LENGTH-14, // max msg length 1561 7 * RESFACTOR, // font height in pixels 1562 -1, -1, // x,y for edit line (appears above msgs) 1563 0,//BG 1, // enable edit overflow 1564 20, // min, 1565 MAX_MESSAGE_LENGTH - 14, // max for trimming overflow 1566 #ifdef WIN32 1567 Lepton_To_Pixel(Map.TacLeptonWidth)); // Width in pixels of buffer 1568 #else 1569 (320-SIDEBAR_WID)); // Width in pixels of buffer 1570 #endif 1571 1572 if (Session.Type != GAME_NORMAL && Session.Type != GAME_SKIRMISH && 1573 !Session.Play) { 1574 if (Session.Type == GAME_TEN) { 1575 #if(TEN) 1576 Session.Create_TEN_Connections(); 1577 #endif // TEN 1578 } else if (Session.Type == GAME_MPATH) { 1579 #if(MPATH) 1580 Session.Create_MPATH_Connections(); 1581 #endif 1582 } else { 1583 Session.Create_Connections(); 1584 } 1585 } 1586 1587 1588 /* 1589 ** If this isnt an internet game that set the unit build rate to its default value 1590 */ 1591 if (Session.Type != GAME_INTERNET){ 1592 UnitBuildPenalty = 100; 1593 } 1594 1595 /* 1596 ** Hide the SeenPage; force the map to render one frame. The caller can 1597 ** then fade the palette in. 1598 ** (If we loaded a game, this step will fade out the title screen. If we 1599 ** started a scenario, Start_Scenario() will have played a couple of VQ 1600 ** movies, which will have cleared the screen to black already.) 1601 */ 1602 Call_Back(); 1603 Hide_Mouse(); 1604 BlackPalette.Set(FADE_PALETTE_MEDIUM, Call_Back); 1605 // Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back); 1606 #ifdef WIN32 1607 HiddenPage.Clear(); 1608 VisiblePage.Clear(); 1609 #else 1610 HidPage.Clear(); 1611 SeenPage.Clear(); 1612 #endif //WIN32 1613 Show_Mouse(); 1614 Set_Logic_Page(SeenBuff); 1615 #ifdef WIN32 1616 /* 1617 ** Sidebar is always active in hi-res. 1618 */ 1619 if (!Debug_Map) { 1620 Map.SidebarClass::Activate(1); 1621 } 1622 #endif //WIN32 1623 Map.Flag_To_Redraw(); 1624 Call_Back(); 1625 Map.Render(); 1626 1627 #ifdef WOLAPI_INTEGRATION 1628 1629 //ajw debugging only 1630 // debugprint( "Debugging Session...\n" ); 1631 // debugprint( "Session.Players count is %i.\n", Session.Players.Count() ); 1632 for (i = 0; i < Session.Players.Count(); i++) 1633 { 1634 NetNumType net; 1635 NetNodeType node; 1636 Session.Players[i]->Address.Get_Address( net, node ); 1637 // debugprint( "Player %i, %s, color %i, ip %i.%i.%i.%i.%i.%i\n", i, Session.Players[i]->Name, 1638 // Session.Players[i]->Player.Color, node[0], node[1], node[2], node[3], node[4], node[5] ); 1639 } 1640 // debugprint( "PlanetWestwoodPortNumber is %i\n", PlanetWestwoodPortNumber ); 1641 1642 #endif 1643 1644 return(true); 1645 } 1646 1647 1648 /*********************************************************************************************** 1649 * Play_Intro -- plays the introduction & logo movies * 1650 * * 1651 * INPUT: * 1652 * * 1653 * OUTPUT: * 1654 * none. * 1655 * * 1656 * WARNINGS: * 1657 * none. * 1658 * * 1659 * HISTORY: * 1660 * 06/06/1995 BRR : Created. * 1661 * 05/08/1996 JLB : Modified for Red Alert and direction control. * 1662 *=============================================================================================*/ 1663 static void Play_Intro(bool sequenced) 1664 { 1665 static VQType _counter = VQ_FIRST; 1666 1667 Keyboard->Clear(); 1668 if (sequenced) { 1669 if (_counter <= VQ_FIRST) _counter = VQ_COUNT; 1670 if (_counter == VQ_COUNT) _counter--; 1671 if (_counter == VQ_REDINTRO) _counter--; 1672 if (_counter == VQ_TITLE) _counter--; 1673 Hide_Mouse(); 1674 VisiblePage.Clear(); 1675 Show_Mouse(); 1676 Play_Movie(VQType(_counter--), THEME_NONE); 1677 1678 // Show_Mouse(); 1679 } else { 1680 Hide_Mouse(); 1681 VisiblePage.Clear(); 1682 Show_Mouse(); 1683 #ifdef WIN32 1684 Play_Movie(VQ_REDINTRO, THEME_NONE, false); 1685 #else 1686 Play_Movie(VQ_TITLE, THEME_NONE, false); 1687 #endif 1688 } 1689 } 1690 1691 1692 /*********************************************************************************************** 1693 * Anim_Init -- Initialize the VQ animation control structure. * 1694 * * 1695 * VQ animations are controlled by a structure passed to the VQ player. This routine * 1696 * initializes the structure to values required by C&C. * 1697 * * 1698 * INPUT: none * 1699 * * 1700 * OUTPUT: none * 1701 * * 1702 * WARNINGS: Only need to call this routine once at the beginning of the game. * 1703 * * 1704 * HISTORY: * 1705 * 12/20/1994 JLB : Created. * 1706 *=============================================================================================*/ 1707 1708 #ifdef WIN32 1709 #ifdef MOVIE640 1710 //GraphicBufferClass VQ640(711, 400, (void *)NULL); 1711 #endif 1712 #endif 1713 void Anim_Init(void) 1714 { 1715 #if (0) 1716 #ifdef WIN32 1717 1718 /* Configure player with INI file */ 1719 VQA_DefaultConfig(&AnimControl); 1720 AnimControl.DrawFlags = VQACFGF_TOPLEFT; 1721 AnimControl.DrawFlags |= VQACFGF_BUFFER; 1722 //AnimControl.DrawFlags |= VQACFGF_NODRAW; 1723 //BG - M. Grayford says turn this off AnimControl.DrawFlags |= VQACFGF_NOSKIP; 1724 1725 AnimControl.DrawFlags |= VQACFGF_NOSKIP; 1726 AnimControl.FrameRate = -1; 1727 AnimControl.DrawRate = -1; 1728 AnimControl.DrawerCallback = VQ_Call_Back; 1729 AnimControl.ImageWidth = 320; 1730 AnimControl.ImageHeight = 200; 1731 AnimControl.ImageBuf = (unsigned char *)SysMemPage.Get_Offset(); 1732 #ifdef MOVIE640 1733 if(IsVQ640) { 1734 AnimControl.ImageWidth = 711; 1735 AnimControl.ImageHeight = 400; 1736 AnimControl.ImageBuf = (unsigned char *)VQ640.Get_Offset(); 1737 } 1738 #endif 1739 AnimControl.Vmode = 0; 1740 AnimControl.OptionFlags |= VQAOPTF_CAPTIONS|VQAOPTF_EVA; 1741 if (SlowPalette) { 1742 AnimControl.OptionFlags |= VQAOPTF_SLOWPAL; 1743 } 1744 AnimControl.SoundObject = SoundObject; 1745 AnimControl.PrimaryBufferPtr = PrimaryBufferPtr; 1746 if (MonoClass::Is_Enabled()) { 1747 AnimControl.OptionFlags |= VQAOPTF_MONO; 1748 } 1749 1750 #else //WIN32 1751 /* Configure player with INI file */ 1752 VQA_DefaultConfig(&AnimControl); 1753 // void const * font = Load_Font(FONT8); 1754 // AnimControl.EVAFont = (char *)font; 1755 // AnimControl.CapFont = (char *)font; 1756 AnimControl.DrawerCallback = VQ_Call_Back; 1757 AnimControl.ImageWidth = 320; 1758 AnimControl.ImageHeight = 200; 1759 AnimControl.Vmode = MCGA_MODE; 1760 AnimControl.VBIBit = VertBlank; 1761 AnimControl.DrawFlags |= VQACFGF_TOPLEFT; 1762 AnimControl.OptionFlags |= VQAOPTF_HMIINIT|VQAOPTF_CAPTIONS|VQAOPTF_EVA; 1763 // AnimControl.AudioBuf = (unsigned char *)HidPage.Get_Buffer(); 1764 // AnimControl.AudioBufSize = 32768U; 1765 AnimControl.DigiCard = NewConfig.DigitCard; 1766 AnimControl.HMIBufSize = 8192; 1767 AnimControl.DigiHandle = Get_Digi_Handle(); 1768 AnimControl.Volume = 0x00FF; 1769 AnimControl.AudioRate = 22050; 1770 // if (NewConfig.Speed) AnimControl.AudioRate = 11025; 1771 1772 if (!Debug_Quiet && Get_Digi_Handle() != -1) { 1773 AnimControl.OptionFlags |= VQAOPTF_AUDIO; 1774 } 1775 1776 if (MonoClass::Is_Enabled()) { 1777 AnimControl.OptionFlags |= VQAOPTF_MONO; 1778 } 1779 1780 #endif //WIN32 1781 #endif 1782 } 1783 1784 1785 /*********************************************************************************************** 1786 * Parse_Command_Line -- Parses the command line parameters. * 1787 * * 1788 * This routine should be called before the graphic mode is initialized. It examines the * 1789 * command line parameters and sets the appropriate globals. If there is an error, then * 1790 * it outputs a command summary and then returns false. * 1791 * * 1792 * INPUT: argc -- The number of command line arguments. * 1793 * * 1794 * argv -- Pointer to character string array that holds the individual arguments. * 1795 * * 1796 * OUTPUT: bool; Was the command line parsed successfully? * 1797 * * 1798 * WARNINGS: none * 1799 * * 1800 * HISTORY: * 1801 * 03/18/1995 JLB : Created. * 1802 *=============================================================================================*/ 1803 bool Parse_Command_Line(int argc, char * argv[]) 1804 { 1805 /* 1806 ** Parse the command line and set globals to reflect the parameters 1807 ** passed in. 1808 */ 1809 Whom = HOUSE_GOOD; 1810 Special.Init(); 1811 1812 Debug_Map = false; 1813 Debug_Unshroud = false; 1814 1815 for (int index = 1; index < argc; index++) { 1816 char * string; // Pointer to argument. 1817 long code = 0; 1818 1819 char arg_string[512]; 1820 int str_len = strlen(argv[index]); 1821 char *src = argv[index]; 1822 char *dest = arg_string; 1823 for (int i=0 ; i<str_len ; i++) { 1824 if (*src == '\"') { 1825 src++; 1826 } else { 1827 *dest++ = *src++; 1828 } 1829 } 1830 *dest++ = 0; 1831 string = arg_string; 1832 strupr(string); 1833 1834 //string = strupr(argv[index]); 1835 1836 /* 1837 ** Print usage text only if requested. 1838 */ 1839 if (stricmp("/?", string) == 0 || stricmp("-?", string) == 0 || stricmp("-h", string) == 0 || stricmp("/h", string) == 0) { 1840 /* 1841 ** Unrecognized command line parameter... Display usage 1842 ** and then exit. 1843 */ 1844 puts(TEXT_OPTIONS); 1845 return(false); 1846 } 1847 1848 1849 bool processed = true; 1850 long ob = Obfuscate(string); 1851 1852 /* 1853 ** Check to see if the parameter is a cheat enabling one. 1854 */ 1855 long const * optr = (const long*)&CheatCodes[0]; 1856 while (*optr) { 1857 if (*optr++ == ob) { 1858 Debug_Playtest = true; 1859 Debug_Flag = true; 1860 break; 1861 } 1862 } 1863 1864 /* 1865 ** Check to see if the parameter is a cheat enabling one. 1866 */ 1867 optr = (const long*)&PlayCodes[0]; 1868 while (*optr) { 1869 if (*optr++ == ob) { 1870 Debug_Playtest = true; 1871 Debug_Flag = true; 1872 break; 1873 } 1874 } 1875 1876 /* 1877 ** Check to see if the parameter is a scenario editor 1878 ** enabling one. 1879 */ 1880 optr = (const long*)&EditorCodes[0]; 1881 while (*optr) { 1882 if (*optr++ == ob) { 1883 Debug_Map = true; 1884 Debug_Unshroud = true; 1885 Debug_Flag = true; 1886 Debug_Playtest = true; 1887 break; 1888 } 1889 } 1890 1891 switch (ob) { 1892 1893 #ifdef VIRGIN_CHEAT_KEYS 1894 case PARM_PLAYTEST: 1895 Debug_Playtest = true; 1896 break; 1897 #endif 1898 1899 /* 1900 ** Special flag - is C&C being run from the install program? 1901 */ 1902 case PARM_INSTALL: 1903 Special.IsFromInstall = true; 1904 // If uncommented, will disable the <ESC> key during the first movie run. 1905 // BreakoutAllowed = false; 1906 break; 1907 1908 #if(TEN) 1909 case PARM_ALLOW_SOLO: 1910 Session.AllowSolo = 1; 1911 break; 1912 #endif 1913 1914 #if(MPATH) 1915 case PARM_ALLOW_SOLO: 1916 Session.AllowSolo = 1; 1917 break; 1918 #endif 1919 1920 default: 1921 processed = false; 1922 break; 1923 } 1924 if (processed) continue; 1925 1926 1927 #ifdef CHEAT_KEYS 1928 /* 1929 ** Scenario Editor Mode 1930 */ 1931 if (stricmp(string, "-CHECKMAP") == 0) { 1932 Debug_Check_Map = true; 1933 continue; 1934 } 1935 1936 #endif 1937 1938 /* 1939 ** File search path override. 1940 */ 1941 if (strstr(string, "-CD")) { 1942 CCFileClass::Set_Search_Drives(&string[3]); 1943 continue; 1944 } 1945 1946 #if (0) 1947 /* 1948 ** Build speed modifier 1949 */ 1950 if (strstr (string, "-UNITRATE:")){ 1951 int unit_rate; 1952 sscanf (string, "-UNITRATE:%d", &unit_rate); 1953 UnitBuildPenalty = unit_rate; 1954 } 1955 #endif //(0) 1956 1957 /* 1958 ** Specify destination connection for network play 1959 */ 1960 if (strstr(string, "-DESTNET")) { 1961 NetNumType net; 1962 NetNodeType node; 1963 1964 /* 1965 ** Scan the command-line string, pulling off each address piece 1966 */ 1967 int i = 0; 1968 char * p = strtok(string + 8, "."); 1969 while (p) { 1970 int x; 1971 1972 sscanf(p, "%x", &x); // convert from hex string to int 1973 if (i < 4) { 1974 net[i] = (char)x; // fill NetNum 1975 } else { 1976 node[i-4] = (char)x; // fill NetNode 1977 } 1978 i++; 1979 p = strtok(NULL, "."); 1980 } 1981 1982 /* 1983 ** If all the address components were successfully read, fill in the 1984 ** BridgeNet with a broadcast address to the network across the bridge. 1985 */ 1986 if (i >= 4) { 1987 Session.IsBridge = 1; 1988 memset(node, 0xff, 6); 1989 Session.BridgeNet = IPXAddressClass(net, node); 1990 } 1991 continue; 1992 } 1993 1994 /* 1995 ** Specify socket ID, as an offset from 0x4000. 1996 */ 1997 if (strstr(string, "-SOCKET")) { 1998 unsigned short socket; 1999 2000 socket = (unsigned short)(atoi(string + strlen("SOCKET"))); 2001 socket += 0x4000; 2002 if (socket >= 0x4000 && socket < 0x8000) { 2003 Ipx.Set_Socket (socket); 2004 } 2005 continue; 2006 } 2007 2008 /* 2009 ** Set the Net Stealth option 2010 */ 2011 if (strstr(string, "-STEALTH")) { 2012 Session.NetStealth = true; 2013 continue; 2014 } 2015 2016 /* 2017 ** Set the Net Protection option 2018 */ 2019 if (strstr(string, "-MESSAGES")) { 2020 Session.NetProtect = false; 2021 continue; 2022 } 2023 2024 /* 2025 ** Allow "attract" mode 2026 */ 2027 if (strstr(string, "-ATTRACT")) { 2028 Session.Attract = true; 2029 continue; 2030 } 2031 2032 2033 #ifdef WIN32 2034 /* 2035 ** Set screen to 640x480 instead of 640x400 2036 */ 2037 if (strstr(string, "-480")) { 2038 ScreenHeight = 480; 2039 continue; 2040 } 2041 2042 /* 2043 ** Check for spawn from WChat 2044 */ 2045 #ifndef FIXIT_VERSION_3 // WChat eliminated. 2046 if (strstr(string,"-WCHAT")){ 2047 SpawnedFromWChat = true; 2048 } 2049 #endif 2050 2051 #endif 2052 2053 #ifdef CHEAT_KEYS 2054 /* 2055 ** Specify the random number seed (for debugging) 2056 */ 2057 if (strstr(string, "-SEED")) { 2058 CustomSeed = (unsigned short)(atoi(string + strlen("SEED"))); 2059 continue; 2060 } 2061 2062 #ifndef WIN32 2063 /* 2064 ** Don't install Page Fault Handler (MUST use this for debugger) 2065 */ 2066 if (stricmp(string, "-NOPFS") == 0) { 2067 UsePageFaultHandler = 0; 2068 continue; 2069 } 2070 #endif 2071 2072 #endif 2073 2074 2075 #if(TEN) 2076 /* 2077 ** Enable TEN 2078 */ 2079 if (strstr(string, "TEN")) { 2080 2081 #ifdef CHEAT_KEYS 2082 Debug_Flag = true; 2083 MonoClass::Enable(); 2084 #endif 2085 2086 Session.Type = GAME_TEN; 2087 Special.IsFromInstall = false; 2088 // 2089 // Create the Ten network manager. This allows us to keep 2090 // the packet queues clean even while we're initializing the game, 2091 // so the queues don't fill up in case we're slow, or the user 2092 // didn't insert a CD. 2093 // 2094 Ten = new TenConnManClass(); 2095 Ten->Init(); 2096 strcpy(Session.OptionsFile, "OPTIONS.INI"); 2097 Ten->Flush_All(); 2098 continue; 2099 } 2100 2101 /* 2102 ** Set the game options filename 2103 */ 2104 if (strstr(string, "OPTIONS:")) { 2105 strcpy(Session.OptionsFile, string + 8); 2106 continue; 2107 } 2108 #endif // TEN 2109 2110 #if(MPATH) 2111 /* 2112 ** Enable MPATH 2113 */ 2114 if (strstr(string, "MPATH")) { 2115 2116 #ifdef CHEAT_KEYS 2117 Debug_Flag = true; 2118 MonoClass::Enable(); 2119 #endif 2120 2121 Session.Type = GAME_MPATH; 2122 Special.IsFromInstall = false; 2123 // 2124 // Create the MPath network manager. This allows us to keep 2125 // the packet queues clean even while we're initializing the game, 2126 // so the queues don't fill up in case we're slow, or the user 2127 // didn't insert a CD. 2128 // 2129 MPath = new MPlayerManClass(); 2130 MPath->Init(); 2131 strcpy(Session.OptionsFile, "OPTIONS.INI"); 2132 MPath->Flush_All(); 2133 continue; 2134 } 2135 2136 /* 2137 ** Set the game options filename 2138 */ 2139 if (strstr(string, "OPTIONS:")) { 2140 strcpy(Session.OptionsFile, string + 8); 2141 continue; 2142 } 2143 #endif // MPATH 2144 2145 2146 #ifdef NEVER 2147 /* 2148 ** Handle the prog init differently in this case. 2149 */ 2150 if (strstr(string, "-V")) { 2151 continue; 2152 } 2153 #endif 2154 2155 /* 2156 ** look for passed-in video mode to default to 2157 */ 2158 #ifndef WIN32 2159 if (strnicmp(string, "-V", strlen("-V")) == 0) { 2160 Set_Video_Mode(MCGA_MODE); // do this to get around first_time variable... 2161 Set_Original_Video_Mode(atoi(string+2)); 2162 continue; 2163 } 2164 #endif 2165 2166 #ifdef CHEAT_KEYS 2167 if (strstr(string,"-NOMOVIES")){ 2168 bNoMovies = true; 2169 } 2170 #endif 2171 2172 /* 2173 ** Special command line control parsing. 2174 */ 2175 if (strnicmp(string, "-X", strlen("-O")) == 0) { 2176 string += strlen("-X"); 2177 while (*string) { 2178 char code = *string++; 2179 switch (toupper(code)) { 2180 2181 #ifdef CHEAT_KEYS 2182 /* 2183 ** Monochrome debug screen enable. 2184 */ 2185 case 'M': 2186 MonoClass::Enable(); 2187 break; 2188 2189 /* 2190 ** Inert weapons -- no units take damage. 2191 */ 2192 case 'I': 2193 Special.IsInert = true; 2194 break; 2195 2196 /* 2197 ** Hussled recharge timer. 2198 */ 2199 case 'H': 2200 Special.IsSpeedBuild = true; 2201 break; 2202 2203 /* 2204 ** "Record" a multi-player game 2205 */ 2206 case 'X': 2207 Session.Record = 1; 2208 break; 2209 2210 /* 2211 ** "Play Back" a multi-player game 2212 */ 2213 case 'Y': 2214 Session.Play = 1; 2215 break; 2216 2217 /* 2218 ** Print lots of debug stuff about events & packets 2219 */ 2220 case 'P': 2221 Debug_Print_Events = true; 2222 break; 2223 #endif 2224 2225 /* 2226 ** Quiet mode override control. 2227 */ 2228 case 'Q': 2229 Debug_Quiet = true; 2230 break; 2231 2232 default: 2233 puts(TEXT_INVALID); 2234 return(false); 2235 } 2236 2237 } 2238 2239 continue; 2240 } 2241 } 2242 return(true); 2243 } 2244 2245 2246 /*********************************************************************************************** 2247 * Obfuscate -- Sufficiently transform parameter to thwart casual hackers. * 2248 * * 2249 * This routine borrows from CRC and PGP technology to sufficiently alter the parameter * 2250 * in order to make it difficult to reverse engineer the key phrase. This is designed to * 2251 * be used for hidden game options that will be released at a later time over Westwood's * 2252 * Web page or through magazine hint articles. * 2253 * * 2254 * This algorithm is cryptographically categorized as a "one way hash". * 2255 * * 2256 * Since this is a one way transformation, it becomes much more difficult to reverse * 2257 * engineer the pass phrase even if the resultant pass code is known. This has an added * 2258 * benefit of making this algorithm immune to traditional cryptographic attacks. * 2259 * * 2260 * The largest strength of this transformation algorithm lies in the restriction on the * 2261 * source vector being legal ASCII uppercase characters. This restriction alone makes even * 2262 * a simple CRC transformation practically impossible to reverse engineer. This algorithm * 2263 * uses far more than a simple CRC transformation to achieve added strength from advanced * 2264 * attack methods. * 2265 * * 2266 * INPUT: string -- Pointer to the key phrase that will be transformed into a code. * 2267 * * 2268 * OUTPUT: Returns with the code that the key phrase is translated into. * 2269 * * 2270 * WARNINGS: A zero length pass phrase results in a 0x00000000 result code. * 2271 * * 2272 * HISTORY: * 2273 * 08/19/1995 JLB : Created. * 2274 *=============================================================================================*/ 2275 long Obfuscate(char const * string) 2276 { 2277 char buffer[1024]; 2278 2279 if (!string) return(0); 2280 memset(buffer, '\xA5', sizeof(buffer)); 2281 2282 /* 2283 ** Copy key phrase into a working buffer. This hides any transformation done 2284 ** to the string. 2285 */ 2286 strncpy(buffer, string, sizeof(buffer)); 2287 buffer[sizeof(buffer)-1] = '\0'; 2288 int length = strlen(buffer); 2289 2290 /* 2291 ** Only upper case letters are significant. 2292 */ 2293 strupr(buffer); 2294 2295 /* 2296 ** Ensure that only visible ASCII characters compose the key phrase. This 2297 ** discourages the direct forced illegal character input method of attack. 2298 */ 2299 int index; 2300 for (index = 0; index < length; index++) { 2301 if (!isgraph(buffer[index])) { 2302 buffer[index] = 'A' + (index%26); 2303 } 2304 } 2305 2306 /* 2307 ** Increase the strength of even short pass phrases by extending the 2308 ** length to be at least a minimum number of characters. This helps prevent 2309 ** a weak pass phrase from compromising the obfuscation process. This 2310 ** process also forces the key phrase to be an even multiple of four. 2311 ** This is necessary to support the cypher process that occurs later. 2312 */ 2313 if (length < 16 || (length & 0x03)) { 2314 int maxlen = 16; 2315 if (((length+3) & 0x00FC) > maxlen) { 2316 maxlen = ((length+3) & 0x00FC); 2317 } 2318 for (index = length; index < maxlen; index++) { 2319 buffer[index] = 'A' + ((('?' ^ buffer[index-length]) + index) % 26); 2320 } 2321 length = index; 2322 buffer[length] = '\0'; 2323 } 2324 2325 /* 2326 ** Transform the buffer into a number. This transformation is character 2327 ** order dependant. 2328 */ 2329 long code = Calculate_CRC(buffer, length); 2330 2331 /* 2332 ** Record a copy of this initial transformation to be used in a later 2333 ** self referential transformation. 2334 */ 2335 long copy = code; 2336 2337 /* 2338 ** Reverse the character string and combine with the previous transformation. 2339 ** This doubles the workload of trying to reverse engineer the CRC calculation. 2340 */ 2341 strrev(buffer); 2342 code ^= Calculate_CRC(buffer, length); 2343 2344 /* 2345 ** Perform a self referential transformation. This makes a reverse engineering 2346 ** by using a cause and effect attack more difficult. 2347 */ 2348 code = code ^ copy; 2349 2350 /* 2351 ** Unroll and combine the code value into the pass phrase and then perform 2352 ** another self referential transformation. Although this is a trivial cypher 2353 ** process, it gives the sophisticated hacker false hope since the strong 2354 ** cypher process occurs later. 2355 */ 2356 strrev(buffer); // Restore original string order. 2357 for (index = 0; index < length; index++) { 2358 code ^= (unsigned char)buffer[index]; 2359 unsigned char temp = (unsigned char)code; 2360 buffer[index] ^= temp; 2361 code >>= 8; 2362 code |= (((long)temp)<<24); 2363 } 2364 2365 /* 2366 ** Introduce loss into the vector. This strengthens the key against traditional 2367 ** cryptographic attack engines. Since this also weakens the key against 2368 ** unconventional attacks, the loss is limited to less than 10%. 2369 */ 2370 for (index = 0; index < length; index++) { 2371 static unsigned char _lossbits[] = {0x00,0x08,0x00,0x20,0x00,0x04,0x10,0x00}; 2372 static unsigned char _addbits[] = {0x10,0x00,0x00,0x80,0x40,0x00,0x00,0x04}; 2373 2374 buffer[index] |= _addbits[index % (sizeof(_addbits)/sizeof(_addbits[0]))]; 2375 buffer[index] &= ~_lossbits[index % (sizeof(_lossbits)/sizeof(_lossbits[0]))]; 2376 } 2377 2378 /* 2379 ** Perform a general cypher transformation on the vector 2380 ** and use the vector itself as the cypher key. This is a variation on the 2381 ** cypher process used in PGP. It is a very strong cypher process with no known 2382 ** weaknesses. However, in this case, the cypher key is the vector itself and this 2383 ** opens up a weakness against attacks that have access to this transformation 2384 ** algorithm. The sheer workload of reversing this transformation should be enough 2385 ** to discourage even the most determined hackers. 2386 */ 2387 for (index = 0; index < length; index += 4) { 2388 short key1 = buffer[index]; 2389 short key2 = buffer[index+1]; 2390 short key3 = buffer[index+2]; 2391 short key4 = buffer[index+3]; 2392 short val1 = key1; 2393 short val2 = key2; 2394 short val3 = key3; 2395 short val4 = key4; 2396 2397 val1 *= key1; 2398 val2 += key2; 2399 val3 += key3; 2400 val4 *= key4; 2401 2402 short s3 = val3; 2403 val3 ^= val1; 2404 val3 *= key1; 2405 short s2 = val2; 2406 val2 ^= val4; 2407 val2 += val3; 2408 val2 *= key3; 2409 val3 += val2; 2410 2411 val1 ^= val2; 2412 val4 ^= val3; 2413 2414 val2 ^= s3; 2415 val3 ^= s2; 2416 2417 buffer[index] = val1; 2418 buffer[index+1] = val2; 2419 buffer[index+2] = val3; 2420 buffer[index+3] = val4; 2421 } 2422 2423 /* 2424 ** Convert this final vector into a cypher key code to be 2425 ** returned by this routine. 2426 */ 2427 code = Calculate_CRC(buffer, length); 2428 2429 /* 2430 ** Return the final code value. 2431 */ 2432 return(code); 2433 } 2434 2435 2436 /*********************************************************************************************** 2437 * Calculate_CRC -- Calculates a one-way hash from a data block. * 2438 * * 2439 * This routine is used to create a hash value from a data block. The algorithm is similar * 2440 * to a CRC, but is faster. * 2441 * * 2442 * INPUT: buffer -- Pointer to a buffer of data to be 'hashed'. * 2443 * * 2444 * len -- The length of the buffer to compute the hash upon. * 2445 * * 2446 * OUTPUT: Returns with a 32bit hash value calculated from the specified buffer. * 2447 * * 2448 * WARNINGS: none * 2449 * * 2450 * HISTORY: * 2451 * 03/02/1996 JLB : Created. * 2452 *=============================================================================================*/ 2453 extern "C" { 2454 long Calculate_CRC(void * buffer, long len) 2455 { 2456 return(CRCEngine()(buffer, len)); 2457 } 2458 } 2459 2460 2461 /*************************************************************************** 2462 * Init_Random -- Initializes the random-number generator * 2463 * * 2464 * INPUT: * 2465 * none. * 2466 * * 2467 * OUTPUT: * 2468 * none. * 2469 * * 2470 * WARNINGS: * 2471 * none. * 2472 * * 2473 * HISTORY: * 2474 * 12/04/1995 BRR : Created. * 2475 *=========================================================================*/ 2476 void Init_Random(void) 2477 { 2478 #ifdef WIN32 2479 2480 /* 2481 ** Gather some "random" bits from the system timer. Actually, only the 2482 ** low order millisecond bits are secure. The other bits could be 2483 ** easily guessed from the system clock (most clocks are fairly accurate 2484 ** and thus predictable). 2485 */ 2486 SYSTEMTIME t; 2487 GetSystemTime(&t); 2488 CryptRandom.Seed_Byte(t.wMilliseconds); 2489 CryptRandom.Seed_Bit(t.wSecond); 2490 CryptRandom.Seed_Bit(t.wSecond>>1); 2491 CryptRandom.Seed_Bit(t.wSecond>>2); 2492 CryptRandom.Seed_Bit(t.wSecond>>3); 2493 CryptRandom.Seed_Bit(t.wSecond>>4); 2494 CryptRandom.Seed_Bit(t.wMinute); 2495 CryptRandom.Seed_Bit(t.wMinute>>1); 2496 CryptRandom.Seed_Bit(t.wMinute>>2); 2497 CryptRandom.Seed_Bit(t.wMinute>>3); 2498 CryptRandom.Seed_Bit(t.wMinute>>4); 2499 CryptRandom.Seed_Bit(t.wHour); 2500 CryptRandom.Seed_Bit(t.wDay); 2501 CryptRandom.Seed_Bit(t.wDayOfWeek); 2502 CryptRandom.Seed_Bit(t.wMonth); 2503 CryptRandom.Seed_Bit(t.wYear); 2504 #else 2505 2506 /* 2507 ** Gather some "random" bits from the DOS mode timer. 2508 */ 2509 struct timeb t; 2510 ftime(&t); 2511 CryptRandom.Seed_Byte(t.millitm); 2512 CryptRandom.Seed_Byte(t.time); 2513 #endif 2514 2515 #ifdef FIXIT_MULTI_SAVE 2516 // 2517 // If we've loaded a multiplayer save game, return now; the random # 2518 // class is loaded along with ScenarioClass. 2519 // 2520 if (Session.LoadGame) { 2521 return; 2522 } 2523 2524 // 2525 // If we're playing a recording, the Seed is loaded in 2526 // Load_Recording_Values(). Just init the random # and return. 2527 // 2528 if (Session.Play) { 2529 RandNumb = Seed; 2530 Scen.RandomNumber = Seed; 2531 return; 2532 } 2533 #else 2534 /* 2535 ** Do nothing if we've loaded a multiplayer game, or we're playing back 2536 ** a recording; the random number generator is initialized by loading 2537 ** the game. 2538 */ 2539 if (Session.LoadGame || Session.Play) { 2540 RandNumb = Seed; 2541 Scen.RandomNumber = Seed; 2542 return; 2543 } 2544 #endif // FIXIT_MULTI_SAVE 2545 2546 /* 2547 ** Initialize the random number Seed. For multiplayer, this will have been done 2548 ** in the connection dialogs. For single-player games, AND if we're not playing 2549 ** back a recording, init the Seed to a random value. 2550 */ 2551 if (Session.Type == GAME_NORMAL || Session.Type == GAME_SKIRMISH && 2552 !Session.Play) { 2553 2554 /* 2555 ** Set the optional user-specified seed 2556 */ 2557 if (CustomSeed != 0) { 2558 Seed = CustomSeed; 2559 } else { 2560 srand(time(NULL)); 2561 Seed = rand(); 2562 } 2563 } 2564 2565 /* 2566 ** Initialize the random-number generators 2567 */ 2568 Scen.RandomNumber = Seed; 2569 RandNumb = Seed; 2570 } 2571 2572 2573 /*********************************************************************************************** 2574 * Load_Title_Page -- Load the background art for the title page. * 2575 * * 2576 * This routine will load the background art in a machine independent format. There is * 2577 * different art required for the hi-res and lo-res versions of the game. * 2578 * * 2579 * INPUT: visible -- Should the title page art be copied to the visible page by this * 2580 * routine? * 2581 * * 2582 * OUTPUT: none * 2583 * * 2584 * WARNINGS: Be sure the mouse is hidden if the image is to be copied to the visible page. * 2585 * * 2586 * HISTORY: * 2587 * 06/03/1996 JLB : Created. * 2588 *=============================================================================================*/ 2589 void Load_Title_Page(bool visible) 2590 { 2591 #ifdef WIN32 2592 Load_Title_Screen("TITLE.PCX", &HidPage, (unsigned char*)CCPalette.Get_Data()); 2593 if (visible) { 2594 HidPage.Blit(SeenPage); 2595 } 2596 #else 2597 Load_Picture("TITLE.CPS", HidPage, HidPage, CCPalette, BM_DEFAULT); 2598 if (visible) { 2599 HidPage.Blit(SeenPage); 2600 } 2601 #endif 2602 } 2603 2604 2605 /*********************************************************************************************** 2606 * Init_Color_Remaps -- Initialize the text remap tables. * 2607 * * 2608 * There are various color scheme remap tables that are dependant upon the color remap * 2609 * information embedded within the palette control file. This routine will fetch that * 2610 * data and build the text remap tables as indicated. * 2611 * * 2612 * INPUT: none * 2613 * * 2614 * OUTPUT: none * 2615 * * 2616 * WARNINGS: none * 2617 * * 2618 * HISTORY: * 2619 * 06/03/1996 JLB : Created. * 2620 * 09/11/2019 ST : The default resolution doesn't have to match the size of the palette image* 2621 *=============================================================================================*/ 2622 static void Init_Color_Remaps(void) 2623 { 2624 /* 2625 ** Setup the remap tables. PALETTE.CPS contains a special set of pixels in 2626 ** the upper-left corner. Each row of 16 pixels is one range of colors. The 2627 ** first row represents unity (the default color units are drawn in); rows 2628 ** after that are the remap colors. 2629 */ 2630 2631 #ifdef WIN32 2632 GraphicBufferClass temp_page(320, 200, (void*)NULL); 2633 temp_page.Clear(); 2634 Load_Picture("PALETTE.CPS", temp_page, temp_page, NULL, BM_DEFAULT); 2635 temp_page.Blit(HidPage); 2636 #else 2637 Load_Picture("PALETTE.CPS", HidPage, HidPage, NULL, BM_DEFAULT); 2638 #endif 2639 for (PlayerColorType pcolor = PCOLOR_FIRST; pcolor < PCOLOR_COUNT; pcolor++) { 2640 2641 unsigned char * ptr = ColorRemaps[pcolor].RemapTable; 2642 2643 for (int color = 0; color < 256; color++) { 2644 ptr[color] = color; 2645 } 2646 2647 int index; 2648 for (index = 0; index < 16; index++) { 2649 ptr[HidPage.Get_Pixel(index, 0)] = HidPage.Get_Pixel(index, pcolor); 2650 } 2651 for (index = 0; index < 6; index++) { 2652 ColorRemaps[pcolor].FontRemap[10+index] = HidPage.Get_Pixel(2+index, pcolor); 2653 } 2654 ColorRemaps[pcolor].BrightColor = WHITE; 2655 // ColorRemaps[pcolor].BrightColor = HidPage.Get_Pixel(1, pcolor); 2656 ColorRemaps[pcolor].Color = HidPage.Get_Pixel(4, pcolor); 2657 2658 ColorRemaps[pcolor].Shadow = HidPage.Get_Pixel(10, pcolor); 2659 ColorRemaps[pcolor].Background = HidPage.Get_Pixel(9, pcolor); 2660 ColorRemaps[pcolor].Corners = HidPage.Get_Pixel(7, pcolor); 2661 ColorRemaps[pcolor].Highlight = HidPage.Get_Pixel(4, pcolor); 2662 ColorRemaps[pcolor].Bright = HidPage.Get_Pixel(0, pcolor); 2663 ColorRemaps[pcolor].Underline = HidPage.Get_Pixel(0, pcolor); 2664 ColorRemaps[pcolor].Bar = HidPage.Get_Pixel(6, pcolor); 2665 2666 /* 2667 ** This must grab from column 4 because the multiplayer color dialog palette counts 2668 ** on this to be true. 2669 */ 2670 ColorRemaps[pcolor].Box = HidPage.Get_Pixel(4, pcolor); 2671 } 2672 2673 /* 12/9/2019 SKY - Swap Blue and Grey color remaps */ 2674 { 2675 RemapControlType temp; 2676 memcpy(&temp, &ColorRemaps[PCOLOR_BLUE], sizeof(RemapControlType)); 2677 memcpy(&ColorRemaps[PCOLOR_BLUE], &ColorRemaps[PCOLOR_GREY], sizeof(RemapControlType)); 2678 memcpy(&ColorRemaps[PCOLOR_GREY], &temp, sizeof(RemapControlType)); 2679 } 2680 2681 /* 2682 ** Now do the special dim grey scheme 2683 */ 2684 for (int color = 0; color < 256; color++) { 2685 GreyScheme.RemapTable[color] = color; 2686 } 2687 for (int index = 0; index < 6; index++) { 2688 GreyScheme.FontRemap[10+index] = HidPage.Get_Pixel(9+index, PCOLOR_GREY) & 0x00FF; 2689 } 2690 GreyScheme.BrightColor = HidPage.Get_Pixel(3, PCOLOR_GREY) & 0x00FF; 2691 GreyScheme.Color = HidPage.Get_Pixel(7, PCOLOR_GREY) & 0x00FF; 2692 2693 GreyScheme.Shadow = ColorRemaps[PCOLOR_GREY].RemapTable[HidPage.Get_Pixel(15, PCOLOR_GREY) & 0x00FF]; 2694 GreyScheme.Background = ColorRemaps[PCOLOR_GREY].RemapTable[HidPage.Get_Pixel(14, PCOLOR_GREY) & 0x00FF]; 2695 GreyScheme.Corners = ColorRemaps[PCOLOR_GREY].RemapTable[HidPage.Get_Pixel(13, PCOLOR_GREY) & 0x00FF]; 2696 GreyScheme.Highlight = ColorRemaps[PCOLOR_GREY].RemapTable[HidPage.Get_Pixel(9, PCOLOR_GREY) & 0x00FF]; 2697 GreyScheme.Bright = ColorRemaps[PCOLOR_GREY].RemapTable[HidPage.Get_Pixel(5, PCOLOR_GREY) & 0x00FF]; 2698 GreyScheme.Underline = ColorRemaps[PCOLOR_GREY].RemapTable[HidPage.Get_Pixel(5, PCOLOR_GREY) & 0x00FF]; 2699 GreyScheme.Bar = ColorRemaps[PCOLOR_GREY].RemapTable[HidPage.Get_Pixel(11, PCOLOR_GREY) & 0x00FF]; 2700 GreyScheme.Box = ColorRemaps[PCOLOR_GREY].RemapTable[HidPage.Get_Pixel(11, PCOLOR_GREY) & 0x00FF]; 2701 2702 /* 2703 ** Set up the metallic remap table for the font that prints over the tabs 2704 */ 2705 memset ((void*)&MetalScheme, 4, sizeof(MetalScheme)); 2706 for (int color_counter = 0; color_counter < 16; color_counter++) { 2707 MetalScheme.FontRemap[color_counter] = color_counter; 2708 } 2709 MetalScheme.FontRemap[1] = 128; 2710 MetalScheme.FontRemap[2] = 12; 2711 MetalScheme.FontRemap[3] = 13; 2712 MetalScheme.FontRemap[4] = 14; 2713 MetalScheme.Color = 128; 2714 MetalScheme.Background = 0; 2715 MetalScheme.Underline = 128; 2716 2717 /* 2718 ** Set up the font remap table for the mission briefing font 2719 */ 2720 for (int colr = 0; colr < 16; colr++) { 2721 ColorRemaps[PCOLOR_TYPE].FontRemap[colr] = HidPage.Get_Pixel(colr, PCOLOR_TYPE); 2722 } 2723 2724 ColorRemaps[PCOLOR_TYPE].Shadow = 11; 2725 ColorRemaps[PCOLOR_TYPE].Background = 10; 2726 ColorRemaps[PCOLOR_TYPE].Corners = 10; 2727 ColorRemaps[PCOLOR_TYPE].Highlight = 9; 2728 ColorRemaps[PCOLOR_TYPE].Bright = 15; 2729 ColorRemaps[PCOLOR_TYPE].Underline = 11; 2730 ColorRemaps[PCOLOR_TYPE].Bar = 11; 2731 ColorRemaps[PCOLOR_TYPE].Box = 10; 2732 ColorRemaps[PCOLOR_TYPE].BrightColor = 15; 2733 ColorRemaps[PCOLOR_TYPE].Color = 9; 2734 2735 GadgetClass::Set_Color_Scheme(&ColorRemaps[PCOLOR_DIALOG_BLUE]); 2736 // GadgetClass::Set_Color_Scheme(&ColorRemaps[PCOLOR_BLUE]); 2737 } 2738 2739 2740 /*********************************************************************************************** 2741 * Init_Heaps -- Initialize the game heaps and buffers. * 2742 * * 2743 * This routine will allocate the game heaps and buffers. The rules file has already been * 2744 * processed by the time that this routine is called. * 2745 * * 2746 * INPUT: none * 2747 * * 2748 * OUTPUT: none * 2749 * * 2750 * WARNINGS: none * 2751 * * 2752 * HISTORY: * 2753 * 06/03/1996 JLB : Created. * 2754 *=============================================================================================*/ 2755 static void Init_Heaps(void) 2756 { 2757 /* 2758 ** Initialize the game object heaps. 2759 */ 2760 Vessels.Set_Heap(Rule.VesselMax); 2761 Units.Set_Heap(Rule.UnitMax); 2762 Factories.Set_Heap(Rule.FactoryMax); 2763 Terrains.Set_Heap(Rule.TerrainMax); 2764 Templates.Set_Heap(Rule.TemplateMax); 2765 Smudges.Set_Heap(Rule.SmudgeMax); 2766 Overlays.Set_Heap(Rule.OverlayMax); 2767 Infantry.Set_Heap(Rule.InfantryMax); 2768 Bullets.Set_Heap(Rule.BulletMax); 2769 Buildings.Set_Heap(Rule.BuildingMax); 2770 Anims.Set_Heap(Rule.AnimMax); 2771 Aircraft.Set_Heap(Rule.AircraftMax); 2772 Triggers.Set_Heap(Rule.TriggerMax); 2773 TeamTypes.Set_Heap(Rule.TeamTypeMax); 2774 Teams.Set_Heap(Rule.TeamMax); 2775 Houses.Set_Heap(HOUSE_MAX); 2776 TriggerTypes.Set_Heap(Rule.TrigTypeMax); 2777 // Weapons.Set_Heap(Rule.WeaponMax); 2778 2779 /* 2780 ** Speech holding tank buffer. Since speech does not mix, it can be placed 2781 ** into a custom holding tank only as large as the largest speech file to 2782 ** be played. 2783 */ 2784 for (int index = 0; index < ARRAY_SIZE(SpeechBuffer); index++) { 2785 SpeechBuffer[index] = new char [SPEECH_BUFFER_SIZE]; 2786 SpeechRecord[index] = VOX_NONE; 2787 assert(SpeechBuffer[index] != NULL); 2788 } 2789 2790 /* 2791 ** Allocate the theater buffer block. 2792 */ 2793 TheaterBuffer = new Buffer(THEATER_BUFFER_SIZE); 2794 assert(TheaterBuffer != NULL); 2795 } 2796 2797 2798 /*********************************************************************************************** 2799 * Init_Expansion_Files -- Fetch any override expansion mixfiles. * 2800 * * 2801 * This routine will search for and register/cache any override mixfiles found. * 2802 * * 2803 * INPUT: none * 2804 * * 2805 * OUTPUT: none * 2806 * * 2807 * WARNINGS: none * 2808 * * 2809 * HISTORY: * 2810 * 06/03/1996 JLB : Created. * 2811 *=============================================================================================*/ 2812 static void Init_Expansion_Files(void) 2813 { 2814 /* 2815 ** Need to search the search paths. ST - 3/15/2019 2:18PM 2816 */ 2817 const char *path = ".\\"; 2818 char search_path[_MAX_PATH]; 2819 char scan_path[_MAX_PATH]; 2820 2821 for (int p = 0; p < 100; p++) { 2822 2823 strcpy(search_path, path); 2824 if (search_path[strlen(search_path) - 1] != '\\') { 2825 strcat(search_path, "\\"); 2826 } 2827 2828 strcpy(scan_path, search_path); 2829 strcat(scan_path, "SC*.MIX"); 2830 2831 WIN32_FIND_DATA find_data; 2832 memset(&find_data, 0, sizeof(find_data)); 2833 HANDLE file_handle = FindFirstFile(scan_path, &find_data); 2834 if (file_handle != INVALID_HANDLE_VALUE) 2835 { 2836 do 2837 { 2838 char *ptr = strdup(find_data.cFileName); 2839 new MFCD(ptr, &FastKey); 2840 } while (FindNextFile(file_handle, &find_data)); 2841 FindClose(file_handle); 2842 } 2843 2844 memset(&find_data, 0, sizeof(find_data)); 2845 strcpy(scan_path, search_path); 2846 strcat(scan_path, "Ss*.MIX"); 2847 file_handle = FindFirstFile(scan_path, &find_data); 2848 if (file_handle != INVALID_HANDLE_VALUE) 2849 { 2850 do 2851 { 2852 char *ptr = strdup(find_data.cFileName); 2853 new MFCD(ptr, &FastKey); 2854 } while (FindNextFile(file_handle, &find_data)); 2855 FindClose(file_handle); 2856 } 2857 2858 path = CDFileClass::Get_Search_Path(p); 2859 2860 if (path == NULL) { 2861 break; 2862 } 2863 } 2864 2865 #if (0) 2866 /* 2867 ** Before all else, cache any additional mixfiles. 2868 */ 2869 struct find_t ff; // for _dos_findfirst 2870 if (!_dos_findfirst("SC*.MIX", _A_NORMAL, &ff)) { 2871 char * ptr; 2872 do { 2873 ptr = strdup(ff.name); 2874 new MFCD(ptr, &FastKey); 2875 MFCD::Cache(ptr); 2876 } while (!_dos_findnext(&ff)); 2877 } 2878 if (!_dos_findfirst("SS*.MIX", _A_NORMAL, &ff)) { 2879 char * ptr; 2880 do { 2881 ptr = strdup(ff.name); 2882 new MFCD(ptr, &FastKey); 2883 } while (!_dos_findnext(&ff)); 2884 } 2885 #endif 2886 } 2887 2888 2889 /*********************************************************************************************** 2890 * Init_One_Time_Systems -- Initialize internal pointers to the bulk data. * 2891 * * 2892 * This performs the one-time processing required after the bulk data has been cached but * 2893 * before the game actually starts. Typically, this routine extracts pointers to all the * 2894 * embedded data sub-files within the main game data mixfile. This routine must be called * 2895 * AFTER the bulk data has been cached. * 2896 * * 2897 * INPUT: none * 2898 * * 2899 * OUTPUT: none * 2900 * * 2901 * WARNINGS: Call this routine AFTER the bulk data has been cached. * 2902 * * 2903 * HISTORY: * 2904 * 06/03/1996 JLB : Created. * 2905 *=============================================================================================*/ 2906 static void Init_One_Time_Systems(void) 2907 { 2908 Call_Back(); 2909 Map.One_Time(); 2910 Logic.One_Time(); 2911 Options.One_Time(); 2912 Session.One_Time(); 2913 2914 ObjectTypeClass::One_Time(); 2915 BuildingTypeClass::One_Time(); 2916 BulletTypeClass::One_Time(); 2917 HouseTypeClass::One_Time(); 2918 TemplateTypeClass::One_Time(); 2919 OverlayTypeClass::One_Time(); 2920 SmudgeTypeClass::One_Time(); 2921 TerrainTypeClass::One_Time(); 2922 UnitTypeClass::One_Time(); 2923 VesselTypeClass::One_Time(); 2924 InfantryTypeClass::One_Time(); 2925 AnimTypeClass::One_Time(); 2926 AircraftTypeClass::One_Time(); 2927 HouseClass::One_Time(); 2928 } 2929 2930 2931 /*********************************************************************************************** 2932 * Init_Fonts -- Initialize all the game font pointers. * 2933 * * 2934 * This routine is used to fetch pointers to the game fonts. The mixfile containing these * 2935 * fonts must have been previously cached. This routine is a necessary prerequisite to * 2936 * displaying any dialogs or printing any text. * 2937 * * 2938 * INPUT: none * 2939 * * 2940 * OUTPUT: none * 2941 * * 2942 * WARNINGS: none * 2943 * * 2944 * HISTORY: * 2945 * 06/03/1996 JLB : Created. * 2946 *=============================================================================================*/ 2947 static void Init_Fonts(void) 2948 { 2949 Metal12FontPtr = MFCD::Retrieve("12METFNT.FNT"); 2950 MapFontPtr = MFCD::Retrieve("HELP.FNT"); 2951 Font6Ptr = MFCD::Retrieve("6POINT.FNT"); 2952 GradFont6Ptr = MFCD::Retrieve("GRAD6FNT.FNT"); 2953 EditorFont = MFCD::Retrieve("EDITFNT.FNT"); 2954 Font8Ptr = MFCD::Retrieve("8POINT.FNT"); 2955 FontPtr = (char *)Font8Ptr; 2956 Set_Font(FontPtr); 2957 Font3Ptr = MFCD::Retrieve("3POINT.FNT"); 2958 ScoreFontPtr = MFCD::Retrieve("SCOREFNT.FNT"); 2959 FontLEDPtr = MFCD::Retrieve("LED.FNT"); 2960 VCRFontPtr = MFCD::Retrieve("VCR.FNT"); 2961 TypeFontPtr = MFCD::Retrieve("8POINT.FNT"); //("TYPE.FNT"); //VG 10/17/96 2962 } 2963 2964 2965 /*********************************************************************************************** 2966 * Init_CDROM_Access -- Initialize the CD-ROM access handler. * 2967 * * 2968 * This routine is called to setup the CD-ROM access or emulation handler. It will ensure * 2969 * that the appropriate CD-ROM is present (dependant on the RequiredCD global). * 2970 * * 2971 * INPUT: none * 2972 * * 2973 * OUTPUT: none * 2974 * * 2975 * WARNINGS: The fonts, palettes, and other bootstrap systems must have been initialized * 2976 * prior to calling this routine since this routine will quite likely display * 2977 * a dialog box requesting the appropriate CD be inserted. * 2978 * * 2979 * HISTORY: * 2980 * 06/03/1996 JLB : Created. * 2981 *=============================================================================================*/ 2982 static void Init_CDROM_Access(void) 2983 { 2984 VisiblePage.Clear(); 2985 HidPage.Clear(); 2986 2987 #ifdef FIXIT_VERSION_3 2988 // Determine if we're going to be running from a DVD. 2989 // The entire session will either require a DVD, or the regular CDs. Never both. 2990 // Call Using_DVD() to determine which case it is. 2991 // Here we set the value that Using_DVD() returns. 2992 Determine_If_Using_DVD(); 2993 // Force_CD_Available() is modified when Using_DVD() is true so that all requests become requests for the DVD. 2994 #endif 2995 2996 /* 2997 ** Always try to look at the CD-ROM for data files. 2998 */ 2999 if (!CCFileClass::Is_There_Search_Drives()) { 3000 3001 /* 3002 ** This call is needed because of a side effect of this function. It will examine the 3003 ** CD-ROMs attached to this computer and set the appropriate status values. Without this 3004 ** call, the "?:\\" could not be filled in correctly. 3005 */ 3006 Force_CD_Available(-1); 3007 3008 /* 3009 ** If there are no search drives specified then we must be playing 3010 ** off cd, so read files from there. 3011 */ 3012 int error; 3013 3014 do { 3015 error = CCFileClass::Set_Search_Drives("?:\\"); 3016 switch (error) { 3017 case 1: 3018 VisiblePage.Clear(); 3019 GamePalette.Set(); 3020 Show_Mouse(); 3021 WWMessageBox().Process(TXT_CD_ERROR1, TXT_OK); 3022 Prog_End("Init_CDROM_Access - CD_ERROR1", true); 3023 Emergency_Exit(EXIT_FAILURE); 3024 3025 case 2: 3026 VisiblePage.Clear(); 3027 GamePalette.Set(); 3028 Show_Mouse(); 3029 if (WWMessageBox().Process(TXT_CD_DIALOG_1, TXT_OK, TXT_CANCEL) == 1) { 3030 Prog_End("Init_CDROM_Access - CD_ERROR2", true); 3031 Emergency_Exit(EXIT_FAILURE); 3032 } 3033 Hide_Mouse(); 3034 break; 3035 3036 default: 3037 VisiblePage.Clear(); 3038 Show_Mouse(); 3039 if (!Force_CD_Available(RequiredCD)) { 3040 Prog_End("Init_CDROM_Access - Force_CD_Available failed", true); 3041 Emergency_Exit(EXIT_FAILURE); 3042 } 3043 Hide_Mouse(); 3044 break; 3045 } 3046 } while (error); 3047 3048 RequiredCD = -1; 3049 } else { 3050 3051 /* 3052 ** If there are search drives specified then all files are to be 3053 ** considered local. 3054 */ 3055 RequiredCD = -2; 3056 } 3057 } 3058 3059 3060 /*********************************************************************************************** 3061 * Init_Bootstrap_Mixfiles -- Registers and caches any mixfiles needed for bootstrapping. * 3062 * * 3063 * This routine will register the initial mixfiles that are required to display error * 3064 * messages and get input from the player. * 3065 * * 3066 * INPUT: none * 3067 * * 3068 * OUTPUT: none * 3069 * * 3070 * WARNINGS: Be sure to call this routine before any dialogs would be displayed to the * 3071 * player. * 3072 * * 3073 * HISTORY: * 3074 * 06/03/1996 JLB : Created. * 3075 *=============================================================================================*/ 3076 static void Init_Bootstrap_Mixfiles(void) 3077 { 3078 int temp = RequiredCD; 3079 RequiredCD = -2; 3080 3081 #ifdef WOLAPI_INTEGRATION 3082 CCFileClass fileWolapiMix( "WOLAPI.MIX" ); 3083 if( fileWolapiMix.Is_Available() ) 3084 { 3085 new MFCD( "WOLAPI.MIX", &FastKey ); 3086 MFCD::Cache( "WOLAPI.MIX" ); 3087 } 3088 #endif 3089 3090 #ifdef FIXIT_CSII // Ok. ajw 3091 CCFileClass file2("EXPAND2.MIX"); 3092 if (file2.Is_Available()) { 3093 new MFCD("EXPAND2.MIX", &FastKey); 3094 bool ok = MFCD::Cache("EXPAND2.MIX"); 3095 assert(ok); 3096 } 3097 #endif 3098 3099 #ifdef FIXIT_CSII // Ok. ajw 3100 bool ok1; 3101 #if 0 3102 new MFCD("HIRES1.MIX", &FastKey); 3103 ok1 = MFCD::Cache("HIRES1.MIX"); 3104 assert(ok1); 3105 #else 3106 new MFCD("LORES1.MIX", &FastKey); 3107 ok1 = MFCD::Cache("LORES1.MIX"); 3108 assert(ok1); 3109 #endif 3110 #endif 3111 3112 #ifdef FIXIT_ANTS // Ok. ajw 3113 CCFileClass file("EXPAND.MIX"); 3114 if (file.Is_Available()) { 3115 new MFCD("EXPAND.MIX", &FastKey); 3116 bool ok = MFCD::Cache("EXPAND.MIX"); 3117 assert(ok); 3118 } 3119 #endif 3120 3121 new MFCD("REDALERT.MIX", &FastKey); 3122 3123 /* 3124 ** Bootstrap enough of the system so that the error dialog box can successfully 3125 ** be displayed. 3126 */ 3127 new MFCD("LOCAL.MIX", &FastKey); // Cached. 3128 bool ok = MFCD::Cache("LOCAL.MIX"); 3129 assert(ok); 3130 3131 #if 0 3132 new MFCD("HIRES.MIX", &FastKey); 3133 ok = MFCD::Cache("HIRES.MIX"); 3134 assert(ok); 3135 3136 new MFCD("NCHIRES.MIX", &FastKey); //Non-cached hires stuff incl VQ palettes 3137 #else 3138 new MFCD("LORES.MIX", &FastKey); 3139 ok = MFCD::Cache("LORES.MIX"); 3140 assert(ok); 3141 #endif //WIN32 3142 3143 RequiredCD = temp; 3144 } 3145 3146 3147 /*********************************************************************************************** 3148 * Init_Secondary_Mixfiles -- Register and cache secondary mixfiles. * 3149 * * 3150 * This routine is used to register the mixfiles that are needed for main menu processing. * 3151 * Call this routine before the main menu is display and processed. * 3152 * * 3153 * INPUT: none * 3154 * * 3155 * OUTPUT: none * 3156 * * 3157 * WARNINGS: none * 3158 * * 3159 * HISTORY: * 3160 * 06/03/1996 JLB : Created. * 3161 *=============================================================================================*/ 3162 //#define DENZIL_MIXEXTRACT 3163 #ifdef DENZIL_MIXEXTRACT 3164 void Extract(char* filename, char* outfile); 3165 #endif 3166 3167 static void Init_Secondary_Mixfiles(void) 3168 { 3169 MainMix = new MFCD("MAIN.MIX", &FastKey); 3170 assert(MainMix != NULL); 3171 3172 //Denzil extract mixfile 3173 #ifdef DENZIL_MIXEXTRACT 3174 #if(0) 3175 Extract("CONQUER.MIX", "o:\\projects\\radvd\\data\\extract\\conquer.mix"); 3176 Extract("EDHI.MIX", "o:\\projects\\radvd\\data\\extract\\edhi.mix"); 3177 Extract("EDLO.MIX", "o:\\projects\\radvd\\data\\extract\\edlo.mix"); 3178 Extract("GENERAL.MIX", "o:\\projects\\radvd\\data\\extract\\general.mix"); 3179 Extract("INTERIOR.MIX", "o:\\projects\\radvd\\data\\extract\\interior.mix"); 3180 Extract("MOVIES1.MIX", "o:\\projects\\radvd\\data\\extract\\movies1.mix"); 3181 Extract("SCORES.MIX", "o:\\projects\\radvd\\data\\extract\\scores.mix"); 3182 Extract("SNOW.MIX", "o:\\projects\\radvd\\data\\extract\\snow.mix"); 3183 Extract("SOUNDS.MIX", "o:\\projects\\radvd\\data\\extract\\sounds.mix"); 3184 Extract("RUSSIAN.MIX", "o:\\projects\\radvd\\data\\extract\\russian.mix"); 3185 Extract("ALLIES.MIX", "o:\\projects\\radvd\\data\\extract\\allies.mix"); 3186 Extract("TEMPERAT.MIX", "o:\\projects\\radvd\\data\\extract\\temperat.mix"); 3187 #else 3188 Extract("CONQUER.MIX", "o:\\projects\\radvd\\data\\extract\\conquer.mix"); 3189 Extract("EDHI.MIX", "o:\\projects\\radvd\\data\\extract\\edhi.mix"); 3190 Extract("EDLO.MIX", "o:\\projects\\radvd\\data\\extract\\edlo.mix"); 3191 Extract("GENERAL.MIX", "o:\\projects\\radvd\\data\\extract\\general.mix"); 3192 Extract("INTERIOR.MIX", "o:\\projects\\radvd\\data\\extract\\interior.mix"); 3193 Extract("MOVIES2.MIX", "o:\\projects\\radvd\\data\\extract\\movies2.mix"); 3194 Extract("SCORES.MIX", "o:\\projects\\radvd\\data\\extract\\scores.mix"); 3195 Extract("SNOW.MIX", "o:\\projects\\radvd\\data\\extract\\snow.mix"); 3196 Extract("SOUNDS.MIX", "o:\\projects\\radvd\\data\\extract\\sounds.mix"); 3197 Extract("RUSSIAN.MIX", "o:\\projects\\radvd\\data\\extract\\russian.mix"); 3198 Extract("ALLIES.MIX", "o:\\projects\\radvd\\data\\extract\\allies.mix"); 3199 Extract("TEMPERAT.MIX", "o:\\projects\\radvd\\data\\extract\\temperat.mix"); 3200 #endif 3201 #endif 3202 3203 /* 3204 ** Inform the file system of the various MIX files. 3205 */ 3206 ConquerMix = new MFCD("CONQUER.MIX", &FastKey); // Cached. 3207 // new MFCD("TRANSIT.MIX", &FastKey); 3208 3209 if (GeneralMix == NULL) GeneralMix = new MFCD("GENERAL.MIX", &FastKey); // Never cached. 3210 3211 if (CCFileClass("MOVIES1.MIX").Is_Available()) { 3212 MoviesMix = new MFCD("MOVIES1.MIX", &FastKey); // Never cached. 3213 } else { 3214 MoviesMix = new MFCD("MOVIES2.MIX", &FastKey); // Never cached. 3215 } 3216 assert(MoviesMix != NULL); 3217 3218 /* 3219 ** Register the score mixfile. 3220 */ 3221 ScoresPresent = true; 3222 ScoreMix = new MFCD("SCORES.MIX", &FastKey); 3223 ThemeClass::Scan(); 3224 3225 /* 3226 ** These are sound card specific, but the install program would have 3227 ** copied the correct versions to the hard drive. 3228 */ 3229 new MFCD("SPEECH.MIX", &FastKey); // Never cached. 3230 new MFCD("SOUNDS.MIX", &FastKey); // Cached. 3231 new MFCD("RUSSIAN.MIX", &FastKey); // Cached. 3232 new MFCD("ALLIES.MIX", &FastKey); // Cached. 3233 } 3234 3235 3236 /*********************************************************************************************** 3237 * Bootstrap -- Perform the initial bootstrap procedure. * 3238 * * 3239 * This routine will load and initialize the game engine such that a dialog box could be * 3240 * displayed. Because this is very critical, call this routine before any other game * 3241 * initialization code. * 3242 * * 3243 * INPUT: none * 3244 * * 3245 * OUTPUT: none * 3246 * * 3247 * WARNINGS: none * 3248 * * 3249 * HISTORY: * 3250 * 06/03/1996 JLB : Created. * 3251 *=============================================================================================*/ 3252 static void Bootstrap(void) 3253 { 3254 BlackPalette.Set(); 3255 3256 /* 3257 ** Be sure to short circuit the CD-ROM check if there is a CD-ROM override 3258 ** path. 3259 */ 3260 if (CCFileClass::Is_There_Search_Drives()) { 3261 RequiredCD = -2; 3262 } 3263 3264 /* 3265 ** Process the message loop until we are in focus. We need to be in focus to read pixels from 3266 ** the screen. 3267 */ 3268 #if (0) //PG 3269 #ifdef WIN32 3270 do { 3271 Keyboard->Check(); 3272 } while (!GameInFocus); 3273 AllSurfaces.SurfacesRestored = false; 3274 #endif 3275 3276 /* 3277 ** Perform any special debug-only processing. This includes preparing the 3278 ** monochrome screen. 3279 */ 3280 Mono_Clear_Screen(); 3281 #endif 3282 /* 3283 ** Register and make resident all local mixfiles with particular emphasis 3284 ** on the mixfiles that are necessary to display and error messages and 3285 ** process further initialization. 3286 */ 3287 Init_Bootstrap_Mixfiles(); 3288 3289 /* 3290 ** Initialize the resident font pointers. 3291 */ 3292 Init_Fonts(); 3293 3294 #ifndef WIN32 3295 /* 3296 ** Install the hard error handler. 3297 */ 3298 _harderr(harderr_handler); // BG: Install hard error handler 3299 3300 /* 3301 ** Install a Page Fault handler 3302 */ 3303 if (UsePageFaultHandler) { 3304 Install_Page_Fault_Handle(); 3305 } 3306 #endif 3307 3308 /* 3309 ** Setup the keyboard processor in preparation for the game. 3310 */ 3311 #ifdef WIN32 3312 Keyboard->Clear(); 3313 #else 3314 Keyboard_Attributes_Off(BREAKON | SCROLLLOCKON | TRACKEXT | PAUSEON | CTRLSON | CTRLCON | FILTERONLY | TASKSWITCHABLE); 3315 Keyboard_Attributes_On(PASSBREAKS); 3316 Keyboard->Clear(); 3317 #endif 3318 3319 /* 3320 ** This is the shape staging buffer. It must always be available, so it is 3321 ** allocated here and never freed. The library sets the globals ShapeBuffer 3322 ** and ShapeBufferSize to these values, so it can be accessed for other 3323 ** purposes. 3324 */ 3325 Set_Shape_Buffer(new unsigned char[SHAPE_BUFFER_SIZE], SHAPE_BUFFER_SIZE); 3326 3327 /* 3328 ** Fetch the language text from the hard drive first. If it cannot be 3329 ** found on the hard drive, then look for it in the mixfile. 3330 */ 3331 #ifdef STEVES_LOAD_OVERRIDE 3332 RawFileClass strings ("CONQUER.ENG"); 3333 if (strings.Is_Available()){ 3334 SystemStrings = new char [strings.Size()]; 3335 strings.Read((void*)SystemStrings, strings.Size()); 3336 }else{ 3337 SystemStrings = (char const *)MFCD::Retrieve(Language_Name("CONQUER")); 3338 } 3339 #else 3340 SystemStrings = (char const *)MFCD::Retrieve(Language_Name("CONQUER")); 3341 #endif 3342 DebugStrings = (char const *)MFCD::Retrieve("DEBUG.ENG"); 3343 3344 /* 3345 ** Default palette initialization. 3346 */ 3347 // PG_TO_FIX. This doesn't seem right. ST - 5/9/2019 3348 //memmove((unsigned char *)&GamePalette[0], (void *)MFCD::Retrieve("TEMPERAT.PAL"), 768L); 3349 //WhitePalette[0] = BlackPalette[0]; 3350 // GamePalette.Set(); 3351 3352 /* 3353 ** Initialize expansion files (if present). Expansion files must be located 3354 ** in the current directory. 3355 */ 3356 Init_Expansion_Files(); 3357 3358 SidebarScheme.Background = BLACK; 3359 SidebarScheme.Corners = LTGREY; 3360 SidebarScheme.Shadow = DKGREY; 3361 SidebarScheme.Highlight = WHITE; 3362 SidebarScheme.Color = LTGREY; 3363 SidebarScheme.Bright = WHITE; 3364 SidebarScheme.BrightColor = WHITE; 3365 SidebarScheme.Box = LTGREY; 3366 GadgetClass::Set_Color_Scheme(&SidebarScheme); 3367 } 3368 3369 3370 /*********************************************************************************************** 3371 * Init_Mouse -- Initialize the mouse system. * 3372 * * 3373 * This routine will ensure that a valid mouse driver is present and a working mouse * 3374 * pointer can be displayed. The mouse is hidden when this routine exits. * 3375 * * 3376 * INPUT: none * 3377 * * 3378 * OUTPUT: none * 3379 * * 3380 * WARNINGS: none * 3381 * * 3382 * HISTORY: * 3383 * 06/03/1996 JLB : Created. * 3384 *=============================================================================================*/ 3385 static void Init_Mouse(void) 3386 { 3387 /* 3388 ** Since there is no mouse shape currently available we need 3389 ** to set one of our own. 3390 */ 3391 #ifdef WIN32 3392 ShowCursor(false); 3393 #endif 3394 if (MouseInstalled) { 3395 void const * temp_mouse_shapes = MFCD::Retrieve("MOUSE.SHP"); 3396 if (temp_mouse_shapes) { 3397 Set_Mouse_Cursor(0, 0, Extract_Shape(temp_mouse_shapes, 0)); 3398 while (Get_Mouse_State() > 1) Show_Mouse(); 3399 } 3400 } else { 3401 char buffer[255]; 3402 GamePalette.Set(); 3403 GamePalette.Set(); 3404 sprintf(buffer, TEXT_NO_MOUSE); 3405 VisiblePage.Clear(); 3406 WWMessageBox().Process(buffer, TXT_OK); 3407 Prog_End("Init_Mouse", true); 3408 Emergency_Exit(1); 3409 } 3410 3411 Map.Set_Default_Mouse(MOUSE_NORMAL, false); 3412 Show_Mouse(); 3413 while (Get_Mouse_State() > 1) Show_Mouse(); 3414 Call_Back(); 3415 Hide_Mouse(); 3416 } 3417 3418 3419 #ifdef OBSOLETE 3420 /*********************************************************************************************** 3421 * Init_Authorization -- Verifies that the player is authorized to play the game. * 3422 * * 3423 * This is a development routine that restricts access to the game by way of passwords. * 3424 * * 3425 * INPUT: none * 3426 * * 3427 * OUTPUT: none * 3428 * * 3429 * WARNINGS: none * 3430 * * 3431 * HISTORY: * 3432 * 06/03/1996 JLB : Created. * 3433 *=============================================================================================*/ 3434 static void Init_Authorization(void) 3435 { 3436 if (Special.IsFromInstall) return; 3437 3438 Load_Title_Page(); 3439 #ifdef WIN32 3440 Wait_Vert_Blank(); 3441 #else //WIN32 3442 Init_Delay(); 3443 Wait_Vert_Blank(VertBlank); 3444 #endif //WIN32 3445 3446 CCPalette.Set(); 3447 // Set_Palette(Palette); 3448 HidPage.Blit(SeenPage); 3449 Show_Mouse(); 3450 3451 /* 3452 ** Fetch the type of game to be played. This will be either 3453 ** C&C:Red Alert or C&C:Plus. 3454 */ 3455 //tryagain: 3456 3457 bool ok = Debug_Flag; 3458 int counter = 3; 3459 3460 if (Debug_Flag) ok = true; 3461 3462 /* 3463 ** C&C:Red Alert requires a password for legal entry. Try (three times) to get a correct 3464 ** password. If not found, then try again. 3465 */ 3466 bool skipper = false; 3467 #ifdef NEVER 3468 while (!ok && counter) { 3469 SmartPtr<char const> str = Fetch_Password(TXT_PASSWORD_CAPTION, TXT_PASSWORD_MESSAGE, TXT_OK); 3470 SmartPtr<long const> lptr = &CheatCodes[0]; 3471 while (*lptr) { 3472 if (Obfuscate(str) == *lptr++) { 3473 ok = true; 3474 break; 3475 } 3476 } 3477 lptr = &EditorCodes[0]; 3478 while (*lptr) { 3479 if (Obfuscate(str) == *lptr++) { 3480 ok = true; 3481 break; 3482 } 3483 } 3484 lptr = &PlayCodes[0]; 3485 while (*lptr) { 3486 if (Obfuscate(str) == *lptr++) { 3487 ok = true; 3488 skipper = true; 3489 break; 3490 } 3491 } 3492 3493 if (ok) break; 3494 3495 Hide_Mouse(); 3496 Load_Title_Page(); 3497 HidPage.Blit(SeenPage); 3498 Show_Mouse(); 3499 Delay(TIMER_SECOND*(4-counter)*1); 3500 if (WWMessageBox().Process(TXT_PASSWORD_ERROR, TXT_TRY_AGAIN, TXT_CANCEL)) { 3501 goto tryagain; 3502 } 3503 3504 counter--; 3505 if (counter == 0) goto tryagain; 3506 } 3507 #endif 3508 3509 if (!skipper) { 3510 CCPalette.Set(); 3511 } 3512 3513 Hide_Mouse(); 3514 Load_Title_Page(); 3515 HidPage.Blit(SeenPage); 3516 Show_Mouse(); 3517 Call_Back(); 3518 } 3519 #endif 3520 3521 3522 /*********************************************************************************************** 3523 * Init_Bulk_Data -- Initialize the time-consuming mixfile caching. * 3524 * * 3525 * This routine is called to handle the time consuming process of game initialization. * 3526 * The title page will be displayed when this routine is called. * 3527 * * 3528 * INPUT: none * 3529 * * 3530 * OUTPUT: none * 3531 * * 3532 * WARNINGS: This routine will take a very long time. * 3533 * * 3534 * HISTORY: * 3535 * 06/03/1996 JLB : Created. * 3536 *=============================================================================================*/ 3537 static void Init_Bulk_Data(void) 3538 { 3539 /* 3540 ** Cache the main game data. This operation can take a very long time. 3541 */ 3542 MFCD::Cache("CONQUER.MIX"); 3543 if (SampleType != 0 && !Debug_Quiet) { 3544 MFCD::Cache("SOUNDS.MIX"); 3545 MFCD::Cache("RUSSIAN.MIX"); 3546 MFCD::Cache("ALLIES.MIX"); 3547 } 3548 Call_Back(); 3549 3550 /* 3551 ** Fetch the tutorial message data. 3552 */ 3553 INIClass ini; 3554 ini.Load(CCFileClass("TUTORIAL.INI")); 3555 for (int index = 0; index < ARRAY_SIZE(TutorialText); index++) { 3556 TutorialText[index] = NULL; 3557 3558 char buffer[128]; 3559 char num[10]; 3560 sprintf(num, "%d", index); 3561 if (ini.Get_String("Tutorial", num, "", buffer, sizeof(buffer))) { 3562 TutorialText[index] = strdup(buffer); 3563 } 3564 } 3565 3566 /* 3567 ** Perform one-time game system initializations. 3568 */ 3569 Init_One_Time_Systems(); 3570 } 3571 3572 3573 /*********************************************************************************************** 3574 * Init_Keys -- Initialize the cryptographic keys. * 3575 * * 3576 * This routine will initialize the fast cryptographic key. It will also initialize the * 3577 * slow one if this is a scenario editor version of the game. * 3578 * * 3579 * INPUT: none * 3580 * * 3581 * OUTPUT: none * 3582 * * 3583 * WARNINGS: none * 3584 * * 3585 * HISTORY: * 3586 * 07/08/1996 JLB : Created. * 3587 *=============================================================================================*/ 3588 static void Init_Keys(void) 3589 { 3590 RAMFileClass file((void*)Keys, strlen(Keys)); 3591 INIClass ini; 3592 ini.Load(file); 3593 3594 FastKey = ini.Get_PKey(true); 3595 #ifdef SCENARIO_EDITOR 3596 SlowKey = ini.Get_PKey(false); 3597 #endif 3598 } 3599 3600 3601 /*************************************************************************** 3602 * Save_Recording_Values -- Saves multiplayer-specific values * 3603 * * 3604 * This routine saves multiplayer values that need to be restored for a * 3605 * save game. In addition to saving the random # seed for this scenario, * 3606 * it saves the contents of the actual random number generator; this * 3607 * ensures that the random # sequencer will pick up where it left off when * 3608 * the game was saved. * 3609 * This routine also saves the header for a Recording file, so it must * 3610 * save some data not needed specifically by a save-game file (ie Seed). * 3611 * * 3612 * INPUT: * 3613 * file file to save to * 3614 * * 3615 * OUTPUT: * 3616 * true = success, false = failure * 3617 * * 3618 * WARNINGS: * 3619 * none. * 3620 * * 3621 * HISTORY: * 3622 * 09/28/1995 BRR : Created. * 3623 *=========================================================================*/ 3624 bool Save_Recording_Values(CCFileClass & file) 3625 { 3626 Session.Save(file); 3627 file.Write(&BuildLevel, sizeof(BuildLevel)); 3628 file.Write(&Debug_Unshroud, sizeof(Debug_Unshroud)); 3629 file.Write(&Seed, sizeof(Seed)); 3630 file.Write(&Scen.Scenario, sizeof(Scen.Scenario)); 3631 file.Write(Scen.ScenarioName, sizeof(Scen.ScenarioName)); 3632 file.Write(&Whom, sizeof(Whom)); 3633 file.Write(&Special, sizeof(SpecialClass)); 3634 file.Write(&Options, sizeof(GameOptionsClass)); 3635 3636 return (true); 3637 } 3638 3639 3640 /*************************************************************************** 3641 * Load_Recording_Values -- Loads multiplayer-specific values * 3642 * * 3643 * INPUT: * 3644 * file file to load from * 3645 * * 3646 * OUTPUT: * 3647 * true = success, false = failure * 3648 * * 3649 * WARNINGS: * 3650 * none. * 3651 * * 3652 * HISTORY: * 3653 * 09/28/1995 BRR : Created. * 3654 *=========================================================================*/ 3655 bool Load_Recording_Values(CCFileClass & file) 3656 { 3657 Session.Load(file); 3658 file.Read(&BuildLevel, sizeof(BuildLevel)); 3659 file.Read(&Debug_Unshroud, sizeof(Debug_Unshroud)); 3660 file.Read(&Seed, sizeof(Seed)); 3661 file.Read(&Scen.Scenario, sizeof(Scen.Scenario)); 3662 file.Read(Scen.ScenarioName, sizeof(Scen.ScenarioName)); 3663 file.Read(&Whom, sizeof(Whom)); 3664 file.Read(&Special, sizeof(SpecialClass)); 3665 file.Read(&Options, sizeof(GameOptionsClass)); 3666 return (true); 3667 } 3668 3669 extern "C" { 3670 void __PRO(void) { 3671 // printf("_pro\n"); 3672 } 3673 } 3674 3675 #ifdef DENZIL_MIXEXTRACT 3676 void Extract(char* filename, char* outname) 3677 { 3678 CCFileClass inFile(filename); 3679 CCFileClass outFile(outname); 3680 3681 inFile.Open(); 3682 outFile.Open(WRITE); 3683 3684 void* buffer = malloc(32768); 3685 3686 if (buffer) 3687 { 3688 unsigned long size = inFile.Size(); 3689 unsigned long bytes; 3690 3691 while (size > 0) 3692 { 3693 bytes = inFile.Read(buffer, 32768); 3694 outFile.Write(buffer, bytes); 3695 size -= bytes; 3696 } 3697 3698 free(buffer); 3699 } 3700 } 3701 #endif 3702 3703 3704 #ifdef FIXIT_VERSION_3 3705 3706 bool bUsingDVD = false; 3707 3708 const char* Game_Registry_Key(); 3709 3710 //*********************************************************************************************** 3711 bool Is_DVD_Installed() 3712 { 3713 bool bInstalled; 3714 HKEY hKey; 3715 if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, Game_Registry_Key(), 0, KEY_READ, &hKey ) != ERROR_SUCCESS ) 3716 return false; 3717 DWORD dwValue; 3718 DWORD dwBufSize = sizeof( DWORD ); 3719 if( RegQueryValueEx( hKey, "DVD", 0, NULL, (LPBYTE)&dwValue, &dwBufSize ) != ERROR_SUCCESS ) 3720 bInstalled = false; 3721 else 3722 bInstalled = (bool)dwValue; // (Presumably true, if it's there...) 3723 3724 RegCloseKey( hKey ); 3725 3726 return bInstalled; 3727 } 3728 3729 //*********************************************************************************************** 3730 bool Determine_If_Using_DVD() 3731 { 3732 // Determines if the user has a DVD currently available. If they do, we'll use it throughout the 3733 // session. Else we won't check for it again and will always ask for CDs. 3734 if( Is_DVD_Installed() ) 3735 { 3736 if( Force_CD_Available( 5 ) ) 3737 { 3738 bUsingDVD = true; 3739 } 3740 else 3741 { 3742 // User hit cancel. Allow things to progress normally. They will be prompted for 3743 // a Red Alert disk as usual. 3744 bUsingDVD = false; 3745 } 3746 } 3747 else 3748 bUsingDVD = false; 3749 3750 return bUsingDVD; 3751 } 3752 3753 //*********************************************************************************************** 3754 bool Using_DVD() 3755 { 3756 return bUsingDVD; 3757 } 3758 3759 #endif 3760 3761 3762 3763 3764 /*********************************************************************************************** 3765 * Free_Heaps -- Clear out the heaps before exit * 3766 * * 3767 * * 3768 * INPUT: none * 3769 * * 3770 * OUTPUT: none * 3771 * * 3772 * WARNINGS: * 3773 * * 3774 * HISTORY: * 3775 * 12/18/2019 11:59AM ST : Created. * 3776 *=============================================================================================*/ 3777 void Free_Heaps(void) 3778 { 3779 HouseTypes.Clear(); 3780 BuildingTypes.Clear(); 3781 AircraftTypes.Clear(); 3782 InfantryTypes.Clear(); 3783 BulletTypes.Clear(); 3784 AnimTypes.Clear(); 3785 UnitTypes.Clear(); 3786 VesselTypes.Clear(); 3787 TemplateTypes.Clear(); 3788 TerrainTypes.Clear(); 3789 OverlayTypes.Clear(); 3790 SmudgeTypes.Clear(); 3791 #if (0) 3792 HouseTypeClass::Init_Heap(); 3793 BuildingTypeClass::Init_Heap(); 3794 AircraftTypeClass::Init_Heap(); 3795 InfantryTypeClass::Init_Heap(); 3796 BulletTypeClass::Init_Heap(); 3797 AnimTypeClass::Init_Heap(); 3798 UnitTypeClass::Init_Heap(); 3799 VesselTypeClass::Init_Heap(); 3800 TemplateTypeClass::Init_Heap(); 3801 TerrainTypeClass::Init_Heap(); 3802 OverlayTypeClass::Init_Heap(); 3803 SmudgeTypeClass::Init_Heap(); 3804 3805 // Heap init moved here from globals.cpp. ST - 5/20/2019 3806 CCPtr<AircraftClass>::Set_Heap(&Aircraft); 3807 CCPtr<AnimClass>::Set_Heap(&Anims); 3808 CCPtr<BuildingClass>::Set_Heap(&Buildings); 3809 CCPtr<BulletClass>::Set_Heap(&Bullets); 3810 CCPtr<FactoryClass>::Set_Heap(&Factories); 3811 CCPtr<HouseClass>::Set_Heap(&Houses); 3812 CCPtr<InfantryClass>::Set_Heap(&Infantry); 3813 CCPtr<OverlayClass>::Set_Heap(&Overlays); 3814 CCPtr<SmudgeClass>::Set_Heap(&Smudges); 3815 CCPtr<TeamClass>::Set_Heap(&Teams); 3816 CCPtr<TeamTypeClass>::Set_Heap(&TeamTypes); 3817 CCPtr<TemplateClass>::Set_Heap(&Templates); 3818 CCPtr<TerrainClass>::Set_Heap(&Terrains); 3819 CCPtr<TriggerClass>::Set_Heap(&Triggers); 3820 CCPtr<TriggerTypeClass>::Set_Heap(&TriggerTypes); 3821 3822 CCPtr<HouseTypeClass>::Set_Heap(&HouseTypes); 3823 CCPtr<BuildingTypeClass>::Set_Heap(&BuildingTypes); 3824 CCPtr<AircraftTypeClass>::Set_Heap(&AircraftTypes); 3825 CCPtr<InfantryTypeClass>::Set_Heap(&InfantryTypes); 3826 CCPtr<BulletTypeClass>::Set_Heap(&BulletTypes); 3827 CCPtr<AnimTypeClass>::Set_Heap(&AnimTypes); 3828 CCPtr<UnitTypeClass>::Set_Heap(&UnitTypes); 3829 CCPtr<VesselTypeClass>::Set_Heap(&VesselTypes); 3830 CCPtr<TemplateTypeClass>::Set_Heap(&TemplateTypes); 3831 CCPtr<TerrainTypeClass>::Set_Heap(&TerrainTypes); 3832 CCPtr<OverlayTypeClass>::Set_Heap(&OverlayTypes); 3833 CCPtr<SmudgeTypeClass>::Set_Heap(&SmudgeTypes); 3834 #endif 3835 3836 Vessels.Clear(); 3837 Units.Clear(); 3838 Factories.Clear(); 3839 Terrains.Clear(); 3840 Templates.Clear(); 3841 Smudges.Clear(); 3842 Overlays.Clear(); 3843 Infantry.Clear(); 3844 Bullets.Clear(); 3845 Buildings.Clear(); 3846 Anims.Clear(); 3847 Aircraft.Clear(); 3848 Triggers.Clear(); 3849 TeamTypes.Clear(); 3850 Teams.Clear(); 3851 Houses.Clear(); 3852 TriggerTypes.Clear(); 3853 3854 /* 3855 ** Speech holding tank buffer. Since speech does not mix, it can be placed 3856 ** into a custom holding tank only as large as the largest speech file to 3857 ** be played. 3858 */ 3859 for (int index = 0; index < ARRAY_SIZE(SpeechBuffer); index++) { 3860 if (SpeechBuffer[index]) { 3861 delete [] SpeechBuffer[index]; 3862 SpeechBuffer[index] = NULL; 3863 } 3864 } 3865 3866 /* 3867 ** Allocate the theater buffer block. 3868 */ 3869 if (TheaterBuffer) { 3870 delete TheaterBuffer; 3871 TheaterBuffer = NULL; 3872 } 3873 }