CnC_Remastered_Collection

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

SCENARIO.CPP (129951B)


      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 //Mono_Printf("%d %s\n",__LINE__,__FILE__);
     17 /* $Header: /CounterStrike/SCENARIO.CPP 15    3/13/97 2:06p Steve_tall $ */
     18 /***********************************************************************************************
     19  ***              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               ***
     20  ***********************************************************************************************
     21  *                                                                                             *
     22  *                 Project Name : Command & Conquer                                            *
     23  *                                                                                             *
     24  *                    File Name : SCENARIO.CPP                                                 *
     25  *                                                                                             *
     26  *                   Programmer : Joe L. Bostic                                                *
     27  *                                                                                             *
     28  *                   Start Date : September 10, 1993                                           *
     29  *                                                                                             *
     30  *                  Last Update : October 21, 1996 [JLB]                                       *
     31  *                                                                                             *
     32  * This module handles the scenario reading and writing. Scenario related                      *
     33  * code that is executed between scenario play can also be here.                               *
     34  *                                                                                             *
     35  *---------------------------------------------------------------------------------------------*
     36  * Functions:                                                                                  *
     37  *   Assign_Houses -- Assigns multiplayer houses to various players                            *
     38  *   Clear_Flag_Spots -- Clears flag overlays off the map                                      *
     39  *   Clear_Scenario -- Clears all data in preparation for scenario load.                       *
     40  *   Clip_Move -- moves in given direction from given cell; clips to map                       *
     41  *   Clip_Scatter -- randomly scatters from given cell; won't fall off map                     *
     42  *   Create_Units -- Creates infantry & units, for non-base multiplayer                        *
     43  *   Do_Lose -- Display losing comments.                                                       *
     44  *   Do_Restart -- Handle the restart mission process.                                         *
     45  *   Do_Win -- Display winning congratulations.                                                *
     46  *   Fill_In_Data -- Recreate all data that is not loaded with scenario.                       *
     47  *   Post_Load_Game -- Fill in an inferred data from the game state.                           *
     48  *   Read_Scenario -- Reads a scenario from disk.                                              *
     49  *   Read_Scenario_INI -- Read specified scenario INI file.                                    *
     50  *   Remove_AI_Players -- Removes the computer AI houses & their units                         *
     51  *   Restate_Mission -- Handles restating the mission objective.                               *
     52  *   Scan_Place_Object -- places an object >near< the given cell                               *
     53  *   ScenarioClass::ScenarioClass -- Constructor for the scenario control object.              *
     54  *   ScenarioClass::Set_Global_To -- Set scenario global to value specified.                   *
     55  *   Set_Scenario_Name -- Creates the INI scenario name string.                                *
     56  *   Start_Scenario -- Starts the scenario.                                                    *
     57  *   Write_Scenario_INI -- Write the scenario INI file.                                        *
     58  *   ScenarioClass::Do_BW_Fade -- Cause the palette to temporarily shift to B/W.               *
     59  *   ScenarioClass::Do_Fade_AI -- Process the palette fading effect.                           *
     60  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     61 
     62 #include	"function.h"
     63 #ifdef WIN32
     64 #include "tcpip.h"
     65 #include "ccdde.h"
     66 
     67 extern bool SpawnedFromWChat;
     68 #endif
     69 extern int PreserveVQAScreen;
     70 
     71 void Display_Briefing_Text_GlyphX();
     72 
     73 extern void GlyphX_Assign_Houses(void);	//ST - 8/8/2019 12:35PM
     74 extern bool UseGlyphXStartLocations;		//ST - 3/31/2020 9:54AM
     75 
     76 //#include "WolDebug.h"
     77 
     78 #ifdef FIXIT_VERSION_3		//	Stalemate games.
     79 #include "WolStrng.h"
     80 #endif
     81 
     82 static void Remove_AI_Players(void);
     83 static void Create_Units(bool official);
     84 static CELL Clip_Scatter(CELL cell, int maxdist);
     85 static CELL Clip_Move(CELL cell, FacingType facing, int dist);
     86 
     87 // Made this non-static so we can access it from the updated assign players function. ST - 8/9/2019 10:35AM
     88 int _build_tech[11] = {
     89 	2,2,			// Tech level 0 and 1 are the same (tech 0 is never used).
     90 	4,
     91 	5,
     92 	7,
     93 	8,
     94 	9,
     95 	10,
     96 	11,
     97 	12,
     98 	13
     99 };
    100 
    101 
    102 #ifdef FRENCH
    103 #define TXT_HACKHACK  "Accomplie"
    104 #endif
    105 #if defined(ENGLISH) || defined(GERMAN)
    106 #define TXT_HACKHACK  Text_String(TXT_ACCOMPLISHED)
    107 #endif
    108 
    109 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
    110 bool Is_Mission_Counterstrike (char *file_name);
    111 bool Is_Mission_Aftermath (char *file_name);
    112 #endif
    113 
    114 /***********************************************************************************************
    115  * ScenarioClass::ScenarioClass -- Constructor for the scenario control object.                *
    116  *                                                                                             *
    117  *    This constructs the default scenario control object. Normally, all the default values    *
    118  *    are meaningless since the act of starting a scenario will fill in all of the values with *
    119  *    settings retrieved from the scenario control file.                                       *
    120  *                                                                                             *
    121  * INPUT:   none                                                                               *
    122  *                                                                                             *
    123  * OUTPUT:  none                                                                               *
    124  *                                                                                             *
    125  * WARNINGS:   none                                                                            *
    126  *                                                                                             *
    127  * HISTORY:                                                                                    *
    128  *   07/03/1996 JLB : Created.                                                                 *
    129  *=============================================================================================*/
    130 ScenarioClass::ScenarioClass(void) :
    131 	Difficulty(DIFF_NORMAL),
    132 	CDifficulty(DIFF_NORMAL),
    133 	Timer(0),
    134 	MissionTimer(0),
    135 	ShroudTimer(TICKS_PER_MINUTE * Rule.ShroudRate),
    136 	Scenario(1),
    137 	Theater(THEATER_TEMPERATE),
    138 	IntroMovie(VQ_NONE),
    139 	BriefMovie(VQ_NONE),
    140 	WinMovie(VQ_NONE),
    141 	WinMovie2(VQ_NONE),
    142 	WinMovie3(VQ_NONE),
    143 	WinMovie4(VQ_NONE),
    144 	LoseMovie(VQ_NONE),
    145 	ActionMovie(VQ_NONE),
    146 	TransitTheme(THEME_NONE),
    147 	PlayerHouse(HOUSE_GREECE),
    148 	CarryOverPercent(0),
    149 	CarryOverMoney(0),
    150 	CarryOverCap(0),
    151 	Percent(0),
    152 	BridgeCount(0),
    153 	CarryOverTimer(0),
    154 	IsBridgeChanged(false),
    155 	IsGlobalChanged(false),
    156 	IsToCarryOver(false),
    157 	IsToInherit(false),
    158 	IsTanyaEvac(false),
    159 	IsFadingBW(false),
    160 	IsFadingColor(false),
    161 	IsEndOfGame(false),
    162 	IsInheritTimer(false),
    163 	IsNoSpyPlane(false),
    164 	IsSkipScore(false),
    165 	IsOneTimeOnly(false),
    166 	IsNoMapSel(false),
    167 	IsTruckCrate(false),
    168 	IsMoneyTiberium(false),
    169 #ifdef FIXIT_VERSION_3			//	For endgame auto-sonar pulse.
    170 #define AUTOSONAR_PERIOD	TICKS_PER_SECOND * 40
    171 	AutoSonarTimer( AUTOSONAR_PERIOD ),
    172 #endif
    173 	FadeTimer(0)
    174 {
    175 	for (int index = 0; index < ARRAY_SIZE(Waypoint); index++) {
    176 		Waypoint[index] = -1;
    177 	}
    178 	strcpy(Description, "");
    179 	strcpy(ScenarioName, "");
    180 	strcpy(BriefingText, "");
    181 	memset(GlobalFlags, '\0', sizeof(GlobalFlags));
    182 	memset(Views, '\0', sizeof(Views));
    183 }
    184 
    185 
    186 /***********************************************************************************************
    187  * ScenarioClass::Do_BW_Fade -- Cause the palette to temporarily shift to B/W.                 *
    188  *                                                                                             *
    189  *    This routine will start the palette to fade to B/W for a brief moment.                   *
    190  *                                                                                             *
    191  * INPUT:   none                                                                               *
    192  *                                                                                             *
    193  * OUTPUT:  none                                                                               *
    194  *                                                                                             *
    195  * WARNINGS:   none                                                                            *
    196  *                                                                                             *
    197  * HISTORY:                                                                                    *
    198  *   10/21/1996 JLB : Created.                                                                 *
    199  *=============================================================================================*/
    200 void ScenarioClass::Do_BW_Fade(void)
    201 {
    202 	IsFadingBW = true;
    203 	IsFadingColor = false;
    204 	FadeTimer = GRAYFADETIME;
    205 }
    206 
    207 
    208 /***********************************************************************************************
    209  * ScenarioClass::Do_Fade_AI -- Process the palette fading effect.                             *
    210  *                                                                                             *
    211  *    This routine will handle the maintenance of the palette fading effect. It should be      *
    212  *    called once per game frame.                                                              *
    213  *                                                                                             *
    214  * INPUT:   none                                                                               *
    215  *                                                                                             *
    216  * OUTPUT:  none                                                                               *
    217  *                                                                                             *
    218  * WARNINGS:   none                                                                            *
    219  *                                                                                             *
    220  * HISTORY:                                                                                    *
    221  *   10/21/1996 JLB : Created.                                                                 *
    222  *=============================================================================================*/
    223 void ScenarioClass::Do_Fade_AI(void)
    224 {
    225 	if (IsFadingColor) {
    226 		if (FadeTimer == 0) {
    227 			IsFadingColor = false;
    228 		}
    229 		fixed newsat = Options.Get_Saturation() * fixed(GRAYFADETIME-FadeTimer, GRAYFADETIME);
    230 		Options.Adjust_Palette(OriginalPalette, GamePalette, Options.Get_Brightness(), newsat, Options.Get_Tint(), Options.Get_Contrast());
    231 		GamePalette.Set();
    232 	}
    233 	if (IsFadingBW) {
    234 		if (FadeTimer == 0) {
    235 			IsFadingBW = false;
    236 		}
    237 		fixed newsat = Options.Get_Saturation() * fixed(FadeTimer, GRAYFADETIME);
    238 		Options.Adjust_Palette(OriginalPalette, GamePalette, Options.Get_Brightness(), newsat, Options.Get_Tint(), Options.Get_Contrast());
    239 		GamePalette.Set();
    240 		if (!IsFadingBW) {
    241 			IsFadingColor = true;
    242 			FadeTimer = GRAYFADETIME;
    243 		}
    244 	}
    245 }
    246 
    247 
    248 /***********************************************************************************************
    249  * ScenarioClass::Set_Global_To -- Set scenario global to value specified.                     *
    250  *                                                                                             *
    251  *    This routine will set the global flag to the falue (true/false) specified. It will       *
    252  *    also scan for and spring any triggers that are dependant upon that global.               *
    253  *                                                                                             *
    254  * INPUT:   global   -- The global flag to change.                                             *
    255  *                                                                                             *
    256  *          value    -- The value to change the global flag to.                                *
    257  *                                                                                             *
    258  * OUTPUT:  Returns with the previous value of the flag.                                       *
    259  *                                                                                             *
    260  * WARNINGS:   none                                                                            *
    261  *                                                                                             *
    262  * HISTORY:                                                                                    *
    263  *   07/26/1996 JLB : Created.                                                                 *
    264  *=============================================================================================*/
    265 bool ScenarioClass::Set_Global_To(int global, bool value)
    266 {
    267 	if ((unsigned)global < ARRAY_SIZE(Scen.GlobalFlags)) {
    268 
    269 		bool previous = GlobalFlags[global];
    270 		if (previous != value) {
    271 			GlobalFlags[global] = value;
    272 			IsGlobalChanged = true;
    273 
    274 			/*
    275 			**	Special case to scan through all triggers and if any are found that depend on this
    276 			**	global being set/cleared, then if there is an elapsed time event associated, it
    277 			**	will be reset at this time.
    278 			*/
    279 			for (int index = 0; index < Triggers.Count(); index++) {
    280 				TriggerClass * tp = Triggers.Ptr(index);
    281 				if ((tp->Class->Event1.Event == TEVENT_GLOBAL_SET || tp->Class->Event1.Event == TEVENT_GLOBAL_CLEAR) && tp->Class->Event1.Data.Value == global) {
    282 					tp->Class->Event2.Reset(tp->Event1);
    283 				}
    284 				if ((tp->Class->Event2.Event == TEVENT_GLOBAL_SET || tp->Class->Event2.Event == TEVENT_GLOBAL_CLEAR) && tp->Class->Event2.Data.Value == global) {
    285 					tp->Class->Event1.Reset(tp->Event1);
    286 				}
    287 			}
    288 		}
    289 		return(previous);
    290 	}
    291 	return(false);
    292 }
    293 
    294 
    295 /***********************************************************************************************
    296  * Start_Scenario -- Starts the scenario.                                                      *
    297  *                                                                                             *
    298  *    This routine will start the scenario. In addition to loading the scenario data, it will  *
    299  *    play the briefing and action movies.                                                     *
    300  *                                                                                             *
    301  * INPUT:   root     -- Pointer to the filename root for this scenario (e.g., "SCG01EA").      *
    302  *                                                                                             *
    303  *          briefing -- Should the briefing be played? Normally this is true except when the   *
    304  *                      scenario is restarting.                                                *
    305  *                                                                                             *
    306  * OUTPUT:  Was the scenario started without error?                                            *
    307  *                                                                                             *
    308  * WARNINGS:   none                                                                            *
    309  *                                                                                             *
    310  * HISTORY:                                                                                    *
    311  *   07/04/1995 JLB : Created.                                                                 *
    312  *=============================================================================================*/
    313 bool Start_Scenario(char * name, bool briefing)
    314 {
    315 //BG	Theme.Queue_Song(THEME_QUIET);
    316 Theme.Stop();
    317 	IsTanyaDead = SaveTanya;
    318 	if (!Read_Scenario(name)) {
    319 		return(false);
    320 	}
    321 
    322 	/* Swap Lt. Blue and Blue color remaps in skirmish/multiplayer */
    323 	if (Session.Type != GAME_NORMAL) {
    324 		RemapControlType temp;
    325 		memcpy(&temp, &ColorRemaps[PCOLOR_LTBLUE], sizeof(RemapControlType));
    326 		memcpy(&ColorRemaps[PCOLOR_LTBLUE], &ColorRemaps[PCOLOR_BLUE], sizeof(RemapControlType));
    327 		memcpy(&ColorRemaps[PCOLOR_BLUE], &temp, sizeof(RemapControlType));
    328 	}
    329 
    330 	/*
    331 	**	Play the winning movie and then start the next scenario.
    332 	*/
    333 	RequiredCD = -1;
    334 //	if (RequiredCD != -2 && Session.Type == GAME_NORMAL) {
    335 //		if (Scen.Scenario == 1)
    336 //			RequiredCD = -1;
    337 //		else {
    338 //			 if((Scen.Scenario >= 20 && Scen.ScenarioName[2] == 'G' || Scen.ScenarioName[2] == 'U') || Scen.ScenarioName[2] == 'A'
    339 //				|| (Scen.ScenarioName[2] == 'M' && Scen.Scenario >= 25))
    340 //		       	    RequiredCD = 2;
    341 //			 else if(Scen.ScenarioName[2] == 'U')
    342 //			    RequiredCD = 1;
    343 //			 else if(Scen.ScenarioName[2] == 'G')
    344 //			    RequiredCD = 0;
    345 //			}
    346 //
    347 //#ifdef FIXIT_FORCE_CD
    348 // Forces the CD to be inserted according to the scenario being loaded.
    349 //Hide_Mouse();
    350 //VisiblePage.Clear();
    351 //Show_Mouse();
    352 //GamePalette.Set();
    353 //if (!Force_CD_Available(RequiredCD)) {
    354 //       	Prog_End();
    355 //       	exit(EXIT_FAILURE);
    356 //}
    357 //#endif
    358 
    359 
    360 
    361 //   	}
    362 	Theme.Stop();
    363 
    364 	if (briefing) {
    365 		Hide_Mouse();
    366 		VisiblePage.Clear();
    367 		Show_Mouse();
    368 		Play_Movie(Scen.IntroMovie);
    369 		Play_Movie(Scen.BriefMovie);
    370 	}
    371 
    372 	/*
    373 	** If there's no briefing movie, restate the mission at the beginning.
    374 	*/
    375 #if 1 // 12/04/2019 - LLL
    376 	if (Session.Type == GAME_NORMAL && Scen.BriefMovie == VQ_NONE) {
    377 		Display_Briefing_Text_GlyphX();
    378 	}
    379 #else
    380 	char buffer[25];
    381 	if (Scen.BriefMovie != VQ_NONE) {
    382 		sprintf(buffer, "%s.VQA", VQName[Scen.BriefMovie]);
    383 	}
    384 	if (Session.Type == GAME_NORMAL && Scen.BriefMovie == VQ_NONE || !CCFileClass(buffer).Is_Available()) {
    385 		/*
    386 		** Make sure the mouse is visible before showing the restatement.
    387 		*/
    388 		while(Get_Mouse_State()) {
    389 			Show_Mouse();
    390 		}
    391 		Restate_Mission(Scen.ScenarioName, TXT_OK, TXT_NONE);
    392 	}
    393 #endif
    394 
    395 	if (briefing) {
    396 		Hide_Mouse();
    397 		VisiblePage.Clear();
    398 		Show_Mouse();
    399 		Play_Movie(Scen.ActionMovie, Scen.TransitTheme);
    400 	}
    401 
    402 	if (Scen.TransitTheme == THEME_NONE) {
    403 		Theme.Queue_Song(THEME_FIRST);
    404 	}
    405 
    406 	/*
    407 	** Set the options values, since the palette has been initialized by Read_Scenario
    408 	*/
    409 	Options.Set();
    410 
    411 	return(true);
    412 }
    413 
    414 
    415 /***********************************************************************************************
    416  * Set_Scenario_Difficulty -- Sets the difficulty of the scenario.                             *
    417  *                                                                                             *
    418  *    Updates the player's difficulty in single-player mode.                                   *
    419  *                                                                                             *
    420  * INPUT:   difficulty     -- Scenario difficulty                                              *
    421  *                                                                                             *
    422  * OUTPUT:     none                                                                            *
    423  *                                                                                             *
    424  * WARNINGS:   Only works in single-player.                                                    *
    425  *             Must call Start_Scenario first to initialize the player.                        *
    426  *                                                                                             *
    427  * HISTORY:                                                                                    *
    428  *   10/02/2019 SKY : Created.                                                                 *
    429  *=============================================================================================*/
    430 void Set_Scenario_Difficulty(int difficulty)
    431 {
    432 	if (Session.Type == GAME_NORMAL) {
    433 		switch (difficulty) {
    434 			case 0:
    435 				PlayerPtr->Assign_Handicap(DIFF_EASY);
    436 				break;
    437 			case 1:
    438 				PlayerPtr->Assign_Handicap(DIFF_NORMAL);
    439 				break;
    440 			case 2:
    441 				PlayerPtr->Assign_Handicap(DIFF_HARD);
    442 				break;
    443 			default:
    444 				break;
    445 		}
    446 	}
    447 }
    448 
    449 
    450 /***********************************************************************************************
    451  * Read_Scenario -- Reads a scenario from disk.                                                *
    452  *                                                                                             *
    453  *    This will read a scenario from disk. Use this to begin a scenario.                       *
    454  *    It doesn't perform any rendering, it merely sets up the system                           *
    455  *    with the proper data. Setting of the right game state will start                         *
    456  *    the scenario running.                                                                    *
    457  *                                                                                             *
    458  * INPUT:   root     -- Scenario root filename                                                 *
    459  *                                                                                             *
    460  * OUTPUT:     none                                                                            *
    461  *                                                                                             *
    462  * WARNINGS:   You must clear out the system variables before calling                          *
    463  *             this function. Use the Clear_Scenario() function.                               *
    464  *               It is assumed that Scenario is set to the current scenario number.            *
    465  *                                                                                             *
    466  * HISTORY:                                                                                    *
    467  *   07/22/1991     : Created.                                                                 *
    468  *   02/03/1992 JLB : Uses house identification.                                               *
    469  *=============================================================================================*/
    470 bool Read_Scenario(char * name)
    471 {
    472 	BStart(BENCH_SCENARIO);
    473 	Clear_Scenario();
    474 	ScenarioInit++;
    475 	if (Read_Scenario_INI(name)) {
    476 #ifdef FIXIT_CSII	//	ajw - Added runtime check for Aftermath to skirmish mode case.
    477 		bool readini = false;
    478 		switch(Session.Type) {
    479 			case GAME_NORMAL:
    480 				readini = false;
    481 				break;
    482 			case GAME_SKIRMISH:
    483 #ifdef FIXIT_VERSION_3
    484 				readini = bAftermathMultiplayer;
    485 #endif
    486 				break;
    487 			case GAME_INTERNET:
    488 #ifndef FIXIT_VERSION_3			//	Loading of Aftermath rules depends on bAftermathMultiplayer now.
    489 				if (Is_Mission_Counterstrike(name)) {
    490 					readini = false;	// Don't allow AM units on a CS map in WChat
    491 					break;
    492 				}
    493 #endif		//	( Note lack of break; )
    494 			default:
    495 #ifdef FIXIT_VERSION_3
    496 				readini = bAftermathMultiplayer;
    497 #else
    498 				if (PlayingAgainstVersion >= VERSION_AFTERMATH_CS) {
    499 					readini = true;
    500 				}
    501 #endif
    502 				break;
    503 		}
    504 		if(readini) {
    505 			/*
    506 			** Find out if the CD in the current drive is the Aftermath disc.
    507 		  	*/
    508 #ifdef FIXIT_VERSION_3
    509 			int cd_index = Get_CD_Index(CCFileClass::Get_CD_Drive(), 1*60);
    510 			if( !( Using_DVD() && cd_index == 5 ) && cd_index != 3 ) {
    511 #else
    512 			if(Get_CD_Index(CCFileClass::Get_CD_Drive(), 1*60) != 3) {
    513 #endif
    514 				GamePalette.Set(FADE_PALETTE_FAST, Call_Back);
    515 				RequiredCD = 3;
    516 				if (!Force_CD_Available(RequiredCD)) {	// force Aftermath CD in drive.
    517 #ifndef WOLAPI_INTEGRATION
    518 					#ifdef WIN32
    519 					if(Special.IsFromWChat || SpawnedFromWChat) {
    520 						char packet[10] = {"Hello"};
    521 					Send_Data_To_DDE_Server (packet, strlen(packet), DDEServerClass::DDE_CONNECTION_FAILED);
    522 						}
    523 					#endif
    524 #endif
    525 					if (!RunningAsDLL) {	//PG
    526 						Emergency_Exit(EXIT_FAILURE);
    527 					}
    528 		     	}
    529 			}
    530 			CCINIClass ini;
    531 			if (ini.Load(CCFileClass("MPLAYER.INI"), false)) {
    532 				Rule.General(ini);
    533 				Rule.Recharge(ini);
    534 				Rule.AI(ini);
    535 				Rule.Powerups(ini);
    536 				Rule.Land_Types(ini);
    537 				Rule.Themes(ini);
    538 				Rule.IQ(ini);
    539 				Rule.Objects(ini);
    540 				Rule.Difficulty(ini);
    541 			}
    542 		}
    543 #endif
    544 		Fill_In_Data();
    545 		Map.Set_View_Dimensions(0, 0, Map.MapCellWidth, Map.MapCellHeight);
    546 	} else {
    547 		
    548 #if (1)
    549 		char message[200];
    550 		if (name) {
    551 			sprintf(message, "Failed to load scenario %s", name);
    552 			GlyphX_Debug_Print(message);
    553 		} else {
    554 			GlyphX_Debug_Print("Failed to load scenario");
    555 		}
    556 #else		
    557 		GamePalette.Set(FADE_PALETTE_FAST, Call_Back);
    558 //		Fade_Palette_To(GamePalette, FADE_PALETTE_FAST, Call_Back);
    559 		Show_Mouse();
    560 		WWMessageBox().Process(TXT_UNABLE_READ_SCENARIO);
    561 		Hide_Mouse();
    562 #endif
    563 		
    564 		BEnd(BENCH_SCENARIO);
    565 		return(false);
    566 	}
    567 	ScenarioInit--;
    568 	BEnd(BENCH_SCENARIO);
    569 	return(true);
    570 }
    571 
    572 
    573 /***********************************************************************************************
    574  * Fill_In_Data -- Recreate all data that is not loaded with scenario.                         *
    575  *                                                                                             *
    576  *    This routine is called after the INI file for the scenario has been processed. It will   *
    577  *    infer the game state from the scenario INI data.                                         *
    578  *                                                                                             *
    579  * INPUT:   none                                                                               *
    580  *                                                                                             *
    581  * OUTPUT:  none                                                                               *
    582  *                                                                                             *
    583  * WARNINGS:   none                                                                            *
    584  *                                                                                             *
    585  * HISTORY:                                                                                    *
    586  *   10/07/1992 JLB : Created.                                                                 *
    587  *=============================================================================================*/
    588 void Fill_In_Data(void)
    589 {
    590 	/*
    591 	**	The basic scenario data load does not contain the full set of
    592 	**	game data. We now must fill in the missing pieces.
    593 	*/
    594 	ScenarioInit++;
    595 	int index;
    596 	for (index = 0; index < Buildings.Count(); index++) {
    597 		Buildings.Ptr(index)->Update_Buildables();
    598 	}
    599 
    600 	Map.Flag_To_Redraw(true);
    601 
    602 	/*
    603 	**	Reset the movement zones according to the terrain passability.
    604 	*/
    605 	Map.Zone_Reset(MZONEF_ALL);
    606 
    607 
    608 #ifdef WIN32
    609 	/*
    610 	**	Since the sidebar starts up activated, adjust the home start position so that
    611 	**	the right edge of the map will still be visible.
    612 	*/
    613 	if (!Debug_Map) {
    614 		Map.SidebarClass::Activate(1);
    615 //		if (Session.Type == GAME_NORMAL) {
    616 			Scen.Views[0] = Scen.Views[1] = Scen.Views[2] = Scen.Views[3] = Scen.Waypoint[WAYPT_HOME];
    617 			Map.Set_Tactical_Position(Cell_Coord((Scen.Waypoint[WAYPT_HOME] - (MAP_CELL_W * 4 * RESFACTOR)) - (5*RESFACTOR)));
    618 //		}
    619 	}
    620 #endif
    621 
    622 	/*
    623 	**	Handle any data resetting that can be safely inferred from the actual
    624 	**	data that has been loaded.
    625 	*/
    626 	/*
    627 	**	Distribute the trigger pointers to the appropriate working lists.
    628 	*/
    629 	for (index = 0; index < TriggerTypes.Count(); index++) {
    630 		TriggerTypeClass * tp = TriggerTypes.Ptr(index);
    631 
    632 		assert(tp != NULL);
    633 
    634 		if (tp->Attaches_To() & ATTACH_MAP) {
    635 			MapTriggers.Add(Find_Or_Make(tp));
    636 		}
    637 		if (tp->Attaches_To() & ATTACH_GENERAL) {
    638 			LogicTriggers.Add(Find_Or_Make(tp));
    639 		}
    640 		if (tp->Attaches_To() & ATTACH_HOUSE) {
    641 			HouseTriggers[tp->House].Add(Find_Or_Make(tp));
    642 		}
    643 	}
    644 
    645 	ScenarioInit--;
    646 
    647 	/*
    648 	** Now go through and set all the cells ringing the map to be visible, so
    649 	** we won't get the wall of shadow at the edge of the map.
    650 	*/
    651 	int x,y;
    652 	for (x = Map.MapCellX-1; x < ((Map.MapCellX + Map.MapCellWidth + 1)); x++) {
    653 		Map[XY_Cell(x, Map.MapCellY-1)].IsVisible =
    654 			Map[XY_Cell(x, Map.MapCellY-1)].IsMapped = true;
    655 
    656 		Map[XY_Cell(x, Map.MapCellY+Map.MapCellHeight)].IsVisible =
    657 			Map[XY_Cell(x, Map.MapCellY+Map.MapCellHeight)].IsMapped = true;
    658 	}
    659 	for (y = Map.MapCellY; y < (Map.MapCellY + Map.MapCellHeight); y++) {
    660 		Map[XY_Cell(Map.MapCellX-1, y)].IsVisible =
    661 			Map[XY_Cell(Map.MapCellX-1, y)].IsMapped = true;
    662 		Map[XY_Cell(Map.MapCellX+Map.MapCellWidth, y)].IsVisible =
    663 			Map[XY_Cell(Map.MapCellX+Map.MapCellWidth, y)].IsMapped = true;
    664 	}
    665 
    666 	/*
    667 	**	If inheriting from a previous scenario was indicated, then create the carry over
    668 	**	objects at this time.
    669 	*/
    670 	if (Scen.IsToInherit) {
    671 		CarryoverClass * cptr = Carryover;
    672 		while (cptr != NULL) {
    673 			cptr->Create();
    674 			cptr = (CarryoverClass *)cptr->Get_Next();
    675 		}
    676 	}
    677 
    678 	/*
    679 	**	The "allow win" action is a special case that is handled here. The total number
    680 	**	of triggers that have this action must be recorded.
    681 	*/
    682 	for (index = 0; index < TriggerTypes.Count(); index++) {
    683 		TriggerTypeClass * tp = TriggerTypes.Ptr(index);
    684 		if (tp->Action1.Action == TACTION_ALLOWWIN ||
    685 			(tp->ActionControl != MULTI_ONLY && tp->Action2.Action == TACTION_ALLOWWIN)) {
    686 
    687 			HouseClass::As_Pointer(tp->House)->Blockage++;
    688 		}
    689 	}
    690 
    691 	/*
    692 	**	Move available money to silos, if the scenario flag so indicates.
    693 	*/
    694 	if (Scen.IsMoneyTiberium) {
    695 		for (HousesType house = HOUSE_FIRST; house < HOUSE_COUNT; house++) {
    696 			HouseClass * hptr = HouseClass::As_Pointer(house);
    697 			if (hptr != NULL) {
    698 				int tomove = hptr->Capacity - hptr->Tiberium;
    699 				hptr->Credits -= tomove;
    700 				hptr->Tiberium += tomove;
    701 			}
    702 		}
    703 	}
    704 
    705 	/*
    706 	**	Count all non-destroyed bridges on the map.
    707 	*/
    708 	Scen.BridgeCount = Map.Intact_Bridge_Count();
    709 
    710 	Map.All_To_Look(PlayerPtr, true);
    711 }
    712 
    713 
    714 /***********************************************************************************************
    715  * Post_Load_Game -- Fill in an inferred data from the game state.                             *
    716  *                                                                                             *
    717  *    This routine is typically called after a game has been loaded. Some working data lists   *
    718  *    can be rebuild from the game state. This working data is rebuilt rather than being       *
    719  *    stored with the game data file.                                                          *
    720  *                                                                                             *
    721  * INPUT:   load_multi -- true if we're loading a multiplayer game                             *
    722  *                                                                                             *
    723  * OUTPUT:  none                                                                               *
    724  *                                                                                             *
    725  * WARNINGS:   Although it is safe to call this routine whenever, it is only needed after a    *
    726  *             game load.                                                                      *
    727  *                                                                                             *
    728  * HISTORY:                                                                                    *
    729  *   11/30/1995 JLB : Created.                                                                 *
    730  *=============================================================================================*/
    731 void Post_Load_Game(int load_multi)
    732 {
    733 	Map.Set_View_Dimensions(0, 0, Map.MapCellWidth, Map.MapCellHeight);
    734 	//
    735 	// Do NOT call Overpass if we're loading a multiplayer game; it calls the
    736 	// random # generator, which throws the games out of sync if they were
    737 	// saved on different frame #'s.
    738 	//
    739 	if (!load_multi) {
    740 		Map.Overpass();
    741 	}
    742 	Scen.BridgeCount = Map.Intact_Bridge_Count();
    743 	Map.Zone_Reset(MZONEF_ALL);
    744 }
    745 
    746 
    747 /***********************************************************************************************
    748  * Clear_Scenario -- Clears all data in preparation for scenario load.                         *
    749  *                                                                                             *
    750  *    This routine will clear out all data specific to a scenario in                           *
    751  *    preparation for a subsequent scenario data load. This will free                          *
    752  *    all units, animations, and icon maps.                                                    *
    753  *                                                                                             *
    754  * INPUT:   none                                                                               *
    755  *                                                                                             *
    756  * OUTPUT:  none                                                                               *
    757  *                                                                                             *
    758  * WARNINGS:   none                                                                            *
    759  *                                                                                             *
    760  * HISTORY:                                                                                    *
    761  *   07/22/1991     : Created.                                                                 *
    762  *   03/21/1992 JLB : Changed buffer allocations, so changes memset code.                      *
    763  *   07/13/1995 JLB : End count down moved here.                                               *
    764  *=============================================================================================*/
    765 void Clear_Scenario(void)
    766 {
    767 // TCTCTC -- possibly just use in-place new of scenario object?
    768 
    769 	Scen.MissionTimer = 0;
    770 	Scen.MissionTimer.Stop();
    771 	Scen.Timer = 0;
    772 	Scen.ShroudTimer = 0;
    773 	Scen.IntroMovie = VQ_NONE;
    774 	Scen.BriefMovie = VQ_NONE;
    775 	Scen.WinMovie = VQ_NONE;
    776 	Scen.WinMovie2 = VQ_NONE;
    777 	Scen.WinMovie3 = VQ_NONE;
    778 	Scen.WinMovie4 = VQ_NONE;
    779 	Scen.LoseMovie = VQ_NONE;
    780 	Scen.ActionMovie = VQ_NONE;
    781 	Scen.IsNoSpyPlane = false;
    782 	Scen.IsTanyaEvac = false;
    783 	Scen.IsEndOfGame = false;
    784 	Scen.IsInheritTimer = false;
    785 	Scen.IsToCarryOver = false;
    786 	Scen.IsSkipScore = false;
    787 	Scen.IsOneTimeOnly = false;
    788 	Scen.IsTruckCrate = false;
    789 	Scen.IsMoneyTiberium = false;
    790 	Scen.IsNoMapSel = false;
    791 	Scen.CarryOverCap = 0;
    792 	Scen.CarryOverPercent = 0;
    793 	Scen.TransitTheme = THEME_NONE;
    794 	Scen.Percent = 0;
    795 
    796 	memset(Scen.GlobalFlags, 0, sizeof(Scen.GlobalFlags));
    797 
    798 	MapTriggers.Clear();
    799 	LogicTriggers.Clear();
    800 
    801 	for (HousesType house = HOUSE_FIRST; house < HOUSE_COUNT; house++) {
    802 		HouseTriggers[house].Clear();
    803 	}
    804 
    805 	/*
    806 	** Call everyone's Init routine, except the Map's; for the Map, only call
    807 	** MapClass::Init, which clears the Cell array.  The Display::Init requires
    808 	** a Theater argument, and the theater is not known at this point; also, it
    809 	** would reload MixFiles, which isn't desired.  Display::Read_INI calls its
    810 	** own Init, which will Init the entire Map hierarchy.
    811 	*/
    812 	Map.Init_Clear();
    813 	Score.Init();
    814 	Logic.Init();
    815 
    816 	HouseClass::Init();
    817 	ObjectClass::Init();
    818 	TeamTypeClass::Init();
    819 	TeamClass::Init();
    820 	TriggerClass::Init();
    821 	TriggerTypeClass::Init();
    822 	AircraftClass::Init();
    823 	AnimClass::Init();
    824 	BuildingClass::Init();
    825 	BulletClass::Init();
    826 	InfantryClass::Init();
    827 	OverlayClass::Init();
    828 	SmudgeClass::Init();
    829 	TemplateClass::Init();
    830 	TerrainClass::Init();
    831 	UnitClass::Init();
    832 	VesselClass::Init();
    833 
    834 	FactoryClass::Init();
    835 
    836 	Base.Init();
    837 
    838 	CurrentObject.Clear_All();
    839 
    840 	for (int index = 0; index < WAYPT_COUNT; index++) {
    841 		Scen.Waypoint[index] = -1;
    842 	}
    843 
    844 #ifdef FIXIT_VERSION_3			//	For endgame auto-sonar pulse.
    845 	bAutoSonarPulse = false;
    846 #endif
    847 
    848 #ifdef FIXIT_VERSION_3		//	Stalemate games.
    849 	Scen.bLocalProposesDraw = false;
    850 	Scen.bOtherProposesDraw = false;
    851 #endif
    852 
    853 }
    854 
    855 
    856 /***********************************************************************************************
    857  * Do_Win -- Display winning congratulations.                                                  *
    858  *                                                                                             *
    859  *    Perform the win the mission process. This will display any winning movies and the score  *
    860  *    screen. Followed by the map selection screen and then the load of the new scenario.      *
    861  *                                                                                             *
    862  * INPUT:   none                                                                               *
    863  *                                                                                             *
    864  * OUTPUT:  none                                                                               *
    865  *                                                                                             *
    866  * WARNINGS:   none                                                                            *
    867  *                                                                                             *
    868  * HISTORY:                                                                                    *
    869  *   08/05/1992 JLB : Created.                                                                 *
    870  *   01/01/1995 JLB : Carries money forward into next scenario.                                *
    871  *=============================================================================================*/
    872 void Do_Win(void)
    873 {
    874 	Map.Set_Default_Mouse(MOUSE_NORMAL);
    875 	Hide_Mouse();
    876 	Theme.Queue_Song(THEME_QUIET);
    877 
    878 	/*
    879 	** If this is a multiplayer game, clear the game's name so we won't respond
    880 	** to game queries any more (in Call_Back)
    881 	*/
    882 	if (Session.Type != GAME_NORMAL) {
    883 		Session.GameName[0] = 0;
    884 	}
    885 
    886 	/*
    887 	**	Determine a cosmetic center point for the text.
    888 	*/
    889 	int x = Map.TacPixelX + (Lepton_To_Pixel(Map.TacLeptonWidth)/2);
    890 
    891 	/*
    892 	** Hack section.  If it's allied scenario 10, variation A, then skip the
    893 	** score and map selection, don't increment scenario, and set it to
    894 	** variation B.
    895 	*/
    896 #ifdef FIXIT_ANTS
    897 	if (Session.Type != GAME_NORMAL || !Scen.IsSkipScore || AntsEnabled) {
    898 #else
    899 	if (Session.Type != GAME_NORMAL || !Scen.IsSkipScore ) {
    900 #endif	//FIXIT_ANTS
    901 
    902 		/*
    903 		**	Announce win to player.
    904 		*/
    905 		Set_Logic_Page(SeenBuff);
    906 		Map.Flag_To_Redraw (true);
    907 		Map.Render();
    908 #ifdef WIN32
    909 		Fancy_Text_Print(TXT_SCENARIO_WON, x, 90*RESFACTOR, &ColorRemaps[PCOLOR_RED], TBLACK, TPF_CENTER|TPF_VCR|TPF_USE_GRAD_PAL|TPF_DROPSHADOW);
    910 #else
    911 		Fancy_Text_Print(TXT_MISSION, x, 90*RESFACTOR, &ColorRemaps[PCOLOR_RED], TBLACK, TPF_CENTER|TPF_VCR|TPF_USE_GRAD_PAL|TPF_DROPSHADOW);
    912 		Fancy_Text_Print(TXT_HACKHACK, x, 110*RESFACTOR, &ColorRemaps[PCOLOR_RED], TBLACK, TPF_CENTER|TPF_VCR|TPF_USE_GRAD_PAL|TPF_DROPSHADOW);
    913 #endif
    914 		CountDownTimer = TIMER_SECOND * 3;
    915 		while (Is_Speaking()) {};
    916 		Speak(VOX_ACCOMPLISHED);
    917 		while (CountDownTimer || Is_Speaking()) {
    918 			Call_Back();
    919 		}
    920 	}
    921 
    922 	/*
    923 	** Stop here if this is a multiplayer game.
    924 	*/
    925 	if (Session.Type != GAME_NORMAL) {
    926 		if (!Session.Play) {
    927 			Session.GamesPlayed++;
    928 			Multi_Score_Presentation();
    929 			Session.CurGame++;
    930 			if (Session.CurGame >= MAX_MULTI_GAMES) {
    931 				Session.CurGame = MAX_MULTI_GAMES - 1;
    932 			}
    933 		}
    934 		GameActive = 0;
    935 		Show_Mouse();
    936 		return;
    937 	}
    938 
    939 	Hide_Mouse();
    940 	VisiblePage.Clear();
    941 	Show_Mouse();
    942 	Play_Movie(Scen.WinMovie);
    943 	Play_Movie(Scen.WinMovie2);
    944 	Play_Movie(Scen.WinMovie3);
    945 	Play_Movie(Scen.WinMovie4);
    946 
    947 	Keyboard->Clear();
    948 
    949 	SaveTanya = IsTanyaDead;
    950 	Scen.CarryOverTimer = Scen.MissionTimer;
    951 //	int timer = Scen.MissionTimer;
    952 
    953 	/*
    954 	**	Do the ending screens only if not playing back a recorded game.
    955 	*/
    956 	if (!Session.Play) {
    957 		/*
    958 		**	If the score presentation should be performed, then do
    959 		**	so now.
    960 		*/
    961 		Keyboard->Clear();
    962 		if (!Scen.IsSkipScore) {
    963 			Score.Presentation();
    964 		}
    965 
    966 
    967 		if (Scen.IsOneTimeOnly) {
    968 			GameActive = false;
    969 			Show_Mouse();
    970 #ifdef FIXIT_ANTS
    971 			AntsEnabled = false;
    972 //			Mono_Printf("Scenario.cpp one time only antsenabled is false\n");
    973 #endif
    974 			return;
    975 		}
    976 
    977 		/*
    978 		** If this scenario is flagged as ending the game then print the credits and exit.
    979 		*/
    980 #if (0)//PG
    981 		if (Scen.IsEndOfGame) {
    982 			if (PlayerPtr->ActLike == HOUSE_USSR) {
    983 				Play_Movie(VQ_SOVFINAL);
    984 			} else {
    985 				Play_Movie(VQ_ALLYEND);
    986 			}
    987 			Show_Who_Was_Responsible();
    988 			GameActive = false;
    989 			Show_Mouse();
    990 #ifdef FIXIT_ANTS
    991 			AntsEnabled = false;
    992 #endif
    993 			return;
    994 		}
    995 #endif
    996 		/*
    997 		** Hack section.  If it's allied scenario 10, variation A, then skip the
    998 		** score and map selection, don't increment scenario, and set it to
    999 		** variation B.
   1000 		*/
   1001 		if (Scen.IsNoMapSel) {
   1002 			// force it to play the second half of scenario 10
   1003 #ifdef FIXIT_ANTS
   1004 			if (AntsEnabled) {
   1005 				char scenarioname[24];
   1006 				strcpy(scenarioname, Scen.ScenarioName);
   1007 				char buf[10];
   1008 				Scen.Scenario++;
   1009 				sprintf(buf, "%02d", Scen.Scenario);
   1010 				memcpy(&scenarioname[3], buf, 2);
   1011 				Scen.Set_Scenario_Name(scenarioname);
   1012 			} else {
   1013 				Scen.ScenarioName[6] = 'B';
   1014 			}
   1015 
   1016 #else
   1017 			Scen.ScenarioName[6] = 'B';
   1018 #endif
   1019 
   1020 		} else {
   1021 			Scen.Set_Scenario_Name(Map_Selection());
   1022 		}
   1023 
   1024 		Keyboard->Clear();
   1025 	}
   1026 
   1027 	Scen.CarryOverMoney = PlayerPtr->Credits;
   1028 
   1029 	/*
   1030 	**	If requested, record the scenario's objects in the carry over list
   1031 	**	for possible use in a future scenario.
   1032 	*/
   1033 	if (Scen.IsToCarryOver) {
   1034 
   1035 		/*
   1036 		**	First delete any existing carry over list. Any old list will be
   1037 		**	blasted over by the new list -- there is only one logic carryover
   1038 		**	list to be maintained.
   1039 		*/
   1040 		while (Carryover) {
   1041 			CarryoverClass * cptr = (CarryoverClass *)Carryover->Get_Next();
   1042 			Carryover->Remove();
   1043 			delete Carryover;
   1044 			Carryover = cptr;
   1045 		}
   1046 
   1047 		/*
   1048 		**	Record all objects, that are to be part of the carry over set, into
   1049 		**	the carry over list.
   1050 		*/
   1051 		for (int building_index = 0; building_index < Buildings.Count(); building_index++) {
   1052 			BuildingClass * building = Buildings.Ptr(building_index);
   1053 
   1054 			if (building && !building->IsInLimbo && building->Strength > 0) {
   1055 				CarryoverClass * cptr = new CarryoverClass(building);
   1056 
   1057 				if (cptr) {
   1058 					if (Carryover) {
   1059 						cptr->Add_Tail(*Carryover);
   1060 					} else {
   1061 						Carryover = cptr;
   1062 					}
   1063 				}
   1064 			}
   1065 		}
   1066 		for (int unit_index = 0; unit_index < Units.Count(); unit_index++) {
   1067 			UnitClass * unit = Units.Ptr(unit_index);
   1068 
   1069 			if (unit && !unit->IsInLimbo && unit->Strength > 0) {
   1070 				CarryoverClass * cptr = new CarryoverClass(unit);
   1071 
   1072 				if (cptr) {
   1073 					if (Carryover) {
   1074 						cptr->Add_Tail(*Carryover);
   1075 					} else {
   1076 						Carryover = cptr;
   1077 					}
   1078 				}
   1079 			}
   1080 		}
   1081 		for (int infantry_index = 0; infantry_index < Infantry.Count(); infantry_index++) {
   1082 			InfantryClass * infantry = Infantry.Ptr(infantry_index);
   1083 
   1084 			if (infantry && !infantry->IsInLimbo && infantry->Strength > 0) {
   1085 				CarryoverClass * cptr = new CarryoverClass(infantry);
   1086 
   1087 				if (cptr) {
   1088 					if (Carryover) {
   1089 						cptr->Add_Tail(*Carryover);
   1090 					} else {
   1091 						Carryover = cptr;
   1092 					}
   1093 				}
   1094 			}
   1095 		}
   1096 		for (int vessel_index = 0; vessel_index < Vessels.Count(); vessel_index++) {
   1097 			VesselClass * vessel = Vessels.Ptr(vessel_index);
   1098 
   1099 			if (vessel && !vessel->IsInLimbo && vessel->Strength > 0) {
   1100 				CarryoverClass * cptr = new CarryoverClass(vessel);
   1101 
   1102 				if (cptr) {
   1103 					if (Carryover) {
   1104 						cptr->Add_Tail(*Carryover);
   1105 					} else {
   1106 						Carryover = cptr;
   1107 					}
   1108 				}
   1109 			}
   1110 		}
   1111 	}
   1112 
   1113 	/*
   1114 	** Generate a new scenario filename
   1115 	*/
   1116 //	Scen.Set_Scenario_Name(Scen.Scenario, Scen.ScenPlayer, Scen.ScenDir, Scen.ScenVar);
   1117 	Start_Scenario(Scen.ScenarioName);
   1118 
   1119 	/*
   1120 	**	If the mission timer is to be inheriteded from the previous scenario then do it now.
   1121 	*/
   1122 	if (Scen.IsInheritTimer) {
   1123 		Scen.MissionTimer = Scen.CarryOverTimer;
   1124 		Scen.MissionTimer.Start();
   1125 	}
   1126 
   1127 //	PlayerPtr->NukePieces = nukes;
   1128 
   1129 	Map.Render();
   1130 	GamePalette.Set(FADE_PALETTE_FAST, Call_Back);
   1131 //	Fade_Palette_To(GamePalette, FADE_PALETTE_FAST, Call_Back);
   1132 	Show_Mouse();
   1133 }
   1134 
   1135 
   1136 /***********************************************************************************************
   1137  * Do_Lose -- Display losing comments.                                                         *
   1138  *                                                                                             *
   1139  *    Performs the lose mission processing. This will generally display a "would you like      *
   1140  *    to replay" dialog and then either reload the scenario or set flags such that the main    *
   1141  *    menu will appear.                                                                        *
   1142  *                                                                                             *
   1143  * INPUT:   none                                                                               *
   1144  *                                                                                             *
   1145  * OUTPUT:  none                                                                               *
   1146  *                                                                                             *
   1147  * WARNINGS:   none                                                                            *
   1148  *                                                                                             *
   1149  * HISTORY:                                                                                    *
   1150  *   08/05/1992 JLB : Created.                                                                 *
   1151  *=============================================================================================*/
   1152 void Do_Lose(void)
   1153 {
   1154 	Map.Set_Default_Mouse(MOUSE_NORMAL);
   1155 	Hide_Mouse();
   1156 
   1157 	Theme.Queue_Song(THEME_QUIET);
   1158 
   1159 	/*
   1160 	** If this is a multiplayer game, clear the game's name so we won't respond
   1161 	** to game queries any more (in Call_Back)
   1162 	*/
   1163 	if (Session.Type != GAME_NORMAL) {
   1164 		Session.GameName[0] = 0;
   1165 	}
   1166 
   1167 	/*
   1168 	**	Determine a cosmetic center point for the text.
   1169 	*/
   1170 	int x = Map.TacPixelX + (Lepton_To_Pixel(Map.TacLeptonWidth)/2);
   1171 
   1172 	/*
   1173 	**	Announce win to player.
   1174 	*/
   1175 	Set_Logic_Page(SeenBuff);
   1176 	Fancy_Text_Print(TXT_SCENARIO_LOST, x, 90*RESFACTOR, &ColorRemaps[PCOLOR_RED], TBLACK, TPF_CENTER|TPF_VCR|TPF_USE_GRAD_PAL|TPF_DROPSHADOW);
   1177 	CountDownTimer = TIMER_SECOND * 3;
   1178 	while (Is_Speaking()) {};
   1179 	Speak(VOX_FAIL);
   1180 	while (CountDownTimer || Is_Speaking()) {
   1181 		Call_Back();
   1182 	}
   1183 
   1184 	/*
   1185 	** Stop here if this is a multiplayer game.
   1186 	*/
   1187 	if (Session.Type != GAME_NORMAL) {
   1188 		if (!Session.Play) {
   1189 			Session.GamesPlayed++;
   1190 			Multi_Score_Presentation();
   1191 			Session.CurGame++;
   1192 			if (Session.CurGame >= MAX_MULTI_GAMES) {
   1193 				Session.CurGame = MAX_MULTI_GAMES - 1;
   1194 			}
   1195 		}
   1196 		GameActive = 0;
   1197 		Show_Mouse();
   1198 		return;
   1199 	}
   1200 
   1201 	Hide_Mouse();
   1202 	VisiblePage.Clear();
   1203 	Show_Mouse();
   1204 #ifdef CHEAT_KEYS
   1205 //	Mono_Printf("Trying to play lose movie\n");
   1206 #endif //CHEAT_KEYS
   1207 	Play_Movie(Scen.LoseMovie);
   1208 
   1209 	/*
   1210 	** Start same scenario again
   1211 	*/
   1212 	GamePalette.Set();
   1213 	Show_Mouse();
   1214 	if (!Session.Play && !WWMessageBox().Process(TXT_TO_REPLAY, TXT_YES, TXT_NO)) {
   1215 		Hide_Mouse();
   1216 		Keyboard->Clear();
   1217 		Start_Scenario(Scen.ScenarioName, false);
   1218 
   1219 		/*
   1220 		**	Start the scenario timer with the carried over value if necessary.
   1221 		*/
   1222 		if (Scen.IsInheritTimer) {
   1223 			Scen.MissionTimer = Scen.CarryOverTimer;
   1224 			Scen.MissionTimer.Start();
   1225 		}
   1226 
   1227 		Map.Render();
   1228 	} else {
   1229 		Hide_Mouse();
   1230 		GameActive = 0;
   1231 	}
   1232 
   1233 	GamePalette.Set(FADE_PALETTE_FAST, Call_Back);
   1234 	Show_Mouse();
   1235 }
   1236 
   1237 #ifdef FIXIT_VERSION_3		//	Stalemate games.
   1238 /***********************************************************************************************
   1239  * Do_Draw -- Parallels Do_Win and Do_Lose, for multiplayer games that end in a draw.
   1240  *=============================================================================================*/
   1241 void Do_Draw(void)
   1242 {
   1243 	Map.Set_Default_Mouse(MOUSE_NORMAL);
   1244 	Hide_Mouse();
   1245 
   1246 	Theme.Queue_Song(THEME_QUIET);
   1247 
   1248 	/*
   1249 	** If this is a multiplayer game, clear the game's name so we won't respond
   1250 	** to game queries any more (in Call_Back)
   1251 	*/
   1252 	if (Session.Type != GAME_NORMAL) {
   1253 		Session.GameName[0] = 0;
   1254 	}
   1255 
   1256 	/*
   1257 	**	Determine a cosmetic center point for the text.
   1258 	*/
   1259 	int x = Map.TacPixelX + (Lepton_To_Pixel(Map.TacLeptonWidth)/2);
   1260 
   1261 	/*
   1262 	**	Announce win to player.
   1263 	*/
   1264 	Set_Logic_Page(SeenBuff);
   1265 	Fancy_Text_Print(TXT_WOL_DRAW, x, 90*RESFACTOR, &ColorRemaps[PCOLOR_RED], TBLACK, TPF_CENTER|TPF_VCR|TPF_USE_GRAD_PAL|TPF_DROPSHADOW);
   1266 	CountDownTimer = TIMER_SECOND * 3;
   1267 	while (Is_Speaking()) {};
   1268 	Speak(VOX_CONTROL_EXIT);
   1269 	while (CountDownTimer || Is_Speaking()) {
   1270 		Call_Back();
   1271 	}
   1272 
   1273 	/*
   1274 	** Stop here if this is a multiplayer game.
   1275 	*/
   1276 	if (!Session.Play) {
   1277 		Session.GamesPlayed++;
   1278 		Multi_Score_Presentation();
   1279 		Session.CurGame++;
   1280 		if (Session.CurGame >= MAX_MULTI_GAMES) {
   1281 			Session.CurGame = MAX_MULTI_GAMES - 1;
   1282 		}
   1283 	}
   1284 	GameActive = 0;
   1285 	Show_Mouse();
   1286 }
   1287 #endif
   1288 
   1289 /***********************************************************************************************
   1290  * Do_Restart -- Handle the restart mission process.                                           *
   1291  *                                                                                             *
   1292  *    This routine is called in the main game loop when the mission must be restarted. This    *
   1293  *    routine will throw away the current game and reload the appropriate mission. The         *
   1294  *    game will "resume" at the start of the mission.                                          *
   1295  *                                                                                             *
   1296  * INPUT:   none                                                                               *
   1297  *                                                                                             *
   1298  * OUTPUT:  none                                                                               *
   1299  *                                                                                             *
   1300  * WARNINGS:   none                                                                            *
   1301  *                                                                                             *
   1302  * HISTORY:                                                                                    *
   1303  *   08/24/1995 JLB : Created.                                                                 *
   1304  *=============================================================================================*/
   1305 void Do_Restart(void)
   1306 {
   1307 	/*
   1308 	** Start a timer going, before we restart the scenario
   1309 	*/
   1310 	CDTimerClass<SystemTimerClass> timer;
   1311 	timer = TICKS_PER_SECOND * 4;
   1312 	Theme.Queue_Song(THEME_QUIET);
   1313 
   1314 	WWMessageBox().Process(TXT_RESTARTING, TXT_NONE);
   1315 
   1316 	Map.Set_Default_Mouse(MOUSE_NORMAL);
   1317 	Keyboard->Clear();
   1318 	Start_Scenario(Scen.ScenarioName, false);
   1319 
   1320 	/*
   1321 	**	Start the scenario timer with the carried over value if necessary.
   1322 	*/
   1323 	if (Scen.IsInheritTimer) {
   1324 		Scen.MissionTimer = Scen.CarryOverTimer;
   1325 		Scen.MissionTimer.Start();
   1326 	}
   1327 
   1328 	/*
   1329 	** Make sure the message stays displayed for at least 1 second
   1330 	*/
   1331 	while (timer > 0) {
   1332 		Call_Back();
   1333 	}
   1334 	Keyboard->Clear();
   1335 
   1336 	Map.Render();
   1337 }
   1338 
   1339 
   1340 /***********************************************************************************************
   1341  * Restate_Mission -- Handles restating the mission objective.                                 *
   1342  *                                                                                             *
   1343  *    This routine will display the mission objective (as text). It will also give the         *
   1344  *    option to redisplay the mission briefing video.                                          *
   1345  *                                                                                             *
   1346  * INPUT:   name  -- The scenario name. This is the unique identifier for the scenario         *
   1347  *                   briefing text as it appears in the "MISSION.INI" file.                    *
   1348  *                                                                                             *
   1349  * OUTPUT:  Returns the response from the dialog. This will either be 1 if the video was       *
   1350  *          requested, or 0 if the return to game options button was selected.                 *
   1351  *                                                                                             *
   1352  * WARNINGS:   none                                                                            *
   1353  *                                                                                             *
   1354  * HISTORY:                                                                                    *
   1355  *   06/23/1995 JLB : Created.                                                                 *
   1356  *   08/06/1995 JLB : Uses preloaded briefing text.                                            *
   1357  *=============================================================================================*/
   1358 bool Restate_Mission(char const * name, int button1, int button2)
   1359 {
   1360 	if (name) {
   1361 
   1362 		bool brief = true;
   1363 		char buffer[25];
   1364 		if (Scen.BriefMovie != VQ_NONE) {
   1365 			sprintf(buffer, "%s.VQA", VQName[Scen.BriefMovie]);
   1366 		}
   1367 
   1368 		if (Scen.BriefMovie == VQ_NONE || !CCFileClass(buffer).Is_Available()) {
   1369 			button2 = TXT_OK;
   1370 			button1 = TXT_NONE;
   1371 			brief = false;
   1372 		}
   1373 
   1374 		/*
   1375 		**	If mission object text was found, then display it.
   1376 		*/
   1377 		if (strlen(Scen.BriefingText)) {
   1378 			strcpy(_ShapeBuffer, Scen.BriefingText);
   1379 			BlackPalette.Set(FADE_PALETTE_MEDIUM, Call_Back);
   1380 			if (BGMessageBox(_ShapeBuffer, button2, button1)) {
   1381 				return(true);
   1382 			}
   1383 			if (!brief) return(true);
   1384 			return(false);
   1385 		}
   1386 	}
   1387 	return(false);
   1388 }
   1389 
   1390 
   1391 #define	BUTTON_1		1
   1392 #define	BUTTON_2		2
   1393 #define	BUTTON_3		3
   1394 #define	BUTTON_FLAG	0x8000
   1395 int BGMessageBox(char const * msg, int btn1, int btn2)
   1396 {
   1397 #define BUFFSIZE 511
   1398 	char buffer[BUFFSIZE];
   1399 	int retval;
   1400 	bool process;								// loop while true
   1401 	KeyNumType input;							// user input
   1402 	int selection;
   1403 	bool pressed;
   1404 	int curbutton;
   1405 	TextButtonClass * buttons[3];
   1406 	BOOL display;									// display level
   1407 	int  realval[5];
   1408 	int  morebutton = 3;						// which button says "more": 2 or 3?
   1409 
   1410 	const char * b1txt = Text_String(btn1);
   1411 	const char * b2txt = Text_String(btn2);
   1412 #ifdef FRENCH
   1413 	const char * b3txt = "SUITE";
   1414 #else
   1415 #ifdef GERMAN
   1416 	const char * b3txt = "MEHR";
   1417 #else
   1418 	const char * b3txt = "MORE";
   1419 #endif
   1420 #endif
   1421 
   1422 	const void *briefsnd = MFCD::Retrieve("BRIEFING.AUD");
   1423 
   1424 	GadgetClass::Set_Color_Scheme(&ColorRemaps[PCOLOR_TYPE]);
   1425 
   1426 	/*
   1427 	** If the message won't be needing the 'more' button, get rid of it.
   1428 	*/
   1429 	if (strlen(msg) <= BUFFSIZE-1) {
   1430 		b3txt = "";
   1431 	}
   1432 
   1433 #ifdef WIN32
   1434 	GraphicBufferClass seen_buff_save(VisiblePage.Get_Width(), VisiblePage.Get_Height(), (void*)NULL);
   1435 #endif
   1436 
   1437 	/*
   1438 	** If there's no text for button one, zero it out.
   1439 	*/
   1440 	if (*b1txt == '\0') {
   1441 		b1txt = b2txt;
   1442 		b2txt = "";
   1443 		if(*b1txt == '\0') {
   1444 			b1txt=0;
   1445 		}
   1446 	}
   1447 
   1448 	/*
   1449 	** If there's no text for button two, zero it out.  However, if there
   1450 	** is text for button three, move its text (always "MORE") to button two,
   1451 	** and set the morebutton flag to point to button two.  Then, clear out
   1452 	** button 3.
   1453 	*/
   1454 	if (*b2txt == '\0') {
   1455 		b2txt = 0;
   1456 		if (*b3txt != '\0') {
   1457 			b2txt = b3txt;
   1458 			b3txt = "";
   1459 			morebutton = 1;
   1460 		}
   1461 	}
   1462 
   1463 	/*
   1464 	** If there's no text for button three, zero it out.
   1465 	*/
   1466 	if (*b3txt == '\0') b3txt = 0;
   1467 
   1468 	Fancy_Text_Print(TXT_NONE, 0, 0, &ColorRemaps[PCOLOR_TYPE], TBLACK, TPF_6PT_GRAD|TPF_USE_GRAD_PAL);
   1469 	/*
   1470 	**	Examine the optional button parameters. Fetch the width and starting
   1471 	**	characters for each.
   1472 	*/
   1473 	char b1char, b2char, b3char;	// 1st char of each string
   1474 	int bwidth, bheight;				// button width and height
   1475 	int numbuttons = 0;
   1476 	if (b1txt) {
   1477 		b1char = toupper(b1txt[0]);
   1478 
   1479 		/*
   1480 		**	Build the button list.
   1481 		*/
   1482 		bheight = FontHeight + FontYSpacing + 2;
   1483 		bwidth = max((String_Pixel_Width(b1txt) + 8), 80);
   1484 		if (b2txt) {
   1485 			numbuttons = 2;
   1486 			b2char = toupper(b2txt[0]);
   1487 			bwidth = max(((int)String_Pixel_Width( b2txt ) + 8), bwidth);
   1488 //			b1x = x + 10;								// left side
   1489 
   1490 			if (b3txt) {
   1491 				numbuttons = 3;
   1492 				b3char = toupper(b3txt[0]);
   1493 				bwidth = max(((int)String_Pixel_Width( b3txt ) + 8), bwidth);
   1494 			}
   1495 
   1496 		} else {
   1497 			numbuttons = 1;
   1498 //			b1x = x + ((width - bwidth) >> 1);		// centered
   1499 		}
   1500 	}
   1501 
   1502 	/*
   1503 	**	Determine the dimensions of the text to be used for the dialog box.
   1504 	**	These dimensions will control how the dialog box looks.
   1505 	*/
   1506 	buffer[BUFFSIZE-1] = 0;
   1507 	int buffend = BUFFSIZE-1;
   1508 	strncpy(buffer, msg, BUFFSIZE-1);
   1509 	/*
   1510 	** Scan through the string to see if it got clipped, and if so, we'll
   1511 	** trim it back to the last space so it'll clip on a word.
   1512 	*/
   1513 	if (strlen(buffer) != strlen(msg)) {
   1514 		while (buffer[buffend] != ' ') buffend--;
   1515 		buffer[buffend]=0;
   1516 	}
   1517 	Fancy_Text_Print(TXT_NONE, 0, 0, &ColorRemaps[PCOLOR_TYPE], TBLACK, TPF_6PT_GRAD|TPF_USE_GRAD_PAL);
   1518 	int width;
   1519 	int height;
   1520 	Format_Window_String(buffer, 300, width, height);
   1521 	height += (numbuttons == 0) ? 30 : 60;
   1522 
   1523 	int x = (SeenBuff.Get_Width() - width) / 2;
   1524 	int y = (SeenBuff.Get_Height() - height) / 2;
   1525 
   1526 	/*
   1527 	**	Other inits.
   1528 	*/
   1529 	Set_Logic_Page(SeenBuff);
   1530 
   1531 	/*
   1532 	**	Initialize the button structures. All are initialized, even though one (or none) may
   1533 	**	actually be added to the button list.
   1534 	*/
   1535 	TextButtonClass button1(BUTTON_1, b1txt, TPF_BUTTON,
   1536 		x + ((numbuttons == 1) ? ((width - bwidth) >> 1) : 10), y + height - (bheight + 5), bwidth);
   1537 
   1538 	TextButtonClass button2(BUTTON_2, b2txt, TPF_BUTTON,
   1539 		x + width - (bwidth + 10), y + height - (bheight + 5), bwidth);
   1540 
   1541 	TextButtonClass button3(BUTTON_3, b3txt, TPF_BUTTON,
   1542 		0, y + height - (bheight + 5));
   1543 	button3.X = x + ((width - button3.Width) >> 1);
   1544 
   1545 	TextButtonClass * buttonlist = 0;
   1546 	curbutton = 0;
   1547 
   1548 	/*
   1549 	**	Add and initialize the buttons to the button list.
   1550 	*/
   1551 	if (numbuttons) {
   1552 		buttonlist = &button1;
   1553 		buttons[0] = &button1;
   1554 		realval[0] = BUTTON_1;
   1555 		if (numbuttons > 2) {
   1556 			button3.Add(*buttonlist);
   1557 			buttons[1] = &button3;
   1558 			realval[1] = BUTTON_3;
   1559 			button2.Add(*buttonlist);
   1560 			buttons[2] = &button2;
   1561 			realval[2] = BUTTON_2;
   1562 			buttons[curbutton]->Turn_On();
   1563 		} else if (numbuttons == 2) {
   1564 			button2.Add(*buttonlist);
   1565 			buttons[1] = &button2;
   1566 			realval[1] = BUTTON_2;
   1567 			buttons[curbutton]->Turn_On();
   1568 		}
   1569 	}
   1570 
   1571 	/*
   1572 	**	Draw the dialog.
   1573 	*/
   1574 	Hide_Mouse();
   1575 
   1576 	PaletteClass temp;
   1577 #ifdef WIN32
   1578 	char *filename = "SOVPAPER.PCX";
   1579 	if (PlayerPtr->Class->House != HOUSE_USSR && PlayerPtr->Class->House != HOUSE_UKRAINE) {
   1580 		filename = "ALIPAPER.PCX";
   1581 	}
   1582 	Load_Title_Screen(filename, &HidPage, (unsigned char*)temp.Get_Data());
   1583 #else
   1584 	char *filename = "SOVPAPER.CPS";
   1585 	if (PlayerPtr->Class->House != HOUSE_USSR && PlayerPtr->Class->House != HOUSE_UKRAINE) {
   1586 		filename = "ALIPAPER.CPS";
   1587 	}
   1588 	Load_Uncompress(CCFileClass(filename), HidPage, HidPage, temp);
   1589 #endif
   1590 	HidPage.Blit(SeenPage);
   1591 
   1592 	#ifdef WIN32
   1593 	VisiblePage.Blit(seen_buff_save);
   1594 	#endif
   1595 
   1596 	static unsigned char _scorepal[]={0,1,12,13,4,5,6,7,8,9,10,255,252,253,14,248};
   1597 	Set_Font_Palette(_scorepal);
   1598 	temp.Set(FADE_PALETTE_MEDIUM, Call_Back);
   1599 
   1600 	/*
   1601 	**	Main Processing Loop.
   1602 	*/
   1603 
   1604 	int bufindex = 0;
   1605 
   1606 	Keyboard->Clear();
   1607 
   1608 	Set_Font_Palette(_scorepal);
   1609 	int xprint = x + 20;
   1610 	int yprint = y + 25;
   1611 	do {
   1612 		#ifdef WIN32
   1613 		/*
   1614 		** If we have just received input focus again after running in the background then
   1615 		** we need to redraw.
   1616 		*/
   1617 		if (AllSurfaces.SurfacesRestored) {
   1618 			AllSurfaces.SurfacesRestored = false;
   1619 			Hide_Mouse();
   1620 			seen_buff_save.Blit(VisiblePage);
   1621 			display = true;
   1622 			Show_Mouse();
   1623 		}
   1624 		#endif
   1625 		char bufprint[2];
   1626 		bufprint[1]=0;
   1627 		bufprint[0] = buffer[bufindex];
   1628 		if (bufprint[0] == '\r' || bufprint[0] == '@') {
   1629 			xprint = x + 20;
   1630 			yprint += FontHeight + FontYSpacing;
   1631 
   1632 		} else {
   1633 			if (bufprint[0] != 20) {
   1634 				SeenPage.Print(bufprint, xprint, yprint, TBLACK, TBLACK);
   1635 #ifdef WIN32
   1636 				seen_buff_save.Print(bufprint, xprint, yprint, TBLACK, TBLACK);
   1637 #endif
   1638 				xprint += Char_Pixel_Width(bufprint[0]);
   1639 			}
   1640 		}
   1641 		if (bufprint[0] == '\r' || bufprint[0] == '@') {
   1642 #ifdef WIN32
   1643 			Play_Sample(briefsnd, 255, Options.Normalize_Volume(135));
   1644 #else
   1645 			Play_Sample(briefsnd, 255, Options.Normalize_Volume(45));
   1646 #endif
   1647 			CDTimerClass<SystemTimerClass> cd;
   1648 			cd = 5;
   1649 			do {
   1650 				Call_Back();
   1651 			} while(!Keyboard->Check() && cd);
   1652 		}
   1653 	} while (buffer[++bufindex]);
   1654 
   1655 	Show_Mouse();
   1656 	Keyboard->Clear();
   1657 
   1658 	if (buttonlist) {
   1659 		process = true;
   1660 		pressed = false;
   1661 		while (process) {
   1662 			#ifdef WIN32
   1663 			/*
   1664 			** If we have just received input focus again after running in the background then
   1665 			** we need to redraw.
   1666 			*/
   1667 			if (AllSurfaces.SurfacesRestored) {
   1668 				AllSurfaces.SurfacesRestored = false;
   1669 				Hide_Mouse();
   1670 				seen_buff_save.Blit(VisiblePage);
   1671 				display = true;
   1672 				Show_Mouse();
   1673 			}
   1674 			#endif
   1675 
   1676 			if (display) {
   1677 				display = false;
   1678 
   1679 				Hide_Mouse();
   1680 
   1681 				/*
   1682 				**	Redraw the buttons.
   1683 				*/
   1684 				if (buttonlist) {
   1685 					buttonlist->Draw_All();
   1686 				}
   1687 				Show_Mouse();
   1688 			}
   1689 
   1690 			/*
   1691 			**	Invoke game callback.
   1692 			*/
   1693 			Call_Back();
   1694 
   1695 			/*
   1696 			**	Fetch and process input.
   1697 			*/
   1698 			input = buttonlist->Input();
   1699 			switch (input) {
   1700 				case (BUTTON_1|BUTTON_FLAG):
   1701 					selection = realval[0];
   1702 					pressed = true;
   1703 					break;
   1704 
   1705 				case (KN_ESC):
   1706 					if (numbuttons > 2) {
   1707 						selection = realval[1];
   1708 						pressed = true;
   1709 					} else {
   1710 						selection = realval[2];
   1711 						pressed = true;
   1712 					}
   1713 					break;
   1714 
   1715 				case (BUTTON_2|BUTTON_FLAG):
   1716 					selection = BUTTON_2;
   1717 					pressed = true;
   1718 					break;
   1719 
   1720 				case (BUTTON_3|BUTTON_FLAG):
   1721 					selection = realval[1];
   1722 					pressed = true;
   1723 					break;
   1724 
   1725 				case (KN_LEFT):
   1726 					if (numbuttons > 1) {
   1727 						buttons[curbutton]->Turn_Off();
   1728 						buttons[curbutton]->Flag_To_Redraw();
   1729 
   1730 						curbutton--;
   1731 						if (curbutton < 0) {
   1732 							curbutton = numbuttons - 1;
   1733 						}
   1734 
   1735 						buttons[curbutton]->Turn_On();
   1736 						buttons[curbutton]->Flag_To_Redraw();
   1737 					}
   1738 					break;
   1739 
   1740 				case (KN_RIGHT):
   1741 					if (numbuttons > 1) {
   1742 						buttons[curbutton]->Turn_Off();
   1743 						buttons[curbutton]->Flag_To_Redraw();
   1744 
   1745 						curbutton++;
   1746 						if (curbutton > (numbuttons - 1) ) {
   1747 							curbutton = 0;
   1748 						}
   1749 
   1750 						buttons[curbutton]->Turn_On();
   1751 						buttons[curbutton]->Flag_To_Redraw();
   1752 					}
   1753 					break;
   1754 
   1755 				case (KN_RETURN):
   1756 					selection = curbutton + BUTTON_1;
   1757 					pressed = true;
   1758 					break;
   1759 
   1760 				/*
   1761 				**	Check 'input' to see if it's the 1st char of button text
   1762 				*/
   1763 				default:
   1764 					if (b1char == toupper(Keyboard->To_ASCII((KeyNumType)(input & 0xFF)))) {
   1765 						selection = BUTTON_1;
   1766 						pressed = true;
   1767 					} else if (b2txt!=NULL &&
   1768 						b2char == toupper(Keyboard->To_ASCII((KeyNumType)(input & 0xFF)))) {
   1769 						selection = BUTTON_2;
   1770 						pressed = true;
   1771 					} else if (b3txt!=NULL &&
   1772 						b3char == toupper(Keyboard->To_ASCII((KeyNumType)(input & 0xFF)))) {
   1773 						selection = BUTTON_3;
   1774 						pressed = true;
   1775 					}
   1776 					break;
   1777 			}
   1778 
   1779 			if (pressed) {
   1780 				switch (selection) {
   1781 					case (BUTTON_1):
   1782 						retval = 1;
   1783 						process = false;
   1784 						break;
   1785 
   1786 					case (BUTTON_2):
   1787 						retval = 0;
   1788 						process = false;
   1789 						break;
   1790 
   1791 					case BUTTON_3:
   1792 						retval = 2;
   1793 						process = false;
   1794 						break;
   1795 				}
   1796 
   1797 				pressed = false;
   1798 			}
   1799 		}
   1800 
   1801 	} else {
   1802 
   1803 		Keyboard->Clear();
   1804 	}
   1805 
   1806 	if (retval == (morebutton-1) && strlen(msg) > BUFFSIZE-1) {
   1807 		retval = BGMessageBox(msg + buffend + 1, btn1, btn2);
   1808 	}
   1809 	/*
   1810 	** Restore the screen.
   1811 	*/
   1812 	Hide_Mouse();
   1813 	/*
   1814 	** Now set the palette, depending on if we're going to show the video or
   1815 	** go back to the main menu.
   1816 	*/
   1817 	switch (retval) {
   1818 		case 0:
   1819 //			BlackPalette.Set(FADE_PALETTE_MEDIUM, Call_Back);
   1820 //			SeenPage.Clear();
   1821 ////			CCPalette.Set();
   1822 //			break;
   1823 		case 1:
   1824 			BlackPalette.Set(FADE_PALETTE_MEDIUM, Call_Back);
   1825 			SeenPage.Clear();
   1826 			break;
   1827 		default:
   1828 			break;
   1829 	}
   1830 	Show_Mouse();
   1831 
   1832 	GadgetClass::Set_Color_Scheme(&ColorRemaps[PCOLOR_DIALOG_BLUE]);
   1833 
   1834 	return(retval);
   1835 }
   1836 
   1837 
   1838 /***********************************************************************************************
   1839  * Set_Scenario_Name -- Creates the INI scenario name string.                                  *
   1840  *                                                                                             *
   1841  *    This routine is used by the scenario loading and saving code. It generates the scenario  *
   1842  *    INI root file name for the specified scenario parameters.                                *
   1843  *                                                                                             *
   1844  * INPUT:                                                                                      *
   1845  *         buf         buffer to store filename in; must be long enough for root.ext           *
   1846  *       scenario      scenario number                                                         *
   1847  *       player      player type for this game (GDI, NOD, multi-player, ...)                   *
   1848  *       dir         directional parameter for this game (East/West)                           *
   1849  *       var         variation of this game (Lose, A/B/C/D, etc)                               *
   1850  *                                                                                             *
   1851  * OUTPUT:  none.                                                                              *
   1852  *                                                                                             *
   1853  * WARNINGS:   none.                                                                           *
   1854  *                                                                                             *
   1855  * HISTORY:                                                                                    *
   1856  *   05/28/1994 JLB : Created.                                                                 *
   1857  *   05/01/1995 BRR : 2-player scenarios use same names as multiplayer                         *
   1858  *=============================================================================================*/
   1859 void ScenarioClass::Set_Scenario_Name(int scenario, ScenarioPlayerType player, ScenarioDirType dir, ScenarioVarType var)
   1860 {
   1861 	Scenario = scenario;
   1862 //	ScenPlayer = player;
   1863 //	ScenDir = dir;
   1864 //	ScenVar = var;
   1865 
   1866 	char c_player;			// character representing player type
   1867 	char c_dir;				// character representing direction type
   1868 	char c_var;				// character representing variation type
   1869 	ScenarioVarType i;
   1870 	char fname[_MAX_FNAME+_MAX_EXT];
   1871 
   1872 	/*
   1873 	** Set the player-type value.
   1874 	*/
   1875 	switch (player) {
   1876 		case SCEN_PLAYER_SPAIN:
   1877 			c_player = HouseTypeClass::As_Reference(HOUSE_SPAIN).Prefix;
   1878 			break;
   1879 
   1880 		case SCEN_PLAYER_GREECE:
   1881 			c_player = HouseTypeClass::As_Reference(HOUSE_GREECE).Prefix;
   1882 			break;
   1883 
   1884 		case SCEN_PLAYER_USSR:
   1885 			c_player = HouseTypeClass::As_Reference(HOUSE_USSR).Prefix;
   1886 			break;
   1887 
   1888 		case SCEN_PLAYER_JP:
   1889 			c_player = HouseTypeClass::As_Reference(HOUSE_JP).Prefix;
   1890 			break;
   1891 
   1892 		/*
   1893 		**	Multi player scenario.
   1894 		*/
   1895 		default:
   1896 			c_player = HouseTypeClass::As_Reference(HOUSE_MULTI1).Prefix;
   1897 			break;
   1898 	}
   1899 
   1900 	/*
   1901 	** Set the directional character value.
   1902 	** If SCEN_DIR_NONE is specified, randomly pick a direction; otherwise, use 'E' or 'W'
   1903 	*/
   1904 	switch (dir) {
   1905 		case SCEN_DIR_EAST:
   1906 			c_dir = 'E';
   1907 			break;
   1908 
   1909 		case SCEN_DIR_WEST:
   1910 			c_dir = 'W';
   1911 			break;
   1912 
   1913 		default:
   1914 		case SCEN_DIR_NONE:
   1915 			c_dir = Percent_Chance(50) ? 'W' : 'E';
   1916 			break;
   1917 	}
   1918 
   1919 	/*
   1920 	** Set the variation value.
   1921 	*/
   1922 	if (var == SCEN_VAR_NONE) {
   1923 
   1924 		/*
   1925 		** Find which variations are available for this scenario
   1926 		*/
   1927 		for (i = SCEN_VAR_FIRST; i < SCEN_VAR_COUNT; i++) {
   1928 			sprintf(fname, "SC%c%02d%c%c.INI", c_player, scenario, c_dir, 'A' + i);
   1929 			if (!CCFileClass(fname).Is_Available()) {
   1930 				break;
   1931 			}
   1932 		}
   1933 
   1934 		if (i==SCEN_VAR_FIRST) {
   1935 			c_var = 'X';						// indicates an error
   1936 		} else {
   1937 			c_var = 'A' + Random_Pick(0, i-1);
   1938 //			ScenVar = (ScenarioVarType)i;
   1939 		}
   1940 	} else {
   1941 		switch (var) {
   1942 			case SCEN_VAR_A:
   1943 				c_var = 'A';
   1944 				break;
   1945 
   1946 			case SCEN_VAR_B:
   1947 				c_var = 'B';
   1948 				break;
   1949 
   1950 			case SCEN_VAR_C:
   1951 				c_var = 'C';
   1952 				break;
   1953 
   1954 			case SCEN_VAR_D:
   1955 				c_var = 'D';
   1956 				break;
   1957 
   1958 			default:
   1959 				c_var = 'L';
   1960 				break;
   1961 
   1962 		}
   1963 	}
   1964 
   1965 	/*
   1966 	** generate the filename
   1967 	*/
   1968 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   1969 //Mono_Printf("In set_scenario_name, scenario # = %d\n",scenario);Keyboard->Get();Keyboard->Get();
   1970 	if (scenario < 100) {
   1971 		sprintf(ScenarioName, "SC%c%02d%c%c.INI", c_player, scenario, c_dir, c_var);
   1972 	} else {
   1973 		char first = (scenario / 36) + 'A';
   1974 		char second = scenario % 36;
   1975 
   1976 		if (second < 10) {
   1977 			second += '0';
   1978 		} else {
   1979 			second = (second - 10) + 'A';
   1980 		}
   1981 
   1982 		sprintf(ScenarioName, "SC%c%c%c%c%c.INI", c_player, first, second, c_dir, c_var);
   1983 	}
   1984 #else
   1985 	sprintf(ScenarioName, "SC%c%02d%c%c.INI", c_player, scenario, c_dir, c_var);
   1986 #endif
   1987 }
   1988 
   1989 
   1990 void ScenarioClass::Set_Scenario_Name(char const * name)
   1991 {
   1992 	if (name != NULL) {
   1993 		strncpy(ScenarioName, name, sizeof(ScenarioName));
   1994 		ScenarioName[ARRAY_SIZE(ScenarioName)-1] = '\0';
   1995 
   1996 		char buf[3];
   1997 		memcpy(buf, &ScenarioName[3], 2);
   1998 		buf[2] = '\0';
   1999 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2000 		if (buf[0] > '9' || buf[1] > '9') {
   2001 			char first = buf[0];
   2002 			char second = buf[1];
   2003 			if (first <= '9') {
   2004 				first -= '0';
   2005 			} else {
   2006 				first -= 'A';
   2007 			}
   2008 
   2009 			if (second <= '9') {
   2010 				second -= '0';
   2011 			} else {
   2012 				second = (second - 'A') + 10;
   2013 			}
   2014 
   2015 			Scenario = (36 * first) + second;
   2016 		} else {
   2017 			Scenario = atoi(buf);
   2018 		}
   2019 #else
   2020 		Scenario = atoi(buf);
   2021 #endif
   2022 	}
   2023 }
   2024 
   2025 
   2026 
   2027 /***********************************************************************************************
   2028  * Read_Scenario_INI -- Read specified scenario INI file.                                      *
   2029  *                                                                                             *
   2030  *    Read in the scenario INI file. This routine only sets the game                           *
   2031  *    globals with that data that is explicitly defined in the INI file.                       *
   2032  *    The remaining necessary interpolated data is generated elsewhere.                        *
   2033  *                                                                                             *
   2034  * INPUT:                                                                                      *
   2035  *          root      root filename for scenario file to read                                  *
   2036  *                                                                                             *
   2037  *          fresh      true = should the current scenario be cleared?                          *
   2038  *                                                                                             *
   2039  * OUTPUT:  bool; Was the scenario read successful?                                            *
   2040  *                                                                                             *
   2041  * WARNINGS:   none                                                                            *
   2042  *                                                                                             *
   2043  * HISTORY:                                                                                    *
   2044  *   10/07/1992 JLB : Created.  V.Grippi added CS check 2/5/97                                                               *
   2045  *=============================================================================================*/
   2046 bool Read_Scenario_INI(char * fname, bool )
   2047 {
   2048 //	char fname[_MAX_FNAME+_MAX_EXT];			// full INI filename
   2049 
   2050 
   2051 	ScenarioInit++;
   2052 
   2053 	Clear_Scenario();
   2054 #ifdef OBSOLETE
   2055 	/*
   2056 	** If we are not dealing with scenario 1, or a multi player scenario
   2057 	** then make sure the correct disk is in the drive.
   2058 	*/
   2059 	if (RequiredCD != -2) {
   2060 		RequiredCD = -1;
   2061 	}
   2062 #endif
   2063 
   2064 	/*
   2065 	** Only force a CD check if this is a single player game or if its
   2066 	** a multiplayer game on an official scenario. If its non-official
   2067 	** (a user scenario) then we dont care which CD is in because the
   2068 	** scenario is stored locally on the hard drive. In this case, we
   2069 	** have already verified its existance. ST 3/1/97 4:52PM.
   2070 	*/
   2071 #ifdef FIXIT_VERSION_3		//	Avoid CD check if official scenario was downloaded.
   2072 	if( ( Session.Type == GAME_NORMAL || Session.ScenarioIsOfficial ) && _stricmp( Scen.ScenarioName, "download.tmp" ) ){
   2073 #else
   2074 	if (Session.Type == GAME_NORMAL || Session.ScenarioIsOfficial){
   2075 #endif
   2076 
   2077 		/*
   2078 		** If this is scenario 1 then it should be on all CDs unless its an ant scenario
   2079 		*/
   2080 		if (Scen.Scenario == 1 && Scen.ScenarioName[2] != 'A') {
   2081 	   	RequiredCD = -1;
   2082 		} else {
   2083 //			Mono_Printf("Read_SCen_INI scenario is: %s\n", Scen.ScenarioName);
   2084 			/*
   2085 			** If this is a multiplayer scenario we need to find out if its a counterstrike
   2086 			** scenario. If so then we need CD 2. The original multiplayer scenarios are on
   2087 			** all CDs.
   2088 			*/
   2089 			if (Session.Type != GAME_NORMAL) {
   2090 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2091 				RequiredCD = -1;	// default that any CD will do.
   2092 // If it's a counterstrike mission, require the counterstrike CD, unless the
   2093 // Aftermath CD is already in the drive, in which case, leave it there.
   2094 // Note, this works because this section only tests for multiplayer scenarios.
   2095 				if (Is_Mission_Counterstrike(Scen.ScenarioName)) {
   2096 					RequiredCD = 2;
   2097 					if( Is_Aftermath_Installed() || Get_CD_Index(CCFileClass::Get_CD_Drive(), 1*60) == 3 )
   2098 					{
   2099 						RequiredCD = 3;
   2100 					}
   2101 				}
   2102 				if(Is_Mission_Aftermath(Scen.ScenarioName)) {
   2103 					RequiredCD = 3;
   2104 				}
   2105 #else
   2106 				if (Scen.Scenario > 24) {
   2107 					RequiredCD = 2;
   2108 				} else {
   2109 					RequiredCD = -1;
   2110 				}
   2111 #endif
   2112 			} else {
   2113 
   2114 				/*
   2115 				** This is a solo game. If the scenario number is >= 20 or its an ant mission
   2116 				** then we need the counterstrike CD (2)
   2117 				*/
   2118      			if (Scen.Scenario >= 20 || Scen.ScenarioName[2] == 'A') {
   2119 					RequiredCD = 2;
   2120 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2121      				if (Scen.Scenario >= 36 && Scen.ScenarioName[2] != 'A') {
   2122 						RequiredCD = 3;
   2123 #ifdef BOGUSCD
   2124 	RequiredCD = -1;
   2125 #endif
   2126 					}
   2127 #endif
   2128 				} else {
   2129 
   2130 					/*
   2131 					** This is a solo mission from the original Red Alert. Choose the Soviet or
   2132 					** allied CD depending on the scenario name.
   2133 					*/
   2134 					if (Scen.ScenarioName[2] == 'U') {
   2135 						RequiredCD = 1;
   2136 					} else {
   2137 						if (Scen.ScenarioName[2] == 'G') {
   2138 //							Mono_Printf("We are setting REquiredCD to 0");
   2139 							RequiredCD = 0;
   2140 
   2141 						}
   2142 					}
   2143      			}
   2144 			}
   2145 		}
   2146 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2147 // If we're asking for a CD swap, check to see if we need to set the palette
   2148 // to avoid a black screen.  If this is a normal RA game, and the CD being
   2149 // requested is an RA CD, then don't set the palette, leave the map screen up.
   2150 
   2151 #ifdef FIXIT_VERSION_3
   2152 		int cd_index = Get_CD_Index(CCFileClass::Get_CD_Drive(), 1*60);
   2153 		if( !( Using_DVD() && cd_index == 5 ) && cd_index != RequiredCD ) {
   2154 #else
   2155 		if (Get_CD_Index(CCFileClass::Get_CD_Drive(), 1*60) != RequiredCD) {
   2156 #endif
   2157 			if ((RequiredCD == 0 || RequiredCD == 1) && Session.Type == GAME_NORMAL) {
   2158 				SeenPage.Clear();
   2159 			}
   2160 			GamePalette.Set(FADE_PALETTE_FAST, Call_Back);
   2161 		}
   2162 #endif
   2163 		if (!Force_CD_Available(RequiredCD)) {
   2164 			Prog_End("Read_Scenario_INI Force_CD_Available failed", true);
   2165 			if (!RunningAsDLL) {	//PG
   2166 				Emergency_Exit(EXIT_FAILURE);
   2167 			}
   2168      	}
   2169 	} else {
   2170 		/*
   2171 		** This is a user scenario so any old CD will do.
   2172 		*/
   2173 		RequiredCD = -1;
   2174 	}
   2175 
   2176 
   2177 	/*
   2178 	**	Create scenario filename and read the file.
   2179 	*/
   2180 //	sprintf(fname, "%s.INI", root);
   2181 	CCINIClass ini;
   2182 	CCFileClass file(fname);
   2183 //	file.Cache();
   2184 
   2185 	int result = ini.Load(file, true);
   2186 	if (result == 0) {
   2187 //		Mono_Printf("ini.Load failed");
   2188 		GlyphX_Debug_Print("Failed to load scenario file");
   2189 		GlyphX_Debug_Print(fname);
   2190 		return(false);
   2191 	}
   2192 
   2193 	GlyphX_Debug_Print("Loaded scenario file");
   2194 	GlyphX_Debug_Print(file);
   2195 
   2196 	/*
   2197 	** If the scenario digest is wrong then the return code will be a 2.
   2198 	*/
   2199 	if (result == 2) {
   2200 //		if (Session.Type == GAME_NORMAL || Session.ScenarioIsOfficial) {
   2201 			/*
   2202 			**	Make a special exception so that multiplayer maps from 1 through
   2203 			**	24 will not care if the message digest is in error. All other
   2204 			**	maps will abort the scenario load.
   2205 			*/
   2206 			if (Scen.ScenarioName[2] != 'M' || Scen.Scenario >= 25) {
   2207 #if (1)				
   2208 				GlyphX_Debug_Print("Scenario digest is wrong");
   2209 #else				
   2210 				GamePalette.Set();
   2211 				WWMessageBox().Process(TXT_SCENARIO_ERROR, TXT_OK);
   2212 #endif
   2213 #ifdef RELEASE_VERSION
   2214 				return(false);
   2215 #endif
   2216 			}
   2217 //		}
   2218 	}
   2219 
   2220 	/*
   2221 	**	Reset the rules values to their initial settings.
   2222 	*/
   2223 #ifdef FIXIT_NAME_OVERRIDE
   2224 	for (int index = 0; index < ARRAY_SIZE(NameOverride); index++) {
   2225 		if (NameOverride[index] != NULL) free((void*)NameOverride[index]);
   2226 		NameOverride[index] = NULL;
   2227 		NameIDOverride[index] = 0;
   2228 	}
   2229 	if (Session.Type == GAME_NORMAL)  {
   2230 		Special.IsShadowGrow = false;
   2231 	}
   2232 #endif
   2233 
   2234 #ifdef FIXIT_ANTS
   2235 	Session.Messages.Reset();
   2236 //	Session.Messages.Add_Message(NULL, 0, NULL, PCOLOR_GREEN, TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_FULLSHADOW, 1);
   2237 //	Session.Messages.Add_Message(NULL, 0, NULL, PCOLOR_GREEN, TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_FULLSHADOW, 1);
   2238 //	Session.Messages.Add_Message(NULL, 0, NULL, PCOLOR_GREEN, TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_FULLSHADOW, 1);
   2239 //	Session.Messages.Add_Message(NULL, 0, NULL, PCOLOR_GREEN, TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_FULLSHADOW, 1);
   2240 //	Session.Messages.Add_Message(NULL, 0, NULL, PCOLOR_GREEN, TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_FULLSHADOW, 1);
   2241 //	Session.Messages.Add_Message(NULL, 0, NULL, PCOLOR_GREEN, TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_FULLSHADOW, 1);
   2242 	WeaponTypeClass::As_Pointer(WEAPON_FLAMER)->Sound = VOC_NONE;
   2243 	InfantryTypeClass::As_Reference(INFANTRY_THIEF).IsDoubleOwned = false;
   2244 	InfantryTypeClass::As_Reference(INFANTRY_E4).IsDoubleOwned = false;
   2245 	InfantryTypeClass::As_Reference(INFANTRY_SPY).PrimaryWeapon = NULL;
   2246 	InfantryTypeClass::As_Reference(INFANTRY_SPY).SecondaryWeapon = NULL;
   2247 	InfantryTypeClass::As_Reference(INFANTRY_GENERAL).IsBomber = false;
   2248 	UnitTypeClass::As_Reference(UNIT_HARVESTER).IsExploding = false;
   2249 	UnitTypeClass::As_Reference(UNIT_ANT1).Level = -1;
   2250 	UnitTypeClass::As_Reference(UNIT_ANT2).Level = -1;
   2251 	UnitTypeClass::As_Reference(UNIT_ANT3).Level = -1;
   2252 	BuildingTypeClass::As_Reference(STRUCT_QUEEN).Level = -1;
   2253 	BuildingTypeClass::As_Reference(STRUCT_LARVA1).Level = -1;
   2254 	BuildingTypeClass::As_Reference(STRUCT_LARVA2).Level = -1;
   2255 #endif
   2256 
   2257 
   2258 	Rule.General(RuleINI);
   2259 	Rule.Recharge(RuleINI);
   2260 	Rule.AI(RuleINI);
   2261 	Rule.Powerups(RuleINI);
   2262 	Rule.Land_Types(RuleINI);
   2263 	Rule.Themes(RuleINI);
   2264 	Rule.IQ(RuleINI);
   2265 	Rule.Objects(RuleINI);
   2266 	Rule.Difficulty(RuleINI);
   2267 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98 - Except does this _change_ any rules, or just add to them? - Just adds.
   2268 	Rule.General(AftermathINI);
   2269 	Rule.Recharge(AftermathINI);
   2270 	Rule.AI(AftermathINI);
   2271 	Rule.Powerups(AftermathINI);
   2272 	Rule.Land_Types(AftermathINI);
   2273 	Rule.Themes(AftermathINI);
   2274 	Rule.IQ(AftermathINI);
   2275 	Rule.Objects(AftermathINI);
   2276 	Rule.Difficulty(AftermathINI);
   2277 #endif
   2278 
   2279 	/*
   2280 	**	For civilians, remove the graphics name override from the base rules (can still be overridden in scenario-specific INI).
   2281 	*/
   2282 	for (int iindex = 0; iindex < InfantryTypes.Count(); iindex++) {
   2283 		InfantryTypeClass* itype = InfantryTypes.Ptr(iindex);
   2284 		if (itype->IsCivilian) {
   2285 			itype->GraphicName[0] = '\0';
   2286 		}
   2287 	}
   2288 
   2289 	/*
   2290 	**	Override any rules values specified in this
   2291 	**	particular scenario file.
   2292 	*/
   2293 	Rule.General(ini);
   2294 	Rule.Recharge(ini);
   2295 	Rule.AI(ini);
   2296 	Rule.Powerups(ini);
   2297 	Rule.Land_Types(ini);
   2298 	Rule.Themes(ini);
   2299 	Rule.IQ(ini);
   2300 	Rule.Objects(ini);
   2301 	Rule.Difficulty(ini);
   2302 
   2303 	/*
   2304 	**	- Fix a legacy bug with England and France country bonuses.
   2305 	**	- Use ore growth and spread values from the special settings.
   2306 	*/
   2307 	if (Session.Type != GAME_NORMAL) {
   2308 		HouseTypeClass::As_Reference(HOUSE_ENGLAND).ArmorBias = fixed(9, 10);
   2309 		HouseTypeClass::As_Reference(HOUSE_FRANCE).ROFBias = fixed(9, 10);
   2310 
   2311 		Rule.IsTGrowth = Special.IsTGrowth;
   2312 		Rule.IsTSpread = Special.IsTSpread;
   2313 	}
   2314 
   2315 	/*
   2316 	** Init the Scenario CRC value
   2317 	*/
   2318 	ScenarioCRC = 0;
   2319 #ifdef TOFIX
   2320 	len = strlen(buffer);
   2321 	for (int i = 0; i < len; i++) {
   2322 		val = (unsigned char)buffer[i];
   2323 		Add_CRC(&ScenarioCRC, (unsigned long)val);
   2324 	}
   2325 #endif
   2326 
   2327 	/*
   2328 	**	Fetch the appropriate movie names from the INI file.
   2329 	*/
   2330 	const char * const BASIC = "Basic";
   2331 	ini.Get_String(BASIC, "Name", "<none>", Scen.Description, sizeof(Scen.Description));
   2332 	Scen.IntroMovie = ini.Get_VQType(BASIC, "Intro", Scen.IntroMovie);
   2333 	Scen.BriefMovie = ini.Get_VQType(BASIC, "Brief", Scen.BriefMovie);
   2334 	Scen.WinMovie = ini.Get_VQType(BASIC, "Win", Scen.WinMovie);
   2335 	Scen.WinMovie2 = ini.Get_VQType(BASIC, "Win2", Scen.WinMovie2);
   2336 	Scen.WinMovie3 = ini.Get_VQType(BASIC, "Win3", Scen.WinMovie3);
   2337 	Scen.WinMovie4 = ini.Get_VQType(BASIC, "Win4", Scen.WinMovie4);
   2338 	Scen.LoseMovie = ini.Get_VQType(BASIC, "Lose", Scen.LoseMovie);
   2339 	Scen.ActionMovie = ini.Get_VQType(BASIC, "Action", Scen.ActionMovie);
   2340 	Scen.IsToCarryOver = ini.Get_Bool(BASIC, "ToCarryOver", Scen.IsToCarryOver);
   2341 	Scen.IsToInherit = ini.Get_Bool(BASIC, "ToInherit", Scen.IsToInherit);
   2342 	Scen.IsInheritTimer = ini.Get_Bool(BASIC, "TimerInherit", Scen.IsInheritTimer);
   2343 	Scen.IsEndOfGame = ini.Get_Bool(BASIC, "EndOfGame", Scen.IsEndOfGame);
   2344 	Scen.IsTanyaEvac = ini.Get_Bool(BASIC, "CivEvac", Scen.IsTanyaEvac);
   2345 	Scen.TransitTheme = ini.Get_ThemeType(BASIC, "Theme", THEME_NONE);
   2346 	NewINIFormat = ini.Get_Int(BASIC, "NewINIFormat", 0);
   2347 	Scen.CarryOverPercent = ini.Get_Fixed(BASIC, "CarryOverMoney", Scen.CarryOverPercent);
   2348 	Scen.CarryOverPercent = Saturate(Scen.CarryOverPercent, 1);
   2349 	Scen.CarryOverCap = ini.Get_Int(BASIC, "CarryOverCap", Scen.CarryOverCap);
   2350 	Scen.IsNoSpyPlane = ini.Get_Bool(BASIC, "NoSpyPlane", Scen.IsNoSpyPlane);
   2351 	Scen.IsSkipScore = ini.Get_Bool(BASIC, "SkipScore", Scen.IsSkipScore);
   2352 	Scen.IsOneTimeOnly = ini.Get_Bool(BASIC, "OneTimeOnly", Scen.IsOneTimeOnly);
   2353 	Scen.IsNoMapSel = ini.Get_Bool(BASIC, "SkipMapSelect", Scen.IsNoMapSel);
   2354 	Scen.IsTruckCrate = ini.Get_Bool(BASIC, "TruckCrate", Scen.IsTruckCrate);
   2355 	Scen.IsMoneyTiberium = ini.Get_Bool(BASIC, "FillSilos", Scen.IsMoneyTiberium);
   2356 	Scen.Percent = ini.Get_Int(BASIC, "Percent", Scen.Percent);
   2357 
   2358 	/*
   2359 	**	Read in the specific information for each of the house types.  This creates
   2360 	**	the houses of different types.
   2361 	*/
   2362 	HouseClass::Read_INI(ini);
   2363 	Call_Back();
   2364 
   2365 	/*
   2366 	**	Read in the team-type data. The team types must be created before any
   2367 	**	triggers can be created.
   2368 	*/
   2369 	TeamTypeClass::Read_INI(ini);
   2370 	Call_Back();
   2371 
   2372 	/*
   2373 	**	Read in the trigger data. The triggers must be created before any other
   2374 	**	objects can be initialized.
   2375 	*/
   2376 	TriggerTypeClass::Read_INI(ini);
   2377 	Call_Back();
   2378 
   2379 
   2380 	/*
   2381 	**	Read in the map control values. This includes dimensions
   2382 	**	as well as theater information.
   2383 	*/
   2384 	Map.Read_INI(ini);
   2385 	Call_Back();
   2386 
   2387 	/*
   2388 	**	Assign PlayerPtr by reading the player's house from the INI;
   2389 	**	Must be done before any TechnoClass objects are created.
   2390 	*/
   2391 	if (Session.Type == GAME_NORMAL) {
   2392 		PlayerPtr = HouseClass::As_Pointer(ini.Get_HousesType(BASIC, "Player", HOUSE_GREECE));
   2393 		PlayerPtr->Assign_Handicap(Scen.Difficulty);
   2394 		int carryover;
   2395 		if (Scen.CarryOverCap != -1) {
   2396 			carryover = min(Scen.CarryOverMoney * Scen.CarryOverPercent, Scen.CarryOverCap);
   2397 		} else {
   2398 			carryover = Scen.CarryOverMoney * Scen.CarryOverPercent;
   2399 		}
   2400 		PlayerPtr->Credits += carryover;
   2401 		PlayerPtr->Control.InitialCredits += carryover;
   2402 	} else {
   2403 		//Call the new Assign_Houses function. ST - 8/8/2019 12:35PM
   2404 		//Assign_Houses();
   2405 		GlyphX_Assign_Houses();
   2406 	}
   2407 	PlayerPtr->IsHuman = true;
   2408 	PlayerPtr->IsPlayerControl = true;
   2409 
   2410 //	if (NewINIFormat < 2 || !ini.Is_Present("MapPack")) {
   2411 //		Map.Read_Binary(root, &ScenarioCRC);
   2412 //	}
   2413 
   2414 
   2415 	/*
   2416 	**	Read in and place the 3D terrain objects.
   2417 	*/
   2418 	TerrainClass::Read_INI(ini);
   2419 	Call_Back();
   2420 	/*
   2421 	**	Read in and place the units (all sides).
   2422 	*/
   2423 	UnitClass::Read_INI(ini);
   2424 	Call_Back();
   2425 
   2426 	AircraftClass::Read_INI(ini);
   2427 	Call_Back();
   2428 
   2429 	VesselClass::Read_INI(ini);
   2430 	Call_Back();
   2431 
   2432 	/*
   2433 	**	Read in and place the infantry units (all sides).
   2434 	*/
   2435 	InfantryClass::Read_INI(ini);
   2436 	Call_Back();
   2437 
   2438 
   2439 
   2440 	/*
   2441 	**	Read in and place all the buildings on the map.
   2442 	*/
   2443 	BuildingClass::Read_INI(ini);
   2444 	Call_Back();
   2445 
   2446 	/*
   2447 	**	Read in the AI's base information.
   2448 	*/
   2449 	Base.Read_INI(ini);
   2450 	Call_Back();
   2451 
   2452       	/*
   2453 	**	Read in any normal overlay objects.
   2454 	*/
   2455 	OverlayClass::Read_INI(ini);
   2456 	Call_Back();
   2457 
   2458 	/*
   2459 	**	Read in any smudge overlays.
   2460 	*/
   2461 	SmudgeClass::Read_INI(ini);
   2462 	Call_Back();
   2463 
   2464 	/*	Moved above ini.Get_TextBlock(...) so Xlat mission.ini could be loaded
   2465 	**	If the briefing text could not be found in the INI file, then search
   2466 	**	the mission.ini file.  VG 10/17/96
   2467 	*/
   2468 	INIClass mini;
   2469 	mini.Load(CCFileClass("MISSION.INI"));
   2470 	mini.Get_TextBlock(fname, Scen.BriefingText, sizeof(Scen.BriefingText));
   2471 
   2472 	/*
   2473 	**	Read in any briefing text.
   2474 	*/
   2475 	if (Scen.BriefingText[0] == '\0') {
   2476 		ini.Get_TextBlock("Briefing", Scen.BriefingText, sizeof(Scen.BriefingText));
   2477 	}
   2478 	/*
   2479 	**	Perform a final overpass of the map. This handles smoothing of certain
   2480 	**	types of terrain (tiberium).
   2481 	*/
   2482 	Map.Overpass();
   2483 	Call_Back();
   2484 
   2485 	/*
   2486 	**	Special cases:
   2487 	**		Gold Rush multiplayer map cell 9033 - LAND_ROCK
   2488 	**		The Lake District multiplayer map cell 8482 - LAND_ROCK
   2489 	**		Blue Lakes multiplayer map cell 11937 - LAND_RIVER
   2490 	**		USSR mission 13 - fixup trigger action
   2491 	**		Allied mission 5B - fail mission if spy re-boards the transport at mission start
   2492 	**		Allied mission 8A - Germany is allied with Greece and itself
   2493 	**		Allied mission 9A - fail mission if tech center is destroyed before being spied
   2494 	**		Aftermath: Brother in Arms - have transports move to separate waypoints
   2495 	**		Aftermath: Let's Make a Steal - Make the pillboxes un-capturable
   2496 	**		Counterstrike: Soviet Soldier Volkov and Chitzkoi / Deus Ex Machina - Sniper burst fix
   2497 	*/
   2498 	if (_stricmp(Scen.ScenarioName, "scmh8ea.ini") == 0) {
   2499 		Map[(CELL)9033].Override_Land_Type(LAND_ROCK);
   2500 	}
   2501 
   2502 	if (_stricmp(Scen.ScenarioName, "scm93ea.ini") == 0) {
   2503 		Map[(CELL)8482].Override_Land_Type(LAND_ROCK);
   2504 	}
   2505 
   2506 	if (_stricmp(Scen.ScenarioName, "scmh4ea.ini") == 0) {
   2507 		Map[(CELL)11937].Override_Land_Type(LAND_RIVER);
   2508 	}
   2509 
   2510 	if (_stricmp(Scen.ScenarioName, "scu13ea.ini") == 0) {
   2511 		TriggerTypeClass* trigger = TriggerTypes.Ptr(11);
   2512 		trigger->Action1.Trigger.Set_Raw(39);
   2513 	}
   2514 
   2515 	if (_stricmp(Scen.ScenarioName, "scg05eb.ini") == 0) {
   2516 		TeamTypeClass* spy1_team = TeamTypeClass::From_Name("spy1");
   2517 		assert(spy1_team != NULL);
   2518 		spy1_team->MissionList[spy1_team->MissionCount].Mission = TMISSION_SET_GLOBAL;
   2519 		spy1_team->MissionList[spy1_team->MissionCount].Data.Value = 16;
   2520 		spy1_team->MissionCount++;
   2521 
   2522 		TriggerTypeClass* los3_trigger = new TriggerTypeClass();
   2523 		los3_trigger->IsPersistant = TriggerTypeClass::VOLATILE;
   2524 		los3_trigger->House = HOUSE_GREECE;
   2525 		los3_trigger->EventControl = MULTI_AND;
   2526 		los3_trigger->ActionControl = MULTI_AND;
   2527 		los3_trigger->Event1.Event = TEVENT_GLOBAL_SET;
   2528 		los3_trigger->Event1.Data.Value = 16;
   2529 		los3_trigger->Event2.Event = TEVENT_ALL_DESTROYED;
   2530 		los3_trigger->Event2.Data.House = HOUSE_GREECE;
   2531 		los3_trigger->Action1.Action = TACTION_LOSE;
   2532 		los3_trigger->Action1.Data.Value = -255;
   2533 		los3_trigger->Action2.Action = TACTION_NONE;
   2534 		los3_trigger->Action2.Data.Value = -1;
   2535 
   2536 		TriggerTypeClass* frc1_trigger = TriggerTypeClass::From_Name("frc1");
   2537 		assert(frc1_trigger != NULL);
   2538 		frc1_trigger->Action1.Trigger = los3_trigger;
   2539 	}
   2540 
   2541 	if (_stricmp(Scen.ScenarioName, "scg08ea.ini") == 0) {
   2542 		for (int house = HOUSE_FIRST; house < HOUSE_COUNT; ++house) {
   2543 			HouseClass* ptr = Houses.Ptr(house);
   2544 			if (ptr != NULL && ptr->IsActive) {
   2545 				if (ptr->Class->House == HOUSE_GREECE || ptr->Class->House == HOUSE_GERMANY) {
   2546 					ptr->Make_Ally(HOUSE_GERMANY);
   2547 				}
   2548 			}
   2549 		}
   2550 	}
   2551 
   2552 	if (_stricmp(Scen.ScenarioName, "scg09ea.ini") == 0) {
   2553 		TriggerTypeClass* spyd_trigger = TriggerTypeClass::From_Name("Spyd");
   2554 		assert(spyd_trigger != NULL);
   2555 
   2556 		TriggerTypeClass* kos_trigger = new TriggerTypeClass();
   2557 		kos_trigger->IsPersistant = spyd_trigger->IsPersistant;
   2558 		kos_trigger->House = spyd_trigger->House;
   2559 		kos_trigger->EventControl = MULTI_LINKED;
   2560 		kos_trigger->ActionControl = MULTI_ONLY;
   2561 		kos_trigger->Event1.Event = spyd_trigger->Event1.Event;
   2562 		kos_trigger->Event1.Data = spyd_trigger->Event1.Data;
   2563 		kos_trigger->Event2.Event = TEVENT_DESTROYED;
   2564 		kos_trigger->Event2.Data.Value = 0;
   2565 		kos_trigger->Action1.Action = TACTION_SET_GLOBAL;
   2566 		kos_trigger->Action1.Data.Value = 22;
   2567 		kos_trigger->Action2.Action = TACTION_SET_GLOBAL;
   2568 		kos_trigger->Action2.Data.Value = 23;
   2569 
   2570 		spyd_trigger->Event1.Event = TEVENT_GLOBAL_SET;
   2571 		spyd_trigger->Event1.Data.Value = 22;
   2572 
   2573 		for (int index = 0; index < Buildings.Count(); index++) {
   2574 			BuildingClass* building = Buildings.Ptr(index);
   2575 			if (building->Trigger.Is_Valid() && (building->Trigger->Class == spyd_trigger)) {
   2576 				building->Attach_Trigger(Find_Or_Make(kos_trigger));
   2577 			}
   2578 		}
   2579 
   2580 		TriggerTypeClass* los3_trigger = new TriggerTypeClass();
   2581 		los3_trigger->IsPersistant = spyd_trigger->IsPersistant;
   2582 		los3_trigger->House = spyd_trigger->House;
   2583 		los3_trigger->EventControl = MULTI_AND;
   2584 		los3_trigger->ActionControl = MULTI_AND;
   2585 		los3_trigger->Event1.Event = TEVENT_GLOBAL_SET;
   2586 		los3_trigger->Event1.Data.Value = 23;
   2587 		los3_trigger->Event2.Event = TEVENT_GLOBAL_CLEAR;
   2588 		los3_trigger->Event2.Data.Value = 22;
   2589 		los3_trigger->Action1.Action = TACTION_LOSE;
   2590 		los3_trigger->Action1.Data.Value = -255;
   2591 		los3_trigger->Action2.Action = TACTION_TEXT_TRIGGER;
   2592 		los3_trigger->Action2.Data.Value = 54;
   2593 	}
   2594 
   2595 	if (_stricmp(Scen.ScenarioName, "scu46ea.ini") == 0) {
   2596 		Scen.Waypoint[20] = 9915;
   2597 		Scen.Waypoint[21] = 9919;
   2598 		Map[Scen.Waypoint[20]].IsWaypoint = 1;
   2599 		Map[Scen.Waypoint[21]].IsWaypoint = 1;
   2600 
   2601 		TeamTypeClass* rnf1_team = TeamTypeClass::From_Name("rnf1");
   2602 		assert(rnf1_team != NULL);
   2603 		rnf1_team->MissionList[0].Data.Value = 20;
   2604 
   2605 		TeamTypeClass* rnf2_team = TeamTypeClass::From_Name("rnf2");
   2606 		assert(rnf2_team != NULL);
   2607 		rnf2_team->MissionList[0].Data.Value = 21;
   2608 	}
   2609 
   2610 	if (_stricmp(Scen.ScenarioName, "scu42ea.ini") == 0) {
   2611 		BuildingTypeClass::As_Reference(STRUCT_PILLBOX).IsCaptureable = false;
   2612 	}
   2613 
   2614 	if ((_stricmp(Scen.ScenarioName, "scu35ea.ini") == 0) || (_stricmp(Scen.ScenarioName, "scu47ea.ini") == 0)) {
   2615 		WeaponTypeClass::As_Pointer(Weapon_From_Name("Sniper"))->Burst = 2;
   2616 	}
   2617 
   2618 	/*
   2619 	**	Multi-player last-minute fixups:
   2620 	**	- If computer players are disabled, remove all computer-owned houses
   2621 	**	- If bases are disabled, create the scenario dynamically
   2622 	**	- Remove any flag spot overlays lying around
   2623 	**	- If capture-the-flag is enabled, assign flags to cells.
   2624 	*/
   2625 	if (Session.Type != GAME_NORMAL /*|| Scen.ScenPlayer == SCEN_PLAYER_2PLAYER || Scen.ScenPlayer == SCEN_PLAYER_MPLAYER*/) {
   2626 
   2627 		/*
   2628 		**	If Ghosts are disabled and we're not editing, remove computer players
   2629 		**	(Must be done after all objects are read in from the INI)
   2630 		*/
   2631 		if ( (Session.Options.AIPlayers + Session.Players.Count() < Rule.MaxPlayers) && !Debug_Map) {
   2632 			Remove_AI_Players();
   2633 		}
   2634 
   2635 		/*
   2636 		**	Units must be created for each house.  If bases are ON, this routine
   2637 		**	will create an MCV along with the units; otherwise, it will just create
   2638 		**	a whole bunch of units.  Session.Options.UnitCount is the total # of units
   2639 		**	to create.
   2640 		*/
   2641 		if (!Debug_Map) {
   2642 			int save_init = ScenarioInit;			// turn ScenarioInit off
   2643 			ScenarioInit = 0;
   2644 			Create_Units(ini.Get_Bool("Basic", "Official", false));
   2645 			ScenarioInit = save_init;				// turn ScenarioInit back on
   2646 		}
   2647 
   2648 		/*
   2649 		**	Place crates if random crates are enabled for
   2650 		**	this scenario.
   2651 		*/
   2652 		if (Session.Options.Goodies) {
   2653 			int count = max(Rule.CrateMinimum, Session.NumPlayers);
   2654 			count = min(count, Rule.CrateMaximum);
   2655 			for (int index = 0; index < count; index++) {
   2656 				Map.Place_Random_Crate();
   2657 			}
   2658 		}
   2659 	}
   2660 
   2661 	Call_Back();
   2662 
   2663 	/*
   2664 	**	Return with flag saying that the scenario file was read.
   2665 	*/
   2666 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98 - Added runtime check.
   2667 	if( Is_Aftermath_Installed() )
   2668 	{
   2669 		if (Session.Type == GAME_SKIRMISH || Session.Type == GAME_GLYPHX_MULTIPLAYER) {
   2670 			bAftermathMultiplayer = NewUnitsEnabled = OverrideNewUnitsEnabled;
   2671 		}
   2672 	}	
   2673 #endif
   2674 	ScenarioInit--;
   2675 	return(true);
   2676 }
   2677 
   2678 
   2679 /***********************************************************************************************
   2680  * Write_Scenario_INI -- Write the scenario INI file.                                          *
   2681  *                                                                                             *
   2682  * INPUT:                                                                                      *
   2683  *      root      root filename for the scenario                                               *
   2684  *                                                                                             *
   2685  * OUTPUT:                                                                                     *
   2686  *      none.                                                                                  *
   2687  *                                                                                             *
   2688  * WARNINGS:                                                                                   *
   2689  *      none.                                                                                  *
   2690  *                                                                                             *
   2691  * HISTORY:                                                                                    *
   2692  *   10/07/1992 JLB : Created.                                                                 *
   2693  *   05/11/1995 JLB : Updates movie data.                                                      *
   2694  *=============================================================================================*/
   2695 void Write_Scenario_INI(char * fname)
   2696 {
   2697 #ifndef CHEAT_KEYS
   2698 	fname = fname;
   2699 #else
   2700 //	CCFileClass file(fname);
   2701 
   2702 	CCINIClass ini;
   2703 
   2704 	/*
   2705 	**	Preload the old scenario if it is present because there may
   2706 	**	be some fields in the INI that are processed but not written
   2707 	**	out. Preloading the scenario will preserve these manually
   2708 	**	maintained entries.
   2709 	*/
   2710 	if (CCFileClass(fname).Is_Available()) {
   2711 		ini.Load(CCFileClass(fname), true);
   2712 	}
   2713 
   2714 	static char const * const BASIC = "Basic";
   2715 	ini.Clear(BASIC);
   2716 	ini.Put_String(BASIC, "Name", Scen.Description);
   2717 	ini.Put_VQType(BASIC, "Intro", Scen.IntroMovie);
   2718 	ini.Put_VQType(BASIC, "Brief", Scen.BriefMovie);
   2719 	ini.Put_VQType(BASIC, "Win", Scen.WinMovie);
   2720 	ini.Put_VQType(BASIC, "Lose", Scen.LoseMovie);
   2721 	ini.Put_VQType(BASIC, "Action", Scen.ActionMovie);
   2722 	ini.Put_HousesType(BASIC, "Player", PlayerPtr->Class->House);
   2723 	ini.Put_ThemeType(BASIC, "Theme", Scen.TransitTheme);
   2724 	ini.Put_Fixed(BASIC, "CarryOverMoney", Scen.CarryOverPercent);
   2725 	ini.Put_Bool(BASIC, "ToCarryOver", Scen.IsToCarryOver);
   2726 	ini.Put_Bool(BASIC, "ToInherit", Scen.IsToInherit);
   2727 	ini.Put_Bool(BASIC, "TimerInherit", Scen.IsInheritTimer);
   2728 	ini.Put_Bool(BASIC, "CivEvac", Scen.IsTanyaEvac);
   2729 	ini.Put_Int(BASIC, "NewINIFormat", 3);
   2730 	ini.Put_Int(BASIC, "CarryOverCap", Scen.CarryOverCap/100);
   2731 	ini.Put_Bool(BASIC, "EndOfGame", Scen.IsEndOfGame);
   2732 	ini.Put_Bool(BASIC, "NoSpyPlane", Scen.IsNoSpyPlane);
   2733 	ini.Put_Bool(BASIC, "SkipScore", Scen.IsSkipScore);
   2734 	ini.Put_Bool(BASIC, "OneTimeOnly", Scen.IsOneTimeOnly);
   2735 	ini.Put_Bool(BASIC, "SkipMapSelect", Scen.IsNoMapSel);
   2736 	ini.Put_Bool(BASIC, "Official", true);
   2737 	ini.Put_Bool(BASIC, "FillSilos", Scen.IsMoneyTiberium);
   2738 	ini.Put_Bool(BASIC, "TruckCrate", Scen.IsTruckCrate);
   2739 	ini.Put_Int(BASIC, "Percent", Scen.Percent);
   2740 
   2741 	HouseClass::Write_INI(ini);
   2742 	TeamTypeClass::Write_INI(ini);
   2743 	TriggerTypeClass::Write_INI(ini);
   2744 	Map.Write_INI(ini);
   2745 	TerrainClass::Write_INI(ini);
   2746 	UnitClass::Write_INI(ini);
   2747 	VesselClass::Write_INI(ini);
   2748 	InfantryClass::Write_INI(ini);
   2749 	BuildingClass::Write_INI(ini);
   2750 	Base.Write_INI(ini);
   2751 	OverlayClass::Write_INI(ini);
   2752 	SmudgeClass::Write_INI(ini);
   2753 
   2754 	if (strlen(Scen.BriefingText)) {
   2755 		ini.Put_TextBlock("Briefing", Scen.BriefingText);
   2756 	}
   2757 //	sprintf(fname, "%s.INI", root);
   2758 	RawFileClass rawfile(fname);
   2759 	ini.Save(rawfile, true);
   2760 #endif
   2761 }
   2762 
   2763 
   2764 /***********************************************************************************************
   2765  * Assign_Houses -- Assigns multiplayer houses to various players                              *
   2766  *                                                                                             *
   2767  * This routine assigns all players to a multiplayer house slot; it forms network connections  *
   2768  * to each player.  The Connection ID used is the value for that player's HousesType.			  *
   2769  *                                                                                             *
   2770  * PlayerPtr is also set here.																					  *
   2771  *                                                                                             *
   2772  * INPUT:                                                                                      *
   2773  *      none.                                                                                  *
   2774  *                                                                                             *
   2775  * OUTPUT:                                                                                     *
   2776  *      none.                                                                                  *
   2777  *                                                                                             *
   2778  * WARNINGS:                                                                                   *
   2779  *		This routine assumes the 'Players' vector has been properly filled in with players'		  *
   2780  *		names, addresses, color, etc.																				  *
   2781  *		Also, it's assumed that the HouseClass's have all been created & initialized.				  *
   2782  *                                                                                             *
   2783  * HISTORY:                                                                                    *
   2784  *   06/09/1995 BRR : Created.                                                                 *
   2785  *   07/14/1995 JLB : Records name of player in house structure.                               *
   2786  *=============================================================================================*/
   2787 void Assign_Houses(void)
   2788 {
   2789 	int assigned[MAX_PLAYERS];
   2790 	int color_used[8];
   2791 	int i,j;
   2792 	HousesType house;
   2793 	HouseClass * housep;
   2794 	int lowest_color;
   2795 	int index;
   2796 	HousesType pref_house;
   2797 	int color;
   2798 
   2799 	//------------------------------------------------------------------------
   2800 	// Initialize
   2801 	//------------------------------------------------------------------------
   2802 	for (i = 0; i < MAX_PLAYERS; i++) {
   2803 		assigned[i] = 0;
   2804 		color_used[i] = 0;
   2805 	}
   2806 
   2807 //	debugprint( "Assign_Houses()\n" );
   2808 	//------------------------------------------------------------------------
   2809 	// Assign each player in 'Players' to a multiplayer house.  Players will
   2810 	// be sorted by their chosen color value (this value must be unique among
   2811 	// all the players).
   2812 	//------------------------------------------------------------------------
   2813 	for (i = 0; i < Session.Players.Count(); i++) {
   2814 
   2815 		//.....................................................................
   2816 		// Find the player with the lowest color index
   2817 		//.....................................................................
   2818 		index = 0;
   2819 		lowest_color = 255;
   2820 		for (j = 0; j < Session.Players.Count(); j++) {
   2821 			//..................................................................
   2822 			// If we've already assigned this house, skip it.
   2823 			//..................................................................
   2824 			if (assigned[j]) {
   2825 				continue;
   2826 			}
   2827 			if (Session.Players[j]->Player.Color < lowest_color) {
   2828 				lowest_color = Session.Players[j]->Player.Color;
   2829 				index = j;
   2830 			}
   2831 		}
   2832 
   2833 		//.....................................................................
   2834 		// Mark this player as having been assigned.
   2835 		//.....................................................................
   2836 		assigned[index] = 1;
   2837 		color_used[Session.Players[index]->Player.Color] = 1;
   2838 
   2839 		//.....................................................................
   2840 		// Assign the lowest-color'd player to the next available slot in the
   2841 		// HouseClass array.
   2842 		//.....................................................................
   2843 		house = (HousesType)(i + HOUSE_MULTI1);
   2844 		housep = HouseClass::As_Pointer(house);
   2845 		memset((char *)housep->IniName, 0, MPLAYER_NAME_MAX);
   2846 		strncpy((char *)housep->IniName, Session.Players[index]->Name, MPLAYER_NAME_MAX - 1);
   2847 #ifdef WOLAPI_INTEGRATION
   2848 		//	Make another copy of name, permanent throughout entire game.
   2849 		strncpy((char *)housep->InitialName, Session.Players[index]->Name, MPLAYER_NAME_MAX - 1);
   2850 #endif
   2851 		housep->IsHuman = true;
   2852 		housep->Init_Data((PlayerColorType)(Session.Players[index]->Player.Color),
   2853 			Session.Players[index]->Player.House, Session.Options.Credits);
   2854 		if (index == 0) {
   2855 			PlayerPtr = housep;
   2856 		}
   2857 		/*
   2858 		**	Convert the build level into an actual tech level to assign to the house.
   2859 		**	There isn't a one-to-one correspondence.
   2860 		*/
   2861 		housep->Control.TechLevel = _build_tech[BuildLevel];
   2862 
   2863 		housep->Assign_Handicap(Scen.Difficulty);
   2864 
   2865 		//.....................................................................
   2866 		// Record where we placed this player
   2867 		//.....................................................................
   2868 		Session.Players[index]->Player.ID = house;
   2869 
   2870 //		debugprint( "Assigned ID of %i to %s\n", house, Session.Players[index]->Name );
   2871 	}
   2872 
   2873 	//------------------------------------------------------------------------
   2874 	// Now assign computer players to the remaining houses.
   2875 	//------------------------------------------------------------------------
   2876 	for (i = Session.Players.Count(); i < Session.Players.Count() + Session.Options.AIPlayers; i++) {
   2877 		house = (HousesType)(i + HOUSE_MULTI1);
   2878 		housep = HouseClass::As_Pointer(house);
   2879 		if (Percent_Chance(50)) {
   2880 			pref_house = HOUSE_GREECE;
   2881 		} else {
   2882 			pref_house = HOUSE_USSR;
   2883 		}
   2884 
   2885 		//.....................................................................
   2886 		// Pick a color for this house; keep looping until we find one.
   2887 		//.....................................................................
   2888 		while (1) {
   2889 			color = Random_Pick(0, 7);
   2890 			if (color_used[color] == false) {
   2891 				break;
   2892 			}
   2893 		}
   2894 		color_used[color] = true;
   2895 
   2896 		//.....................................................................
   2897 		// Set up the house
   2898 		//.....................................................................
   2899 //		housep->Control.MaxUnit = 80;
   2900 //		housep->Control.MaxInfantry = 60;
   2901 //		housep->Control.MaxBuilding = 60;
   2902 //		housep->Control.MaxVessel = 60;
   2903 		housep->IsHuman = false;
   2904 		housep->IsStarted = true;
   2905 
   2906 		strcpy(housep->IniName, Text_String(TXT_COMPUTER));
   2907 
   2908 		if (Session.Type != GAME_NORMAL) {
   2909 			housep->IQ = Rule.MaxIQ;
   2910 		}
   2911 
   2912 		housep->Init_Data((PlayerColorType)color, pref_house, Session.Options.Credits);
   2913 		housep->Control.TechLevel = _build_tech[BuildLevel];
   2914 //		housep->Control.TechLevel = BuildLevel;
   2915 
   2916 		DiffType difficulty = Scen.CDifficulty;
   2917 
   2918 		if (Session.Players.Count() > 1 && Rule.IsCompEasyBonus && difficulty > DIFF_EASY) {
   2919 			difficulty = (DiffType)(difficulty - 1);
   2920 		}
   2921 		housep->Assign_Handicap(difficulty);
   2922 	}
   2923 
   2924 	for (i = Session.Players.Count()+Session.Options.AIPlayers; i < Rule.MaxPlayers; i++) {
   2925 		house = (HousesType)(i + HOUSE_MULTI1);
   2926 		housep = HouseClass::As_Pointer(house);
   2927 		if (housep != NULL) {
   2928 			housep->IsDefeated = true;
   2929 		}
   2930 	}
   2931 }
   2932 
   2933 
   2934 /***********************************************************************************************
   2935  * Remove_AI_Players -- Removes the computer AI houses & their units                           *
   2936  *                                                                                             *
   2937  * INPUT:                                                                                      *
   2938  *      none.                                                                                  *
   2939  *                                                                                             *
   2940  * OUTPUT:                                                                                     *
   2941  *      none.                                                                                  *
   2942  *                                                                                             *
   2943  * WARNINGS:                                                                                   *
   2944  *      none.                                                                                  *
   2945  *                                                                                             *
   2946  * HISTORY:                                                                                    *
   2947  *   06/09/1995 BRR : Created.                                                                 *
   2948  *=============================================================================================*/
   2949 static void Remove_AI_Players(void)
   2950 {
   2951 	int i;
   2952 	int aicount = 0;
   2953 	HousesType house;
   2954 	HouseClass * housep;
   2955 
   2956 #if (0)
   2957 	for (i = 0; i < MAX_PLAYERS; i++) {
   2958 		house = (HousesType)(i + (int)HOUSE_MULTI1);
   2959 		housep = HouseClass::As_Pointer (house);
   2960 		if (housep->IsHuman == false) {
   2961 			aicount++;
   2962 			if(aicount > Session.Options.AIPlayers) {
   2963 				housep->Clobber_All();
   2964 			}
   2965 		}
   2966 	}
   2967 #else
   2968 	/*
   2969 	** AI players are set up like human players now. ST - 8/13/2019 1:32PM
   2970 	*/
   2971 	for (i = 0; i < MAX_PLAYERS; i++) {
   2972 		if (i >= Session.Players.Count()) {
   2973 			house = (HousesType)(i + (int)HOUSE_MULTI1);
   2974 			housep = HouseClass::As_Pointer (house);
   2975 			if (housep->IsHuman == false) {
   2976 				housep->Clobber_All();
   2977 			}
   2978 		}
   2979 	}
   2980 
   2981 #endif
   2982 }
   2983 
   2984 
   2985 #define USE_GLYPHX_START_LOCATIONS 1
   2986 
   2987 
   2988 /***********************************************************************************************
   2989  * Create_Units -- Creates infantry & units, for non-base multiplayer                          *
   2990  *                                                                                             *
   2991  * This routine uses data tables to determine which units to create for either                 *
   2992  * a GDI or NOD house, and how many of each.                                                   *
   2993  *                                                                                             *
   2994  * It also sets each house's FlagHome & FlagLocation to the Waypoint selected                  *
   2995  * as that house's "home" cell.                                                                *
   2996  *                                                                                             *
   2997  * INPUT:   official -- Directs the placement logic to use the full set of waypoints rather    *
   2998  *                      than biasing toward the first four.                                    *
   2999  *                                                                                             *
   3000  * OUTPUT:                                                                                     *
   3001  *      none.                                                                                  *
   3002  *                                                                                             *
   3003  * WARNINGS:                                                                                   *
   3004  *      none.                                                                                  *
   3005  *                                                                                             *
   3006  * HISTORY:                                                                                    *
   3007  *   06/09/1995 BRR : Created.                                                                 *
   3008  *=============================================================================================*/
   3009 static int ReserveInfantryIndex = 0;
   3010 static void Reserve_Infantry()
   3011 {
   3012 	if (Infantry.Count() == Infantry.Length()) {
   3013 		delete Infantry.Ptr(ReserveInfantryIndex);
   3014 		ReserveInfantryIndex = (ReserveInfantryIndex + 1) % Infantry.Length();
   3015 	}
   3016 }
   3017 
   3018 static int ReserveUnitIndex = 0;
   3019 static void Reserve_Unit()
   3020 {
   3021 	if (Units.Count() == Units.Length()) {
   3022 		delete Units.Ptr(ReserveUnitIndex);
   3023 		ReserveUnitIndex = (ReserveUnitIndex + 1) % Units.Length();
   3024 	}
   3025 }
   3026 
   3027 static void Create_Units(bool official)
   3028 {
   3029 	static struct {
   3030 		int MinLevel;
   3031 		UnitType AllyType[2];
   3032 		UnitType SovietType[2];
   3033 	} utable[] = {
   3034 		{4,	{UNIT_MTANK2,   UNIT_LTANK}, 	{UNIT_MTANK,		 UNIT_NONE}},
   3035 		{5,	{UNIT_APC,      UNIT_NONE},  	{UNIT_V2_LAUNCHER, UNIT_NONE}},
   3036 		{8,	{UNIT_ARTY,     UNIT_JEEP},  	{UNIT_MTANK,		 UNIT_NONE}},
   3037 		{10,	{UNIT_MTANK2,   UNIT_MTANK2},	{UNIT_HTANK,		 UNIT_NONE}}
   3038 	};
   3039 	static int num_units[ARRAY_SIZE(utable)];		// # of each type of unit to create
   3040 	int tot_units;												// total # units to create
   3041 
   3042 	static struct {
   3043 		int MinLevel;
   3044 		int AllyCount;
   3045 		InfantryType AllyType;
   3046 		int SovietCount;
   3047 		InfantryType SovietType;
   3048 	} itable[] = {
   3049 		{0,	1,INFANTRY_E1,				1,INFANTRY_E1},
   3050 		{2,	1,INFANTRY_E3,				1,INFANTRY_E2},
   3051 		{4,	1,INFANTRY_E3,				1,INFANTRY_E4},
   3052 
   3053 // removed because of bug B478 (inappropriate infantry given in a bases off scenario).
   3054 //		{5,	1,INFANTRY_RENOVATOR,	1,INFANTRY_RENOVATOR},
   3055 //		{6,	1,INFANTRY_SPY,			1,INFANTRY_DOG},
   3056 //		{10,	1,INFANTRY_THIEF,			1,INFANTRY_DOG},
   3057 //		{12,	1,INFANTRY_MEDIC,			2,INFANTRY_DOG}
   3058 	};
   3059 	static int num_infantry[ARRAY_SIZE(itable)];// # of each type of infantry to create
   3060 	int tot_infantry;											// total # infantry to create
   3061 
   3062 
   3063 	CELL centroid;			// centroid of this house's stuff
   3064 	CELL centerpt;			// centroid for a category of objects, as a CELL
   3065 
   3066 	int u_limit=0;			// last allowable index of units for this BuildLevel
   3067 	int i_limit=0;			// last allowable index of infantry for this BuildLevel
   3068 	TechnoClass * obj;		// newly-created object
   3069 	int i,j,k;				// loop counters
   3070 	int scaleval;			// value to scale # units or infantry
   3071 
   3072 	ReserveInfantryIndex = ReserveUnitIndex = 0;
   3073 
   3074 	/*
   3075 	**	For the current BuildLevel, find the max allowable index into the tables
   3076 	*/
   3077 	for (i = 0; i < ARRAY_SIZE(utable); i++) {
   3078 		if (PlayerPtr->Control.TechLevel >= utable[i].MinLevel) {
   3079 			u_limit = i+1;
   3080 		}
   3081 	}
   3082 	for (i = 0; i < ARRAY_SIZE(itable); i++) {
   3083 		if (PlayerPtr->Control.TechLevel >= itable[i].MinLevel) {
   3084 			i_limit = i+1;
   3085 		}
   3086 	}
   3087 
   3088 	/*
   3089 	**	Compute how many of each buildable category to create
   3090 	*/
   3091 	/*
   3092 	**	Compute allowed # units
   3093 	*/
   3094 	tot_units = (Session.Options.UnitCount * 2) / 3;
   3095 	if (u_limit == 0) tot_units = 0;
   3096 
   3097 	/*
   3098 	**	Init # of each category to 0
   3099 	*/
   3100 	for (i = 0; i < u_limit; i++) {
   3101 		num_units[i] = 0;
   3102 	}
   3103 
   3104 	/*
   3105 	**	Increment # of each category, until we've used up all units
   3106 	*/
   3107 	j = 0;
   3108 	for (i = 0; i < tot_units; i++) {
   3109 		num_units[j]++;
   3110 		j++;
   3111 		if (j >= u_limit) {
   3112 			j = 0;
   3113 		}
   3114 	}
   3115 
   3116 	/*
   3117 	**	Compute allowed # infantry
   3118 	*/
   3119 	tot_infantry = Session.Options.UnitCount - tot_units;
   3120 
   3121 	/*
   3122 	**	Init # of each category to 0
   3123 	*/
   3124 	for (i = 0; i < i_limit; i++) {
   3125 		num_infantry[i] = 0;
   3126 	}
   3127 
   3128 	/*
   3129 	**	Increment # of each category, until we've used up all infantry
   3130 	*/
   3131 	j = 0;
   3132 	for (i = 0; i < tot_infantry; i++) {
   3133 		num_infantry[j]++;
   3134 		j++;
   3135 		if (j >= i_limit) {
   3136 			j = 0;
   3137 		}
   3138 	}
   3139 
   3140 	/*
   3141 	**	Build a list of the valid waypoints. This normally shouldn't be
   3142 	**	necessary because the scenario level designer should have assigned
   3143 	**	valid locations to the first N waypoints, but just in case, this
   3144 	**	loop verifies that.
   3145 	*/
   3146 
   3147 	const unsigned int MAX_STORED_WAYPOINTS = 26;
   3148 
   3149 	bool taken[MAX_STORED_WAYPOINTS];
   3150 	CELL waypts[MAX_STORED_WAYPOINTS];
   3151 	assert(Rule.MaxPlayers < ARRAY_SIZE(waypts));
   3152 	int num_waypts = 0;
   3153 
   3154 	/*
   3155 	**	Calculate the number of waypoints (as a minimum) that will be lifted from the
   3156 	**	mission file. Bias this number so that only the first 4 waypoints are used
   3157 	**	if there are 4 or fewer players. Unofficial maps will pick from all the
   3158 	**	available waypoints.
   3159 	*/
   3160 #ifndef USE_GLYPHX_START_LOCATIONS
   3161 	int look_for = max(4, Session.Players.Count()+Session.Options.AIPlayers);
   3162 	if (!official) {
   3163 		look_for = 8;
   3164 	}
   3165 #else
   3166 	/*
   3167 	** We allow the users to choose from all available start positions, even on official maps. ST - 1/15/2020 9:19AM
   3168 	*/
   3169 	int look_for = Session.Players.Count();
   3170 #endif
   3171 		
   3172 	for (int waycount = 0; waycount < 26; waycount++) {
   3173 //	for (int waycount = 0; waycount < max(4, Session.Players.Count()+Session.Options.AIPlayers); waycount++) {
   3174 		if (Scen.Waypoint[waycount] != -1) {
   3175 			waypts[num_waypts] = Scen.Waypoint[waycount];
   3176 			taken[num_waypts] = false;
   3177 			num_waypts++;
   3178 
   3179 			if (num_waypts >= MAX_STORED_WAYPOINTS)
   3180 			{
   3181 				break;
   3182 			}
   3183 		}
   3184 	}
   3185 
   3186 	/*
   3187 	**	If there are insufficient waypoints to account for all players, then randomly assign
   3188 	**	starting points until there is enough.
   3189 	*/
   3190 	int deficiency = look_for - num_waypts;
   3191 //	int deficiency = (Session.Players.Count() + Session.Options.AIPlayers) - num_waypts;
   3192 	if (deficiency > 0) {
   3193 		for (int index = 0; index < deficiency; index++) {
   3194 			CELL trycell = XY_Cell(Map.MapCellX + Random_Pick(0, Map.MapCellWidth-1), Map.MapCellY + Random_Pick(0, Map.MapCellHeight-1));
   3195 
   3196 			trycell = Map.Nearby_Location(trycell, SPEED_TRACK);
   3197 			waypts[num_waypts] = trycell;
   3198 			taken[num_waypts] = false;
   3199 			num_waypts++;
   3200 		}
   3201 	}
   3202 
   3203 	/*
   3204 	**	Loop through all houses.  Computer-controlled houses, with Session.Options.Bases
   3205 	**	ON, are treated as though bases are OFF (since we have no base-building
   3206 	**	AI logic.)
   3207 	*/
   3208 	int numtaken = 0;
   3209 	for (HousesType house = HOUSE_MULTI1; house < (HOUSE_MULTI1 + Session.MaxPlayers); house++) {
   3210 
   3211 		/*
   3212 		**	Get a pointer to this house; if there is none, go to the next house
   3213 		*/
   3214 		HouseClass * hptr = HouseClass::As_Pointer(house);
   3215 		if (hptr == NULL) {
   3216 			continue;
   3217 		}
   3218 
   3219 		/*
   3220 		**	Pick the starting location for this house. The first house just picks
   3221 		**	one of the valid locations at random. The other houses pick the furthest
   3222 		**	wapoint from the existing houses.
   3223 		*/
   3224 		if (!UseGlyphXStartLocations) {
   3225 		
   3226 			if (numtaken == 0) {
   3227 				int pick = Random_Pick(0, num_waypts-1);
   3228 				centroid = waypts[pick];
   3229 				hptr->StartLocationOverride = pick;
   3230 				taken[pick] = true;
   3231 				numtaken++;
   3232 			} else {
   3233 
   3234 				/*
   3235 				**	Set all waypoints to have a score of zero in preparation for giving
   3236 				**	a distance score to all waypoints.
   3237 				*/
   3238 				int score[26];
   3239 				memset(score, '\0', sizeof(score));
   3240 
   3241 				/*
   3242 				**	Scan through all waypoints and give a score as a value of the sum
   3243 				**	of the distances from this waypoint to all taken waypoints.
   3244 				*/
   3245 				for (int index = 0; index < num_waypts; index++) {
   3246 
   3247 					/*
   3248 					**	If this waypoint has not already been taken, then accumulate the
   3249 					**	sum of the distance between this waypoint and all other taken
   3250 					**	waypoints.
   3251 					*/
   3252 					if (!taken[index]) {
   3253 						for (int trypoint = 0; trypoint < num_waypts; trypoint++) {
   3254 
   3255 							if (taken[trypoint]) {
   3256 								score[index] += Distance(Cell_Coord(waypts[index]), Cell_Coord(waypts[trypoint]));
   3257 							}
   3258 						}
   3259 					}
   3260 				}
   3261 
   3262 				/*
   3263 				**	Now find the waypoint with the largest score. This waypoint is the one
   3264 				**	that is furthest from all other taken waypoints.
   3265 				*/
   3266 				int best = 0;
   3267 				int bestvalue = 0;
   3268 				for (int searchindex = 0; searchindex < num_waypts; searchindex++) {
   3269 					if (score[searchindex] > bestvalue || bestvalue == 0) {
   3270 						bestvalue = score[searchindex];
   3271 						best = searchindex;
   3272 					}
   3273 				}
   3274 
   3275 				/*
   3276 				**	Assign this best position to the house.
   3277 				*/
   3278 				centroid = waypts[best];
   3279 				hptr->StartLocationOverride = best;
   3280 				taken[best] = true;
   3281 				numtaken++;
   3282 			}
   3283 		} else {
   3284 			
   3285 			/*
   3286 			** New code that respects the start locations passed in from GlyphX.
   3287 			**
   3288 			** ST - 1/8/2020 3:39PM
   3289 			*/
   3290 			centroid = waypts[hptr->StartLocationOverride];
   3291 		}
   3292 
   3293 		/*
   3294 		**	Assign the center of this house to the waypoint location.
   3295 		*/
   3296 		hptr->Center = Cell_Coord(centroid);
   3297 
   3298 		/*
   3299 		**	If Bases are ON, human & computer houses are treated differently
   3300 		*/
   3301 		if (Session.Options.Bases) {
   3302 
   3303 			/*
   3304 			**	- For a human-controlled house:
   3305 			**	  - Set 'scaleval' to 1
   3306 			**	  - Create an MCV
   3307 			**	  - Attach a flag to it for capture-the-flag mode
   3308 			*/
   3309 			scaleval = 1;
   3310 			Reserve_Unit();
   3311 			obj = new UnitClass (UNIT_MCV, house);
   3312 			if (!obj->Unlimbo(Cell_Coord(centroid), DIR_N)) {
   3313 				if (!Scan_Place_Object(obj, centroid)) {
   3314 					delete obj;
   3315 					obj = NULL;
   3316 				}
   3317 			}
   3318 			if (obj != NULL) {
   3319 				hptr->FlagHome = 0;
   3320 				hptr->FlagLocation = 0;
   3321 				if (Special.IsCaptureTheFlag) {
   3322 					hptr->Flag_Attach((UnitClass *)obj, true);
   3323 				}
   3324 			}
   3325 		} else {
   3326 
   3327 			/*
   3328 			**	If bases are OFF, set 'scaleval' to 1 & create a Mobile HQ for
   3329 			**	capture-the-flag mode.
   3330 			*/
   3331 			scaleval = 1;
   3332 #ifdef TOFIX
   3333 			if (Special.IsCaptureTheFlag) {
   3334 				obj = new UnitClass (UNIT_TRUCK, house);
   3335 				obj->Unlimbo(Cell_Coord(centroid), DIR_N);
   3336 				hptr->FlagHome = 0;					// turn house's flag off
   3337 				hptr->FlagLocation = 0;
   3338 			}
   3339 #endif
   3340 		}
   3341 
   3342 		/*
   3343 		**	Create units for this house
   3344 		*/
   3345 		for (i = 0; i < u_limit; i++) {
   3346 
   3347 			/*
   3348 			**	Find the center point for this category.
   3349 			*/
   3350 			centerpt = Clip_Scatter(centroid, 4);
   3351 
   3352 			/*
   3353 			**	Place objects; loop through all unit in this category
   3354 			*/
   3355 			for (j = 0; j < num_units[i] * scaleval; j++) {
   3356 
   3357 				/*
   3358 				**	Create an Ally unit
   3359 				*/
   3360 				if (hptr->ActLike != HOUSE_USSR && hptr->ActLike != HOUSE_UKRAINE) {
   3361 					for (k = 0; k < 2; k++) if(utable[i].AllyType[k] != UNIT_NONE) {
   3362 						Reserve_Unit();
   3363 						obj = new UnitClass (utable[i].AllyType[k], house);
   3364 						if (!Scan_Place_Object(obj, centerpt)) {
   3365 							delete obj;
   3366 						} else {
   3367 							if (!hptr->IsHuman) {
   3368 								obj->Set_Mission(MISSION_GUARD_AREA);
   3369 							} else {
   3370 								obj->Set_Mission(MISSION_GUARD);
   3371 							}
   3372 						}
   3373 					}
   3374 				} else {
   3375 
   3376 					/*
   3377 					**	Create a Soviet unit
   3378 					*/
   3379 					for (k = 0; k < 2; k++) if(utable[i].SovietType[k] != UNIT_NONE) {
   3380 						Reserve_Unit();
   3381 						obj = new UnitClass (utable[i].SovietType[k], house);
   3382 						if (!Scan_Place_Object(obj, centerpt)) {
   3383 							delete obj;
   3384 						} else {
   3385 							if (!hptr->IsHuman) {
   3386 								obj->Set_Mission(MISSION_GUARD_AREA);
   3387 							} else {
   3388 								obj->Set_Mission(MISSION_GUARD);
   3389 							}
   3390 						}
   3391 					}
   3392 				}
   3393 			}
   3394 		}
   3395 
   3396 		/*
   3397 		**	Create infantry
   3398 		*/
   3399 		for (i = 0; i < i_limit; i++) {
   3400 			/*
   3401 			**	Find the center point for this category.
   3402 			*/
   3403 			centerpt = Clip_Scatter(centroid, 4);
   3404 
   3405 			/*
   3406 			**	Place objects; loop through all unit in this category
   3407 			*/
   3408 			for (j = 0; j < num_infantry[i] * scaleval; j++) {
   3409 
   3410 				/*
   3411 				**	Create Ally infantry (Note: Unlimbo calls Enter_Idle_Mode(), which
   3412 				**	assigns the infantry to HUNT; we must use Set_Mission() to override
   3413 				**	this state.)
   3414 				*/
   3415 				if (hptr->ActLike != HOUSE_USSR && hptr->ActLike != HOUSE_UKRAINE) {
   3416 					for (k = 0; k < itable[i].AllyCount; k++) {
   3417 						Reserve_Infantry();
   3418 						obj = new InfantryClass (itable[i].AllyType, house);
   3419 						if (!Scan_Place_Object(obj, centerpt)) {
   3420 							delete obj;
   3421 						} else {
   3422 							if (!hptr->IsHuman) {
   3423 								obj->Set_Mission(MISSION_GUARD_AREA);
   3424 							} else {
   3425 								obj->Set_Mission(MISSION_GUARD);
   3426 							}
   3427 						}
   3428 					}
   3429 				} else {
   3430 
   3431 					/*
   3432 					**	Create Soviet infantry
   3433 					*/
   3434 					for (k = 0; k < itable[i].SovietCount; k++) {
   3435 						Reserve_Infantry();
   3436 						obj = new InfantryClass (itable[i].SovietType, house);
   3437 						if (!Scan_Place_Object(obj, centerpt)) {
   3438 							delete obj;
   3439 						} else {
   3440 							if (!hptr->IsHuman) {
   3441 								obj->Set_Mission(MISSION_GUARD_AREA);
   3442 							} else {
   3443 								obj->Set_Mission(MISSION_GUARD);
   3444 							}
   3445 						}
   3446 					}
   3447 				}
   3448 			}
   3449 		}
   3450 	}
   3451 }
   3452 
   3453 
   3454 /***********************************************************************************************
   3455  * Scan_Place_Object -- places an object >near< the given cell                                 *
   3456  *                                                                                             *
   3457  * INPUT:                                                                                      *
   3458  *      obj      ptr to object to Unlimbo                                                      *
   3459  *      cell      center of search area                                                        *
   3460  *                                                                                             *
   3461  * OUTPUT:                                                                                     *
   3462  *      true = object was placed; false = it wasn't                                            *
   3463  *                                                                                             *
   3464  * WARNINGS:                                                                                   *
   3465  *      none.                                                                                  *
   3466  *                                                                                             *
   3467  * HISTORY:                                                                                    *
   3468  *   06/09/1995 BRR : Created.                                                                 *
   3469  *=============================================================================================*/
   3470 int Scan_Place_Object(ObjectClass * obj, CELL cell)
   3471 {
   3472 	int dist;				// for object placement
   3473 	FacingType rot;		// for object placement
   3474 	FacingType fcounter;	// for object placement
   3475 	int tryval;
   3476 	CELL newcell;
   3477 	TechnoClass * techno;
   3478 	int skipit;
   3479 
   3480 	/*
   3481 	**	First try to unlimbo the object in the given cell.
   3482 	*/
   3483 	if (Map.In_Radar(cell)) {
   3484 		techno = Map[cell].Cell_Techno();
   3485 		if (!techno || (techno->What_Am_I()==RTTI_INFANTRY &&
   3486 			obj->What_Am_I()==RTTI_INFANTRY)) {
   3487 			if (obj->Unlimbo(Cell_Coord(cell), DIR_N)) {
   3488 				return(true);
   3489 			}
   3490 		}
   3491 	}
   3492 
   3493 	/*
   3494 	**	Loop through distances from the given center cell; skip the center cell.
   3495 	**	For each distance, try placing the object along each rotational direction;
   3496 	**	if none are available, try each direction with a random scatter value.
   3497 	**	If that fails, go to the next distance.
   3498 	**	This ensures that the closest coordinates are filled first.
   3499 	*/
   3500 	for (dist = 1; dist < 32; dist++) {
   3501 
   3502 		/*
   3503 		**	Pick a random starting direction
   3504 		*/
   3505 		rot = Random_Pick(FACING_N, FACING_NW);
   3506 
   3507 		/*
   3508 		**	Try all directions twice
   3509 		*/
   3510 		for (tryval = 0 ; tryval < 2; tryval++) {
   3511 
   3512 			/*
   3513 			**	Loop through all directions, at this distance.
   3514 			*/
   3515 			for (fcounter = FACING_N; fcounter <= FACING_NW; fcounter++) {
   3516 
   3517 				skipit = false;
   3518 
   3519 				/*
   3520 				**	Pick a coordinate along this directional axis
   3521 				*/
   3522 				newcell = Clip_Move(cell, rot, dist);
   3523 
   3524 				/*
   3525 				**	If this is our second try at this distance, add a random scatter
   3526 				**	to the desired cell, so our units aren't all aligned along spokes.
   3527 				*/
   3528 				if (tryval > 0) {
   3529 					newcell = Clip_Scatter (newcell, 1);
   3530 				}
   3531 
   3532 				/*
   3533 				**	If, by randomly scattering, we've chosen the exact center, skip
   3534 				**	it & try another direction.
   3535 				*/
   3536 				if (newcell==cell) {
   3537 					skipit = true;
   3538 				}
   3539 
   3540 				if (!skipit) {
   3541 					/*
   3542 					**	Only attempt to Unlimbo the object if:
   3543 					**	- there is no techno in the cell
   3544 					**	- the techno in the cell & the object are both infantry
   3545 					*/
   3546 					techno = Map[newcell].Cell_Techno();
   3547 					if (!techno || (techno->What_Am_I()==RTTI_INFANTRY &&
   3548 						obj->What_Am_I()==RTTI_INFANTRY)) {
   3549 						if (obj->Unlimbo(Cell_Coord(newcell), DIR_N)) {
   3550 							return(true);
   3551 						}
   3552 					}
   3553 				}
   3554 
   3555 				rot++;
   3556 				if (rot > FACING_NW) {
   3557 					rot = FACING_N;
   3558 				}
   3559 			}
   3560 		}
   3561 	}
   3562 
   3563 	return(false);
   3564 }
   3565 
   3566 
   3567 /***********************************************************************************************
   3568  * Clip_Scatter -- randomly scatters from given cell; won't fall off map                       *
   3569  *                                                                                             *
   3570  * INPUT:                                                                                      *
   3571  *      cell      cell to scatter from                                                         *
   3572  *      maxdist   max distance to scatter                                                      *
   3573  *                                                                                             *
   3574  * OUTPUT:                                                                                     *
   3575  *      new cell number                                                                        *
   3576  *                                                                                             *
   3577  * WARNINGS:                                                                                   *
   3578  *      none.                                                                                  *
   3579  *                                                                                             *
   3580  * HISTORY:                                                                                    *
   3581  *   07/30/1995 BRR : Created.                                                                 *
   3582  *=============================================================================================*/
   3583 static CELL Clip_Scatter(CELL cell, int maxdist)
   3584 {
   3585 	int x,y;
   3586 	int xdist;
   3587 	int ydist;
   3588 	int xmin,xmax;
   3589 	int ymin,ymax;
   3590 
   3591 	/*
   3592 	**	Get X & Y coords of given starting cell
   3593 	*/
   3594 	x = Cell_X(cell);
   3595 	y = Cell_Y(cell);
   3596 
   3597 	/*
   3598 	**	Compute our x & y limits
   3599 	*/
   3600 	xmin = Map.MapCellX;
   3601 	xmax = xmin + Map.MapCellWidth - 1;
   3602 	ymin = Map.MapCellY;
   3603 	ymax = ymin + Map.MapCellHeight - 1;
   3604 
   3605 	/*
   3606 	**	Adjust the x-coordinate
   3607 	*/
   3608 	xdist = Random_Pick(0, maxdist);
   3609 	if (Percent_Chance(50)) {
   3610 		x += xdist;
   3611 		if (x > xmax) {
   3612 			x = xmax;
   3613 		}
   3614 	} else {
   3615 		x -= xdist;
   3616 		if (x < xmin) {
   3617 			x = xmin;
   3618 		}
   3619 	}
   3620 
   3621 	/*
   3622 	**	Adjust the y-coordinate
   3623 	*/
   3624 	ydist = Random_Pick(0, maxdist);
   3625 	if (Percent_Chance(50)) {
   3626 		y += ydist;
   3627 		if (y > ymax) {
   3628 			y = ymax;
   3629 		}
   3630 	} else {
   3631 		y -= ydist;
   3632 		if (y < ymin) {
   3633 			y = ymin;
   3634 		}
   3635 	}
   3636 
   3637 	return (XY_Cell(x, y));
   3638 }
   3639 
   3640 
   3641 /***********************************************************************************************
   3642  * Clip_Move -- moves in given direction from given cell; clips to map                         *
   3643  *                                                                                             *
   3644  * INPUT:                                                                                      *
   3645  *      cell      cell to start from                                                           *
   3646  *      facing   direction to move                                                             *
   3647  *      dist      distance to move                                                             *
   3648  *                                                                                             *
   3649  * OUTPUT:                                                                                     *
   3650  *      new cell number                                                                        *
   3651  *                                                                                             *
   3652  * WARNINGS:                                                                                   *
   3653  *      none.                                                                                  *
   3654  *                                                                                             *
   3655  * HISTORY:                                                                                    *
   3656  *   07/30/1995 BRR : Created.                                                                 *
   3657  *=============================================================================================*/
   3658 static CELL Clip_Move(CELL cell, FacingType facing, int dist)
   3659 {
   3660 	int x,y;
   3661 	int xmin,xmax;
   3662 	int ymin,ymax;
   3663 
   3664 	/*
   3665 	**	Get X & Y coords of given starting cell
   3666 	*/
   3667 	x = Cell_X(cell);
   3668 	y = Cell_Y(cell);
   3669 
   3670 	/*
   3671 	**	Compute our x & y limits
   3672 	*/
   3673 	xmin = Map.MapCellX;
   3674 	xmax = xmin + Map.MapCellWidth - 1;
   3675 	ymin = Map.MapCellY;
   3676 	ymax = ymin + Map.MapCellHeight - 1;
   3677 
   3678 	/*
   3679 	**	Adjust the x-coordinate
   3680 	*/
   3681 	switch (facing) {
   3682 		case FACING_N:
   3683 			y -= dist;
   3684 			break;
   3685 
   3686 		case FACING_NE:
   3687 			x += dist;
   3688 			y -= dist;
   3689 			break;
   3690 
   3691 		case FACING_E:
   3692 			x += dist;
   3693 			break;
   3694 
   3695 		case FACING_SE:
   3696 			x += dist;
   3697 			y += dist;
   3698 			break;
   3699 
   3700 		case FACING_S:
   3701 			y += dist;
   3702 			break;
   3703 
   3704 		case FACING_SW:
   3705 			x -= dist;
   3706 			y += dist;
   3707 			break;
   3708 
   3709 		case FACING_W:
   3710 			x -= dist;
   3711 			break;
   3712 
   3713 		case FACING_NW:
   3714 			x -= dist;
   3715 			y -= dist;
   3716 			break;
   3717 	}
   3718 
   3719 	/*
   3720 	**	Clip to the map
   3721 	*/
   3722 	if (x > xmax)
   3723 		x = xmax;
   3724 	if (x < xmin)
   3725 		x = xmin;
   3726 
   3727 	if (y > ymax)
   3728 		y = ymax;
   3729 	if (y < ymin)
   3730 		y = ymin;
   3731 
   3732 	return (XY_Cell(x, y));
   3733 }
   3734 
   3735 
   3736 void Disect_Scenario_Name(char const * name, int & scenario, ScenarioPlayerType & player, ScenarioDirType & dir, ScenarioVarType & var)
   3737 {
   3738 	if (name == NULL) return;
   3739 
   3740 	/*
   3741 	**	Fetch the scenario number.
   3742 	*/
   3743 	char buf[3];
   3744 	memcpy(buf, &name[3], 2);
   3745 	buf[2] = '\0';
   3746 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   3747 	char first = buf[0];
   3748 	char second = buf[1];
   3749 	if (first <= '9' && second <= '9') {
   3750 		scenario = atoi(buf);
   3751 	} else {
   3752 		if (first <= '9') {
   3753 			first -= '0';
   3754 		} else {
   3755 			if (first >= 'a' && first <= 'z') {
   3756 				first -= 'a';
   3757 			} else {
   3758 				first -= 'A';
   3759 			}
   3760 		}
   3761 		if (second <= '9') {
   3762 			second -= '0';
   3763 		} else {
   3764 			if (second >= 'a' && second <= 'z') {
   3765 				second = (second - 'a') + 10;
   3766 			} else {
   3767 				second = (second - 'A') + 10;
   3768 			}
   3769 		}
   3770 		scenario = (36 * first) + second;
   3771 	}
   3772 #else
   3773 	scenario = atoi(buf);
   3774 #endif
   3775 
   3776 	/*
   3777 	**	Fetch the scenario player (side).
   3778 	*/
   3779 	player = SCEN_PLAYER_GREECE;
   3780 	if (name[2] == HouseTypeClass::As_Reference(HOUSE_SPAIN).Prefix) {
   3781 		player = SCEN_PLAYER_SPAIN;
   3782 	}
   3783 	if (name[2] == HouseTypeClass::As_Reference(HOUSE_GREECE).Prefix) {
   3784 		player = SCEN_PLAYER_GREECE;
   3785 	}
   3786 	if (name[2] == HouseTypeClass::As_Reference(HOUSE_USSR).Prefix) {
   3787 		player = SCEN_PLAYER_USSR;
   3788 	}
   3789 
   3790 	/*
   3791 	**	Fetch the direction.
   3792 	*/
   3793 	dir = SCEN_DIR_EAST;
   3794 	if (name[5] == 'E') {
   3795 		dir = SCEN_DIR_EAST;
   3796 	} else {
   3797 		dir = SCEN_DIR_WEST;
   3798 	}
   3799 
   3800 	/*
   3801 	**	Fetch the variation.
   3802 	*/
   3803 	var = SCEN_VAR_A;
   3804 	var = ScenarioVarType((name[6] - 'A') + SCEN_VAR_A);
   3805 }