CnC_Remastered_Collection

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

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