CnC_Remastered_Collection

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

MAP.CPP (76464B)


      1 //
      2 // Copyright 2020 Electronic Arts Inc.
      3 //
      4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
      5 // software: you can redistribute it and/or modify it under the terms of 
      6 // the GNU General Public License as published by the Free Software Foundation, 
      7 // either version 3 of the License, or (at your option) any later version.
      8 
      9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
     10 // in the hope that it will be useful, but with permitted additional restrictions 
     11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
     12 // distributed with this program. You should have received a copy of the 
     13 // GNU General Public License along with permitted additional restrictions 
     14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
     15 
     16 /* $Header:   F:\projects\c&c\vcs\code\map.cpv   2.17   16 Oct 1995 16:52:22   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 : MAP.CPP                                                      *
     24  *                                                                                             *
     25  *                   Programmer : Joe L. Bostic                                                *
     26  *                                                                                             *
     27  *                   Start Date : September 10, 1993                                           *
     28  *                                                                                             *
     29  *                  Last Update : August 20, 1995 [JLB]                                        *
     30  *                                                                                             *
     31  *---------------------------------------------------------------------------------------------*
     32  * Functions:                                                                                  *
     33  *   MapClass::Cell_Distance -- Determines the distance between two cells.                     *
     34  *   MapClass::Cell_Region -- Determines the region from a specified cell number.              *
     35  *   MapClass::Cell_Threat -- Gets a houses threat value for a cell                            *
     36  *   MapClass::Close_Object -- Finds a clickable close object to the specified coordinate.     *
     37  *   MapClass::In_Radar -- Is specified cell in the radar map?                                 *
     38  *   MapClass::Init -- clears all cells                                                        *
     39  *   MapClass::Logic -- Handles map related logic functions.                                   *
     40  *   MapClass::One_Time -- Performs special one time initializations for the map.              *
     41  *   MapClass::Overlap_Down -- computes & marks object's overlap cells                         *
     42  *   MapClass::Overlap_Up -- Computes & clears object's overlap cells                          *
     43  *   MapClass::Overpass -- Performs any final cleanup to a freshly constructed map.            *
     44  *   MapClass::Pick_Up -- Removes specified object from the map.                               *
     45  *   MapClass::Place_Down -- Places the specified object onto the map.                         *
     46  *   MapClass::Place_Random_Crate -- Places a crate at random location on map.                 *
     47  *   MapClass::Read_Binary -- reads the map's binary image file                                *
     48  *   MapClass::Set_Map_Dimensions -- Initialize the map.                                       *
     49  *   MapClass::Sight_From -- Mark as visible the cells within a specified radius.              *
     50  *   MapClass::Validate -- validates every cell on the map                                     *
     51  *   MapClass::Write_Binary -- writes the map's binary image file                              *
     52  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     53 
     54 #include "function.h"
     55 
     56 #define	MCW	MAP_CELL_W
     57 int const MapClass::RadiusOffset[] = {
     58 	/* 0  */	0,
     59 	/* 1  */	(-MCW*1)-1,(-MCW*1)+0,(-MCW*1)+1,-1,1,(MCW*1)-1,(MCW*1)+0,(MCW*1)+1,
     60 	/* 2  */	(-MCW*2)-1,(-MCW*2)+0,(-MCW*2)+1,(-MCW*1)-2,(-MCW*1)+2,-2,2,(MCW*1)-2,(MCW*1)+2,(MCW*2)-1,(MCW*2)+0,(MCW*2)+1,
     61 	/* 3  */	(-MCW*3)-1,(-MCW*3)+0,(-MCW*3)+1,(-MCW*2)-2,(-MCW*2)+2,(-MCW*1)-3,(-MCW*1)+3,-3,3,(MCW*1)-3,(MCW*1)+3,(MCW*2)-2,(MCW*2)+2,(MCW*3)-1,(MCW*3)+0,(MCW*3)+1,
     62 	/* 4  */	(-MCW*4)-1,(-MCW*4)+0,(-MCW*4)+1,(-MCW*3)-3,(-MCW*3)-2,(-MCW*3)+2,(-MCW*3)+3,(-MCW*2)-3,(-MCW*2)+3,(-MCW*1)-4,(-MCW*1)+4,-4,4,(MCW*1)-4,(MCW*1)+4,(MCW*2)-3,(MCW*2)+3,(MCW*3)-3,(MCW*3)-2,(MCW*3)+2,(MCW*3)+3,(MCW*4)-1,(MCW*4)+0,(MCW*4)+1,
     63 	/* 5  */	(-MCW*5)-1,(-MCW*5)+0,(-MCW*5)+1,(-MCW*4)-3,(-MCW*4)-2,(-MCW*4)+2,(-MCW*4)+3,(-MCW*3)-4,(-MCW*3)+4,(-MCW*2)-4,(-MCW*2)+4,(-MCW*1)-5,(-MCW*1)+5,-5,5,(MCW*1)-5,(MCW*1)+5,(MCW*2)-4,(MCW*2)+4,(MCW*3)-4,(MCW*3)+4,(MCW*4)-3,(MCW*4)-2,(MCW*4)+2,(MCW*4)+3,(MCW*5)-1,(MCW*5)+0,(MCW*5)+1,
     64 	/* 6  */	(-MCW*6)-1,(-MCW*6)+0,(-MCW*6)+1,(-MCW*5)-3,(-MCW*5)-2,(-MCW*5)+2,(-MCW*5)+3,(-MCW*4)-4,(-MCW*4)+4,(-MCW*3)-5,(-MCW*3)+5,(-MCW*2)-5,(-MCW*2)+5,(-MCW*1)-6,(-MCW*1)+6,-6,6,(MCW*1)-6,(MCW*1)+6,(MCW*2)-5,(MCW*2)+5,(MCW*3)-5,(MCW*3)+5,(MCW*4)-4,(MCW*4)+4,(MCW*5)-3,(MCW*5)-2,(MCW*5)+2,(MCW*5)+3,(MCW*6)-1,(MCW*6)+0,(MCW*6)+1,
     65 	/* 7  */	(-MCW*7)-1,(-MCW*7)+0,(-MCW*7)+1,(-MCW*6)-3,(-MCW*6)-2,(-MCW*6)+2,(-MCW*6)+3,(-MCW*5)-5,(-MCW*5)-4,(-MCW*5)+4,(-MCW*5)+5,(-MCW*4)-5,(-MCW*4)+5,(-MCW*3)-6,(-MCW*3)+6,(-MCW*2)-6,(-MCW*2)+6,(-MCW*1)-7,(-MCW*1)+7,-7,7,(MCW*1)-7,(MCW*1)+7,(MCW*2)-6,(MCW*2)+6,(MCW*3)-6,(MCW*3)+6,(MCW*4)-5,(MCW*4)+5,(MCW*5)-5,(MCW*5)-4,(MCW*5)+4,(MCW*5)+5,(MCW*6)-3,(MCW*6)-2,(MCW*6)+2,(MCW*6)+3,(MCW*7)-1,(MCW*7)+0,(MCW*7)+1,
     66 	/* 8  */	(-MCW*8)-1,(-MCW*8)+0,(-MCW*8)+1,(-MCW*7)-3,(-MCW*7)-2,(-MCW*7)+2,(-MCW*7)+3,(-MCW*6)-5,(-MCW*6)-4,(-MCW*6)+4,(-MCW*6)+5,(-MCW*5)-6,(-MCW*5)+6,(-MCW*4)-6,(-MCW*4)+6,(-MCW*3)-7,(-MCW*3)+7,(-MCW*2)-7,(-MCW*2)+7,(-MCW*1)-8,(-MCW*1)+8,-8,8,(MCW*1)-8,(MCW*1)+8,(MCW*2)-7,(MCW*2)+7,(MCW*3)-7,(MCW*3)+7,(MCW*4)-6,(MCW*4)+6,(MCW*5)-6,(MCW*5)+6,(MCW*6)-5,(MCW*6)-4,(MCW*6)+4,(MCW*6)+5,(MCW*7)-3,(MCW*7)-2,(MCW*7)+2,(MCW*7)+3,(MCW*8)-1,(MCW*8)+0,(MCW*8)+1,
     67 	/* 9  */	(-MCW*9)-1,(-MCW*9)+0,(-MCW*9)+1,(-MCW*8)-3,(-MCW*8)-2,(-MCW*8)+2,(-MCW*8)+3,(-MCW*7)-5,(-MCW*7)-4,(-MCW*7)+4,(-MCW*7)+5,(-MCW*6)-6,(-MCW*6)+6,(-MCW*5)-7,(-MCW*5)+7,(-MCW*4)-7,(-MCW*4)+7,(-MCW*3)-8,(-MCW*3)+8,(-MCW*2)-8,(-MCW*2)+8,(-MCW*1)-9,(-MCW*1)+9,-9,9,(MCW*1)-9,(MCW*1)+9,(MCW*2)-8,(MCW*2)+8,(MCW*3)-8,(MCW*3)+8,(MCW*4)-7,(MCW*4)+7,(MCW*5)-7,(MCW*5)+7,(MCW*6)-6,(MCW*6)+6,(MCW*7)-5,(MCW*7)-4,(MCW*7)+4,(MCW*7)+5,(MCW*8)-3,(MCW*8)-2,(MCW*8)+2,(MCW*8)+3,(MCW*9)-1,(MCW*9)+0,(MCW*9)+1,
     68 	/* 10 */	(-MCW*10)-1,(-MCW*10)+0,(-MCW*10)+1,(-MCW*9)-3,(-MCW*9)-2,(-MCW*9)+2,(-MCW*9)+3,(-MCW*8)-5,(-MCW*8)-4,(-MCW*8)+4,(-MCW*8)+5,(-MCW*7)-7,(-MCW*7)-6,(-MCW*7)+6,(-MCW*7)+7,(-MCW*6)-7,(-MCW*6)+7,(-MCW*5)-8,(-MCW*5)+8,(-MCW*4)-8,(-MCW*4)+8,(-MCW*3)-9,(-MCW*3)+9,(-MCW*2)-9,(-MCW*2)+9,(-MCW*1)-10,(-MCW*1)+10,-10,10,(MCW*1)-10,(MCW*1)+10,(MCW*2)-9,(MCW*2)+9,(MCW*3)-9,(MCW*3)+9,(MCW*4)-8,(MCW*4)+8,(MCW*5)-8,(MCW*5)+8,(MCW*6)-7,(MCW*6)+7,(MCW*7)-7,(MCW*7)-6,(MCW*7)+6,(MCW*7)+7,(MCW*8)-5,(MCW*8)-4,
     69 			(MCW*8)+4,(MCW*8)+5,(MCW*9)-3,(MCW*9)-2,(MCW*9)+2,(MCW*9)+3,(MCW*10)-1,(MCW*10)+0,(MCW*10)+1,
     70 };
     71 
     72 int const MapClass::RadiusCount[11] = {1,9,21,37,61,89,121,161,205,253,309};
     73 
     74 
     75 CellClass *BlubCell;
     76 
     77 /***********************************************************************************************
     78  * MapClass::One_Time -- Performs special one time initializations for the map.                *
     79  *                                                                                             *
     80  *    This routine is used by the game initialization function in order to perform any one     *
     81  *    time initializations required for the map. This includes allocation of the map and       *
     82  *    setting up its default dimensions.                                                       *
     83  *                                                                                             *
     84  * INPUT:   none                                                                               *
     85  *                                                                                             *
     86  * OUTPUT:  none                                                                               *
     87  *                                                                                             *
     88  * WARNINGS:   This routine MUST be called once and only once.                                 *
     89  *                                                                                             *
     90  * HISTORY:                                                                                    *
     91  *   05/31/1994 JLB : Created.                                                                 *
     92  *   12/01/1994 BR : Added CellTriggers initialization                                         *
     93  *=============================================================================================*/
     94 void MapClass::One_Time(void)
     95 {
     96 	GScreenClass::One_Time();
     97 
     98 	XSize = MAP_CELL_W;
     99 	YSize = MAP_CELL_H;
    100 	Size = XSize * YSize;
    101 
    102 	/*
    103 	**	Allocate the cell array.
    104 	*/
    105 	Alloc_Cells();
    106 
    107 	/*
    108 	**	Init the CellTriggers array to the required size.
    109 	*/
    110 	CellTriggers.Resize(MAP_CELL_TOTAL);
    111 }
    112 
    113 ////////////////////////////////////////////////////
    114 // Added this function to allow the editor to setup the map without setting up the entire system. - 06/18/2019 JAS
    115 void MapClass::One_Time_Editor(void)
    116 {
    117 	XSize = MAP_CELL_W;
    118 	YSize = MAP_CELL_H;
    119 	Size = XSize * YSize;
    120 
    121 	/*
    122 	**	Allocate the cell array.
    123 	*/
    124 	Alloc_Cells();
    125 
    126 	/*
    127 	**	Init the CellTriggers array to the required size.
    128 	*/
    129 	CellTriggers.Resize(MAP_CELL_TOTAL);
    130 }
    131 // End of change. - 06/15/2019 JAS
    132 ////////////////////////////////////////////////////
    133 
    134 /***********************************************************************************************
    135  * MapClass::Init_Clear -- clears the map & buffers to a known state                           *
    136  *                                                                                             *
    137  * INPUT:                                                                                      *
    138  *      none.                                                                                  *
    139  *                                                                                             *
    140  * OUTPUT:                                                                                     *
    141  *      none.                                                                                  *
    142  *                                                                                             *
    143  * WARNINGS:                                                                                   *
    144  *      none.                                                                                  *
    145  *                                                                                             *
    146  * HISTORY:                                                                                    *
    147  *   03/17/1995 BRR : Created.                                                                 *
    148  *=============================================================================================*/
    149 void MapClass::Init_Clear(void)
    150 {
    151 	GScreenClass::Init_Clear();
    152 	Init_Cells();
    153 	TiberiumScan = 0;
    154 	IsForwardScan = true;
    155 	TiberiumGrowthCount = 0;
    156 	TiberiumSpreadCount = 0;
    157 }
    158 
    159 
    160 /***********************************************************************************************
    161  * MapClass::Alloc_Cells -- allocates the cell array                                           *
    162  *                                                                                             *
    163  * This routine should be called at One_Time, and after loading the Map object from a save     *
    164  * game, but prior to loading the cell objects.                                                *
    165  *                                                                                             *
    166  * INPUT:                                                                                      *
    167  *      none.                                                                                  *
    168  *                                                                                             *
    169  * OUTPUT:                                                                                     *
    170  *      none.                                                                                  *
    171  *                                                                                             *
    172  * WARNINGS:                                                                                   *
    173  *      none.                                                                                  *
    174  *                                                                                             *
    175  * HISTORY:                                                                                    *
    176  *   03/17/1995 BRR : Created.                                                                 *
    177  *=============================================================================================*/
    178 void MapClass::Alloc_Cells(void)
    179 {
    180 	/*
    181 	**	Assume that whatever the contents of the VectorClass are is garbage
    182 	**	(it may have been loaded from a save-game file), so zero it out first.
    183 	*/
    184 	Vector = 0;
    185 	VectorMax = 0;
    186 	IsAllocated = 0;
    187 	Resize(Size);
    188 }
    189 
    190 
    191 /***********************************************************************************************
    192  * MapClass::Free_Cells -- frees the cell array                                                *
    193  *                                                                                             *
    194  * This routine is used by the Load_Game routine to free the map's cell array before loading   *
    195  * the map object from disk; the array is then re-allocated & cleared before the cell objects  *
    196  * are loaded.                                                                                 *
    197  *                                                                                             *
    198  * INPUT:                                                                                      *
    199  *      none.                                                                                  *
    200  *                                                                                             *
    201  * OUTPUT:                                                                                     *
    202  *      none.                                                                                  *
    203  *                                                                                             *
    204  * WARNINGS:                                                                                   *
    205  *      none.                                                                                  *
    206  *                                                                                             *
    207  * HISTORY:                                                                                    *
    208  *   03/17/1995 BRR : Created.                                                                 *
    209  *=============================================================================================*/
    210 void MapClass::Free_Cells(void)
    211 {
    212 	Clear();
    213 }
    214 
    215 
    216 /***********************************************************************************************
    217  * MapClass::Init_Cells -- Initializes the cell array to a fresh state.                        *
    218  *                                                                                             *
    219  * This routine is used by Init_Clear to set the cells to a known state; it's also used by     *
    220  * the Load_Game routine to init all cells before loading a set of cells from disk, so it      *
    221  * needs to be called separately from the other Init_xxx() routines.                           *
    222  *                                                                                             *
    223  * INPUT:                                                                                      *
    224  *      none.                                                                                  *
    225  *                                                                                             *
    226  * OUTPUT:                                                                                     *
    227  *      none.                                                                                  *
    228  *                                                                                             *
    229  * WARNINGS:                                                                                   *
    230  *      none.                                                                                  *
    231  *                                                                                             *
    232  * HISTORY:                                                                                    *
    233  *   03/17/1995 BRR : Created.                                                                 *
    234  *=============================================================================================*/
    235 void MapClass::Init_Cells(void)
    236 {
    237 	TotalValue = 0;
    238 #ifdef NEVER
    239 	Free_Cells();
    240 	Alloc_Cells();
    241 #else
    242 	for (int index = 0; index < MAP_CELL_TOTAL; index++) {
    243 		Map[index] = CellClass();
    244 	}
    245 #endif
    246 }
    247 
    248 
    249 /***********************************************************************************************
    250  * MapClass::Set_Map_Dimensions -- Set map dimensions.                                         *
    251  *                                                                                             *
    252  *    This routine is used to set the legal limits and position of the                         *
    253  *    map as it relates to the overall map array. Typically, this is                           *
    254  *    called by the scenario loading code.                                                     *
    255  *                                                                                             *
    256  * INPUT:   x,y   -- The X and Y coordinate of the "upper left" corner                         *
    257  *                   of the map.                                                               *
    258  *                                                                                             *
    259  *          w,h   -- The width and height of the legal map.                                    *
    260  *                                                                                             *
    261  * OUTPUT:  none                                                                               *
    262  *                                                                                             *
    263  * WARNINGS:   none                                                                            *
    264  *                                                                                             *
    265  * HISTORY:                                                                                    *
    266  *   05/14/1994 JLB : Created.                                                                 *
    267  *=============================================================================================*/
    268 void MapClass::Set_Map_Dimensions(int x, int y, int w, int h)
    269 {
    270 	MapCellX = x;
    271 	MapCellY = y;
    272 	MapCellWidth = w;
    273 	MapCellHeight = h;
    274 }
    275 
    276 
    277 /***********************************************************************************************
    278  * MapClass::Sight_From -- Mark as visible the cells within a specified radius.                *
    279  *                                                                                             *
    280  *    This routine is used to reveal the cells around a specific location.                     *
    281  *    Typically, as a unit moves or is deployed, this routine will be                          *
    282  *    called. Since it deals with MANY cells, it needs to be extremely                         *
    283  *    fast.                                                                                    *
    284  *                                                                                             *
    285  * INPUT:   house		-- Player to perform the visibility update for                            *
    286  *                                                                                             *
    287  * 			cell     -- The coordinate that the sighting originates from.                      *
    288  *                                                                                             *
    289  *          sightrange-- The distance in cells that sighting extends.                          *
    290  *                                                                                             *
    291  *          incremental-- Is this an incremental sighting. In other                            *
    292  *                      words, has this function been called before where                      *
    293  *                      the center coordinate is no more than one cell                         *
    294  *                      distant from the last time?                                            *
    295  *                                                                                             *
    296  * OUTPUT:  none                                                                               *
    297  *                                                                                             *
    298  * WARNINGS:   none                                                                            *
    299  *                                                                                             *
    300  * HISTORY:                                                                                    *
    301  *   05/19/1992 JLB : Created.                                                                 *
    302  *   03/08/1994 JLB : Updated to use sight table and incremental flag.                         *
    303  *   05/18/1994 JLB : Converted to member function.                                            *
    304  *   03/06/2019 ST  : Added HouseClass pointer parameter for new multiplayer code              *
    305  *=============================================================================================*/
    306 void MapClass::Sight_From(HouseClass *house, CELL cell, int sightrange, bool incremental)
    307 {
    308 	int xx;				// Center cell X coordinate (bounds checking).
    309 	int const *ptr;	// Offset pointer.
    310 	int count;			// Counter for number of offsets to process.
    311 
    312 	// Added. ST - 3/6/2019 1:50PM
    313 	if ((house == NULL || house->IsHuman == false) && !ShareAllyVisibility) {
    314 		return;
    315 	}
    316 
    317 	/*
    318 	**	Units that are off-map cannot sight.
    319 	*/
    320 	if (!In_Radar(cell)) return;
    321 	if (!sightrange || sightrange > 10) return;
    322 
    323 	/*
    324 	**	Determine logical cell coordinate for center scan point.
    325 	*/
    326 	xx = Cell_X(cell);
    327 
    328 	/*
    329 	**	Incremental scans only scan the outer rings. Full scans
    330 	**	scan all internal cells as well.
    331 	*/
    332 	count = RadiusCount[sightrange];
    333 	ptr = &RadiusOffset[0];
    334 	if (incremental) {
    335 		if (sightrange > 1) {
    336 			ptr += RadiusCount[sightrange-2];
    337 			count -= RadiusCount[sightrange-2];
    338 		}
    339 	}
    340 
    341 	/*
    342 	**	Process all offsets required for the desired scan.
    343 	*/
    344 	while (count--) {
    345 		CELL	newcell;			// New cell with offset.
    346 		int	xdiff;			// New cell's X coordinate distance from center.
    347 
    348 		newcell = cell + *ptr++;
    349 
    350 		/*
    351 		**	Determine if the map edge has been wrapped. If so,
    352 		**	then don't process the cell.
    353 		*/
    354 		if ((unsigned)newcell >= MAP_CELL_TOTAL) continue;
    355 		xdiff = Cell_X(newcell) - xx;
    356 		xdiff = ABS(xdiff);
    357 		if (xdiff > sightrange) continue;
    358 		if (Distance(newcell, cell) > sightrange) continue;
    359 
    360 		/*
    361 		**	Map the cell. For incremental scans, then update
    362 		**	adjacent cells as well. For full scans, just update
    363 		**	the cell itself.
    364 		*/
    365 		// Pass the house through, instead of assuming it's the local player. ST - 3/6/2019 10:26AM
    366 		//Map.Map_Cell(newcell, PlayerPtr);
    367 		Map.Map_Cell(newcell, house, true);
    368 	}
    369 }
    370 
    371 
    372 /***********************************************************************************************
    373  * MapClass::Cell_Distance -- Determines the distance between two cells.                       *
    374  *                                                                                             *
    375  *    This routine will return with the calculated "straight line"                             *
    376  *    distance between the two cells specified. It uses the dragon strike                      *
    377  *    method of distance calculation.                                                          *
    378  *                                                                                             *
    379  * INPUT:   cell1    -- First cell.                                                            *
    380  *                                                                                             *
    381  *          cell2    -- Second cell.                                                           *
    382  *                                                                                             *
    383  * OUTPUT:  Returns with the "cell" distance between the two cells                             *
    384  *          specified.                                                                         *
    385  *                                                                                             *
    386  * WARNINGS:   none                                                                            *
    387  *                                                                                             *
    388  * HISTORY:                                                                                    *
    389  *   04/29/1994 JLB : Created.                                                                 *
    390  *   04/30/1994 JLB : Converted to member function.                                            *
    391  *=============================================================================================*/
    392 int MapClass::Cell_Distance(CELL cell1, CELL cell2)
    393 {
    394 	register int	x,y;		// Difference on X and Y axis.
    395 
    396 	x = Cell_X(cell1) - Cell_X(cell2);
    397 	y = Cell_Y(cell1) - Cell_Y(cell2);
    398 
    399 	if (x < 0) x = -x;
    400 	if (y < 0) y = -y;
    401 
    402 	if (x > y) {
    403 		return(x + (y>>1));
    404 	}
    405 	return(y + (x>>1));
    406 }
    407 
    408 
    409 /***********************************************************************************************
    410  * MapClass::In_Radar -- Is specified cell in the radar map?                                   *
    411  *                                                                                             *
    412  *    This determines if the specified cell can be within the navigable                        *
    413  *    bounds of the map. Technically, this means, any cell that can be                         *
    414  *    scanned by radar. If a cell returns false from this function, then                       *
    415  *    the player could never move to or pass over this cell.                                   *
    416  *                                                                                             *
    417  * INPUT:   cell  -- The cell to examine.                                                      *
    418  *                                                                                             *
    419  * OUTPUT:  bool; Is this cell possible to be displayed on radar?                              *
    420  *                                                                                             *
    421  * WARNINGS:   none                                                                            *
    422  *                                                                                             *
    423  * HISTORY:                                                                                    *
    424  *   10/07/1992 JLB : Created.                                                                 *
    425  *   04/30/1994 JLB : Converted to member function.                                            *
    426  *   05/01/1994 JLB : Speeded up.                                                              *
    427  *=============================================================================================*/
    428 bool MapClass::In_Radar(CELL cell) const
    429 {
    430 	if (cell & 0xF000) return(false);
    431 	return((unsigned)(Cell_X(cell) - MapCellX) < (unsigned)MapCellWidth && (unsigned)(Cell_Y(cell) - MapCellY) < (unsigned)MapCellHeight);
    432 }
    433 
    434 
    435 /***********************************************************************************************
    436  * MapClass::Place_Down -- Places the specified object onto the map.                           *
    437  *                                                                                             *
    438  *    This routine is used to place an object onto the map. It updates the "occupier" of the   *
    439  *    cells that this object covers. The cells are determined from the Occupy_List function    *
    440  *    provided by the object. Only one cell can have an occupier and this routine is the only  *
    441  *    place that sets this condition.                                                          *
    442  *                                                                                             *
    443  * INPUT:   cell     -- The cell to base object occupation around.                             *
    444  *                                                                                             *
    445  *          object   -- The object to place onto the map.                                      *
    446  *                                                                                             *
    447  * OUTPUT:  none                                                                               *
    448  *                                                                                             *
    449  * WARNINGS:   none                                                                            *
    450  *                                                                                             *
    451  * HISTORY:                                                                                    *
    452  *   07/31/1994 JLB : Created.                                                                 *
    453  *=============================================================================================*/
    454 void MapClass::Place_Down(CELL cell, ObjectClass * object)
    455 {
    456 	if (!object) return;
    457 
    458 	short const *list = object->Occupy_List();
    459 	while (*list != REFRESH_EOL) {
    460 		CELL newcell = cell + *list++;
    461 		if ((unsigned)newcell < MAP_CELL_TOTAL) {
    462 			(*this)[newcell].Occupy_Down(object);
    463 			(*this)[newcell].Recalc_Attributes();
    464 			(*this)[newcell].Redraw_Objects();
    465 		}
    466 	}
    467 
    468 	list = object->Overlap_List();
    469 	while (*list != REFRESH_EOL) {
    470 		CELL newcell = cell + *list++;
    471 		if ((unsigned)newcell < MAP_CELL_TOTAL) {
    472 			(*this)[newcell].Overlap_Down(object);
    473 			(*this)[newcell].Redraw_Objects();
    474 		}
    475 	}
    476 }
    477 
    478 
    479 /***********************************************************************************************
    480  * MapClass::Pick_Up -- Removes specified object from the map.                                 *
    481  *                                                                                             *
    482  *    The object specified is removed from the map by this routine. This will remove the       *
    483  *    occupation flag for all the cells that the object covers. The cells that are covered     *
    484  *    are determined from the Occupy_List function.                                            *
    485  *                                                                                             *
    486  * INPUT:   cell     -- The cell that the object is centered about.                            *
    487  *                                                                                             *
    488  *          object   -- Pointer to the object that will be removed.                            *
    489  *                                                                                             *
    490  * OUTPUT:  none                                                                               *
    491  *                                                                                             *
    492  * WARNINGS:   none                                                                            *
    493  *                                                                                             *
    494  * HISTORY:                                                                                    *
    495  *   07/31/1994 JLB : Created.                                                                 *
    496  *=============================================================================================*/
    497 void MapClass::Pick_Up(CELL cell, ObjectClass * object)
    498 {
    499 	if (!object) return;
    500 
    501 	short const *list = object->Occupy_List();
    502 	while (*list != REFRESH_EOL) {
    503 		CELL newcell = cell + *list++;
    504 		if ((unsigned)newcell < MAP_CELL_TOTAL) {
    505 			(*this)[newcell].Occupy_Up(object);
    506 			(*this)[newcell].Recalc_Attributes();
    507 			(*this)[newcell].Redraw_Objects();
    508 		}
    509 	}
    510 
    511 	list = object->Overlap_List();
    512 	while (*list != REFRESH_EOL) {
    513 		CELL newcell = cell + *list++;
    514 		if ((unsigned)newcell < MAP_CELL_TOTAL) {
    515 			(*this)[newcell].Overlap_Up(object);
    516 			(*this)[newcell].Redraw_Objects();
    517 		}
    518 	}
    519 }
    520 
    521 
    522 /***********************************************************************************************
    523  * MapClass::Overlap_Down -- computes & marks object's overlap cells                           *
    524  *                                                                                             *
    525  * This routine is just like Place_Down, but it doesn't mark the cell's Occupier.              *
    526  * This routine is used to implement MARK_OVERLAP_DOWN, which is useful for changing           *
    527  * an object's render size, but not its logical size (ie when it's selected or an              *
    528  * animation is attached to it).                                                               *
    529  *                                                                                             *
    530  * INPUT:                                                                                      *
    531  *      cell -- The cell to base object overlap around.                                        *
    532  *    object   -- The object to place onto the map.                                            *
    533  *                                                                                             *
    534  * OUTPUT:                                                                                     *
    535  *      none.                                                                                  *
    536  *                                                                                             *
    537  * WARNINGS:                                                                                   *
    538  *      none.                                                                                  *
    539  *                                                                                             *
    540  * HISTORY:                                                                                    *
    541  *   07/12/1995 BRR : Created.                                                                 *
    542  *=============================================================================================*/
    543 void MapClass::Overlap_Down(CELL cell, ObjectClass * object)
    544 {
    545 	if (!object) return;
    546 
    547 	short const *list = object->Overlap_List();
    548 	while (*list != REFRESH_EOL) {
    549 		CELL newcell = cell + *list++;
    550 		if ((unsigned)newcell < MAP_CELL_TOTAL) {
    551 			(*this)[newcell].Overlap_Down(object);
    552 			(*this)[newcell].Redraw_Objects();
    553 		}
    554 	}
    555 }
    556 
    557 
    558 /***********************************************************************************************
    559  * MapClass::Overlap_Up -- Computes & clears object's overlap cells                            *
    560  *                                                                                             *
    561  * This routine is just like Pick_Up, but it doesn't mark the cell's Occupier.                 *
    562  * This routine is used to implement MARK_OVERLAP_UP, which is useful for changing             *
    563  * an object's render size, but not its logical size (ie when it's selected or an              *
    564  * animation is attached to it).                                                               *
    565  *                                                                                             *
    566  * INPUT:                                                                                      *
    567  *      cell -- The cell to base object overlap around.                                        *
    568  *    object   -- The object to place onto the map.                                            *
    569  *                                                                                             *
    570  * OUTPUT:                                                                                     *
    571  *      none.                                                                                  *
    572  *                                                                                             *
    573  * WARNINGS:                                                                                   *
    574  *      none.                                                                                  *
    575  *                                                                                             *
    576  * HISTORY:                                                                                    *
    577  *   07/12/1995 BRR : Created.                                                                 *
    578  *=============================================================================================*/
    579 void MapClass::Overlap_Up(CELL cell, ObjectClass * object)
    580 {
    581 	if (!object) return;
    582 
    583 	short const *list = object->Overlap_List();
    584 	while (*list != REFRESH_EOL) {
    585 		CELL newcell = cell + *list++;
    586 		if ((unsigned)newcell < MAP_CELL_TOTAL) {
    587 			(*this)[newcell].Overlap_Up(object);
    588 			(*this)[newcell].Redraw_Objects();
    589 		}
    590 	}
    591 }
    592 
    593 
    594 /***********************************************************************************************
    595  * MapClass::Overpass -- Performs any final cleanup to a freshly constructed map.              *
    596  *                                                                                             *
    597  *    This routine will clean up anything necessary with the presumption that the map has      *
    598  *    been freshly created. Such things to clean up include various tiberium concentrations.   *
    599  *                                                                                             *
    600  * INPUT:   none                                                                               *
    601  *                                                                                             *
    602  * OUTPUT:  Returns the total credit value of the tiberium on the map.                         *
    603  *                                                                                             *
    604  * WARNINGS:   none                                                                            *
    605  *                                                                                             *
    606  * HISTORY:                                                                                    *
    607  *   09/19/1994 JLB : Created.                                                                 *
    608  *   02/13/1995 JLB : Returns total tiberium worth.                                            *
    609  *   02/15/1995 JLB : Optimal scan.                                                            *
    610  *=============================================================================================*/
    611 long MapClass::Overpass(void)
    612 {
    613 	long value = 0;
    614 
    615 	/*
    616 	**	Smooth out Tiberium. Cells that are not surrounded by other tiberium
    617 	**	will be reduced in density.
    618 	*/
    619 	for (int y = 0; y < MapCellHeight-1; y++) {
    620 		for (int x = 0; x < MapCellWidth; x++) {
    621 			value += (*this)[(MapCellY+y) * MAP_CELL_W + (MapCellX+x)].Tiberium_Adjust(true);
    622 		}
    623 	}
    624 	return(value);
    625 }
    626 
    627 
    628 /***********************************************************************************************
    629  * MapClass::Read_Binary -- reads the map's binary image file                                  *
    630  *                                                                                             *
    631  * INPUT:                                                                                      *
    632  *      root      root filename for scenario                                                   *
    633  *      crc       ptr to CRC value to update                                                   *
    634  *                                                                                             *
    635  * OUTPUT:                                                                                     *
    636  *      1 = success, 0 = failure                                                               *
    637  *                                                                                             *
    638  * WARNINGS:                                                                                   *
    639  *      none.                                                                                  *
    640  *                                                                                             *
    641  * HISTORY:                                                                                    *
    642  *   11/14/1994 BR : Created.                                                                  *
    643  *   01/08/1995 JLB : Fixup any obsolete icons detected.                                       *
    644  *=============================================================================================*/
    645 #ifdef DEMO
    646 bool MapClass::Read_Binary(char const * root, unsigned long *)
    647 #else
    648 bool MapClass::Read_Binary(char const * root, unsigned long *crc)
    649 #endif
    650 {
    651 	CCFileClass file;
    652 	char fname[_MAX_FNAME+_MAX_EXT];
    653 	int i;
    654 	char *map;
    655 	void *rawmap;
    656 	void const * shape;
    657 
    658 	/*
    659 	**	Filename = INI name with BIN extension.
    660 	*/
    661 	sprintf(fname,"%s.BIN",root);
    662 
    663 	/*
    664 	**	Create object & open file.
    665 	*/
    666 	file.Set_Name(fname);
    667 	if (!file.Is_Available()) {
    668 		return(false);
    669 	}
    670 	file.Open(READ);
    671 
    672 	/*
    673 	**	Loop through all cells.
    674 	*/
    675 	CellClass * cellptr = &Map[0];
    676 	for (i = 0; i < MAP_CELL_TOTAL; i++) {
    677 		struct {
    678 			TemplateType TType;		// Template type.
    679 			unsigned char TIcon;		// Template icon number.
    680 		} temp;
    681 
    682 		if (file.Read(&temp, sizeof(temp)) != sizeof(temp)) break;
    683 		if (temp.TType == (TemplateType)255) {
    684 			temp.TType = TEMPLATE_NONE;
    685 		}
    686 
    687 		/*
    688 		**	Verify that the template type actually contains the template number specified. If
    689 		**	an illegal icon was specified, then replace it with clear terrain.
    690 		*/
    691 		if (temp.TType != TEMPLATE_CLEAR1 && temp.TType != TEMPLATE_NONE) {
    692 			TemplateTypeClass const &ttype = TemplateTypeClass::As_Reference(temp.TType);
    693 			shape = ttype.Get_Image_Data();
    694 			if (shape) {
    695 				rawmap = Get_Icon_Set_Map(shape);
    696 				if (rawmap) {
    697 					map = (char*)rawmap;
    698 					if ((temp.TIcon >= (ttype.Width * ttype.Height)) || (map[temp.TIcon] == -1)) {
    699 						temp.TIcon = 0;
    700 						temp.TType = TEMPLATE_NONE;
    701 					}
    702 				}
    703 			}
    704 		}
    705 
    706 		cellptr->TType = temp.TType;
    707 		cellptr->TIcon = temp.TIcon;
    708 		cellptr->Recalc_Attributes();
    709 
    710 #ifndef DEMO
    711 		Add_CRC(crc, (unsigned long)cellptr->TType);
    712 		Add_CRC(crc, (unsigned long)cellptr->TIcon);
    713 #endif
    714 
    715 		cellptr++;
    716 	}
    717 
    718 	/*
    719 	**	Close the file.
    720 	*/
    721 	file.Close();
    722 
    723 	return(i == MAP_CELL_TOTAL);
    724 }
    725 
    726 
    727 /***********************************************************************************************
    728  * MapClass::Read_BinaryRead_Binary_File -- reads the map's binary image file						  *
    729  *                                                                                             *
    730  * INPUT:                                                                                      *
    731  *      fname     file path for scenario																		  *
    732  *      crc       ptr to CRC value to update                                                   *
    733  *                                                                                             *
    734  * OUTPUT:                                                                                     *
    735  *      1 = success, 0 = failure                                                               *
    736  *                                                                                             *
    737  * WARNINGS:                                                                                   *
    738  *      none.                                                                                  *
    739  *                                                                                             *
    740  * HISTORY:                                                                                    *
    741  *   10/28/2019 JAS : Created.                                                                  *
    742  *=============================================================================================*/
    743 bool MapClass::Read_Binary_File(char const * fname, unsigned long *crc)
    744 {
    745 	CCFileClass file;
    746 
    747 	int i;
    748 	char *map;
    749 	void *rawmap;
    750 	void const * shape;
    751 
    752 	/*
    753 	**	Create object & open file.
    754 	*/
    755 	file.Set_Name(fname);
    756 	if (!file.Is_Available()) {
    757 		return(false);
    758 	}
    759 	file.Open(READ);
    760 
    761 	/*
    762 	**	Loop through all cells.
    763 	*/
    764 	CellClass * cellptr = &Map[0];
    765 	for (i = 0; i < MAP_CELL_TOTAL; i++) {
    766 		struct {
    767 			TemplateType TType;		// Template type.
    768 			unsigned char TIcon;		// Template icon number.
    769 		} temp;
    770 
    771 		if (file.Read(&temp, sizeof(temp)) != sizeof(temp)) break;
    772 		if (temp.TType == (TemplateType)255) {
    773 			temp.TType = TEMPLATE_NONE;
    774 		}
    775 
    776 		/*
    777 		**	Verify that the template type actually contains the template number specified. If
    778 		**	an illegal icon was specified, then replace it with clear terrain.
    779 		*/
    780 		if (temp.TType != TEMPLATE_CLEAR1 && temp.TType != TEMPLATE_NONE) {
    781 			shape = TemplateTypeClass::As_Reference(temp.TType).Get_Image_Data();
    782 			if (shape) {
    783 				rawmap = Get_Icon_Set_Map(shape);
    784 				if (rawmap) {
    785 					map = (char*)rawmap;
    786 					if (map[temp.TIcon] == -1) {
    787 						temp.TIcon = 0;
    788 						temp.TType = TEMPLATE_NONE;
    789 					}
    790 				}
    791 			}
    792 		}
    793 
    794 		cellptr->TType = temp.TType;
    795 		cellptr->TIcon = temp.TIcon;
    796 		cellptr->Recalc_Attributes();
    797 
    798 #ifndef DEMO
    799 		Add_CRC(crc, (unsigned long)cellptr->TType);
    800 		Add_CRC(crc, (unsigned long)cellptr->TIcon);
    801 #endif
    802 
    803 		cellptr++;
    804 	}
    805 
    806 	/*
    807 	**	Close the file.
    808 	*/
    809 	file.Close();
    810 
    811 	return(i == MAP_CELL_TOTAL);
    812 }
    813 
    814 
    815 
    816 /***********************************************************************************************
    817  * MapClass::Write_Binary -- writes the map's binary image file                                *
    818  *                                                                                             *
    819  * INPUT:                                                                                      *
    820  *      root      root filename for scenario                                                   *
    821  *                                                                                             *
    822  * OUTPUT:                                                                                     *
    823  *      1 = success, 0 = failure                                                               *
    824  *                                                                                             *
    825  * WARNINGS:                                                                                   *
    826  *      none.                                                                                  *
    827  *                                                                                             *
    828  * HISTORY:                                                                                    *
    829  *   11/14/1994 BR : Created.                                                                  *
    830  *=============================================================================================*/
    831 bool MapClass::Write_Binary(char const * root)
    832 {
    833 	CCFileClass *file;
    834 	char fname[_MAX_FNAME+_MAX_EXT];
    835 	int i;
    836 
    837 	/*
    838 	**	Filename = INI name with BIN extension.
    839 	*/
    840 	sprintf(fname,"%s.BIN",root);
    841 
    842 	/*
    843 	**	Create object & open file.
    844 	*/
    845 	file = new CCFileClass(fname);
    846 	file->Open(WRITE);
    847 
    848 	/*
    849 	**	Loop through all cells.
    850 	*/
    851 	for (i = 0; i < MAP_CELL_TOTAL; i++) {
    852 		/*
    853 		**	Save TType.
    854 		*/
    855 		if (file->Write (&(Map[i].TType), sizeof(TemplateType)) != sizeof(TemplateType)) {
    856 			file->Close();
    857 			delete file;
    858 			return(false);
    859 		}
    860 
    861 		/*
    862 		**	Save TIcon.
    863 		*/
    864 		if (file->Write (&(Map[i].TIcon), sizeof(unsigned char)) != sizeof(unsigned char)) {
    865 			file->Close();
    866 			delete file;
    867 			return(false);
    868 		}
    869 	}
    870 
    871 	/*
    872 	**	Close the file.
    873 	*/
    874 	file->Close();
    875 	delete file;
    876 
    877 	return(true);
    878 }
    879 
    880 
    881 /***********************************************************************************************
    882  * MapClass::Logic -- Handles map related logic functions.                                     *
    883  *                                                                                             *
    884  *    Manages tiberium growth and spread.                                                      *
    885  *                                                                                             *
    886  * INPUT:   none                                                                               *
    887  *                                                                                             *
    888  * OUTPUT:  none                                                                               *
    889  *                                                                                             *
    890  * WARNINGS:   none                                                                            *
    891  *                                                                                             *
    892  * HISTORY:                                                                                    *
    893  *   05/11/1995 JLB : Created.                                                                 *
    894  *   07/09/1995 JLB : Handles two directional scan.                                            *
    895  *   08/01/1995 JLB : Gives stronger weight to blossom trees.                                  *
    896  *=============================================================================================*/
    897 void MapClass::Logic(void)
    898 {
    899 	if (Debug_Force_Crash) { *((int *)0) = 1; }
    900 
    901 	/*
    902 	**	Bail early if there is no allowed growth or spread of Tiberium.
    903 	*/
    904 	if (!Special.IsTGrowth && !Special.IsTSpread) return;
    905 
    906 	/*
    907 	**	Scan another block of the map in order to accumulate the potential
    908 	**	Tiberium cells that can grow or spread.
    909 	*/
    910 	int subcount = 30;
    911 	int index;
    912 	for (index = TiberiumScan; index < MAP_CELL_TOTAL; index++) {
    913 		CELL cell = index;
    914 		if (!IsForwardScan) cell = (MAP_CELL_TOTAL-1) - index;
    915 		CellClass *ptr = &(*this)[cell];
    916 
    917 		if (Special.IsTGrowth && ptr->Land_Type() == LAND_TIBERIUM && ptr->OverlayData < 11) {
    918 			if (TiberiumGrowthCount < sizeof(TiberiumGrowth)/sizeof(TiberiumGrowth[0])) {
    919 				TiberiumGrowth[TiberiumGrowthCount++] = cell;
    920 			} else {
    921 				TiberiumGrowth[Random_Pick(0, TiberiumGrowthCount-1)] = cell;
    922 			}
    923 		}
    924 
    925 		/*
    926 		**	Heavy Tiberium growth can spread.
    927 		*/
    928 		TerrainClass * terrain = ptr->Cell_Terrain();
    929 		if (Special.IsTSpread &&
    930 			(ptr->Land_Type() == LAND_TIBERIUM && ptr->OverlayData > 6) ||
    931 			(terrain && terrain->Class->IsTiberiumSpawn)) {
    932 
    933 			int tries = 1;
    934 			if (terrain) tries = 3;
    935 			for (int i = 0; i < tries; i++) {
    936 				if (TiberiumSpreadCount < sizeof(TiberiumSpread)/sizeof(TiberiumSpread[0])) {
    937 					TiberiumSpread[TiberiumSpreadCount++] = cell;
    938 				} else {
    939 					TiberiumSpread[Random_Pick(0, TiberiumSpreadCount-1)] = cell;
    940 				}
    941 			}
    942 		}
    943 		subcount--;
    944 		if (!subcount) break;
    945 	}
    946 	TiberiumScan = index;
    947 
    948 	if (TiberiumScan >= MAP_CELL_TOTAL) {
    949 		int tries = 1;
    950 		if (Special.IsTFast || GameToPlay != GAME_NORMAL) tries = 2;
    951 		
    952 		/*
    953 		** Use the Tiberium setting as a multiplier on growth rate. ST - 7/1/2020 3:05PM
    954 		*/
    955 		if (GameToPlay == GAME_GLYPHX_MULTIPLAYER) {
    956 			if (MPlayerTiberium > 1) {
    957 				tries += (MPlayerTiberium - 1) << 1;
    958 			}
    959 		}
    960 		TiberiumScan = 0;
    961 		IsForwardScan = (IsForwardScan == false);
    962 
    963 		/*
    964 		**	Growth logic.
    965 		*/
    966 		if (TiberiumGrowthCount) {
    967 			for (int i = 0; i < tries; i++) {
    968 				int pick = Random_Pick(0, TiberiumGrowthCount-1);
    969 				CELL cell = TiberiumGrowth[pick];
    970 				CellClass * newcell = &(*this)[cell];
    971 				if (newcell->Land_Type() == LAND_TIBERIUM && newcell->OverlayData < 12-1) {
    972 					newcell->OverlayData++;
    973 				}
    974 				TiberiumGrowth[pick] = TiberiumGrowth[TiberiumGrowthCount - 1];
    975 				TiberiumGrowthCount--;
    976 				if (TiberiumGrowthCount <= 0) {
    977 					break;
    978 				}
    979 			}
    980 		}
    981 		TiberiumGrowthCount = 0;
    982 
    983 		/*
    984 		**	Spread logic.
    985 		*/
    986 		if (TiberiumSpreadCount) {
    987 			for (int i = 0; i < tries; i++) {
    988 				int pick = Random_Pick(0, TiberiumSpreadCount-1);
    989 				CELL cell = TiberiumSpread[pick];
    990 
    991 				/*
    992 				**	Find a pseudo-random adjacent cell that doesn't contain any tiberium.
    993 				*/
    994 				if (Map.In_Radar(cell)) {
    995 					FacingType offset = Random_Pick(FACING_N, FACING_NW);
    996 					for (FacingType index = FACING_N; index < FACING_COUNT; index++) {
    997 						CellClass *newcell = (*this)[cell].Adjacent_Cell(index+offset);
    998 
    999 						if (newcell && newcell->Cell_Object() == NULL && newcell->Land_Type() == LAND_CLEAR && newcell->Overlay == OVERLAY_NONE) {
   1000 							bool found = false;
   1001 
   1002 							switch (newcell->TType) {
   1003 								case TEMPLATE_BRIDGE1:
   1004 								case TEMPLATE_BRIDGE2:
   1005 								case TEMPLATE_BRIDGE3:
   1006 								case TEMPLATE_BRIDGE4:
   1007 									break;
   1008 
   1009 								default:
   1010 									found = true;
   1011 									new OverlayClass(Random_Pick(OVERLAY_TIBERIUM1, OVERLAY_TIBERIUM12), newcell->Cell_Number());
   1012 									newcell->OverlayData = 1;
   1013 									break;
   1014 
   1015 							}
   1016 							if (found) break;
   1017 						}
   1018 					}
   1019 				}
   1020 				TiberiumSpread[pick] = TiberiumSpread[TiberiumSpreadCount - 1];
   1021 				TiberiumSpreadCount--;
   1022 				if (TiberiumSpreadCount <= 0) {
   1023 					break;
   1024 				}
   1025 			}
   1026 		}
   1027 		TiberiumSpreadCount = 0;
   1028 	}
   1029 }
   1030 
   1031 
   1032 /***********************************************************************************************
   1033  * MapClass::Cell_Region -- Determines the region from a specified cell number.                *
   1034  *                                                                                             *
   1035  *    Use this routine to determine what region a particular cell lies in.                     *
   1036  *                                                                                             *
   1037  * INPUT:   cell  -- The cell number to examine.                                               *
   1038  *                                                                                             *
   1039  * OUTPUT:  Returns with the region that the specified cell occupies.                          *
   1040  *                                                                                             *
   1041  * WARNINGS:   none                                                                            *
   1042  *                                                                                             *
   1043  * HISTORY:                                                                                    *
   1044  *   03/15/1995 JLB : Created.                                                                 *
   1045  *=============================================================================================*/
   1046 int MapClass::Cell_Region(CELL cell)
   1047 {
   1048 	return((Cell_X(cell) / REGION_WIDTH) + 1) +	(((Cell_Y(cell) / REGION_HEIGHT) + 1) * MAP_REGION_WIDTH);
   1049 }
   1050 
   1051 
   1052 /***************************************************************************
   1053  * MapClass::Cell_Threat -- Gets a houses threat value for a cell          *
   1054  *                                                                         *
   1055  * INPUT:   CELL        cell    - the cell number to check                 *
   1056  *            HouseType house   - the house to check                       *
   1057  *                                                                         *
   1058  * OUTPUT:                                                                 *
   1059  *                                                                         *
   1060  * WARNINGS:                                                               *
   1061  *                                                                         *
   1062  * HISTORY:                                                                *
   1063  *   04/25/1995 PWG : Created.                                             *
   1064  *=========================================================================*/
   1065 int MapClass::Cell_Threat(CELL cell, HousesType house)
   1066 {
   1067 	int threat = HouseClass::As_Pointer(house)->Regions[Map.Cell_Region(Map[cell].Cell_Number())].Threat_Value();
   1068 	//using function for IsVisible so we have different results for different players - JAS 2019/09/30
   1069 	if (!threat && Map[cell].Is_Visible(house)) {
   1070 		threat = 1;
   1071 	}
   1072 	return(threat);
   1073 }
   1074 
   1075 
   1076 /***********************************************************************************************
   1077  * MapClass::Place_Random_Crate -- Places a crate at random location on map.                   *
   1078  *                                                                                             *
   1079  *    This routine will place a crate at a random location on the map. This routine will only  *
   1080  *    make a limited number of attempts to place and if unsuccessful, it will not place any.   *
   1081  *                                                                                             *
   1082  * INPUT:   none                                                                               *
   1083  *                                                                                             *
   1084  * OUTPUT:  Was a crate successfully placed?                                                   *
   1085  *                                                                                             *
   1086  * WARNINGS:   none                                                                            *
   1087  *                                                                                             *
   1088  * HISTORY:                                                                                    *
   1089  *   07/08/1995 JLB : Created.                                                                 *
   1090  *=============================================================================================*/
   1091 bool MapClass::Place_Random_Crate(void)
   1092 {
   1093 	int old = ScenarioInit;
   1094 	ScenarioInit = 0;
   1095 	for (int index = 0; index < 100; index++) {
   1096 		int x = Random_Pick(0, MapCellWidth-1);
   1097 		int y = Random_Pick(0, MapCellHeight-1);
   1098 		CELL cell = XY_Cell(MapCellX+x, MapCellY+y);
   1099 
   1100 		CellClass * ptr = &(*this)[cell];
   1101 		if (ptr->Is_Generally_Clear() && ptr->Overlay == OVERLAY_NONE) {
   1102 			ptr->Overlay = OVERLAY_WOOD_CRATE;
   1103 			ptr->OverlayData = 0;
   1104 			ptr->Redraw_Objects();
   1105 			ScenarioInit = old;
   1106 			return(true);
   1107 		}
   1108 	}
   1109 	ScenarioInit = old;
   1110 	return(false);
   1111 }
   1112 
   1113 
   1114 /***************************************************************************
   1115  * MapClass::Validate -- validates every cell on the map                   *
   1116  *                                                                         *
   1117  * This is a debugging routine, designed to detect memory trashers that    *
   1118  * alter the map.  This routine is slow, but thorough.                     *
   1119  *                                                                         *
   1120  * INPUT:                                                                  *
   1121  *      none.                                                              *
   1122  *                                                                         *
   1123  * OUTPUT:                                                                 *
   1124  *      true = map is OK, false = an error was found                       *
   1125  *                                                                         *
   1126  * WARNINGS:                                                               *
   1127  *      none.                                                              *
   1128  *                                                                         *
   1129  * HISTORY:                                                                *
   1130  *   07/08/1995 BRR : Created.                                             *
   1131  *=========================================================================*/
   1132 int MapClass::Validate(void)
   1133 {
   1134 	CELL cell;
   1135 	TemplateType ttype;
   1136 	unsigned char ticon;
   1137 	//TemplateTypeClass const *tclass;
   1138 	//unsigned char map[13*8];
   1139 	OverlayType overlay;
   1140 	SmudgeType smudge;
   1141 	ObjectClass *obj;
   1142 	LandType land;
   1143 	int i;
   1144 
   1145 BlubCell = &((*this)[797]);
   1146 
   1147 if (BlubCell->Overlapper[1]) {
   1148 	obj = BlubCell->Overlapper[1];
   1149 	if (obj) {
   1150 		if (obj->IsInLimbo)
   1151 		obj = obj;
   1152 	}
   1153 }
   1154 
   1155 	/*------------------------------------------------------------------------
   1156 	Check every cell on the map, even those that aren't displayed,
   1157 	in the hopes of detecting a memory trasher.
   1158 	------------------------------------------------------------------------*/
   1159 	for (cell = 0; cell < MAP_CELL_TOTAL; cell++) {
   1160 		/*.....................................................................
   1161 		Validate Template & Icon data
   1162 		.....................................................................*/
   1163 		ttype = (*this)[cell].TType;
   1164 		ticon = (*this)[cell].TIcon;
   1165 		if (ttype >= TEMPLATE_COUNT && ttype != TEMPLATE_NONE)
   1166 			return(false);
   1167 
   1168 		/*.....................................................................
   1169 		To validate the icon value, we have to get a copy of the template's
   1170 		"icon map"; this map will have 0xff's in spots where there is no
   1171 		icon.  If the icon value is out of range or points to an invalide spot,
   1172 		return an error.
   1173 		.....................................................................*/
   1174 #if (0)
   1175 		if (ttype != TEMPLATE_NONE) {
   1176 			tclass = &TemplateTypeClass::As_Reference(ttype);
   1177 			ticon = (*this)[cell].TIcon;
   1178 			Mem_Copy(Get_Icon_Set_Map(tclass->Get_Image_Data()), map,
   1179 				tclass->Width * tclass->Height);
   1180 			if (ticon < 0 ||
   1181 				ticon >= (tclass->Width * tclass->Height) ||
   1182 				map[ticon]==0xff)
   1183 				return (false);
   1184 		}
   1185 #endif
   1186 		/*.....................................................................
   1187 		Validate Overlay
   1188 		.....................................................................*/
   1189 		overlay = (*this)[cell].Overlay;
   1190 		if (overlay < OVERLAY_NONE || overlay >= OVERLAY_COUNT)
   1191 			return(false);
   1192 
   1193 		/*.....................................................................
   1194 		Validate Smudge
   1195 		.....................................................................*/
   1196 		smudge = (*this)[cell].Smudge;
   1197 		if (smudge < SMUDGE_NONE || smudge >= SMUDGE_COUNT)
   1198 			return(false);
   1199 
   1200 		/*.....................................................................
   1201 		Validate LandType
   1202 		.....................................................................*/
   1203 		land = (*this)[cell].Land_Type();
   1204 		if (land < LAND_CLEAR || land >= LAND_COUNT)
   1205 			return(false);
   1206 
   1207 		/*.....................................................................
   1208 		Validate Occupier
   1209 		.....................................................................*/
   1210 		obj = (*this)[cell].Cell_Occupier();
   1211 		if (obj) {
   1212 			
   1213 			volatile TARGET target = obj->As_Target();		// This will do some internal verification
   1214 			
   1215 			if (!obj->IsActive) {
   1216 				return false;
   1217 			}
   1218 
   1219 			if (obj->IsInLimbo) {
   1220 				return false;
   1221 			}
   1222 				
   1223 			if (((unsigned int)Coord_Cell(obj->Coord) > 4095)) {
   1224 				return (false);
   1225 			}
   1226 		}
   1227 
   1228 		/*.....................................................................
   1229 		Validate Overlappers
   1230 		.....................................................................*/
   1231 		for (i = 0; i < 3; i++) {
   1232 			obj = (*this)[cell].Overlapper[i];
   1233 			if (obj) {
   1234 				
   1235 				volatile TARGET target = obj->As_Target();		// This will do some internal verification
   1236 
   1237 				if (!obj->IsActive) {
   1238 					return false;
   1239 				}
   1240 
   1241 				if (obj->IsInLimbo) {
   1242 					return false;
   1243 				}
   1244 				
   1245 				if (((unsigned int)Coord_Cell(obj->Coord) > 4095)) {
   1246 					return (false);
   1247 				}
   1248 			}
   1249 		}
   1250 	}
   1251 
   1252 	return (true);
   1253 }
   1254 
   1255 
   1256 
   1257 /***********************************************************************************************
   1258  * MapClass::Clean -- Clean up dangling pointers caused by bugs in the originl code.           *
   1259  *                                                                                             *
   1260  *   Ideally, we'd fix the underlying cause of the overlappers not being cleared               *
   1261  *   but we can afford the CPU time now                                                        *
   1262  *                                                                                             *
   1263  * INPUT:   none                                                                               *
   1264  *                                                                                             *
   1265  * OUTPUT:                                                                                     *
   1266  *                                                                                             *
   1267  * WARNINGS:   none                                                                            *
   1268  *                                                                                             *
   1269  * HISTORY:                                                                                    *
   1270  *   4/14/2020 11:48AM ST : Created.                                                           *
   1271  *=============================================================================================*/
   1272 void MapClass::Clean(void)
   1273 {
   1274 	CELL cell;
   1275 	ObjectClass *obj;
   1276 	int i;
   1277 #ifndef NDEBUG	
   1278 	char debug_message[256];
   1279 #endif
   1280 	bool active_fail = false;
   1281 	bool limbo_fail = false;
   1282 	const char *type_text = NULL;
   1283 	const char *ini_name = NULL;
   1284 	AbstractClass abstract_object;
   1285 	unsigned long abstract_vtable = *(unsigned long*)&abstract_object;
   1286 
   1287 	/*------------------------------------------------------------------------
   1288 	Check every cell on the map, even those that aren't displayed.
   1289 	------------------------------------------------------------------------*/
   1290 	for (cell = 0; cell < MAP_CELL_TOTAL; cell++) {
   1291 
   1292 		/*.....................................................................
   1293 		Validate Occupier
   1294 		.....................................................................*/
   1295 		(*this)[cell].Cell_Occupier();
   1296 
   1297 		/*.....................................................................
   1298 		Validate Overlappers
   1299 		.....................................................................*/
   1300 		for (i = 0; i < 3; i++) {
   1301 			obj = (*this)[cell].Overlapper[i];
   1302 			if (obj) {
   1303 				
   1304 				if (!obj->IsActive) {
   1305 					(*this)[cell].Overlapper[i] = NULL;
   1306 					active_fail = true;
   1307 				}
   1308 
   1309 				if (!active_fail && obj->IsInLimbo) {
   1310 					(*this)[cell].Overlapper[i] = NULL;
   1311 					limbo_fail = true;
   1312 				}
   1313 
   1314 				if (active_fail || limbo_fail) {
   1315 #ifndef NDEBUG					
   1316 					/*
   1317 					** This object is likely deleted. 
   1318 					*/
   1319 					if (abstract_vtable == *(unsigned long*)obj) {
   1320 						type_text = "Abstract";
   1321 						ini_name = "UNKNOWN";
   1322 					} else {
   1323 
   1324 						RTTIType type = obj->What_Am_I();
   1325 	
   1326 						switch (type) {
   1327 							default:
   1328 								type_text = "Unknown";
   1329 								break;
   1330 
   1331 							case RTTI_INFANTRY:
   1332 								type_text = "Infantry";
   1333 								break;
   1334 						
   1335 							case RTTI_UNIT:
   1336 								type_text = "Unit";
   1337 								break;
   1338 						
   1339 							case RTTI_AIRCRAFT:
   1340 								type_text = "Aircraft";
   1341 								break;
   1342 					
   1343 							case RTTI_BUILDING:
   1344 								type_text = "Building";
   1345 								break;
   1346 
   1347 							case RTTI_BULLET:
   1348 								type_text = "Bullet";
   1349 								break;
   1350 
   1351 							case RTTI_ANIM:
   1352 								type_text = "Anim";
   1353 								break;
   1354 
   1355 							case RTTI_SMUDGE:
   1356 								type_text = "Smudge";
   1357 								break;
   1358 
   1359 							case RTTI_TERRAIN:
   1360 								type_text = "Terrain";
   1361 								break;
   1362 						}
   1363 
   1364 						ini_name = obj->Class_Of().IniName;
   1365 					}
   1366 
   1367 					sprintf_s(debug_message, sizeof(debug_message) - 1, "Cleaned %s overlapper in cell %08X. Type=%s, IniName=%s", active_fail ? "inactive" : "limbo", cell, type_text, ini_name);
   1368 					GlyphX_Debug_Print(debug_message);
   1369 #endif //NDEBUG					
   1370 				}
   1371 			}
   1372 		}
   1373 	}
   1374 }
   1375 
   1376 
   1377 /***********************************************************************************************
   1378  * MapClass::Close_Object -- Finds a clickable close object to the specified coordinate.       *
   1379  *                                                                                             *
   1380  *    This routine is used by the mouse input processing code to find a clickable object       *
   1381  *    close to coordinate specified. This is for targeting as well as selection determination. *
   1382  *                                                                                             *
   1383  * INPUT:   coord -- The coordinate to scan for close object from.                             *
   1384  *                                                                                             *
   1385  * OUTPUT:  Returns with a pointer to an object that is nearby the specified coordinate.       *
   1386  *                                                                                             *
   1387  * WARNINGS:   There could be a cloaked object at the location, but it won't be considered     *
   1388  *             if it is not owned by the player.                                               *
   1389  *                                                                                             *
   1390  * HISTORY:                                                                                    *
   1391  *   08/20/1995 JLB : Created.                                                                 *
   1392  *=============================================================================================*/
   1393 ObjectClass * MapClass::Close_Object(COORDINATE coord) const
   1394 {
   1395 	ObjectClass * object = 0;
   1396 	int distance = 0;
   1397 	CELL cell = Coord_Cell(coord);
   1398 
   1399 	/*
   1400 	**	Scan through current and adjacent cells, looking for the
   1401 	**	closest object (within reason) to the specified coordinate.
   1402 	*/
   1403 	static int _offsets[] = {0, -1, 1, -MAP_CELL_W, MAP_CELL_W, MAP_CELL_W-1, MAP_CELL_W+1, -(MAP_CELL_W-1), -(MAP_CELL_W+1)};
   1404 	for (int index = 0; index < (sizeof(_offsets) / sizeof(_offsets[0])); index++) {
   1405 
   1406 		/*
   1407 		**	Examine the cell for close object. Make sure that the cell actually is a
   1408 		**	legal one.
   1409 		*/
   1410 		CELL newcell = cell + _offsets[index];
   1411 		if (In_Radar(newcell)) {
   1412 
   1413 			/*
   1414 			**	Search through all objects that occupy this cell and then
   1415 			**	find the closest object. Check against any previously found object
   1416 			**	to ensure that it is actually closer.
   1417 			*/
   1418 			ObjectClass * o = (*this)[newcell].Cell_Occupier();
   1419 			while (o) {
   1420 
   1421 				/*
   1422 				**	Special case check to ignore cloaked object if not allied with the player.
   1423 				*/
   1424 				// Changed for multiplayer. ST - 3/13/2019 5:38PM
   1425 				if (!o->Is_Techno() || !((TechnoClass *)o)->Is_Cloaked(PlayerPtr)) {
   1426 				//if (!o->Is_Techno() || ((TechnoClass *)o)->IsOwnedByPlayer || ((TechnoClass *)o)->Cloak != CLOAKED) {
   1427 					int d=-1;
   1428 					if (o->What_Am_I() == RTTI_BUILDING) {
   1429 						d = Distance(coord, Cell_Coord(newcell));
   1430 						if (d > 0x00C0) d = -1;
   1431 					} else {
   1432 						d = Distance(coord, o->Center_Coord());
   1433 					}
   1434 					if (d >= 0 && (!object || d < distance)) {
   1435 						distance = d;
   1436 						object = o;
   1437 					}
   1438 				}
   1439 				o = o->Next;
   1440 			}
   1441 		}
   1442 	}
   1443 
   1444 	/*
   1445 	** Handle aircraft selection separately, since they aren't tracked in cells while flying
   1446 	*/
   1447 	for (int index = 0; index < Aircraft.Count(); index++) {
   1448 		AircraftClass * aircraft = Aircraft.Ptr(index);
   1449 
   1450 		if (aircraft->In_Which_Layer() != LAYER_GROUND) {
   1451 			if (!aircraft->Is_Cloaked(PlayerPtr)) {
   1452 				int d = Distance(coord, Coord_Add(aircraft->Center_Coord(), XY_Coord(0, -Pixel_To_Lepton(aircraft->Altitude))));
   1453 				if (d >= 0 && (!object || d < distance)) {
   1454 					distance = d;
   1455 					object = aircraft;
   1456 				}
   1457 			}
   1458 		}
   1459 	}
   1460 
   1461 	/*
   1462 	**	Only return the object if it is within 1/4 cell distance from the specified
   1463 	**	coordinate.
   1464 	*/
   1465 	if (object && distance > 0xC0) {
   1466 		object = 0;
   1467 	}
   1468 	return(object);
   1469 }
   1470 
   1471 
   1472 
   1473 
   1474 #ifdef USE_RA_AI
   1475 
   1476 /*
   1477 ** Nearby_Location pulled in from RA for AI. ST - 7/24/2019 5:54PM
   1478 */
   1479 #ifndef ARRAY_SIZE
   1480 #define ARRAY_SIZE(a)	(sizeof(a)/sizeof(a[0]))
   1481 #endif
   1482 
   1483 /***********************************************************************************************
   1484  * MapClass::Nearby_Location -- Finds a generally clear location near a specified cell.        *
   1485  *                                                                                             *
   1486  *    This routine is used to find a location that probably will be ok to move to that is      *
   1487  *    located as close as possible to the specified cell. The computer uses this when it has   *
   1488  *    determined the ideal location for an object, but then needs to give a valid movement     *
   1489  *    destination to a unit.                                                                   *
   1490  *                                                                                             *
   1491  * INPUT:   cell  -- The cell that scanning should radiate out from.                           *
   1492  *                                                                                             *
   1493  *          zone  -- The zone that must be matched to find a legal location (value of -1 means *
   1494  *                   any zone will do).                                                        *
   1495  *                                                                                             *
   1496  *                                                                                             *
   1497  *          check -- The type of zone to check against. Only valid if a zone value is given.   *
   1498  *                                                                                             *
   1499  * OUTPUT:  Returns with the cell that is generally clear (legal to move to) that is close     *
   1500  *          to the specified cell.                                                             *
   1501  *                                                                                             *
   1502  * WARNINGS:   none                                                                            *
   1503  *                                                                                             *
   1504  * HISTORY:                                                                                    *
   1505  *   10/05/1995 JLB : Created.                                                                 *
   1506  *=============================================================================================*/
   1507 CELL MapClass::Nearby_Location(CELL cell) const	//, SpeedType speed, int zone, MZoneType check) const
   1508 {
   1509 	CELL topten[10];
   1510 	int count = 0;
   1511 	int xx = Cell_X(cell);
   1512 	int yy = Cell_Y(cell);
   1513 
   1514 	/*
   1515 	**	Determine the limits of the scanning in the four directions so that
   1516 	**	it won't scan past the edge of the world.
   1517 	*/
   1518 	int left = MapCellX;
   1519 	int right = MapCellX + MapCellWidth - 1;
   1520 	int top = MapCellY;
   1521 	int bottom = MapCellY + MapCellHeight - 1;
   1522 
   1523 	/*
   1524 	**	Radiate outward from the specified location, looking for the closest
   1525 	**	location that is generally clear.
   1526 	*/
   1527 	for (int radius = 0; radius < MAP_CELL_W; radius++) {
   1528 		CELL newcell;
   1529 		CellClass const * cellptr;
   1530 
   1531 		/*
   1532 		**	Scan the top and bottom rows of the "box".
   1533 		*/
   1534 		for (int x = xx-radius; x <= xx+radius; x++) {
   1535 			if (x >= left && x <= right) {
   1536 				int y = yy-radius;
   1537 				if (y >= top) {
   1538 					newcell = XY_Cell(x, y);
   1539 					cellptr = &Map[newcell];
   1540 					if (Map.In_Radar(newcell) && cellptr->Is_Clear_To_Move(false, false)) {
   1541 						topten[count++] = newcell;
   1542 					}
   1543 				}
   1544 				if (count == ARRAY_SIZE(topten)) break;
   1545 
   1546 				y = yy+radius;
   1547 				if (y <= bottom) {
   1548 					newcell = XY_Cell(x, y);
   1549 					cellptr = &Map[newcell];
   1550 					if (Map.In_Radar(newcell) && cellptr->Is_Clear_To_Move(false, false)) {
   1551 						topten[count++] = newcell;
   1552 					}
   1553 				}
   1554 				if (count == ARRAY_SIZE(topten)) break;
   1555 			}
   1556 		}
   1557 
   1558 		if (count == ARRAY_SIZE(topten)) break;
   1559 
   1560 		/*
   1561 		**	Scan the left and right columns of the "box".
   1562 		*/
   1563 		for (int y = yy-radius; y <= yy+radius; y++) {
   1564 			if (y >= top && y <= bottom) {
   1565 				int x = xx-radius;
   1566 				if (x >= left) {
   1567 					newcell = XY_Cell(x, y);
   1568 					cellptr = &Map[newcell];
   1569 					if (Map.In_Radar(newcell) && cellptr->Is_Clear_To_Move(false, false)) {
   1570 						topten[count++] = newcell;
   1571 					}
   1572 				}
   1573 				if (count == ARRAY_SIZE(topten)) break;
   1574 
   1575 				x = xx+radius;
   1576 				if (x <= right) {
   1577 					newcell = XY_Cell(x, y);
   1578 					cellptr = &Map[newcell];
   1579 					if (Map.In_Radar(newcell) && cellptr->Is_Clear_To_Move(false, false)) {
   1580 						topten[count++] = newcell;
   1581 					}
   1582 				}
   1583 				if (count == ARRAY_SIZE(topten)) break;
   1584 			}
   1585 		}
   1586 
   1587 		if (count > 0) break;
   1588 	}
   1589 
   1590 	if (count > 0) {
   1591 		return(topten[Frame % count]);
   1592 	}
   1593 	return(0);
   1594 }
   1595 
   1596 #endif // USE_RA_AI