STARTUP.CPP (29014B)
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\startup.cpv 2.17 16 Oct 1995 16:48:12 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 : STARTUP.CPP * 24 * * 25 * Programmer : Joe L. Bostic * 26 * * 27 * Start Date : October 3, 1994 * 28 * * 29 * Last Update : August 27, 1995 [JLB] * 30 * * 31 *---------------------------------------------------------------------------------------------* 32 * Functions: * 33 * Delete_Swap_Files -- Deletes previously existing swap files. * 34 * Prog_End -- Cleans up library systems in prep for game exit. * 35 * main -- Initial startup routine (preps library systems). * 36 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 37 38 #include "function.h" 39 #include <conio.h> 40 #include <io.h> 41 #include "ccdde.h" 42 43 bool Read_Private_Config_Struct(char *profile, NewConfigType *config); 44 void Delete_Swap_Files(void); 45 void Print_Error_End_Exit(char *string); 46 void Print_Error_Exit(char *string); 47 WinTimerClass *WinTimer; 48 extern void Create_Main_Window ( HANDLE instance , int command_show , int width , int height); 49 50 extern bool ReadyToQuit; 51 void Read_Setup_Options(RawFileClass *config_file); 52 53 bool VideoBackBufferAllowed = true; 54 void Check_From_WChat(char *wchat_name); 55 bool SpawnedFromWChat = false; 56 bool ProgEndCalled = false; 57 58 59 extern "C"{ 60 bool __cdecl Detect_MMX_Availability(void); 61 void __cdecl Init_MMX(void); 62 } 63 64 65 66 #if (0) 67 char WibbleBuffer[1024*1024]; 68 69 void CD_Test(void) 70 { 71 HANDLE handle; 72 DWORD size; 73 74 handle= CreateFile("e:\\scores.mix", GENERIC_READ, FILE_SHARE_READ, 75 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 76 77 if (handle== INVALID_HANDLE_VALUE){ 78 return; 79 } 80 81 unsigned bytes_read; 82 83 do{ 84 bytes_read = ReadFile (handle , WibbleBuffer , 1024*1024, &size, NULL); 85 86 }while(size == 1024*1024); 87 88 89 CloseHandle (handle); 90 } 91 #endif //(0) 92 93 94 95 /*********************************************************************************************** 96 * main -- Initial startup routine (preps library systems). * 97 * * 98 * This is the routine that is first called when the program starts up. It basically * 99 * handles the command line parsing and setting up library systems. * 100 * * 101 * INPUT: argc -- Number of command line arguments. * 102 * * 103 * argv -- Pointer to array of comman line argument strings. * 104 * * 105 * OUTPUT: Returns with execution failure code (if any). * 106 * * 107 * WARNINGS: none * 108 * * 109 * HISTORY: * 110 * 03/20/1995 JLB : Created. * 111 *=============================================================================================*/ 112 113 HINSTANCE ProgramInstance; 114 extern BOOL CC95AlreadyRunning; 115 void Move_Point(short &x, short &y, register DirType dir, unsigned short distance); 116 117 void Check_Use_Compressed_Shapes (void); 118 extern void DLL_Shutdown(void); 119 120 121 BOOL WINAPI DllMain(HINSTANCE instance, unsigned int fdwReason, void *lpvReserved) 122 { 123 lpvReserved; 124 125 switch (fdwReason) { 126 127 case DLL_PROCESS_ATTACH: 128 ProgramInstance = instance; 129 break; 130 131 case DLL_PROCESS_DETACH: 132 if (WindowsTimer) { 133 delete WindowsTimer; 134 WindowsTimer = NULL; 135 } 136 DLL_Shutdown(); 137 138 MixFileClass::Free_All(); 139 140 Uninit_Game(); 141 142 break; 143 144 case DLL_THREAD_ATTACH: 145 case DLL_THREAD_DETACH: 146 break; 147 } 148 149 150 151 return true; 152 } 153 154 155 //int PASCAL WinMain ( HINSTANCE instance , HINSTANCE , char * command_line , int command_show ) 156 //{ 157 // Heap_Dump_Check( "first thing in main" ); 158 // malloc(1); 159 160 int DLL_Startup(const char * command_line_in) 161 { 162 RunningAsDLL = true; 163 int command_show = SW_HIDE; 164 HINSTANCE instance = ProgramInstance; 165 char command_line[1024]; 166 strcpy(command_line, command_line_in); 167 168 CCDebugString ("C&C95 - Starting up.\n"); 169 170 171 //WindowsTimer = new WinTimerClass(60,FALSE); 172 //CD_Test(); 173 174 175 176 /* 177 ** These values return 0x47 if code is working correctly 178 */ 179 // int temp = Desired_Facing256 (1070, 5419, 1408, 5504); 180 181 182 183 /* 184 ** If we are already running then switch to the existing process and exit 185 */ 186 SpawnedFromWChat = false; 187 188 if (CC95AlreadyRunning) { //Set in the DDEServer constructor 189 //MessageBox (NULL, "Error - attempt to restart C&C95 when already running.", "Command & Conquer", MB_ICONEXCLAMATION|MB_OK); 190 191 HWND ccwindow; 192 ccwindow = FindWindow ("Command & Conquer", "Command & Conquer"); 193 if (ccwindow){ 194 SetForegroundWindow ( ccwindow ); 195 ShowWindow ( ccwindow, SW_RESTORE ); 196 } 197 198 return (EXIT_SUCCESS); 199 } 200 201 // ST - 3/6/2019 1:36PM 202 //DDSCAPS surface_capabilities; 203 204 if (Ram_Free(MEM_NORMAL) < 5000000) { 205 #ifdef GERMAN 206 printf("Zuwenig Hauptspeicher verfgbar.\n"); 207 #else 208 #ifdef FRENCH 209 printf("Mmoire vive (RAM) insuffisante.\n"); 210 #else 211 printf("Insufficient RAM available.\n"); 212 #endif 213 #endif 214 return(EXIT_FAILURE); 215 } 216 217 218 //void *test_buffer = Alloc(20,MEM_NORMAL); 219 220 //memset ((char*)test_buffer, 0, 21); 221 222 //Free(test_buffer); 223 224 225 int argc; //Command line argument count 226 unsigned command_scan; 227 char command_char; 228 char * argv[20]; //Pointers to command line arguments 229 char path_to_exe[280]; 230 231 ProgramInstance = instance; 232 233 /* 234 ** Get the full path to the .EXE 235 */ 236 GetModuleFileName (instance, &path_to_exe[0], 280); 237 238 /* 239 ** First argument is supposed to be a pointer to the .EXE that is running 240 ** 241 */ 242 argc=1; //Set argument count to 1 243 argv[0]=&path_to_exe[0]; //Set 1st command line argument to point to full path 244 245 /* 246 ** Get pointers to command line arguments just like if we were in DOS 247 ** 248 ** The command line we get is cr/zero? terminated. 249 ** 250 */ 251 252 command_scan=0; 253 254 do { 255 /* 256 ** Scan for non-space character on command line 257 */ 258 do { 259 command_char = *( command_line+command_scan++ ); 260 } while ( command_char==' ' ); 261 262 if ( command_char!=0 && command_char != 13 ){ 263 argv[argc++]=command_line+command_scan-1; 264 265 /* 266 ** Scan for space character on command line 267 */ 268 bool in_quotes = false; 269 do { 270 command_char = *( command_line+command_scan++ ); 271 if (command_char == '"') { 272 in_quotes = !in_quotes; 273 } 274 } while ( (in_quotes || command_char!=' ') && command_char != 0 && command_char!=13 ); 275 276 *( command_line+command_scan-1 ) = 0; 277 } 278 279 } while ( command_char != 0 && command_char != 13 && argc<20 ); 280 281 282 283 /* 284 ** Remember the current working directory and drive. 285 */ 286 #if (0) //PG_TO_FIX 287 unsigned olddrive; 288 char oldpath[MAX_PATH]; 289 getcwd(oldpath, sizeof(oldpath)); 290 _dos_getdrive(&olddrive); 291 292 293 /* 294 ** Change directory to the where the executable is located. Handle the 295 ** case where there is no path attached to argv[0]. 296 */ 297 char drive[_MAX_DRIVE]; 298 char path[_MAX_PATH]; 299 unsigned drivecount; 300 _splitpath(argv[0], drive, path, NULL, NULL); 301 if (!drive[0]) { 302 drive[0] = ('A' + olddrive)-1; 303 } 304 if (!path[0]) { 305 strcpy(path, "."); 306 } 307 _dos_setdrive(toupper((drive[0])-'A')+1, &drivecount); 308 if (path[strlen(path)-1] == '\\') { 309 path[strlen(path)-1] = '\0'; 310 } 311 chdir(path); 312 #endif 313 314 #ifdef JAPANESE 315 ForceEnglish = false; 316 #endif 317 if (Parse_Command_Line(argc, argv)) { 318 319 WindowsTimer = new WinTimerClass(60,FALSE); 320 #if (0) 321 int time_test = WindowsTimer->Get_System_Tick_Count(); 322 Sleep (1000); 323 if (WindowsTimer->Get_System_Tick_Count() == time_test){ 324 #ifdef FRENCH 325 MessageBox(0, "Error - L'horloge systme n'a pas pu s'initialiser en raison de l'instabilit du sytme. Vous devez redmarrer Windows.", "Command & Conquer" , MB_OK|MB_ICONSTOP); 326 #else 327 #ifdef GERMAN 328 MessageBox(0, "Fehler - das Timer-System konnte aufgrund einer Instabilitt des Systems nicht initialisiert werden. Bitte starten Sie Windows neu.", "Command & Conquer", MB_OK|MB_ICONSTOP); 329 #else 330 MessageBox(0, "Error - Timer system failed to start due to system instability. You need to restart Windows.", "Command & Conquer", MB_OK|MB_ICONSTOP); 331 #endif //GERMAN 332 #endif //FRENCH 333 return(EXIT_FAILURE); 334 } 335 #endif 336 337 RawFileClass cfile("CONQUER.INI"); 338 339 #ifdef JAPANESE 340 //////////////////////////////////////if(!ForceEnglish) KBLanguage = 1; 341 #endif 342 343 344 /* 345 ** Check for existance of MMX support on the processor 346 */ 347 if (Detect_MMX_Availability()){ 348 //MessageBox(NULL, "MMX extensions detected - enabling MMX support.", "Command & Conquer",MB_ICONEXCLAMATION|MB_OK); 349 MMXAvailable = true; 350 } 351 352 /* 353 ** If there is loads of memory then use uncompressed shapes 354 */ 355 Check_Use_Compressed_Shapes(); 356 357 /* 358 ** If there is not enough disk space free, dont allow the product to run. 359 */ 360 if (Disk_Space_Available() < INIT_FREE_DISK_SPACE) { 361 #ifdef GERMAN 362 char disk_space_message [512]; 363 sprintf (disk_space_message, "Nicht genug Festplattenplatz fr Command & Conquer.\nSie brauchen %d MByte freien Platz auf der Festplatte.", (INIT_FREE_DISK_SPACE) / (1024 * 1024)); 364 MessageBox(NULL, disk_space_message, "Command & Conquer", MB_ICONEXCLAMATION|MB_OK); 365 if ( WindowsTimer ) 366 delete WindowsTimer; 367 return (EXIT_FAILURE); 368 #endif 369 #ifdef FRENCH 370 char disk_space_message [512]; 371 sprintf (disk_space_message, "Espace disque insuffisant pour lancer Command & Conquer.\nVous devez disposer de %d Mo d'espace disponsible sur disque dur.", (INIT_FREE_DISK_SPACE) / (1024 * 1024)); 372 MessageBox(NULL, disk_space_message, "Command & Conquer", MB_ICONEXCLAMATION|MB_OK); 373 if ( WindowsTimer ) 374 delete WindowsTimer; 375 return (EXIT_FAILURE); 376 #endif 377 #if !(FRENCH | GERMAN) 378 int reply = MessageBox(NULL, "Warning - you are critically low on free disk space for virtual memory and save games. Do you want to play C&C anyway?", "Command & Conquer", MB_ICONQUESTION|MB_YESNO); 379 if (reply == IDNO){ 380 381 if ( WindowsTimer ) 382 delete WindowsTimer; 383 return (EXIT_FAILURE); 384 } 385 386 #endif 387 } 388 389 #if (0) // ST - 1/2/2019 5:50PM 390 CDFileClass::Set_CD_Drive (CDList.Get_First_CD_Drive()); 391 #endif 392 if (cfile.Is_Available()) { 393 394 #ifndef NOMEMCHECK 395 char * cdata = (char *)Load_Alloc_Data(cfile); 396 Read_Private_Config_Struct(cdata, &NewConfig); 397 delete [] cdata; 398 #else 399 Read_Private_Config_Struct((char *)Load_Alloc_Data(cfile), &NewConfig); 400 #endif 401 Read_Setup_Options( &cfile ); 402 403 CCDebugString ("C&C95 - Creating main window.\n"); 404 405 Create_Main_Window( instance , command_show , ScreenWidth , ScreenHeight ); 406 407 CCDebugString ("C&C95 - Initialising audio.\n"); 408 409 SoundOn = Audio_Init ( MainWindow , 16 , false , 11025*2 , 0 ); 410 411 Palette = new(MEM_CLEAR) unsigned char[768]; 412 413 BOOL video_success = FALSE; 414 CCDebugString ("C&C95 - Setting video mode.\n"); 415 /* 416 ** Set 640x400 video mode. If its not available then try for 640x480 417 */ 418 if (ScreenHeight == 400){ 419 if (Set_Video_Mode (MainWindow, ScreenWidth, ScreenHeight, 8)){ 420 video_success = TRUE; 421 }else{ 422 if (Set_Video_Mode (MainWindow, ScreenWidth, 480, 8)){ 423 video_success = TRUE; 424 ScreenHeight = 480; 425 } 426 } 427 }else{ 428 if (Set_Video_Mode (MainWindow, ScreenWidth, ScreenHeight, 8)){ 429 video_success = TRUE; 430 } 431 } 432 433 if (!video_success){ 434 CCDebugString ("C&C95 - Failed to set video mode.\n"); 435 MessageBox(MainWindow, Text_String(TXT_UNABLE_TO_SET_VIDEO_MODE), "Command & Conquer", MB_ICONEXCLAMATION|MB_OK); 436 if (WindowsTimer) delete WindowsTimer; 437 if (Palette) delete [] Palette; 438 return (EXIT_FAILURE); 439 } 440 441 CCDebugString ("C&C95 - Initialising video surfaces.\n"); 442 443 if (ScreenWidth==320){ 444 VisiblePage.Init( ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0); 445 ModeXBuff.Init( ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)(GBC_VISIBLE | GBC_VIDEOMEM)); 446 } else { 447 448 #if (1) //ST - 1/3/2019 2:11PM 449 450 VisiblePage.Init( ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0); 451 HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0); 452 453 454 #else 455 VisiblePage.Init( ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)(GBC_VISIBLE | GBC_VIDEOMEM)); 456 457 /* 458 ** Check that we really got a video memory page. Failure is fatal. 459 */ 460 memset (&surface_capabilities, 0, sizeof(surface_capabilities)); 461 VisiblePage.Get_DD_Surface()->GetCaps(&surface_capabilities); 462 if (surface_capabilities.dwCaps & DDSCAPS_SYSTEMMEMORY){ 463 /* 464 ** Aaaarrgghh! 465 */ 466 CCDebugString ("C&C95 - Unable to allocate primary surface.\n"); 467 MessageBox(MainWindow, Text_String(TXT_UNABLE_TO_ALLOCATE_PRIMARY_VIDEO_BUFFER), "Command & Conquer", MB_ICONEXCLAMATION|MB_OK); 468 if (WindowsTimer) delete WindowsTimer; 469 if (Palette) delete [] Palette; 470 return (EXIT_FAILURE); 471 } 472 473 /* 474 ** If we have enough left then put the hidpage in video memory unless... 475 ** 476 ** If there is no blitter then we will get better performance with a system 477 ** memory hidpage 478 ** 479 ** Use a system memory page if the user has specified it via the ccsetup program. 480 */ 481 CCDebugString ("C&C95 - Allocating back buffer "); 482 long video_memory = Get_Free_Video_Memory(); 483 unsigned video_capabilities = Get_Video_Hardware_Capabilities(); 484 if (video_memory < ScreenWidth*ScreenHeight || 485 (! (video_capabilities & VIDEO_BLITTER)) || 486 (video_capabilities & VIDEO_NO_HARDWARE_ASSIST) || 487 !VideoBackBufferAllowed){ 488 CCDebugString ("in system memory.\n"); 489 HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0); 490 } else { 491 //HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0); 492 CCDebugString ("in video memory.\n"); 493 HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)GBC_VIDEOMEM); 494 495 /* 496 ** Make sure we really got a video memory hid page. If we didnt then things 497 ** will run very slowly. 498 */ 499 memset (&surface_capabilities, 0, sizeof(surface_capabilities)); 500 HiddenPage.Get_DD_Surface()->GetCaps(&surface_capabilities); 501 if (surface_capabilities.dwCaps & DDSCAPS_SYSTEMMEMORY){ 502 /* 503 ** Oh dear, big trub. This must be an IBM Aptiva or something similarly cruddy. 504 ** We must redo the Hidden Page as system memory. 505 */ 506 AllSurfaces.Remove_DD_Surface(HiddenPage.Get_DD_Surface()); // Remove the old surface from the AllSurfaces list 507 HiddenPage.Get_DD_Surface()->Release(); 508 HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0); 509 }else{ 510 VisiblePage.Attach_DD_Surface(&HiddenPage); 511 } 512 } 513 #endif 514 } 515 ScreenHeight = 1536; 516 517 if (VisiblePage.Get_Height() == 480){ 518 SeenBuff.Attach(&VisiblePage,0, 40, 1536, 1536); 519 HidPage.Attach(&HiddenPage, 0, 40, 1536, 1536); 520 }else{ 521 SeenBuff.Attach(&VisiblePage,0, 0, 1536, 1536); 522 HidPage.Attach(&HiddenPage, 0, 0, 1536, 1536); 523 } 524 CCDebugString ("C&C95 - Adjusting variables for resolution.\n"); 525 Options.Adjust_Variables_For_Resolution(); 526 527 CCDebugString ("C&C95 - Setting palette.\n"); 528 /////////Set_Palette(Palette); 529 530 WindowList[0][WINDOWWIDTH] = SeenBuff.Get_Width() >> 3; 531 WindowList[0][WINDOWHEIGHT] = SeenBuff.Get_Height(); 532 533 /* 534 ** Install the memory error handler 535 */ 536 Memory_Error = &Memory_Error_Handler; 537 538 /* 539 ** Initialise MMX support if its available 540 */ 541 CCDebugString ("C&C95 - Entering MMX detection.\n"); 542 if (MMXAvailable){ 543 Init_MMX(); 544 } 545 546 CCDebugString ("C&C95 - Creating mouse class.\n"); 547 WWMouse = new WWMouseClass(&SeenBuff, 32, 32); 548 // MouseInstalled = Install_Mouse(32,24,320,200); 549 MouseInstalled = TRUE; 550 551 /* 552 ** See if we should run the intro 553 */ 554 CCDebugString ("C&C95 - Reading CONQUER.INI.\n"); 555 char *buffer = (char*)Alloc(64000 , MEM_NORMAL); //(char *)HidPage.Get_Buffer(); 556 cfile.Read(buffer, cfile.Size()); 557 buffer[cfile.Size()] = '\0'; 558 559 /* 560 ** Check for forced intro movie run disabling. If the conquer 561 ** configuration file says "no", then don't run the intro. 562 */ 563 char tempbuff[5]; 564 WWGetPrivateProfileString("Intro", "PlayIntro", "Yes", tempbuff, 4, buffer); 565 if ((stricmp(tempbuff, "No") == 0) || SpawnedFromWChat) { 566 Special.IsFromInstall = false; 567 }else{ 568 Special.IsFromInstall = true; 569 } 570 SlowPalette = WWGetPrivateProfileInt("Options", "SlowPalette", 1, buffer); 571 572 #ifdef DEMO 573 /* 574 ** Check for override directory path for CD searches. 575 */ 576 WWGetPrivateProfileString("CD", "Path", ".", OverridePath, sizeof(OverridePath), buffer); 577 #endif 578 579 /* 580 ** Regardless of whether we should run it or not, here we're 581 ** gonna change it to say "no" in the future. 582 */ 583 WWWritePrivateProfileString("Intro", "PlayIntro", "No", buffer); 584 cfile.Write(buffer, strlen(buffer)); 585 586 Free(buffer); 587 588 CCDebugString ("C&C95 - Checking availability of C&CSPAWN.INI packet from WChat.\n"); 589 if (DDEServer.Get_MPlayer_Game_Info()){ 590 CCDebugString ("C&C95 - C&CSPAWN.INI packet available.\n"); 591 Check_From_WChat(NULL); 592 }else{ 593 CCDebugString ("C&C95 - C&CSPAWN.INI packet not arrived yet.\n"); 594 //Check_From_WChat("C&CSPAWN.INI"); 595 //if (Special.IsFromWChat){ 596 // DDEServer.Disable(); 597 //} 598 } 599 600 /* 601 ** If the intro is being run for the first time, then don't 602 ** allow breaking out of it with the <ESC> key. 603 */ 604 if (Special.IsFromInstall) { 605 BreakoutAllowed = false; 606 } 607 608 Memory_Error_Exit = Print_Error_End_Exit; 609 610 CCDebugString ("C&C95 - Entering main game.\n"); 611 Main_Game(argc, argv); 612 613 if (RunningAsDLL) { 614 return (EXIT_SUCCESS); 615 } 616 617 VisiblePage.Clear(); 618 HiddenPage.Clear(); 619 // Set_Video_Mode(RESET_MODE); 620 621 Memory_Error_Exit = Print_Error_Exit; 622 623 CCDebugString ("C&C95 - About to exit.\n"); 624 ReadyToQuit = 1; 625 626 PostMessage(MainWindow, WM_DESTROY, 0, 0); 627 do 628 { 629 Keyboard::Check(); 630 }while (ReadyToQuit == 1); 631 632 CCDebugString ("C&C95 - Returned from final message loop.\n"); 633 //Prog_End(); 634 //Invalidate_Cached_Icons(); 635 //VisiblePage.Un_Init(); 636 //HiddenPage.Un_Init(); 637 //AllSurfaces.Release(); 638 //Reset_Video_Mode(); 639 //Stop_Profiler(); 640 return (EXIT_SUCCESS); 641 642 } else { 643 #ifdef GERMAN 644 puts("Bitte erst das SETUP-Programm starten.\n"); 645 #else 646 #ifdef FRENCH 647 puts("Lancez d'abord le programme de configuration SETUP.\n"); 648 #else 649 puts("Run SETUP program first."); 650 puts("\n"); 651 #endif 652 Kbd.Get(); 653 #endif 654 } 655 656 // Remove_Keyboard_Interrupt(); 657 if (WindowsTimer){ 658 delete WindowsTimer; 659 WindowsTimer = NULL; 660 } 661 662 if (Palette){ 663 delete [] Palette; 664 Palette = NULL; 665 } 666 } 667 668 /* 669 ** Restore the current drive and directory. 670 */ 671 #ifdef NOT_FOR_WIN95 672 _dos_setdrive(olddrive, &drivecount); 673 chdir(oldpath); 674 #endif //NOT_FOR_WIN95 675 676 return(EXIT_SUCCESS); 677 } 678 679 680 /*********************************************************************************************** 681 * Prog_End -- Cleans up library systems in prep for game exit. * 682 * * 683 * This routine should be called before the game terminates. It handles cleaning up * 684 * library systems so that a graceful return to the host operating system is achieved. * 685 * * 686 * INPUT: none * 687 * * 688 * OUTPUT: none * 689 * * 690 * WARNINGS: none * 691 * * 692 * HISTORY: * 693 * 03/20/1995 JLB : Created. * 694 *=============================================================================================*/ 695 void __cdecl Prog_End(const char *why, bool fatal) // Added why and fatal parameters. ST - 6/27/2019 10:10PM 696 { 697 GlyphX_Debug_Print("Prog_End()"); 698 699 if (why) { 700 GlyphX_Debug_Print(why); 701 } 702 if (fatal) { 703 *((int*)0) = 0; 704 } 705 706 #ifndef DEMO 707 if (GameToPlay == GAME_MODEM || GameToPlay == GAME_NULL_MODEM) { 708 // NullModem.Change_IRQ_Priority(0); 709 } 710 #endif 711 CCDebugString ("C&C95 - About to call Sound_End.\n"); 712 Sound_End(); 713 CCDebugString ("C&C95 - Returned from Sound_End.\n"); 714 if (WWMouse){ 715 CCDebugString ("C&C95 - Deleting mouse object.\n"); 716 delete WWMouse; 717 WWMouse = NULL; 718 } 719 if (WindowsTimer){ 720 CCDebugString ("C&C95 - Deleting windows timer.\n"); 721 delete WindowsTimer; 722 WindowsTimer = NULL; 723 } 724 725 if (Palette){ 726 CCDebugString ("C&C95 - Deleting palette object.\n"); 727 delete [] Palette; 728 Palette = NULL; 729 } 730 731 ProgEndCalled = true; 732 } 733 734 735 /*********************************************************************************************** 736 * Delete_Swap_Files -- Deletes previously existing swap files. * 737 * * 738 * This routine will scan through the current directory and delete any swap files it may * 739 * find. This is used to clear out any left over swap files from previous runs (crashes) * 740 * of the game. This routine presumes that it cannot delete the swap file that is created * 741 * by the current run of the game. * 742 * * 743 * INPUT: none * 744 * * 745 * OUTPUT: none * 746 * * 747 * WARNINGS: none * 748 * * 749 * HISTORY: * 750 * 08/27/1995 JLB : Created. * 751 *=============================================================================================*/ 752 void Delete_Swap_Files(void) 753 { 754 #if (0) 755 struct find_t ff; // for _dos_findfirst 756 757 if (!_dos_findfirst("*.SWP", _A_NORMAL, &ff)) { 758 do { 759 unlink(ff.name); 760 } while(!_dos_findnext(&ff)); 761 } 762 #endif 763 } 764 765 766 void Print_Error_End_Exit(char *string) 767 { 768 printf( "%s\n", string ); 769 Get_Key(); 770 Prog_End(); 771 printf( "%s\n", string ); 772 if (!RunningAsDLL) { 773 exit(1); 774 } 775 } 776 777 778 void Print_Error_Exit(char *string) 779 { 780 printf( "%s\n", string ); 781 if (!RunningAsDLL) { 782 exit(1); 783 } 784 } 785 786 787 788 789 790 791 792 793 /*********************************************************************************************** 794 * Read_Setup_Options -- Read stuff in from the INI file that we need to know sooner * 795 * * 796 * * 797 * * 798 * INPUT: Nothing * 799 * * 800 * OUTPUT: Nothing * 801 * * 802 * WARNINGS: None * 803 * * 804 * HISTORY: * 805 * 6/7/96 4:09PM ST : Created * 806 *=============================================================================================*/ 807 void Read_Setup_Options( RawFileClass *config_file ) 808 { 809 char *buffer = new char [config_file->Size()]; 810 811 if (config_file->Is_Available()){ 812 813 config_file->Read (buffer, config_file->Size()); 814 815 VideoBackBufferAllowed = WWGetPrivateProfileInt ("Options", "VideoBackBuffer", 1, buffer); 816 AllowHardwareBlitFills = WWGetPrivateProfileInt ("Options", "HardwareFills", 1, buffer); 817 ScreenHeight = WWGetPrivateProfileInt ("Options", "Resolution", 0, buffer) ? 1536 : 1536; 818 IsV107 = WWGetPrivateProfileInt ("Options", "Compatibility", 0, buffer); 819 820 /* 821 ** See if an alternative socket number has been specified 822 */ 823 int socket = WWGetPrivateProfileInt ("Options", "Socket", 0, buffer); 824 if (socket >0 ){ 825 socket += 0x4000; 826 if (socket >= 0x4000 && socket < 0x8000) { 827 Ipx.Set_Socket (socket); 828 } 829 } 830 831 /* 832 ** See if a destination network has been specified 833 */ 834 char netbuf [512]; 835 memset (netbuf, 0, sizeof (netbuf) ); 836 char *netptr = WWGetPrivateProfileString ("Options", "DestNet", NULL, netbuf, sizeof (netbuf), buffer); 837 838 if (netptr && strlen (netbuf)){ 839 NetNumType net; 840 NetNodeType node; 841 842 /* 843 ** Scan the string, pulling off each address piece 844 */ 845 int i = 0; 846 char * p = strtok(netbuf,"."); 847 int x; 848 while (p) { 849 sscanf(p,"%x",&x); // convert from hex string to int 850 if (i < 4) { 851 net[i] = (char)x; // fill NetNum 852 } else { 853 node[i-4] = (char)x; // fill NetNode 854 } 855 i++; 856 p = strtok(NULL,"."); 857 } 858 859 /* 860 ** If all the address components were successfully read, fill in the 861 ** BridgeNet with a broadcast address to the network across the bridge. 862 */ 863 if (i >= 4) { 864 IsBridge = 1; 865 memset(node, 0xff, 6); 866 BridgeNet = IPXAddressClass(net, node); 867 } 868 } 869 870 } 871 872 delete [] buffer; 873 }