CnC_Remastered_Collection

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

INIT.CPP (90624B)


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