STARTUP.CPP (36005B)
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/STARTUP.CPP 6 3/15/97 7:18p Steve_tall $ */ 17 /*********************************************************************************************** 18 *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** 19 *********************************************************************************************** 20 * * 21 * Project Name : Command & Conquer * 22 * * 23 * File Name : STARTUP.CPP * 24 * * 25 * Programmer : Joe L. Bostic * 26 * * 27 * Start Date : October 3, 1994 * 28 * * 29 * Last Update : September 30, 1996 [JLB] * 30 * * 31 *---------------------------------------------------------------------------------------------* 32 * Functions: * 33 * Prog_End -- Cleans up library systems in prep for game exit. * 34 * main -- Initial startup routine (preps library systems). * 35 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 36 37 #include "function.h" 38 #include <conio.h> 39 #include <io.h> 40 41 #ifdef WIN32 42 #include "ccdde.h" 43 #include "ipx95.h" 44 #endif //WIN32 45 46 #ifdef MCIMPEG // Denzil 6/15/98 47 #include "mcimovie.h" 48 #endif 49 50 #ifdef WOLAPI_INTEGRATION 51 //#include "WolDebug.h" 52 #endif 53 54 extern char RedAlertINI[_MAX_PATH]; 55 56 bool Read_Private_Config_Struct(FileClass & file, NewConfigType * config); 57 void Print_Error_End_Exit(char * string); 58 void Print_Error_Exit(char * string); 59 60 #ifdef WIN32 61 //WinTimerClass * WinTimer; 62 extern void Create_Main_Window ( HANDLE instance , int command_show , int width , int height); 63 extern bool RA95AlreadyRunning; 64 HINSTANCE ProgramInstance; 65 void Check_Use_Compressed_Shapes (void); 66 void Read_Setup_Options(RawFileClass *config_file); 67 bool VideoBackBufferAllowed = true; 68 #else 69 BOOL Init_Timer_System(unsigned int freq, int partial = FALSE); 70 BOOL Remove_Timer_System(VOID); 71 #endif //WIN32 72 73 const char* Game_Registry_Key(); 74 75 #if (ENGLISH) 76 #define WINDOW_NAME "Red Alert" 77 #endif 78 79 #if (FRENCH) 80 #define WINDOW_NAME "Alerte Rouge" 81 #endif 82 83 #if (GERMAN) 84 #define WINDOW_NAME "Alarmstufe Rot" 85 #endif 86 87 // Added. ST - 5/14/2019 88 bool ProgEndCalled = false; 89 90 extern "C"{ 91 extern char *BigShapeBufferStart; 92 extern char *TheaterShapeBufferStart; 93 extern BOOL UseBigShapeBuffer; 94 extern bool IsTheaterShape; 95 } 96 97 extern void Free_Heaps(void); 98 extern void DLL_Shutdown(void); 99 100 BOOL WINAPI DllMain(HINSTANCE instance, unsigned int fdwReason, void *lpvReserved) 101 { 102 lpvReserved; 103 104 switch (fdwReason) { 105 106 case DLL_PROCESS_ATTACH: 107 ProgramInstance = instance; 108 break; 109 110 case DLL_PROCESS_DETACH: 111 if (WindowsTimer) { 112 delete WindowsTimer; 113 WindowsTimer = NULL; 114 } 115 116 /* 117 ** Red Alert doesn't clean up memory. Do some of that here. 118 */ 119 MFCD::Free_All(); 120 121 if (BigShapeBufferStart) { 122 Free(BigShapeBufferStart); 123 BigShapeBufferStart = NULL; 124 } 125 126 if (TheaterShapeBufferStart) { 127 Free(TheaterShapeBufferStart); 128 TheaterShapeBufferStart = NULL; 129 } 130 131 if (_ShapeBuffer) { 132 delete [] _ShapeBuffer; 133 _ShapeBuffer = NULL; 134 } 135 136 DLL_Shutdown(); 137 Free_Heaps(); 138 break; 139 140 case DLL_THREAD_ATTACH: 141 case DLL_THREAD_DETACH: 142 break; 143 } 144 145 return true; 146 } 147 148 149 150 /*********************************************************************************************** 151 * main -- Initial startup routine (preps library systems). * 152 * * 153 * This is the routine that is first called when the program starts up. It basically * 154 * handles the command line parsing and setting up library systems. * 155 * * 156 * INPUT: argc -- Number of command line arguments. * 157 * * 158 * argv -- Pointer to array of command line argument strings. * 159 * * 160 * OUTPUT: Returns with execution failure code (if any). * 161 * * 162 * WARNINGS: none * 163 * * 164 * HISTORY: * 165 * 03/20/1995 JLB : Created. * 166 *=============================================================================================*/ 167 #ifdef WIN32 168 //int PASCAL WinMain(HINSTANCE, HINSTANCE, char *, int ) 169 //PG int PASCAL WinMain ( HINSTANCE instance , HINSTANCE , char * command_line , int command_show ) 170 int DLL_Startup(const char * command_line_in) 171 172 #else //WIN32 173 int main(int argc, char * argv[]) 174 #endif //WIN32 175 176 { 177 #ifdef WIN32 178 179 RunningAsDLL = true; 180 int command_show = SW_HIDE; 181 HINSTANCE instance = ProgramInstance; 182 char command_line[1024]; 183 strcpy(command_line, command_line_in); 184 185 186 187 #ifndef MPEGMOVIE // Denzil 6/10/98 188 //PG DDSCAPS surface_capabilities; 189 #endif 190 191 /* 192 ** First thing to do is check if there is another instance of Red Alert already running 193 ** and if so, switch to the existing instance and terminate ourselves. 194 */ 195 SpawnedFromWChat = false; 196 #if (0)//PG 197 if (RA95AlreadyRunning) { //Set in the DDEServer constructor 198 //MessageBox (NULL, "Error - attempt to restart Red Alert 95 when already running.", "Red Alert", MB_ICONEXCLAMATION|MB_OK); 199 200 HWND ccwindow; 201 ccwindow = FindWindow (WINDOW_NAME, WINDOW_NAME); 202 if (ccwindow) { 203 SetForegroundWindow ( ccwindow ); 204 ShowWindow ( ccwindow, SW_RESTORE ); 205 } 206 207 return (EXIT_SUCCESS); 208 } 209 #endif 210 211 #endif 212 //printf("in program.\n");getch(); 213 //printf("ram free = %ld\n",Ram_Free(MEM_NORMAL));getch(); 214 #ifdef WIN32 215 if (Ram_Free(MEM_NORMAL) < 7000000) { 216 #else 217 218 void *temp_mem = malloc (13*1024*1024); 219 if (temp_mem) { 220 free (temp_mem); 221 }else{ 222 223 //if (Ram_Free(MEM_NORMAL) < 13000000) { 224 // if (Ram_Free(MEM_NORMAL) < 3500000) { 225 #endif 226 printf (TEXT_NO_RAM); 227 228 #ifndef WIN32 229 printf (TEXT_USE_START_MENU); 230 getch(); 231 #endif 232 233 #if (0) 234 235 /* 236 ** Take a stab at finding out how much memory there is available. 237 */ 238 239 for ( int mem = 13*1024*1024 ; mem >0 ; mem -=1024 ) { 240 temp_mem = malloc (mem); 241 if (temp_mem){ 242 free (temp_mem); 243 printf ("Memory available: %d", mem); 244 break; 245 } 246 } 247 248 getch(); 249 #endif //(0) 250 return(EXIT_FAILURE); 251 } 252 253 #ifdef WIN32 254 255 if (strstr(command_line, "f:\\projects\\c&c0") != NULL || 256 strstr(command_line, "F:\\PROJECTS\\C&C0") != NULL) { 257 MessageBox(0, "Playing off of the network is not allowed.", "Red Alert", MB_OK|MB_ICONSTOP); 258 return(EXIT_FAILURE); 259 } 260 261 int argc; //Command line argument count 262 unsigned command_scan; 263 char command_char; 264 char * argv[20]; //Pointers to command line arguments 265 char path_to_exe[132]; 266 267 ProgramInstance = instance; 268 269 /* 270 ** Get the full path to the .EXE 271 */ 272 GetModuleFileName (instance, &path_to_exe[0], 132); 273 274 /* 275 ** First argument is supposed to be a pointer to the .EXE that is running 276 ** 277 */ 278 argc=1; //Set argument count to 1 279 argv[0]=&path_to_exe[0]; //Set 1st command line argument to point to full path 280 281 /* 282 ** Get pointers to command line arguments just like if we were in DOS 283 ** 284 ** The command line we get is cr/zero? terminated. 285 ** 286 */ 287 288 command_scan=0; 289 290 do { 291 /* 292 ** Scan for non-space character on command line 293 */ 294 do { 295 command_char = *( command_line+command_scan++ ); 296 } while ( command_char==' ' ); 297 298 if ( command_char!=0 && command_char != 13 ) { 299 argv[argc++]=command_line+command_scan-1; 300 301 /* 302 ** Scan for space character on command line 303 */ 304 bool in_quotes = false; 305 do { 306 command_char = *( command_line+command_scan++ ); 307 if (command_char == '"') { 308 in_quotes = !in_quotes; 309 } 310 } while ( (in_quotes || command_char!=' ') && command_char != 0 && command_char!=13 ); 311 *( command_line+command_scan-1 ) = 0; 312 } 313 314 } while ( command_char != 0 && command_char != 13 && argc<20 ); 315 316 #endif //WIN32 317 318 /* 319 ** Remember the current working directory and drive. 320 */ 321 #if (0)//PG 322 unsigned olddrive; 323 char oldpath[MAX_PATH]; 324 getcwd(oldpath, sizeof(oldpath)); 325 _dos_getdrive(&olddrive); 326 327 /* 328 ** Change directory to the where the executable is located. Handle the 329 ** case where there is no path attached to argv[0]. 330 */ 331 char drive[_MAX_DRIVE]; 332 char path[_MAX_PATH]; 333 unsigned drivecount; 334 _splitpath(argv[0], drive, path, NULL, NULL); 335 if (!drive[0]) { 336 drive[0] = ('A' + olddrive)-1; 337 } 338 if (!path[0]) { 339 strcpy(path, "."); 340 } 341 _dos_setdrive(toupper((drive[0])-'A')+1, &drivecount); 342 if (path[strlen(path)-1] == '\\') { 343 path[strlen(path)-1] = '\0'; 344 } 345 chdir(path); 346 #endif 347 348 #ifdef WOLAPI_INTEGRATION 349 // Look for special wolapi install program, used after the patch to version 3, to install "Shared Internet Components". 350 WIN32_FIND_DATA wfd; 351 HANDLE hWOLSetupFile = FindFirstFile( "wolsetup.exe", &wfd ); 352 bool bWOLSetupFile = ( hWOLSetupFile != INVALID_HANDLE_VALUE ); 353 // if( bWOLSetupFile ) 354 // debugprint( "Found wolsetup.exe\n" ); 355 FindClose( hWOLSetupFile ); 356 // Look for special registry entry that tells us when the setup exe has done its thing. 357 HKEY hKey; 358 RegOpenKeyEx( HKEY_LOCAL_MACHINE, Game_Registry_Key(), 0, KEY_READ, &hKey ); 359 DWORD dwValue; 360 DWORD dwBufSize = sizeof( DWORD ); 361 if( RegQueryValueEx( hKey, "WolapiInstallComplete", 0, NULL, (LPBYTE)&dwValue, &dwBufSize ) == ERROR_SUCCESS ) 362 { 363 // debugprint( "Found WolapiInstallComplete in registry\n" ); 364 // Setup has finished. Delete the setup exe and remove reg key. 365 if( bWOLSetupFile ) 366 { 367 if( DeleteFile( "wolsetup.exe" ) ) 368 RegDeleteValue( hKey, "WolapiInstallComplete" ); 369 } 370 else 371 RegDeleteValue( hKey, "WolapiInstallComplete" ); 372 } 373 RegCloseKey( hKey ); 374 375 // I've been having problems getting the patch to delete "conquer.eng", which is present in the game 376 // directory for 1.08, but which must NOT be present for this version (Aftermath mix files provide the 377 // string overrides that the 1.08 separate conquer.eng did before Aftermath). 378 // Delete conquer.eng if it's found. 379 if( FindFirstFile( "conquer.eng", &wfd ) != INVALID_HANDLE_VALUE ) 380 DeleteFile( "conquer.eng" ); 381 382 #endif 383 384 if (Parse_Command_Line(argc, argv)) { 385 386 #if(TEN) 387 // 388 // Only allow the TEN version of the game to run if the TEN 389 // or AllowSoloPlayOptions arguments are specified. 390 // 391 if (Session.AllowSolo==0 && Session.Type != GAME_TEN) { 392 #ifdef WIN32 393 MessageBox(NULL, "Red Alert for TEN\n (c) 1996 Westwood Studios", 394 "Red Alert", MB_OK); 395 exit(0); 396 #else 397 printf("\n"); 398 printf(" Red Alert for TEN\n"); 399 printf(" (c) 1996 Westwood Studios\n"); 400 printf("\n"); 401 exit(0); 402 #endif // WIN32 403 } 404 #endif // TEN 405 406 #if(MPATH) 407 // 408 // Only allow the MPATH version of the game to run if the MPATH 409 // or AllowSoloPlayOptions arguments are specified. 410 // 411 if (Session.AllowSolo==0 && Session.Type != GAME_MPATH) { 412 #ifdef WIN32 413 MessageBox(NULL, "Red Alert for MPATH\n (c) 1996 Westwood Studios", 414 "Red Alert", MB_OK); 415 exit(0); 416 #else 417 printf("\n"); 418 printf(" Red Alert for MPATH\n"); 419 printf(" (c) 1996 Westwood Studios\n"); 420 printf("\n"); 421 exit(0); 422 #endif // WIN32 423 } 424 #endif // MPATH 425 426 #ifdef WIN32 427 428 WindowsTimer = new WinTimerClass(60, FALSE); 429 #if (0)//PG 430 int time_test = WindowsTimer->Get_System_Tick_Count(); 431 Sleep (1000); 432 if (WindowsTimer->Get_System_Tick_Count() == time_test){ 433 MessageBox(0, TEXT_ERROR_TIMER, TEXT_SHORT_TITLE, MB_OK|MB_ICONSTOP); 434 return(EXIT_FAILURE); 435 } 436 #endif 437 #else //WIN32 438 Init_Timer_System(60, true); 439 #endif //WIN32 440 441 //////////////////////////////////////// 442 // The editor needs to load the Red Alert ini file from a different location than the real game. - 7/18/2019 JAS 443 char* red_alert_file_path = nullptr; 444 if (RunningFromEditor) 445 { 446 red_alert_file_path = RedAlertINI; 447 } 448 else 449 { 450 red_alert_file_path = CONFIG_FILE_NAME; 451 } 452 453 RawFileClass cfile(red_alert_file_path); 454 //RawFileClass cfile(CONFIG_FILE_NAME); 455 // end of change - 7/18/2019 JAS 456 //////////////////////////////////////// 457 458 #ifndef WIN32 459 Install_Keyboard_Interrupt(Get_RM_Keyboard_Address(), Get_RM_Keyboard_Size()); 460 #endif //WIN32 461 462 #ifdef NEVER 463 Keyboard->IsLibrary = true; 464 if (Debug_Flag) { 465 Keyboard_Attributes_On(DEBUGINT); 466 } 467 #endif 468 469 Keyboard = new KeyboardClass(); 470 471 #ifdef WIN32 472 /* 473 ** If there is loads of memory then use uncompressed shapes 474 */ 475 Check_Use_Compressed_Shapes(); 476 #endif 477 478 /* 479 ** If there is not enough disk space free, don't allow the product to run. 480 */ 481 if (Disk_Space_Available() < INIT_FREE_DISK_SPACE) { 482 483 #ifdef WIN32 484 #if (0)//PG 485 char disk_space_message [512]; 486 sprintf(disk_space_message, TEXT_CRITICALLY_LOW); //PG , (INIT_FREE_DISK_SPACE) / (1024 * 1024)); 487 int reply = MessageBox(NULL, disk_space_message, TEXT_SHORT_TITLE, MB_ICONQUESTION|MB_YESNO); 488 if (reply == IDNO) { 489 if ( WindowsTimer ) 490 delete WindowsTimer; 491 return (EXIT_FAILURE); 492 } 493 #endif 494 #else 495 printf(TEXT_INSUFFICIENT); 496 printf(TEXT_MUST_HAVE, INIT_FREE_DISK_SPACE / (1024 * 1024)); 497 printf("\n"); 498 if (Keyboard) Keyboard->Get(); 499 // Keyboard::IsLibrary = false; 500 Remove_Keyboard_Interrupt(); 501 Remove_Timer_System(); 502 return(EXIT_FAILURE); 503 #endif 504 } 505 506 if (cfile.Is_Available()) { 507 508 Read_Private_Config_Struct(cfile, &NewConfig); 509 510 #ifdef WIN32 511 512 /* 513 ** Set the options as requested by the ccsetup program 514 */ 515 Read_Setup_Options( &cfile ); 516 517 Create_Main_Window( instance , command_show , ScreenWidth , ScreenHeight ); 518 SoundOn = Audio_Init ( MainWindow , 16 , false , 11025*2 , 0 ); 519 #else //WIN32 520 if (!Debug_Quiet) { 521 Audio_Init(NewConfig.DigitCard, 522 NewConfig.Port, 523 NewConfig.IRQ, 524 NewConfig.DMA, 525 PLAYBACK_RATE_NORMAL, 526 // (NewConfig.Speed) ? PLAYBACK_RATE_SLOW : PLAYBACK_RATE_NORMAL, 527 NewConfig.BitsPerSample, 528 // 4, 529 (Get_CPU() < 5) ? 3 : 5, 530 // (NewConfig.Speed) ? 3 : 5, 531 NewConfig.Reverse); 532 SoundOn = true; 533 } else { 534 Audio_Init(0, -1, -1, -1, PLAYBACK_RATE_NORMAL, 8, 5, false); 535 } 536 #endif //WIN32 537 538 539 #ifdef WIN32 540 #ifdef MPEGMOVIE // Denzil 6/10/98 541 if (!InitDDraw()) 542 return (EXIT_FAILURE); 543 #else 544 BOOL video_success = FALSE; 545 /* 546 ** Set 640x400 video mode. If its not available then try for 640x480 547 */ 548 if (ScreenHeight == 400) { 549 if (Set_Video_Mode (MainWindow, ScreenWidth, ScreenHeight, 8)) { 550 video_success = TRUE; 551 } else { 552 if (Set_Video_Mode (MainWindow, ScreenWidth, 480, 8)) { 553 video_success = TRUE; 554 ScreenHeight = 480; 555 } 556 } 557 } else { 558 if (Set_Video_Mode (MainWindow, ScreenWidth, ScreenHeight, 8)) { 559 video_success = TRUE; 560 } 561 } 562 563 if (!video_success) { 564 MessageBox(MainWindow, TEXT_VIDEO_ERROR, TEXT_SHORT_TITLE, MB_ICONEXCLAMATION|MB_OK); 565 if (WindowsTimer) delete WindowsTimer; 566 //if (Palette) delete Palette; 567 return (EXIT_FAILURE); 568 } 569 570 if (ScreenWidth==320) { 571 VisiblePage.Init( ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0); 572 ModeXBuff.Init( ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)(GBC_VISIBLE | GBC_VIDEOMEM)); 573 } else { 574 575 #if (1) //ST - 1/3/2019 2:11PM 576 577 VisiblePage.Init(ScreenWidth, ScreenHeight, NULL, 0, (GBC_Enum)0); 578 HiddenPage.Init(ScreenWidth, ScreenHeight, NULL, 0, (GBC_Enum)0); 579 580 #else 581 VisiblePage.Init( ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)(GBC_VISIBLE | GBC_VIDEOMEM)); 582 583 /* 584 ** Check that we really got a video memory page. Failure is fatal. 585 */ 586 memset (&surface_capabilities, 0, sizeof(surface_capabilities)); 587 VisiblePage.Get_DD_Surface()->GetCaps(&surface_capabilities); 588 if (surface_capabilities.dwCaps & DDSCAPS_SYSTEMMEMORY) { 589 /* 590 ** Aaaarrgghh! 591 */ 592 WWDebugString(TEXT_DDRAW_ERROR);WWDebugString("\n"); 593 MessageBox(MainWindow, TEXT_DDRAW_ERROR, TEXT_SHORT_TITLE, MB_ICONEXCLAMATION|MB_OK); 594 if (WindowsTimer) delete WindowsTimer; 595 return (EXIT_FAILURE); 596 } 597 598 /* 599 ** If we have enough left then put the hidpage in video memory unless... 600 ** 601 ** If there is no blitter then we will get better performance with a system 602 ** memory hidpage 603 ** 604 ** Use a system memory page if the user has specified it via the ccsetup program. 605 */ 606 unsigned video_memory = Get_Free_Video_Memory(); 607 unsigned video_capabilities = Get_Video_Hardware_Capabilities(); 608 if (video_memory < (unsigned int)(ScreenWidth*ScreenHeight) || 609 (! (video_capabilities & VIDEO_BLITTER)) || 610 (video_capabilities & VIDEO_NO_HARDWARE_ASSIST) || 611 !VideoBackBufferAllowed) { 612 HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0); 613 } else { 614 //HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0); 615 HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)GBC_VIDEOMEM); 616 617 /* 618 ** Make sure we really got a video memory hid page. If we didnt then things 619 ** will run very slowly. 620 */ 621 memset (&surface_capabilities, 0, sizeof(surface_capabilities)); 622 HiddenPage.Get_DD_Surface()->GetCaps(&surface_capabilities); 623 if (surface_capabilities.dwCaps & DDSCAPS_SYSTEMMEMORY) { 624 625 /* 626 ** Oh dear, big trub. This must be an IBM Aptiva or something similarly cruddy. 627 ** We must redo the Hidden Page as system memory. 628 */ 629 AllSurfaces.Remove_DD_Surface(HiddenPage.Get_DD_Surface()); // Remove the old surface from the AllSurfaces list 630 HiddenPage.Get_DD_Surface()->Release(); 631 HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0); 632 } else { 633 VisiblePage.Attach_DD_Surface(&HiddenPage); 634 } 635 } 636 #endif 637 } 638 639 ScreenHeight = 3072; 640 641 if (VisiblePage.Get_Height() == 480) { 642 SeenBuff.Attach(&VisiblePage, 0, 40, 3072, 3072); 643 HidPage.Attach(&HiddenPage, 0, 40, 3072, 3072); 644 } else { 645 SeenBuff.Attach(&VisiblePage, 0, 0, 3072, 3072); 646 HidPage.Attach(&HiddenPage, 0, 0, 3072, 3072); 647 } 648 #endif // MPEGMOVIE - Denzil 6/10/98 649 650 Options.Adjust_Variables_For_Resolution(); 651 652 /* 653 ** Install the memory error handler 654 */ 655 Memory_Error = &Memory_Error_Handler; 656 657 WindowList[0][WINDOWWIDTH] = SeenBuff.Get_Width(); 658 WindowList[0][WINDOWHEIGHT] = SeenBuff.Get_Height(); 659 WindowList[WINDOW_EDITOR][WINDOWWIDTH] = SeenBuff.Get_Width(); 660 WindowList[WINDOW_EDITOR][WINDOWHEIGHT]= SeenBuff.Get_Height(); 661 662 //////////////////////////////////////// 663 // The editor needs to not start the mouse up. - 7/22/2019 JAS 664 if (!RunningFromEditor) 665 { 666 WWMouse = new WWMouseClass(&SeenBuff, 48, 48); 667 MouseInstalled = TRUE; 668 } 669 670 //PG CDFileClass::Set_CD_Drive (CDList.Get_First_CD_Drive()); 671 672 #else //WIN32 673 674 Options.Adjust_Variables_For_Resolution(); 675 if (!Special.IsFromInstall) { 676 BlackPalette.Set(); 677 // Set_Palette(Palette); 678 Set_Video_Mode(MCGA_MODE); 679 } 680 MouseInstalled = Install_Mouse(32, 24, 320, 200); 681 #endif //WIN32 682 683 /* 684 ** See if we should run the intro 685 */ 686 INIClass ini; 687 ini.Load(cfile); 688 689 /* 690 ** Check for forced intro movie run disabling. If the conquer 691 ** configuration file says "no", then don't run the intro. 692 ** Don't do this for TEN & MPath. 693 */ 694 if (!Special.IsFromInstall && Session.Type != GAME_TEN && 695 Session.Type != GAME_MPATH) { 696 Special.IsFromInstall = ini.Get_Bool("Intro", "PlayIntro", true); 697 } 698 SlowPalette = ini.Get_Bool("Options", "SlowPalette", false); 699 700 /* 701 ** Regardless of whether we should run it or not, here we're 702 ** gonna change it to say "no" in the future. 703 */ 704 if (Special.IsFromInstall) { 705 BreakoutAllowed = true; 706 // BreakoutAllowed = false; 707 ini.Put_Bool("Intro", "PlayIntro", false); 708 ini.Save(cfile); 709 } 710 711 #ifndef WOLAPI_INTEGRATION 712 #ifdef WIN32 713 /* 714 ** If WChat has been trying to send us a game start packet then receive it and 715 ** flag that we were spawned from WCHat so we dont play the into movie. 716 */ 717 if (DDEServer.Get_MPlayer_Game_Info()){ 718 Check_From_WChat(NULL); 719 }else{ 720 //Check_From_WChat("C&CSPAWN.INI"); 721 //if (Special.IsFromWChat){ 722 // DDEServer.Disable(); 723 //} 724 } 725 #endif //WIN32 726 #endif 727 /* 728 ** If the intro is being run for the first time, then don't 729 ** allow breaking out of it with the <ESC> key. 730 */ 731 if (Special.IsFromInstall) { 732 BreakoutAllowed = true; 733 // BreakoutAllowed = false; 734 } 735 736 Memory_Error_Exit = Print_Error_End_Exit; 737 738 Main_Game(argc, argv); 739 740 if (RunningAsDLL) { //PG 741 return (EXIT_SUCCESS); 742 } 743 744 #ifdef MPEGMOVIE // Denzil 6/15/98 745 if (MpgSettings != NULL) 746 delete MpgSettings; 747 748 #ifdef MCIMPEG 749 if (MciMovie != NULL) 750 delete MciMovie; 751 #endif 752 #endif 753 754 #ifdef WIN32 755 VisiblePage.Clear(); 756 HiddenPage.Clear(); 757 #else //WIN32 758 SeenPage.Clear(); 759 Set_Video_Mode(RESET_MODE); 760 #endif //WIN32 761 Memory_Error_Exit = Print_Error_Exit; 762 763 #ifdef WIN32 764 /* 765 ** Flag that this is a clean shutdown (not killed with Ctrl-Alt-Del) 766 */ 767 ReadyToQuit = 1; 768 769 /* 770 ** Post a message to our message handler to tell it to clean up. 771 */ 772 PostMessage(MainWindow, WM_DESTROY, 0, 0); 773 774 /* 775 ** Wait until the message handler has dealt with the message 776 */ 777 do 778 { 779 Keyboard->Check(); 780 }while (ReadyToQuit == 1); 781 782 return (EXIT_SUCCESS); 783 784 #else //WIN32 785 Remove_Mouse(); 786 Sound_End(); 787 #endif //WIN32 788 } else { 789 if (!RunningFromEditor) 790 { 791 puts(TEXT_SETUP_FIRST); 792 Keyboard->Get(); 793 } 794 } 795 796 #ifdef WIN32 797 if (WindowsTimer) { 798 delete WindowsTimer; 799 WindowsTimer = NULL; 800 } 801 802 #else //WIN32 803 Remove_Keyboard_Interrupt(); 804 Remove_Timer_System(); 805 #endif //WIN32 806 } 807 /* 808 ** Restore the current drive and directory. 809 */ 810 #ifndef WIN32 811 _dos_setdrive(olddrive, &drivecount); 812 chdir(oldpath); 813 #endif //WIN32 814 return(EXIT_SUCCESS); 815 } 816 817 818 /* Initialize DirectDraw and surfaces */ 819 bool InitDDraw(void) 820 { 821 822 VisiblePage.Init(ScreenWidth, ScreenHeight, NULL, 0, (GBC_Enum)(GBC_VISIBLE | GBC_VIDEOMEM)); 823 HiddenPage.Init(ScreenWidth, ScreenHeight, NULL, 0, (GBC_Enum)GBC_VIDEOMEM); 824 VisiblePage.Attach_DD_Surface(&HiddenPage); 825 SeenBuff.Attach(&VisiblePage, 0, 0, 3072, 3072); 826 HidPage.Attach(&HiddenPage, 0, 0, 3072, 3072); 827 828 #if (0)//PG 829 DDSCAPS surface_capabilities; 830 BOOL video_success = FALSE; 831 832 /* Set 640x400 video mode. If its not available then try for 640x480 */ 833 if (ScreenHeight == 400) 834 { 835 if (Set_Video_Mode(MainWindow, ScreenWidth, ScreenHeight, 8)) 836 { 837 video_success = TRUE; 838 } 839 else 840 { 841 if (Set_Video_Mode(MainWindow, ScreenWidth, 480, 8)) 842 { 843 video_success = TRUE; 844 ScreenHeight = 480; 845 } 846 } 847 } 848 else 849 { 850 if (Set_Video_Mode(MainWindow, ScreenWidth, ScreenHeight, 8)) 851 { 852 video_success = TRUE; 853 } 854 } 855 856 if (!video_success) 857 { 858 MessageBox(MainWindow, TEXT_VIDEO_ERROR, TEXT_SHORT_TITLE, MB_ICONEXCLAMATION|MB_OK); 859 860 if (WindowsTimer) 861 delete WindowsTimer; 862 863 return false; 864 } 865 866 if (ScreenWidth == 320) 867 { 868 VisiblePage.Init(ScreenWidth, ScreenHeight, NULL, 0, (GBC_Enum)0); 869 ModeXBuff.Init(ScreenWidth, ScreenHeight, NULL, 0, (GBC_Enum)(GBC_VISIBLE|GBC_VIDEOMEM)); 870 } 871 else 872 { 873 VisiblePage.Init(ScreenWidth, ScreenHeight, NULL, 0, (GBC_Enum)(GBC_VISIBLE|GBC_VIDEOMEM)); 874 875 /* Check that we really got a video memory page. Failure is fatal. */ 876 memset(&surface_capabilities, 0, sizeof(surface_capabilities)); 877 VisiblePage.Get_DD_Surface()->GetCaps(&surface_capabilities); 878 879 if (surface_capabilities.dwCaps & DDSCAPS_SYSTEMMEMORY) 880 { 881 /* Aaaarrgghh! */ 882 WWDebugString(TEXT_DDRAW_ERROR);WWDebugString("\n"); 883 MessageBox(MainWindow, TEXT_DDRAW_ERROR, TEXT_SHORT_TITLE, MB_ICONEXCLAMATION|MB_OK); 884 885 if (WindowsTimer) 886 delete WindowsTimer; 887 888 return false; 889 } 890 891 /* If we have enough left then put the hidpage in video memory unless... 892 * 893 * If there is no blitter then we will get better performance with a system 894 * memory hidpage 895 * 896 * Use a system memory page if the user has specified it via the ccsetup program. 897 */ 898 unsigned video_memory = Get_Free_Video_Memory(); 899 unsigned video_capabilities = Get_Video_Hardware_Capabilities(); 900 901 if (video_memory < ScreenWidth * ScreenHeight 902 || (!(video_capabilities & VIDEO_BLITTER)) 903 || (video_capabilities & VIDEO_NO_HARDWARE_ASSIST) 904 || !VideoBackBufferAllowed) 905 { 906 HiddenPage.Init(ScreenWidth, ScreenHeight, NULL, 0, (GBC_Enum)0); 907 } 908 else 909 { 910 HiddenPage.Init(ScreenWidth, ScreenHeight, NULL, 0, (GBC_Enum)GBC_VIDEOMEM); 911 912 /* Make sure we really got a video memory hid page. If we didnt then things 913 * will run very slowly. 914 */ 915 memset(&surface_capabilities, 0, sizeof(surface_capabilities)); 916 HiddenPage.Get_DD_Surface()->GetCaps(&surface_capabilities); 917 918 if (surface_capabilities.dwCaps & DDSCAPS_SYSTEMMEMORY) 919 { 920 /* Oh dear, big trub. This must be an IBM Aptiva or something similarly cruddy. 921 * We must redo the Hidden Page as system memory. 922 */ 923 AllSurfaces.Remove_DD_Surface(HiddenPage.Get_DD_Surface()); // Remove the old surface from the AllSurfaces list 924 HiddenPage.Get_DD_Surface()->Release(); 925 HiddenPage.Init(ScreenWidth, ScreenHeight, NULL, 0, (GBC_Enum)0); 926 } 927 else 928 { 929 VisiblePage.Attach_DD_Surface(&HiddenPage); 930 } 931 } 932 } 933 934 ScreenHeight = 400; 935 936 if (VisiblePage.Get_Height() == 480) 937 { 938 SeenBuff.Attach(&VisiblePage, 0, 40, 3072, 3072); 939 HidPage.Attach(&HiddenPage, 0, 40, 3072, 3072); 940 } 941 else 942 { 943 SeenBuff.Attach(&VisiblePage, 0, 0, 3072, 3072); 944 HidPage.Attach(&HiddenPage, 0, 0, 3072, 3072); 945 } 946 #endif 947 return true; 948 } 949 950 951 /*********************************************************************************************** 952 * Prog_End -- Cleans up library systems in prep for game exit. * 953 * * 954 * This routine should be called before the game terminates. It handles cleaning up * 955 * library systems so that a graceful return to the host operating system is achieved. * 956 * * 957 * INPUT: why - text description of exit reason * 958 * fatal - indicates a fatal error * 959 * * 960 * OUTPUT: none * 961 * * 962 * WARNINGS: none * 963 * * 964 * HISTORY: * 965 * 03/20/1995 JLB : Created. * 966 * 08/07/2019 ST : Added why and fatal params * 967 *=============================================================================================*/ 968 #ifdef WIN32 969 void __cdecl Prog_End(const char *why, bool fatal) 970 { 971 GlyphX_Debug_Print("Prog_End()"); 972 973 if (why) { 974 GlyphX_Debug_Print(why); 975 } 976 if (fatal) { 977 *((int*)0) = 0; 978 } 979 980 if (Session.Type == GAME_GLYPHX_MULTIPLAYER) { 981 return; 982 } 983 984 Sound_End(); 985 if (WWMouse) { 986 delete WWMouse; 987 WWMouse = NULL; 988 } 989 if (WindowsTimer) { 990 delete WindowsTimer; 991 WindowsTimer = NULL; 992 } 993 994 ProgEndCalled = true; 995 } 996 #else //WIN32 997 998 void Prog_End(void) 999 { 1000 if (Session.Type == GAME_MODEM || Session.Type == GAME_NULL_MODEM) { 1001 NullModem.Change_IRQ_Priority(0); 1002 } 1003 1004 Set_Video_Mode(RESET_MODE); 1005 Remove_Keyboard_Interrupt(); 1006 Remove_Mouse(); 1007 Sound_End(); 1008 Remove_Timer_System(); 1009 } 1010 #endif //WIN32 1011 1012 1013 void Print_Error_End_Exit(char * string) 1014 { 1015 Prog_End(string, true); 1016 printf( "%s\n", string ); 1017 if (!RunningAsDLL) { 1018 exit(1); 1019 } 1020 } 1021 1022 1023 void Print_Error_Exit(char * string) 1024 { 1025 GlyphX_Debug_Print(string); 1026 1027 printf( "%s\n", string ); 1028 if (!RunningAsDLL) { 1029 exit(1); 1030 } 1031 } 1032 1033 1034 1035 1036 1037 1038 1039 /*********************************************************************************************** 1040 * Emergency_Exit -- Function to call when we want to exit unexpectedly. * 1041 * Use this function instead of exit(n) so everything is properly cleaned up.* 1042 * * 1043 * * 1044 * INPUT: Code to return to the OS * 1045 * * 1046 * OUTPUT: Nothing * 1047 * * 1048 * WARNINGS: None * 1049 * * 1050 * HISTORY: * 1051 * 3/13/97 1:32AM ST : Created * 1052 *=============================================================================================*/ 1053 void Emergency_Exit ( int code ) 1054 { 1055 if (RunningAsDLL) { //PG 1056 return; 1057 } 1058 1059 #ifdef WIN32 1060 1061 /* 1062 ** Clear out the video buffers so we dont glitch when we lose focus 1063 */ 1064 VisiblePage.Clear(); 1065 HiddenPage.Clear(); 1066 BlackPalette.Set(); 1067 Memory_Error_Exit = Print_Error_Exit; 1068 1069 /* 1070 ** Flag that this is an emergency shut down - not a clean shutdown but 1071 ** not killed with Ctrl-Alt-Del either. 1072 */ 1073 ReadyToQuit = 3; 1074 1075 /* 1076 ** Post a message to our message handler to tell it to clean up. 1077 */ 1078 PostMessage(MainWindow, WM_DESTROY, 0, 0); 1079 1080 /* 1081 ** Wait until the message handler has dealt with the message 1082 */ 1083 do 1084 { 1085 Keyboard->Check(); 1086 }while (ReadyToQuit == 3); 1087 1088 1089 #else //WIN32 1090 /* 1091 ** Do the DOS end 1092 */ 1093 Prog_End(); 1094 1095 #endif //WIN32 1096 1097 exit ( code ); 1098 } 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 #ifdef WIN32 1111 1112 /*********************************************************************************************** 1113 * Read_Setup_Options -- Read stuff in from the INI file that we need to know sooner * 1114 * * 1115 * * 1116 * * 1117 * INPUT: Ptr to config file class * 1118 * * 1119 * OUTPUT: Nothing * 1120 * * 1121 * WARNINGS: None * 1122 * * 1123 * HISTORY: * 1124 * 6/7/96 4:09PM ST : Created * 1125 * 09/30/1996 JLB : Uses INI class. * 1126 *=============================================================================================*/ 1127 void Read_Setup_Options( RawFileClass *config_file ) 1128 { 1129 if (config_file->Is_Available()) { 1130 1131 INIClass ini; 1132 1133 ini.Load(*config_file); 1134 1135 /* 1136 ** Read in the boolean options 1137 */ 1138 VideoBackBufferAllowed = ini.Get_Bool("Options", "VideoBackBuffer", true); 1139 AllowHardwareBlitFills = ini.Get_Bool("Options", "HardwareFills", true); 1140 ScreenHeight = ini.Get_Bool("Options", "Resolution", false) ? 3072 : 3072; 1141 1142 /* 1143 ** See if an alternative socket number has been specified 1144 */ 1145 int socket = ini.Get_Int("Options", "Socket", 0); 1146 if (socket >0 ) { 1147 socket += 0x4000; 1148 if (socket >= 0x4000 && socket < 0x8000) { 1149 Ipx.Set_Socket (socket); 1150 } 1151 } 1152 1153 /* 1154 ** See if a destination network has been specified 1155 */ 1156 char netbuf [512]; 1157 memset(netbuf, 0, sizeof(netbuf)); 1158 char * netptr = netbuf; 1159 bool found = ini.Get_String("Options", "DestNet", NULL, netbuf, sizeof(netbuf)); 1160 1161 if (found && netptr != NULL && strlen(netbuf)) { 1162 NetNumType net; 1163 NetNodeType node; 1164 1165 /* 1166 ** Scan the string, pulling off each address piece 1167 */ 1168 int i = 0; 1169 char * p = strtok(netbuf,"."); 1170 int x; 1171 while (p != NULL) { 1172 sscanf(p,"%x",&x); // convert from hex string to int 1173 if (i < 4) { 1174 net[i] = (char)x; // fill NetNum 1175 } else { 1176 node[i-4] = (char)x; // fill NetNode 1177 } 1178 i++; 1179 p = strtok(NULL,"."); 1180 } 1181 1182 /* 1183 ** If all the address components were successfully read, fill in the 1184 ** BridgeNet with a broadcast address to the network across the bridge. 1185 */ 1186 if (i >= 4) { 1187 Session.IsBridge = 1; 1188 memset(node, 0xff, 6); 1189 Session.BridgeNet = IPXAddressClass(net, node); 1190 } 1191 } 1192 } 1193 } 1194 1195 void Get_OS_Version (void) 1196 { 1197 //PG 1198 //WindowsNT = ((GetVersion() & 0x80000000) == 0) ? true : false; 1199 1200 #if (0) 1201 OSVERSIONINFO osversion; 1202 if ( GetVersionEx (&osversion) ){ 1203 WindowsNT = (osversion.dwPlatformId == VER_PLATFORM_WIN32_NT) ? true : false; 1204 OutputDebugString ("RA95 - Got OS version\n"); 1205 }else{ 1206 OutputDebugString ("RA95 - Failed to get OS version\n"); 1207 char debugstr [128]; 1208 sprintf (debugstr, "RA95 - Error code is %d\n", GetLastError()); 1209 OutputDebugString (debugstr); 1210 1211 } 1212 #endif //(0) 1213 1214 } 1215 1216 1217 #endif //WIN32