CnC_Remastered_Collection

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

DISPLAY.CPP (218047B)


      1 //
      2 // Copyright 2020 Electronic Arts Inc.
      3 //
      4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
      5 // software: you can redistribute it and/or modify it under the terms of 
      6 // the GNU General Public License as published by the Free Software Foundation, 
      7 // either version 3 of the License, or (at your option) any later version.
      8 
      9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
     10 // in the hope that it will be useful, but with permitted additional restrictions 
     11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
     12 // distributed with this program. You should have received a copy of the 
     13 // GNU General Public License along with permitted additional restrictions 
     14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
     15 
     16 /* $Header: /CounterStrike/DISPLAY.CPP 3     3/09/97 8:04p Joe_bostic $ */
     17 /***********************************************************************************************
     18  ***              C O N F I D E N T I A L  ---  W E S T W O O D  S T U D I O S               ***
     19  ***********************************************************************************************
     20  *                                                                                             *
     21  *                 Project Name : Command & Conquer                                            *
     22  *                                                                                             *
     23  *                    File Name : DISPLAY.CPP                                                  *
     24  *                                                                                             *
     25  *                   Programmer : Joe L. Bostic                                                *
     26  *                                                                                             *
     27  *                   Start Date : September 10, 1993                                           *
     28  *                                                                                             *
     29  *                  Last Update : October 20, 1996 [JLB]                                       *
     30  *                                                                                             *
     31  *---------------------------------------------------------------------------------------------*
     32  * Functions:                                                                                  *
     33  *   DisplayClass::Compute_Start_Pos -- Computes player's start pos from unit coords.          *
     34  *   DisplayClass::AI -- Handles the maintenance tasks for the map display.                    *
     35  *   DisplayClass::All_To_Look -- Direct all objects to look around for the player.            *
     36  *   DisplayClass::Calculated_Cell -- Fetch a map cell based on specified method.              *
     37  *   DisplayClass::Cell_Object -- Determines what has been clicked on.                         *
     38  *   DisplayClass::Cell_Shadow   -- Determine what shadow icon to use for the cell.            *
     39  *   DisplayClass::Center_Map -- Centers the map about the currently selected objects          *
     40  *   DisplayClass::Click_Cell_Calc -- Determines cell from screen X & Y.                       *
     41  *   DisplayClass::Closest_Free_Spot -- Finds the closest cell sub spot that is free.          *
     42  *   DisplayClass::Coord_To_Pixel -- Determines X and Y pixel coordinates.                     *
     43  *   DisplayClass::Cursor_Mark -- Set or resets the cursor display flag bits.                  *
     44  *   DisplayClass::DisplayClass -- Default constructor for display class.                      *
     45  *   DisplayClass::Draw_It -- Draws the tactical map.                                          *
     46  *   DisplayClass::Encroach_Shadow -- Causes the shadow to creep back by one cell.             *
     47  *   DisplayClass::Flag_Cell -- Flag the specified cell to be redrawn.                         *
     48  *   DisplayClass::Flag_To_Redraw -- Flags the display so that it will be redrawn as soon as poss*
     49  *   DisplayClass::Get_Occupy_Dimensions -- computes width & height of the given occupy list   *
     50  *   DisplayClass::Good_Reinforcement_Cell -- Checks cell for renforcement legality.           *
     51  *   DisplayClass::In_View -- Determines if cell is visible on screen.                         *
     52  *   DisplayClass::Init_Clear -- Clears the display to a known state.                          *
     53  *   DisplayClass::Init_IO -- Creates the map's button list                                    *
     54  *   DisplayClass::Init_Theater -- Theater-specific initialization                             *
     55  *   DisplayClass::Is_Spot_Free -- Determines if cell sub spot is free of occupation.          *
     56  *   DisplayClass::Map_Cell -- Mark specified cell as having been mapped.                      *
     57  *   DisplayClass::Mouse_Left_Held -- Handles the left button held down.                       *
     58  *   DisplayClass::Mouse_Left_Press -- Handles the left mouse button press.                    *
     59  *   DisplayClass::Mouse_Left_Release -- Handles the left mouse button release.                *
     60  *   DisplayClass::Mouse_Left_Up -- Handles the left mouse "cruising" over the map.            *
     61  *   DisplayClass::Mouse_Right_Press -- Handles the right mouse button press.                  *
     62  *   DisplayClass::Next_Object -- Searches for next object on display.                         *
     63  *   DisplayClass::One_Time -- Performs any special one time initializations.                  *
     64  *   DisplayClass::Passes_Proximity_Check -- Determines if building placement is near friendly sq*
     65  *   DisplayClass::Pixel_To_Coord -- converts screen coord to COORDINATE                       *
     66  *   DisplayClass::Prev_Object -- Searches for the previous object on the map.                 *
     67  *   DisplayClass::Read_INI -- Reads map control data from INI file.                           *
     68  *   DisplayClass::Redraw_Icons -- Draws all terrain icons necessary.                          *
     69  *   DisplayClass::Redraw_Shadow -- Draw the shadow overlay.                                   *
     70  *   DisplayClass::Refresh_Band -- Causes all cells under the rubber band to be redrawn.       *
     71  *   DisplayClass::Refresh_Cells -- Redraws all cells in list.                                 *
     72  *   DisplayClass::Remove -- Removes a game object from the rendering system.                  *
     73  *   DisplayClass::Repair_Mode_Control -- Controls the repair mode.                            *
     74  *   DisplayClass::Scroll_Map -- Scroll the tactical map in desired direction.                 *
     75  *   DisplayClass::Select_These -- All selectable objects in region are selected.              *
     76  *   DisplayClass::Sell_Mode_Control -- Controls the sell mode.                                *
     77  *   DisplayClass::Set_Cursor_Pos -- Controls the display and animation of the tac cursor.     *
     78  *   DisplayClass::Set_Cursor_Shape -- Changes the shape of the terrain square cursor.         *
     79  *   DisplayClass::Set_Tactical_Position -- Sets the tactical view position.                   *
     80  *   DisplayClass::Set_View_Dimensions -- Sets the tactical display screen coordinates.        *
     81  *   DisplayClass::Shroud_Cell -- Returns the specified cell into the shrouded condition.      *
     82  *   DisplayClass::Submit -- Adds a game object to the map rendering system.                   *
     83  *   DisplayClass::TacticalClass::Action -- Processes input for the tactical map.              *
     84  *   DisplayClass::Text_Overlap_List -- Creates cell overlap list for specified text string.   *
     85  *   DisplayClass::Write_INI -- Write the map data to the INI file specified.                  *
     86  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     87 
     88 #include	"function.h"
     89 #include	"vortex.h"
     90 
     91 /*
     92 **	These layer control elements are used to group the displayable objects
     93 **	so that proper overlap can be obtained.
     94 */
     95 LayerClass DisplayClass::Layer[LAYER_COUNT];
     96 
     97 /*
     98 ** Fading tables
     99 */
    100 unsigned char DisplayClass::FadingBrighten[256];
    101 unsigned char DisplayClass::FadingShade[256];
    102 unsigned char DisplayClass::FadingWayDark[256];
    103 unsigned char DisplayClass::FadingLight[256];
    104 unsigned char DisplayClass::FadingGreen[256];
    105 unsigned char DisplayClass::FadingYellow[256];
    106 unsigned char DisplayClass::FadingRed[256];
    107 unsigned char DisplayClass::TranslucentTable[(MAGIC_COL_COUNT+1)*256];
    108 unsigned char DisplayClass::WhiteTranslucentTable[(1+1)*256];
    109 unsigned char DisplayClass::MouseTranslucentTable[(4+1)*256];
    110 void const * DisplayClass::TransIconset;
    111 unsigned char DisplayClass::UnitShadow[(USHADOW_COL_COUNT+1)*256];
    112 unsigned char DisplayClass::UnitShadowAir[(USHADOW_COL_COUNT+1)*256];
    113 unsigned char DisplayClass::SpecialGhost[2*256];
    114 
    115 void const * DisplayClass::ShadowShapes;
    116 unsigned char DisplayClass::ShadowTrans[(SHADOW_COL_COUNT+1)*256];
    117 
    118 /*
    119 ** Bit array of cell redraw flags
    120 */
    121 BooleanVectorClass DisplayClass::CellRedraw;
    122 
    123 /*
    124 ** The main button that intercepts user input to the map
    125 */
    126 DisplayClass::TacticalClass DisplayClass::TacButton;
    127 
    128 //
    129 // We need a way to bypass visible view checks when we are running in the context of GlyphX without using the
    130 // internal C&C renderer. We shouldn't know or care what the user is actually looking at
    131 // ST - 4/17/2019 9:01AM
    132 //
    133 bool DisplayClass::IgnoreViewConstraints = false;
    134 
    135 
    136 static int const TEX_X = 0;
    137 static int const TEX_Y = 6;
    138 static int const TEX_W = 14;
    139 
    140 //Added for getting the input for special character keys from the client 
    141 // - 6/26/2019 JAS 
    142 extern bool DLL_Export_Get_Input_Key_State(KeyNumType key);
    143 
    144 
    145 /***********************************************************************************************
    146  * DisplayClass::DisplayClass -- Default constructor for display class.                        *
    147  *                                                                                             *
    148  *    This constructor for the display class just initializes some of the display settings.    *
    149  *    Most settings are initialized with the correct values at the time that the Init function *
    150  *    is called. There are some cases where default values are wise and this routine fills     *
    151  *    those particular ones in.                                                                *
    152  *                                                                                             *
    153  * INPUT:   none                                                                               *
    154  *                                                                                             *
    155  * OUTPUT:  none                                                                               *
    156  *                                                                                             *
    157  * WARNINGS:   none                                                                            *
    158  *                                                                                             *
    159  * HISTORY:                                                                                    *
    160  *   12/06/1994 JLB : Created.                                                                 *
    161  *=============================================================================================*/
    162 DisplayClass::DisplayClass(void) :
    163 	TacticalCoord(0),
    164 	TacLeptonWidth(0),
    165 	TacLeptonHeight(0),
    166 	ZoneCell(0),
    167 	ZoneOffset(0),
    168 	CursorSize(0),
    169 	ProximityCheck(false),
    170 	PendingObjectPtr(0),
    171 	PendingObject(0),
    172 	PendingHouse(HOUSE_NONE),
    173 	TacPixelX(0),
    174 	TacPixelY(0),
    175 	DesiredTacticalCoord(0),
    176 	IsToRedraw(true),
    177 	IsRepairMode(false),
    178 	IsSellMode(false),
    179 	IsTargettingMode(SPC_NONE),
    180 	IsRubberBand(false),
    181 	IsTentative(false),
    182 	IsShadowPresent(false),
    183 	BandX(0),
    184 	BandY(0),
    185 	NewX(0),
    186 	NewY(0)
    187 {
    188 	ShadowShapes = 0;
    189 	TransIconset = 0;
    190 
    191 	Set_View_Dimensions(0, 8, 320/CELL_PIXEL_W, 200/CELL_PIXEL_H);
    192 }
    193 
    194 
    195 /***********************************************************************************************
    196  * DisplayClass::One_Time -- Performs any special one time initializations.                    *
    197  *                                                                                             *
    198  *    This routine is called from the game initialization process. It is to perform any one    *
    199  *    time initializations necessary for the map display system. It allocates the staging      *
    200  *    buffer needed for the radar map.                                                         *
    201  *                                                                                             *
    202  * INPUT:   none                                                                               *
    203  *                                                                                             *
    204  * OUTPUT:  none                                                                               *
    205  *                                                                                             *
    206  * WARNINGS:   This routine must be called ONCE and only once.                                 *
    207  *                                                                                             *
    208  * HISTORY:                                                                                    *
    209  *   05/31/1994 JLB : Created.                                                                 *
    210  *   05/31/1994 JLB : Handles layer system now.                                                *
    211  *   06/02/1994 JLB : Takes care of misc display tables and data allocation.                   *
    212  *=============================================================================================*/
    213 void DisplayClass::One_Time(void)
    214 {
    215 	MapClass::One_Time();
    216 
    217 	/*
    218 	** Init the CellRedraw bit array.  Do not do this in the constructor, since the
    219 	** BooleanVector may not have been constructed yet.
    220 	*/
    221 	CellRedraw.Resize(MAP_CELL_TOTAL);
    222 
    223 	for (LayerType layer = LAYER_FIRST; layer < LAYER_COUNT; layer++) {
    224 		Layer[layer].One_Time();
    225 	}
    226 
    227 	/*
    228 	**	Load the generic transparent icon set.
    229 	*/
    230 	TransIconset = MFCD::Retrieve("TRANS.ICN");
    231 
    232 	#ifndef NDEBUG
    233 		RawFileClass file("SHADOW.SHP");
    234 		if (file.Is_Available()) {
    235 			ShadowShapes = Load_Alloc_Data(file);
    236 		} else {
    237 			ShadowShapes = MFCD::Retrieve("SHADOW.SHP");
    238 		}
    239 	#else
    240 		ShadowShapes = MFCD::Retrieve("SHADOW.SHP");
    241 	#endif
    242 
    243 	//PG Set_View_Dimensions(0, 8 * RESFACTOR);
    244 	Set_View_Dimensions(0, 0);
    245 }
    246 
    247 
    248 /***********************************************************************************************
    249  * DisplayClass::Init_Clear -- clears the display to a known state                             *
    250  *                                                                                             *
    251  * INPUT:                                                                                      *
    252  *      none.                                                                                  *
    253  *                                                                                             *
    254  * OUTPUT:                                                                                     *
    255  *      none.                                                                                  *
    256  *                                                                                             *
    257  * WARNINGS:                                                                                   *
    258  *      none.                                                                                  *
    259  *                                                                                             *
    260  * HISTORY:                                                                                    *
    261  *   03/17/1995 BRR : Created.                                                                 *
    262  *=============================================================================================*/
    263 void DisplayClass::Init_Clear(void)
    264 {
    265 	MapClass::Init_Clear();
    266 
    267 	/*
    268 	** Clear any object being placed
    269 	*/
    270 	PendingObjectPtr = 0;
    271 	PendingObject = 0;
    272 	PendingHouse = HOUSE_NONE;
    273 	CursorSize = 0;
    274 	IsTargettingMode = SPC_NONE;
    275 	IsRepairMode = false;
    276 	IsRubberBand = false;
    277 	IsTentative = false;
    278 	IsSellMode = false;
    279 
    280 	/*
    281 	** Empty all the display's layers
    282 	*/
    283 	for (LayerType layer = LAYER_FIRST; layer < LAYER_COUNT; layer++) {
    284 		Layer[layer].Init();
    285 	}
    286 }
    287 
    288 
    289 /***********************************************************************************************
    290  * DisplayClass::Init_IO -- clears & re-builds the map's button list                           *
    291  *                                                                                             *
    292  * INPUT:                                                                                      *
    293  *      none.                                                                                  *
    294  *                                                                                             *
    295  * OUTPUT:                                                                                     *
    296  *      none.                                                                                  *
    297  *                                                                                             *
    298  * WARNINGS:                                                                                   *
    299  *      none.                                                                                  *
    300  *                                                                                             *
    301  * HISTORY:                                                                                    *
    302  *   03/17/1995 BRR : Created.                                                                 *
    303  *=============================================================================================*/
    304 void DisplayClass::Init_IO(void)
    305 {
    306 	MapClass::Init_IO();
    307 	/*
    308 	** Re-attach our buttons to the main map button list, only in non-edit mode.
    309 	*/
    310 	if (!Debug_Map) {
    311 		TacButton.Zap();
    312 		Add_A_Button(TacButton);
    313 	}
    314 }
    315 
    316 
    317 /***********************************************************************************************
    318  * DisplayClass::Init_Theater -- Performs theater-specific initialization (mixfiles, etc)      *
    319  *                                                                                             *
    320  * INPUT:                                                                                      *
    321  *      theater         new theater                                                            *
    322  *                                                                                             *
    323  * OUTPUT:                                                                                     *
    324  *      none.                                                                                  *
    325  *                                                                                             *
    326  * WARNINGS:                                                                                   *
    327  *      none.                                                                                  *
    328  *                                                                                             *
    329  * HISTORY:                                                                                    *
    330  *   03/17/1995 BRR : Created.                                                                 *
    331  *   05/07/1996 JLB : Added translucent tables.                                                *
    332  *=============================================================================================*/
    333 void DisplayClass::Init_Theater(TheaterType theater)
    334 {
    335 	char			fullname[16];
    336 	static TLucentType const MouseCols[4] = {
    337 		{BLACK, BLACK, 110, 0},
    338 		{WHITE, WHITE, 110, 0},
    339 		{LTGREY, LTGREY, 110, 0},
    340 		{DKGREY, DKGREY, 110, 0}
    341 	};
    342 	static TLucentType const MagicCols[MAGIC_COL_COUNT] = {
    343 		{32,32,110,0},
    344 		{33,33,110,0},
    345 		{34,34,110,0},
    346 		{35,35,110,0},
    347 		{36,36,110,0},
    348 		{37,37,110,0},
    349 		{38,38,110,0},
    350 		{39,39,110,0},
    351 		{BLACK, BLACK, 200, 0},
    352 		{WHITE, BLACK, 40, 0},
    353 		{LTGREY, BLACK, 80, 0},
    354 		{DKGREY, BLACK, 140, 0},
    355 		{LTGREEN,	BLACK,130,0}
    356 	};
    357 	static TLucentType const WhiteCols[1] = {
    358 		{1, WHITE, 80, 0}
    359 	};
    360 	static TLucentType const ShadowCols[SHADOW_COL_COUNT] = {
    361 		{WHITE+1,	BLACK,130,0},
    362 		{WHITE,		BLACK,170,0},
    363 		{LTGRAY,		BLACK,250,0},
    364 		{DKGRAY,		BLACK,250,0}
    365 	};
    366 	static TLucentType const UShadowCols[USHADOW_COL_COUNT] = {
    367 		{LTGREEN,	BLACK,130,0}
    368 	};
    369 	static TLucentType const UShadowColsAir[USHADOW_COL_COUNT] = {
    370 		{LTGREEN,	WHITE,0,0}
    371 	};
    372 	static TLucentType const UShadowColsSnow[USHADOW_COL_COUNT] = {
    373 		{LTGREEN,	BLACK,75,0}
    374 	};
    375 
    376 	/*
    377 	**	Invoke parent's init routine.
    378 	*/
    379 	MapClass::Init_Theater(theater);
    380 
    381 	/*
    382 	** Save the new theater value
    383 	*/
    384 	Scen.Theater = theater;
    385 
    386 	/*
    387 	** Unload old mixfiles, and cache the new ones
    388 	*/
    389 	sprintf(fullname, "%s.MIX", Theaters[theater].Root);
    390 
    391 #ifndef WIN32
    392 LastTheater = THEATER_NONE;
    393 #endif
    394 
    395 	if (Scen.Theater != LastTheater) {
    396 		if (TheaterData != NULL) {
    397 			delete TheaterData;
    398 		}
    399 		TheaterData = new MFCD(fullname, &FastKey);
    400 		assert(TheaterData != NULL);
    401 
    402 		bool theaterload = TheaterData->Cache(TheaterBuffer);
    403 		assert(theaterload);
    404 //		LastTheater = Scen.Theater;
    405 	}
    406 
    407 	/*
    408 	**	Load the custom palette associated with this theater.
    409 	**	The fading palettes will have to be generated as well.
    410 	*/
    411 	sprintf(fullname, "%s.PAL", Theaters[theater].Root);
    412 	PaletteClass const * ptr = (PaletteClass *)MFCD::Retrieve(fullname);
    413 
    414 	GamePalette = * ptr;
    415 
    416 	OriginalPalette = GamePalette;
    417 
    418 	Build_Fading_Table(GamePalette.Get_Data(), FadingGreen, GREEN, 110);
    419 
    420 	Build_Fading_Table(GamePalette.Get_Data(), FadingYellow, YELLOW, 140);
    421 
    422 	Build_Fading_Table(GamePalette.Get_Data(), FadingRed, RED, 140);
    423 
    424 	Build_Translucent_Table(GamePalette, &MouseCols[0], 4, MouseTranslucentTable);
    425 
    426 	Build_Translucent_Table(GamePalette, &MagicCols[0], MAGIC_COL_COUNT, TranslucentTable);
    427 
    428 	Build_Translucent_Table(GamePalette, &WhiteCols[0], 1, WhiteTranslucentTable);
    429 
    430 	Build_Translucent_Table(GamePalette, &ShadowCols[0], SHADOW_COL_COUNT, ShadowTrans);
    431 
    432 	Conquer_Build_Translucent_Table(GamePalette, &UShadowColsAir[0], USHADOW_COL_COUNT, UnitShadowAir);
    433 	memcpy(&UnitShadowAir[256], ColorRemaps[PCOLOR_GOLD].RemapTable, sizeof(ColorRemaps[PCOLOR_GOLD].RemapTable));
    434 	if (theater == THEATER_SNOW) {
    435 		Conquer_Build_Translucent_Table(GamePalette, &UShadowColsSnow[0], USHADOW_COL_COUNT, UnitShadow);
    436 	} else {
    437 		Conquer_Build_Translucent_Table(GamePalette, &UShadowCols[0], USHADOW_COL_COUNT, UnitShadow);
    438 	}
    439 
    440 	if (theater == THEATER_SNOW) {
    441 		Conquer_Build_Fading_Table(GamePalette, FadingShade, BLACK, 75);
    442 	} else {
    443 		Conquer_Build_Fading_Table(GamePalette, FadingShade, BLACK, 130);
    444 	}
    445 
    446 	Conquer_Build_Fading_Table(GamePalette, FadingLight, WHITE, 85);
    447 
    448 	/*
    449 	**	Create the shadow color used by aircraft.
    450 	*/
    451 	Conquer_Build_Fading_Table(GamePalette, &SpecialGhost[256], BLACK, 100);
    452 	for (int index = 0; index < 256; index++) {
    453 		SpecialGhost[index] = 0;
    454 	}
    455 
    456 	Make_Fading_Table(GamePalette, FadingBrighten, WHITE, 25);
    457 
    458 	Make_Fading_Table(GamePalette, FadingWayDark, DKGRAY, 192);
    459 
    460 	/*
    461 	**	Adjust the palette according to the visual control option settings.
    462 	*/
    463 	Options.Fixup_Palette();
    464 }
    465 
    466 
    467 /***********************************************************************************************
    468  * DisplayClass::Text_Overlap_List -- Creates cell overlap list for specified text string.     *
    469  *                                                                                             *
    470  *    This routine is used to create an overlap list that specifies all the cells that are     *
    471  *    covered by the specified text string. This overlap list is used to handle map  refresh   *
    472  *    logic.                                                                                   *
    473  *                                                                                             *
    474  * INPUT:   text  -- Pointer to the text that would appear on the map and must have an         *
    475  *                   overlap list generated.                                                   *
    476  *                                                                                             *
    477  *          x,y   -- The coordinates that the text would appear (upper left corner).           *
    478  *                                                                                             *
    479  * OUTPUT:  Returns with a pointer to an overlap list that covers all cells "under" the text   *
    480  *          if were displayed at the coordinates specified. The list is actually a series of   *
    481  *          offsets from the display's upper left corner cell number.                          *
    482  *                                                                                             *
    483  * WARNINGS:   none                                                                            *
    484  *                                                                                             *
    485  * HISTORY:                                                                                    *
    486  *   12/06/1994 JLB : Created.                                                                 *
    487  *   12/07/1994 JLB : Sidebar fixup.                                                           *
    488  *   08/13/1995 JLB : Optimized for variable sized help text.                                  *
    489  *=============================================================================================*/
    490 short const * DisplayClass::Text_Overlap_List(char const * text, int x, int y) const
    491 {
    492 	static short _list[60];
    493 	int count = ARRAY_SIZE(_list);
    494 
    495 	if (text != NULL) {
    496 		short * ptr = &_list[0];
    497 		int len = String_Pixel_Width(text)+CELL_PIXEL_W;
    498 		int right = TacPixelX + Lepton_To_Pixel(TacLeptonWidth);
    499 
    500 		/*
    501 		**	If the help text would spill into the sidebar, then flag this fact, but
    502 		**	shorten the apparent length so that the icon list calculation will
    503 		**	function correctly.
    504 		*/
    505 		if (x+len >= TacPixelX+Lepton_To_Pixel(TacLeptonWidth)) {
    506 			len = right-x;
    507 			*ptr++ = REFRESH_SIDEBAR;
    508 			count--;
    509 		}
    510 
    511 		/*
    512 		**	Build the list of overlap cell offset values according to the text
    513 		**	coordinate and the length.
    514 		*/
    515 		if (x <= right) {
    516 			CELL ul = Click_Cell_Calc(x, y-1);
    517 			CELL lr = Click_Cell_Calc(x+len-1, Bound(y+24, TacPixelY, TacPixelY+Lepton_To_Pixel(TacLeptonHeight) - 1));
    518 
    519 			if (ul == -1) ul = Click_Cell_Calc(x, y);
    520 
    521 			if (ul != -1 && lr != -1) {
    522 				for (int yy = Cell_Y(ul); yy <= Cell_Y(lr); yy++) {
    523 					for (int xx = Cell_X(ul); xx <= Cell_X(lr); xx++) {
    524 						*ptr++ = XY_Cell(xx, yy) - Coord_Cell(TacticalCoord);
    525 						count--;
    526 						if (count < 2) break;
    527 					}
    528 					if (count < 2) break;
    529 				}
    530 			}
    531 		}
    532 
    533 		*ptr = REFRESH_EOL;
    534 	}
    535 	return(_list);
    536 }
    537 
    538 
    539 /***********************************************************************************************
    540  * DisplayClass::Set_View_Dimensions -- Sets the tactical display screen coordinates.          *
    541  *                                                                                             *
    542  *    Use this routine to set the tactical map screen coordinates and dimensions. This routine *
    543  *    is typically used when the screen size or position changes as a result of the sidebar    *
    544  *    changing position or appearance.                                                         *
    545  *                                                                                             *
    546  * INPUT:   x,y   -- The X and Y pixel position on the screen for the tactical map upper left  *
    547  *                   corner.                                                                   *
    548  *                                                                                             *
    549  *          width -- The width of the tactical display (in icons). If this parameter is        *
    550  *                   omitted, then the width will be as wide as the screen will allow.         *
    551  *                                                                                             *
    552  *          height-- The height of the tactical display (in icons). If this parameter is       *
    553  *                   omitted, then the width will be as wide as the screen will allow.         *
    554  *                                                                                             *
    555  * OUTPUT:  none                                                                               *
    556  *                                                                                             *
    557  * WARNINGS:   none                                                                            *
    558  *                                                                                             *
    559  * HISTORY:                                                                                    *
    560  *   12/06/1994 JLB : Created.                                                                 *
    561  *   06/27/1995 JLB : Adjusts tactical map position if necessary.                              *
    562  *=============================================================================================*/
    563 void DisplayClass::Set_View_Dimensions(int x, int y, int width, int height)
    564 {
    565 	if (width == -1) {
    566 		TacLeptonWidth = Pixel_To_Lepton(SeenBuff.Get_Width()-x);
    567 	} else {
    568 		TacLeptonWidth = width * CELL_LEPTON_W;
    569 	}
    570 
    571 	// ST - 3/1/2019 12:05PM
    572 	// Made the below code more consistent with the width calculation. This is needed if we aren't going to draw the tabs at the top of the screen
    573 	//
    574 	if (height == -1) {
    575 		TacLeptonHeight = Pixel_To_Lepton(SeenBuff.Get_Height() - y);
    576 		//height = (SeenBuff.Get_Height()-y) / CELL_PIXEL_H;
    577 	}
    578 	else {
    579 		TacLeptonHeight = height * CELL_LEPTON_H;
    580 	}
    581 	//TacLeptonHeight = height * CELL_LEPTON_H;
    582 
    583 	/*
    584 	**	Adjust the tactical cell if it is now in an invalid position
    585 	**	because of the changed dimensions.
    586 	*/
    587 	int xx = 0;// Coord_X(TacticalCoord) - (MapCellX * CELL_LEPTON_W);
    588 	int yy = 0;// Coord_Y(TacticalCoord) - (MapCellY * CELL_LEPTON_H);
    589 
    590 	Confine_Rect(&xx, &yy, TacLeptonWidth, TacLeptonHeight, MapCellWidth * CELL_LEPTON_W, MapCellHeight * CELL_LEPTON_H);
    591 
    592 	Set_Tactical_Position(XY_Coord(xx + (MapCellX * CELL_LEPTON_W), yy + (MapCellY * CELL_LEPTON_H)));
    593 
    594 	TacPixelX = x;
    595 	TacPixelY = y;
    596 	WindowList[WINDOW_TACTICAL][WINDOWX] = x;
    597 	WindowList[WINDOW_TACTICAL][WINDOWY] = y;
    598 	WindowList[WINDOW_TACTICAL][WINDOWWIDTH] = Lepton_To_Pixel(TacLeptonWidth);
    599 	WindowList[WINDOW_TACTICAL][WINDOWHEIGHT] = Lepton_To_Pixel(TacLeptonHeight);
    600 	if (Window == WINDOW_TACTICAL) {
    601 		Change_Window(0);
    602 		Change_Window(Window);
    603 	}
    604 	IsToRedraw = true;
    605 	Flag_To_Redraw(false);
    606 
    607 	TacButton.X = TacPixelX;
    608 	TacButton.Y = TacPixelY;
    609 	TacButton.Width = Lepton_To_Pixel(TacLeptonWidth);
    610 	TacButton.Height = Lepton_To_Pixel(TacLeptonHeight);
    611 }
    612 
    613 
    614 /***********************************************************************************************
    615  * DisplayClass::Set_Cursor_Shape -- Changes the shape of the terrain square cursor.           *
    616  *                                                                                             *
    617  *    This routine is used to set up the terrain cursor according to the size of the object    *
    618  *    that is to be placed down. The terrain cursor looks like an arbitrary collection of      *
    619  *    hatched square overlays. Typical use is when placing buildings.                          *
    620  *                                                                                             *
    621  * INPUT:   list  -- A pointer to the list that contains offsets to the cells that are to      *
    622  *                   be marked.                                                                *
    623  *                                                                                             *
    624  * OUTPUT:  none                                                                               *
    625  *                                                                                             *
    626  * WARNINGS:   none                                                                            *
    627  *                                                                                             *
    628  * HISTORY:                                                                                    *
    629  *   06/03/1994 JLB : Created.                                                                 *
    630  *   06/26/1995 JLB : Puts placement cursor into static buffer.                                *
    631  *=============================================================================================*/
    632 void DisplayClass::Set_Cursor_Shape(short const * list)
    633 {
    634 	if (CursorSize) {
    635 		Cursor_Mark(ZoneCell+ZoneOffset, false);
    636 	}
    637 	ZoneOffset = 0;
    638 
    639 	if (list) {
    640 		int	w,h;
    641 		static short _list[50];
    642 
    643 		memcpy(_list, list, sizeof(_list));
    644 		CursorSize = _list;
    645 		Get_Occupy_Dimensions (w, h, CursorSize);
    646 		ZoneOffset = -(((h/2)*MAP_CELL_W)+(w/2));
    647 		Cursor_Mark(ZoneCell+ZoneOffset, true);
    648 	} else {
    649 		CursorSize = 0;
    650 	}
    651 }
    652 
    653 
    654 /***********************************************************************************************
    655  * DisplayClass::Passes_Proximity_Check -- Determines if building placement is near friendly sq*
    656  *                                                                                             *
    657  *    This routine is used by the building placement cursor logic to determine whether the     *
    658  *    at the current cursor position if the building would be adjacent to another friendly     *
    659  *    building. In cases where this is not true, then the building cannot be placed at all.    *
    660  *    This determination is returned by the function.                                          *
    661  *                                                                                             *
    662  * INPUT:   object   -- The building object that the current placement system is examining.    *
    663  *                                                                                             *
    664  *          house    -- The house to base the proximity check upon. Typically this is the      *
    665  *                      player's house, but in multiplay, the computer needs to check for      *
    666  *                      proximity as well.                                                     *
    667  *                                                                                             *
    668  *          list     -- Pointer to the building's offset list.                                 *
    669  *                                                                                             *
    670  *          trycell  -- The cell to base the offset list on.                                   *
    671  *                                                                                             *
    672  * OUTPUT:  bool; Can the pending building object be placed at the present cursor location     *
    673  *                checking only for proximity to friendly buildings?  If this isn't for a      *
    674  *                building type object, then this routine always returns true.                 *
    675  *                                                                                             *
    676  * WARNINGS:   none                                                                            *
    677  *                                                                                             *
    678  * HISTORY:                                                                                    *
    679  *   06/06/1994 JLB : Created.                                                                 *
    680  *   06/07/1994 JLB : Handles concrete check.                                                  *
    681  *   10/11/1994 BWG : Added IsProximate check for ore refineries                               *
    682  *=============================================================================================*/
    683 bool DisplayClass::Passes_Proximity_Check(ObjectTypeClass const * object, HousesType house, short const * list, CELL trycell) const
    684 {
    685 	short const * ptr;
    686 	int retval = -1;
    687 	bool noradar = false;
    688 	//bool nomapped = false;			    // Not used. ST - 8/6/2019 10:51AM
    689 	bool shipyard = false;
    690 
    691 	if (house == PlayerPtr->Class->House) {
    692 		PassedProximity = false;
    693 	}
    694 
    695 	/*
    696 	** In editor mode, the proximity check always passes.
    697 	*/
    698 	if (Debug_Map) {
    699 		return(true);
    700 	}
    701 
    702 	if (list == NULL || trycell == 0) {
    703 		return(true);
    704 	}
    705 
    706 	if (object == NULL || object->What_Am_I() != RTTI_BUILDINGTYPE) {
    707 		return(true);
    708 	}
    709 
    710 	BuildingTypeClass const * building = (BuildingTypeClass const *)object;
    711 
    712 	/*
    713 	**	Scan through all cells that the building foundation would cover. If any adjacent
    714 	**	cells to these are of friendly persuasion, then consider the proximity check to
    715 	**	have been a success.
    716 	*/
    717 	ptr = list;
    718 //	ptr = CursorSize;
    719 	CELL cell = trycell;
    720 //	CELL cell = ZoneCell;
    721 	if (building->Adjacent == 1) {
    722 		while (*ptr != REFRESH_EOL && (retval == -1) ) {
    723 			cell = trycell + *ptr++;
    724 //			cell = ZoneCell + ZoneOffset + *ptr++;
    725 
    726 			if (!In_Radar(cell)) {
    727 				retval = false;
    728 				noradar = true;
    729 				break;
    730 			}
    731 
    732 			for (FacingType facing = FACING_FIRST; facing < FACING_COUNT; facing++) {
    733 				CELL	newcell = Adjacent_Cell(cell, facing);
    734 
    735 				if (!In_Radar(newcell)) continue;
    736 
    737 				// Code has no effect. ST - 8/6/2019 10:51AM
    738 				//if (!(*this)[newcell].IsMapped) {
    739 				//	nomapped = true;
    740 				//}
    741 				BuildingClass * base = (*this)[newcell].Cell_Building();
    742 
    743 				/*
    744 				**	The special cell ownership flag allows building adjacent
    745 				**	to friendly walls and bibs even though there is no official
    746 				**	building located there.
    747 				*/
    748 				//BG: Modified so only walls can be placed next to walls - buildings can't.
    749 				//JLB: Except for bibs, in which case buildings can be placed next to these.
    750 				if (building->IsWall ||
    751 					((*this)[newcell].Smudge != SMUDGE_NONE && SmudgeTypeClass::As_Reference((*this)[newcell].Smudge).IsBib)) {
    752 
    753 					if ((*this)[newcell].Owner == house) {
    754 						retval = true;
    755 						break;
    756 					}
    757 				}
    758 
    759 				// we've found a building...
    760 				if (base != NULL && base->House->Class->House == house && base->Class->IsBase) {
    761 					retval = true;
    762 					break;
    763 				}
    764 
    765 				/* BG: modifications to allow buildings one cell away from other buildings.
    766 				** This is done by scanning each cell that fails the check (hence getting
    767 				** to this point) and looking at the n/s/e/w adjacent cells to see if they
    768 				** have buildings in them.  If they do, and they match us, then succeed.
    769 				*/
    770 				if (retval != -1) break;
    771 
    772 				for (FacingType newface = FACING_N; newface < FACING_COUNT; newface++) {
    773 					CELL	newercell = Adjacent_Cell(newcell, newface);
    774 
    775 					if (building->IsWall ||
    776 									((*this)[newercell].Smudge != SMUDGE_NONE && SmudgeTypeClass::As_Reference((*this)[newercell].Smudge).IsBib)) {
    777 
    778 						if ((*this)[newercell].Owner == house) {
    779 							retval = true;
    780 							break;
    781 						}
    782 					}
    783 
    784 					TechnoClass * newbase = (*this)[newercell].Cell_Techno();
    785 
    786 					// we've found a building...
    787 					if (newbase != NULL && newbase->What_Am_I() == RTTI_BUILDING && newbase->House->Class->House == house && ((BuildingClass const *)newbase)->Class->IsBase) {
    788 						retval = true;
    789 						break;
    790 					}
    791 				}
    792 				if (retval != -1) break;
    793 			}
    794 		}
    795 	}
    796 
    797 	if (retval == -1) retval = false;
    798 
    799 	if (house == PlayerPtr->Class->House) {
    800 		PassedProximity = (retval != false);
    801 	}
    802 
    803 	/*
    804 	**	If this object has special dispensation to be placed further than one cell from
    805 	**	other regular buildings, then check for this case now. Only bother to check if
    806 	**	it hasn't already been given permission to be placed down.
    807 	*/
    808 	if (!retval && !noradar && object->What_Am_I() == RTTI_BUILDINGTYPE) {
    809 
    810 		// For land mines, let's make it check proximity within 10 squares
    811 		if (building->Adjacent > 1) {
    812 			for (int index = 0; index < Buildings.Count(); index++) {
    813 				BuildingClass * obj = Buildings.Ptr(index);
    814 				if (obj != NULL && !obj->IsInLimbo && obj->House->Class->House == house && obj->Class->IsBase) {
    815 					int centdist = ::Distance(obj->Center_Coord(), Cell_Coord(cell));
    816 					centdist /= CELL_LEPTON_W;
    817 					centdist -= (obj->Class->Width() + obj->Class->Height()) / 2;
    818 					if (centdist <= building->Adjacent) {
    819 						retval = true;
    820 						break;
    821 					}
    822 				}
    823 			}
    824 		}
    825 	}
    826 
    827 	return((bool)retval);
    828 }
    829 
    830 
    831 /***********************************************************************************************
    832  * DisplayClass::Set_Cursor_Pos -- Controls the display and animation of the tac cursor.       *
    833  *                                                                                             *
    834  *    This routine controls the location, display, and animation of the                        *
    835  *    tactical map cursor.                                                                     *
    836  *                                                                                             *
    837  * INPUT:   pos   -- Position to move the cursor do. If -1 is passed then                      *
    838  *                   the cursor will just be hidden. If the position                           *
    839  *                   passed is the same as the last position passed in,                        *
    840  *                   then animation could occur (based on timers).                             *
    841  *                                                                                             *
    842  * OUTPUT:     none                                                                            *
    843  *                                                                                             *
    844  * WARNINGS:   none                                                                            *
    845  *                                                                                             *
    846  * HISTORY:                                                                                    *
    847  *   05/22/1991 JLB : Created.                                                                 *
    848  *   06/02/1994 JLB : Converted to member function.                                            *
    849  *   06/08/1994 JLB : If position is -1, then follow mouse.                                    *
    850  *   02/28/1995 JLB : Forces placement cursor to fit on map.                                   *
    851  *=============================================================================================*/
    852 CELL DisplayClass::Set_Cursor_Pos(CELL pos)
    853 {
    854 	CELL	prevpos;			// Last position of cursor (for jump-back reasons).
    855 
    856 	/*
    857 	**	Follow the mouse position if no cell number is provided.
    858 	*/
    859 	if (pos == -1) {
    860 		pos = Click_Cell_Calc(Get_Mouse_X(), Get_Mouse_Y());
    861 	}
    862 
    863 	if (CursorSize == NULL) {
    864 		prevpos = ZoneCell;
    865 		ZoneCell = pos;
    866 		return(prevpos);
    867 	}
    868 
    869 	/*
    870 	**	Adjusts the position so that the placement cursor is never part way off the
    871 	**	tactical map.
    872 	*/
    873 	int w,h;
    874 	Get_Occupy_Dimensions(w, h, CursorSize);
    875 
    876 	int x = Cell_X(pos + ZoneOffset);
    877 	int y = Cell_Y(pos + ZoneOffset);
    878 
    879 	if (x < Coord_XCell(TacticalCoord)) x = Coord_XCell(TacticalCoord);
    880 	if (y < Coord_YCell(TacticalCoord)) y = Coord_YCell(TacticalCoord);
    881 	if (x+w >= Coord_XCell(TacticalCoord) + Lepton_To_Cell(TacLeptonWidth)) x = Coord_XCell(TacticalCoord)+Lepton_To_Cell(TacLeptonWidth)-w;
    882 	if (y+h >= Coord_YCell(TacticalCoord) + Lepton_To_Cell(TacLeptonHeight)) y = Coord_YCell(TacticalCoord)+Lepton_To_Cell(TacLeptonHeight)-h;
    883 	pos = XY_Cell(x, y) - ZoneOffset;
    884 
    885 	/*
    886 	** This checks to see if NO animation or drawing is to occur and, if so,
    887 	**	exits.
    888 	*/
    889 	if (pos == ZoneCell) return(pos);
    890 
    891 	prevpos = ZoneCell;
    892 
    893 	/*
    894 	**	If the cursor is visible, then handle the graphic update.
    895 	**	Otherwise, just update the global position of the cursor.
    896 	*/
    897 	if (CursorSize != NULL) {
    898 
    899 		/*
    900 		** Erase the old cursor (if it exists) AND the cursor is moving.
    901 		*/
    902 		if (pos != ZoneCell && ZoneCell != -1) {
    903 			Cursor_Mark(ZoneCell+ZoneOffset, false);
    904 		}
    905 
    906 		/*
    907 		** Render the cursor (could just be animation).
    908 		*/
    909 		if (pos != -1) {
    910 			Cursor_Mark(pos+ZoneOffset, true);
    911 		}
    912 	}
    913 	ZoneCell = pos;
    914 	ProximityCheck = Passes_Proximity_Check(PendingObject, PendingHouse, CursorSize, ZoneCell+ZoneOffset);
    915 
    916 	return(prevpos);
    917 }
    918 
    919 
    920 /***********************************************************************************************
    921  * DisplayClass::Get_Occupy_Dimensions -- computes width & height of the given occupy list     *
    922  *                                                                                             *
    923  * INPUT:                                                                                      *
    924  *      w      ptr to fill in with height                                                      *
    925  *      h      ptr to fill in with width                                                       *
    926  *                                                                                             *
    927  * OUTPUT:                                                                                     *
    928  *      none.                                                                                  *
    929  *                                                                                             *
    930  * WARNINGS:                                                                                   *
    931  *      none.                                                                                  *
    932  *                                                                                             *
    933  * HISTORY:                                                                                    *
    934  *   03/31/1995 BRR : Created.                                                                 *
    935  *=============================================================================================*/
    936 void DisplayClass::Get_Occupy_Dimensions(int & w, int & h, short const * list) const
    937 {
    938 	int min_x = MAP_CELL_W;
    939 	int max_x = -MAP_CELL_W;
    940 	int min_y = MAP_CELL_H;
    941 	int max_y = -MAP_CELL_H;
    942 	int x,y;
    943 
    944 	w = 0;
    945 	h = 0;
    946 
    947 	if (!list) {
    948 		/*
    949 		** Loop through all cell offsets, accumulating max & min x- & y-coords
    950 		*/
    951 		while (*list != REFRESH_EOL) {
    952 			/*
    953 			** Compute x & y coords of the current cell offset.  We can't use Cell_X()
    954 			** & Cell_Y(), because they use shifts to compute the values, and if the
    955 			** offset is negative we'll get a bogus coordinate!
    956 			*/
    957 			x = (*list) % MAP_CELL_W;
    958 			y = (*list) / MAP_CELL_H;
    959 
    960 			max_x = max(max_x, x);
    961 			min_x = min(min_x, x);
    962 			max_y = max(max_y, y);
    963 			min_y = min(min_y, y);
    964 
    965 			list++;
    966 		}
    967 
    968 		w = max(1, max_x - min_x + 1);
    969 		h = min(1, max_y - min_y + 1);
    970 	}
    971 }
    972 
    973 
    974 /***********************************************************************************************
    975  * DisplayClass::Cursor_Mark -- Set or resets the cursor display flag bits.                    *
    976  *                                                                                             *
    977  *    This routine will clear or set the cursor display bits on the map.                       *
    978  *    If the bit is set, then the cursor will be rendered on that map                          *
    979  *    icon.                                                                                    *
    980  *                                                                                             *
    981  * INPUT:   pos   -- Position of the upper left corner of the cursor.                          *
    982  *                                                                                             *
    983  *          on    -- Should the bit be turned on?                                              *
    984  *                                                                                             *
    985  * OUTPUT:  none                                                                               *
    986  *                                                                                             *
    987  * WARNINGS:   Be sure that every call to set the bits is matched by a                         *
    988  *             corresponding call to clear the bits.                                           *
    989  *                                                                                             *
    990  * HISTORY:                                                                                    *
    991  *   09/04/1991 JLB : Created.                                                                 *
    992  *   06/02/1994 JLB : Converted to member function.                                            *
    993  *=============================================================================================*/
    994 void DisplayClass::Cursor_Mark(CELL pos, bool on)
    995 {
    996 	CELL const * ptr;
    997 	CellClass * cellptr;
    998 
    999 	if ((unsigned)pos >= MAP_CELL_TOTAL) return;
   1000 
   1001 	/*
   1002 	**	For every cell in the CursorSize list, invoke its Redraw_Objects and
   1003 	**	toggle its IsCursorHere flag
   1004 	*/
   1005 	ptr = CursorSize;
   1006 	while (*ptr != REFRESH_EOL) {
   1007 		CELL cell = pos + *ptr++;
   1008 		if (In_Radar(cell)) {
   1009 			cellptr = &(*this)[cell];
   1010 			cellptr->Redraw_Objects();
   1011 			if (on) {
   1012 				cellptr->IsCursorHere = true;
   1013 			} else {
   1014 				cellptr->IsCursorHere = false;
   1015 			}
   1016 		}
   1017 	}
   1018 
   1019 	/*
   1020 	**	For every cell in the PendingObjectPtr's Overlap_List, invoke its
   1021 	**	Redraw_Objects routine.
   1022 	*/
   1023 	if (PendingObjectPtr && PendingObjectPtr->IsActive) {
   1024 		ptr = PendingObjectPtr->Overlap_List();
   1025 		while (*ptr != REFRESH_EOL) {
   1026 			CELL cell = pos + *ptr++;
   1027 			if (In_Radar(cell)) {
   1028 				cellptr = &(*this)[cell];
   1029 				cellptr->Redraw_Objects();
   1030 			}
   1031 		}
   1032 	}
   1033 }
   1034 
   1035 
   1036 /***********************************************************************************************
   1037  * DisplayClass::AI -- Handles the maintenance tasks for the map display.                      *
   1038  *                                                                                             *
   1039  *    This routine is called once per game display frame (15 times per second). It handles     *
   1040  *    the mouse shape tracking and map scrolling as necessary.                                 *
   1041  *                                                                                             *
   1042  * INPUT:   input -- The next key just fetched from the input queue.                           *
   1043  *                                                                                             *
   1044  *          x,y   -- Mouse coordinates.                                                        *
   1045  *                                                                                             *
   1046  * OUTPUT:  Modifies the input code if necessary. When the input code is consumed, it gets     *
   1047  *          set to 0.                                                                          *
   1048  *                                                                                             *
   1049  * WARNINGS:   none                                                                            *
   1050  *                                                                                             *
   1051  * HISTORY:                                                                                    *
   1052  *   06/01/1994 JLB : Created.                                                                 *
   1053  *   06/02/1994 JLB : Filters mouse click input.                                               *
   1054  *   06/07/1994 JLB : Fixed so template click will behave right.                               *
   1055  *   10/14/1994 JLB : Changing cursor shape over target.                                       *
   1056  *   12/31/1994 JLB : Takes mouse coordinates as parameters.                                   *
   1057  *   06/27/1995 JLB : Breaks out of rubber band mode if mouse leaves map.                      *
   1058  *=============================================================================================*/
   1059 void DisplayClass::AI(KeyNumType & input, int x, int y)
   1060 {
   1061 	if (
   1062 		IsRubberBand &&
   1063 		(Get_Mouse_X() < TacPixelX ||
   1064 		Get_Mouse_Y() < TacPixelY ||
   1065 		Get_Mouse_X() >= (TacPixelX + Lepton_To_Pixel(TacLeptonWidth)) ||
   1066 		Get_Mouse_Y() >= (TacPixelY + Lepton_To_Pixel(TacLeptonHeight)))) {
   1067 			Mouse_Left_Release(-1, Get_Mouse_X(), Get_Mouse_Y(), NULL, ACTION_NONE);
   1068 	}
   1069 
   1070 	MapClass::AI(input, x, y);
   1071 }
   1072 
   1073 
   1074 /***********************************************************************************************
   1075  * DisplayClass::Submit -- Adds a game object to the map rendering system.                     *
   1076  *                                                                                             *
   1077  *    This routine is used to add an arbitrary (but tangible) game object to the map. It will  *
   1078  *    be rendered (made visible) once it is submitted to this function. This function builds   *
   1079  *    the list of game objects that get rendered each frame as necessary. It is possible to    *
   1080  *    submit the game object to different rendering layers. All objects in a layer get drawn   *
   1081  *    at the same time. Using this layer method it becomes possible to have objects "below"    *
   1082  *    other objects.                                                                           *
   1083  *                                                                                             *
   1084  * INPUT:   object   -- Pointer to the object to add.                                          *
   1085  *                                                                                             *
   1086  *          layer    -- The layer to add the object to.                                        *
   1087  *                                                                                             *
   1088  * OUTPUT:  none                                                                               *
   1089  *                                                                                             *
   1090  * WARNINGS:   none                                                                            *
   1091  *                                                                                             *
   1092  * HISTORY:                                                                                    *
   1093  *   05/31/1994 JLB : Created.                                                                 *
   1094  *   05/31/1994 JLB : Improved layer system.                                                   *
   1095  *   05/31/1994 JLB : Sorts object position if this is for the ground layer.                   *
   1096  *=============================================================================================*/
   1097 void DisplayClass::Submit(ObjectClass const * object, LayerType layer)
   1098 {
   1099 	if (object) {
   1100 		Layer[layer].Submit(object, (layer == LAYER_GROUND));
   1101 	}
   1102 }
   1103 
   1104 
   1105 /***********************************************************************************************
   1106  * DisplayClass::Remove -- Removes a game object from the rendering system.                    *
   1107  *                                                                                             *
   1108  *    Every object that is to disappear from the map must be removed from the rendering        *
   1109  *    system.                                                                                  *
   1110  *                                                                                             *
   1111  * INPUT:   object   -- The object to remove.                                                  *
   1112  *                                                                                             *
   1113  *          layer    -- The layer to remove it from.                                           *
   1114  *                                                                                             *
   1115  * OUTPUT:  none                                                                               *
   1116  *                                                                                             *
   1117  * WARNINGS:   none                                                                            *
   1118  *                                                                                             *
   1119  * HISTORY:                                                                                    *
   1120  *   05/31/1994 JLB : Created.                                                                 *
   1121  *   05/31/1994 JLB : Improved layer system.                                                   *
   1122  *=============================================================================================*/
   1123 void DisplayClass::Remove(ObjectClass const * object, LayerType layer)
   1124 {
   1125 	assert(object != 0);
   1126 	assert(object->IsActive);
   1127 
   1128 	if (object) {
   1129 		Layer[layer].Delete((ObjectClass *)object);
   1130 	}
   1131 }
   1132 
   1133 
   1134 /***********************************************************************************************
   1135  * DisplayClass::Click_Cell_Calc -- Determines cell from screen X & Y.                         *
   1136  *                                                                                             *
   1137  *    This routine is used to determine the cell that is located at the                        *
   1138  *    screen pixel coordinates given. Typical use is when the player                           *
   1139  *    clicks with the mouse on the tactical map.                                               *
   1140  *                                                                                             *
   1141  * INPUT:   x,y   -- Screen pixel coordinates.                                                 *
   1142  *                                                                                             *
   1143  * OUTPUT:  Returns with cell that is under the coordinates specified.                         *
   1144  *          If the coordinate specified is outside of the tactical                             *
   1145  *          map, then -1 is returned.                                                          *
   1146  *                                                                                             *
   1147  * WARNINGS:   none                                                                            *
   1148  *                                                                                             *
   1149  * HISTORY:                                                                                    *
   1150  *   05/27/1994 JLB : Created.                                                                 *
   1151  *=============================================================================================*/
   1152 CELL DisplayClass::Click_Cell_Calc(int x, int y) const
   1153 {
   1154 	x -= TacPixelX;
   1155 	x = Pixel_To_Lepton(x);
   1156 	y -= TacPixelY;
   1157 	y = Pixel_To_Lepton(y);
   1158 
   1159 	// Possibly ignore the view constraints if we aren't using the internal renderer. ST - 8/5/2019 11:56AM
   1160 	if (IgnoreViewConstraints || (unsigned)x < TacLeptonWidth && (unsigned)y < TacLeptonHeight) {
   1161 		COORDINATE tcoord = XY_Coord(Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(TacticalCoord))), Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(TacticalCoord))));
   1162 		return(Coord_Cell(Coord_Add(tcoord, XY_Coord(x, y))));
   1163 	}
   1164 	return(-1);
   1165 }
   1166 
   1167 
   1168 /***********************************************************************************************
   1169  * DisplayClass::Scroll_Map -- Scroll the tactical map in desired direction.                   *
   1170  *                                                                                             *
   1171  *    This routine is used to scroll the tactical map view in the desired                      *
   1172  *    direction. It can also be used to determine if scrolling would be                        *
   1173  *    legal without actually performing any scrolling action.                                  *
   1174  *                                                                                             *
   1175  * INPUT:   facing   -- The direction to scroll the tactical map.                              *
   1176  *                                                                                             *
   1177  *          distance -- The distance in leptons to scroll the map.                             *
   1178  *                                                                                             *
   1179  *          really   -- Should the map actually be scrolled?  If false,                        *
   1180  *                      then only the legality of a scroll is checked.                         *
   1181  *                                                                                             *
   1182  * OUTPUT:  bool; Would scrolling in the desired direction be possible?                        *
   1183  *                                                                                             *
   1184  * WARNINGS:   none                                                                            *
   1185  *                                                                                             *
   1186  * HISTORY:                                                                                    *
   1187  *   10/07/1992 JLB : Created.                                                                 *
   1188  *   05/20/1994 JLB : Converted to member function.                                            *
   1189  *   08/09/1995 JLB : Added distance parameter.                                                *
   1190  *   08/10/1995 JLB : Any direction scrolling.                                                 *
   1191  *=============================================================================================*/
   1192 bool DisplayClass::Scroll_Map(DirType facing, int & distance, bool really)
   1193 {
   1194 	/*
   1195 	**	If the distance is invalid then no further checking is required. Bail
   1196 	**	with a no-can-do flag.
   1197 	*/
   1198 	if (distance == 0) return(false);
   1199 	FacingType crude = Dir_Facing(facing);
   1200 
   1201 	if (Coord_X(TacticalCoord) == Cell_To_Lepton(MapCellX) && crude != FACING_W) {
   1202 		if (crude == FACING_SW) facing = DIR_S;
   1203 		if (crude == FACING_NW) facing = DIR_N;
   1204 	}
   1205 	if (Coord_Y(TacticalCoord) == Cell_To_Lepton(MapCellY) && crude != FACING_N) {
   1206 		if (crude == FACING_NW) facing = DIR_W;
   1207 		if (crude == FACING_NE) facing = DIR_E;
   1208 	}
   1209 	if (Coord_X(TacticalCoord) + TacLeptonWidth == Cell_To_Lepton(MapCellX+MapCellWidth) && crude != FACING_E) {
   1210 		if (crude == FACING_NE) facing = DIR_N;
   1211 		if (crude == FACING_SE) facing = DIR_S;
   1212 	}
   1213 	if (Coord_Y(TacticalCoord) + TacLeptonHeight == Cell_To_Lepton(MapCellY+MapCellHeight) && crude != FACING_S) {
   1214 		if (crude == FACING_SE) facing = DIR_E;
   1215 		if (crude == FACING_SW) facing = DIR_W;
   1216 	}
   1217 
   1218 	/*
   1219 	**	Determine the coordinate that it wants to scroll to.
   1220 	*/
   1221 	COORDINATE coord = Coord_Move(TacticalCoord, facing, distance);
   1222 
   1223 	/*
   1224 	**	Clip the new coordinate to the edges of the game world.
   1225 	*/
   1226 	int xx = (int)(short)Coord_X(coord) - (short)Cell_To_Lepton(MapCellX);
   1227 	int yy = (int)(short)Coord_Y(coord) - (short)Cell_To_Lepton(MapCellY);
   1228 	bool shifted = Confine_Rect(&xx, &yy, TacLeptonWidth, TacLeptonHeight, Cell_To_Lepton(MapCellWidth), Cell_To_Lepton(MapCellHeight));
   1229 	if (xx < 0) {
   1230 		xx = 0;
   1231 		shifted = true;
   1232 	}
   1233 	if (yy < 0) {
   1234 		yy = 0;
   1235 		shifted = true;
   1236 	}
   1237 	coord = XY_Coord(xx + Cell_To_Lepton(MapCellX), yy + Cell_To_Lepton(MapCellY));
   1238 
   1239 	/*
   1240 	**	If the desired scroll was bound by the edge of the map, then adjust the distance to more accurately
   1241 	**	reflect the actual distance moved.
   1242 	*/
   1243 	if (shifted) {
   1244 		distance = Distance(TacticalCoord, coord);
   1245 	}
   1246 
   1247 	/*
   1248 	**	If the new coordinate is the same as the old, then no scrolling would occur.
   1249 	*/
   1250 	if (!distance || coord == TacticalCoord) return(false);
   1251 
   1252 	/*
   1253 	**	Since the new coordinate is different than the old one, possibly adjust the real
   1254 	**	tactical map accordingly.
   1255 	*/
   1256 	if (really) {
   1257 		Set_Tactical_Position(coord);
   1258 		IsToRedraw = true;
   1259 		Flag_To_Redraw(false);
   1260 
   1261 		/*
   1262 		**	Scrolled map REQUIRES all top layer units to be redrawn.
   1263 		*/
   1264 		int index;
   1265 		for (index = 0; index < Layer[LAYER_TOP].Count(); index++) {
   1266 			Layer[LAYER_TOP][index]->Mark(MARK_CHANGE);
   1267 		}
   1268 		for (index = 0; index < Layer[LAYER_AIR].Count(); index++) {
   1269 			Layer[LAYER_AIR][index]->Mark(MARK_CHANGE);
   1270 		}
   1271 
   1272 
   1273 	}
   1274 	return(true);
   1275 }
   1276 
   1277 
   1278 /***********************************************************************************************
   1279  * DisplayClass::Refresh_Cells -- Redraws all cells in list.                                   *
   1280  *                                                                                             *
   1281  *    This routine is used to flag all cells in the specified list for                         *
   1282  *    redrawing.                                                                               *
   1283  *                                                                                             *
   1284  * INPUT:   cell  -- The origin cell that the list is offset from.                             *
   1285  *                                                                                             *
   1286  *          list  -- Pointer to a list of offsets from the origin cell.                        *
   1287  *                   Each cell so specified is flagged for redraw.                             *
   1288  *                                                                                             *
   1289  * OUTPUT:  none                                                                               *
   1290  *                                                                                             *
   1291  * WARNINGS:   This routine is rather slow (by definition).                                    *
   1292  *                                                                                             *
   1293  * HISTORY:                                                                                    *
   1294  *   05/14/1994 JLB : Created.                                                                 *
   1295  *   08/01/1994 JLB : Simplified.                                                              *
   1296  *=============================================================================================*/
   1297 void DisplayClass::Refresh_Cells(CELL cell, short const * list)
   1298 {
   1299 	short tlist[36];
   1300 
   1301 	if (*list == REFRESH_SIDEBAR) {
   1302 		list++;
   1303 	}
   1304 
   1305 	List_Copy(list, ARRAY_SIZE(tlist), tlist);
   1306 	short * tt = tlist;
   1307 	int count = 0;
   1308 	while (*tt != REFRESH_EOL) {
   1309 		if (count >= ARRAY_SIZE(tlist)) {  // Added overrun check. ST - 8/14/2019 3:14PM		
   1310 			break;
   1311 		}
   1312 		CELL newcell = cell + *tt++;
   1313 		if (In_Radar(newcell)) {
   1314 			(*this)[newcell].Redraw_Objects();
   1315 		}
   1316 		count++;
   1317 	}
   1318 }
   1319 
   1320 
   1321 /***********************************************************************************************
   1322  * DisplayClass::Cell_Shadow   -- Determine what shadow icon to use for the cell.              *
   1323  *                                                                                             *
   1324  *    This routine will examine the specified cell and adjacent cells to                       *
   1325  *    determine what shadow icon to use.                                                       *
   1326  *                                                                                             *
   1327  * INPUT:   cell     -- The cell to examine.                                                   *
   1328  *                                                                                             *
   1329  * OUTPUT:  Returns with the shadow icon to use. -2= all black.                                *
   1330  *                                                -1= map cell.                                *
   1331  *                                                                                             *
   1332  * WARNINGS:   none                                                                            *
   1333  *                                                                                             *
   1334  * HISTORY:                                                                                    *
   1335  *   03/01/1994 JLB : Created.                                                                 *
   1336  *   04/04/1994 JLB : Revamped for new shadow icon method.                                     *
   1337  *   04/30/1994 JLB : Converted to member function.                                            *
   1338  *   08/05/2019  ST : Added house parameter so we can do this per player                       ** 
   1339  *=============================================================================================*/
   1340 int DisplayClass::Cell_Shadow(CELL cell, HouseClass *house) const
   1341 {
   1342 	static char const _shadow[256]={
   1343 		-1,33, 2, 2,34,37, 2, 2,
   1344 		 4,26, 6, 6, 4,26, 6, 6,
   1345 		35,45,17,17,38,41,17,17,
   1346 		 4,26, 6, 6, 4,26, 6, 6,
   1347 		 8,21,10,10,27,31,10,10,
   1348 		12,23,14,14,12,23,14,14,
   1349 		 8,21,10,10,27,31,10,10,
   1350 		12,23,14,14,12,23,14,14,
   1351 
   1352 		32,36,25,25,44,40,25,25,
   1353 		19,30,20,20,19,30,20,20,
   1354 		39,43,29,29,42,46,29,29,
   1355 		19,30,20,20,19,30,20,20,
   1356 		 8,21,10,10,27,31,10,10,
   1357 		12,23,14,14,12,23,14,14,
   1358 		 8,21,10,10,27,31,10,10,
   1359 		12,23,14,14,12,23,14,14,
   1360 
   1361 		 1, 1, 3, 3,16,16, 3, 3,
   1362 		 5, 5, 7, 7, 5, 5, 7, 7,
   1363 		24,24,18,18,28,28,18,18,
   1364 		 5, 5, 7, 7, 5, 5, 7, 7,
   1365 		 9, 9,11,11,22,22,11,11,
   1366 		13,13,-2,-2,13,13,-2,-2,
   1367 		 9, 9,11,11,22,22,11,11,
   1368 		13,13,-2,-2,13,13,-2,-2,
   1369 
   1370 		 1, 1, 3, 3,16,16, 3, 3,
   1371 		 5, 5, 7, 7, 5, 5, 7, 7,
   1372 		24,24,18,18,28,28,18,18,
   1373 		 5, 5, 7, 7, 5, 5, 7, 7,
   1374 		 9, 9,11,11,22,22,11,11,
   1375 		13,13,-2,-2,13,13,-2,-2,
   1376 		 9, 9,11,11,22,22,11,11,
   1377 		13,13,-2,-2,13,13,-2,-2
   1378 	};
   1379 
   1380 	int index = 0, value = -1;
   1381 
   1382 	/*
   1383 	**	Don't map cells that are at the edges. This solves
   1384 	**	problem of accessing cells off the bounds of map and into
   1385 	**	who-knows-what memory.
   1386 	*/
   1387 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   1388 	if ((unsigned)(Cell_X(cell)-1) >= MAP_CELL_W-2) return(-1);
   1389 	if ((unsigned)(Cell_Y(cell)-1) >= MAP_CELL_H-2) return(-1);
   1390 #else
   1391 	if ((unsigned)(Cell_Y(cell)-1) > MAP_CELL_H-2) return(-1);
   1392 #endif
   1393 	//if ((unsigned)(Cell_Y(cell)-1) > MAP_CELL_H-2) return(-2);
   1394 
   1395 	CellClass const * cellptr = &(*this)[cell];
   1396 
   1397 	/*
   1398 	**	Presume solid black if that is what is here already.
   1399 	*/
   1400 	if (!cellptr->Is_Visible(house) && !cellptr->Is_Mapped(house)) value = -2;
   1401 
   1402 	if (cellptr->Is_Mapped(house) /*&& !cellptr->IsVisible*/) {
   1403 		/*
   1404 		** Build an index into the lookup table using all 8 surrounding cells.
   1405 		** We're mapping a revealed cell and we only care about the existence
   1406 		** of black cells.  Bit numbering starts at the upper-right corner and
   1407 		** goes around the cell clockwise, so 0x80 = directly north.
   1408 		*/
   1409 		cell -= MAP_CELL_W + 1; cellptr -= MAP_CELL_W + 1;
   1410 		if (!cellptr->Is_Mapped(house) && In_Radar(cell)) index |= 0x40;
   1411 		cell++; cellptr++;
   1412 		if (!cellptr->Is_Mapped(house) && In_Radar(cell)) index |= 0x80;
   1413 		cell++; cellptr++;
   1414 		if (!cellptr->Is_Mapped(house) && In_Radar(cell)) index |= 0x01;
   1415 		cell += MAP_CELL_W - 2; cellptr += MAP_CELL_W - 2;
   1416 		if (!cellptr->Is_Mapped(house) && In_Radar(cell)) index |= 0x20;
   1417 		cell += 2; cellptr += 2;
   1418 		if (!cellptr->Is_Mapped(house) && In_Radar(cell)) index |= 0x02;
   1419 		cell += MAP_CELL_W - 2; cellptr += MAP_CELL_W - 2;
   1420 		if (!cellptr->Is_Mapped(house) && In_Radar(cell)) index |= 0x10;
   1421 		cell++; cellptr++;
   1422 		if (!cellptr->Is_Mapped(house) && In_Radar(cell)) index |= 0x08;
   1423 		cell++; cellptr++;
   1424 		if (!cellptr->Is_Mapped(house) && In_Radar(cell)) index |= 0x04;
   1425 
   1426 		value = _shadow[index];
   1427 	}
   1428 	return(value);
   1429 }
   1430 
   1431 
   1432 #if (0)		                            // Old code for reference. ST - 8/15/2019 10:25AM
   1433 /***********************************************************************************************
   1434  * DisplayClass::Cell_Shadow   -- Determine what shadow icon to use for the cell.              *
   1435  *                                                                                             *
   1436  *    This routine will examine the specified cell and adjacent cells to                       *
   1437  *    determine what shadow icon to use.                                                       *
   1438  *                                                                                             *
   1439  * INPUT:   cell     -- The cell to examine.                                                   *
   1440  *                                                                                             *
   1441  * OUTPUT:  Returns with the shadow icon to use. -2= all black.                                *
   1442  *                                                -1= map cell.                                *
   1443  *                                                                                             *
   1444  * WARNINGS:   none                                                                            *
   1445  *                                                                                             *
   1446  * HISTORY:                                                                                    *
   1447  *   03/01/1994 JLB : Created.                                                                 *
   1448  *   04/04/1994 JLB : Revamped for new shadow icon method.                                     *
   1449  *   04/30/1994 JLB : Converted to member function.                                            *
   1450  *=============================================================================================*/
   1451 int DisplayClass::Cell_Shadow(CELL cell) const
   1452 {
   1453 	static char const _shadow[256]={
   1454 		-1,33, 2, 2,34,37, 2, 2,
   1455 		 4,26, 6, 6, 4,26, 6, 6,
   1456 		35,45,17,17,38,41,17,17,
   1457 		 4,26, 6, 6, 4,26, 6, 6,
   1458 		 8,21,10,10,27,31,10,10,
   1459 		12,23,14,14,12,23,14,14,
   1460 		 8,21,10,10,27,31,10,10,
   1461 		12,23,14,14,12,23,14,14,
   1462 
   1463 		32,36,25,25,44,40,25,25,
   1464 		19,30,20,20,19,30,20,20,
   1465 		39,43,29,29,42,46,29,29,
   1466 		19,30,20,20,19,30,20,20,
   1467 		 8,21,10,10,27,31,10,10,
   1468 		12,23,14,14,12,23,14,14,
   1469 		 8,21,10,10,27,31,10,10,
   1470 		12,23,14,14,12,23,14,14,
   1471 
   1472 		 1, 1, 3, 3,16,16, 3, 3,
   1473 		 5, 5, 7, 7, 5, 5, 7, 7,
   1474 		24,24,18,18,28,28,18,18,
   1475 		 5, 5, 7, 7, 5, 5, 7, 7,
   1476 		 9, 9,11,11,22,22,11,11,
   1477 		13,13,-2,-2,13,13,-2,-2,
   1478 		 9, 9,11,11,22,22,11,11,
   1479 		13,13,-2,-2,13,13,-2,-2,
   1480 
   1481 		 1, 1, 3, 3,16,16, 3, 3,
   1482 		 5, 5, 7, 7, 5, 5, 7, 7,
   1483 		24,24,18,18,28,28,18,18,
   1484 		 5, 5, 7, 7, 5, 5, 7, 7,
   1485 		 9, 9,11,11,22,22,11,11,
   1486 		13,13,-2,-2,13,13,-2,-2,
   1487 		 9, 9,11,11,22,22,11,11,
   1488 		13,13,-2,-2,13,13,-2,-2
   1489 	};
   1490 
   1491 	int index = 0, value = -1;
   1492 
   1493 	/*
   1494 	**	Don't map cells that are at the top or bottom edge. This solves
   1495 	**	problem of accessing cells off the top or bottom of the map and into
   1496 	**	who-knows-what memory.
   1497 	*/
   1498 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   1499 	if ((unsigned)(Cell_Y(cell)-1) >= MAP_CELL_H-2) return(-1);
   1500 #else
   1501 	if ((unsigned)(Cell_Y(cell)-1) > MAP_CELL_H-2) return(-1);
   1502 #endif
   1503 	//if ((unsigned)(Cell_Y(cell)-1) > MAP_CELL_H-2) return(-2);
   1504 
   1505 	CellClass const * cellptr = &(*this)[cell];
   1506 
   1507 	/*
   1508 	**	Presume solid black if that is what is here already.
   1509 	*/
   1510 	if (!cellptr->IsVisible && !cellptr->IsMapped) value = -2;
   1511 
   1512 	if (cellptr->IsMapped /*&& !cellptr->IsVisible*/) {
   1513 		/*
   1514 		** Build an index into the lookup table using all 8 surrounding cells.
   1515 		** We're mapping a revealed cell and we only care about the existence
   1516 		** of black cells.  Bit numbering starts at the upper-right corner and
   1517 		** goes around the cell clockwise, so 0x80 = directly north.
   1518 		*/
   1519 		cellptr-= MAP_CELL_W + 1;
   1520 		if (!cellptr->IsMapped) index |= 0x40;
   1521 		cellptr++;
   1522 		if (!cellptr->IsMapped) index |= 0x80;
   1523 		cellptr++;
   1524 		if (!cellptr->IsMapped) index |= 0x01;
   1525 		cellptr += MAP_CELL_W - 2;
   1526 		if (!cellptr->IsMapped) index |= 0x20;
   1527 		cellptr += 2;
   1528 		if (!cellptr->IsMapped) index |= 0x02;
   1529 		cellptr += MAP_CELL_W - 2;
   1530 		if (!cellptr->IsMapped) index |= 0x10;
   1531 		cellptr++;
   1532 		if (!cellptr->IsMapped) index |= 0x08;
   1533 		cellptr++;
   1534 		if (!cellptr->IsMapped) index |= 0x04;
   1535 
   1536 		value = _shadow[index];
   1537 	}
   1538 	return(value);
   1539 }
   1540 #endif
   1541 
   1542 /***********************************************************************************************
   1543  * DisplayClass::Map_Cell -- Mark specified cell as having been mapped.                        *
   1544  *                                                                                             *
   1545  *    This routine maps the specified cell. The cell must not already                          *
   1546  *    have been mapped and the mapping player must be the human.                               *
   1547  *    This routine will update any adjacent cell map icon as appropriate.                      *
   1548  *                                                                                             *
   1549  * INPUT:   cell  -- The cell to be mapped.                                                    *
   1550  *                                                                                             *
   1551  *          house -- The player that is doing the mapping.                                     *
   1552  *                                                                                             *
   1553  * OUTPUT:  bool; Was action taken to map this cell?                                           *
   1554  *                                                                                             *
   1555  * WARNINGS:   none.                                                                           *
   1556  *                                                                                             *
   1557  * HISTORY:                                                                                    *
   1558  *   08/05/1992 JLB : Created.                                                                 *
   1559  *   04/30/1994 JLB : Converted to member function.                                            *
   1560  *   05/24/1994 JLB : Takes pointer to HouseClass.                                             *
   1561  *   02/20/1996 JLB : Allied units reveal the map for the player.                              *
   1562  *   08/05/2019  ST : Use per-player mapping so we can track the shroud for all players        *
   1563  *=============================================================================================*/
   1564 bool DisplayClass::Map_Cell(CELL cell, HouseClass * house, bool check_radar_spied, bool and_for_allies)
   1565 {
   1566 	// OK for house not to be PlayerPtr. ST - 8/6/2019 10:05AM
   1567 	//if (house != PlayerPtr || !In_Radar(cell)) return(false);
   1568 	if (house == NULL || !In_Radar(cell)) return(false);
   1569 	
   1570 	if (!house->IsHuman) {
   1571 		if (!ShareAllyVisibility || !and_for_allies && !check_radar_spied) {
   1572 			return false;
   1573 		}
   1574 	}
   1575 	
   1576 	/*
   1577 	** First check for the condition where we're spying on a house's radar
   1578 	** facility, to see if his mapping is applicable to us.
   1579 	*/
   1580 	if (Session.Type != GAME_GLYPHX_MULTIPLAYER) {
   1581 		// Original code. ST - 8/15/2019 10:26AM
   1582 		if (house && house != PlayerPtr) {
   1583 			if (house->RadarSpied & (1<<(PlayerPtr->Class->House))) house = PlayerPtr;
   1584 			if (Session.Type == GAME_NORMAL && house->Is_Ally(PlayerPtr)) house = PlayerPtr;
   1585 		}
   1586 	} else {
   1587 		// Version to work with any human player, not just PlayerPtr
   1588 		if (house && check_radar_spied) {
   1589 			
   1590 			for (int i=0 ; i<Session.Players.Count() ; i++) {
   1591 				HouseClass *player_ptr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
   1592 				if (player_ptr->IsHuman) {
   1593 					if (house->RadarSpied & (1<<(player_ptr->Class->House))) {
   1594 						Map_Cell(cell, player_ptr, false, false);
   1595 					}
   1596 				}
   1597 			}
   1598 		}
   1599 	}
   1600 
   1601 	/*
   1602 	** Maybe also recurse to map for allies
   1603 	*/
   1604 	if (ShareAllyVisibility && and_for_allies && Session.Type == GAME_GLYPHX_MULTIPLAYER) {
   1605 		
   1606 		for (int i=0 ; i<Session.Players.Count() ; i++) {
   1607 			HouseClass *player_ptr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
   1608 			if (player_ptr && player_ptr->IsActive && player_ptr->IsHuman) {
   1609 				if (player_ptr != house && house->Is_Ally(player_ptr)) {
   1610 					Map_Cell(cell, player_ptr, check_radar_spied, false);
   1611 				}
   1612 			}
   1613 		}
   1614 	}
   1615 
   1616 	CellClass * cellptr = &(*this)[cell];
   1617 
   1618 	/*
   1619 	**	Don't bother remapping this cell if it is already mapped.
   1620 	*/
   1621 #if (1)	
   1622 	if (cellptr->Is_Mapped(house)) {
   1623 		if (!cellptr->Is_Visible(house)) {
   1624 			cellptr->Redraw_Objects();
   1625 		}
   1626 		return(false);
   1627 	}
   1628 #else
   1629 	if (cellptr->IsMapped) {
   1630 		if (!cellptr->IsVisible) {
   1631 			cellptr->Redraw_Objects();
   1632 		}
   1633 		return(false);
   1634 	}
   1635 #endif
   1636 	/*
   1637 	** Mark the cell as being mapped. This must be done first because
   1638 	**	if the IsVisible flag must be set, then it might affect the
   1639 	**	adjacent cell processing.
   1640 	*/
   1641 	// Set per player. ST - 8/6/2019 10:18AM
   1642 	cellptr->Set_Mapped(house);
   1643 	cellptr->Redraw_Objects();
   1644 	if (Cell_Shadow(cell, house) == -1) {
   1645 		cellptr->Set_Visible(house);
   1646 	}
   1647 
   1648 	/*
   1649 	**	Check out all adjacent cells to see if they need
   1650 	**	to be mapped as well. This is necessary because of the
   1651 	**	"unique" method of showing shadowed cells. Many combinations
   1652 	**	are not allowed, and to fix this, just map the cells until
   1653 	**	all is ok.
   1654 	*/
   1655 	int xx = Cell_X(cell);
   1656 	for (FacingType dir = FACING_FIRST; dir < FACING_COUNT; dir++) {
   1657 		int	shadow;
   1658 		CELL	c;
   1659 		int xdiff;
   1660 
   1661 		c = Adjacent_Cell(cell, dir);
   1662 
   1663 		/*
   1664 		**	Determine if the map edge has been wrapped. If so,
   1665 		**	then don't process the cell.
   1666 		*/
   1667 		if ((unsigned)c >= MAP_CELL_TOTAL) continue;
   1668 		xdiff = Cell_X(c) - xx;
   1669 		xdiff = ABS(xdiff);
   1670 		if (xdiff > 1) continue;
   1671 
   1672 		CellClass * cptr = &(*this)[c];
   1673 		cptr->Redraw_Objects();
   1674 
   1675 #if (1)
   1676 		// New client/server friendly code
   1677 		if (c != cell && !cptr->Is_Visible(house)) {
   1678 			shadow = Cell_Shadow(c, house);
   1679 
   1680 			if (shadow == -1) {
   1681 				if (!cptr->Is_Mapped(house)) {
   1682 					Map_Cell(c, house, check_radar_spied, false);
   1683 				} else {
   1684 					cptr->Set_Visible(house);
   1685 				}
   1686 			} else {
   1687 				if (shadow != -2 && !cptr->Is_Mapped(house)) {
   1688 					Map_Cell(c, house, check_radar_spied, false);
   1689 				}
   1690 			}
   1691 		}
   1692 #else
   1693 		// Old peer/peer code
   1694 		if (c != cell && !cptr->IsVisible) {
   1695 			shadow = Cell_Shadow(c);
   1696 
   1697 			if (shadow == -1) {
   1698 				if (!cptr->IsMapped) {
   1699 					Map_Cell(c, house);
   1700 				} else {
   1701 					cptr->IsVisible = true;
   1702 				}
   1703 			} else {
   1704 				if (shadow != -2 && !cptr->IsMapped) {
   1705 					Map_Cell(c, house);
   1706 				}
   1707 			}
   1708 		}
   1709 #endif
   1710 	}
   1711 
   1712 	TechnoClass * tech = (*this)[cell].Cell_Techno();
   1713 	if (tech) {
   1714 		tech->Revealed(house);
   1715 	}
   1716 	return(true);
   1717 }
   1718 
   1719 
   1720 /***********************************************************************************************
   1721  * DisplayClass::Coord_To_Pixel -- Determines X and Y pixel coordinates.                       *
   1722  *                                                                                             *
   1723  *    This is the routine that figures out the location on the screen for                      *
   1724  *    a specified coordinate. It is one of the fundamental routines                            *
   1725  *    necessary for rendering the game objects. It performs some quick                         *
   1726  *    tests to see if the coordinate is in a visible region and returns                        *
   1727  *    this check as a boolean value.                                                           *
   1728  *                                                                                             *
   1729  * INPUT:   coord -- The coordinate to check.                                                  *
   1730  *                                                                                             *
   1731  *          x,y   -- Reference to the pixel coordinates that this                              *
   1732  *                   coordinate would be when rendered.                                        *
   1733  *                                                                                             *
   1734  * OUTPUT:  bool; Is this coordinate in a visible portion of the map?                          *
   1735  *                                                                                             *
   1736  * WARNINGS:   If the coordinate is not in a visible portion of the                            *
   1737  *             map, then this X and Y parameters are not set.                                  *
   1738  *                                                                                             *
   1739  * HISTORY:                                                                                    *
   1740  *   05/14/1994 JLB : Created.                                                                 *
   1741  *   12/15/1994 JLB : Converted to member function.                                            *
   1742  *   01/07/1995 JLB : Uses inline functions to extract coord components.                       *
   1743  *   08/09/1995 JLB : Uses new coordinate system.                                              *
   1744  *=============================================================================================*/
   1745 #define	EDGE_ZONE	(CELL_LEPTON_W*2)
   1746 bool DisplayClass::Coord_To_Pixel(COORDINATE coord, int &x, int &y) const
   1747 {
   1748 	int xtac = Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(TacticalCoord)));
   1749 	int xoff = Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(coord)));
   1750 	xoff = (xoff + EDGE_ZONE) - xtac;
   1751 
   1752 	int ytac = Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(TacticalCoord)));
   1753 	int yoff = Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(coord)));
   1754 	yoff = (yoff + EDGE_ZONE) - ytac;
   1755 
   1756 	x = Lepton_To_Pixel(xoff) - CELL_PIXEL_W * 2;
   1757 	y = Lepton_To_Pixel(yoff) - CELL_PIXEL_H * 2;
   1758 
   1759 	// Possibly ignore the view constraints if we aren't using the internal renderer. ST - 4/17/2019 9:06AM
   1760 	return(coord && (IgnoreViewConstraints || ((xoff <= TacLeptonWidth + EDGE_ZONE * 2) && (yoff <= TacLeptonHeight + EDGE_ZONE * 2))));
   1761 }
   1762 
   1763 #if (0) //reference. ST - 5/8/2019
   1764 bool DisplayClass::Coord_To_Pixel(COORDINATE coord, int &x, int &y) const
   1765 {
   1766 	if (coord) {
   1767 		int xtac = Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(TacticalCoord)));
   1768 		int xoff = Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(coord)));
   1769 
   1770 		xoff = (xoff+EDGE_ZONE) - xtac;
   1771 		if ((unsigned)xoff <= TacLeptonWidth + EDGE_ZONE*2) {
   1772 			int ytac = Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(TacticalCoord)));
   1773 			int yoff = Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(coord)));
   1774 
   1775 			yoff = (yoff+EDGE_ZONE) - ytac;
   1776 			if ((unsigned)yoff <= TacLeptonHeight + EDGE_ZONE*2) {
   1777 				x = Lepton_To_Pixel(xoff)-CELL_PIXEL_W*2;
   1778 				y = Lepton_To_Pixel(yoff)-CELL_PIXEL_H*2;
   1779 				return(true);
   1780 			}
   1781 		}
   1782 	}
   1783 	return(false);
   1784 }
   1785 #endif
   1786 
   1787 /***********************************************************************************************
   1788  * DisplayClass::Push_Onto_TacMap -- Moves x & y coords to being on tactical map               *
   1789  *                                                                                             *
   1790  * This routine expects a line to be drawn between SOURCE & DEST, so it pushes the coords to   *
   1791  * be within the region bounded by TacMapX,Y - + TacMapW,H.                                    *
   1792  *                                                                                             *
   1793  * INPUT:   source, dest -- References to the coordinates to check.                            *
   1794  *                                                                                             *
   1795  *                                                                                             *
   1796  * OUTPUT:  bool; Are these coordinates in a visible portion of the map?                       *
   1797  *                Returns true if the pushed source & dest are visible, but if neither are     *
   1798  *                within the map, then it returns false.                                       *
   1799  *                                                                                             *
   1800  *                                                                                             *
   1801  * HISTORY:                                                                                    *
   1802  *   03/27/1995 BWG : Created.                                                                 *
   1803  *=============================================================================================*/
   1804 bool DisplayClass::Push_Onto_TacMap(COORDINATE & source, COORDINATE & dest)
   1805 {
   1806 	if (!source || !dest) return(false);
   1807 
   1808 	int x1 = Coord_X(source);
   1809 	int y1 = Coord_Y(source);
   1810 	int x2 = Coord_X(dest);
   1811 	int y2 = Coord_Y(dest);
   1812 	int left = Coord_X(TacticalCoord);
   1813 	int right = Coord_X(TacticalCoord) + TacLeptonWidth;
   1814 	int top = Coord_Y(TacticalCoord);
   1815 	int bottom = Coord_Y(TacticalCoord) + TacLeptonHeight;
   1816 
   1817 	if (x1 < left && x2 < left) return(false);
   1818 	if (x1 > right && x2 > right) return(false);
   1819 	if (y1 < top && y2 < top) return(false);
   1820 	if (y1 > bottom && y2 > bottom) return(false);
   1821 
   1822 	x1 = Bound(x1, left, right);
   1823 	x2 = Bound(x2, left, right);
   1824 	y1 = Bound(y1, top, bottom);
   1825 	y2 = Bound(y2, top, bottom);
   1826 
   1827 	source = XY_Coord(x1, y1);
   1828 	dest = XY_Coord(x2, y2);
   1829 	return(true);
   1830 }
   1831 
   1832 
   1833 /***********************************************************************************************
   1834  * DisplayClass::Cell_Object -- Determines what has been clicked on.                           *
   1835  *                                                                                             *
   1836  *    This routine is used to determine what the player has clicked on.                        *
   1837  *    It is passed the cell that the click was on and it then examines                         *
   1838  *    the cell and returns with a pointer to the object that is there.                         *
   1839  *                                                                                             *
   1840  * INPUT:   cell  -- The cell that has been clicked upon.                                      *
   1841  *                                                                                             *
   1842  *          x,y   -- Optional offsets from the upper left corner of the cell to be used in     *
   1843  *                   determining exactly which object in the cell is desired.                  *
   1844  *                                                                                             *
   1845  * OUTPUT:  Returns with a pointer to the object that is "clickable" in                        *
   1846  *          the specified cell.                                                                *
   1847  *                                                                                             *
   1848  * WARNINGS:   none                                                                            *
   1849  *                                                                                             *
   1850  * HISTORY:                                                                                    *
   1851  *   05/14/1994 JLB : Created.                                                                 *
   1852  *=============================================================================================*/
   1853 ObjectClass * DisplayClass::Cell_Object(CELL cell, int x, int y) const
   1854 {
   1855 	return(*this)[cell].Cell_Object(x, y);
   1856 }
   1857 
   1858 
   1859 /***********************************************************************************************
   1860  * DisplayClass::Draw_It -- Draws the tactical map.                                            *
   1861  *                                                                                             *
   1862  *    This will draw the tactical map at the recorded position.   This                         *
   1863  *    routine is used whenever the tactical map moves or needs to be                           *
   1864  *    completely redrawn. It will handle making the necessary adjustments                      *
   1865  *    to accomodate a moving cursor.                                                           *
   1866  *                                                                                             *
   1867  * INPUT:      forced   -- bool; force redraw of the entire display?                           *
   1868  *                                                                                             *
   1869  * OUTPUT:     none                                                                            *
   1870  *                                                                                             *
   1871  * WARNINGS:   none                                                                            *
   1872  *                                                                                             *
   1873  * HISTORY:                                                                                    *
   1874  *   04/15/1991 JLB : Created. (benchmark = 292)                                               *
   1875  *   04/15/1991 JLB : Added _cell2meta[] reference array (206)                                 *
   1876  *   04/15/1991 JLB : Added actual map reference for terrain (207)                             *
   1877  *   04/16/1991 JLB : _cell2meta converted to int (194)                                        *
   1878  *   04/16/1991 JLB : References actual CellIcon[] array (204)                                 *
   1879  *   04/16/1991 JLB : Cell size increased to 16 x 16 (167)                                     *
   1880  *   04/17/1991 JLB : Cell based tactical map rendering (165)                                  *
   1881  *   04/22/1991 JLB : Uses Draw_Stamp() for icon rendering (426)                               *
   1882  *   04/22/1991 JLB : Draw_Stamp uses LogicPage now (276)                                      *
   1883  *   04/23/1991 JLB : Map active location cursor (334)                                         *
   1884  *   05/02/1991 JLB : Added smoothing and 3 icons sets (431)                                   *
   1885  *   05/22/1991 JLB : Broken into Draw_Map() and Refresh_Map().                                *
   1886  *   09/14/1991 JLB : Uses Refresh_Cell when new cells scroll onto display.                    *
   1887  *   05/12/1992 JLB : Destination page support.                                                *
   1888  *   02/14/1994 JLB : Revamped.                                                                *
   1889  *   05/01/1994 JLB : Converted to member function.                                            *
   1890  *   12/15/1994 JLB : Updated to work with display hierarchy.                                  *
   1891  *   12/24/1994 JLB : Examines redraw bit intelligently.                                       *
   1892  *   12/24/1994 JLB : Combined with old Refresh_Map() function.                                *
   1893  *   01/10/1995 JLB : Rubber band drawing.                                                     *
   1894  *=============================================================================================*/
   1895  void DisplayClass::Draw_It(bool forced)
   1896 {
   1897 	int	x,y;			// Working cell index values.
   1898 
   1899 	MapClass::Draw_It(forced);
   1900 
   1901 	if (IsToRedraw || forced) {
   1902 		BStart(BENCH_TACTICAL);
   1903 		IsToRedraw = false;
   1904 
   1905 		/*
   1906 		**	In rubber band mode, mark all cells under the "rubber band" to be
   1907 		**	redrawn.
   1908 		*/
   1909 		Refresh_Band();
   1910 
   1911 		/*
   1912 		** Mark all cells under the vortex to be redrawn
   1913 		*/
   1914 		ChronalVortex.Set_Redraw();
   1915 
   1916 
   1917 		/*
   1918 		** If the multiplayer message system is displaying one or more messages,
   1919 		** flag all cells covered by the messages to redraw.  This will prevent
   1920 		** messages from smearing the map if it scrolls.
   1921 		*/
   1922 		int num = Session.Messages.Num_Messages();
   1923 		if (num > 0) {
   1924 			CELL cell;
   1925 			for (cell = Coord_Cell(TacticalCoord); cell < Coord_Cell(TacticalCoord) + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
   1926 				(*this)[cell].Redraw_Objects();
   1927 			}
   1928 			for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W;
   1929 				cell < Coord_Cell(TacticalCoord) + MAP_CELL_W + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
   1930 				(*this)[cell].Redraw_Objects();
   1931 			}
   1932 			if (num > 1) {
   1933 				for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W*2;
   1934 					cell < Coord_Cell(TacticalCoord) + MAP_CELL_W*2 + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
   1935 					(*this)[cell].Redraw_Objects();
   1936 				}
   1937 			}
   1938 			if (num > 2) {
   1939 				for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W*3;
   1940 					cell < Coord_Cell(TacticalCoord) + MAP_CELL_W*3 + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
   1941 					(*this)[cell].Redraw_Objects();
   1942 				}
   1943 			}
   1944 			if (num > 3) {
   1945 				for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W*4;
   1946 					cell < Coord_Cell(TacticalCoord) + MAP_CELL_W*4 + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
   1947 					(*this)[cell].Redraw_Objects();
   1948 				}
   1949 			}
   1950 		}
   1951 
   1952 		/*
   1953 		**	Check for a movement of the tactical map. If there has been some
   1954 		**	movement, then part (or all) of the icons must be redrawn.
   1955 		*/
   1956 		if (Lepton_To_Pixel(Coord_X(DesiredTacticalCoord)) != Lepton_To_Pixel(Coord_X(TacticalCoord)) ||
   1957 			Lepton_To_Pixel(Coord_Y(DesiredTacticalCoord)) != Lepton_To_Pixel(Coord_Y(TacticalCoord))) {
   1958 
   1959 			int xmod = Lepton_To_Pixel(Coord_X(DesiredTacticalCoord));
   1960 			int ymod = Lepton_To_Pixel(Coord_Y(DesiredTacticalCoord));
   1961 
   1962 			int oldx = Lepton_To_Pixel(Coord_X(TacticalCoord))-xmod;		// Old relative offset.
   1963 			int oldy = Lepton_To_Pixel(Coord_Y(TacticalCoord))-ymod;
   1964 
   1965 			int oldw = Lepton_To_Pixel(TacLeptonWidth)-ABS(oldx);			// Replicable width.
   1966 			int oldh = Lepton_To_Pixel(TacLeptonHeight)-ABS(oldy);		// Replicable height.
   1967 
   1968 			if (oldw < 1) forced = true;
   1969 			if (oldh < 1) forced = true;
   1970 
   1971 
   1972 #ifdef WIN32		//For WIN32 only redraw the edges of the map that move into view
   1973 
   1974 			/*
   1975 			** Work out which map edges need to be redrawn
   1976 			*/
   1977 			BOOL redraw_right = (oldx < 0) ? true : false;		//Right hand edge
   1978 			BOOL redraw_left  = (oldx > 0) ? true : false;		//Left hand edge
   1979 			BOOL redraw_bottom= (oldy < 0) ? true : false;		//Bottom edge
   1980 			BOOL redraw_top	= (oldy > 0) ? true : false;		//Top edge
   1981 
   1982 			/*
   1983 			**	Blit any replicable block to avoid having to drawstamp.
   1984 			*/
   1985 			if (!forced && (oldw != Lepton_To_Pixel(TacLeptonWidth) || oldh != Lepton_To_Pixel(TacLeptonHeight))) {
   1986 				Set_Cursor_Pos(-1);
   1987 
   1988 				/*
   1989 				** If hid page is in video memory then blit from the seen page to avoid blitting
   1990 				**  an overlapped region.
   1991 				*/
   1992 				if (HidPage.Get_IsDirectDraw()) {
   1993 					Hide_Mouse();
   1994 							SeenBuff.Blit(HidPage,
   1995 									((oldx < 0) ? -oldx : 0) +TacPixelX,
   1996 									((oldy < 0) ? -oldy : 0) +TacPixelY,
   1997 									((oldx < 0) ? 0 : oldx) +TacPixelX,
   1998 									((oldy < 0) ? 0 : oldy) +TacPixelY,
   1999 									oldw,
   2000 									oldh);
   2001 					Show_Mouse();
   2002 				} else {
   2003 					HidPage.Blit(HidPage,
   2004 									((oldx < 0) ? -oldx : 0) +TacPixelX,
   2005 									((oldy < 0) ? -oldy : 0) +TacPixelY,
   2006 									((oldx < 0) ? 0 : oldx) +TacPixelX,
   2007 									((oldy < 0) ? 0 : oldy) +TacPixelY,
   2008 									oldw,
   2009 									oldh);
   2010 				}
   2011 
   2012 			} else {
   2013 				forced = true;
   2014 			}
   2015 
   2016 			if (oldx < 0) oldx = 0;
   2017 			if (oldy < 0) oldy = 0;
   2018 
   2019 			/*
   2020 			** Record new map position for future reference.
   2021 			*/
   2022 			ScenarioInit++;
   2023 			Set_Tactical_Position(DesiredTacticalCoord);
   2024 			ScenarioInit--;
   2025 
   2026 			if (!forced) {
   2027 
   2028 				/*
   2029 				**
   2030 				**	Set the 'redraw stamp' bit for any cells that could not be copied.
   2031 				**
   2032 				*/
   2033 				int startx = -Lepton_To_Pixel(Coord_XLepton(TacticalCoord));
   2034 				int starty = -Lepton_To_Pixel(Coord_YLepton(TacticalCoord));
   2035 				oldw -= 24;
   2036 				oldh -= 24;
   2037 
   2038 				if (abs(oldx) < 0x25 && abs(oldy) < 0x25) {
   2039 
   2040 					/*
   2041 					** The width of the area we redraw depends on the scroll speed
   2042 					*/
   2043 					int extra_x = (abs(oldx)>=16) ? 2 : 1;
   2044 					int extra_y = (abs(oldy)>=16) ? 2 : 1;
   2045 
   2046 					/*
   2047 					** Flag the cells across the top of the visible area if required
   2048 					*/
   2049 					if (redraw_top) {
   2050 						for (y = starty; y <= starty+CELL_PIXEL_H*extra_y; y += CELL_PIXEL_H) {
   2051 							for (x = startx; x <= Lepton_To_Pixel(TacLeptonWidth)+((CELL_PIXEL_W*2)); x += CELL_PIXEL_W) {
   2052 								CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
   2053 											Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
   2054 
   2055 								if (c > 0) (*this)[c].Redraw_Objects(true);
   2056 							}
   2057 						}
   2058 					}
   2059 
   2060 					/*
   2061 					** Flag the cells across the bottom of the visible area if required
   2062 					*/
   2063 					if (redraw_bottom) {
   2064 						for (y = Lepton_To_Pixel(TacLeptonHeight)-CELL_PIXEL_H*(1+extra_y); y <= Lepton_To_Pixel(TacLeptonHeight)+CELL_PIXEL_H*3; y += CELL_PIXEL_H) {
   2065 							for (x = startx; x <= Lepton_To_Pixel(TacLeptonWidth)+((CELL_PIXEL_W*2)); x += CELL_PIXEL_W) {
   2066 								CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
   2067 											Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
   2068 
   2069 								if (c > 0) (*this)[c].Redraw_Objects(true);
   2070 							}
   2071 						}
   2072 					}
   2073 
   2074 					/*
   2075 					** Flag the cells down the left of the visible area if required
   2076 					*/
   2077 					if (redraw_left) {
   2078 						for (x = startx; x <= startx + CELL_PIXEL_W*extra_x; x += CELL_PIXEL_W) {
   2079 							for (y = starty; y <= Lepton_To_Pixel(TacLeptonHeight)+((CELL_PIXEL_H*2)); y += CELL_PIXEL_H) {
   2080 								CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
   2081 											Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
   2082 
   2083 								if (c > 0) (*this)[c].Redraw_Objects(true);
   2084 							}
   2085 						}
   2086 					}
   2087 
   2088 					/*
   2089 					** Flag the cells down the right of the visible area if required
   2090 					*/
   2091 					if (redraw_right) {
   2092 						for (x = Lepton_To_Pixel(TacLeptonWidth)-CELL_PIXEL_W*(extra_x+1); x <= Lepton_To_Pixel(TacLeptonWidth)+CELL_PIXEL_W*3; x += CELL_PIXEL_W) {
   2093 							for (y = starty; y <= Lepton_To_Pixel(TacLeptonHeight)+((CELL_PIXEL_H*2)); y += CELL_PIXEL_H) {
   2094 								CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
   2095 											Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
   2096 
   2097 								if (c > 0) (*this)[c].Redraw_Objects(true);
   2098 							}
   2099 						}
   2100 					}
   2101 
   2102 				} else {
   2103 
   2104 					/*
   2105 					**	Set the 'redraw stamp' bit for any cells that could not be copied.
   2106 					*/
   2107 					int startx = -Lepton_To_Pixel(Coord_XLepton(TacticalCoord));
   2108 					int starty = -Lepton_To_Pixel(Coord_YLepton(TacticalCoord));
   2109 					oldw -= 24;
   2110 					oldh -= 24;
   2111 					for (y = starty; y <= Lepton_To_Pixel(TacLeptonHeight)+((CELL_PIXEL_H*2)); y += CELL_PIXEL_H) {
   2112 						for (x = startx; x <= Lepton_To_Pixel(TacLeptonWidth)+((CELL_PIXEL_W*2)); x += CELL_PIXEL_W) {
   2113 							if (x <= oldx || x >= oldx+oldw || y <= oldy || y >= oldy+oldh) {
   2114 								CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
   2115 											Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
   2116 
   2117 								if (c > 0) {
   2118 									(*this)[c].Redraw_Objects(true);
   2119 								}
   2120 							}
   2121 						}
   2122 					}
   2123 				}
   2124 			}
   2125 
   2126 		} else {
   2127 
   2128 			/*
   2129 			**	Set the tactical coordinate just in case the desired tactical has changed but
   2130 			**	not enough to result in any visible map change. This is likely to occur with very
   2131 			**	slow scroll rates.
   2132 			*/
   2133 			ScenarioInit++;
   2134 			if (DesiredTacticalCoord != TacticalCoord) {
   2135 				Set_Tactical_Position(DesiredTacticalCoord);
   2136 			}
   2137 			ScenarioInit--;
   2138 		}
   2139 
   2140 
   2141 #else	//WIN32
   2142 			/*
   2143 			**	Blit any replicable block to avoid having to drawstamp.
   2144 			*/
   2145 			if (!forced && (oldw != Lepton_To_Pixel(TacLeptonWidth) || oldh != Lepton_To_Pixel(TacLeptonHeight))) {
   2146 				Set_Cursor_Pos(-1);
   2147 
   2148 				HidPage.Blit(HidPage,
   2149 								((oldx < 0) ? -oldx : 0) +TacPixelX,
   2150 								((oldy < 0) ? -oldy : 0) +TacPixelY,
   2151 								((oldx < 0) ? 0 : oldx) +TacPixelX,
   2152 								((oldy < 0) ? 0 : oldy) +TacPixelY,
   2153 								oldw,
   2154 								oldh);
   2155 			} else {
   2156 				forced = true;
   2157 			}
   2158 
   2159 			if (oldx < 0) oldx = 0;
   2160 			if (oldy < 0) oldy = 0;
   2161 
   2162 			/*
   2163 			** Record new map position for future reference.
   2164 			*/
   2165 			ScenarioInit++;
   2166 			Set_Tactical_Position(DesiredTacticalCoord);
   2167 			ScenarioInit--;
   2168 
   2169 			if (!forced) {
   2170 
   2171 				/*
   2172 				**	Set the 'redraw stamp' bit for any cells that could not be copied.
   2173 				*/
   2174 				int startx = -Lepton_To_Pixel(Coord_XLepton(TacticalCoord));
   2175 				int starty = -Lepton_To_Pixel(Coord_YLepton(TacticalCoord));
   2176 				oldw -= 24;
   2177 				oldh -= 24;
   2178 				for (y = starty; y <= Lepton_To_Pixel(TacLeptonHeight)+((CELL_PIXEL_H*2)); y += CELL_PIXEL_H) {
   2179 					for (x = startx; x <= Lepton_To_Pixel(TacLeptonWidth)+((CELL_PIXEL_W*2)); x += CELL_PIXEL_W) {
   2180 						if (x <= oldx || x >= oldx+oldw || y <= oldy || y >= oldy+oldh) {
   2181 							CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
   2182 										Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
   2183 
   2184 							if (c > 0) {
   2185 								(*this)[c].Redraw_Objects(true);
   2186 							}
   2187 						}
   2188 					}
   2189 				}
   2190 			}
   2191 
   2192 		} else {
   2193 
   2194 			/*
   2195 			**	Set the tactical coordinate just in case the desired tactical has changed but
   2196 			**	not enough to result in any visible map change. This is likely to occur with very
   2197 			**	slow scroll rates.
   2198 			*/
   2199 			ScenarioInit++;
   2200 			if (DesiredTacticalCoord != TacticalCoord) {
   2201 				Set_Tactical_Position(DesiredTacticalCoord);
   2202 			}
   2203 			ScenarioInit--;
   2204 		}
   2205 #endif
   2206 
   2207 		/*
   2208 		**	If the entire tactical map is forced to be redrawn, then set all the redraw flags
   2209 		**	and let the normal processing take care of the rest.
   2210 		*/
   2211 		if (forced) {
   2212 			CellRedraw.Set();
   2213 		}
   2214 
   2215 		/*
   2216 		**	The first order of business is to redraw all the underlying icons that are
   2217 		**	flagged to be redrawn.
   2218 		*/
   2219 		if (HidPage.Lock()) {
   2220 			Redraw_Icons();
   2221 
   2222 			/*
   2223 			**	Draw the infantry bodies in this special layer.
   2224 			*/
   2225 //			for (int index = 0; index < Anims.Count(); index++) {
   2226 //				AnimClass * anim = Anims.Ptr(index);
   2227 //				if (*anim >= ANIM_CORPSE1 && *anim <= ANIM_CORPSE3) {
   2228 //					anim->Render(forced);
   2229 //				}
   2230 //			}
   2231 
   2232 #ifdef SORTDRAW
   2233 			/*
   2234 			** Draw the vortex effect over the terrain
   2235 			*/
   2236 			ChronalVortex.Render();
   2237 
   2238 			Redraw_OIcons();
   2239 #endif
   2240 
   2241 			HidPage.Unlock();
   2242 		}
   2243 
   2244 #ifndef WIN32
   2245 		/*
   2246 		**	Once the icons are drawn, duplicate the bottom line of the screen into the phantom
   2247 		**	area one line below the screen. This causes the predator effect to work on any
   2248 		**	shape drawn at the bottom of the screen.
   2249 		*/
   2250 		HidPage.Blit(HidPage, 0, HidPage.Get_Height()-1, 0, HidPage.Get_Height(), HidPage.Get_Width(), 1, false);
   2251 #endif
   2252 
   2253 		if (HidPage.Lock()) {
   2254 
   2255 #ifndef SORTDRAW
   2256 			/*
   2257 			** Draw the vortex effect over the terrain
   2258 			*/
   2259 			ChronalVortex.Render();
   2260 #endif
   2261 
   2262 			/*
   2263 			**	Redraw the game objects layer by layer. The layer drawing occurs on the ground layer
   2264 			**	first and then followed by all the layers in increasing altitude.
   2265 			*/
   2266 			BStart(BENCH_OBJECTS);
   2267 			for (LayerType layer = LAYER_FIRST; layer < LAYER_COUNT; layer++) {
   2268 				for (int index = 0; index < Layer[layer].Count(); index++) {
   2269 					ObjectClass * ptr = Layer[layer][index];
   2270 
   2271 #ifdef SORTDRAW
   2272 					/*
   2273 					**	Techno objects are drawn as part of the cell redraw process since techno
   2274 					**	objects in the ground layer are handled by the Occupier and Overlapper
   2275 					**	pointer lists.
   2276 					*/
   2277 					if (!Debug_Map && ptr->Is_Techno() && layer == LAYER_GROUND && ((TechnoClass*)ptr)->Visual_Character() == VISUAL_NORMAL) continue;
   2278 #endif
   2279 
   2280 //					if (ptr->What_Am_I() == RTTI_ANIM && *((AnimClass*)ptr) >= ANIM_CORPSE1 && *((AnimClass*)ptr) <= ANIM_CORPSE3) {
   2281 //						continue;
   2282 //					}
   2283 					assert(ptr->IsActive);
   2284 					ptr->Render(forced);
   2285 				}
   2286 			}
   2287 			BEnd(BENCH_OBJECTS);
   2288 
   2289 	//ChronalVortex.Render();
   2290 			/*
   2291 			**	Finally, redraw the shadow overlay as necessary.
   2292 			*/
   2293 			BStart(BENCH_SHROUD);
   2294 			Redraw_Shadow();
   2295 			BEnd(BENCH_SHROUD);
   2296 		}
   2297 		HidPage.Unlock();
   2298 
   2299 #ifdef SORTDRAW
   2300 		for (int index = 0; index < Layer[LAYER_GROUND].Count(); index++) {
   2301 			Layer[LAYER_GROUND][index]->IsToDisplay = false;
   2302 		}
   2303 #endif
   2304 
   2305 		/*
   2306 		**	Draw the rubber band over the top of it all.
   2307 		*/
   2308 		if (IsRubberBand) {
   2309 			LogicPage->Draw_Rect(BandX+TacPixelX, BandY+TacPixelY, NewX+TacPixelX, NewY+TacPixelY, WHITE);
   2310 		}
   2311 
   2312 		/*
   2313 		**	Clear the redraw flags so that normal redraw flag setting can resume.
   2314 		*/
   2315 		CellRedraw.Reset();
   2316 
   2317 #ifdef SCENARIO_EDITOR
   2318 		/*
   2319 		**	If we're placing an object (PendingObject is non-NULL), and that object
   2320 		**	is NOT an icon, smudge, or overlay, draw it here.
   2321 		**	Terrain, Buildings & Aircraft aren't drawn at the cell's center coord;
   2322 		**	they're drawn at the upper left coord, so I have to AND the coord value
   2323 		**	with 0xFF00FF00 to strip off the lepton coordinates, but leave the
   2324 		**	cell coordinates.
   2325 		*/
   2326 		if (Debug_Map && PendingObjectPtr) {
   2327 			PendingObjectPtr->Coord = PendingObjectPtr->Class_Of().Coord_Fixup(Cell_Coord(ZoneCell + ZoneOffset));
   2328 			PendingObjectPtr->Render(true);
   2329 		}
   2330 #endif
   2331 		BEnd(BENCH_TACTICAL);
   2332 	}
   2333 }
   2334 
   2335 
   2336 /***********************************************************************************************
   2337  * DisplayClass::Redraw_Icons -- Draws all terrain icons necessary.                            *
   2338  *                                                                                             *
   2339  *    This routine will redraw all of the terrain icons that are flagged                       *
   2340  *    to be redrawn.                                                                           *
   2341  *                                                                                             *
   2342  * INPUT:   none                                                                               *
   2343  *                                                                                             *
   2344  * OUTPUT:  none                                                                               *
   2345  *                                                                                             *
   2346  * WARNINGS:   none.                                                                           *
   2347  *                                                                                             *
   2348  * HISTORY:                                                                                    *
   2349  *   02/14/1994 JLB : Created.                                                                 *
   2350  *   05/01/1994 JLB : Converted to member function.                                            *
   2351  *   06/20/1994 JLB : Uses cell drawing support function.                                      *
   2352  *   12/06/1994 JLB : Scans tactical view in separate row/column loops                         *
   2353  *   12/24/1994 JLB : Uses the cell bit flag array to determine what to redraw.                *
   2354  *=============================================================================================*/
   2355 void DisplayClass::Redraw_Icons(void)
   2356 {
   2357 	IsShadowPresent = false;
   2358 	for (int y = -Coord_YLepton(TacticalCoord); y <= TacLeptonHeight; y += CELL_LEPTON_H) {
   2359 		for (int x = -Coord_XLepton(TacticalCoord); x <= TacLeptonWidth; x += CELL_LEPTON_W) {
   2360 			COORDINATE coord = Coord_Add(TacticalCoord, XY_Coord(x, y));
   2361 			CELL cell = Coord_Cell(coord);
   2362 			coord = Coord_Whole(Cell_Coord(cell));
   2363 
   2364 			/*
   2365 			**	Only cells flagged to be redraw are examined.
   2366 			*/
   2367 			if (In_View(cell) && Is_Cell_Flagged(cell)) {
   2368 				int xpixel;
   2369 				int ypixel;
   2370 
   2371 				if (Coord_To_Pixel(coord, xpixel, ypixel)) {
   2372 					CellClass * cellptr = &(*this)[coord];
   2373 
   2374 					/*
   2375 					**	If there is a portion of the underlying icon that could be visible,
   2376 					**	then draw it.  Also draw the cell if the shroud is off.
   2377 					*/
   2378 					//if (cellptr->IsMapped || Debug_Unshroud) {
   2379 					if (cellptr->Is_Mapped(PlayerPtr) || Debug_Unshroud) {		// Use PlayerPtr since we won't be rendering in MP. ST - 3/6/2019 2:49PM
   2380 						cellptr->Draw_It(xpixel, ypixel);
   2381 					}
   2382 
   2383 					/*
   2384 					**	If any cell is not fully mapped, then flag it so that the shadow drawing
   2385 					**	process will occur.  Only draw the shadow if Debug_Unshroud is false.
   2386 					*/
   2387 					//if (!cellptr->IsVisible && !Debug_Unshroud) {
   2388 					if (!cellptr->Is_Visible(PlayerPtr) && !Debug_Unshroud) {	// Use PlayerPtr since we won't be rendering in MP. ST - 3/6/2019 2:49PM
   2389 						IsShadowPresent = true;
   2390 					}
   2391 				}
   2392 			}
   2393 		}
   2394 	}
   2395 }
   2396 
   2397 
   2398 #ifdef SORTDRAW
   2399 void DisplayClass::Redraw_OIcons(void)
   2400 {
   2401 	for (int y = -Coord_YLepton(TacticalCoord); y <= TacLeptonHeight; y += CELL_LEPTON_H) {
   2402 		for (int x = -Coord_XLepton(TacticalCoord); x <= TacLeptonWidth; x += CELL_LEPTON_W) {
   2403 			COORDINATE coord = Coord_Add(TacticalCoord, XY_Coord(x, y));
   2404 			CELL cell = Coord_Cell(coord);
   2405 			coord = Coord_Whole(Cell_Coord(cell));
   2406 
   2407 			/*
   2408 			**	Only cells flagged to be redraw are examined.
   2409 			*/
   2410 			if (In_View(cell) && Is_Cell_Flagged(cell)) {
   2411 				int xpixel;
   2412 				int ypixel;
   2413 
   2414 				if (Coord_To_Pixel(coord, xpixel, ypixel)) {
   2415 					CellClass * cellptr = &(*this)[coord];
   2416 
   2417 					/*
   2418 					**	If there is a portion of the underlying icon that could be visible,
   2419 					**	then draw it.  Also draw the cell if the shroud is off.
   2420 					*/
   2421 					//if (cellptr->IsMapped || Debug_Unshroud) {
   2422 					if (cellptr->Is_Mapped(PlayerPtr) || Debug_Unshroud) {		// Use PlayerPtr since we won't be rendering in MP. ST - 3/6/2019 2:49PM
   2423 						cellptr->Draw_It(xpixel, ypixel, true);
   2424 					}
   2425 				}
   2426 			}
   2427 		}
   2428 	}
   2429 }
   2430 #endif
   2431 
   2432 
   2433 /***********************************************************************************************
   2434  * DisplayClass::Redraw_Shadow -- Draw the shadow overlay.                                     *
   2435  *                                                                                             *
   2436  *    This routine is called after all other tactical map rendering takes place. It draws      *
   2437  *    the shadow map over the tactical map.                                                    *
   2438  *                                                                                             *
   2439  * INPUT:   none                                                                               *
   2440  *                                                                                             *
   2441  * OUTPUT:  none                                                                               *
   2442  *                                                                                             *
   2443  * WARNINGS:   none                                                                            *
   2444  *                                                                                             *
   2445  * HISTORY:                                                                                    *
   2446  *   01/01/1995 JLB : Created.                                                                 *
   2447  *   08/06/1995 JLB : Clips the fill rect if necessary.                                        *
   2448  *=============================================================================================*/
   2449 void DisplayClass::Redraw_Shadow(void)
   2450 {
   2451 	if (IsShadowPresent) {
   2452 		for (int y = -Coord_YLepton(TacticalCoord); y <= TacLeptonHeight; y += CELL_LEPTON_H) {
   2453 			for (int x = -Coord_XLepton(TacticalCoord); x <= TacLeptonWidth; x += CELL_LEPTON_W) {
   2454 				COORDINATE coord = Coord_Add(TacticalCoord, XY_Coord(x, y));
   2455 				CELL cell = Coord_Cell(coord);
   2456 				coord = Coord_Whole(Cell_Coord(cell));
   2457 
   2458 				/*
   2459 				**	Only cells flagged to be redrawn are examined.
   2460 				*/
   2461 				if (In_View(cell) && Is_Cell_Flagged(cell)) {
   2462 					int xpixel;
   2463 					int ypixel;
   2464 
   2465 					if (Coord_To_Pixel(coord, xpixel, ypixel)) {
   2466 						CellClass * cellptr = &(*this)[coord];
   2467 						//if (cellptr->IsVisible) continue;
   2468 						if (cellptr->Is_Visible(PlayerPtr)) continue;		// Use PlayerPtr since we won't be rendering in MP. ST - 8/6/2019 10:44AM
   2469 						int shadow = -2;
   2470 						//if (cellptr->IsMapped) {
   2471 						if (cellptr->Is_Mapped(PlayerPtr)) {					// Use PlayerPtr since we won't be rendering in MP. ST - 8/6/2019 10:44AM
   2472 							shadow = Cell_Shadow(cell, PlayerPtr);				// Use PlayerPtr since we won't be rendering in MP. ST - 8/6/2019 10:44AM
   2473 						}
   2474 						if (shadow >= 0) {
   2475 							CC_Draw_Shape(ShadowShapes, shadow, xpixel, ypixel, WINDOW_TACTICAL, SHAPE_GHOST, NULL, ShadowTrans);
   2476 						} else {
   2477 							if (shadow != -1) {
   2478 								int ww = CELL_PIXEL_W;
   2479 								int hh = CELL_PIXEL_H;
   2480 
   2481 								if (Clip_Rect(&xpixel, &ypixel, &ww, &hh, Lepton_To_Pixel(TacLeptonWidth), Lepton_To_Pixel(TacLeptonHeight)) >= 0) {
   2482 									LogicPage->Fill_Rect(TacPixelX+xpixel, TacPixelY+ypixel, TacPixelX+xpixel+ww-1, TacPixelY+ypixel+hh-1, BLACK);
   2483 								}
   2484 							}
   2485 						}
   2486 					}
   2487 				}
   2488 			}
   2489 		}
   2490 	}
   2491 }
   2492 
   2493 
   2494 /***********************************************************************************************
   2495  * DisplayClass::Next_Object -- Searches for next object on display.                           *
   2496  *                                                                                             *
   2497  *    This utility routine is used to find the "next" object from the object specified. This   *
   2498  *    is typically used when <TAB> is pressed and the current object shifts.                   *
   2499  *                                                                                             *
   2500  * INPUT:   object   -- The current object to base the "next" calculation off of.              *
   2501  *                                                                                             *
   2502  * OUTPUT:  Returns with a pointer to the next object. If there is no objects available,       *
   2503  *          then NULL is returned.                                                             *
   2504  *                                                                                             *
   2505  * WARNINGS:   none                                                                            *
   2506  *                                                                                             *
   2507  * HISTORY:                                                                                    *
   2508  *   06/20/1994 JLB : Created.                                                                 *
   2509  *=============================================================================================*/
   2510 ObjectClass * DisplayClass::Next_Object(ObjectClass * object) const
   2511 {
   2512 	ObjectClass * firstobj = NULL;
   2513 	bool foundmatch = false;
   2514 
   2515 	if (object == NULL) {
   2516 		foundmatch = true;
   2517 	}
   2518 	for (unsigned uindex = 0; uindex < (unsigned)Layer[LAYER_GROUND].Count(); uindex++) {
   2519 		ObjectClass * obj = Layer[LAYER_GROUND][uindex];
   2520 
   2521 		/*
   2522 		**	Verify that the object can be selected by and is owned by the player.
   2523 		*/
   2524 		if (obj != NULL && obj->Is_Players_Army()) {
   2525 			if (firstobj == NULL) firstobj = obj;
   2526 			if (foundmatch) return(obj);
   2527 			if (object == obj) foundmatch = true;
   2528 		}
   2529 	}
   2530 	return(firstobj);
   2531 }
   2532 
   2533 
   2534 /***********************************************************************************************
   2535  * DisplayClass::Prev_Object -- Searches for the previous object on the map.                   *
   2536  *                                                                                             *
   2537  *    This routine will search for the previous object. Previous is defined as the one listed  *
   2538  *    before the specified object in the ground layer. If there is no specified object, then   *
   2539  *    the last object in the ground layer is returned.                                         *
   2540  *                                                                                             *
   2541  * INPUT:   object   -- Pointer to the object that "previous" is to be defined from.           *
   2542  *                                                                                             *
   2543  * OUTPUT:  Returns with a pointer to the object previous to the specified one.                *
   2544  *                                                                                             *
   2545  * WARNINGS:   none                                                                            *
   2546  *                                                                                             *
   2547  * HISTORY:                                                                                    *
   2548  *   08/24/1995 JLB : Created.                                                                 *
   2549  *=============================================================================================*/
   2550 ObjectClass * DisplayClass::Prev_Object(ObjectClass * object)  const
   2551 {
   2552 	ObjectClass * firstobj = NULL;
   2553 	bool foundmatch = false;
   2554 
   2555 	if (object == NULL) {
   2556 		foundmatch = true;
   2557 	}
   2558 	for (int uindex = Layer[LAYER_GROUND].Count()-1; uindex >= 0; uindex--) {
   2559 		ObjectClass * obj = Layer[LAYER_GROUND][uindex];
   2560 
   2561 		/*
   2562 		**	Verify that the object can be selected by and is owned by the player.
   2563 		*/
   2564 		if (obj != NULL && obj->Is_Players_Army()) {
   2565 			if (firstobj == NULL) firstobj = obj;
   2566 			if (foundmatch) return(obj);
   2567 			if (object == obj) foundmatch = true;
   2568 		}
   2569 	}
   2570 
   2571 	return(firstobj);
   2572 }
   2573 
   2574 
   2575 /***********************************************************************************************
   2576  * DisplayClass::Pixel_To_Coord -- converts screen coord to COORDINATE                         *
   2577  *                                                                                             *
   2578  * INPUT:                                                                                      *
   2579  *      x,y      pixel coordinates to convert                                                  *
   2580  *                                                                                             *
   2581  * OUTPUT:                                                                                     *
   2582  *      COORDINATE of pixel                                                                    *
   2583  *                                                                                             *
   2584  * WARNINGS:                                                                                   *
   2585  *      none.                                                                                  *
   2586  *                                                                                             *
   2587  * HISTORY:                                                                                    *
   2588  *   11/09/1994 BR : Created.                                                                  *
   2589  *   12/06/1994 JLB : Uses map dimension variables in display class.                           *
   2590  *   12/10/1994 JLB : Uses union to speed building coordinate value.                           *
   2591  *=============================================================================================*/
   2592 COORDINATE DisplayClass::Pixel_To_Coord(int x, int y) const
   2593 {
   2594 	/*
   2595 	**	Normalize the pixel coordinates to be relative to the upper left corner
   2596 	**	of the tactical map. The coordinates are expressed in leptons.
   2597 	*/
   2598 	x -= TacPixelX;
   2599 	x = Pixel_To_Lepton(x);
   2600 	y -= TacPixelY;
   2601 	y = Pixel_To_Lepton(y);
   2602 
   2603 	/*
   2604 	**	If pixel coordinate is over the tactical map, then translate it into a coordinate
   2605 	**	value. If not, then just return with NULL.
   2606 	*/
   2607 	// Possibly ignore the view constraints if we aren't using the internal renderer. ST - 8/6/2019 10:47AM
   2608 	//if ((unsigned)x < TacLeptonWidth && (unsigned)y < TacLeptonHeight) {
   2609 	if (IgnoreViewConstraints || ((unsigned)x < TacLeptonWidth && (unsigned)y < TacLeptonHeight)) {
   2610 		return(Coord_Add(TacticalCoord, XY_Coord(x, y)));
   2611 	}
   2612 	return(0);
   2613 }
   2614 
   2615 
   2616 /***********************************************************************************************
   2617  * DisplayClass::Calculated_Cell -- Fetch a map cell based on specified method.                *
   2618  *                                                                                             *
   2619  *    Find a cell meeting the specified requirements. This function is                         *
   2620  *    used for scenario reinforcements.                                                        *
   2621  *                                                                                             *
   2622  * INPUT:   dir   -- Method of picking a map cell.                                             *
   2623  *                                                                                             *
   2624  *          waypoint -- Closest waypoint to use for finding appropriate map edge.              *
   2625  *                                                                                             *
   2626  *          cell  -- Cell to find closest edge to if waypoint not specified.                   *
   2627  *                                                                                             *
   2628  *          loco  -- The locomotion of the reinforcements that are trying to enter.            *
   2629  *                                                                                             *
   2630  *          zonecheck   -- Is zone checking required?                                          *
   2631  *                                                                                             *
   2632  *          mzone    -- The movement zone type to check against (only if zone checking).       *
   2633  *                                                                                             *
   2634  * OUTPUT:  Returns with the calculated cell. If 0, then this indicates                        *
   2635  *          that no legal cell was found.                                                      *
   2636  *                                                                                             *
   2637  * WARNINGS:   none                                                                            *
   2638  *                                                                                             *
   2639  * HISTORY:                                                                                    *
   2640  *   10/07/1992 JLB : Created.                                                                 *
   2641  *   04/11/1994 JLB : Revamped.                                                                *
   2642  *   05/18/1994 JLB : Converted to member function.                                            *
   2643  *   12/18/1995 JLB : Handles edge preference scan.                                            *
   2644  *   06/24/1996 JLB : Removed Dune II legacy code.                                             *
   2645  *   06/25/1996 JLB : Rewrote and greatly simplified.                                          *
   2646  *   10/05/1996 JLB : Checks for zone and crushable status.                                    *
   2647  *=============================================================================================*/
   2648 CELL DisplayClass::Calculated_Cell(SourceType dir, WAYPOINT waypoint, CELL cell, SpeedType loco, bool zonecheck, MZoneType mzone) const
   2649 {
   2650 	bool vert = false;
   2651 	bool horz = false;
   2652 	int x = 0;
   2653 	int y = 0;
   2654 	CELL punt = 0;			// If all else fails, return this cell location.
   2655 	int zone = -1;			// Tentative zone for legality checking.
   2656 
   2657 	/*
   2658 	**	Waypoint edge detection for ground based reinforcements that have a waypoint origin are
   2659 	**	determined by finding the closest map edge to the waypoint. Reinforcement location
   2660 	**	scanning starts from that position.
   2661 	*/
   2662 	CELL trycell = -1;
   2663 	if (waypoint != -1) {
   2664 		trycell = Scen.Waypoint[waypoint];
   2665 	}
   2666 	if (trycell == -1) {
   2667 		trycell = cell;
   2668 	}
   2669 
   2670 	/*
   2671 	**	If zone checking is requested, then find the correct zone to use.
   2672 	*/
   2673 	if (zonecheck && trycell != -1) {
   2674 		zone = (*this)[trycell].Zones[mzone];
   2675 	}
   2676 
   2677 	/*
   2678 	**	If the cell or waypoint specified as been detected as legal, then set up the map edge
   2679 	**	scanning values accordingly.
   2680 	*/
   2681 	if (trycell != -1) {
   2682 		x = Cell_X(trycell) - MapCellX;
   2683 		x = min(x, (-Cell_X(trycell) + (MapCellX+MapCellWidth)));
   2684 
   2685 		y = Cell_Y(trycell) - MapCellY;
   2686 		y = min(y, (-Cell_Y(trycell) + (MapCellY+MapCellHeight)));
   2687 
   2688 		if (x < y) {
   2689 			vert = true;
   2690 			horz = false;
   2691 			if ((Cell_X(trycell)-MapCellX) < MapCellWidth/2) {
   2692 				x = -1;
   2693 			} else {
   2694 				x = MapCellWidth;
   2695 			}
   2696 			y = Cell_Y(trycell) - MapCellY;
   2697 
   2698 		} else {
   2699 
   2700 			vert = false;
   2701 			horz = true;
   2702 			if ((Cell_Y(trycell)-MapCellY) < MapCellHeight/2) {
   2703 				y = -1;
   2704 			} else {
   2705 				y = MapCellHeight;
   2706 			}
   2707 			x = Cell_X(trycell) - MapCellX;
   2708 		}
   2709 	}
   2710 
   2711 	/*
   2712 	**	If no map edge can be inferred from the waypoint, then go with the
   2713 	**	map edge specified by the edge parameter.
   2714 	*/
   2715 	if (!vert && !horz) {
   2716 		switch (dir) {
   2717 			default:
   2718 			case SOURCE_NORTH:
   2719 				horz = true;
   2720 				y = -1;
   2721 				x = Random_Pick(0, MapCellWidth-1);
   2722 				break;
   2723 
   2724 			case SOURCE_SOUTH:
   2725 				horz = true;
   2726 				y = MapCellHeight;
   2727 				x = Random_Pick(0, MapCellWidth-1);
   2728 				break;
   2729 
   2730 			case SOURCE_EAST:
   2731 				vert = true;
   2732 				x = MapCellWidth;
   2733 				y = Random_Pick(0, MapCellHeight-1);
   2734 				break;
   2735 
   2736 			case SOURCE_WEST:
   2737 				vert = true;
   2738 				x = -1;
   2739 				y = Random_Pick(0, MapCellHeight-1);
   2740 				break;
   2741 		}
   2742 	}
   2743 
   2744 	/*
   2745 	**	Determine the default reinforcement cell if all else fails.
   2746 	*/
   2747 	punt = XY_Cell(x + MapCellX, y + MapCellY);
   2748 
   2749 	/*
   2750 	**	Scan through the vertical and horizontal edges of the map looking for
   2751 	**	a relatively clear cell for object placement. The cell scanned is
   2752 	**	from the edge position specified by the X and Y variables.
   2753 	*/
   2754 	if (vert) {
   2755 		int modifier = (x > MapCellX) ? -1 : 1;
   2756 
   2757 		for (int index = 0; index < MapCellHeight; index++) {
   2758 			CELL trycell = XY_Cell(x + MapCellX, ((y + index) % MapCellHeight) + MapCellY);
   2759 
   2760 			if (Good_Reinforcement_Cell(trycell, trycell+modifier, loco, zone, mzone)) {
   2761 				return(trycell);
   2762 			}
   2763 		}
   2764 	}
   2765 
   2766 	if (horz) {
   2767 		int modifier = (y > MapCellY) ? -MAP_CELL_W : MAP_CELL_W;
   2768 
   2769 		for (int index = 0; index < MapCellWidth; index++) {
   2770 			CELL trycell = XY_Cell(((x + index) % MapCellWidth) + MapCellX, y + MapCellY);
   2771 
   2772 			if (Good_Reinforcement_Cell(trycell, trycell+modifier, loco, zone, mzone)) {
   2773 				return(trycell);
   2774 			}
   2775 		}
   2776 	}
   2777 
   2778 	/*
   2779 	**	If there was no success in finding a suitable reinforcement edge cell, then return
   2780 	**	with the default 'punt' cell location.
   2781 	*/
   2782 	return(punt);
   2783 }
   2784 
   2785 
   2786 /***********************************************************************************************
   2787  * DisplayClass::Good_Reinforcement_Cell -- Checks cell for renforcement legality.             *
   2788  *                                                                                             *
   2789  *    This routine will check the secified cell (given the specified conditions) and determine *
   2790  *    if that is a good cell for reinforcement purposes. It checks for passability of the cell *
   2791  *    as well as zone and whether blocking walls can be crushed.                               *
   2792  *                                                                                             *
   2793  * INPUT:   outcell  -- The cell that is just outside the edge of the map.                     *
   2794  *                                                                                             *
   2795  *          incell   -- The cell that is just inside the edge of the map.                      *
   2796  *                                                                                             *
   2797  *          loco     -- The locomotion type of the reinforcement.                              *
   2798  *                                                                                             *
   2799  *          zone     -- The zone that the eventual movement destination lies. A reinforcement  *
   2800  *                      edge must fall within the same zone.                                   *
   2801  *                                                                                             *
   2802  *          mzone    -- The zone check type to check against (if zone checking required)       *
   2803  *                                                                                             *
   2804  * OUTPUT:  bool; Is the specified cell good for reinforcement purposes?                       *
   2805  *                                                                                             *
   2806  * WARNINGS:   none                                                                            *
   2807  *                                                                                             *
   2808  * HISTORY:                                                                                    *
   2809  *   10/05/1996 JLB : Created.                                                                 *
   2810  *=============================================================================================*/
   2811 bool DisplayClass::Good_Reinforcement_Cell(CELL outcell, CELL incell, SpeedType loco, int zone, MZoneType mzone) const
   2812 {
   2813 	/*
   2814 	**	If the map edge location is not clear for object placement, then this is not
   2815 	**	a good cell for reinforcement purposes.
   2816 	*/
   2817 	if (!(*this)[outcell].Is_Clear_To_Move(loco, false, false)) {
   2818 		return(false);
   2819 	}
   2820 
   2821 	/*
   2822 	**	If it looks like the on-map cell cannot be driven on to, then return with
   2823 	**	the failure code.
   2824 	*/
   2825 	if (!(*this)[incell].Is_Clear_To_Move(loco, false, false, zone, mzone)) {
   2826 		return(false);
   2827 	}
   2828 
   2829 	/*
   2830 	**	If the reinforcement cell is already occupied, then return a failure code.
   2831 	*/
   2832 	if ((*this)[outcell].Cell_Techno() != NULL) {
   2833 		return(false);
   2834 	}
   2835 	if ((*this)[incell].Cell_Techno() != NULL) return(false);
   2836 
   2837 	/*
   2838 	**	All tests have passed, return with success code.
   2839 	*/
   2840 //Mono_Printf("<%04X>\n", incell);Keyboard->Get();
   2841 	return(true);
   2842 }
   2843 
   2844 
   2845 /***********************************************************************************************
   2846  * DisplayClass::Select_These -- All selectable objects in region are selected.                *
   2847  *                                                                                             *
   2848  *    Use this routine to simultaneously select all objects within the coordinate region       *
   2849  *    specified. This routine is used by the multi-select rubber band handler.                 *
   2850  *                                                                                             *
   2851  * INPUT:   coord1   -- Coordinate of one corner of the selection region.                      *
   2852  *                                                                                             *
   2853  *          coord2   -- The opposite corner of the selection region.                           *
   2854  *                                                                                             *
   2855  *          additive -- Does this add to the existing selection or replace it.                 *
   2856  *                                                                                             *
   2857  * OUTPUT:  none                                                                               *
   2858  *                                                                                             *
   2859  * WARNINGS:   none                                                                            *
   2860  *                                                                                             *
   2861  * HISTORY:                                                                                    *
   2862  *   01/19/1995 JLB : Created.                                                                 *
   2863  *   04/25/1995 JLB : Limited to non-building type.                                            *
   2864  *   03/06/1996 JLB : Allows selection of aircraft with bounding box.                          *
   2865  *=============================================================================================*/
   2866 static bool should_exclude_from_selection(ObjectClass* obj)
   2867 {
   2868 	return (obj->What_Am_I() == RTTI_UNIT) &&
   2869 		(((UnitClass *)obj)->Class->IsToHarvest ||
   2870 		*((UnitClass *)obj) == UNIT_MCV);
   2871 }
   2872 
   2873 void DisplayClass::Select_These(COORDINATE coord1, COORDINATE coord2, bool additive)
   2874 {
   2875 	COORDINATE tcoord = TacticalCoord;	//Cell_Coord(TacticalCell) & 0xFF00FF00L;
   2876 
   2877 	coord1 = Coord_Add(tcoord, coord1);
   2878 	coord2 = Coord_Add(tcoord, coord2);
   2879 	int x1 = Coord_X(coord1);
   2880 	int x2 = Coord_X(coord2);
   2881 	int y1 = Coord_Y(coord1);
   2882 	int y2 = Coord_Y(coord2);
   2883 
   2884 	/*
   2885 	**	Ensure that coordinate number one represents the upper left corner
   2886 	**	and coordinate number two represents the lower right corner.
   2887 	*/
   2888 	if (x1 > x2) {
   2889 		int temp = x1;
   2890 		x1 = x2;
   2891 		x2 = temp;
   2892 	}
   2893 	if (y1 > y2) {
   2894 		int temp = y1;
   2895 		y1 = y2;
   2896 		y2 = temp;
   2897 	}
   2898 
   2899 	/*
   2900 	**	Sweep through all ground layer objects and select the ones within the
   2901 	**	bounding box.
   2902 	*/
   2903 	if (!additive) {
   2904 		Unselect_All();
   2905 	}
   2906 	AllowVoice = true;
   2907 	for (int index = 0; index < Layer[LAYER_GROUND].Count(); index++) {
   2908 		ObjectClass * obj = Layer[LAYER_GROUND][index];
   2909 		COORDINATE ocoord = obj->Center_Coord();
   2910 		int x = Coord_X(ocoord);
   2911 		int y = Coord_Y(ocoord);
   2912 
   2913 		/*
   2914 		**	Only try to select objects that are allowed to be selected, and are within the bounding box.
   2915 		*/
   2916 		HouseClass * hptr = HouseClass::As_Pointer(obj->Owner());
   2917 		if (	obj->Class_Of().IsSelectable &&
   2918 				obj->What_Am_I() != RTTI_BUILDING &&
   2919 				(!obj->Is_Techno() || !((TechnoClass*)obj)->Is_Cloaked(PlayerPtr)) &&
   2920 				x >= x1 && x <= x2 && y >= y1 && y <= y2) {
   2921 			bool old_allow_voice = AllowVoice;
   2922 			bool is_player_controlled = (hptr != NULL) && hptr->IsPlayerControl;
   2923 			AllowVoice &= is_player_controlled;
   2924 			if (obj->Select(true)) {
   2925 				if (is_player_controlled) {
   2926 					old_allow_voice = false;
   2927 				}
   2928 			}
   2929 			AllowVoice = old_allow_voice;
   2930 		}
   2931 	}
   2932 
   2933 	/*
   2934 	**	Select any aircraft with the bounding box.
   2935 	*/
   2936 	for (int air_index = 0; air_index < Aircraft.Count(); air_index++) {
   2937 		AircraftClass * aircraft = Aircraft.Ptr(air_index);
   2938 		COORDINATE ocoord = aircraft->Center_Coord();
   2939 		int x = Coord_X(ocoord);
   2940 		int y = Coord_Y(ocoord);
   2941 
   2942 		/*
   2943 		**	Only try to select objects that are allowed to be selected, and are within the bounding box.
   2944 		*/
   2945 		if (	aircraft->Class->IsSelectable &&
   2946 				!aircraft->Is_Cloaked(PlayerPtr) &&
   2947 				!aircraft->Is_Selected_By_Player() &&
   2948 				x >= x1 && x <= x2 && y >= y1 && y <= y2) {
   2949 			bool old_allow_voice = AllowVoice;
   2950 			bool is_player_controlled = aircraft->House->IsPlayerControl;
   2951 			AllowVoice &= is_player_controlled;
   2952 			if (aircraft->Select(true)) {
   2953 				if (is_player_controlled) {
   2954 					old_allow_voice = false;
   2955 				}
   2956 			}
   2957 			AllowVoice = old_allow_voice;
   2958 		}
   2959 	}
   2960 
   2961 	/*
   2962 	** If a mix of player and non-player controlled units were selected, make sure non-player controlled units are de-selected
   2963 	*/
   2964 	bool player_controlled_units = false, non_player_controlled_units = false;
   2965 	for (int i = 0; (i < CurrentObject.Count()) && (!player_controlled_units || !non_player_controlled_units); ++i) {
   2966 		HouseClass * hptr = HouseClass::As_Pointer(CurrentObject[i]->Owner());
   2967 		if (hptr->IsPlayerControl) {
   2968 			player_controlled_units = true;
   2969 		}
   2970 		else {
   2971 			non_player_controlled_units = true;
   2972 		}
   2973 	}
   2974 	if (player_controlled_units && non_player_controlled_units) {
   2975 		for (int i = 0; i < CurrentObject.Count(); ++i) {
   2976 			HouseClass * hptr = HouseClass::As_Pointer(CurrentObject[i]->Owner());
   2977 			if (!hptr->IsPlayerControl) {
   2978 				int count_before = CurrentObject.Count();
   2979 				CurrentObject[i]->Unselect();
   2980 				if (count_before <= CurrentObject.Count()) {
   2981 					GlyphX_Debug_Print("Select_These failed to remove an object");
   2982 					CurrentObject.Delete(CurrentObject[i]);
   2983 				}
   2984 				--i;
   2985 			}
   2986 		}
   2987 	}
   2988 
   2989 	/*
   2990 	** If player-controlled units are non-additively selected, remove harvesters and MCVs if they aren't the only types of units selected
   2991 	*/
   2992 	if (!additive && player_controlled_units) {
   2993 		bool any_to_exclude = false, all_to_exclude = true;
   2994 		for (int i = 0; i < CurrentObject.Count(); ++i) {
   2995 			bool exclude = should_exclude_from_selection(CurrentObject[i]);
   2996 			any_to_exclude |= exclude;
   2997 			all_to_exclude &= exclude;
   2998 		}
   2999 		if (any_to_exclude && !all_to_exclude) {
   3000 			for (int i = 0; i < CurrentObject.Count(); ++i) {
   3001 				if (should_exclude_from_selection(CurrentObject[i])) {
   3002 					int count_before = CurrentObject.Count();
   3003 					CurrentObject[i]->Unselect();
   3004 					if (count_before <= CurrentObject.Count()) {
   3005 						GlyphX_Debug_Print("Select_These failed to remove an object");
   3006 						CurrentObject.Delete(CurrentObject[i]);
   3007 					}
   3008 					--i;
   3009 				}
   3010 			}
   3011 		}
   3012 	}
   3013 
   3014 	AllowVoice = true;
   3015 }
   3016 
   3017 
   3018 /***********************************************************************************************
   3019  * DisplayClass::Refresh_Band -- Causes all cells under the rubber band to be redrawn.         *
   3020  *                                                                                             *
   3021  *    Use this routine to flag all cells that are covered in some fashion by the multi-unit    *
   3022  *    select "rubber band" to be redrawn. This is necessary whenever the rubber band changes   *
   3023  *    size or is being removed.                                                                *
   3024  *                                                                                             *
   3025  * INPUT:   none                                                                               *
   3026  *                                                                                             *
   3027  * OUTPUT:  none                                                                               *
   3028  *                                                                                             *
   3029  * WARNINGS:   none                                                                            *
   3030  *                                                                                             *
   3031  * HISTORY:                                                                                    *
   3032  *   01/19/1995 JLB : Created.                                                                 *
   3033  *=============================================================================================*/
   3034 void DisplayClass::Refresh_Band(void)
   3035 {
   3036 	if (IsRubberBand) {
   3037 
   3038 		/*
   3039 		**	In rubber band mode, mark all cells under the "rubber band" to be
   3040 		**	redrawn.
   3041 		*/
   3042 		int x1 = BandX+TacPixelX;
   3043 		int y1 = BandY+TacPixelY;
   3044 		int x2 = NewX+TacPixelX;
   3045 		int y2 = NewY+TacPixelY;
   3046 
   3047 		if (x1 > x2) {
   3048 			int temp = x1;
   3049 			x1 = x2;
   3050 			x2 = temp;
   3051 		}
   3052 		if (y1 > y2) {
   3053 			int temp = y1;
   3054 			y1 = y2;
   3055 			y2 = temp;
   3056 		}
   3057 
   3058 		CELL cell;
   3059 		for (int y = y1; y <= y2+CELL_PIXEL_H; y += CELL_PIXEL_H) {
   3060 			cell = Click_Cell_Calc(x1, Bound(y, 0, TacPixelY+Lepton_To_Pixel(TacLeptonHeight)));
   3061 			if (cell != -1) (*this)[cell].Redraw_Objects();
   3062 
   3063 			cell = Click_Cell_Calc(x2, Bound(y, 0, TacPixelY+Lepton_To_Pixel(TacLeptonHeight)));
   3064 			if (cell != -1) (*this)[cell].Redraw_Objects();
   3065 		}
   3066 
   3067 		for (int x = x1; x <= x2+CELL_PIXEL_W; x += CELL_PIXEL_W) {
   3068 			cell = Click_Cell_Calc(Bound(x, 0, TacPixelX+Lepton_To_Pixel(TacLeptonWidth)), y1);
   3069 			if (cell != -1) (*this)[cell].Redraw_Objects();
   3070 
   3071 			cell = Click_Cell_Calc(Bound(x, 0, TacPixelX+Lepton_To_Pixel(TacLeptonWidth)), y2);
   3072 			if (cell != -1) (*this)[cell].Redraw_Objects();
   3073 		}
   3074 
   3075 		/*
   3076 		**	Stretching the rubber band requires all objects to be redrawn.
   3077 		*/
   3078 		int index;
   3079 		for (index = 0; index < Layer[LAYER_TOP].Count(); index++) {
   3080 			Layer[LAYER_TOP][index]->Mark(MARK_CHANGE);
   3081 		}
   3082 		for (index = 0; index < Layer[LAYER_AIR].Count(); index++) {
   3083 			Layer[LAYER_AIR][index]->Mark(MARK_CHANGE);
   3084 		}
   3085 	}
   3086 }
   3087 
   3088 
   3089 /***********************************************************************************************
   3090  * DisplayClass::TacticalClass::Action -- Processes input for the tactical map.                *
   3091  *                                                                                             *
   3092  *    This routine handles the input directed at the tactical map. Since input, in this        *
   3093  *    regard, includes even the presence of the mouse over the tactical map, this routine      *
   3094  *    is called nearly every game frame. It handles adjusting the mouse shape as well as       *
   3095  *    giving orders to units.                                                                  *
   3096  *                                                                                             *
   3097  * INPUT:   flags -- The gadget event flags that triggered the call to this function.          *
   3098  *                                                                                             *
   3099  *          key   -- A reference to the keyboard event (if any).                               *
   3100  *                                                                                             *
   3101  * OUTPUT:  bool; Should processing be aborted on any succeeding buttons in the chain?         *
   3102  *                                                                                             *
   3103  * WARNINGS:   none                                                                            *
   3104  *                                                                                             *
   3105  * HISTORY:                                                                                    *
   3106  *   02/17/1995 JLB : Created.                                                                 *
   3107  *=============================================================================================*/
   3108 int DisplayClass::TacticalClass::Action(unsigned flags, KeyNumType & key)
   3109 {
   3110 	int		x,y;					// Sub cell pixel coordinates.
   3111 	bool		shadow;
   3112 	ObjectClass * object = 0;
   3113 	ActionType action = ACTION_NONE;		// Action possible with currently selected object.
   3114 
   3115 	/*
   3116 	**	Set some working variables that depend on the mouse position. For the press
   3117 	**	or release event, special mouse queuing storage variables are used. Other
   3118 	**	events must use the current mouse position globals.
   3119 	*/
   3120 	if (flags & (LEFTPRESS|LEFTRELEASE|RIGHTPRESS|RIGHTRELEASE)) {
   3121 		x = Keyboard->MouseQX;
   3122 		y = Keyboard->MouseQY;
   3123 	} else {
   3124 		x = Get_Mouse_X();
   3125 		y = Get_Mouse_Y();
   3126 	}
   3127 	bool edge = (y == 0 || x == 0 || x == SeenBuff.Get_Width()-1 || y == SeenBuff.Get_Height()-1);
   3128 	COORDINATE coord = Map.Pixel_To_Coord(x, y);
   3129 	CELL cell = Coord_Cell(coord);
   3130 	if (coord) {
   3131 
   3132 		//shadow = (!Map[cell].IsMapped && !Debug_Unshroud);
   3133 		shadow = (!Map[cell].Is_Mapped(PlayerPtr) && !Debug_Unshroud);		// Use PlayerPtr since we won't be rendering in MP. ST - 8/6/2019 10:49AM
   3134 		x -= Map.TacPixelX;
   3135 		y -= Map.TacPixelY;
   3136 
   3137 		/*
   3138 		** Cause any displayed cursor to move along with the mouse cursor.
   3139 		*/
   3140 		if (cell != Map.ZoneCell) {
   3141 			Map.Set_Cursor_Pos(cell);
   3142 		}
   3143 
   3144 		/*
   3145 		**	Determine the object that the mouse is currently over.
   3146 		*/
   3147 		if (!shadow) {
   3148 			object = Map.Close_Object(coord);
   3149 
   3150 			/*
   3151 			**	Special case check to ignore cloaked object if not allied with the player.
   3152 			*/
   3153 			if (object != NULL && object->Is_Techno() && ((TechnoClass *)object)->Is_Cloaked(PlayerPtr, true)) {
   3154 				object = NULL;
   3155 			}
   3156 		}
   3157 
   3158 		/*
   3159 		**	If there is a currently selected object, then the action to perform if
   3160 		**	the left mouse button were clicked must be determined.
   3161 		*/
   3162 		if (CurrentObject.Count()) {
   3163 			if (object != NULL) {
   3164 				action = Best_Object_Action(object);
   3165 			} else {
   3166 				action = Best_Object_Action(cell);
   3167 			}
   3168 
   3169 		} else {
   3170 
   3171 			if (object && object->Class_Of().IsSelectable) {
   3172 				action = ACTION_SELECT;
   3173 			}
   3174 
   3175 			if (Map.IsRepairMode) {
   3176 				if (object && object->Owner() == PlayerPtr->Class->House && object->Can_Repair()) {
   3177 					action = ACTION_REPAIR;
   3178 				} else {
   3179 					action = ACTION_NO_REPAIR;
   3180 				}
   3181 			}
   3182 
   3183 			if (Map.IsSellMode) {
   3184 				if (object && object->Owner() == PlayerPtr->Class->House && object->Can_Demolish()) {
   3185 					if (object->What_Am_I() == RTTI_BUILDING) {
   3186 						action = ACTION_SELL;
   3187 					} else {
   3188 						action = ACTION_SELL_UNIT;
   3189 					}
   3190 				} else {
   3191 
   3192 					/*
   3193 					**	Check to see if the cursor is over an owned wall.
   3194 					*/
   3195 					if (Map[cell].Overlay != OVERLAY_NONE &&
   3196 						OverlayTypeClass::As_Reference(Map[cell].Overlay).IsWall &&
   3197 						Map[cell].Owner == PlayerPtr->Class->House) {
   3198 							action = ACTION_SELL;
   3199 					} else {
   3200 						action = ACTION_NO_SELL;
   3201 					}
   3202 				}
   3203 			}
   3204 
   3205 			if (Map.IsTargettingMode == SPC_NUCLEAR_BOMB) {
   3206 				action = ACTION_NUKE_BOMB;
   3207 			}
   3208 
   3209 			if (Map.IsTargettingMode == SPC_PARA_BOMB) {
   3210 				action = ACTION_PARA_BOMB;
   3211 			}
   3212 
   3213 			if (Map.IsTargettingMode == SPC_PARA_INFANTRY) {
   3214 				action = ACTION_PARA_INFANTRY;
   3215 			}
   3216 
   3217 			if (Map.IsTargettingMode == SPC_SPY_MISSION) {
   3218 				action = ACTION_SPY_MISSION;
   3219 			}
   3220 
   3221 			if (Map.IsTargettingMode == SPC_IRON_CURTAIN) {
   3222 				action = ACTION_IRON_CURTAIN;
   3223 			}
   3224 
   3225 			if (Map.IsTargettingMode == SPC_CHRONOSPHERE) {
   3226 				action = ACTION_CHRONOSPHERE;
   3227 			}
   3228 
   3229 			if (Map.IsTargettingMode == SPC_CHRONO2) {
   3230 				action = ACTION_CHRONO2;
   3231 				if (shadow) action = ACTION_NOMOVE;
   3232 				ObjectClass const * tobject = As_Object(PlayerPtr->UnitToTeleport);
   3233 
   3234 				/*
   3235 				**	Determine if the object can be teleported to the destination cell.
   3236 				*/
   3237 				if (tobject != NULL && tobject->Is_Techno()) {
   3238 					TechnoClass const * uobject = (TechnoClass const *)tobject;
   3239 					if (!uobject->Can_Teleport_Here(cell)) {
   3240 //					if (((UnitClass *)As_Object(PlayerPtr->UnitToTeleport))->Can_Enter_Cell(cell, FACING_NONE) != MOVE_OK) {
   3241 						action = ACTION_NOMOVE;
   3242 					}
   3243 
   3244 				}
   3245 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   3246 				else {	// If the object is no longer valid, cancel targetting mode.
   3247 					action = ACTION_NOMOVE;
   3248 					Map.IsTargettingMode = SPC_NONE;
   3249 				}
   3250 #endif
   3251 			}
   3252 
   3253 			if (Map.PendingObject) {
   3254 				action = ACTION_NONE;
   3255 			}
   3256 		}
   3257 
   3258 		/*
   3259 		**	Move any cursor displayed.
   3260 		*/
   3261 		if (cell != Map.ZoneCell) {
   3262 			Map.Set_Cursor_Pos(cell);
   3263 		}
   3264 
   3265 		/*
   3266 		**	A right mouse button press cancels the current action or selection.
   3267 		*/
   3268 		if (flags & RIGHTPRESS) {
   3269 			Map.Mouse_Right_Press();
   3270 		}
   3271 
   3272 		/*
   3273 		**	Make sure that if the mouse button has been released and the map doesn't know about it,
   3274 		**	then it must be informed. Do this by faking a mouse release event.
   3275 		*/
   3276 		if ((flags & LEFTUP) && Map.IsRubberBand) {
   3277 			flags |= LEFTRELEASE;
   3278 		}
   3279 
   3280 		/*
   3281 		**	When the mouse buttons aren't pressed, only the mouse cursor shape is processed.
   3282 		**	The shape changes depending on what object the mouse is currently over and what
   3283 		**	object is currently selected.
   3284 		*/
   3285 		if (!edge) {
   3286 			if (flags & LEFTUP) {
   3287 				Map.Mouse_Left_Up(cell, shadow, object, action);
   3288 			}
   3289 		}
   3290 
   3291 		/*
   3292 		**	Normal actions occur when the mouse button is released. The press event is
   3293 		**	intercepted and possible rubber-band mode is flagged.
   3294 		*/
   3295 		if (flags & LEFTRELEASE) {
   3296 			Map.Mouse_Left_Release(cell, x, y, object, action);
   3297 		}
   3298 
   3299 		/*
   3300 		**	When the mouse is first pressed on the map, then record the mouse
   3301 		**	position so that a proper check before going into rubber band
   3302 		**	mode can be made. Rubber band mode starts when the mouse is
   3303 		**	held down and moved a certain minimum distance.
   3304 		*/
   3305 		if (!edge && (flags & LEFTPRESS)) {
   3306 			Map.Mouse_Left_Up(cell, shadow, object, action);
   3307 			Map.Mouse_Left_Press(x, y);
   3308 		}
   3309 
   3310 		/*
   3311 		**	While the mouse is being held down, determine if rubber band mode should
   3312 		**	start. If rubber band mode is already active, then update the size
   3313 		**	and flag the map to redraw it.
   3314 		*/
   3315 		if (flags & LEFTHELD) {
   3316 			Map.Mouse_Left_Held(x, y);
   3317 		}
   3318 	}
   3319 
   3320 	return(GadgetClass::Action(0, key));
   3321 }
   3322 
   3323 
   3324 /***********************************************************************************************
   3325  * DisplayClass::TacticalClass::Selection_At_Mouse --  Object selection								  *
   3326  *																															  *
   3327  *     Selects any objects at the current mouse position.		                                *
   3328  *																													        *
   3329  *                                                                                             *
   3330  * INPUT:   flags -- The gadget event flags that triggered the call to this function.          *
   3331  *                                                                                             *
   3332  *          key   -- A reference to the keyboard event (if any).                               *
   3333  *                                                                                             *
   3334  * OUTPUT:  bool; Should processing be aborted on any succeeding buttons in the chain?         *
   3335  *                                                                                             *
   3336  * WARNINGS:   none                                                                            *
   3337  *                                                                                             *
   3338  * HISTORY:                                                                                    *
   3339  *   2019/09/17  JAS					                                                              *
   3340  *=============================================================================================*/
   3341 int DisplayClass::TacticalClass::Selection_At_Mouse(unsigned flags, KeyNumType & key)
   3342 {
   3343 	int		x, y;					// Sub cell pixel coordinates.
   3344 	bool edge = false;
   3345 	if (flags & (LEFTPRESS | LEFTRELEASE | RIGHTPRESS | RIGHTRELEASE)) {
   3346 		x = Keyboard->MouseQX;
   3347 		y = Keyboard->MouseQY;
   3348 	}
   3349 	else {
   3350 		x = Get_Mouse_X();
   3351 		y = Get_Mouse_Y();
   3352 
   3353 		if (x == 0 || y == 199 || x == 319) edge = true;
   3354 	}
   3355 	COORDINATE coord = Map.Pixel_To_Coord(x, y);
   3356 	CELL cell = Coord_Cell(coord);
   3357 
   3358 	if (coord) {
   3359 		bool shadow = (!Map[cell].Is_Visible(PlayerPtr) && !Debug_Unshroud);					// Use PlayerPtr since we won't be rendering in MP. ST - 3/6/2019 2:49PM
   3360 		x -= Map.TacPixelX;
   3361 		y -= Map.TacPixelY;
   3362 
   3363 		/*
   3364 		** Cause any displayed cursor to move along with the mouse cursor.
   3365 		*/
   3366 		if (cell != Map.ZoneCell) {
   3367 			Map.Set_Cursor_Pos(cell);
   3368 		}
   3369 
   3370 		ObjectClass* object = nullptr;
   3371 
   3372 		/*
   3373 		**	Determine the object that the mouse is currently over.
   3374 		*/
   3375 		if (!shadow) {
   3376 			object = Map.Close_Object(coord);
   3377 		}
   3378 
   3379 		if (object != nullptr)
   3380 		{
   3381 			bool shiftdown = DLL_Export_Get_Input_Key_State(KN_LSHIFT);
   3382 
   3383 			if (shiftdown)
   3384 			{
   3385 				Map.Mouse_Left_Release(cell, x, y, object, ACTION_TOGGLE_SELECT);
   3386 			}
   3387 			else
   3388 			{
   3389 				Map.Mouse_Left_Release(cell, x, y, object, ACTION_SELECT);
   3390 			}
   3391 
   3392 		}
   3393 		else
   3394 		{
   3395 			Unselect_All();
   3396 		}
   3397 	}
   3398 
   3399 	return 0;
   3400 }
   3401 
   3402 /***********************************************************************************************
   3403  * DisplayClass::TacticalClass::Command_Object --  Commanding Units								     *
   3404  *																															  *
   3405  *     Issues a command to the currently selected unit.			                                *
   3406  *																													        *
   3407  *                                                                                             *
   3408  * INPUT:   flags -- The gadget event flags that triggered the call to this function.          *
   3409  *                                                                                             *
   3410  *          key   -- A reference to the keyboard event (if any).                               *
   3411  *                                                                                             *
   3412  * OUTPUT:  bool; Should processing be aborted on any succeeding buttons in the chain?         *
   3413  *                                                                                             *
   3414  * WARNINGS:   none                                                                            *
   3415  *                                                                                             *
   3416  * HISTORY:                                                                                    *
   3417  *   2019/09/17  JAS					                                                              *
   3418  *=============================================================================================*/
   3419 int DisplayClass::TacticalClass::Command_Object(unsigned flags, KeyNumType & key)
   3420 {
   3421 	int		x, y;					// Sub cell pixel coordinates.
   3422 	bool edge = false;
   3423 	if (flags & (LEFTPRESS | LEFTRELEASE | RIGHTPRESS | RIGHTRELEASE)) {
   3424 		x = Keyboard->MouseQX;
   3425 		y = Keyboard->MouseQY;
   3426 	}
   3427 	else {
   3428 		x = Get_Mouse_X();
   3429 		y = Get_Mouse_Y();
   3430 
   3431 		if (x == 0 || y == 199 || x == 319) edge = true;
   3432 	}
   3433 	COORDINATE coord = Map.Pixel_To_Coord(x, y);
   3434 	CELL cell = Coord_Cell(coord);
   3435 
   3436 	ActionType action = ACTION_NONE;
   3437 
   3438 	if (coord) {
   3439 		bool shadow = (!Map[cell].Is_Mapped(PlayerPtr) && !Debug_Unshroud);					// Use PlayerPtr since we won't be rendering in MP. ST - 3/6/2019 2:49PM
   3440 		x -= Map.TacPixelX;
   3441 		y -= Map.TacPixelY;
   3442 
   3443 		/*
   3444 		** Cause any displayed cursor to move along with the mouse cursor.
   3445 		*/
   3446 		if (cell != Map.ZoneCell) {
   3447 			Map.Set_Cursor_Pos(cell);
   3448 		}
   3449 
   3450 		ObjectClass* object = nullptr;
   3451 
   3452 		/*
   3453 		**	Determine the object that the mouse is currently over.
   3454 		*/
   3455 		if (!shadow) {
   3456 			object = Map.Close_Object(coord);
   3457 		}
   3458 
   3459 		if (CurrentObject.Count()) {
   3460 			if (object) {
   3461 				action = Best_Object_Action(object);
   3462 			}
   3463 			else {
   3464 				action = Best_Object_Action(cell);
   3465 			}
   3466 		}
   3467 
   3468 		if (action != ACTION_SELECT)
   3469 		{
   3470 			Map.Mouse_Left_Release(cell, x, y, object, action);
   3471 		}
   3472 	}
   3473 	return 0;
   3474 }
   3475 
   3476 
   3477 /***********************************************************************************************
   3478  * DisplayClass::Mouse_Right_Press -- Handles the right mouse button press.                    *
   3479  *                                                                                             *
   3480  *    This routine is called when the right mouse button is pressed. This action is supposed   *
   3481  *    to cancel whatever mode or process is active. If there is nothing to cancel, then it     *
   3482  *    will default to unselecting any units that might be currently selected.                  *
   3483  *                                                                                             *
   3484  * INPUT:   none                                                                               *
   3485  *                                                                                             *
   3486  * OUTPUT:  none                                                                               *
   3487  *                                                                                             *
   3488  * WARNINGS:   none                                                                            *
   3489  *                                                                                             *
   3490  * HISTORY:                                                                                    *
   3491  *   02/24/1995 JLB : Created.                                                                 *
   3492  *=============================================================================================*/
   3493 void DisplayClass::Mouse_Right_Press(void)
   3494 {
   3495 	if (PendingObjectPtr && PendingObjectPtr->Is_Techno()) {
   3496 		//PendingObjectPtr->Transmit_Message(RADIO_OVER_OUT);
   3497 		PendingObjectPtr = 0;
   3498 		PendingObject = 0;
   3499 		PendingHouse = HOUSE_NONE;
   3500 		Set_Cursor_Shape(0);
   3501 	} else {
   3502 		if (IsRepairMode) {
   3503 			IsRepairMode = false;
   3504 		} else {
   3505 			if (IsSellMode) {
   3506 				IsSellMode = false;
   3507 			} else {
   3508 				if (IsTargettingMode != SPC_NONE) {
   3509 					IsTargettingMode = SPC_NONE;
   3510 				} else {
   3511 					Unselect_All();
   3512 				}
   3513 			}
   3514 		}
   3515 	}
   3516 
   3517 	// If it breaks... call 228.
   3518 	Set_Default_Mouse(MOUSE_NORMAL, Map.IsSmall);
   3519 }
   3520 
   3521 
   3522 /***********************************************************************************************
   3523  * DisplayClass::Mouse_Left_Up -- Handles the left mouse "cruising" over the map.              *
   3524  *                                                                                             *
   3525  *    This routine is called continuously while the mouse is over the tactical map but there   *
   3526  *    are no mouse buttons pressed. Typically, this adjusts the mouse shape and the pop-up     *
   3527  *    help text.                                                                               *
   3528  *                                                                                             *
   3529  * INPUT:   shadow   -- Is the mouse hovering over shadowed terrain?                           *
   3530  *                                                                                             *
   3531  *          object   -- Pointer to the object that the mouse is currently over (may be NULL).  *
   3532  *                                                                                             *
   3533  *          action   -- This is the action that the currently selected object (if any) will    *
   3534  *                      perform if the left mouse button were clicked at this location.        *
   3535  *                                                                                             *
   3536  * OUTPUT:  none                                                                               *
   3537  *                                                                                             *
   3538  * WARNINGS:   none                                                                            *
   3539  *                                                                                             *
   3540  * HISTORY:                                                                                    *
   3541  *   02/24/1995 JLB : Created.                                                                 *
   3542  *   07/05/1995 JLB : Removed pop up help text for shadow and terrain after #3.                *
   3543  *=============================================================================================*/
   3544 void DisplayClass::Mouse_Left_Up(CELL cell, bool shadow, ObjectClass * object, ActionType action, bool wsmall)
   3545 {
   3546 	IsTentative = false;
   3547 
   3548 	TARGET target = TARGET_NONE;
   3549 	if (object != NULL) {
   3550 		target = object->As_Target();
   3551 	} else {
   3552 		if (cell != -1) {
   3553 			target = As_Target(cell);
   3554 		}
   3555 	}
   3556 
   3557 	/*
   3558 	**	Don't allow selection of an object that is located in shadowed terrain.
   3559 	**	In fact, just show the normal move cursor in order to keep the shadowed
   3560 	**	terrain a mystery.
   3561 	*/
   3562 	if (shadow) {
   3563 		switch (action) {
   3564 			case ACTION_NO_DEPLOY:
   3565 				Set_Default_Mouse(MOUSE_NO_DEPLOY, wsmall);
   3566 				break;
   3567 
   3568 			case ACTION_NO_ENTER:
   3569 				Set_Default_Mouse(MOUSE_NO_ENTER, wsmall);
   3570 				break;
   3571 
   3572 			case ACTION_NO_GREPAIR:
   3573 				Set_Default_Mouse(MOUSE_NO_GREPAIR, wsmall);
   3574 				break;
   3575 
   3576 			case ACTION_DAMAGE:
   3577 				Set_Default_Mouse(MOUSE_NORMAL, wsmall);
   3578 				break;
   3579 
   3580 			case ACTION_GREPAIR:
   3581 				Set_Default_Mouse(MOUSE_NORMAL, wsmall);
   3582 				break;
   3583 
   3584 			case ACTION_GUARD_AREA:
   3585 				Set_Default_Mouse(MOUSE_AREA_GUARD, wsmall);
   3586 				break;
   3587 
   3588 			case ACTION_NONE:
   3589 				Set_Default_Mouse(MOUSE_NORMAL, wsmall);
   3590 				break;
   3591 
   3592 			case ACTION_NO_SELL:
   3593 			case ACTION_SELL:
   3594 			case ACTION_SELL_UNIT:
   3595 				Set_Default_Mouse(MOUSE_NO_SELL_BACK, wsmall);
   3596 				break;
   3597 
   3598 			case ACTION_NO_REPAIR:
   3599 			case ACTION_REPAIR:
   3600 				Set_Default_Mouse(MOUSE_NO_REPAIR, wsmall);
   3601 				break;
   3602 
   3603 			case ACTION_NUKE_BOMB:
   3604 				Set_Default_Mouse(MOUSE_NUCLEAR_BOMB, wsmall);
   3605 				break;
   3606 
   3607 			case ACTION_AIR_STRIKE:
   3608 			case ACTION_PARA_BOMB:
   3609 			case ACTION_PARA_INFANTRY:
   3610 			case ACTION_SPY_MISSION:
   3611 			case ACTION_IRON_CURTAIN:
   3612 				Set_Default_Mouse(MOUSE_AIR_STRIKE, wsmall);
   3613 				break;
   3614 
   3615 			case ACTION_CHRONOSPHERE:
   3616 				Set_Default_Mouse(MOUSE_CHRONO_SELECT, wsmall);
   3617 				break;
   3618 
   3619 			case ACTION_CHRONO2:
   3620 				Set_Default_Mouse(MOUSE_CHRONO_DEST, wsmall);
   3621 				break;
   3622 
   3623 			case ACTION_HEAL:
   3624 				Set_Default_Mouse(MOUSE_HEAL, wsmall);
   3625 				break;
   3626 
   3627 			case ACTION_NOMOVE:
   3628 				if (CurrentObject.Count()) {
   3629 					MouseType mouse_type = MOUSE_NO_MOVE;
   3630 					for (int i = 0; i < CurrentObject.Count(); ++i) {
   3631 						if (CurrentObject[i]->What_Am_I() != RTTI_AIRCRAFT) {
   3632 							mouse_type = MOUSE_CAN_MOVE;
   3633 							break;
   3634 						}
   3635 					}
   3636 					Set_Default_Mouse(mouse_type, wsmall);
   3637 					break;
   3638 				}
   3639 				// Fall into next case for non aircraft object types.
   3640 
   3641 			default:
   3642 				Set_Default_Mouse(MOUSE_CAN_MOVE, wsmall);
   3643 				break;
   3644 
   3645 		}
   3646 	} else {
   3647 
   3648 		/*
   3649 		**	Change the mouse shape according to the default action that will occur
   3650 		**	if the mouse button were clicked at this location.
   3651 		*/
   3652 		switch (action) {
   3653 			case ACTION_NO_DEPLOY:
   3654 				Set_Default_Mouse(MOUSE_NO_DEPLOY, wsmall);
   3655 				break;
   3656 
   3657 			case ACTION_NO_ENTER:
   3658 				Set_Default_Mouse(MOUSE_NO_ENTER, wsmall);
   3659 				break;
   3660 
   3661 			case ACTION_NO_GREPAIR:
   3662 				Set_Default_Mouse(MOUSE_NO_GREPAIR, wsmall);
   3663 				break;
   3664 
   3665 			case ACTION_DAMAGE:
   3666 				Set_Default_Mouse(MOUSE_DAMAGE, wsmall);
   3667 				break;
   3668 
   3669 			case ACTION_GREPAIR:
   3670 				Set_Default_Mouse(MOUSE_GREPAIR, wsmall);
   3671 				break;
   3672 
   3673 			case ACTION_TOGGLE_SELECT:
   3674 			case ACTION_SELECT:
   3675 				Set_Default_Mouse(MOUSE_CAN_SELECT, wsmall);
   3676 				break;
   3677 
   3678 			case ACTION_MOVE:
   3679 				Set_Default_Mouse(MOUSE_CAN_MOVE, wsmall);
   3680 				break;
   3681 
   3682 			case ACTION_GUARD_AREA:
   3683 				Set_Default_Mouse(MOUSE_AREA_GUARD, wsmall);
   3684 				break;
   3685 
   3686 			case ACTION_ATTACK:
   3687 				if (Target_Legal(target) && CurrentObject.Count() == 1 && CurrentObject[0]->Is_Techno() && ((TechnoClass *)CurrentObject[0])->In_Range(target, 0)) {
   3688 					Set_Default_Mouse(MOUSE_STAY_ATTACK, wsmall);
   3689 					break;
   3690 				}
   3691 				// fall into next case.
   3692 
   3693 			case ACTION_HARVEST:
   3694 				Set_Default_Mouse(MOUSE_CAN_ATTACK, wsmall);
   3695 				break;
   3696 
   3697 			case ACTION_SABOTAGE:
   3698 				Set_Default_Mouse(MOUSE_DEMOLITIONS, wsmall);
   3699 				break;
   3700 
   3701 			case ACTION_ENTER:
   3702 			case ACTION_CAPTURE:
   3703 				Set_Default_Mouse(MOUSE_ENTER, wsmall);
   3704 				break;
   3705 
   3706 			case ACTION_NOMOVE:
   3707 				Set_Default_Mouse(MOUSE_NO_MOVE, wsmall);
   3708 				break;
   3709 
   3710 			case ACTION_NO_SELL:
   3711 				Set_Default_Mouse(MOUSE_NO_SELL_BACK, wsmall);
   3712 				break;
   3713 
   3714 			case ACTION_NO_REPAIR:
   3715 				Set_Default_Mouse(MOUSE_NO_REPAIR, wsmall);
   3716 				break;
   3717 
   3718 			case ACTION_SELF:
   3719 				Set_Default_Mouse(MOUSE_DEPLOY, wsmall);
   3720 				break;
   3721 
   3722 			case ACTION_REPAIR:
   3723 				Set_Default_Mouse(MOUSE_REPAIR, wsmall);
   3724 				break;
   3725 
   3726 			case ACTION_SELL_UNIT:
   3727 				Set_Default_Mouse(MOUSE_SELL_UNIT, wsmall);
   3728 				break;
   3729 
   3730 			case ACTION_SELL:
   3731 				Set_Default_Mouse(MOUSE_SELL_BACK, wsmall);
   3732 				break;
   3733 
   3734 			case ACTION_NUKE_BOMB:
   3735 				Set_Default_Mouse(MOUSE_NUCLEAR_BOMB, wsmall);
   3736 				break;
   3737 
   3738 			case ACTION_AIR_STRIKE:
   3739 			case ACTION_PARA_BOMB:
   3740 			case ACTION_PARA_INFANTRY:
   3741 			case ACTION_SPY_MISSION:
   3742 			case ACTION_IRON_CURTAIN:
   3743 				Set_Default_Mouse(MOUSE_AIR_STRIKE, wsmall);
   3744 				break;
   3745 
   3746 			case ACTION_CHRONOSPHERE:
   3747 				Set_Default_Mouse(MOUSE_CHRONO_SELECT, wsmall);
   3748 				break;
   3749 
   3750 			case ACTION_CHRONO2:
   3751 				Set_Default_Mouse(MOUSE_CHRONO_DEST, wsmall);
   3752 				break;
   3753 
   3754 			case ACTION_HEAL:
   3755 				Set_Default_Mouse(MOUSE_HEAL, wsmall);
   3756 				break;
   3757 
   3758 			case ACTION_TOGGLE_PRIMARY:
   3759 				Set_Default_Mouse(MOUSE_DEPLOY, wsmall);
   3760 				break;
   3761 
   3762 			default:
   3763 				Set_Default_Mouse(MOUSE_NORMAL, wsmall);
   3764 				break;
   3765 		}
   3766 	}
   3767 #if 0
   3768 	/*
   3769 	**	Never display help text if the mouse is held over the radar map.
   3770 	*/
   3771 	if (wsmall) {
   3772 		return;
   3773 	}
   3774 
   3775 	/*
   3776 	**	Give a generic help message when over shadow terrain.
   3777 	*/
   3778 	if (shadow) {
   3779 //		if (Scen.Scenario < 4) {
   3780 			Help_Text(TXT_SHADOW);
   3781 //		} else {
   3782 //			Help_Text(TXT_NONE);
   3783 //		}
   3784 	} else {
   3785 
   3786 		/*
   3787 		**	If the mouse is held over objects on the map, then help text may
   3788 		**	pop up that tells what the object is. This call informs the help
   3789 		**	system of the text name for the object under the mouse.
   3790 		*/
   3791 		if (object != NULL) {
   3792 			int text;
   3793 			int color = LTGREY;
   3794 
   3795 			/*
   3796 			**	Fetch the appropriate background color for help text.
   3797 			*/
   3798 			if (PlayerPtr->Is_Ally(object)) {
   3799 				color = GREEN;
   3800 			} else {
   3801 				if (object->Owner() == HOUSE_NONE || object->Owner() == HOUSE_NEUTRAL) {
   3802 					color = LTGREY;
   3803 				} else {
   3804 					color = PINK;
   3805 				}
   3806 			}
   3807 
   3808 			/*
   3809 			**	Fetch the name of the object. If it is an enemy object, then
   3810 			**	the exact identity is glossed over with a generic text.
   3811 			*/
   3812 			text = object->Full_Name();
   3813 			if (object->Is_Techno() && !((TechnoTypeClass const &)object->Class_Of()).IsNominal) {
   3814 
   3815 				if (!((TechnoClass *)object)->House->Is_Ally(PlayerPtr)) {
   3816 //				if (!PlayerPtr->Is_Ally(object)) {
   3817 					switch (object->What_Am_I()) {
   3818 						case RTTI_INFANTRY:
   3819 							text = TXT_ENEMY_SOLDIER;
   3820 							break;
   3821 
   3822 						case RTTI_UNIT:
   3823 							text = TXT_ENEMY_VEHICLE;
   3824 							break;
   3825 
   3826 						case RTTI_BUILDING:
   3827 							text = TXT_ENEMY_STRUCTURE;
   3828 							break;
   3829 					}
   3830 				}
   3831 			}
   3832 
   3833 			if (/*Scen.Scenario > 3 ||*/ object->What_Am_I() != RTTI_TERRAIN) {
   3834 				Help_Text(text, -1, -1, color);
   3835 			} else {
   3836 				Help_Text(TXT_NONE);
   3837 			}
   3838 		} else {
   3839 			if ((*this)[cell].Land_Type() == LAND_TIBERIUM) {
   3840 				Help_Text(TXT_MINERALS);
   3841 			} else {
   3842 				Help_Text(TXT_NONE);
   3843 			}
   3844 		}
   3845 	}
   3846 #endif
   3847 }
   3848 
   3849 
   3850 /***********************************************************************************************
   3851  * DisplayClass::Mouse_Left_Release -- Handles the left mouse button release.                  *
   3852  *                                                                                             *
   3853  *    This routine is called when the left mouse button is released over the tactical map.     *
   3854  *    The release event is the workhorse of the game. Most actions occur at the moment of      *
   3855  *    mouse release.                                                                           *
   3856  *                                                                                             *
   3857  * INPUT:   cell     -- The cell that the mouse is over.                                       *
   3858  *                                                                                             *
   3859  *          x,y      -- The mouse pixel coordinate.                                            *
   3860  *                                                                                             *
   3861  *          object   -- Pointer to the object that the mouse is over.                          *
   3862  *                                                                                             *
   3863  *          action   -- The action that the currently selected object (if any) will            *
   3864  *                      perform.                                                               *
   3865  *                                                                                             *
   3866  * OUTPUT:  none                                                                               *
   3867  *                                                                                             *
   3868  * WARNINGS:   none                                                                            *
   3869  *                                                                                             *
   3870  * HISTORY:                                                                                    *
   3871  *   02/24/1995 JLB : Created.                                                                 *
   3872  *   03/27/1995 JLB : Handles sell and repair actions.                                         *
   3873  *=============================================================================================*/
   3874 void DisplayClass::Mouse_Left_Release(CELL cell, int x, int y, ObjectClass * object, ActionType action, bool wsmall)
   3875 {
   3876 	if (PendingObjectPtr) {
   3877 		/*
   3878 		**	Try to place the pending object onto the map.
   3879 		*/
   3880 		if (ProximityCheck) {
   3881 			OutList.Add(EventClass(EventClass::PLACE, PendingObjectPtr->What_Am_I(), cell + ZoneOffset));
   3882 		} else {
   3883 			Speak(VOX_DEPLOY);
   3884 		}
   3885 
   3886 	} else {
   3887 
   3888 		if (IsRubberBand) {
   3889 			Refresh_Band();
   3890 			Select_These(XYP_Coord(BandX, BandY), XYP_Coord(x, y));
   3891 
   3892 			Set_Default_Mouse(MOUSE_NORMAL, wsmall);
   3893 			IsRubberBand = false;
   3894 			IsTentative = false;
   3895 			Map.DisplayClass::IsToRedraw = true;
   3896 			Map.Flag_To_Redraw(false);
   3897 
   3898 		} else {
   3899 
   3900 			/*
   3901 			**	Toggle the select state of the object.
   3902 			*/
   3903 			if (action == ACTION_TOGGLE_SELECT) {
   3904 				if (!object || !CurrentObject.Count()) {
   3905 					action = ACTION_SELECT;
   3906 				} else {
   3907 					if (object->Is_Selected_By_Player()) {
   3908 						object->Unselect();
   3909 					} else {
   3910 						object->Select();
   3911 					}
   3912 				}
   3913 			}
   3914 
   3915 			/*
   3916 			**	Selection of other object action.
   3917 			*/
   3918 			if (action == ACTION_SELECT || (action == ACTION_NONE && object && object->Class_Of().IsSelectable && !object->Is_Selected_By_Player())) {
   3919 				if (object->Is_Selected_By_Player()) {
   3920 					object->Unselect();
   3921 				}
   3922 				if (object->Select()) {
   3923 					Unselect_All_Except(object);
   3924 					Set_Default_Mouse(MOUSE_NORMAL, wsmall);
   3925 				}
   3926 			}
   3927 
   3928 			/*
   3929 			**	If an action was detected as possible, then pass this action event
   3930 			**	to all selected objects.
   3931 			*/
   3932 			if (action != ACTION_NONE && action != ACTION_SELECT && action != ACTION_TOGGLE_SELECT) {
   3933 
   3934 				/*
   3935 				**	Pass the action to all the selected objects. But first, redetermine
   3936 				**	what action that object should perform. This, seemingly redundant
   3937 				**	process, is necessary since multiple objects could be selected and each
   3938 				**	might perform a different action when the click occurs.
   3939 				*/
   3940 				bool doflash = true;
   3941 				AllowVoice = true;
   3942 				FormMove = false;
   3943 				FormSpeed = SPEED_WHEEL;
   3944 				FormMaxSpeed = MPH_LIGHT_SPEED;
   3945 
   3946 				if ( (action == ACTION_MOVE || action == ACTION_NOMOVE) && CurrentObject.Count()) {
   3947 
   3948 					/*
   3949 					** Scan all units.  If any are selected that shouldn't be, or aren't
   3950 					** selected but should be, then this is not a formation move.
   3951 					*/
   3952 					int group = 254;	// init to invalid group #
   3953 
   3954 					if (CurrentObject[0]->Is_Foot()) {
   3955 						group = ((FootClass *)CurrentObject[0])->Group;
   3956 					}
   3957 
   3958 					/*
   3959 					**	Presume this is a formation move unless something is detected
   3960 					**	that will prevent it.
   3961 					*/
   3962 					FormMove = true;
   3963 
   3964 					/*
   3965 					**	First scan through all the selected units to make sure that they
   3966 					**	are all of the same team and have been assigned a particular formation
   3967 					*/
   3968 					for (int index = 0; index < CurrentObject.Count(); index++) {
   3969 						ObjectClass const * tobject = CurrentObject[index];
   3970 
   3971 						/*
   3972 						**	Only moveable (i.e., FootClass) objects can ever be in a formation
   3973 						**	so if a selected object isn't of a FootClass type then it can't be
   3974 						**	a formation move.
   3975 						*/
   3976 						if (tobject->Is_Foot() == false) {
   3977 							FormMove = false;
   3978 							break;
   3979 						}
   3980 
   3981 						/*
   3982 						**	If the object is not part of the same team as the rest of the
   3983 						**	selected group, or it just plain has never been assigned a
   3984 						**	formation offset, then it can't be a formation move.
   3985 						*/
   3986 						FootClass const * foot = (FootClass *)tobject;
   3987 						if (foot->Group != group || foot->XFormOffset == 0x80000000) {
   3988 							FormMove = false;
   3989 							break;
   3990 						}
   3991 
   3992 						/*
   3993 						**	Determine the formation speed on the presumption that this
   3994 						**	will turn out to be a formation move.
   3995 						*/
   3996 						MPHType maxspeed = foot->Techno_Type_Class()->MaxSpeed;
   3997 						if (maxspeed < FormMaxSpeed) {
   3998 							FormMaxSpeed = maxspeed;
   3999 							FormSpeed = foot->Techno_Type_Class()->Speed;
   4000 						}
   4001 					}
   4002 
   4003 					/*
   4004 					**	Loop through all objects (that can theoretically be part of a team) and
   4005 					**	if there are any that are part of the currently selected team, but
   4006 					**	are not currently selected themselves, then this will force this move
   4007 					**	to NOT be a formation move.
   4008 					*/
   4009 					if (FormMove) {
   4010 						for (int index = 0; index < ::Logic.Count(); index++) {
   4011 							ObjectClass const * obj = ::Logic[index];
   4012 
   4013 							/*
   4014 							**	If the object is selected, then it has already been scanned
   4015 							**	by the previous loop.
   4016 							*/
   4017 							if (obj->Is_Selected_By_Player()) continue;
   4018 
   4019 							/*
   4020 							**	Only consider footclass objects.
   4021 							*/
   4022 							if (!obj->Is_Foot()) continue;
   4023 
   4024 							FootClass const * foot = (FootClass *)obj;
   4025 
   4026 							/*
   4027 							**	Only consider objects that are owned by the player.
   4028 							*/
   4029 							if (!foot->Is_Owned_By_Player()) continue;
   4030 
   4031 							/*
   4032 							**	If another member of this team has been discovered and
   4033 							**	it isn't selected, then the formation move cannot take
   4034 							**	place.
   4035 							*/
   4036 							if (foot->Group == group) {
   4037 								FormMove = false;
   4038 								break;
   4039 							}
   4040 						}
   4041 					}
   4042 				}
   4043 
   4044 				for (int index = 0; index < CurrentObject.Count(); index++) {
   4045 					ObjectClass * tobject = CurrentObject[index];
   4046 
   4047 					if (object != NULL) {
   4048 						tobject->Active_Click_With(tobject->What_Action(object), object);
   4049 					} else {
   4050 
   4051 						/*
   4052 						** Trap for formation moves: if this unit is part of a
   4053 						** formation (being part of a team qualifies) and they're
   4054 						** told to move, adjust the target destination so they stay
   4055 						** in formation when they arrive.
   4056 						*/
   4057 						CELL newmove = cell;
   4058 						int whatami = tobject->What_Am_I();
   4059 						if (action == ACTION_MOVE && tobject->Is_Foot()) {
   4060 							int oldisform;
   4061 							FootClass * foot = (FootClass *)tobject;
   4062 							oldisform = foot->IsFormationMove;
   4063 							foot->IsFormationMove = FormMove;
   4064 							if (FormMove && foot->Group != 255 ) {
   4065 								newmove = foot->Adjust_Dest(cell);
   4066 							}
   4067 							foot->IsFormationMove = oldisform;
   4068 						}
   4069 						tobject->Active_Click_With(tobject->What_Action(cell), newmove);
   4070 					}
   4071 					AllowVoice = false;
   4072 				}
   4073 				AllowVoice = true;
   4074 				FormMove = false;
   4075 
   4076 				if (action == ACTION_REPAIR && object->What_Am_I() == RTTI_BUILDING) {
   4077 					OutList.Add(EventClass(EventClass::REPAIR, TargetClass(object)));
   4078 				}
   4079 				if (action == ACTION_SELL_UNIT && object) {
   4080 					switch (object->What_Am_I()) {
   4081 						case RTTI_AIRCRAFT:
   4082 						case RTTI_UNIT:
   4083 							OutList.Add(EventClass(EventClass::SELL, TargetClass(object)));
   4084 							break;
   4085 
   4086 						default:
   4087 							break;
   4088 					}
   4089 
   4090 				}
   4091 				if (action == ACTION_SELL) {
   4092 					if (object) {
   4093 						OutList.Add(EventClass(EventClass::SELL, TargetClass(object)));
   4094 					} else {
   4095 						OutList.Add(EventClass(EventClass::SELLCELL, cell));
   4096 //						OutList.Add(EventClass(EventClass::SELL, ::As_Target(cell)));
   4097 					}
   4098 				}
   4099 
   4100 				if (action == ACTION_NUKE_BOMB) {
   4101 					OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_NUCLEAR_BOMB, cell));
   4102 				}
   4103 
   4104 				if (action == ACTION_PARA_BOMB) {
   4105 					OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_PARA_BOMB, cell));
   4106 				}
   4107 				if (action == ACTION_PARA_INFANTRY) {
   4108 					OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_PARA_INFANTRY, cell));
   4109 				}
   4110 				if (action == ACTION_SPY_MISSION) {
   4111 					OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_SPY_MISSION, cell));
   4112 				}
   4113 				if (action == ACTION_IRON_CURTAIN) {
   4114 					OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_IRON_CURTAIN, cell));
   4115 				}
   4116 				if (action == ACTION_CHRONOSPHERE) {
   4117 					OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_CHRONOSPHERE, cell));
   4118 				}
   4119 				if (action == ACTION_CHRONO2) {
   4120 					OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_CHRONO2, cell));
   4121 				}
   4122 			}
   4123 
   4124 			IsTentative = false;
   4125 		}
   4126 	}
   4127 }
   4128 
   4129 
   4130 /***********************************************************************************************
   4131  * DisplayClass::Mouse_Left_Press -- Handles the left mouse button press.                      *
   4132  *                                                                                             *
   4133  *    Handle the left mouse button press while over the tactical map. If it isn't is           *
   4134  *    repair or sell mode, then a tentative transition to rubber band mode is flagged. If the  *
   4135  *    mouse moves a sufficient distance from this recorded position, then rubber band mode     *
   4136  *    is officially started.                                                                   *
   4137  *                                                                                             *
   4138  * INPUT:   x,y   -- The mouse coordinates at the time of the press.                           *
   4139  *                                                                                             *
   4140  * OUTPUT:  none                                                                               *
   4141  *                                                                                             *
   4142  * WARNINGS:   none                                                                            *
   4143  *                                                                                             *
   4144  * HISTORY:                                                                                    *
   4145  *   02/24/1995 JLB : Created.                                                                 *
   4146  *=============================================================================================*/
   4147 void DisplayClass::Mouse_Left_Press(int x, int y)
   4148 {
   4149 	if (!IsRepairMode && !IsSellMode && IsTargettingMode == SPC_NONE && !PendingObject) {
   4150 		IsTentative = true;
   4151 		BandX = x;
   4152 		BandY = y;
   4153 		NewX = x;
   4154 		NewY = y;
   4155 	}
   4156 }
   4157 
   4158 
   4159 /***********************************************************************************************
   4160  * DisplayClass::Mouse_Left_Held -- Handles the left button held down.                         *
   4161  *                                                                                             *
   4162  *    This routine is called continuously while the left mouse button is held down over        *
   4163  *    the tactical map. This handles the rubber band mode detection and dragging.              *
   4164  *                                                                                             *
   4165  * INPUT:   x,y   -- The mouse coordinate.                                                     *
   4166  *                                                                                             *
   4167  * OUTPUT:  none                                                                               *
   4168  *                                                                                             *
   4169  * WARNINGS:   none                                                                            *
   4170  *                                                                                             *
   4171  * HISTORY:                                                                                    *
   4172  *   02/24/1995 JLB : Created.                                                                 *
   4173  *=============================================================================================*/
   4174 void DisplayClass::Mouse_Left_Held(int x, int y)
   4175 {
   4176 	if (IsRubberBand) {
   4177 		if (x != NewX || y != NewY) {
   4178 			x = Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1);
   4179 			y = Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1);
   4180 			Refresh_Band();
   4181 			NewX = x;
   4182 			NewY = y;
   4183 			IsToRedraw = true;
   4184 			Flag_To_Redraw(false);
   4185 		}
   4186 	} else {
   4187 
   4188 		/*
   4189 		**	If the mouse is still held down while a tentative extended select is possible, then
   4190 		**	check to see if the mouse has moved a sufficient distance in order to activate
   4191 		**	extended select mode.
   4192 		*/
   4193 		if (IsTentative) {
   4194 
   4195 			/*
   4196 			**	The mouse must have moved a minimum distance before rubber band mode can be
   4197 			**	initiated.
   4198 			*/
   4199 			if (ABS(x - BandX) > 4 || ABS(y - BandY) > 4) {
   4200 				IsRubberBand = true;
   4201 				x = Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1);
   4202 				y = Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1);
   4203 				NewX = x;
   4204 				NewY = y;
   4205 				IsToRedraw = true;
   4206 				Flag_To_Redraw(false);
   4207 
   4208 				/*
   4209 				**	Stretching the rubber band requires all objects to be redrawn.
   4210 				*/
   4211 				int index;
   4212 				for (index = 0; index < Layer[LAYER_TOP].Count(); index++) {
   4213 					Layer[LAYER_TOP][index]->Mark(MARK_CHANGE);
   4214 				}
   4215 				for (index = 0; index < Layer[LAYER_AIR].Count(); index++) {
   4216 					Layer[LAYER_AIR][index]->Mark(MARK_CHANGE);
   4217 				}
   4218 
   4219 			}
   4220 		}
   4221 	}
   4222 }
   4223 
   4224 
   4225 // Needed to accomodate Glyphx client sidebar. ST - 4/12/2019 5:29PM
   4226 extern int GlyphXClientSidebarWidthInLeptons;
   4227 
   4228 /***********************************************************************************************
   4229  * DisplayClass::Set_Tactical_Position -- Sets the tactical view position.                     *
   4230  *                                                                                             *
   4231  *    This routine is used to set the tactical view position. The requested position is        *
   4232  *    clipped to the map dimensions as necessary.                                              *
   4233  *                                                                                             *
   4234  * INPUT:   coord -- The coordinate desired for the upper left corner.                         *
   4235  *                                                                                             *
   4236  * OUTPUT:  none                                                                               *
   4237  *                                                                                             *
   4238  * WARNINGS:   none                                                                            *
   4239  *                                                                                             *
   4240  * HISTORY:                                                                                    *
   4241  *   08/13/1995 JLB : Created.                                                                 *
   4242  *=============================================================================================*/
   4243 void DisplayClass::Set_Tactical_Position(COORDINATE coord)
   4244 {
   4245 	/*
   4246 	**	Bound the desired location to fit the legal map edges.
   4247 	*/
   4248 	int xx = 0;// (int)Coord_X(coord) - (int)Cell_To_Lepton(MapCellX);
   4249 	int yy = 0;// (int)Coord_Y(coord) - (int)Cell_To_Lepton(MapCellY);
   4250 
   4251 	Confine_Rect(&xx, &yy, TacLeptonWidth, TacLeptonHeight, Cell_To_Lepton(MapCellWidth) + GlyphXClientSidebarWidthInLeptons, Cell_To_Lepton(MapCellHeight));		// Needed to accomodate Glyphx client sidebar. ST - 4/12/2019 5:29PM
   4252 //	Confine_Rect(&xx, &yy, TacLeptonWidth, TacLeptonHeight, Cell_To_Lepton(MapCellWidth), Cell_To_Lepton(MapCellHeight));
   4253 	coord = XY_Coord(xx + Cell_To_Lepton(MapCellX), yy + Cell_To_Lepton(MapCellY));
   4254 
   4255 	if (ScenarioInit) {
   4256 		TacticalCoord = coord;
   4257 	}
   4258 	DesiredTacticalCoord = coord;
   4259 
   4260 	IsToRedraw = true;
   4261 	Flag_To_Redraw(false);
   4262 }
   4263 
   4264 
   4265 /***********************************************************************************************
   4266  * DisplayClass::Compute_Start_Pos -- Computes player's start pos from unit coords.            *
   4267  *                                                                                             *
   4268  * Use this function in multiplayer games, to compute the scenario starting Tactical Pos.      *
   4269  *                                                                                             *
   4270  * INPUT:   none                                                                               *
   4271  *                                                                                             *
   4272  * OUTPUT:  x, y -- Player starting location                                                   *
   4273  *                                                                                             *
   4274  * WARNINGS:   none                                                                            *
   4275  *                                                                                             *
   4276  * HISTORY:                                                                                    *
   4277  *   02/28/1995 JLB : Commented.                                                               *
   4278  *   06/26/1995 JLB : Fixed building loop.                                                     *
   4279  *   10/20/1996 JLB : Doesn't wrap.                                                            *
   4280  *=============================================================================================*/
   4281 void DisplayClass::Compute_Start_Pos(long& x, long& y)
   4282 {
   4283 	/*
   4284 	**	Find the summation cell-x & cell-y for all the player's units, infantry,
   4285 	**	and buildings.  Buildings are weighted so that they count 16 times more
   4286 	**	than units or infantry.
   4287 	*/
   4288 	x = 0;
   4289 	y = 0;
   4290 	long num = 0;
   4291 	int i;
   4292 	for (i = 0; i < Infantry.Count(); i++) {
   4293 		InfantryClass * infp = Infantry.Ptr(i);
   4294 		if (!infp->IsInLimbo && infp->Is_Owned_By_Player()) {
   4295 			x += (long)Coord_XCell(infp->Coord);
   4296 			y += (long)Coord_YCell(infp->Coord);
   4297 			num++;
   4298 		}
   4299 	}
   4300 
   4301 	for (i = 0; i < Units.Count(); i++) {
   4302 		UnitClass * unitp = Units.Ptr(i);
   4303 		if (!unitp->IsInLimbo && unitp->Is_Owned_By_Player()) {
   4304 			x += (long)Coord_XCell(unitp->Coord);
   4305 			y += (long)Coord_YCell(unitp->Coord);
   4306 			num++;
   4307 		}
   4308 	}
   4309 
   4310 	for (i = 0; i < Buildings.Count(); i++) {
   4311 		BuildingClass * bldgp = Buildings.Ptr(i);
   4312 		if (!bldgp->IsInLimbo && bldgp->Is_Owned_By_Player()) {
   4313 			x += (((long)Coord_XCell(bldgp->Coord)) * 16);
   4314 			y += (((long)Coord_YCell(bldgp->Coord)) * 16);
   4315 			num += 16;
   4316 		}
   4317 	}
   4318 
   4319 	for (i = 0; i < Vessels.Count(); i++) {
   4320 		VesselClass * bldgp = Vessels.Ptr(i);
   4321 		if (!bldgp->IsInLimbo && bldgp->Is_Owned_By_Player()) {
   4322 			x += (((long)Coord_XCell(bldgp->Coord)));
   4323 			y += (((long)Coord_YCell(bldgp->Coord)));
   4324 			num++;
   4325 		}
   4326 	}
   4327 
   4328 	/*
   4329 	**	Divide each coord by 'num' to compute the average value
   4330 	*/
   4331 	if (num > 0) {
   4332 		x /= num;
   4333 	} else {
   4334 		x = 0;
   4335 	}
   4336 
   4337 	if (num > 0) {
   4338 		y /= num;
   4339 	} else {
   4340 		y = 0;
   4341 	}
   4342 }
   4343 
   4344 
   4345 /***********************************************************************************************
   4346  * DisplayClass::Sell_Mode_Control -- Controls the sell mode.                                  *
   4347  *                                                                                             *
   4348  *    This routine will control the sell mode for the player.                                  *
   4349  *                                                                                             *
   4350  * INPUT:   control  -- The mode to set the sell state to.                                     *
   4351  *                      0  = Turn sell mode off.                                               *
   4352  *                      1  = Turn sell mode on.                                                *
   4353  *                      -1 = Toggle sell mode.                                                 *
   4354  *                                                                                             *
   4355  * OUTPUT:  none                                                                               *
   4356  *                                                                                             *
   4357  * WARNINGS:   none                                                                            *
   4358  *                                                                                             *
   4359  * HISTORY:                                                                                    *
   4360  *   07/08/1995 JLB : Created.                                                                 *
   4361  *=============================================================================================*/
   4362 void DisplayClass::Sell_Mode_Control(int control)
   4363 {
   4364 	bool mode = IsSellMode;
   4365 	switch (control) {
   4366 		case 0:
   4367 			mode = false;
   4368 			break;
   4369 
   4370 		case -1:
   4371 			mode = (IsSellMode == false);
   4372 			break;
   4373 
   4374 		case 1:
   4375 			mode = true;
   4376 			break;
   4377 	}
   4378 
   4379 	if (mode != IsSellMode && !PendingObject) {
   4380 		IsRepairMode = false;
   4381 		if (mode && PlayerPtr->BScan) {
   4382 			IsSellMode = true;
   4383 			Unselect_All();
   4384 		} else {
   4385 			IsSellMode = false;
   4386 			Revert_Mouse_Shape();
   4387 		}
   4388 	}
   4389 }
   4390 
   4391 
   4392 /***********************************************************************************************
   4393  * DisplayClass::Repair_Mode_Control -- Controls the repair mode.                              *
   4394  *                                                                                             *
   4395  *    This routine is used to control the repair mode for the player.                          *
   4396  *                                                                                             *
   4397  * INPUT:   control  -- The mode to set the repair to.                                         *
   4398  *                      0 = Turn repair off.                                                   *
   4399  *                      1 = Turn repair on.                                                    *
   4400  *                      -1= Toggle repair state.                                               *
   4401  *                                                                                             *
   4402  * OUTPUT:  none                                                                               *
   4403  *                                                                                             *
   4404  * WARNINGS:   none                                                                            *
   4405  *                                                                                             *
   4406  * HISTORY:                                                                                    *
   4407  *   07/08/1995 JLB : Created.                                                                 *
   4408  *=============================================================================================*/
   4409 void DisplayClass::Repair_Mode_Control(int control)
   4410 {
   4411 	bool mode = IsRepairMode;
   4412 	switch (control) {
   4413 		case 0:
   4414 			mode = false;
   4415 			break;
   4416 
   4417 		case -1:
   4418 			mode = (IsRepairMode == false);
   4419 			break;
   4420 
   4421 		case 1:
   4422 			mode = true;
   4423 			break;
   4424 	}
   4425 
   4426 	if (mode != IsRepairMode && !PendingObject) {
   4427 		IsSellMode = false;
   4428 		if (mode && PlayerPtr->BScan) {
   4429 			IsRepairMode = true;
   4430 			Unselect_All();
   4431 		} else {
   4432 			IsRepairMode = false;
   4433 			Revert_Mouse_Shape();
   4434 		}
   4435 	}
   4436 }
   4437 
   4438 
   4439 /***********************************************************************************************
   4440  * DisplayClass::In_View -- Determines if cell is visible on screen.                           *
   4441  *                                                                                             *
   4442  *    Use this routine to determine if the specified cell is visible on                        *
   4443  *    the display. This is a useful fact, since many display operations                        *
   4444  *    can be skipped if the cell is not visible.                                               *
   4445  *                                                                                             *
   4446  * INPUT:   cell  -- The cell number to check.                                                 *
   4447  *                                                                                             *
   4448  * OUTPUT:  bool; Is this cell visible on the display?                                         *
   4449  *                                                                                             *
   4450  * WARNINGS:   none                                                                            *
   4451  *                                                                                             *
   4452  * HISTORY:                                                                                    *
   4453  *   04/30/1994 JLB : Created.                                                                 *
   4454  *   04/30/1994 JLB : Converted to member function.                                            *
   4455  *=============================================================================================*/
   4456 bool DisplayClass::In_View(register CELL cell) const
   4457 {
   4458 	if (cell & 0xC000) return(false);
   4459 
   4460 	COORDINATE coord = Coord_Whole(Cell_Coord(cell));
   4461 	COORDINATE tcoord = Coord_Whole(TacticalCoord);
   4462 
   4463 	if ((Coord_X(coord) - Coord_X(tcoord)) > TacLeptonWidth+CELL_LEPTON_W-1) return(false);
   4464 	if ((Coord_Y(coord) - Coord_Y(tcoord)) > TacLeptonHeight+CELL_LEPTON_H-1) return(false);
   4465 	return(true);
   4466 }
   4467 
   4468 
   4469 /***********************************************************************************************
   4470  * DisplayClass::Closest_Free_Spot -- Finds the closest cell sub spot that is free.            *
   4471  *                                                                                             *
   4472  *    Use this routine to find the sub cell spot closest to the coordinate specified that is   *
   4473  *    free from occupation. Typical use of this is for infantry destination calculation.       *
   4474  *                                                                                             *
   4475  * INPUT:   coord -- The coordinate to use as the starting point when finding the closest      *
   4476  *                   free spot.                                                                *
   4477  *                                                                                             *
   4478  *          any   -- Ignore occupation and just return the closest sub cell spot?              *
   4479  *                                                                                             *
   4480  * OUTPUT:  Returns with the coordinate of the closest free (possibly) sub cell location.      *
   4481  *                                                                                             *
   4482  * WARNINGS:   none                                                                            *
   4483  *                                                                                             *
   4484  * HISTORY:                                                                                    *
   4485  *   09/22/1995 JLB : Created.                                                                 *
   4486  *=============================================================================================*/
   4487 COORDINATE DisplayClass::Closest_Free_Spot(COORDINATE coord, bool any) const
   4488 {
   4489 	if (coord & HIGH_COORD_MASK) {
   4490 		return(0x00800080);
   4491 	}
   4492 	return Map[coord].Closest_Free_Spot(coord, any);
   4493 }
   4494 
   4495 
   4496 /***********************************************************************************************
   4497  * DisplayClass::Is_Spot_Free -- Determines if cell sub spot is free of occupation.            *
   4498  *                                                                                             *
   4499  *    Use this routine to determine if the coordinate (rounded to the nearest sub cell         *
   4500  *    position) is free for placement. Typical use of this would be for infantry placement.    *
   4501  *                                                                                             *
   4502  * INPUT:   coord -- The coordinate to examine for "freeness". The coordinate is rounded to    *
   4503  *          the nearest free sub cell spot.                                                    *
   4504  *                                                                                             *
   4505  * OUTPUT:  Is the sub spot indicated by the coordinate free from previous occupation?         *
   4506  *                                                                                             *
   4507  * WARNINGS:   none                                                                            *
   4508  *                                                                                             *
   4509  * HISTORY:                                                                                    *
   4510  *   09/22/1995 JLB : Created.                                                                 *
   4511  *=============================================================================================*/
   4512 bool DisplayClass::Is_Spot_Free(COORDINATE coord) const
   4513 {
   4514 	// This can't be right. Copy/paste error, maybe? ST - 5/8/2019
   4515 	//if (coord & HIGH_COORD_MASK) {
   4516 	//	return(0x00800080);
   4517 	//}
   4518 	return Map[coord].Is_Spot_Free(CellClass::Spot_Index(coord));
   4519 }
   4520 
   4521 
   4522 /***********************************************************************************************
   4523  * DisplayClass::Center_Map -- Centers the map about the currently selected objects            *
   4524  *                                                                                             *
   4525  *    This routine will average the position of all the selected objects and then center       *
   4526  *    the map about those objects.                                                             *
   4527  *                                                                                             *
   4528  * INPUT:   center   -- The is an optional center about override coordinate. If specified,     *
   4529  *                      then the map will be centered about that coordinate. Otherwise it      *
   4530  *                      will center about the average location of all selected objects.        *
   4531  *                                                                                             *
   4532  * OUTPUT:  The center coordinate.                                                             *
   4533  *                                                                                             *
   4534  * WARNINGS:   The map position changes by this routine.                                       *
   4535  *                                                                                             *
   4536  * HISTORY:                                                                                    *
   4537  *   08/22/1995 JLB : Created.                                                                 *
   4538  *   09/16/1996 JLB : Takes coordinate to center about (as override).                          *
   4539  *=============================================================================================*/
   4540 COORDINATE DisplayClass::Center_Map(COORDINATE center)
   4541 {
   4542  	int x = 0;
   4543 //	unsigned x = 0;
   4544  	int y = 0;
   4545 //	unsigned y = 0;
   4546 	bool centerit = false;
   4547 
   4548 	if (CurrentObject.Count()) {
   4549 
   4550 		for (int index = 0; index < CurrentObject.Count(); index++) {
   4551 			COORDINATE coord = CurrentObject[index]->Center_Coord();
   4552 
   4553 			x += Coord_X(coord);
   4554 			y += Coord_Y(coord);
   4555 		}
   4556 
   4557 		x /= CurrentObject.Count();
   4558 		y /= CurrentObject.Count();
   4559 		centerit = true;
   4560 	}
   4561 
   4562 	if (center != 0L) {
   4563 		x = Coord_X(center);
   4564 		y = Coord_Y(center);
   4565 		centerit = true;
   4566 	}
   4567 
   4568 	if (centerit) {
   4569 		center = XY_Coord(x, y);
   4570 
   4571 		x = x - (int)TacLeptonWidth/2;
   4572 		if (x < Cell_To_Lepton(MapCellX)) x = Cell_To_Lepton(MapCellX);
   4573 
   4574 		y = y - (int)TacLeptonHeight/2;
   4575 		if (y < Cell_To_Lepton(MapCellY)) y = Cell_To_Lepton(MapCellY);
   4576 
   4577 		Set_Tactical_Position(XY_Coord(x, y));
   4578 
   4579 		return center;
   4580 	}
   4581 
   4582 	return 0;
   4583 }
   4584 
   4585 
   4586 /***********************************************************************************************
   4587  * DisplayClass::Encroach_Shadow -- Causes the shadow to creep back by one cell.               *
   4588  *                                                                                             *
   4589  *    This routine will cause the shadow to creep back by one cell. Multiple calls to this     *
   4590  *    routine will result in the shadow becoming more and more invasive until only the sight   *
   4591  *    range of player controlled units will keep the shadow pushed back.                       *
   4592  *                                                                                             *
   4593  * INPUT:   none                                                                               *
   4594  *          house -- Player to apply shroud to                                                 *
   4595  *                                                                                             *
   4596  * OUTPUT:  none                                                                               *
   4597  *                                                                                             *
   4598  * WARNINGS:   none                                                                            *
   4599  *                                                                                             *
   4600  * HISTORY:                                                                                    *
   4601  *   10/16/1995 JLB : Created.                                                                 *
   4602  *   08/06/2019  ST: Added house parameter for multiplayer                                     *
   4603  *=============================================================================================*/
   4604 void DisplayClass::Encroach_Shadow(HouseClass * house)
   4605 {
   4606 	CELL cell;
   4607 	for (cell = 0; cell < MAP_CELL_TOTAL; cell++) {
   4608 		if (!In_Radar(cell)) continue;
   4609 
   4610 		CellClass * cellptr = &(*this)[cell];
   4611 		if (cellptr->Is_Visible(house) || !cellptr->Is_Mapped(house)) continue;
   4612 
   4613 		cellptr->IsToShroud = true;		// IsToShroud isn't used outside this function. ST - 8/6/2019 2:28PM
   4614 	}
   4615 
   4616 	/*
   4617 	**	Mark all shadow edge cells to be fully shrouded. All adjacent mapped
   4618 	**	cell should become partially shrouded.
   4619 	*/
   4620 	for (cell = 0; cell < MAP_CELL_TOTAL; cell++) {
   4621 		if (!In_Radar(cell)) continue;
   4622 
   4623 		if ((*this)[cell].IsToShroud) {
   4624 			(*this)[cell].IsToShroud = false;
   4625 			Shroud_Cell(cell, house);
   4626 		}
   4627 	}
   4628 
   4629 	All_To_Look(house);
   4630 
   4631 	Flag_To_Redraw(true);
   4632 }
   4633 
   4634 
   4635 /***********************************************************************************************
   4636  * DisplayClass::Shroud_Cell -- Returns the specified cell into the shrouded condition.        *
   4637  *                                                                                             *
   4638  *    This routine is called to add the shroud back to the cell specified. Typical of this     *
   4639  *    would be when the shroud is to regenerate.                                               *
   4640  *                                                                                             *
   4641  * INPUT:   cell  -- The cell that the shroud is to be regenerated upon.                       *
   4642  *          house -- Player to apply shroud to                                                 *
   4643  *                                                                                             *
   4644  * OUTPUT:  none                                                                               *
   4645  *                                                                                             *
   4646  * WARNINGS:   Adjacent cells might be affected by this routine. The affect is determined      *
   4647  *             according to the legality of the partial shadow artwork. In the illegal cases   *
   4648  *             the adjacent cell might become shrouded as well.                                *
   4649  *                                                                                             *
   4650  * HISTORY:                                                                                    *
   4651  *   10/17/1995 JLB : Created.                                                                 *
   4652  *   06/17/1996 JLB : Modified to handle the new shadow pieces.                                *
   4653  *   08/06/2019  ST: Added house parameter for multiplayer                                     *
   4654  *=============================================================================================*/
   4655 void DisplayClass::Shroud_Cell(CELL cell, HouseClass * house)
   4656 {
   4657 	if (house->IsGPSActive) {
   4658 		if ( (*this)[cell].Is_Jamming(house)  ) {
   4659 			return;
   4660 		}
   4661 	}
   4662 	if (!In_Radar(cell)) return;
   4663 
   4664 	CellClass * cellptr = &(*this)[cell];
   4665 	if (cellptr->Is_Mapped(house)) {
   4666 
   4667 		cellptr->Set_Mapped(house, false);
   4668 		cellptr->Set_Visible(house, false);
   4669 		cellptr->Redraw_Objects();
   4670 
   4671 		/*
   4672 		**	Check adjacent cells. There might be some weird combination of
   4673 		**	shrouded cells such that more cells must be shrouded in order for
   4674 		**	this to work.
   4675 		*/
   4676 		for (FacingType dir = FACING_FIRST; dir < FACING_COUNT; dir++) {
   4677 			CELL c = Adjacent_Cell(cell, dir);
   4678 			CellClass * cptr = &(*this)[c];
   4679 
   4680 			/*
   4681 			**	If this adjacent cell must be completely shrouded as a result
   4682 			**	of the map change, yet it isn't already shrouded, then recursively
   4683 			**	shroud that cell.
   4684 			*/
   4685 			if (c != cell) {
   4686 				cptr->Set_Visible(house, false);
   4687 			}
   4688 
   4689 			/*
   4690 			**	Always redraw the cell because, more than likely, the shroud
   4691 			**	edge will change shape because of the map change.
   4692 			*/
   4693 			cptr->Redraw_Objects();
   4694 		}
   4695 	}
   4696 }
   4697 
   4698 
   4699 /***********************************************************************************************
   4700  * DisplayClass::Read_INI -- Reads map control data from INI file.                             *
   4701  *                                                                                             *
   4702  *    This routine is used to read the map control data from the INI                           *
   4703  *    file.                                                                                    *
   4704  *                                                                                             *
   4705  * INPUT:   buffer   -- Pointer to the loaded INI file data.                                   *
   4706  *                                                                                             *
   4707  * OUTPUT:  none                                                                               *
   4708  *                                                                                             *
   4709  * WARNINGS:   The TriggerClass INI data must have been read before calling this function.     *
   4710  *                                                                                             *
   4711  * HISTORY:                                                                                    *
   4712  *   05/27/1994 JLB : Created.                                                                 *
   4713  *=============================================================================================*/
   4714 void DisplayClass::Read_INI(CCINIClass & ini)
   4715 {
   4716 	/*
   4717 	**	Read the map dimensions.
   4718 	*/
   4719 	char const * const name = "Map";
   4720 	int x = ini.Get_Int(name, "X", 1);
   4721 	int y = ini.Get_Int(name, "Y", 1);
   4722 	int w = ini.Get_Int(name, "Width", MAP_CELL_W-2);
   4723 	int h = ini.Get_Int(name, "Height", MAP_CELL_H-2);
   4724 
   4725 #ifndef FIXIT_VERSION_3		//	Map size no longer restricted.
   4726 
   4727 #ifdef FIXIT_CSII	//	checked - ajw
   4728 	if(Session.Type >= GAME_MODEM && Session.Type <= GAME_INTERNET && PlayingAgainstVersion < VERSION_AFTERMATH_CS) {
   4729 		/*
   4730 		**	HACK ALERT:
   4731 		**	Force the map to be limited to the size that 96x96 would be. If the
   4732 		**	size is greater (due to hacking?) then shrink it down to legal size.
   4733 		** BG Note: only do this for multiplayer games against non-AfterMath.
   4734 		*/
   4735 		if (w * h > 96 * 96) {
   4736 			h -= (((w*h) - (96*96)) / w) + 1;
   4737 		}
   4738 	}
   4739 #else
   4740 	/*
   4741 	**	HACK ALERT:
   4742 	**	Force the map to be limited to the size that 96x96 would be. If the
   4743 	**	size is greater (due to hacking?) then shrink it down to legal size.
   4744 	*/
   4745 	if (w * h > 96 * 96) {
   4746 		h -= (((w*h) - (96*96)) / w) + 1;
   4747 	}
   4748 #endif
   4749 
   4750 #endif	//	!FIXIT_VERSION_3
   4751 
   4752 	Set_Map_Dimensions( x, y, w, h );
   4753 
   4754 	/*
   4755 	**	The theater is determined at this point. There is specific data that
   4756 	**	is custom to this data. Load the custom data (as it related to terrain)
   4757 	**	at this point.
   4758 	*/
   4759 	Scen.Theater = ini.Get_TheaterType(name, "Theater", THEATER_TEMPERATE);
   4760 	if (Scen.Theater == THEATER_NONE) {
   4761 		Scen.Theater = THEATER_TEMPERATE;
   4762 	}
   4763 
   4764 	/*
   4765 	** Remove any old theater specific uncompressed shapes
   4766 	*/
   4767 #ifdef WIN32
   4768 	if (Scen.Theater != LastTheater) {
   4769 		Reset_Theater_Shapes();
   4770 	}
   4771 #endif	//WIN32
   4772 
   4773 	/*
   4774 	**	Now that the theater is known, init the entire map hierarchy
   4775 	*/
   4776 	Init(Scen.Theater);
   4777 
   4778 	/*
   4779 	**	Special initializations occur when the theater is known.
   4780 	*/
   4781 	TerrainTypeClass::Init(Scen.Theater);
   4782 	TemplateTypeClass::Init(Scen.Theater);
   4783 	OverlayTypeClass::Init(Scen.Theater);
   4784 	UnitTypeClass::Init(Scen.Theater);
   4785 	InfantryTypeClass::Init(Scen.Theater);
   4786 	BuildingTypeClass::Init(Scen.Theater);
   4787 	BulletTypeClass::Init(Scen.Theater);
   4788 	AnimTypeClass::Init(Scen.Theater);
   4789 	AircraftTypeClass::Init(Scen.Theater);
   4790 	VesselTypeClass::Init(Scen.Theater);
   4791 	SmudgeTypeClass::Init(Scen.Theater);
   4792 
   4793 	/*
   4794 	**	Read the Waypoint entries.
   4795 	*/
   4796 	for (int i = 0; i < WAYPT_COUNT; i++) {
   4797 		char buf[20];
   4798 		sprintf(buf, "%d", i);
   4799 		Scen.Waypoint[i] = ini.Get_Int("Waypoints", buf, -1);
   4800 
   4801 		if (Scen.Waypoint[i] != -1) {
   4802 			(*this)[Scen.Waypoint[i]].IsWaypoint = 1;
   4803 		}
   4804 	}
   4805 
   4806 	/*
   4807 	**	Set the starting position (do this after Init(), which clears the cells'
   4808 	**	IsWaypoint flags).
   4809 	*/
   4810 	if (Scen.Waypoint[WAYPT_HOME] == -1) {
   4811 		Scen.Waypoint[WAYPT_HOME] = XY_Cell(MapCellX + 5*RESFACTOR, MapCellY + 4*RESFACTOR);
   4812 	}
   4813 
   4814 	Scen.Views[0] = Scen.Views[1] = Scen.Views[2] = Scen.Views[3] = Scen.Waypoint[WAYPT_HOME];
   4815 	Set_Tactical_Position(Cell_Coord((Scen.Waypoint[WAYPT_HOME] - (MAP_CELL_W * 4 * RESFACTOR)) - (5*RESFACTOR)));
   4816 
   4817 	/*
   4818 	**	Loop through all CellTrigger entries.
   4819 	*/
   4820 	int len = ini.Entry_Count("CellTriggers");
   4821 	for (int index = 0; index < len; index++) {
   4822 
   4823 		/*
   4824 		**	Get a cell trigger and cell assignment.
   4825 		*/
   4826 		char const * cellentry = ini.Get_Entry("CellTriggers", index);
   4827 		TriggerTypeClass * tp = ini.Get_TriggerType("CellTriggers", cellentry);
   4828 		CELL cell = atoi(cellentry);
   4829 
   4830 		if (tp != NULL && !(*this)[cell].Trigger.Is_Valid()) {
   4831 			TriggerClass * tt = Find_Or_Make(tp);
   4832 			if (tt) {
   4833 				tt->AttachCount++;
   4834 				tt->Cell = cell;
   4835 				(*this)[cell].Trigger = tt;
   4836 			}
   4837 		}
   4838 	}
   4839 
   4840 	/*
   4841 	**	Read the map template data.
   4842 	*/
   4843 	static char const * const MAPPACK = "MapPack";
   4844 	len = ini.Get_UUBlock(MAPPACK, _staging_buffer, sizeof(_staging_buffer));
   4845 	BufferStraw bstraw(_staging_buffer, len);
   4846 	Map.Read_Binary(bstraw);
   4847 
   4848 	LastTheater = Scen.Theater;
   4849 }
   4850 
   4851 
   4852 /***********************************************************************************************
   4853  * DisplayClass::Write_INI -- Write the map data to the INI file specified.                    *
   4854  *                                                                                             *
   4855  *    This routine will output all the data of this map to the INI database specified.         *
   4856  *                                                                                             *
   4857  * INPUT:   ini   -- Reference to the INI handler to store the map data to.                    *
   4858  *                                                                                             *
   4859  * OUTPUT:  none                                                                               *
   4860  *                                                                                             *
   4861  * WARNINGS:   Any existing map data in the INI database will be replaced by this function.    *
   4862  *                                                                                             *
   4863  * HISTORY:                                                                                    *
   4864  *   07/03/1996 JLB : Created.                                                                 *
   4865  *=============================================================================================*/
   4866 void DisplayClass::Write_INI(CCINIClass & ini)
   4867 {
   4868 	char entry[20];
   4869 
   4870 	/*
   4871 	**	Save the map parameters.
   4872 	*/
   4873 	static char const * const NAME = "Map";
   4874 	ini.Clear(NAME);
   4875 	ini.Put_TheaterType(NAME, "Theater", Scen.Theater);
   4876 	ini.Put_Int(NAME, "X", MapCellX);
   4877 	ini.Put_Int(NAME, "Y", MapCellY);
   4878 	ini.Put_Int(NAME, "Width", MapCellWidth);
   4879 	ini.Put_Int(NAME, "Height", MapCellHeight);
   4880 
   4881 	/*
   4882 	**	Save the Waypoint entries.
   4883 	*/
   4884 	static char const * const WAYNAME = "Waypoints";
   4885 	ini.Clear(WAYNAME);
   4886 	for (int i = 0; i < WAYPT_COUNT; i++) {
   4887 		if (Scen.Waypoint[i] != -1) {
   4888 			sprintf(entry, "%d", i);
   4889 			ini.Put_Int(WAYNAME, entry, Scen.Waypoint[i]);
   4890 		}
   4891 	}
   4892 
   4893 	/*
   4894 	**	Save the cell's triggers.
   4895 	*/
   4896 	static char const * const CELLTRIG = "CellTriggers";
   4897 	ini.Clear(CELLTRIG);
   4898 	for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
   4899 		if ((*this)[cell].Trigger.Is_Valid()) {
   4900 			TriggerClass * tp = (*this)[cell].Trigger;
   4901 			if (tp != NULL) {
   4902 
   4903 				/*
   4904 				**	Generate entry name.
   4905 				*/
   4906 				sprintf(entry, "%d", cell);
   4907 
   4908 				/*
   4909 				**	Save entry.
   4910 				*/
   4911 				ini.Put_TriggerType(CELLTRIG, entry, tp->Class);
   4912 			}
   4913 		}
   4914 	}
   4915 
   4916 	/*
   4917 	**	Write the map template data out to the ini file.
   4918 	*/
   4919 	static char const * const MAPPACK = "MapPack";
   4920 	BufferPipe bpipe(_staging_buffer, sizeof(_staging_buffer));
   4921 	int len = Map.Write_Binary(bpipe);
   4922 	ini.Clear(MAPPACK);
   4923 	if (len) {
   4924 		ini.Put_UUBlock(MAPPACK, _staging_buffer, len);
   4925 	}
   4926 }
   4927 
   4928 
   4929 /***********************************************************************************************
   4930  * DisplayClass::All_To_Look -- Direct all objects to look around for the player.              *
   4931  *                                                                                             *
   4932  *    This routine will scan through all objects and tell them to look if they are supposed    *
   4933  *    to be able to reveal the map for the player. This routine may be necessary in cases      *
   4934  *    of gap generator reshroud logic.                                                         *
   4935  *                                                                                             *
   4936  * INPUT:   none                                                                               *
   4937  *                                                                                             *
   4938  * OUTPUT:  none                                                                               *
   4939  *                                                                                             *
   4940  * WARNINGS:   none                                                                            *
   4941  *                                                                                             *
   4942  * HISTORY:                                                                                    *
   4943  *   09/23/1996 JLB : Created.                                                                 *
   4944  *   08/06/2019  ST : Added house parameter so it can work for multiple players                *
   4945  *=============================================================================================*/
   4946 void DisplayClass::All_To_Look(HouseClass *house, bool units_only)
   4947 {
   4948 	for (int index = 0; index < Layer[LAYER_GROUND].Count(); index++) {
   4949 		ObjectClass * object = Layer[LAYER_GROUND][index];
   4950 		if (object != NULL && object->Is_Techno()) {
   4951 			TechnoClass * tech = ((TechnoClass *)object);
   4952 
   4953 			if (tech->What_Am_I() == RTTI_BUILDING && units_only) continue;
   4954 
   4955 			if (tech->House == house) {
   4956 				if (tech->Is_Discovered_By_Player(house)) {
   4957 					object->Look();
   4958 				}
   4959 			} else {
   4960 				//if (tech->What_Am_I() == RTTI_BUILDING && Rule.IsAllyReveal && tech->House->Is_Ally(PlayerPtr)) {
   4961 				if (tech->What_Am_I() == RTTI_BUILDING && Rule.IsAllyReveal && tech->House->Is_Ally(house)) {
   4962 					tech->Look();
   4963 				}
   4964 			}
   4965 		}
   4966 	}
   4967 }
   4968 
   4969 
   4970 /*
   4971 ** Added house parameter for client/server multiplayer. ST - 8/12/2019 11:48AM
   4972 ** 
   4973 ** 
   4974 */
   4975 void DisplayClass::Constrained_Look(COORDINATE center, LEPTON distance, HouseClass *house)
   4976 {
   4977 	for (int index = 0; index < Layer[LAYER_GROUND].Count(); index++) {
   4978 		ObjectClass * object = Layer[LAYER_GROUND][index];
   4979 		if (object != NULL && object->Is_Techno()) {
   4980 			TechnoClass * tech = ((TechnoClass *)object);
   4981 
   4982 //			if (tech->What_Am_I() == RTTI_BUILDING && units_only) continue;
   4983 
   4984 			if (Session.Type != GAME_GLYPHX_MULTIPLAYER) {
   4985 				if (tech->House->IsPlayerControl) {
   4986 					if (tech->IsDiscoveredByPlayer && Distance(tech->Center_Coord(), center) <= (tech->Techno_Type_Class()->SightRange * CELL_LEPTON_W) + distance) {
   4987 						object->Look();
   4988 					}
   4989 				} else {
   4990 					
   4991 					if (tech->What_Am_I() == RTTI_BUILDING && Rule.IsAllyReveal && tech->House->Is_Ally(PlayerPtr) &&
   4992 						Distance(tech->Center_Coord(), center) <= (tech->Techno_Type_Class()->SightRange * CELL_LEPTON_W) + distance) {
   4993 
   4994 						tech->Look();
   4995 					}
   4996 				}
   4997 			} else {
   4998 				
   4999 				if (tech->House->IsHuman) {
   5000 
   5001 					if (tech->House == house) {
   5002 						if (tech->Is_Discovered_By_Player(house) && Distance(tech->Center_Coord(), center) <= (tech->Techno_Type_Class()->SightRange * CELL_LEPTON_W) + distance) {
   5003 							object->Look();
   5004 						}
   5005 					} else {
   5006 						if (tech->What_Am_I() == RTTI_BUILDING && Rule.IsAllyReveal && tech->House->Is_Ally(house) && 
   5007 							Distance(tech->Center_Coord(), center) <= (tech->Techno_Type_Class()->SightRange * CELL_LEPTON_W) + distance) {
   5008 							tech->Look();
   5009 						}
   5010 					}
   5011 				}
   5012 			}
   5013 		}
   5014 	}
   5015 }
   5016 
   5017 
   5018 /***********************************************************************************************
   5019  * DisplayClass::Flag_Cell -- Flag the specified cell to be redrawn.                           *
   5020  *                                                                                             *
   5021  *    This will flag the cell to be redrawn.                                                   *
   5022  *                                                                                             *
   5023  * INPUT:   cell  -- The cell to be flagged.                                                   *
   5024  *                                                                                             *
   5025  * OUTPUT:  none                                                                               *
   5026  *                                                                                             *
   5027  * WARNINGS:   none                                                                            *
   5028  *                                                                                             *
   5029  * HISTORY:                                                                                    *
   5030  *   10/20/1996 JLB : Created.                                                                 *
   5031  *=============================================================================================*/
   5032 void DisplayClass::Flag_Cell(CELL cell)
   5033 {
   5034 	Flag_To_Redraw(false);
   5035 	IsToRedraw = true;
   5036 	CellRedraw[cell] = true;
   5037 }
   5038 
   5039 static ActionType _priority_actions[] = {
   5040 	ACTION_ATTACK,
   5041 	ACTION_ENTER,
   5042 	ACTION_HEAL,
   5043 	ACTION_REPAIR,
   5044 	ACTION_SABOTAGE,
   5045 	ACTION_CAPTURE,
   5046 	ACTION_MOVE
   5047 };
   5048 
   5049 static int get_action_priority(ActionType action)
   5050 {
   5051 	for (int i = 0; i < ARRAY_LENGTH(_priority_actions); ++i) {
   5052 		if (_priority_actions[i] == action) {
   5053 			return i;
   5054 		}
   5055 	}
   5056 	return INT_MAX;
   5057 }
   5058 
   5059 template <typename T>
   5060 static int index_of(const DynamicVectorClass<T*>& list, T* object)
   5061 {
   5062 	for (int i = 0; i < list.Count(); i++) {
   5063 		if (list[i] == object) {
   5064 			return i;
   5065 		}
   5066 	}
   5067 	return -1;
   5068 }
   5069 
   5070 template <typename T>
   5071 static ObjectClass* Best_Object_With_ActionT(DynamicVectorClass<ObjectClass*>& objects, T subject)
   5072 {
   5073 	DynamicVectorClass<const ObjectTypeClass*> checked_types;
   5074 
   5075 	if (objects.Count()) {
   5076 		int best_priority = INT_MAX;
   5077 		ObjectClass* best_object = objects[0];
   5078 		for (int i = 0; i < objects.Count(); ++i) {
   5079 			ObjectClass* object = objects[i];
   5080 			const ObjectTypeClass* type = &object->Class_Of();
   5081 			if (index_of(checked_types, type) != -1) {
   5082 				continue;
   5083 			}
   5084 			checked_types.Add(type);
   5085 			ActionType action = object->What_Action(subject);
   5086 			int priority = get_action_priority(action);
   5087 			if (priority < best_priority) {
   5088 				best_priority = priority;
   5089 				best_object = object;
   5090 				if (best_priority == 0) {
   5091 					break;
   5092 				}
   5093 			}
   5094 		}
   5095 		return best_object;
   5096 	}
   5097 	return NULL;
   5098 }
   5099 
   5100 ObjectClass* Best_Object_With_Action(DynamicVectorClass<ObjectClass*>& objects, const ObjectClass* object)
   5101 {
   5102 	return Best_Object_With_ActionT(objects, object);
   5103 }
   5104 
   5105 ObjectClass* Best_Object_With_Action(DynamicVectorClass<ObjectClass*>& objects, CELL cell)
   5106 {
   5107 	return Best_Object_With_ActionT(objects, cell);
   5108 }
   5109 
   5110 ActionType Best_Object_Action(DynamicVectorClass<ObjectClass*>& objects, const ObjectClass* object)
   5111 {
   5112 	ObjectClass* obj = Best_Object_With_Action(objects, object);
   5113 	return (obj != NULL) ? obj->What_Action(object) : ACTION_NONE;
   5114 }
   5115 
   5116 ActionType Best_Object_Action(DynamicVectorClass<ObjectClass*>& objects, CELL cell)
   5117 {
   5118 	ObjectClass* obj = Best_Object_With_Action(objects, cell);
   5119 	return (obj != NULL) ? obj->What_Action(cell) : ACTION_NONE;
   5120 }
   5121 
   5122 ObjectClass* Best_Object_With_Action(const ObjectClass* object)
   5123 {
   5124 	return Best_Object_With_Action(CurrentObject.Raw(), object);
   5125 }
   5126 
   5127 ObjectClass* Best_Object_With_Action(CELL cell)
   5128 {
   5129 	return Best_Object_With_Action(CurrentObject.Raw(), cell);
   5130 }
   5131 
   5132 ActionType Best_Object_Action(const ObjectClass* object)
   5133 {
   5134 	return Best_Object_Action(CurrentObject.Raw(), object);
   5135 }
   5136 
   5137 ActionType Best_Object_Action(CELL cell)
   5138 {
   5139 	return Best_Object_Action(CurrentObject.Raw(), cell);
   5140 }