CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

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 verfgbar.\n");
    207 #else
    208 #ifdef FRENCH
    209 		printf("M‚moire 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 systŠme n'a pas pu s'initialiser en raison de l'instabilit‚ du sytŠme. Vous devez red‚marrer Windows.",  "Command & Conquer" , MB_OK|MB_ICONSTOP);
    326 #else
    327 #ifdef	GERMAN
    328 			MessageBox(0, "Fehler - das Timer-System konnte aufgrund einer Instabilit„t 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 fr 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 }