INIT.CPP (90624B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 16 /* $Header: F:\projects\c&c\vcs\code\init.cpv 2.18 16 Oct 1995 16:50:16 JOE_BOSTIC $ */ 17 /*********************************************************************************************** 18 *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** 19 *********************************************************************************************** 20 * * 21 * Project Name : Command & Conquer * 22 * * 23 * File Name : 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 * Init_Game -- Main game initialization routine. * 33 * Load_Recording_Values -- Loads recording values from recording file * 34 * Obfuscate -- Sufficiently transform parameter to thwart casual hackers. * 35 * Parse_Command_Line -- Parses the command line parameters. * 36 * Parse_INI_File -- Parses CONQUER.INI for special options * 37 * Play_Intro -- plays the introduction & logo movies * 38 * Save_Recording_Values -- Saves recording values to a recording file * 39 * Select_Game -- The game's main menu * 40 * Version_Number -- Determines the version number. * 41 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 42 43 #include "function.h" 44 #include "loaddlg.h" 45 #include "tcpip.h" 46 #include <conio.h> 47 #include <dos.h> 48 #include "ccdde.h" 49 50 static HANDLE hCCLibrary; 51 52 /**************************************** 53 ** Function prototypes for this module ** 54 *****************************************/ 55 static void Play_Intro(bool for_real = false); 56 57 extern "C" { 58 extern long RandNumb; 59 } 60 61 extern int SimRandIndex; 62 63 #define ATTRACT_MODE_TIMEOUT 3600 // timeout for attract mode 64 #if(0) 65 66 long FAR PASCAL _export Start_Game_Proc(HWND hwnd, UINT message, UINT wParam, LONG lParam) 67 { 68 switch (message) { 69 case WM_CREATE: 70 break; 71 72 case WM_COMMAND: 73 EndDialog(hwnd, TRUE); 74 AllDone = TRUE; 75 break; 76 77 case WM_DESTROY: 78 EndDialog(hwnd, TRUE); 79 break; 80 } 81 return(DefWindowProc(hwnd, message, wParam, lParam)); 82 } 83 #endif 84 85 86 extern bool Server_Remote_Connect(void); 87 extern bool Client_Remote_Connect(void); 88 extern bool SpawnedFromWChat; 89 90 91 /*********************************************************************************************** 92 * Init_Game -- Main game initialization routine. * 93 * * 94 * Perform all one-time game initializations here. This includes all * 95 * allocations and table setups. The intro and other one-time startup * 96 * tasks are also performed here. * 97 * * 98 * INPUT: argc,argv -- Command line arguments. * 99 * * 100 * OUTPUT: none * 101 * * 102 * WARNINGS: Only call this ONCE! * 103 * * 104 * HISTORY: * 105 * 10/07/1992 JLB : Created. * 106 *=============================================================================================*/ 107 bool Init_Game(int , char *[]) 108 { 109 void const *temp_mouse_shapes; 110 111 CCDebugString ("C&C95 - About to load reslib.dll\n"); 112 hCCLibrary = LoadLibrary("reslib.dll"); 113 114 /* 115 ** Initialize the game object heaps. 116 */ 117 CCDebugString ("C&C95 - About to enter Units.Set_Heap\n"); 118 Units.Set_Heap(UNIT_MAX); 119 CCDebugString ("C&C95 - About to enter Factories.Set_Heap\n"); 120 Factories.Set_Heap(FACTORY_MAX); 121 CCDebugString ("C&C95 - About to enter Terrains.Set_Heap\n"); 122 Terrains.Set_Heap(TERRAIN_MAX); 123 CCDebugString ("C&C95 - About to enter Templates.Set_Heap\n"); 124 Templates.Set_Heap(TEMPLATE_MAX); 125 CCDebugString ("C&C95 - About to enter Smudges.Set_Heap\n"); 126 Smudges.Set_Heap(SMUDGE_MAX); 127 CCDebugString ("C&C95 - About to enter Overlays.Set_Heap\n"); 128 Overlays.Set_Heap(OVERLAY_MAX); 129 CCDebugString ("C&C95 - About to enter Infantry.Set_Heap\n"); 130 Infantry.Set_Heap(INFANTRY_MAX); 131 CCDebugString ("C&C95 - About to enter Bullets.Set_Heap\n"); 132 Bullets.Set_Heap(BULLET_MAX); 133 CCDebugString ("C&C95 - About to enter Buildings.Set_Heap\n"); 134 Buildings.Set_Heap(BUILDING_MAX); 135 CCDebugString ("C&C95 - About to enter Anims.Set_Heap\n"); 136 Anims.Set_Heap(ANIM_MAX); 137 CCDebugString ("C&C95 - About to enter Aircraft.Set_Heap\n"); 138 Aircraft.Set_Heap(AIRCRAFT_MAX); 139 CCDebugString ("C&C95 - About to enter Triggers.Set_Heap\n"); 140 Triggers.Set_Heap(TRIGGER_MAX); 141 CCDebugString ("C&C95 - About to enter TeamTypes.Set_Heap\n"); 142 TeamTypes.Set_Heap(TEAMTYPE_MAX); 143 CCDebugString ("C&C95 - About to enter Teams.Set_Heap\n"); 144 Teams.Set_Heap(TEAM_MAX); 145 CCDebugString ("C&C95 - About to enter Houses.Set_Heap\n"); 146 Houses.Set_Heap(HOUSE_MAX); 147 148 /* 149 ** Initialize all the waypoints to invalid values. 150 */ 151 CCDebugString ("C&C95 - About to clear waypoints\n"); 152 memset(Waypoint, 0xFF, sizeof(Waypoint)); 153 154 /* 155 ** Setup the keyboard processor in preparation for the game. 156 */ 157 CCDebugString ("C&C95 - About to do various keyboard inits\n"); 158 #ifdef FIX_ME_LATER 159 Keyboard_Attributes_Off(TRACKEXT | PAUSEON | BREAKON | SCROLLLOCKON | CTRLSON | CTRLCON | PASSBREAKS | FILTERONLY | TASKSWITCHABLE); 160 #endif //FIX_ME_LATER 161 Keyboard::Clear(); 162 Kbd.Clear(); 163 164 /* 165 ** This is the shape staging buffer. It must always be available, so it is 166 ** allocated here and never freed. The library sets the globals ShapeBuffer 167 ** and ShapeBufferSize to these values, so it can be accessed for other 168 ** purposes. 169 */ 170 CCDebugString ("C&C95 - About to call Set_Shape_Buffer\n"); 171 Set_Shape_Buffer(new unsigned char[SHAPE_BUFFER_SIZE], SHAPE_BUFFER_SIZE); 172 173 /* 174 ** Bootstrap enough of the system so that the error dialog box can sucessfully 175 ** be displayed. 176 */ 177 CCDebugString ("C&C95 - About to register CCLOCAL.MIX\n"); 178 #ifdef DEMO 179 new MixFileClass("DEMOL.MIX"); 180 MixFileClass::Cache("DEMOL.MIX"); 181 #else 182 int temp = RequiredCD; 183 RequiredCD = -2; 184 new MixFileClass("CCLOCAL.MIX"); // Cached. 185 MixFileClass::Cache("CCLOCAL.MIX"); 186 CCDebugString ("C&C95 - About to register UPDATE.MIX\n"); 187 new MixFileClass("UPDATE.MIX"); // Cached. 188 new MixFileClass("UPDATA.MIX"); // Cached. 189 CCDebugString ("C&C95 - About to register UPDATEC.MIX\n"); 190 new MixFileClass("UPDATEC.MIX"); // Cached. 191 MixFileClass::Cache("UPDATEC.MIX"); 192 #ifdef JAPANESE 193 CCDebugString ("C&C95 - About to register LANGUAGE.MIX\n"); 194 new MixFileClass("LANGUAGE.MIX"); 195 #endif //JAPANESE 196 197 RequiredCD = temp; 198 199 #endif 200 CCDebugString ("C&C95 - About to load fonts\n"); 201 Green12FontPtr = Load_Alloc_Data(CCFileClass("12GREEN.FNT")); 202 Green12GradFontPtr = Load_Alloc_Data(CCFileClass("12GRNGRD.FNT")); 203 MapFontPtr = Load_Alloc_Data(CCFileClass("8FAT.FNT")); 204 Font8Ptr = MixFileClass::Retrieve(FONT8); 205 FontPtr = (char *)Font8Ptr; 206 Set_Font(FontPtr); 207 Font3Ptr = MixFileClass::Retrieve(FONT3); 208 // Font6Ptr = MixFileClass::Retrieve(FONT6); 209 Font6Ptr = Load_Alloc_Data(CCFileClass("6POINT.FNT")); 210 //ScoreFontPtr = MixFileClass::Retrieve("12GRNGRD.FNT"); //GRAD12FN"); //("SCOREFNT.FNT"); 211 ScoreFontPtr = Load_Alloc_Data(CCFileClass("12GRNGRD.FNT")); 212 FontLEDPtr = MixFileClass::Retrieve("LED.FNT"); 213 VCRFontPtr = MixFileClass::Retrieve("VCR.FNT"); 214 // GradFont6Ptr = MixFileClass::Retrieve("GRAD6FNT.FNT"); 215 GradFont6Ptr = Load_Alloc_Data(CCFileClass("GRAD6FNT.FNT")); 216 BlackPalette = new(MEM_CLEAR|MEM_REAL) unsigned char[768]; 217 GamePalette = new(MEM_CLEAR|MEM_REAL) unsigned char[768]; 218 OriginalPalette = new(MEM_CLEAR|MEM_REAL) unsigned char[768]; 219 WhitePalette = new(MEM_CLEAR|MEM_REAL) unsigned char[768]; 220 memset(WhitePalette, 63, 768); 221 222 CCDebugString ("C&C95 - About to set palette\n"); 223 memset(BlackPalette, 0x01, 768); 224 if (!Special.IsFromInstall) Set_Palette(BlackPalette); 225 memset(BlackPalette, 0, 768); 226 if (!Special.IsFromInstall) { 227 Set_Palette(BlackPalette); 228 CCDebugString ("C&C95 - About to clear visible page\n"); 229 VisiblePage.Clear(); 230 } 231 232 Set_Palette(GamePalette); 233 234 CCDebugString ("C&C95 - About to set the mouse shape\n"); 235 /* 236 ** Since there is no mouse shape currently available we need' 237 ** to set one of our own. 238 */ 239 ShowCursor (FALSE); 240 if (MouseInstalled) { 241 temp_mouse_shapes = MixFileClass::Retrieve("MOUSE.SHP"); 242 if (temp_mouse_shapes) { 243 Set_Mouse_Cursor(0, 0, Extract_Shape(temp_mouse_shapes,0)); 244 while (Get_Mouse_State() > 1) { 245 Show_Mouse(); 246 } 247 } 248 } 249 250 CCDebugString ("C&C95 - About to enter wait for focus loop\n"); 251 /* 252 ** Process the message loop until we are in focus. 253 */ 254 do { 255 CCDebugString ("C&C95 - About to call Keyboard::Check\n"); 256 Keyboard::Check(); 257 }while (!GameInFocus); 258 AllSurfaces.SurfacesRestored=FALSE; 259 260 CCDebugString ("C&C95 - About to load the language file\n"); 261 /* 262 ** Fetch the language text from the hard drive first. If it cannot be 263 ** found on the hard drive, then look for it in the mixfile. 264 */ 265 if (RawFileClass(Language_Name("CONQUER")).Is_Available()) { 266 SystemStrings = (char const *)Load_Alloc_Data(RawFileClass(Language_Name("CONQUER"))); 267 } else { 268 SystemStrings = (char const *)MixFileClass::Retrieve(Language_Name("CONQUER")); 269 } 270 271 /* 272 ** Default palette initialization. Uses the desert palette for convenience, 273 ** but only the non terrain specific colors matter. 274 */ 275 //Mem_Copy((void *)MixFileClass::Retrieve("TEMPERAT.PAL"), GamePalette, 768L); 276 CCFileClass palfile ("TEMPERAT.PAL"); 277 palfile.Read (GamePalette, 768L); 278 279 if (!MouseInstalled) { 280 char buffer[255]; 281 Set_Palette(GamePalette); 282 #ifdef GERMAN 283 sprintf(buffer, "Command & Conquer kann Ihren Maustreiber nicht finden.."); 284 #else 285 #ifdef FRENCH 286 sprintf(buffer, "Command & Conquer ne peut pas dtecter votre gestionnaire de souris."); 287 #else 288 sprintf(buffer, "Command & Conquer is unable to detect your mouse driver."); 289 #endif 290 #endif 291 CCMessageBox().Process(buffer, TXT_OK); 292 Prog_End(); 293 exit(1); 294 } 295 296 #ifdef DEMO 297 /* 298 ** Add in any override path specified in the conquer.ini file. 299 */ 300 if (strlen(OverridePath)) { 301 CCFileClass::Set_Search_Drives(OverridePath); 302 } 303 #endif 304 305 #if (0) //ST - 1/2/2019 5:49PM 306 CCDebugString ("C&C95 - About to search for CD drives\n"); 307 /* 308 ** Always try to look at the CD-ROM for data files. 309 */ 310 if (!CCFileClass::Is_There_Search_Drives()) { 311 312 /* 313 ** If there are no search drives specified then we must be playing 314 ** off cd, so read files from there. 315 */ 316 int error; 317 318 do { 319 if (!CDList.Get_Number_Of_Drives()){ 320 Set_Palette(GamePalette); 321 Show_Mouse(); 322 CCMessageBox().Process(TXT_CD_ERROR1, TXT_OK); 323 Prog_End(); 324 exit(EXIT_FAILURE); 325 } 326 CCFileClass::Set_CD_Drive( CDList.Get_First_CD_Drive() ); 327 328 error = CCFileClass::Set_Search_Drives("?:\\"); 329 switch(error) { 330 case 1: 331 Set_Palette(GamePalette); 332 Show_Mouse(); 333 CCMessageBox().Process(TXT_CD_ERROR1, TXT_OK); 334 Prog_End(); 335 exit(EXIT_FAILURE); 336 337 case 2: 338 Set_Palette(GamePalette); 339 Show_Mouse(); 340 if (CCMessageBox().Process(TXT_CD_DIALOG_1, TXT_OK, TXT_CANCEL) == 1) { 341 Prog_End(); 342 exit(EXIT_FAILURE); 343 } 344 Hide_Mouse(); 345 break; 346 347 default: 348 Show_Mouse(); 349 if (!Force_CD_Available(RequiredCD)) { 350 Prog_End(); 351 exit(EXIT_FAILURE); 352 } 353 Hide_Mouse(); 354 break; 355 } 356 } while (error); 357 358 #ifdef DEMO 359 RequiredCD = -2; 360 #else 361 RequiredCD = -1; 362 #endif 363 } else { 364 365 /* 366 ** If there are search drives specified then all files are to be 367 ** considered local. 368 */ 369 RequiredCD = -2; 370 } 371 #endif 372 373 374 #ifndef DEMO 375 CCDebugString ("C&C95 - About to register addon mixfiles\n"); 376 /* 377 ** Before all else, cache any additional mixfiles. 378 */ 379 380 /* 381 ** Need to search the search paths. ST - 3/15/2019 2:18PM 382 */ 383 const char *path = ".\\"; 384 char search_path[_MAX_PATH]; 385 char scan_path[_MAX_PATH]; 386 387 for (int p=0 ; p<100 ; p++) { 388 389 strcpy(search_path, path); 390 if (search_path[strlen(search_path) - 1] != '\\') { 391 strcat(search_path, "\\"); 392 } 393 394 strcpy(scan_path, search_path); 395 strcat(scan_path, "SC*.MIX"); 396 397 WIN32_FIND_DATA find_data; 398 memset(&find_data, 0, sizeof(find_data)); 399 HANDLE file_handle = FindFirstFile(scan_path, &find_data); 400 if (file_handle != INVALID_HANDLE_VALUE) 401 { 402 do 403 { 404 char *ptr = strdup(find_data.cFileName); 405 new MixFileClass(ptr); 406 MixFileClass::Cache(ptr); 407 } while (FindNextFile(file_handle, &find_data)); 408 FindClose(file_handle); 409 } 410 411 memset(&find_data, 0, sizeof(find_data)); 412 strcpy(scan_path, search_path); 413 strcat(scan_path, "Ss*.MIX"); 414 file_handle = FindFirstFile(scan_path, &find_data); 415 if (file_handle != INVALID_HANDLE_VALUE) 416 { 417 do 418 { 419 char *ptr = strdup(find_data.cFileName); 420 new MixFileClass(ptr); 421 MixFileClass::Cache(ptr); 422 } while (FindNextFile(file_handle, &find_data)); 423 FindClose(file_handle); 424 } 425 426 path = CDFileClass::Get_Search_Path(p); 427 428 if (path == NULL) { 429 break; 430 } 431 } 432 433 #if (0) 434 struct find_t ff; // for _dos_findfirst 435 if (!_dos_findfirst("SC*.MIX", _A_NORMAL, &ff)) { 436 char * ptr; 437 do { 438 ptr = strdup(ff.name); 439 new MixFileClass(ptr); 440 MixFileClass::Cache(ptr); 441 // free(ptr); 442 } while(!_dos_findnext(&ff)); 443 } 444 if (!_dos_findfirst("SS*.MIX", _A_NORMAL, &ff)) { 445 char * ptr; 446 do { 447 ptr = strdup(ff.name); 448 new MixFileClass(ptr); 449 // free(ptr); 450 } while(!_dos_findnext(&ff)); 451 } 452 #endif 453 #endif //DEMO 454 455 CCDebugString ("C&C95 - About to register GENERAL.MIX\n"); 456 // 457 // This is a problem because registering the mix file can call Force_CD_Available which will try to load General.Mix 458 // Might as well just cut to the chase and call it directly. 459 // ST - 1/3/2019 5:19PM 460 // 461 //if (GeneralMix) delete GeneralMix; 462 //GeneralMix = new MixFileClass("GENERAL.MIX"); 463 Force_CD_Available(RequiredCD); 464 465 // if (!_dos_findfirst("SC*.MIX", _A_NORMAL, &ff)) { 466 // do { 467 // new MixFileClass(ff.name); 468 // MixFileClass::Cache(ff.name); 469 // } while(!_dos_findnext(&ff)); 470 // } 471 472 /* 473 ** Inform the file system of the various MIX files. 474 */ 475 #ifdef DEMO 476 new MixFileClass("DEMO.MIX"); 477 if (CCFileClass("DEMOM.MIX").Is_Available()) { 478 if (!MoviesMix) MoviesMix = new MixFileClass("DEMOM.MIX"); 479 ScoresPresent = true; 480 ThemeClass::Scan(); 481 } 482 483 #else 484 CCDebugString ("C&C95 - About to register CONQUER.MIX\n"); 485 new MixFileClass("CONQUER.MIX"); // Cached. 486 CCDebugString ("C&C95 - About to register TRANSIT.MIX\n"); 487 new MixFileClass("TRANSIT.MIX"); 488 489 CCDebugString ("C&C95 - About to register GENERAL.MIX\n"); 490 if (!GeneralMix) GeneralMix = new MixFileClass("GENERAL.MIX"); // Never cached. 491 492 // if (CCFileClass("MOVIES.MIX").Is_Available()) { 493 CCDebugString ("C&C95 - About to register MOVIES.MIX\n"); 494 if (!MoviesMix) MoviesMix = new MixFileClass("MOVIES.MIX"); // Never cached. 495 // } 496 497 498 499 #if (0) 500 501 /* 502 ** Extract a movie from a mixfile. 503 */ 504 char *file_ptr = (char*)Alloc (32 * 1024 * 1024, MEM_NORMAL); 505 CCFileClass whatever ("PINTLE.VQA"); 506 507 int len = whatever.Size(); 508 509 whatever.Open(); 510 511 DWORD actual; 512 HANDLE sfile = CreateFile("c:\\temp\\PINTLE.VQA", GENERIC_WRITE, 0, 513 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 514 515 if (sfile != INVALID_HANDLE_VALUE){ 516 SetFilePointer (sfile, 0, NULL, FILE_END); 517 518 do{ 519 whatever.Read (file_ptr, MIN (len, 1024*64)); 520 WriteFile(sfile, file_ptr, MIN (len, 1024*64), &actual, NULL); 521 len -= MIN (len, 1024*64); 522 }while ( len >0 ); 523 524 CloseHandle (sfile); 525 } 526 527 whatever.Close(); 528 529 Free (file_ptr); 530 531 #endif //(0) 532 533 534 535 /* 536 ** Register the score mixfile. 537 */ 538 CCDebugString ("C&C95 - About to register SCORES.MIX\n"); 539 ScoresPresent = false; 540 // if (CCFileClass("SCORES.MIX").Is_Available()) { 541 ScoresPresent = true; 542 if (!ScoreMix) { 543 ScoreMix = new MixFileClass("SCORES.MIX"); 544 ThemeClass::Scan(); 545 } 546 // } 547 #endif 548 549 /* 550 ** These are sound card specific, but the install program would have 551 ** copied the coorect versions to the hard drive. 552 */ 553 CCDebugString ("C&C95 - About to register SPEECH.MIX\n"); 554 if (CCFileClass("SPEECH.MIX").Is_Available()) { 555 new MixFileClass("SPEECH.MIX"); // Never cached. 556 } 557 CCDebugString ("C&C95 - About to register SOUNDS.MIX\n"); 558 new MixFileClass("SOUNDS.MIX"); // Cached. 559 560 /* 561 ** Initialize the animation system. 562 */ 563 CCDebugString ("C&C95 - About to initialise the animation system\n"); 564 Anim_Init(); 565 566 if (SpawnedFromWChat){ 567 Special.IsFromWChat = true; 568 } 569 570 /* 571 ** Play the introduction movies. 572 */ 573 CCDebugString ("C&C95 - About to play the intro movie\n"); 574 if (!Special.IsFromInstall && !Special.IsFromWChat) Play_Intro(true); 575 576 /* 577 ** Wait for a VSync; during the vertical blank, set the game palette & blit 578 ** the title screen. We must ensure no RGB values in the game palette match 579 ** those in the WWLIB's 'CurrentPalette', or the WWLIB palette-set routine 580 ** will skip that color; the VQ player will have changed that color (behind 581 ** WWLIB's back), so it will be incorrect. 582 */ 583 memset(CurrentPalette, 0x01, 768); 584 585 if (!Special.IsFromInstall) { 586 Load_Title_Screen("HTITLE.PCX", &HidPage, Palette); 587 Blit_Hid_Page_To_Seen_Buff(); 588 } 589 590 Hide_Mouse(); 591 Wait_Vert_Blank(); 592 if (!Special.IsFromInstall) { 593 Set_Palette(Palette); 594 Blit_Hid_Page_To_Seen_Buff(); 595 Show_Mouse(); 596 } 597 Call_Back(); 598 // Window_Dialog_Box(hCCLibrary, "DIALOG_1", MainWindow, MakeProcInstance((FARPROC)Start_Game_Proc, hInstance)); 599 // if (hCCLibrary) FreeLibrary(hCCLibrary); 600 601 #ifdef DEMO 602 MixFileClass::Cache("DEMO.MIX"); 603 MixFileClass::Cache("SOUNDS.MIX"); 604 #else 605 /* 606 ** Cache the main game data. This operation can take a very long time. 607 */ 608 MixFileClass::Cache("CONQUER.MIX"); 609 if (SampleType != 0 && !Debug_Quiet) { 610 MixFileClass::Cache("SOUNDS.MIX"); 611 if (Special.IsJuvenile) { 612 new MixFileClass("ZOUNDS.MIX"); // Cached. 613 MixFileClass::Cache("ZOUNDS.MIX"); 614 } 615 } 616 Call_Back(); 617 #endif 618 619 // malloc(2); 620 621 /* 622 ** Perform any special debug-only processing. This includes preparing the 623 ** monochrome screen. 624 */ 625 Mono_Clear_Screen(); 626 627 #ifdef ONHOLD 628 /* 629 ** Check for addition options not specified on the command-line. This must 630 ** be done before the One_Time calls, but after the shape buffer is set up. 631 */ 632 Parse_INI_File(); 633 #endif 634 635 /* 636 ** Perform one-time game system initializations. 637 */ 638 Call_Back(); 639 // malloc(3); 640 Map.One_Time(); 641 // malloc(4); 642 Logic.One_Time(); 643 // malloc(5); 644 Options.One_Time(); 645 646 // malloc(6); 647 648 ObjectTypeClass::One_Time(); 649 BuildingTypeClass::One_Time(); 650 BulletTypeClass::One_Time(); 651 HouseTypeClass::One_Time(); 652 653 TemplateTypeClass::One_Time(); 654 OverlayTypeClass::One_Time(); 655 SmudgeTypeClass::One_Time(); 656 TerrainTypeClass::One_Time(); 657 UnitTypeClass::One_Time(); 658 659 InfantryTypeClass::One_Time(); 660 AnimTypeClass::One_Time(); 661 AircraftTypeClass::One_Time(); 662 HouseClass::One_Time(); 663 664 /* 665 ** Speech holding tank buffer. Since speech does not mix, it can be placed 666 ** into a custom holding tank only as large as the largest speech file to 667 ** be played. 668 */ 669 SpeechBuffer = new char [SPEECH_BUFFER_SIZE]; 670 Call_Back(); 671 672 /* 673 ** WWLIB bug: MouseState is in some undefined state; show the mouse until 674 ** it really shows. 675 */ 676 Map.Set_Default_Mouse(MOUSE_NORMAL, false); 677 Show_Mouse(); 678 //#ifdef FIX_ME_LATER 679 while (Get_Mouse_State() > 0) Show_Mouse(); 680 //#endif //FIX_ME_LATER 681 Call_Back(); 682 683 #ifndef DEMO 684 /* 685 ** Load multiplayer scenario descriptions 686 */ 687 Read_Scenario_Descriptions(); 688 #endif 689 690 /* 691 ** Initialize the multiplayer score values 692 */ 693 MPlayerGamesPlayed = 0; 694 MPlayerNumScores = 0; 695 MPlayerCurGame = 0; 696 for (int i = 0; i < MAX_MULTI_NAMES; i++) { 697 MPlayerScore[i].Name[0] = '\0'; 698 MPlayerScore[i].Wins = 0; 699 for (int j = 0; j < MAX_MULTI_GAMES; j++) { 700 MPlayerScore[i].Kills[j] = -1; // -1 = this player didn't play this round 701 } 702 } 703 704 /* 705 ** Copy the title screen's palette into the GamePalette & OriginalPalette, 706 ** because the options Load routine uses these palettes to set the brightness, etc. 707 */ 708 memcpy (GamePalette, Palette, 768); 709 memcpy (OriginalPalette, Palette, 768); 710 711 /* 712 ** Read game options, so the GameSpeed is initialized when multiplayer 713 ** dialogs are invoked. (GameSpeed must be synchronized between systems.) 714 */ 715 Options.Load_Settings(); 716 717 return(true); 718 } 719 720 721 //#ifndef NOMEMCHECK 722 void Uninit_Game(void) 723 { 724 delete Map.ShadowPage; 725 Map.ShadowPage = NULL; 726 Map.Free_Cells(); 727 728 delete [] SpeechBuffer; 729 730 CCFileClass::Clear_Search_Drives(); 731 MixFileClass::Free_All(); 732 733 Units.Set_Heap(0); 734 Factories.Set_Heap(0); 735 Terrains.Set_Heap(0); 736 Templates.Set_Heap(0); 737 Smudges.Set_Heap(0); 738 Overlays.Set_Heap(0); 739 Infantry.Set_Heap(0); 740 Bullets.Set_Heap(0); 741 Buildings.Set_Heap(0); 742 Anims.Set_Heap(0); 743 Aircraft.Set_Heap(0); 744 Triggers.Set_Heap(0); 745 TeamTypes.Set_Heap(0); 746 Teams.Set_Heap(0); 747 Houses.Set_Heap(0); 748 749 delete [] _ShapeBuffer; 750 Set_Shape_Buffer(NULL, 0); 751 delete [] BlackPalette; 752 delete [] GamePalette; 753 delete [] OriginalPalette; 754 delete [] WhitePalette; 755 756 WWDOS_Shutdown(); 757 delete [] Palette; 758 } 759 //#endif 760 761 extern bool Do_The_Internet_Menu_Thang(void); 762 extern int ShowCommand; 763 764 /*********************************************************************************************** 765 * Select_Game -- The game's main menu * 766 * * 767 * INPUT: * 768 * fade if true, will fade the palette in gradually * 769 * * 770 * OUTPUT: * 771 * none. * 772 * * 773 * WARNINGS: * 774 * none. * 775 * * 776 * HISTORY: * 777 * 06/05/1995 BRR : Created. * 778 *=============================================================================================*/ 779 extern int Com_Fake_Scenario_Dialog(void); 780 extern int Com_Show_Fake_Scenario_Dialog(void); 781 extern int WChatMaxAhead; 782 extern int WChatSendRate; 783 void Check_From_WChat(char *wchat_name); 784 785 bool Select_Game(bool fade) 786 { 787 enum { 788 SEL_TIMEOUT = -1, // main menu timeout--go into attract mode 789 #ifdef NEWMENU 790 SEL_NEW_SCENARIO, // Expansion scenario to play. 791 #endif 792 SEL_START_NEW_GAME, // start a new game 793 #ifdef BONUS_MISSIONS 794 SEL_BONUS_MISSIONS, 795 #endif //BONUS_MISSIONS 796 SEL_INTERNET, 797 SEL_LOAD_MISSION, // load a saved game 798 SEL_MULTIPLAYER_GAME, // play modem/null-modem/network game 799 SEL_INTRO, // replay the intro 800 SEL_EXIT, // exit to DOS 801 SEL_FAME, // view the hall of fame 802 SEL_NONE, // placeholder default value 803 }; 804 bool gameloaded=false; // Has the game been loaded from the menu? 805 int selection; // the default selection 806 bool process = true; // false = break out of while loop 807 bool display = true; 808 CountDownTimerClass count; 809 int cd_index; 810 811 MEMORYSTATUS mem_info; 812 mem_info.dwLength=sizeof(mem_info); 813 GlobalMemoryStatus(&mem_info); 814 815 /* 816 ** Enable the DDE Server so we can get internet start game packets from WChat 817 */ 818 DDEServer.Enable(); 819 820 if (Special.IsFromInstall) { 821 /* 822 ** Special case for machines with 12 megs or less - just play intro, no choose side screen 823 */ 824 if (mem_info.dwTotalPhys < 12*1024*1024){ 825 VisiblePage.Clear(); 826 Play_Movie("INTRO2", THEME_NONE, false); 827 BreakoutAllowed = true; 828 Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back); 829 fade = true; 830 VisiblePage.Clear(); 831 }else{ 832 display = false; 833 Show_Mouse(); 834 } 835 } 836 837 /* 838 ** [Re]set any globals that need it, in preparation for a new scenario 839 */ 840 GameActive = true; 841 DoList.Init(); 842 OutList.Init(); 843 Frame = 0; 844 PlayerWins = false; 845 PlayerLoses = false; 846 MPlayerObiWan = false; 847 Debug_Unshroud = false; 848 Map.Set_Cursor_Shape(0); 849 Map.PendingObjectPtr = 0; 850 Map.PendingObject = 0; 851 Map.PendingHouse = HOUSE_NONE; 852 853 /* 854 ** Initialize multiplayer-protocol-specific variables: 855 ** If CommProtocol MULTI_E_COMP is used, you must: 856 ** Init FrameSendRate to a sensible value (3 is good) 857 ** Init MPlayerMaxAhead to an even multiple of FrameSendRate, and it must 858 ** be at least 2 * MPlayerMaxAhead 859 */ 860 CommProtocol = COMM_PROTOCOL_SINGLE_NO_COMP; 861 if (!Special.IsFromWChat){ 862 FrameSendRate = 3; 863 } 864 865 ProcessTicks = 0; 866 ProcessFrames = 0; 867 DesiredFrameRate = 30; 868 //#if(TIMING_FIX) 869 NewMaxAheadFrame1 = 0; 870 NewMaxAheadFrame2 = 0; 871 //#endif 872 873 /* 874 ** Init multiplayer game scores. Let Wins accumulate; just init the current 875 ** Kills for this game. Kills of -1 means this player didn't play this round. 876 */ 877 for (int i = 0 ; i < MAX_MULTI_GAMES; i++) { 878 MPlayerScore[i].Kills[MPlayerCurGame] = -1; 879 } 880 881 /* 882 ** Set default mouse shape 883 */ 884 Map.Set_Default_Mouse(MOUSE_NORMAL, false); 885 886 /* 887 ** If the last game we played was a multiplayer game, jump right to that 888 ** menu by pre-setting 'selection'. 889 */ 890 if (GameToPlay == GAME_NORMAL) { 891 selection = SEL_NONE; 892 } else { 893 selection = SEL_MULTIPLAYER_GAME; 894 } 895 896 /* 897 ** Main menu processing; only do this if we're not in editor mode. 898 */ 899 if (!Debug_Map) { 900 901 /* 902 ** Menu selection processing loop 903 */ 904 ScenarioInit++; 905 Theme.Queue_Song(THEME_MAP1); 906 ScenarioInit--; 907 908 /* 909 ** If we're playing back a recording, load all pertinant values & skip 910 ** the menu loop. Hide the now-useless mouse pointer. 911 */ 912 if (PlaybackGame && RecordFile.Is_Available()) { 913 if (RecordFile.Open(READ)) { 914 Load_Recording_Values(); 915 process = false; 916 Theme.Fade_Out(); 917 } else 918 PlaybackGame = false; 919 } 920 921 922 /* 923 ** Handle case where we were spawned from Wchat 924 */ 925 if (SpawnedFromWChat){ 926 Special.IsFromInstall = false; //Dont play intro if we were spawned from wchat 927 selection = SEL_INTERNET; 928 Theme.Queue_Song(THEME_NONE); 929 GameToPlay = GAME_INTERNET; 930 display = false; 931 Set_Logic_Page(SeenBuff); 932 } 933 934 935 while (process) { 936 937 /* 938 ** If we have just received input focus again after running in the background then 939 ** we need to redraw. 940 */ 941 if (AllSurfaces.SurfacesRestored){ 942 AllSurfaces.SurfacesRestored=FALSE; 943 display=TRUE; 944 } 945 946 /* 947 ** Redraw the title page if needed 948 */ 949 if (display) { 950 Hide_Mouse(); 951 952 /* 953 ** Display the title page; fade it in if this is the first time 954 ** through the loop, and the 'fade' flag is true 955 */ 956 Load_Title_Screen("HTITLE.PCX", &HidPage, Palette); 957 memcpy (GamePalette, Palette, 768); 958 Blit_Hid_Page_To_Seen_Buff(); 959 960 if (fade) { 961 Fade_Palette_To(Palette, FADE_PALETTE_SLOW, Call_Back); 962 fade = false; 963 } 964 965 Set_Logic_Page(SeenBuff); 966 #ifdef VIRGIN_CHEAT_KEYS 967 Fancy_Text_Print("V.%d%s", SeenBuff.Get_Width() - 1, SeenBuff.Get_Height() - 10, DKGREY, TBLACK, TPF_6POINT|TPF_FULLSHADOW|TPF_RIGHT, Version_Number(), VersionText, FOREIGN_VERSION_NUMBER); 968 // Fancy_Text_Print("V.%d%s%02d", 319, 190, DKGREY, TBLACK, TPF_6POINT|TPF_FULLSHADOW|TPF_RIGHT, Version_Number(), VersionText, FOREIGN_VERSION_NUMBER); 969 #else 970 971 #ifdef DEMO 972 Version_Number(); 973 Fancy_Text_Print("DEMO V%s", SeenBuff.Get_Width() - 1, SeenBuff.Get_Height() - 10, DKGREY, TBLACK, TPF_6POINT|TPF_FULLSHADOW|TPF_RIGHT, VersionText); 974 #else 975 Fancy_Text_Print("V.%d%s", SeenBuff.Get_Width() - 1, SeenBuff.Get_Height() - 10, DKGREY, TBLACK, TPF_6POINT|TPF_FULLSHADOW|TPF_RIGHT, Version_Number(), VersionText); 976 #endif 977 #endif 978 display = false; 979 Show_Mouse(); 980 } else { 981 if (RunningAsDLL) { 982 return true;; 983 } 984 } 985 /* 986 ** Display menu and fetch selection from player. 987 */ 988 if (Special.IsFromInstall && mem_info.dwTotalPhys >= 12*1024*1024){ 989 selection = SEL_START_NEW_GAME; 990 Theme.Queue_Song(THEME_NONE); 991 } 992 993 /* 994 ** Handle case where we were spawned from Wchat 995 */ 996 if (Special.IsFromWChat && DDEServer.Get_MPlayer_Game_Info()){ 997 Check_From_WChat(NULL); 998 selection = SEL_MULTIPLAYER_GAME; 999 Theme.Queue_Song(THEME_NONE); 1000 GameToPlay = GAME_INTERNET; 1001 }else{ 1002 /* 1003 ** We werent spawned but we could still receive a DDE packet from wchat 1004 */ 1005 if (DDEServer.Get_MPlayer_Game_Info()){ 1006 Check_From_WChat(NULL); 1007 /* 1008 ** Make sure top and bottom of screen are clear in 640x480 mode 1009 */ 1010 if (ScreenHeight == 480){ 1011 VisiblePage.Fill_Rect (0, 0, 639, 40, 0); 1012 VisiblePage.Fill_Rect (0, 440, 639, 479, 0); 1013 } 1014 } 1015 } 1016 1017 if (selection == SEL_NONE) { 1018 // selection = Main_Menu(0); 1019 selection = Main_Menu(ATTRACT_MODE_TIMEOUT); 1020 } 1021 Call_Back(); 1022 1023 switch (selection) { 1024 1025 #ifdef NEWMENU 1026 1027 case SEL_INTERNET: 1028 /* 1029 ** Only call up the internet menu code if we dont already have connect info from WChat 1030 */ 1031 if (!DDEServer.Get_MPlayer_Game_Info()){ 1032 CCDebugString ("C&C95 - About to call Internet Menu.\n"); 1033 if (Do_The_Internet_Menu_Thang() && DDEServer.Get_MPlayer_Game_Info()){ 1034 CCDebugString ("C&C95 - About to call Check_From_WChat.\n"); 1035 Check_From_WChat(NULL); 1036 selection = SEL_MULTIPLAYER_GAME; 1037 display = false; 1038 GameToPlay = GAME_INTERNET; 1039 }else{ 1040 selection = SEL_NONE; 1041 display = true; 1042 } 1043 }else{ 1044 CCDebugString ("C&C95 - About to call Check_From_WChat.\n"); 1045 Check_From_WChat(NULL); 1046 display = false; 1047 GameToPlay = GAME_INTERNET; 1048 selection = SEL_MULTIPLAYER_GAME; 1049 } 1050 break; 1051 1052 1053 /* 1054 ** Pick an expansion scenario. 1055 */ 1056 case SEL_NEW_SCENARIO: 1057 CarryOverMoney = 0; 1058 if (Expansion_Dialog()) { 1059 Theme.Fade_Out(); 1060 // Theme.Queue_Song(THEME_AOI); 1061 GameToPlay = GAME_NORMAL; 1062 process = false; 1063 } else { 1064 display = true; 1065 selection = SEL_NONE; 1066 } 1067 break; 1068 1069 1070 #ifdef BONUS_MISSIONS 1071 1072 /* 1073 ** User selected to play a bonus scenario. 1074 */ 1075 case SEL_BONUS_MISSIONS: 1076 CarryOverMoney = 0; 1077 1078 /* 1079 ** Ensure that CD1 or CD2 is in the drive. These missions 1080 ** are not on the covert CD. 1081 */ 1082 cd_index = Get_CD_Index(CCFileClass::Get_CD_Drive(), 1*60); 1083 /* 1084 ** If cd_index == 2 then its a covert CD 1085 */ 1086 if (cd_index == 2){ 1087 RequiredCD = 0; 1088 if (!Force_CD_Available (RequiredCD)){ 1089 Prog_End("Select_Game - CD not found", true); 1090 exit(EXIT_FAILURE); 1091 } 1092 } 1093 1094 if (Bonus_Dialog()) { 1095 Theme.Fade_Out(); 1096 GameToPlay = GAME_NORMAL; 1097 process = false; 1098 } else { 1099 display = true; 1100 selection = SEL_NONE; 1101 } 1102 break; 1103 1104 1105 #endif //BONUS_MISSIONS 1106 1107 #endif 1108 1109 /* 1110 ** SEL_START_NEW_GAME: Play the game 1111 */ 1112 case SEL_START_NEW_GAME: 1113 CarryOverMoney = 0; 1114 1115 #ifdef DEMO 1116 Hide_Mouse(); 1117 Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back); 1118 Load_Title_Screen("PREPICK.PCX", &HidPage, Palette); 1119 Blit_Hid_Page_To_Seen_Buff(); 1120 Fade_Palette_To(Palette, FADE_PALETTE_MEDIUM, Call_Back); 1121 Clear_KeyBuffer(); 1122 while (!Check_Key_Num()) { 1123 Call_Back(); 1124 } 1125 Get_Key_Num(); 1126 Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back); 1127 Show_Mouse(); 1128 1129 Scenario = 1; 1130 BuildLevel = 1; 1131 #else 1132 Scenario = 1; 1133 BuildLevel = 1; 1134 #endif 1135 ScenPlayer = SCEN_PLAYER_GDI; 1136 ScenDir = SCEN_DIR_EAST; 1137 Whom = HOUSE_GOOD; 1138 1139 #ifndef DEMO 1140 Theme.Fade_Out(); 1141 Choose_Side(); 1142 #endif 1143 1144 /* 1145 ** If user is playing special mode, do NOT change Whom; leave it set to 1146 ** GDI or NOD. Ini.cpp will set the player's ActLike to mirror the 1147 ** Whom value. 1148 */ 1149 if (Special.IsJurassic && AreThingiesEnabled) { 1150 ScenPlayer = SCEN_PLAYER_JP; 1151 ScenDir = SCEN_DIR_EAST; 1152 } 1153 1154 GameToPlay = GAME_NORMAL; 1155 process = false; 1156 break; 1157 1158 /* 1159 ** Load a saved game. 1160 */ 1161 case SEL_LOAD_MISSION: 1162 if (LoadOptionsClass(LoadOptionsClass::LOAD).Process()) { 1163 //Theme.Fade_Out(); 1164 Theme.Queue_Song(THEME_AOI); 1165 process = false; 1166 gameloaded = true; 1167 } else { 1168 display = true; 1169 selection = SEL_NONE; 1170 } 1171 break; 1172 1173 /* 1174 ** SEL_MULTIPLAYER_GAME: set 'GameToPlay' to NULL-modem, modem, or 1175 ** network play. 1176 */ 1177 case SEL_MULTIPLAYER_GAME: 1178 1179 #ifdef DEMO 1180 Hide_Mouse(); 1181 Set_Palette(BlackPalette); 1182 Load_Title_Screen("DEMOPIC.PCX", &HidPage, Palette); 1183 Blit_Hid_Page_To_Seen_Buff(); 1184 Fade_Palette_To(Palette, FADE_PALETTE_MEDIUM, Call_Back); 1185 Clear_KeyBuffer(); 1186 while (!Check_Key()) { 1187 Call_Back(); 1188 } 1189 Get_Key(); 1190 Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back); 1191 Show_Mouse(); 1192 display = true; 1193 fade = true; 1194 selection = SEL_NONE; 1195 #else 1196 switch (GameToPlay) { 1197 1198 /* 1199 ** If 'GameToPlay' isn't already set up for a multiplayer game, 1200 ** we must prompt the user for which type of multiplayer game 1201 ** they want. 1202 */ 1203 case GAME_NORMAL: 1204 GameToPlay = Select_MPlayer_Game(); 1205 if (GameToPlay == GAME_NORMAL) { // 'Cancel' 1206 display = true; 1207 selection = SEL_NONE; 1208 } 1209 break; 1210 1211 case GAME_NULL_MODEM: 1212 case GAME_MODEM: 1213 #if (0) 1214 if ( NullModem.Num_Connections() ) { 1215 NullModem.Init_Send_Queue(); 1216 1217 if ((GameToPlay == GAME_NULL_MODEM && 1218 ModemGameToPlay == MODEM_NULL_HOST) || 1219 (GameToPlay == GAME_MODEM && 1220 ModemGameToPlay == MODEM_DIALER) ) { 1221 1222 if ( !Com_Scenario_Dialog() ) { 1223 GameToPlay = Select_Serial_Dialog(); 1224 if (GameToPlay == GAME_NORMAL) { // user hit Cancel 1225 display = true; 1226 selection = SEL_NONE; 1227 } 1228 } 1229 } else { 1230 if ( !Com_Show_Scenario_Dialog() ) { 1231 GameToPlay = Select_Serial_Dialog(); 1232 if (GameToPlay == GAME_NORMAL) { // user hit Cancel 1233 display = true; 1234 selection = SEL_NONE; 1235 } 1236 } 1237 } 1238 } else { 1239 GameToPlay = Select_MPlayer_Game(); 1240 if (GameToPlay == GAME_NORMAL) { // 'Cancel' 1241 display = true; 1242 selection = SEL_NONE; 1243 } 1244 } 1245 #endif 1246 break; 1247 1248 1249 1250 #ifdef FORCE_WINSOCK 1251 /* 1252 ** Handle being spawned from WChat. Intermnet play based on IPX code now. 1253 */ 1254 case GAME_INTERNET: 1255 CCDebugString ("C&C95 - case GAME_INTERNET:\n"); 1256 if (Special.IsFromWChat){ 1257 //MessageBox (NULL, "About to restore focus to C&C95", "C&C95", MB_OK); 1258 CCDebugString ("C&C95 - About to give myself focus.\n"); 1259 SetForegroundWindow ( MainWindow ); 1260 ShowWindow ( MainWindow, ShowCommand ); 1261 1262 CCDebugString ("C&C95 - About to initialise Winsock.\n"); 1263 if (Winsock.Init()){ 1264 CCDebugString ("C&C95 - About to read multiplayer settings.\n"); 1265 Read_MultiPlayer_Settings (); 1266 Server = PlanetWestwoodIsHost; 1267 1268 CCDebugString ("C&C95 - About to set addresses.\n"); 1269 Winsock.Set_Host_Address(PlanetWestwoodIPAddress); 1270 1271 CCDebugString ("C&C95 - About to call Start_Server or Start_Client.\n"); 1272 if (Server){ 1273 ModemGameToPlay = INTERNET_HOST; 1274 Winsock.Start_Server(); 1275 }else{ 1276 ModemGameToPlay = INTERNET_JOIN; 1277 Winsock.Start_Client(); 1278 } 1279 1280 1281 //#if (0) 1282 /* 1283 ** Flush out any pending packets from a previous game. 1284 */ 1285 CCDebugString ("C&C95 - About to flush packet queue.\n"); 1286 CCDebugString ("C&C95 - Allocating scrap memory.\n"); 1287 char *temp_buffer = new char[1024]; 1288 1289 CCDebugString ("C&C95 - Creating timer class instance.\n"); 1290 CountDownTimerClass ptimer; 1291 1292 CCDebugString ("C&C95 - Entering read loop.\n"); 1293 while (Winsock.Read(temp_buffer, 1024)){ 1294 1295 CCDebugString ("C&C95 - Discarding a packet.\n"); 1296 ptimer.Set (30, true); 1297 while (ptimer.Time()){}; 1298 CCDebugString ("C&C95 - Ready to check for more packets.\n"); 1299 1300 } 1301 CCDebugString ("C&C95 - About to delete scrap memory.\n"); 1302 delete temp_buffer; 1303 //#endif //(0) 1304 1305 1306 1307 }else{ 1308 CCDebugString ("C&C95 - Winsock failed to initialise.\n"); 1309 GameToPlay = GAME_NORMAL; 1310 selection = SEL_EXIT; 1311 Special.IsFromWChat = false; 1312 break; 1313 } 1314 1315 CCDebugString ("C&C95 - About to call Init_Network.\n"); 1316 Init_Network(); 1317 1318 if (DDEServer.Get_MPlayer_Game_Info()){ 1319 CCDebugString ("C&C95 - About to call Read_Game_Options.\n"); 1320 Read_Game_Options( NULL ); 1321 }else{ 1322 Read_Game_Options( "C&CSPAWN.INI" ); 1323 } 1324 1325 if (Server){ 1326 1327 CCDebugString ("C&C95 - About to call Server_Remote_Connect.\n"); 1328 if (Server_Remote_Connect()){ 1329 CCDebugString ("C&C95 - Server_Remote_Connect returned success.\n"); 1330 break; 1331 }else{ 1332 /* 1333 ** We failed to connect to the other player 1334 * 1335 * SEND FAILURE PACKET TO WCHAT HERE !!!!! 1336 * 1337 */ 1338 Winsock.Close(); 1339 GameToPlay = GAME_NORMAL; 1340 selection = SEL_NONE; 1341 DDEServer.Delete_MPlayer_Game_Info(); // Make sure we dont go round in an infinite loop 1342 //Special.IsFromWChat = false; 1343 break; 1344 } 1345 }else{ 1346 CCDebugString ("C&C95 - About to call Client_Remote_Connect.\n"); 1347 if (Client_Remote_Connect()){ 1348 CCDebugString ("C&C95 - Client_Remote_Connect returned success.\n"); 1349 break; 1350 }else{ 1351 /* 1352 ** We failed to connect to the other player 1353 * 1354 * SEND FAILURE PACKET TO WCHAT HERE !!!!! 1355 * 1356 */ 1357 Winsock.Close(); 1358 GameToPlay = GAME_NORMAL; 1359 selection = SEL_NONE; 1360 DDEServer.Delete_MPlayer_Game_Info(); // Make sure we dont go round in an infinite loop 1361 //Special.IsFromWChat = false; 1362 break; 1363 } 1364 } 1365 1366 }else{ 1367 GameToPlay = Select_MPlayer_Game(); 1368 if (GameToPlay == GAME_NORMAL) { // 'Cancel' 1369 display = true; 1370 selection = SEL_NONE; 1371 } 1372 } 1373 break; 1374 1375 #endif //FORCE_WINSOCK 1376 1377 } 1378 1379 1380 switch (GameToPlay) { 1381 /* 1382 ** Internet, Modem or Null-Modem 1383 */ 1384 case GAME_MODEM: 1385 case GAME_NULL_MODEM: 1386 case GAME_INTERNET: 1387 Theme.Fade_Out(); 1388 ScenPlayer = SCEN_PLAYER_2PLAYER; 1389 ScenDir = SCEN_DIR_EAST; 1390 process = false; 1391 Options.ScoreVolume = 0; 1392 break; 1393 1394 1395 /* 1396 ** Network (IPX): start a new network game. 1397 */ 1398 case GAME_IPX: 1399 /* 1400 ** Init network system & remote-connect 1401 */ 1402 if (Init_Network() && Remote_Connect()) { 1403 #if (0) 1404 char seed[80]; 1405 sprintf (seed, "Seed: %08x\n", Seed); 1406 CCDebugString (seed); 1407 1408 sprintf (seed, "rand: %04x\n", rand()); 1409 CCDebugString (seed); 1410 1411 sprintf (seed, "rand: %04x\n", rand()); 1412 CCDebugString (seed); 1413 1414 sprintf (seed, "rand: %04x\n", rand()); 1415 CCDebugString (seed); 1416 #endif 1417 Options.ScoreVolume = 0; 1418 ScenPlayer = SCEN_PLAYER_MPLAYER; 1419 ScenDir = SCEN_DIR_EAST; 1420 process = false; 1421 Theme.Fade_Out(); 1422 } else { // user hit cancel, or init failed 1423 GameToPlay = GAME_NORMAL; 1424 display = true; 1425 selection = SEL_NONE; 1426 } 1427 break; 1428 } 1429 #endif 1430 break; 1431 1432 /* 1433 ** Play a VQ 1434 */ 1435 case SEL_INTRO: 1436 Theme.Fade_Out(); 1437 Theme.Stop(); 1438 Call_Back(); 1439 1440 Force_CD_Available(-1); 1441 Play_Intro(false); 1442 Hide_Mouse(); 1443 1444 // verify existance of movie file before playing this sequence. 1445 if (CCFileClass("TRAILER.VQA").Is_Available()) { 1446 Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back); 1447 VisiblePage.Clear(); 1448 if (CCFileClass("ATTRACT2.CPS").Is_Available()){ 1449 Load_Uncompress(CCFileClass("ATTRACT2.CPS"), SysMemPage, SysMemPage, Palette); 1450 SysMemPage.Scale(SeenBuff, 0, 0, 0, 0, 320, 199, 640, 398); 1451 Fade_Palette_To(Palette, FADE_PALETTE_MEDIUM, Call_Back); 1452 } 1453 Clear_KeyBuffer(); 1454 count.Set(TIMER_SECOND*3); 1455 while (count.Time()) { 1456 Call_Back(); 1457 } 1458 Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back); 1459 1460 Play_Movie("TRAILER"); // Red Alert teaser. 1461 } 1462 1463 if (CCFileClass("SIZZLE.VQA").Is_Available()) { 1464 Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back); 1465 VisiblePage.Clear(); 1466 if (CCFileClass("ATTRACT2.CPS").Is_Available()){ 1467 Load_Uncompress(CCFileClass("ATTRACT2.CPS"), SysMemPage, SysMemPage, Palette); 1468 SysMemPage.Scale(SeenBuff, 0, 0, 0, 0, 320, 199, 640, 398); 1469 Fade_Palette_To(Palette, FADE_PALETTE_MEDIUM, Call_Back); 1470 } 1471 Clear_KeyBuffer(); 1472 count.Set(TIMER_SECOND*3); 1473 while (count.Time()) { 1474 Call_Back(); 1475 } 1476 Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back); 1477 1478 Play_Movie("SIZZLE"); // Red Alert teaser. 1479 } 1480 1481 if (CCFileClass("SIZZLE2.VQA").Is_Available()) { 1482 Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back); 1483 VisiblePage.Clear(); 1484 if (CCFileClass("ATTRACT2.CPS").Is_Available()){ 1485 Load_Uncompress(CCFileClass("ATTRACT2.CPS"), SysMemPage, SysMemPage, Palette); 1486 SysMemPage.Scale(SeenBuff, 0, 0, 0, 0, 320, 199, 640, 398); 1487 Fade_Palette_To(Palette, FADE_PALETTE_MEDIUM, Call_Back); 1488 } 1489 Clear_KeyBuffer(); 1490 count.Set(TIMER_SECOND*3); 1491 while (count.Time()) { 1492 Call_Back(); 1493 } 1494 Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back); 1495 1496 Play_Movie("SIZZLE2"); // Red Alert teaser. 1497 } 1498 1499 Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back); 1500 VisiblePage.Clear(); 1501 if (CCFileClass("ATTRACT2.CPS").Is_Available()){ 1502 Load_Uncompress(CCFileClass("ATTRACT2.CPS"), SysMemPage, SysMemPage, Palette); 1503 SysMemPage.Scale(SeenBuff, 0, 0, 0, 0, 320, 199, 640, 398); 1504 Fade_Palette_To(Palette, FADE_PALETTE_MEDIUM, Call_Back); 1505 } 1506 Clear_KeyBuffer(); 1507 count.Set(TIMER_SECOND*3); 1508 while (count.Time()) { 1509 Call_Back(); 1510 } 1511 Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back); 1512 1513 Play_Movie("CC2TEASE"); 1514 Show_Mouse(); 1515 1516 ScenarioInit++; 1517 Theme.Play_Song (THEME_MAP1); 1518 ScenarioInit--; 1519 display = true; 1520 fade = true; 1521 selection = SEL_NONE; 1522 break; 1523 1524 /* 1525 ** Exit to DOS. 1526 */ 1527 case SEL_EXIT: 1528 #ifdef JAPANESE 1529 Hide_Mouse(); 1530 #endif 1531 Theme.Fade_Out(); 1532 Fade_Palette_To(BlackPalette, FADE_PALETTE_SLOW, NULL); 1533 #ifdef JAPANESE 1534 VisiblePage.Clear(); 1535 #endif 1536 return(false); 1537 1538 /* 1539 ** Display the hall of fame. 1540 */ 1541 case SEL_FAME: 1542 break; 1543 1544 case SEL_TIMEOUT: 1545 if (AllowAttract && RecordFile.Is_Available()) { 1546 PlaybackGame = true; 1547 if (RecordFile.Open(READ)) { 1548 Load_Recording_Values(); 1549 process = false; 1550 Theme.Fade_Out(); 1551 } else { 1552 PlaybackGame = false; 1553 selection = SEL_NONE; 1554 } 1555 } else { 1556 selection = SEL_NONE; 1557 } 1558 break; 1559 1560 default: 1561 break; 1562 } 1563 } 1564 } else { 1565 1566 /* 1567 ** For Debug_Map (editor) mode, if JP option is on, set to load that scenario 1568 */ 1569 Scenario = 1; 1570 if (Special.IsJurassic && AreThingiesEnabled) { 1571 ScenPlayer = SCEN_PLAYER_JP; 1572 ScenDir = SCEN_DIR_EAST; 1573 } 1574 } 1575 CCDebugString ("C&C95 - About to start game initialisation.\n"); 1576 #ifdef FORCE_WINSOCK 1577 if (GameToPlay == GAME_INTERNET){ 1578 CommProtocol = COMM_PROTOCOL_MULTI_E_COMP; 1579 if (!Special.IsFromWChat){ 1580 FrameSendRate = 5; //3; 1581 } 1582 } 1583 #endif //FORCE_WINSOCK 1584 /* 1585 ** Don't carry stray keystrokes into game. 1586 */ 1587 Kbd.Clear(); 1588 1589 /* 1590 ** Get a pointer to the compiler's random number seed. 1591 ** the Get_EAX() must follow immediately after the srand(0) in order to save 1592 ** the address of the random seed. (Currently not used.) 1593 */ 1594 srand(0); 1595 //RandSeedPtr = (long *)Get_EAX(); // ST - 1/2/2019 5:26PM 1596 1597 /* 1598 ** Initialize the random number Seed. For multiplayer, this will have been done 1599 ** in the connection dialogs. For single-player games, AND if we're not playing 1600 ** back a recording, init the Seed to a random value. 1601 */ 1602 if (GameToPlay == GAME_NORMAL && !PlaybackGame) { 1603 srand(timeGetTime()); 1604 //randomize(); 1605 Seed = rand(); 1606 } 1607 1608 /* 1609 ** If user has specified a desired random number seed, use it for multiplayer games 1610 */ 1611 if (CustomSeed != 0) { 1612 Seed = CustomSeed; 1613 } 1614 1615 /* 1616 ** Save initialization values if we're recording this game. 1617 ** This must be done after 'Seed' has been initialized. 1618 */ 1619 if (RecordGame) { 1620 if (RecordFile.Open(WRITE)) { 1621 Save_Recording_Values(); 1622 } else { 1623 RecordGame = false; 1624 } 1625 } 1626 1627 /* 1628 ** Initialize the random-number generator. 1629 */ 1630 //Seed = 1; 1631 1632 srand(Seed); 1633 RandNumb = Seed; 1634 SimRandIndex = 0; 1635 #if (0) 1636 DWORD actual; 1637 HANDLE sfile = CreateFile("random.txt", GENERIC_WRITE, 0, 1638 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 1639 1640 if (sfile != INVALID_HANDLE_VALUE){ 1641 SetFilePointer (sfile, 0, NULL, FILE_END); 1642 1643 int minimum; 1644 int maximum; 1645 char whatever[80]; 1646 for ( int i=0 ; i<1000 ; i++){ 1647 minimum = rand(); 1648 maximum = rand(); 1649 1650 sprintf (whatever, "%04x\n", Random_Pick(minimum, maximum)); 1651 WriteFile(sfile, whatever, strlen(whatever), &actual, NULL); 1652 } 1653 CloseHandle (sfile); 1654 } 1655 #endif 1656 1657 1658 1659 /* 1660 ** Load the scenario. Specify variation 'A' for the editor; for the game, 1661 ** don't specify a variation, to make 'Set_Scenario_Name()' pick a random one. 1662 ** Skip this if we've already loaded a save-game. 1663 */ 1664 if (!gameloaded) { 1665 if (Debug_Map) { 1666 Set_Scenario_Name(ScenarioName, Scenario, ScenPlayer, ScenDir, SCEN_VAR_A); 1667 } else { 1668 Set_Scenario_Name(ScenarioName, Scenario, ScenPlayer, ScenDir); 1669 } 1670 1671 /* 1672 ** Start_Scenario() changes the palette; so, fade out & clear the screen 1673 ** before calling it. 1674 */ 1675 Hide_Mouse(); 1676 1677 if (selection != SEL_START_NEW_GAME) { 1678 Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back); 1679 HiddenPage.Clear(); 1680 VisiblePage.Clear(); 1681 } 1682 Show_Mouse(); 1683 1684 Special.IsFromInstall = 0; 1685 CCDebugString ("C&C95 - Starting scenario.\n"); 1686 if (!Start_Scenario(ScenarioName)) { 1687 return(false); 1688 } 1689 CCDebugString ("C&C95 - Scenario started OK.\n"); 1690 } 1691 1692 /* 1693 ** For multiplayer games, initialize the inter-player message system. 1694 ** Do this after loading the scenario, so the map's upper-left corner is 1695 ** properly set. 1696 */ 1697 CCDebugString ("C&C95 - Initialising message system.\n"); 1698 int factor = (SeenBuff.Get_Width() == 320) ? 1 : 2; 1699 Messages.Init(Map.TacPixelX, Map.TacPixelY, 6, MAX_MESSAGE_LENGTH, 6*factor+1); 1700 1701 /* 1702 ** Hide the SeenBuff; force the map to render one frame. The caller can 1703 ** then fade the palette in. 1704 ** (If we loaded a game, this step will fade out the title screen. If we 1705 ** started a scenario, Start_Scenario() will have played a couple of VQ 1706 ** movies, which will have cleared the screen to black already.) 1707 */ 1708 CCDebugString ("C&C95 - About to call Call_Back.\n"); 1709 Call_Back(); 1710 1711 /* 1712 ** This is desperately sad isnt it? 1713 */ 1714 Hide_Mouse(); 1715 Hide_Mouse(); 1716 Hide_Mouse(); 1717 Hide_Mouse(); 1718 WWMouse->Erase_Mouse(&HidPage, TRUE); 1719 1720 1721 Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back); 1722 HiddenPage.Clear(); 1723 VisiblePage.Clear(); 1724 Set_Logic_Page(SeenBuff); 1725 Map.Flag_To_Redraw(); 1726 Call_Back(); 1727 Map.Render(); 1728 //Show_Mouse(); 1729 1730 /* 1731 ** Special hack initialization of 'MPlayerMaxAhead' to accommodate the 1732 ** compression protocol technology. 1733 */ 1734 #ifdef FORCE_WINSOCK 1735 if (CommProtocol==COMM_PROTOCOL_MULTI_E_COMP && GameToPlay!=GAME_NORMAL) { 1736 if (!Special.IsFromWChat){ 1737 MPlayerMaxAhead = FrameSendRate * 3; //2; 1738 }else{ 1739 MPlayerMaxAhead = WChatMaxAhead; 1740 FrameSendRate = WChatSendRate; 1741 } 1742 } 1743 #endif //FORCE_WINSOCK 1744 1745 if (Debug_Map) { 1746 while (Get_Mouse_State() > 1) { 1747 Show_Mouse(); 1748 } 1749 } 1750 1751 return(true); 1752 } 1753 1754 1755 /*********************************************************************************************** 1756 * Play_Intro -- plays the introduction & logo movies * 1757 * * 1758 * INPUT: * 1759 * for_real if true, this function plays the "real" intro; otherwise, it plays * 1760 * a delicious smorgasbord of visual delights, guaranteed to titillate * 1761 * the ocular & auditory nerve pathways. * 1762 * Well, it plays movies, anyway. * 1763 * * 1764 * OUTPUT: * 1765 * none. * 1766 * * 1767 * WARNINGS: * 1768 * none. * 1769 * * 1770 * HISTORY: * 1771 * 06/06/1995 BRR : Created. * 1772 *=============================================================================================*/ 1773 static void Play_Intro(bool for_real) 1774 { 1775 return; // No game intro movies. - LLL 1776 1777 bool playright = !Key_Down(KN_LCTRL) || !Key_Down(KN_RCTRL); 1778 static int _counter = -1; 1779 static char * _names[] = { 1780 #ifdef DEMO 1781 "LOGO", 1782 1783 #else 1784 1785 "INTRO2", 1786 //#ifdef CHEAT_KEYS 1787 "GDIEND1", 1788 "GDIEND2", 1789 "GDIFINA", 1790 "GDIFINB", 1791 "AIRSTRK", 1792 "AKIRA", 1793 "BANNER", 1794 "BCANYON", 1795 "BKGROUND", 1796 "BOMBAWAY", 1797 "BOMBFLEE", 1798 "BURDET1", 1799 "BURDET2", 1800 "CC2TEASE", 1801 "CONSYARD", 1802 "DESFLEES", 1803 "DESKILL", 1804 "DESOLAT", 1805 "DESSWEEP", 1806 "FLAG", 1807 "FLYY", 1808 "FORESTKL", 1809 "GAMEOVER", 1810 "GDI1", 1811 "GDI10", 1812 "GDI11", 1813 "GDI12", 1814 "GDI13", 1815 "GDI14", 1816 "GDI15", 1817 "GDI2", 1818 "GDI3", 1819 "GDI3LOSE", 1820 "GDI4A", 1821 "GDI4B", 1822 "GDI5", 1823 "GDI6", 1824 "GDI7", 1825 "GDI8A", 1826 "GDI8B", 1827 "GDI9", 1828 "GDILOSE", 1829 "GUNBOAT", 1830 "HELLVALY", 1831 "INSITES", 1832 "KANEPRE", 1833 "LANDING", 1834 "LOGO", 1835 "NAPALM", 1836 "NITEJUMP", 1837 "NOD1", 1838 "NOD10A", 1839 "NOD10B", 1840 "NOD11", 1841 "NOD12", 1842 "NOD13", 1843 "NOD1PRE", 1844 "NOD2", 1845 "NOD3", 1846 "NOD4A", 1847 "NOD4B", 1848 "NOD5", 1849 "NOD6", 1850 "NOD7A", 1851 "NOD7B", 1852 "NOD8", 1853 "NOD9", 1854 "NODEND1", 1855 "NODEND2", 1856 "NODEND3", 1857 "NODEND4", 1858 "NODFINAL", 1859 "NODFLEES", 1860 "NODLOSE", 1861 "NODSWEEP", 1862 "NUKE", 1863 "OBEL", 1864 "PARATROP", 1865 "PINTLE", 1866 "PLANECRA", 1867 "PODIUM", 1868 "REFINT", 1869 "RETRO", 1870 "SABOTAGE", 1871 "SAMDIE", 1872 "SAMSITE", 1873 "SEIGE", 1874 "SETHPRE", 1875 "SPYCRASH", 1876 "STEALTH", 1877 "SUNDIAL", 1878 "TANKGO", 1879 "TANKKILL", 1880 "TBRINFO1", 1881 "TBRINFO2", 1882 "TBRINFO3", 1883 "TIBERFX", 1884 "TRTKIL_D", 1885 "TURTKILL", 1886 "VISOR", 1887 //#endif 1888 #endif 1889 NULL 1890 }; 1891 1892 Keyboard::Clear(); 1893 if (for_real) { 1894 Hide_Mouse(); 1895 Play_Movie("LOGO", THEME_NONE, false); 1896 Show_Mouse(); 1897 } else { 1898 if (!Debug_Flag) { 1899 _counter = 0; 1900 } else { 1901 if (playright) _counter++; 1902 if (_counter == -1) _counter = 0; 1903 } 1904 Hide_Mouse(); 1905 Play_Movie(_names[_counter], THEME_NONE); 1906 Show_Mouse(); 1907 if (!_names[_counter]) { 1908 _counter = -1; 1909 } 1910 } 1911 } 1912 1913 1914 /*********************************************************************************************** 1915 * Anim_Init -- Initialize the VQ animation control structure. * 1916 * * 1917 * VQ animations are controlled by a structure passed to the VQ player. This routine * 1918 * initializes the structure to values required by C&C. * 1919 * * 1920 * INPUT: none * 1921 * * 1922 * OUTPUT: none * 1923 * * 1924 * WARNINGS: Only need to call this routine once at the beginning of the game. * 1925 * * 1926 * HISTORY: * 1927 * 12/20/1994 JLB : Created. * 1928 *=============================================================================================*/ 1929 //extern LPDIRECTSOUND SoundObject; 1930 //extern LPDIRECTSOUNDBUFFER PrimaryBufferPtr; 1931 void Anim_Init(void) 1932 { 1933 //PG_TO_FIX 1934 #if (0) 1935 /* Configure player with INI file */ 1936 VQA_DefaultConfig(&AnimControl); 1937 // void const * font = Load_Font(FONT8); 1938 // AnimControl.EVAFont = (char *)font; 1939 // AnimControl.CapFont = (char *)font; 1940 1941 AnimControl.DrawFlags = VQACFGF_TOPLEFT; 1942 AnimControl.DrawFlags |= VQACFGF_BUFFER; 1943 1944 AnimControl.DrawFlags |= VQACFGF_NOSKIP; 1945 1946 //AnimControl.X1 =0; 1947 //AnimControl.Y1 =0; 1948 AnimControl.FrameRate = -1; 1949 AnimControl.DrawRate = -1; 1950 1951 AnimControl.DrawerCallback = VQ_Call_Back; 1952 AnimControl.ImageWidth = 320; 1953 AnimControl.ImageHeight = 200; 1954 AnimControl.Vmode = 0; 1955 AnimControl.ImageBuf = (unsigned char *)SysMemPage.Get_Offset(); 1956 //AnimControl.VBIBit = VertBlank; 1957 //AnimControl.DrawFlags |= VQACFGF_TOPLEFT; 1958 AnimControl.OptionFlags |= VQAOPTF_CAPTIONS|VQAOPTF_EVA; 1959 1960 if (SlowPalette) { 1961 AnimControl.OptionFlags |= VQAOPTF_SLOWPAL; 1962 } 1963 #endif 1964 // AnimControl.AudioBuf = (unsigned char *)HidPage.Get_Buffer(); 1965 // AnimControl.AudioBufSize = 32768U; 1966 //AnimControl.DigiCard = NewConfig.DigitCard; 1967 //AnimControl.HMIBufSize = 8192; 1968 //AnimControl.DigiHandle = Get_Digi_Handle(); 1969 //AnimControl.Volume = 0x00FF; 1970 //AnimControl.AudioRate = 22050; 1971 // if (NewConfig.Speed) AnimControl.AudioRate = 11025; 1972 1973 1974 //PG_TO_FIX 1975 #if (0) 1976 AnimControl.SoundObject = SoundObject; //Get_Sound_Object(); 1977 AnimControl.PrimaryBufferPtr = PrimaryBufferPtr; //Get_Primart_Buffer(); 1978 #endif 1979 1980 //if (!Debug_Quiet && Get_Digi_Handle() != -1) { 1981 //AnimControl.OptionFlags |= VQAOPTF_AUDIO; 1982 //} 1983 1984 #if (0) 1985 if (MonoClass::Is_Enabled()) { 1986 AnimControl.OptionFlags |= VQAOPTF_MONO; 1987 } 1988 #endif 1989 } 1990 1991 1992 /*********************************************************************************************** 1993 * Parse_Command_Line -- Parses the command line parameters. * 1994 * * 1995 * This routine should be called before the graphic mode is initialized. It examines the * 1996 * command line parameters and sets the appropriate globals. If there is an error, then * 1997 * it outputs a command summary and then returns false. * 1998 * * 1999 * INPUT: argc -- The number of command line arguments. * 2000 * * 2001 * argv -- Pointer to character string array that holds the individual arguments. * 2002 * * 2003 * OUTPUT: bool; Was the command line parsed successfully? * 2004 * * 2005 * WARNINGS: none * 2006 * * 2007 * HISTORY: * 2008 * 03/18/1995 JLB : Created. * 2009 *=============================================================================================*/ 2010 bool Parse_Command_Line(int argc, char *argv[]) 2011 { 2012 /* 2013 ** Parse the command line and set globals to reflect the parameters 2014 ** passed in. 2015 */ 2016 #ifdef DEMO 2017 Scenario = 3; 2018 #else 2019 Scenario = 1; 2020 #endif 2021 ScenPlayer = SCEN_PLAYER_GDI; 2022 ScenDir = SCEN_DIR_EAST; 2023 Whom = HOUSE_GOOD; 2024 Special.Init(); 2025 2026 Debug_Map = false; 2027 // Debug_Play_Map = false; 2028 Debug_Unshroud = false; 2029 2030 for (int index = 1; index < argc; index++) { 2031 char * string; // Pointer to argument. 2032 long code = 0; 2033 2034 char arg_string[512]; 2035 int str_len = strlen(argv[index]); 2036 char *src = argv[index]; 2037 char *dest = arg_string; 2038 for (int i=0 ; i<str_len ; i++) { 2039 if (*src == '\"') { 2040 src++; 2041 } else { 2042 *dest++ = *src++; 2043 } 2044 } 2045 *dest++ = 0; 2046 string = arg_string; 2047 strupr(string); 2048 2049 //string = strupr(argv[index]); 2050 2051 /* 2052 ** Print usage text only if requested. 2053 */ 2054 if (stricmp("/?", string) == 0 || stricmp("-?", string) == 0 || stricmp("-h", string) == 0 || stricmp("/h", string) == 0) { 2055 /* 2056 ** Unrecognized command line parameter... Display usage 2057 ** and then exit. 2058 */ 2059 #ifdef GERMAN 2060 puts("Command & Conquer (c) 1995,1996 Westwood Studios\r\n" 2061 "Parameter:\r\n" 2062 // " -CD<Pfad> = Suchpfad fr Daten-Dateien festlegen.\r\n" 2063 " -DESTNET = Netzwerkkennung des Zielrechners festlegen\r\n" 2064 " (Syntax: DESTNETxx.xx.xx.xx)\r\n" 2065 " -SOCKET = Kennung des Netzwerk-Sockets (0 - 16383)\n" 2066 " -STEALTH = Namen im Mehrspieler-Modus verstecken (\"Boss-Modus\")\r\n" 2067 " -MESSAGES = Mitteilungen von auerhalb des Spiels zulassen\r\n" 2068 // " -ELITE = Fortgeschrittene KI und Gefechtstechniken.\r\n" 2069 "\r\n"); 2070 #else 2071 #ifdef FRENCH 2072 puts("Command & Conquer (c) 1995, Westwood Studios\r\n" 2073 "Paramtres:\r\n" 2074 // " -CD<chemin d'accs> = Recherche des fichiers dans le\r\n" 2075 // " rpertoire indiqu.\r\n" 2076 " -DESTNET = Spcifier le numro de rseau du systme de destination\r\n" 2077 " (Syntaxe: DESTNETxx.xx.xx.xx)\r\n" 2078 " -SOCKET = ID poste rseau (0 16383)\r\n" 2079 " -STEALTH = Cacher les noms en mode multijoueurs (\"Mode Boss\")\r\n" 2080 " -MESSAGES = Autorise les messages extrieurs ce jeu.\r\n" 2081 "\r\n"); 2082 #else 2083 puts("Command & Conquer (c) 1995, 1996 Westwood Studios\r\n" 2084 "Parameters:\r\n" 2085 #ifdef NEVER 2086 " CHEAT = Enable debug keys.\r\n" 2087 " -EDITOR = Enable scenario editor.\r\n" 2088 #endif 2089 // " -CD<path> = Set search path for data files.\r\n" 2090 " -DESTNET = Specify Network Number of destination system\r\n" 2091 " (Syntax: DESTNETxx.xx.xx.xx)\r\n" 2092 " -SOCKET = Network Socket ID (0 - 16383)\n" 2093 " -STEALTH = Hide multiplayer names (\"Boss mode\")\r\n" 2094 " -MESSAGES = Allow messages from outside this game.\r\n" 2095 " -o = Enable compatability with version 1.07.\r\n" 2096 #ifdef JAPANESE 2097 " -ENGLISH = Enable English keyboard compatibility.\r\n" 2098 #endif 2099 // " -ELITE = Advanced AI and combat characteristics.\r\n" 2100 #ifdef NEVER 2101 " -O[options]= Special control options;\r\n" 2102 " 1 : Tiberium grows.\r\n" 2103 " 2 : Tiberium grows and spreads.\r\n" 2104 " A : Aggressive player unit defense enabled.\r\n" 2105 " B : Bargraphs always displayed.\r\n" 2106 " C : Capture the flag mode.\r\n" 2107 " E : Elite defense mode disable (attacker advantage).\r\n" 2108 " D : Deploy reversal allowed for construction yard.\r\n" 2109 " F : Fleeing from direct immediate threats is enabled.\r\n" 2110 " H : Hussled recharge time.\r\n" 2111 " G : Growth for Tiberium slowed in multiplay.\r\n" 2112 " I : Inert weapons -- no damage occurs.\r\n" 2113 " J : 7th grade sound effects.\r\n" 2114 " M : Monochrome debug messages.\r\n" 2115 " N : Name the civilians and buildings.\r\n" 2116 " P : Path algorithm displayed as it works.\r\n" 2117 " Q : Quiet mode (no sound).\r\n" 2118 " R : Road pieces are not added to buildings.\r\n" 2119 " T : Three point turns for wheeled vehicles.\r\n" 2120 " U : U can target and burn trees.\r\n" 2121 " V : Show target selection by opponent.\r\n" 2122 " X : Make a recording of a multiplayer game.\r\n" 2123 " Y : Play a recording of a multiplayer game.\r\n" 2124 " Z : Disaster containment team.\r\n" 2125 #endif 2126 "\r\n"); 2127 #endif 2128 #endif 2129 return(false); 2130 } 2131 2132 2133 bool processed = true; 2134 switch (Obfuscate(string)) { 2135 2136 /* 2137 ** Signal that easy mode is active. 2138 */ 2139 case PARM_EASY: 2140 Special.IsEasy = true; 2141 Special.IsDifficult = false; 2142 break; 2143 2144 /* 2145 ** Signal that hard mode is active. 2146 */ 2147 case PARM_HARD: 2148 Special.IsEasy = false; 2149 Special.IsDifficult = true; 2150 break; 2151 2152 #ifdef VIRGIN_CHEAT_KEYS 2153 case PARM_PLAYTEST: 2154 Debug_Playtest = true; 2155 break; 2156 #endif 2157 2158 #ifdef PARM_CHEATERIK 2159 case PARM_CHEATERIK: 2160 Debug_Playtest = true; 2161 Debug_Flag = true; 2162 break; 2163 #endif 2164 2165 #ifdef PARM_CHEATADAM 2166 case PARM_CHEATADAM: 2167 Debug_Playtest = true; 2168 Debug_Flag = true; 2169 break; 2170 #endif 2171 2172 #ifdef PARM_CHEATMIKE 2173 case PARM_CHEATMIKE: 2174 Debug_Playtest = true; 2175 Debug_Flag = true; 2176 break; 2177 #endif 2178 2179 #ifdef PARM_CHEATDAVID 2180 case PARM_CHEATDAVID: 2181 Debug_Playtest = true; 2182 Debug_Flag = true; 2183 break; 2184 #endif 2185 2186 #ifdef PARM_CHEATPHIL 2187 case PARM_CHEATPHIL: 2188 Debug_Playtest = true; 2189 Debug_Flag = true; 2190 break; 2191 #endif 2192 2193 #ifdef PARM_CHEATBILL 2194 case PARM_CHEATBILL: 2195 Debug_Playtest = true; 2196 Debug_Flag = true; 2197 break; 2198 #endif 2199 2200 #ifdef PARM_CHEAT_STEVET 2201 2202 case PARM_CHEAT_STEVET: 2203 Debug_Playtest = true; 2204 Debug_Flag = true; 2205 break; 2206 2207 #endif 2208 2209 #ifdef PARM_EDITORBILL 2210 case PARM_EDITORBILL: 2211 Debug_Map = true; 2212 Debug_Unshroud = true; 2213 Debug_Flag = true; 2214 break; 2215 #endif 2216 2217 #ifdef PARM_EDITORERIK 2218 case PARM_EDITORERIK: 2219 Debug_Map = true; 2220 Debug_Unshroud = true; 2221 Debug_Flag = true; 2222 break; 2223 #endif 2224 2225 case PARM_SPECIAL: 2226 Special.IsJurassic = true; 2227 AreThingiesEnabled = true; 2228 break; 2229 2230 /* 2231 ** Special flag - is C&C being run from the install program? 2232 */ 2233 case PARM_INSTALL: 2234 #ifndef DEMO 2235 Special.IsFromInstall = true; 2236 #endif 2237 break; 2238 2239 default: 2240 processed = false; 2241 break; 2242 } 2243 if (processed) continue; 2244 2245 2246 #ifdef CHEAT_KEYS 2247 /* 2248 ** Scenario Editor Mode 2249 */ 2250 if (stricmp(string, "-CHECKMAP") == 0) { 2251 Debug_Check_Map = true; 2252 continue; 2253 } 2254 2255 #endif 2256 2257 /* 2258 ** Older version override. 2259 */ 2260 if (stricmp(string, "-O") == 0 || stricmp(string, "-0") == 0) { 2261 IsV107 = true; 2262 continue; 2263 } 2264 2265 /* 2266 ** File search path override. 2267 */ 2268 if (strstr(string, "-CD")) { 2269 CCFileClass::Set_Search_Drives(&string[3]); 2270 continue; 2271 } 2272 #ifdef JAPANESE 2273 /* 2274 ** Enable english-compatible keyboard 2275 */ 2276 if (!stricmp(string,"-ENGLISH")) { 2277 ForceEnglish = true; 2278 continue; 2279 } 2280 #endif 2281 2282 /* 2283 ** Specify destination connection for network play 2284 */ 2285 if (strstr(string, "-DESTNET")) { 2286 NetNumType net; 2287 NetNodeType node; 2288 2289 /* 2290 ** Scan the command-line string, pulling off each address piece 2291 */ 2292 int i = 0; 2293 char * p = strtok(string + 8,"."); 2294 while (p) { 2295 int x; 2296 2297 sscanf(p,"%x",&x); // convert from hex string to int 2298 if (i < 4) { 2299 net[i] = (char)x; // fill NetNum 2300 } else { 2301 node[i-4] = (char)x; // fill NetNode 2302 } 2303 i++; 2304 p = strtok(NULL,"."); 2305 } 2306 2307 /* 2308 ** If all the address components were successfully read, fill in the 2309 ** BridgeNet with a broadcast address to the network across the bridge. 2310 */ 2311 if (i >= 4) { 2312 IsBridge = 1; 2313 memset(node, 0xff, 6); 2314 BridgeNet = IPXAddressClass(net, node); 2315 } 2316 continue; 2317 } 2318 2319 /* 2320 ** Specify socket ID, as an offset from 0x4000. 2321 */ 2322 if (strstr(string, "-SOCKET")) { 2323 unsigned short socket; 2324 2325 socket = (unsigned short)(atoi(string + strlen("SOCKET"))); 2326 socket += 0x4000; 2327 if (socket >= 0x4000 && socket < 0x8000) { 2328 Ipx.Set_Socket (socket); 2329 } 2330 continue; 2331 } 2332 2333 /* 2334 ** Set the Net Stealth option 2335 */ 2336 if (strstr(string, "-STEALTH")) { 2337 NetStealth = true; 2338 continue; 2339 } 2340 2341 /* 2342 ** Set the Net Protection option 2343 */ 2344 if (strstr(string, "-MESSAGES")) { 2345 NetProtect = false; 2346 continue; 2347 } 2348 2349 /* 2350 ** Allow "attract" mode 2351 */ 2352 if (strstr(string, "-ATTRACT")) { 2353 AllowAttract = true; 2354 continue; 2355 } 2356 2357 /* 2358 ** Set screen to 640x480 instead of 640x400 2359 */ 2360 if (strstr(string,"-480")){ 2361 ScreenHeight = 480; 2362 continue; 2363 } 2364 2365 /* 2366 ** Check for spawn from WChat 2367 */ 2368 if (strstr(string,"-WCHAT")){ 2369 SpawnedFromWChat = true; 2370 } 2371 2372 /* 2373 ** Allow use of MMX instructions 2374 */ 2375 if (strstr(string,"-MMX")){ 2376 MMXAvailable = true; 2377 continue; 2378 } 2379 2380 2381 #ifdef CHEAT_KEYS 2382 /* 2383 ** Allow solo net play 2384 */ 2385 if (stricmp(string, "-HANSOLO") == 0) { 2386 MPlayerSolo = true; 2387 continue; 2388 } 2389 2390 /* 2391 ** Specify the random number seed (for debugging) 2392 */ 2393 if (strstr(string, "-SEED")) { 2394 CustomSeed = (unsigned short)(atoi(string + strlen("SEED"))); 2395 continue; 2396 } 2397 #endif 2398 2399 #ifdef NEVER 2400 /* 2401 ** Handle the prog init differently in this case. 2402 */ 2403 if (strstr(string, "-V")) { 2404 continue; 2405 } 2406 #endif 2407 2408 #ifdef FIX_ME_LATER 2409 /* 2410 ** look for passed-in video mode to default to 2411 */ 2412 if (strnicmp(string, "-V", strlen("-V")) == 0) { 2413 Set_Video_Mode(MCGA_MODE); // do this to get around first_time variable... 2414 Set_Original_Video_Mode(atoi(string+2)); 2415 continue; 2416 } 2417 #endif //FIX_ME_LATER 2418 2419 /* 2420 ** Special command line control parsing. 2421 */ 2422 if (strnicmp(string, "-X", strlen("-O")) == 0) { 2423 string += strlen("-X"); 2424 while (*string) { 2425 char code = *string++; 2426 switch (toupper(code)) { 2427 2428 #ifdef ONHOLD 2429 /* 2430 ** Should human generated sound effects be used? 2431 */ 2432 case 'J': 2433 Special.IsJuvenile = true; 2434 break; 2435 #endif 2436 2437 #ifdef CHEAT_KEYS 2438 /* 2439 ** Monochrome debug screen enable. 2440 */ 2441 case 'M': 2442 Special.IsMonoEnabled = true; 2443 break; 2444 2445 /* 2446 ** Inert weapons -- no units take damage. 2447 */ 2448 case 'I': 2449 Special.IsInert = true; 2450 break; 2451 #endif 2452 2453 #ifdef CHEAT_KEYS 2454 /* 2455 ** Hussled recharge timer. 2456 */ 2457 case 'H': 2458 Special.IsSpeedBuild = true; 2459 break; 2460 2461 /* 2462 ** Turn on super-record mode, which thrashes your disk terribly, 2463 ** but is really really cool. Well, sometimes it is, anyway. 2464 ** At least, it can be. Once in a while. 2465 ** This flag tells the recording system to re-open the file for 2466 ** each write, so the recording survives a crash. 2467 */ 2468 case 'S': 2469 SuperRecord = 1; 2470 break; 2471 2472 /* 2473 ** "Record" a multi-player game 2474 */ 2475 case 'X': 2476 RecordGame = 1; 2477 break; 2478 2479 /* 2480 ** "Play Back" a multi-player game 2481 */ 2482 case 'Y': 2483 PlaybackGame = 1; 2484 break; 2485 #endif 2486 2487 #ifdef ONHOLD 2488 /* 2489 ** Bonus scenario enable. 2490 */ 2491 case 'Z': 2492 Special.IsJurassic = true; 2493 break; 2494 #endif 2495 2496 /* 2497 ** Quiet mode override control. 2498 */ 2499 case 'Q': 2500 Debug_Quiet = true; 2501 break; 2502 2503 #ifdef CHEAT_KEYS 2504 /* 2505 ** Target selection by human opponent (network/modem play) will 2506 ** be visible to the player? 2507 */ 2508 case 'V': 2509 Special.IsVisibleTarget = true; 2510 break; 2511 #endif 2512 2513 default: 2514 #ifdef GERMAN 2515 puts("Ungltiger Parameter.\n"); 2516 #else 2517 #ifdef FRENCH 2518 puts("Commande d'option invalide.\n"); 2519 #else 2520 puts("Invalid option switch.\n"); 2521 #endif 2522 #endif 2523 return(false); 2524 } 2525 2526 } 2527 2528 if (Special.IsMonoEnabled) { 2529 MonoClass::Enable(); 2530 } 2531 continue; 2532 } 2533 } 2534 return(true); 2535 } 2536 2537 2538 #ifdef ONHOLD 2539 /*********************************************************************************************** 2540 * Parse_INI_File -- Parses CONQUER.INI for certain options * 2541 * * 2542 * INPUT: * 2543 * none. * 2544 * * 2545 * OUTPUT: * 2546 * none. * 2547 * * 2548 * WARNINGS: * 2549 * none. * 2550 * * 2551 * HISTORY: * 2552 * 08/18/1995 BRR : Created. * 2553 *=============================================================================================*/ 2554 void Parse_INI_File(void) 2555 { 2556 char *buffer; // INI staging buffer pointer. 2557 char buf[128]; 2558 static char section[40]; 2559 static char entry[40]; 2560 static char name[40]; 2561 int len; 2562 int i; 2563 2564 /* 2565 ** These arrays store the coded version of the names Geologic, Period, & Jurassic. 2566 ** Decode them by subtracting 83. For you curious types, the names look like: 2567 ** ¿º 2568 ** ż· 2569 ** ŴƼ 2570 ** If these INI entries aren't found, the IsJurassic flag does nothing. 2571 */ 2572 static char coded_section[] = {154,184,194,191,194,186,188,182,0}; 2573 static char coded_entry[] = {163,184,197,188,194,183,0}; 2574 static char coded_name[] = {157,200,197,180,198,198,188,182,0}; 2575 2576 /*------------------------------------------------------------------------ 2577 Fetch working pointer to the INI staging buffer. Make sure that the buffer 2578 is cleared out before proceeding. 2579 ------------------------------------------------------------------------*/ 2580 buffer = (char *)_ShapeBuffer; 2581 memset(buffer, '\0', _ShapeBufferSize); 2582 2583 /*------------------------------------------------------------------------ 2584 Decode the desired section, entry, & name 2585 ------------------------------------------------------------------------*/ 2586 strcpy (section,coded_section); 2587 len = strlen(coded_section); 2588 for (i = 0; i < len; i++) { 2589 section[i] -= 83; 2590 } 2591 2592 strcpy (entry,coded_entry); 2593 len = strlen(coded_entry); 2594 for (i = 0; i < len; i++) { 2595 entry[i] -= 83; 2596 } 2597 2598 strcpy (name,coded_name); 2599 len = strlen(coded_name); 2600 for (i = 0; i < len; i++) { 2601 name[i] -= 83; 2602 } 2603 2604 /*------------------------------------------------------------------------ 2605 Create filename and read the file. 2606 ------------------------------------------------------------------------*/ 2607 CCFileClass file ("CONQUER.INI"); 2608 if (!file.Is_Available()) { 2609 return; 2610 } else { 2611 file.Read(buffer, _ShapeBufferSize-1); 2612 } 2613 file.Close(); 2614 2615 WWGetPrivateProfileString(section, entry, "", buf, sizeof(buf), buffer); 2616 2617 if (!stricmp (buf,name)) 2618 AreThingiesEnabled = true; 2619 2620 memset (section, 0, sizeof(section)); 2621 memset (entry, 0, sizeof(entry)); 2622 memset (name, 0, sizeof(name)); 2623 } 2624 #endif 2625 2626 2627 /*********************************************************************************************** 2628 * Version_Number -- Determines the version number. * 2629 * * 2630 * This routine will determine the version number by analyzing the date and teim that the * 2631 * program was compiled and then generating a unique version number based on it. The * 2632 * version numbers are guaranteed to be larger for later dates. * 2633 * * 2634 * INPUT: none * 2635 * * 2636 * OUTPUT: Returns with the version number. * 2637 * * 2638 * WARNINGS: none * 2639 * * 2640 * HISTORY: * 2641 * 03/24/1995 JLB : Created. * 2642 *=============================================================================================*/ 2643 int Version_Number(void) 2644 { 2645 #ifdef OBSOLETE 2646 static bool initialized = false; 2647 static int version; 2648 static char * date = __DATE__; 2649 static char * time = __TIME__; 2650 static char const * months = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; 2651 2652 if (!initialized) { 2653 char * ptr; 2654 char * tok; 2655 2656 /* 2657 ** Fetch the month and place in the first two digit positions. 2658 */ 2659 strupr(date); 2660 tok = strtok(date, " "); 2661 ptr = strstr(months, tok); 2662 if (ptr) { 2663 version = (((ptr - months) / 3)+1) * 10000; 2664 } 2665 2666 /* 2667 ** Fetch the date and place that in the next two digit positions. 2668 */ 2669 tok = strtok(NULL, " "); 2670 if (tok) { 2671 version += atoi(tok) * 100; 2672 } 2673 2674 /* 2675 ** Fetch the time and place that in the last two digit positions. 2676 */ 2677 tok = strtok(time, ": "); 2678 if (tok) { 2679 version += atoi(tok); 2680 } 2681 2682 2683 /* 2684 ** Fetch the virgin text file (if present). 2685 */ 2686 RawFileClass file("VERSION.TXT"); 2687 if (file.Is_Available()) { 2688 file.Read(VersionText, sizeof(VersionText)); 2689 VersionText[sizeof(VersionText)-1] = '\0'; 2690 while (VersionText[sizeof(VersionText)-1] == '\r') { 2691 VersionText[sizeof(VersionText)-1] = '\0'; 2692 } 2693 } else { 2694 VersionText[0] = '\0'; 2695 } 2696 2697 initialized = true; 2698 } 2699 return(version); 2700 #endif 2701 2702 #ifdef WIN32 2703 2704 #if (FRENCH) 2705 sprintf(VersionText, ".02"); // Win95 french version number 2706 #endif //FRENCH 2707 2708 #if (GERMAN) 2709 sprintf(VersionText, ".01"); // Win95 german version number 2710 #endif //GERMAN 2711 2712 #if (JAPANESE) 2713 sprintf(VersionText, ".01"); // Win95 german version number 2714 #endif //GERMAN 2715 2716 #if !(FRENCH | GERMAN | JAPANESE) 2717 sprintf(VersionText, ".07"); // Win95 USA version number 2718 #endif //FRENCH | GERMAN 2719 2720 RawFileClass file("VERSION.TXT"); 2721 char version [16]; 2722 memset (version, 0, sizeof (version)); 2723 if (file.Is_Available()){ 2724 file.Read (version, sizeof (version)); 2725 } 2726 strncat (VersionText, version, sizeof (VersionText) - strlen (VersionText) - 1); 2727 2728 #if (FRENCH) 2729 return (1); // Win95 french version number 2730 #endif //FRENCH 2731 2732 #if (GERMAN) 2733 return (1); // Win95 german version number 2734 #endif //GERMAN 2735 2736 #if (JAPANESE) 2737 return (1); // Win95 german version number 2738 #endif //GERMAN 2739 2740 #if !(FRENCH | GERMAN | JAPANESE) 2741 return (1); // Win95 USA version number 2742 #endif //FRENCH | GERMAN 2743 2744 #else 2745 2746 2747 #ifdef PATCH 2748 2749 #ifdef DEMO 2750 sprintf(VersionText, " 1.0a"); // Demo version. 2751 #else 2752 strcpy(VersionText, ".34 "); 2753 #endif 2754 return(1); 2755 2756 #else 2757 2758 #ifdef DEMO 2759 sprintf(VersionText, " 1.0a"); // Demo version. 2760 #else 2761 // sprintf(VersionText, ".%02dp", 13); // Patch version. 2762 sprintf(VersionText, ".%02d", 14); // Master version. 2763 #endif 2764 return(1); 2765 #endif 2766 2767 #endif //WIN32 2768 } 2769 2770 2771 /*************************************************************************** 2772 * Save_Recording_Values -- Saves recording values to a recording file * 2773 * * 2774 * INPUT: * 2775 * none. * 2776 * * 2777 * OUTPUT: * 2778 * none. * 2779 * * 2780 * WARNINGS: * 2781 * none. * 2782 * * 2783 * HISTORY: * 2784 * 05/15/1995 BRR : Created. * 2785 *=========================================================================*/ 2786 void Save_Recording_Values(void) 2787 { 2788 RecordFile.Write(&GameToPlay, sizeof(GameToPlay)); 2789 RecordFile.Write(&ModemGameToPlay, sizeof(ModemGameToPlay)); 2790 RecordFile.Write(&BuildLevel, sizeof(BuildLevel)); 2791 RecordFile.Write(MPlayerName, sizeof(MPlayerName)); 2792 RecordFile.Write(&MPlayerPrefColor, sizeof(MPlayerPrefColor)); 2793 RecordFile.Write(&MPlayerColorIdx, sizeof(MPlayerColorIdx)); 2794 RecordFile.Write(&MPlayerHouse, sizeof(MPlayerHouse)); 2795 RecordFile.Write(&MPlayerLocalID, sizeof(MPlayerLocalID)); 2796 RecordFile.Write(&MPlayerCount, sizeof(MPlayerCount)); 2797 RecordFile.Write(&MPlayerBases, sizeof(MPlayerBases)); 2798 RecordFile.Write(&MPlayerCredits, sizeof(MPlayerCredits)); 2799 RecordFile.Write(&MPlayerTiberium, sizeof(MPlayerTiberium)); 2800 RecordFile.Write(&MPlayerGoodies, sizeof(MPlayerGoodies)); 2801 RecordFile.Write(&MPlayerGhosts, sizeof(MPlayerGhosts)); 2802 RecordFile.Write(&MPlayerUnitCount, sizeof(MPlayerUnitCount)); 2803 RecordFile.Write(MPlayerID, sizeof(MPlayerID)); 2804 RecordFile.Write(MPlayerHouses, sizeof(MPlayerHouses)); 2805 RecordFile.Write(&Seed, sizeof(Seed)); 2806 RecordFile.Write(&Scenario, sizeof(Scenario)); 2807 RecordFile.Write(&ScenPlayer, sizeof(ScenPlayer)); 2808 RecordFile.Write(&ScenDir, sizeof(ScenDir)); 2809 RecordFile.Write(&Whom, sizeof(Whom)); 2810 RecordFile.Write(&Special, sizeof(SpecialClass)); 2811 RecordFile.Write(&Options, sizeof(GameOptionsClass)); 2812 RecordFile.Write(&FrameSendRate, sizeof(FrameSendRate)); 2813 RecordFile.Write(&CommProtocol, sizeof(CommProtocol)); 2814 2815 if (SuperRecord) { 2816 RecordFile.Close(); 2817 } 2818 } 2819 2820 2821 /*************************************************************************** 2822 * Load_Recording_Values -- Loads recording values from recording file * 2823 * * 2824 * INPUT: * 2825 * none. * 2826 * * 2827 * OUTPUT: * 2828 * none. * 2829 * * 2830 * WARNINGS: * 2831 * none. * 2832 * * 2833 * HISTORY: * 2834 * 05/15/1995 BRR : Created. * 2835 *=========================================================================*/ 2836 void Load_Recording_Values(void) 2837 { 2838 Read_MultiPlayer_Settings(); 2839 2840 RecordFile.Read(&GameToPlay, sizeof(GameToPlay)); 2841 RecordFile.Read(&ModemGameToPlay, sizeof(ModemGameToPlay)); 2842 RecordFile.Read(&BuildLevel, sizeof(BuildLevel)); 2843 RecordFile.Read(MPlayerName, sizeof(MPlayerName)); 2844 RecordFile.Read(&MPlayerPrefColor, sizeof(MPlayerPrefColor)); 2845 RecordFile.Read(&MPlayerColorIdx, sizeof(MPlayerColorIdx)); 2846 RecordFile.Read(&MPlayerHouse, sizeof(MPlayerHouse)); 2847 RecordFile.Read(&MPlayerLocalID, sizeof(MPlayerLocalID)); 2848 RecordFile.Read(&MPlayerCount, sizeof(MPlayerCount)); 2849 RecordFile.Read(&MPlayerBases, sizeof(MPlayerBases)); 2850 RecordFile.Read(&MPlayerCredits, sizeof(MPlayerCredits)); 2851 RecordFile.Read(&MPlayerTiberium, sizeof(MPlayerTiberium)); 2852 RecordFile.Read(&MPlayerGoodies, sizeof(MPlayerGoodies)); 2853 RecordFile.Read(&MPlayerGhosts, sizeof(MPlayerGhosts)); 2854 RecordFile.Read(&MPlayerUnitCount, sizeof(MPlayerUnitCount)); 2855 RecordFile.Read(MPlayerID, sizeof(MPlayerID)); 2856 RecordFile.Read(MPlayerHouses, sizeof(MPlayerHouses)); 2857 RecordFile.Read(&Seed, sizeof(Seed)); 2858 RecordFile.Read(&Scenario, sizeof(Scenario)); 2859 RecordFile.Read(&ScenPlayer, sizeof(ScenPlayer)); 2860 RecordFile.Read(&ScenDir, sizeof(ScenDir)); 2861 RecordFile.Read(&Whom, sizeof(Whom)); 2862 RecordFile.Read(&Special, sizeof(SpecialClass)); 2863 RecordFile.Read(&Options, sizeof(GameOptionsClass)); 2864 RecordFile.Read(&FrameSendRate, sizeof(FrameSendRate)); 2865 RecordFile.Read(&CommProtocol, sizeof(CommProtocol)); 2866 } 2867 2868 2869 /*********************************************************************************************** 2870 * Obfuscate -- Sufficiently transform parameter to thwart casual hackers. * 2871 * * 2872 * This routine borrows from CRC and PGP technology to sufficiently alter the parameter * 2873 * in order to make it difficult to reverse engineer the key phrase. This is designed to * 2874 * be used for hidden game options that will be released at a later time over Westwood's * 2875 * Web page or through magazine hint articles. * 2876 * * 2877 * Since this is a one way transformation, it becomes much more difficult to reverse * 2878 * engineer the pass phrase even if the resultant pass code is known. This has an added * 2879 * benefit of making this algorithm immune to traditional cyrptographic attacks. * 2880 * * 2881 * The largest strength of this transformation algorithm lies in the restriction on the * 2882 * source vector being legal ASCII uppercase characters. This restriction alone makes even * 2883 * a simple CRC transformation practically impossible to reverse engineer. This algorithm * 2884 * uses far more than a simple CRC transformation to achieve added strength from advanced * 2885 * attack methods. * 2886 * * 2887 * INPUT: string -- Pointer to the key phrase that will be transformed into a code. * 2888 * * 2889 * OUTPUT: Returns with the code that the key phrase is translated into. * 2890 * * 2891 * WARNINGS: A zero length pass phrase results in a 0x00000000 result code. * 2892 * * 2893 * HISTORY: * 2894 * 08/19/1995 JLB : Created. * 2895 *=============================================================================================*/ 2896 long Obfuscate(char const * string) 2897 { 2898 char buffer[1024]; 2899 2900 if (!string) return(0); 2901 memset(buffer, '\xA5', sizeof(buffer)); 2902 2903 /* 2904 ** Copy key phrase into a working buffer. This hides any transformation done 2905 ** to the string. 2906 */ 2907 strncpy(buffer, string, sizeof(buffer)); 2908 buffer[sizeof(buffer)-1] = '\0'; 2909 int length = strlen(buffer); 2910 2911 /* 2912 ** Only upper case letters are significant. 2913 */ 2914 strupr(buffer); 2915 2916 /* 2917 ** Ensure that only visible ASCII characters compose the key phrase. This 2918 ** discourages the direct forced illegal character input method of attack. 2919 */ 2920 int index; 2921 for (index = 0; index < length; index++) { 2922 if (!isgraph(buffer[index])) { 2923 buffer[index] = 'A' + (index%26); 2924 } 2925 } 2926 2927 /* 2928 ** Increase the strength of even short pass phrases by extending the 2929 ** length to be at least a minimum number of characters. This helps prevent 2930 ** a weak pass phrase from compromising the obfuscation process. This 2931 ** process also forces the key phrase to be an even multiple of four. 2932 ** This is necessary to support the cypher process that occurs later. 2933 */ 2934 if (length < 16 || (length & 0x03)) { 2935 int maxlen = 16; 2936 if (((length+3) & 0x00FC) > maxlen) { 2937 maxlen = ((length+3) & 0x00FC); 2938 } 2939 for (index = length; index < maxlen; index++) { 2940 buffer[index] = 'A' + ((('?' ^ buffer[index-length]) + index) % 26); 2941 } 2942 length = index; 2943 buffer[length] = '\0'; 2944 } 2945 2946 /* 2947 ** Transform the buffer into a number. This transformation is character 2948 ** order dependant. 2949 */ 2950 long code = Calculate_CRC(buffer, length); 2951 2952 /* 2953 ** Record a copy of this initial transformation to be used in a later 2954 ** self referential transformation. 2955 */ 2956 long copy = code; 2957 2958 /* 2959 ** Reverse the character string and combine with the previous transformation. 2960 ** This doubles the workload of trying to reverse engineer the CRC calculation. 2961 */ 2962 strrev(buffer); 2963 code ^= Calculate_CRC(buffer, length); 2964 2965 /* 2966 ** Perform a self referential transformation. This makes a reverse engineering 2967 ** by using a cause and effect attack more difficult. 2968 */ 2969 code = code ^ copy; 2970 2971 /* 2972 ** Unroll and combine the code value into the pass phrase and then perform 2973 ** another self referential transformation. Although this is a trivial cypher 2974 ** process, it gives the sophisticated hacker false hope since the strong 2975 ** cypher process occurs later. 2976 */ 2977 strrev(buffer); // Restore original string order. 2978 for (index = 0; index < length; index++) { 2979 code ^= (unsigned char)buffer[index]; 2980 unsigned char temp = (unsigned char)code; 2981 buffer[index] ^= temp; 2982 code >>= 8; 2983 code |= (((long)temp)<<24); 2984 } 2985 2986 /* 2987 ** Introduce loss into the vector. This strengthens the key against traditional 2988 ** cryptographic attack engines. Since this also weakens the key against 2989 ** unconventional attacks, the loss is limited to less than 10%. 2990 */ 2991 for (index = 0; index < length; index++) { 2992 static unsigned char _lossbits[] = {0x00,0x08,0x00,0x20,0x00,0x04,0x10,0x00}; 2993 static unsigned char _addbits[] = {0x10,0x00,0x00,0x80,0x40,0x00,0x00,0x04}; 2994 2995 buffer[index] |= _addbits[index % (sizeof(_addbits)/sizeof(_addbits[0]))]; 2996 buffer[index] &= ~_lossbits[index % (sizeof(_lossbits)/sizeof(_lossbits[0]))]; 2997 } 2998 2999 /* 3000 ** Perform a general cypher transformation on the vector 3001 ** and use the vector itself as the cypher key. This is a variation on the 3002 ** cypher process used in PGP. It is a very strong cypher process with no known 3003 ** weaknesses. However, in this case, the cypher key is the vector itself and this 3004 ** opens up a weakness against attacks that have access to this transformation 3005 ** algorithm. The sheer workload of reversing this transformation should be enough 3006 ** to discourage even the most determined hackers. 3007 */ 3008 for (index = 0; index < length; index += 4) { 3009 short key1 = buffer[index]; 3010 short key2 = buffer[index+1]; 3011 short key3 = buffer[index+2]; 3012 short key4 = buffer[index+3]; 3013 short val1 = key1; 3014 short val2 = key2; 3015 short val3 = key3; 3016 short val4 = key4; 3017 3018 val1 *= key1; 3019 val2 += key2; 3020 val3 += key3; 3021 val4 *= key4; 3022 3023 short s3 = val3; 3024 val3 ^= val1; 3025 val3 *= key1; 3026 short s2 = val2; 3027 val2 ^= val4; 3028 val2 += val3; 3029 val2 *= key3; 3030 val3 += val2; 3031 3032 val1 ^= val2; 3033 val4 ^= val3; 3034 3035 val2 ^= s3; 3036 val3 ^= s2; 3037 3038 buffer[index] = val1; 3039 buffer[index+1] = val2; 3040 buffer[index+2] = val3; 3041 buffer[index+3] = val4; 3042 } 3043 3044 /* 3045 ** Convert this final vector into a cypher key code to be 3046 ** returned by this routine. 3047 */ 3048 code = Calculate_CRC(buffer, length); 3049 3050 /* 3051 ** Return the final code value. 3052 */ 3053 return(code); 3054 }