CnC_Remastered_Collection

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

FINDPATH.CPP (47315B)


      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/FINDPATH.CPP 1     3/03/97 10:24a 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 : FINDPATH.CPP                                                 *
     24  *                                                                                             *
     25  *                   Programmer : Joe L. Bostic                                                *
     26  *                                                                                             *
     27  *                   Start Date : September 10, 1993                                           *
     28  *                                                                                             *
     29  *                  Last Update : May 25, 1995   [PWG]                                         *
     30  *                                                                                             *
     31  * The path algorithm works by following a LOS path to the target. If it                       *
     32  * collides with an impassable spot, it uses an Edge following routine to                      *
     33  * get around it. The edge follower moves along the edge in a clockwise or                     *
     34  * counter clockwise fashion until finding the destination spot. The                           *
     35  * destination is determined by Find_Path. It is the first passable that                       *
     36  * can be reached (so it will handle the doughnut case, where there is                         *
     37  * a passable in the center of an unreachable area).                                           *
     38  *                                                                                             *
     39  *---------------------------------------------------------------------------------------------*
     40  * Functions:                                                                                  *
     41  *   Clear_Path_Overlap -- clears the path overlap list                                        *
     42  *   Find_Path -- Find a path from point a to point b.                                         *
     43  *   Find_Path_Cell -- Finds a given cell on a specified path                                  *
     44  *   Follow_Edge -- Follow an edge to get around an impassable spot.                           *
     45  *   FootClass::Unravel_Loop -- Unravels a loop in the movement path                           *
     46  *   Get_New_XY -- Get the new x,y based on current position and direction.                    *
     47  *   Optimize_Moves -- Optimize the move list.                                                 *
     48  *   Set_Path_Overlap -- Sets the overlap bit for given cell                                   *
     49  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     50 
     51 #include	"function.h"
     52 //#include	<string.h>
     53 
     54 /*
     55 **	When an edge search is started, it can be performed CLOCKwise or
     56 **	COUNTERCLOCKwise direction.
     57 */
     58 #define	CLOCK				(FacingType)1	// Clockwise.
     59 #define	COUNTERCLOCK	(FacingType)-1	// Counterclockwise.
     60 
     61 /*
     62 **	If defined, diagonal moves are allowed, else no diagonals.
     63 */
     64 #define	DIAGONAL
     65 
     66 /*
     67 **	This is the marker to signify the end of the path list.
     68 */
     69 #define	END			FACING_NONE
     70 
     71 /*
     72 **	"- 1" test for bit manipulation.
     73 */
     74 #define TEST
     75 
     76 /*
     77 **	If memory is more important than speed, set this define to
     78 **	true. It will then perform intermediate optimizations to get the most
     79 **	milage out of a limited movement list staging area. If this value
     80 **	is true then it figures paths a bit more intelligently.
     81 */
     82 #define	SAVEMEM		true
     83 
     84 /*
     85 **	Modify this macro so that given two cell values, it will return
     86 **	a value between 0 and 7, with 0 being North and moving
     87 **	clockwise (just like map degrees).
     88 */
     89 #define	CELL_FACING(a, b)		Dir_Facing(::Direction((a), (b)))
     90 
     91 
     92 /*-------------------------------------------------------------------------*/
     93 /*
     94 **	Cells values are really indexes into the 'map'. The following value is
     95 **	the X width of the map.
     96 */
     97 #define	MODULO	MAP_CELL_W
     98 
     99 /*
    100 **	Maximum lookahead cells. Twice this value in bytes will be
    101 **	reserved on the stack. The smaller this number, the faster the processing.
    102 */
    103 #define MAX_MLIST_SIZE		300
    104 #define THREAT_THRESHOLD	5
    105 
    106 
    107 #define	MAX_PATH_EDGE_FOLLOW	400
    108 
    109 #ifdef NEVER
    110 typedef enum {
    111 	FACING_N,			// North
    112 	FACING_NE,			// North-East
    113 	FACING_E,			// East
    114 	FACING_SE,			// South-East
    115 	FACING_S,			// South
    116 	FACING_SW,			// South-West
    117 	FACING_W,			// West
    118 	FACING_NW,			// North-West
    119 
    120 	FACING_COUNT			// Total of 8 directions (0..7).
    121 } FacingType;
    122 #endif
    123 
    124 
    125 /*-------------------------------------------------------------------------*/
    126 //static bool DrawPath;
    127 
    128 inline FacingType Opposite(FacingType face)
    129 {
    130 	return( (FacingType) (face ^ 4));
    131 }
    132 
    133 
    134 inline static FacingType Next_Direction(FacingType facing, FacingType dir)
    135 {
    136 	facing = facing + dir;
    137 	#ifndef DIAGONAL
    138 		facing = (FacingType)(facing & 0x06);
    139 	#endif
    140 	return(facing);
    141 }
    142 
    143 /*=========================================================================*/
    144 /* Define a couple of variables which are private to the module they are   */
    145 /*      declared in.                                                       */
    146 /*=========================================================================*/
    147 static unsigned long MainOverlap[MAP_CELL_TOTAL/32];		// overlap list for the main path
    148 static unsigned long LeftOverlap[MAP_CELL_TOTAL/32];		// overlap list for the left path
    149 static unsigned long RightOverlap[MAP_CELL_TOTAL/32];	// overlap list for the right path
    150 
    151 
    152 //static CELL MoveMask = 0;
    153 static CELL DestLocation;
    154 static CELL StartLocation;
    155 
    156 /***************************************************************************
    157  * Point_Relative_To_Line -- Relation between a point and a line           *
    158  *                                                                         *
    159  *      If a point is on a line then the following function holds true:    *
    160  *      (x - x2)(z1 - z2) = (z - z2)(x1 - x2) given x,z a point on the     *
    161  *      line (x1,z1),(x2,z2).                                              *
    162  *      If the right side is > then the left side then the point is on one *
    163  *      side of the line and if the right side is < the the left side, then*
    164  *      the point is on the other side of the line.  By subtracting one side*
    165  *      from the other we can determine on what side (if any) the point is on*
    166  *      by testing the side of the resulting subtraction.                  *
    167  *                                                                         *
    168  * INPUT:                                                                  *
    169  *      int   x    - x pos of point.                                       *
    170  *      int   z    - z pos of point.                                       *
    171  *      int   x1 - x pos of first end of line segment.                     *
    172  *      int   z1 - z pos of first end of line segment.                     *
    173  *      int   x1 - x pos of second end of line segment.                    *
    174  *      int   z1 - z pos of second end of line segment.                    *
    175  *                                                                         *
    176  * OUTPUT:                                                                 *
    177  *   Assuming (x1,z1) is north, (x2,z2) is south:                          *
    178  *       0 : point is on line.                                             *
    179  *       > 0 : point is east of line.                                      *
    180  *       < 0 : point is west of line.                                      *
    181  *                                                                         *
    182  * WARNINGS:                                                               *
    183  *    Remember that int means that assumes 16 bits of precision.           *
    184  *                                                                         *
    185  * HISTORY:                                                                *
    186  *   10/28/1994 SKB : Created.                                             *
    187  *=========================================================================*/
    188 int Point_Relative_To_Line(int x, int z, int x1, int z1, int x2, int z2)
    189 {
    190 	return((((long)x - (long)x2) * ((long)z1 - (long)z2)) - (((long)z - (long)z2) * ((long)x1 - (long)x2)));
    191 }
    192 
    193 
    194 /***************************************************************************
    195  * FootClass::Unravel_Loop -- Unravels a loop in the movement path         *
    196  *                                                                         *
    197  * While in the midst of the Follow Edge logic, it is possible (due to the *
    198  * fact that we support diagonal movement) to begin looping around a       *
    199  * column of some type.  The Unravel loop function will scan backward      *
    200  * through the list and fixup the path to try to prevent the loop.         *
    201  *                                                                         *
    202  * INPUT:      path   -   pointer to the generated path so we can pull the *
    203  *                         commands out of it.                             *
    204  *               cell   -   the cell we tried to enter that generated the  *
    205  *                        double overlap condition.                        *
    206  *               dir    -   the direction we tried to enter from when we   *
    207  *                        generated the double overlap condition           *
    208  *               startx -   the start x position of this path segment      *
    209  *               starty - the start y position of this path segment        *
    210  *               destx    - the dest x position for this path segment      *
    211  *               desty    - the dest y position for this path segment      *
    212  *                                                                         *
    213  * OUTPUT:      TRUE    - loop has been successfully unravelled             *
    214  *               FALSE  - loop can not be unravelled so abort follow edge  *
    215  *                                                                         *
    216  * WARNINGS:   none                                                        *
    217  *                                                                         *
    218  * HISTORY:                                                                *
    219  *   05/25/1995 PWG : Created.                                             *
    220  *=========================================================================*/
    221 bool FootClass::Unravel_Loop(PathType * path, CELL &cell, FacingType &dir, int sx, int sy, int dx, int dy, MoveType threshhold)
    222 {
    223 	/*
    224 	** Walk back to the actual cell before we advanced our position
    225 	*/
    226 	FacingType	curr_dir	= dir;
    227 	CELL			curr_pos = Adjacent_Cell(cell, Opposite(curr_dir));
    228 	int			idx		= path->Length;			// start at the last position
    229 	FacingType	* list		= &path->Command[idx-1];	// point to the last command
    230 	int			checkx;
    231 	int			checky;
    232 	int			last_was_line	= false;
    233 
    234 	/*
    235 	** loop backward through the list searching for a point that is
    236 	** on the line.  If the point was a diagonal move then adjust
    237 	** it.
    238 	*/
    239 	while (idx) {
    240 		checkx		= Cell_X(curr_pos);
    241 		checky		= Cell_Y(curr_pos);
    242 
    243 		if (!Point_Relative_To_Line(checkx, checky, sx, sy, dx, dy) || last_was_line) {
    244 
    245 			/*
    246 			** We have now found a point on the line.  Now we must check to see
    247 			** if we left the line on a diagonal.  If we did then we need to fix
    248 			** it up.
    249 			*/
    250 			if (curr_dir & 1 && curr_pos != path->LastFixup) {
    251 				cell 				 = curr_pos;
    252 				dir  				 = *(list-1);
    253 				path->Length	 = idx;
    254 				path->LastFixup = curr_pos;
    255 				return(true);
    256 			}
    257 
    258 			last_was_line = !last_was_line;
    259 		}
    260 
    261 		/*
    262 		** Since this cell will not be in the list, then pull out its cost
    263 		*/
    264 		path->Cost -= Passable_Cell(curr_pos, *list, -1, threshhold);
    265 
    266 		/*
    267 		** Remove this cells flag from the overlap list for the path
    268 		*/
    269 #ifdef TEST
    270 		path->Overlap[curr_pos >> 5] &= ~(1 << ((curr_pos & 31)));
    271 #else
    272 		path->Overlap[curr_pos >> 5] &= ~(1 << ((curr_pos & 31) - 1));
    273 #endif
    274 
    275 		/*
    276 		** Adjust to the next list position and direction.
    277 		*/
    278 		curr_dir = *list--;
    279 		curr_pos	= Adjacent_Cell(curr_pos, Opposite(curr_dir));
    280 		idx--;
    281 	}
    282 
    283 	/*
    284 	** If we can't modify the list to eliminate the problem, then we have
    285 	** a larger problem in that we have deleted all of the cells in the
    286 	** list.
    287 	*/
    288 	return(false);
    289 }
    290 
    291 
    292 /***************************************************************************
    293  * Register_Cell -- registers a cell on our path and check for backtrack   *
    294  *                                                                         *
    295  * This function adds a new cell to our path.  If the cell has already     *
    296  * been recorded as part of our path, then this function moves back down   *
    297  * the list truncating it at the point we registered that cell.  This      *
    298  * function will eliminate all backtracking from the list.                 *
    299  *                                                                         *
    300  * INPUT:      long   * list - the list to set the overlap bit for         *
    301  *               CELL  cell    - the cell to mark on the overlap list      *
    302  *                                                                         *
    303  * OUTPUT:     BOOL - TRUE if bit has been set, FALSE if bit already set   *
    304  *                                                                         *
    305  * HISTORY:                                                                *
    306  *   05/23/1995 PWG : Created.                                             *
    307  *=========================================================================*/
    308 bool FootClass::Register_Cell(PathType * path, CELL cell, FacingType dir, int cost, MoveType threshhold)
    309 {
    310 	FacingType  * list;
    311 	int 	pos  = cell >> 5;
    312 #ifdef TEST
    313 	int	bit  = (cell & 31);
    314 #else
    315 	int	bit  = (cell & 31) - 1;
    316 #endif
    317 
    318 	/*
    319 	** See if this point has already been registered as on the list.  If so
    320 	** we need to truncate the list back to this point and register the
    321 	** new direction.
    322 	*/
    323 	if (path->Overlap[pos] & (1 << bit)) {
    324 		/*
    325 		** If this is not a case of immediate back tracking then handle
    326 		** by searching the list to see what we find.  However is this is
    327 		** an immediate back track, then pop of the last direction
    328 		** and unflag the cell we are in (not the cell we are moving to).
    329 		** Note: That we do not check for a zero length cell because we
    330 		** could not have a duplicate unless there are cells in the list.
    331 		*/
    332 
    333 		if (path->Command[path->Length - 1] == Opposite(dir)) {
    334 			CELL pos = Adjacent_Cell(cell, Opposite(dir));
    335 #ifdef TEST
    336 			path->Overlap[pos >> 5] &= ~(1 << ((pos & 31)));
    337 #else
    338 			path->Overlap[pos >> 5] &= ~(1 << ((pos & 31) - 1));
    339 #endif
    340 			path->Length--;
    341 		} else {
    342 			/*
    343 			** If this overlap is in the same place as we had our last overlap
    344 			** then we are in a loop condition.  We need to signify that we
    345 			** cannot register this cell.
    346 			*/
    347 			if (path->LastOverlap == cell) {
    348 				return(false);
    349 			} else {
    350 				path->LastOverlap = cell;
    351 			}
    352 
    353 			CELL pos 	  	= path->Start;
    354 			int newlen		= 0;
    355 			int idx 		   = 0;
    356 			list		      = path->Command;
    357 
    358 			/*
    359 			** Note that the cell has to be in this list, so theres no sense
    360 			** in checking whether we found it (famous last words).
    361 			**
    362 			** PWG 8/16/95 - However there is no sense searching the list if
    363 			**               the cell we have overlapped on is the cell we
    364 			**               started in.
    365 			*/
    366 
    367 			if (pos != cell) {
    368 				while (idx < path->Length) {
    369 					pos = Adjacent_Cell(pos, *list);
    370 			  		if (pos == cell) {
    371 						idx++;
    372 						list++;
    373 						break;
    374 					}
    375 					idx++;
    376 					list++;
    377 				}
    378 				newlen = idx;
    379 			}
    380 
    381 			/*
    382 			** Now we are pointing at the next command in the list.  From here on
    383 			** out we need to unmark the fact that we have entered these cells and
    384 			** adjust the cost of our path to reflect that we have not entered
    385 			** then.
    386 			*/
    387 			while (idx < path->Length) {
    388 				pos			= Adjacent_Cell(pos, *list);
    389 				path->Cost -= Passable_Cell(pos, *list, -1, threshhold);
    390 #ifdef TEST
    391 				path->Overlap[pos >> 5] &= ~(1 << ((pos & 31)));
    392 #else
    393 				path->Overlap[pos >> 5] &= ~(1 << ((pos & 31) - 1));
    394 #endif
    395 				idx++;
    396 				list++;
    397 			}
    398 			path->Length = newlen;
    399 		}
    400 	} else {
    401 		/*
    402 		** Now we need to register the new direction, updating the cell structure
    403 		** and the cost.
    404 		*/
    405 		int cpos 				= path->Length++;
    406 		path->Command[cpos]	= dir;			// save of the direction we moved
    407 		path->Cost 			  += cost;			// figure new cost for cell
    408 		path->Overlap[pos]  |= (1 << bit);	// mark the we have entered point
    409 	}
    410 	return(true);
    411 }
    412 
    413 
    414 /***********************************************************************************************
    415  * Find_Path -- Find a path from point a to point b.                                           *
    416  *                                                                                             *
    417  * INPUT:      int source x,y, int destination x,y, char *final moves                          *
    418  *             array to store moves, int maximum moves we may attempt                          *
    419  *                                                                                             *
    420  * OUTPUT:     int number of moves it took (IMPOSSIBLE_MOVES if we could                       *
    421  *             not reach the destination                                                       *
    422  *                                                                                             *
    423  * WARNINGS:   This algorithm assumes that the target is NOT situated                          *
    424  *             inside an impassable. If this case may arise, the do-while                      *
    425  *             statement inside the inner while (true) must be changed                         *
    426  *             to include a check to se if the next_x,y is equal to the                        *
    427  *             dest_x,y. If it is, then return(IMPOSSIBLE_MOVES).                              *
    428  *                                                                                             *
    429  * HISTORY:                                                                                    *
    430  *   07/08/1991  CY : Created.                                                                 *
    431  *=============================================================================================*/
    432 PathType * FootClass::Find_Path(CELL dest, FacingType * final_moves, int maxlen, MoveType threshhold)
    433 {
    434 	CELL					source = Coord_Cell(Coord);		// Source expressed as cell
    435 	static PathType	path;										// Main path control.
    436 	CELL					next;										// Next cell to enter
    437 	CELL					startcell;								// Cell we started in
    438 	FacingType			direction;								// Working direction of look ahead.
    439 	FacingType			newdir;									// Tentative facing value.
    440 
    441 	bool					left=false, 							// Was leftward path legal?
    442 							right=false;							// Was rightward path legal?
    443 
    444 	int					len;										// Length of detour command list.
    445 	int					unit_threat;							// Calculated unit threat rating
    446 	int					cost;										// Cost to enter the square
    447 	FacingType			moves_left[MAX_MLIST_SIZE+2], 	// Counterclockwise move list.
    448 							moves_right[MAX_MLIST_SIZE+2];	// Clockwise move list.
    449 	PathType				pleft,pright;							// Path control structures.
    450 	PathType *			which;									// Which path to actually use.
    451 	int					threat = 0;			//
    452 	int					threat_stage = 0; //These weren't initialized. ST - 1/8/2019 12:03PM
    453 
    454 
    455 	/*
    456 	** If we have been provided an illegal place to store our final moves
    457 	** then forget it.
    458 	*/
    459 	if (!final_moves) return(NULL);
    460 
    461 	BStart(BENCH_FINDPATH);
    462 
    463 	PathCount++;
    464 
    465 	if (Team && Team->Class->IsRoundAbout) {
    466 		unit_threat			= (Team) ? Team->Risk : Risk();
    467 		threat_stage		= 0;
    468 		threat				= 0;
    469 	} else {
    470 		unit_threat = threat = -1;
    471 	}
    472 
    473 	StartLocation = source;
    474 	DestLocation = dest;
    475 
    476 	/*
    477 	** Initialize the path structure so that we can keep track of the
    478 	** path.
    479 	*/
    480 	path.Start			= source;
    481 	path.Cost			= 0;
    482 	path.Length 		= 0;
    483 	path.Command 		= final_moves;
    484 	path.Command[0] 	= END;
    485 	path.Overlap		= MainOverlap;
    486 	path.LastOverlap	= -1;
    487 	path.LastFixup		= -1;
    488 
    489 	memset(path.Overlap, 0, sizeof(MainOverlap));
    490 
    491 	/*
    492 	** Clear the over lap list and then make sure that our starting position is marked
    493 	** on the overlap list.  (Otherwise the harvesters will drive in circles... )
    494 	*/
    495 #ifdef TEST
    496 	path.Overlap[source >> 5] |= (1 << ((source & 31)));
    497 #else
    498 	path.Overlap[source >> 5] |= (1 << ((source & 31) - 1));
    499 #endif
    500 
    501 	startcell 			= source;
    502 
    503 	/*
    504 	**	Account for trailing end of list command, so reduce the maximum
    505 	**	allowed legal commands to reflect this.
    506 	*/
    507 	maxlen--;
    508 
    509 	/*
    510 	**	As long as there is room to put commands in the movement command list,
    511 	** then put commands in it.  We build the path using the following
    512 	** methodology.
    513 	**
    514 	** 1. Scan through the desired straight line path until we either hit an
    515 	**    impassable or have created a valid path.
    516 	**
    517 	** 2. If we have hit an impassable, walk through the impassable to make
    518 	**    sure that there is a passable on the other side.  If there is not
    519 	**    and we can not change the impassable, then this list is dead.
    520 	**
    521 	** 3. Walk around the impassable on both the left and right edges and
    522 	**    take the shorter of the two paths.
    523 	**
    524 	** 4. Taking the new location as our start location start again with
    525 	**    step #1.
    526 	*/
    527 	while (path.Length < maxlen) {
    528 
    529 top_of_list:
    530 		/*
    531 		**	Have we reached the destination already?  If so abort any further
    532 		**	command building.
    533 		*/
    534 		if (startcell == dest) {
    535 			break;
    536 		}
    537 
    538 		/*
    539 		**	Find the absolute correct direction to reach the next straight
    540 		** line cell and what cell it is.
    541 		*/
    542 		direction	= CELL_FACING(startcell, dest);
    543 		next			= Adjacent_Cell(startcell, direction);
    544 
    545 		/*
    546 		**	If we can move here, then make this our next move.
    547 		*/
    548 		cost = Passable_Cell(next, direction, threat, threshhold);
    549 		if (cost) {
    550 			Register_Cell(&path, next, direction, cost, threshhold);
    551 		} else {
    552 			/*
    553 			**	If the impassable location is actually the destination,
    554 			**	then stop here and consider this "good enough".
    555 			*/
    556 			if (next == dest) break;
    557 
    558 			/*
    559 			**	We could not move to the next cell, so follow through the
    560 			**	impassable until we find a passable spot that can be reached.
    561 			** Once we find a passable, figure out the shortest path to it.
    562 			** Since we have variable passable conditions this is not as
    563 			** simple as it used to be.  The limiter loop below allows us to
    564 			** step through ten doughnuts before we give up.
    565 			*/
    566 			for (int limiter = 0; limiter < 5; limiter++) {
    567 
    568 				/*
    569 				**	Get the next passable position by zipping through the
    570 				** impassable positions until a passable position is found
    571 				**	or the destination is reached.
    572 				*/
    573 				for (;;) {
    574 
    575 					/*
    576 					**	Move one step closer toward destination.
    577 					*/
    578 					newdir	= CELL_FACING(next, dest);
    579 					next		= Adjacent_Cell(next, newdir);
    580 
    581 					/*
    582 					** If the cell is passable then we have been completely
    583 					** successful.  If the cell is not passable then continue.
    584 					*/
    585 					if (Passable_Cell(next, FACING_NONE, threat, threshhold)) {
    586 //					if ((Passable_Cell(next, FACING_NONE, threat, threshhold)) || (next == dest)) {
    587 						break;
    588 					}
    589 
    590 					/*
    591 					**	If we reached destination while in this loop, we
    592 					**	know that either the destination is impassible (if
    593 					**	we are ignoring) or that we need to up our threat
    594 					** tolerance and try again.
    595 					*/
    596 					if (next == dest) {
    597 						if (threat != -1) {
    598 							switch (threat_stage++) {
    599 								case 0:
    600 									threat = unit_threat >> 1;
    601 									break;
    602 
    603 								case 1:
    604 									threat += unit_threat;
    605 									break;
    606 
    607 								case 2:
    608 									threat = -1;
    609 									break;
    610 							}
    611 							goto top_of_list;
    612 						}
    613 						goto end_of_list;
    614 					}
    615 				}
    616 
    617 				/*
    618 				**	Try to find a path to the passable position by following
    619 				**	the edge of the blocking object in both CLOCKwise and
    620 				**	COUNTERCLOCKwise fashions.
    621 				*/
    622 				int follow_len = maxlen + (maxlen >> 1);
    623 
    624 				Mem_Copy(&path, &pleft, sizeof(PathType));
    625 				pleft.Command 	= &moves_left[0];
    626 				pleft.Overlap 	= LeftOverlap;
    627 				Mem_Copy(path.Command, pleft.Command, path.Length);
    628 				Mem_Copy(path.Overlap, pleft.Overlap, sizeof(LeftOverlap));
    629 
    630 				// MBL 09.30.2019: We hit a runtime bounds crash where END (-1 / 0xFF) was being poked into +1 just past the end of the moves_right[] array;
    631 				// The FacingType moves_left[] and moves_right[] arrays already have MAX_MLIST_SIZE+2 as their size, which may have been a previous attempted fix;
    632 				// We are now passing MAX_MLIST_SIZE, since the sizeof calculations included the +2 buffering;
    633 				#if 0
    634 				left = Follow_Edge(startcell, next, &pleft, COUNTERCLOCK, direction, threat, threat_stage, sizeof(moves_left)/sizeof(moves_left[0]), threshhold);
    635 //				left = Follow_Edge(startcell, next, &pleft, COUNTERCLOCK, direction, threat, threat_stage, follow_len, threshhold);
    636 				#endif
    637 				left = Follow_Edge(startcell, next, &pleft, COUNTERCLOCK, direction, threat, threat_stage, MAX_MLIST_SIZE, threshhold);
    638 
    639 
    640 				if (left) {
    641 					follow_len = min(maxlen, pleft.Length + (pleft.Length >> 1));
    642 				}
    643 
    644 				Mem_Copy(&path, &pright, sizeof(PathType));
    645 				pright.Command = &moves_right[0];
    646 				pright.Overlap = RightOverlap;
    647 				Mem_Copy(path.Command, pright.Command, path.Length);
    648 				Mem_Copy(path.Overlap, pright.Overlap, sizeof(RightOverlap));
    649 
    650 				// MBL 09.30.2019: We hit a runtime bounds crash where END (-1 / 0xFF) was being poked into +1 just past the end of the moves_right[] array;
    651 				// The FacingType moves_left[] and moves_right[] arrays already have MAX_MLIST_SIZE+2 as their size, which may have been a previous attempted fix;
    652 				// We are now passing MAX_MLIST_SIZE, since the sizeof calculations included the +2 buffering;
    653 				#if 0
    654 				right = Follow_Edge(startcell, next, &pright, CLOCK, direction, threat, threat_stage, sizeof(moves_right)/sizeof(moves_right[0]), threshhold);
    655 //				right = Follow_Edge(startcell, next, &pright, CLOCK, direction, threat, threat_stage, follow_len, threshhold);
    656 				#endif
    657 				right = Follow_Edge(startcell, next, &pright, CLOCK, direction, threat, threat_stage, MAX_MLIST_SIZE, threshhold);
    658 
    659 				/*
    660 				**	If we could find a path, break from this loop. Otherwise this
    661 				**	means that we have found a "hole" of passable terrain that
    662 				**	cannot be reached by normal means. Scan forward looking for
    663 				**	the other side of the "doughnut".
    664 				*/
    665 				if (left || right) break;
    666 
    667 				/*
    668 				**	If no path can be found to the intermediate cell, then
    669 				**	presume we have found a doughnut of some sort. Scan
    670 				**	forward until the next impassable is found and then
    671 				**	process this loop again.
    672 				*/
    673 				do {
    674 
    675 					/*
    676 					**	If we reached destination while in this loop, we
    677 					**	know that either the destination is impassible (if
    678 					**	we are ignoring) or that we need to up our threat
    679 					** tolerance and try again.
    680 					*/
    681 					if (next == dest) {
    682 						if (threat != -1) {
    683 							switch (threat_stage++) {
    684 								case 0:
    685 									threat = unit_threat >> 1;
    686 									break;
    687 
    688 								case 1:
    689 									threat += unit_threat;
    690 									break;
    691 
    692 								case 2:
    693 									threat = -1;
    694 									break;
    695 							}
    696 							goto top_of_list;
    697 						}
    698 						goto end_of_list;
    699 					}
    700 
    701 					newdir	= CELL_FACING(next, dest);
    702 					next		= Adjacent_Cell(next, newdir);
    703 				} while (Passable_Cell(next, newdir, threat, threshhold));
    704 			}
    705 
    706 			if (!left && !right) break;
    707 
    708 			/*
    709 			**	We found a path around the impassable locations, so figure out
    710 			**	which one was the smallest and copy those moves into the
    711 			**	path.Command array.
    712 			*/
    713 			which = &pleft;
    714 			if (right) {
    715 				which = &pright;
    716 				if (left) {
    717 					if (pleft.Length < pright.Length) {
    718 						which = &pleft;
    719 					} else {
    720 						which = &pright;
    721 					}
    722 				}
    723 			}
    724 
    725 			/*
    726 			**	Record as much as possible of the shorter of the two
    727 			**	paths. The trailing EOL command is not copied because
    728 			**	this may not be the end of the find path logic.
    729 			*/
    730 			len = which->Length;
    731 			len = min(len, maxlen);
    732 			if (len > 0) {
    733 				memcpy(&path.Overlap[0], &which->Overlap[0], sizeof(LeftOverlap));
    734 				memcpy(&path.Command[0], &which->Command[0], len * sizeof(FacingType));
    735 				path.Length 		= len;
    736 				path.Cost   		= which->Cost;
    737 				path.LastOverlap 	= -1;
    738 				path.LastFixup	 	= -1;
    739 			} else {
    740 				break;
    741 			}
    742 		}
    743 		startcell = next;
    744 	}
    745 
    746 end_of_list:
    747 	/*
    748 	**	Poke in the stop command.
    749 	*/
    750 	if (path.Length < maxlen) {
    751 		path.Command[path.Length++] = END;
    752 	}
    753 
    754 	/*
    755 	**	Optimize the move list but only necessary if
    756 	**	diagonal moves are allowed.
    757 	*/
    758 	#ifdef DIAGONAL
    759 		Optimize_Moves(&path, threshhold);
    760 	#endif
    761 
    762 	BEnd(BENCH_FINDPATH);
    763 
    764 	return(&path);
    765 }
    766 
    767 
    768 /***********************************************************************************************
    769  * Follow_Edge -- Follow an edge to get around an impassable spot.                             *
    770  *                                                                                             *
    771  * INPUT:   start    -- cell to head from                                                      *
    772  *                                                                                             *
    773  *            target   -- Target cell to head to.                                              *
    774  *                                                                                             *
    775  *          path     -- Pointer to path list structure.                                        *
    776  *                                                                                             *
    777  *          search   -- Direction of search (1=clock, -1=counterclock).                        *
    778  *                                                                                             *
    779  *          olddir   -- Facing impassible direction from start.                                *
    780  *                                                                                             *
    781  *          callback -- Function pointer for determining if a cell is                          *
    782  *                      passable or not.                                                       *
    783  *                                                                                             *
    784  * OUTPUT:  bool: Could a path be found to the desired cell?                                   *
    785  *                                                                                             *
    786  * WARNINGS:   none                                                                            *
    787  *                                                                                             *
    788  * HISTORY:                                                                                    *
    789  *   07/08/1991  CY : Created.                                                                 *
    790  *   06/01/1992  JLB : Optimized & commented.                                                  *
    791  *=============================================================================================*/
    792 bool FootClass::Follow_Edge(CELL start, CELL target, PathType * path, FacingType search, FacingType olddir, int threat, int , int max_cells, MoveType threshhold)
    793 {
    794 	FacingType	newdir;			// Direction of facing before surrounding cell check.
    795 	CELL			oldcell,		// Current cell.
    796 					newcell;		// Tentative new cell.
    797 	int			cost;				// Working cost value.
    798 	int			startx;
    799 	int			starty;
    800 	int			online=true;
    801 	int			targetx;
    802 	int			targety;
    803 	int			oldval = 0;
    804 	int			cellcount=0;
    805 	int			forceout = false;
    806 	FacingType	firstdir = (FacingType)-1;
    807 	CELL			firstcell = -1;
    808 	bool			stepped_off_line = false;
    809 	startx 	= Cell_X(start);
    810 	starty	= Cell_Y(start);
    811 	targetx  = Cell_X(target);
    812 	targety	= Cell_Y(target);
    813 
    814 	if (!path) return(false);
    815 	path->LastOverlap = -1;
    816 	path->LastFixup	= -1;
    817 
    818 	#ifndef DIAGONAL
    819 		/*
    820 		**	The edge following algorithm doesn't "do" diagonals. Force initial facing
    821 		**	to be an even 90 degree value. Adjust it in the direction it should be
    822 		**	rotating.
    823 		*/
    824 		if (olddir & 0x01) {
    825 			olddir = Next_Direction(olddir, search);
    826 		}
    827 	#endif
    828 
    829 	newdir		= Next_Direction(olddir, search);
    830 	oldcell 		= start;
    831 	newcell 		= Adjacent_Cell(oldcell, newdir);
    832 
    833 	/*
    834 	**	Continue until we find our target, find our original starting spot,
    835 	**	or run out of moves.
    836 	*/
    837 	while (path->Length < max_cells) {
    838 
    839 		/*
    840 		**	Look in all the adjacent cells to determine a passable one that
    841 		**	most closely matches the desired direction (working in the specified
    842 		**	direction).
    843 		*/
    844 		newdir = olddir;
    845 		for (;;) {
    846 			bool	forcefail;		// Is failure forced?
    847 
    848 			forcefail = false;
    849 
    850 			#ifdef DIAGONAL
    851 				/*
    852 				**	Rotate 45/90 degrees in desired direction.
    853 				*/
    854 				newdir = Next_Direction(newdir, search);
    855 
    856 				/*
    857 				**	If facing a diagonal we must check the next 90 degree location
    858 				**	to make sure that we don't walk right by the destination. This
    859 				**	will happen if the destination it is at the corner edge of an
    860 				**	impassable that we are moving around.
    861 				*/
    862 				if (newdir & FACING_NE) {
    863 					CELL	checkcell;		// Non-diagonal check cell.
    864 					//int	x,y;
    865 
    866 					checkcell = Adjacent_Cell(oldcell, Next_Direction(newdir, search));
    867 
    868 					if (checkcell == target) {
    869 
    870 						/*
    871 						**	This only works if in fact, it is possible to move to the
    872 						**	cell from the current location.
    873 						*/
    874 						cost = Passable_Cell(checkcell, Next_Direction(newdir, search), threat, threshhold);
    875 						if (cost) {
    876 							/*
    877 							**	YES! The destination is at the corner of an impassable, so
    878 							**	set the direction to point directly at it and then the
    879 							**	scanning will terminate later.
    880 							*/
    881 							newdir = Next_Direction(newdir, search);
    882 							newcell = Adjacent_Cell(oldcell, newdir);
    883 							break;
    884 						}
    885 					}
    886 
    887 					/*
    888 					**	Perform special diagonal check. If the edge follower would cross the
    889 					**	diagonal or fall on the diagonal line from the source, then consider
    890 					**	that cell impassible. Otherwise, the find path algorithm will fail
    891 					**	when there are two impassible locations located on a diagonal
    892 					**	that is lined up between the source and destination location.
    893 					**
    894 					** P.S. It might help if you check the right cell rather than using
    895 					**      the value that just happened to be in checkcell.
    896 					*/
    897 
    898 					checkcell = Adjacent_Cell(oldcell, newdir);
    899 
    900 					int checkx		= Cell_X(checkcell);
    901 					int checky		= Cell_Y(checkcell);
    902 					int checkval	= Point_Relative_To_Line(checkx, checky, startx, starty, targetx, targety);
    903 					if (checkval && !online) {
    904 						forcefail = ((checkval ^ oldval) < 0);
    905 					} else {
    906 			 			forcefail = false;
    907 					}
    908 					/*
    909 					** The only exception to the above is when we are directly backtracking
    910 					** because we could be trying to escape from a culdesack!
    911 					*/
    912 					if (forcefail && path->Length > 0 && (FacingType)(newdir ^ 4) == path->Command[path->Length - 1]) {
    913 						forcefail = false;
    914 					}
    915 				}
    916 
    917 			#else
    918 				newdir = Next_Direction(newdir, search*2);
    919 			#endif
    920 
    921 			/*
    922 			**	If we have just checked the same heading we started with,
    923 			**	we are surrounded by impassable characters and we exit.
    924 			*/
    925 			if (newdir == olddir) {
    926 				return(false);
    927 			}
    928 
    929 			/*
    930 			**	Get the new cell.
    931 			*/
    932 			newcell = Adjacent_Cell(oldcell, newdir);
    933 
    934 			/*
    935 			**	If we found a passable position, this is where we should move.
    936 			*/
    937 			if (!forcefail && ((cost = Passable_Cell(newcell, newdir, threat, threshhold)) != 0)) {
    938 				break;
    939 			} else {
    940 				if (newcell == target) {
    941 					forceout = true;
    942 					break;
    943 				}
    944 			}
    945 
    946 		}
    947 
    948 		/*
    949 		**	Record the direction.
    950 		*/
    951 		if (!forceout) {
    952 			/*
    953 			** Mark the cell because this is where we need to be.  If register
    954 			** cell fails then the list has been shortened and we need to adjust
    955 			** the new direction.
    956 			*/
    957 			if (!Register_Cell(path, newcell, newdir, cost, threshhold)) {
    958 				/*
    959 				** The only reason we could not register a cell is that we are in
    960 				** a looping situation.  So we need to try and unravel the loop if
    961 				** we can.
    962 				*/
    963 				if (!Unravel_Loop(path, newcell, newdir, startx, starty, targetx, targety, threshhold)) {
    964 					return(false);
    965 				}
    966 				/*
    967 				** Since we need to eliminate a diagonal we must pretend the upon
    968 				** attaining this square, we were moving turned further in the
    969 				** search direction then we really were.
    970 				*/
    971 				newdir = Next_Direction(newdir, (FacingType)(search*2));
    972 			}
    973 			/*
    974 			** Find out which side of the line this cell is on.  If it is on
    975 			** a side, then store off that side.
    976 			*/
    977 			int newx	= Cell_X(newcell);
    978 			int newy	= Cell_Y(newcell);
    979 			int val	= Point_Relative_To_Line(newx, newy, startx, starty, targetx, targety);
    980 			if (val) {
    981 				oldval = val;
    982 				online = false;
    983 			} else {
    984 				online = true;
    985 			}
    986 			cellcount++;
    987 			if (cellcount == MAX_PATH_EDGE_FOLLOW) {
    988 				return(false);
    989 			}
    990 		}
    991 
    992 		/*
    993 		**	If we have found the target spot, we are done.
    994 		*/
    995 		if (newcell == target) {
    996 			path->Command[path->Length] = END;
    997 			return(true);
    998 		}
    999 
   1000 		/*
   1001 		**	If we make a full circle back to our original spot, get out.
   1002 		*/
   1003 		if (newcell == firstcell && newdir == firstdir) {
   1004 			return(false);
   1005 		}
   1006 
   1007 		if (firstcell == -1) {
   1008 			firstcell = newcell;
   1009 			firstdir  = newdir;
   1010 		}
   1011 
   1012 		/*
   1013 		**	Because we moved, our facing is now incorrect. We want to face toward
   1014 		**	the impassable edge we are following (well, not actually toward, but
   1015 		**	a little past so that we can turn corners). We have to turn 45/90 degrees
   1016 		**	more than expected in anticipation of the pending 45/90 degree turn at
   1017 		**	the start of this loop.
   1018 		*/
   1019 		#ifdef DIAGONAL
   1020 			olddir = Next_Direction(newdir, (FacingType)(-(int)search*3));
   1021 		#else
   1022 			olddir = Next_Direction(newdir, (FacingType)(-(int)search*4));
   1023 		#endif
   1024 		oldcell = newcell;
   1025 	}
   1026 
   1027 	/*
   1028 	**	The maximum search path is exhausted... abort with a failure.
   1029 	*/
   1030 	return(false);
   1031 }
   1032 
   1033 
   1034 /***********************************************************************************************
   1035  * Optimize_Moves -- Optimize the move list.                                                   *
   1036  *                                                                                             *
   1037  * INPUT:      char *moves to optimize                                                         *
   1038  *                                                                                             *
   1039  * OUTPUT:     none (list is optimized)                                                        *
   1040  *                                                                                             *
   1041  * WARNINGS:   EMPTY moves are used to hold the place of eliminated                            *
   1042  *             commands. Also, NEVER call this routine with a list that                        *
   1043  *             contains illegal commands. The list MUST be terminated                          *
   1044  *             with a EOL command                                                              *
   1045  *                                                                                             *
   1046  * HISTORY:                                                                                    *
   1047  *   07/08/1991  CY : Created.                                                                 *
   1048  *   06/01/1992  JLB : Optimized and commented.                                                *
   1049  *=============================================================================================*/
   1050 #define	EMPTY		(FacingType)-2
   1051 int FootClass::Optimize_Moves(PathType * path, MoveType threshhold)
   1052 //int Optimize_Moves(PathType *path, int (*callback)(CELL, FacingType), int threshold)
   1053 {
   1054 	/*
   1055 	**	Facing command pair adjustment table. Compare the facing difference between
   1056 	**	the two commands. 0 means no optimization is possible. 3 means backtracking
   1057 	**	so eliminate both commands. Any other value adjusts the first command facing.
   1058 	*/
   1059 #ifdef DIAGONAL
   1060 	static FacingType _trans[FACING_COUNT] = {(FacingType)0, (FacingType)0, (FacingType)1, (FacingType)2, (FacingType)3, (FacingType)-2, (FacingType)-1, (FacingType)0};	// Smoothing.
   1061 #else
   1062 	static FacingType _trans[FACING_COUNT] = {(FacingType)0, (FacingType)0, (FacingType)0, (FacingType)2, (FacingType)3, (FacingType)-2, (FacingType)0, (FacingType)0};
   1063 #endif
   1064 	FacingType	* cmd1,		// Floating first command pointer.
   1065 					* cmd2,		// Floating second command pointer.
   1066 					newcmd;		// Calculated new optimized command.
   1067 	FacingType	newdir;		// Tentative new direction for smoothing.
   1068 	CELL			cell;			// Working cell (as it moves along path).
   1069 
   1070 	/*
   1071 	**	Abort if there is any illegal parameter.
   1072 	*/
   1073 	if (!path || !path->Command) return(0);
   1074 
   1075 	/*
   1076 	**	Optimization loop -- start scanning with the
   1077 	**	first pair of commands (if there are at least two
   1078 	**	in the command list).
   1079 	*/
   1080 	path->Command[path->Length] = END;		// Force end of list.
   1081 
   1082 	if (path->Length == 0) return(0);
   1083 
   1084 	cell = path->Start;
   1085 	if (path->Length > 1) {
   1086 		cmd2 = path->Command + 1;
   1087 		while (*cmd2 != END) {
   1088 
   1089 			/*
   1090 			**	Set the cmd1 pointer to point to the valid command closest, but
   1091 			**	previous to cmd2. Be sure not to go previous to the head of the
   1092 			**	command list.
   1093 			*/
   1094 			cmd1 = cmd2-1;
   1095 			while (*cmd1 == EMPTY && cmd1 != path->Command) {
   1096 				cmd1--;
   1097 			}
   1098 
   1099 			/*
   1100 			**	If there isn't any valid previous command, then bump the
   1101 			**	cmd pointers to the next command pair and continue...
   1102 			*/
   1103 			if (*cmd1 == EMPTY) {
   1104 				cmd2++;
   1105 				continue;
   1106 			}
   1107 
   1108 			/*
   1109 			**	Fetch precalculated command change value. 0 means leave
   1110 			**	command set alone, 3 means backtrack and eliminate two
   1111 			**	commands. Any other value is new direction and eliminate
   1112 			**	one command.
   1113 			*/
   1114 			newcmd = (FacingType)(*cmd2 - *cmd1);
   1115 			if (newcmd < FACING_N) newcmd = (FacingType)(newcmd + FACING_COUNT);
   1116 			newcmd = _trans[newcmd];
   1117 
   1118 			/*
   1119 			**	Check for backtracking. If this occurs, then eliminate the
   1120 			**	two commands. This is the easiest optimization.
   1121 			*/
   1122 			if (newcmd == FACING_SE) {
   1123 				*cmd1 = EMPTY;
   1124 				*cmd2++ = EMPTY;
   1125 				continue;
   1126 			}
   1127 
   1128 			/*
   1129 			**	If an optimization code was found the process it. The command is a facing
   1130 			**	offset to more directly travel toward the immediate destination cell.
   1131 			*/
   1132 			if (newcmd) {
   1133 
   1134 				/*
   1135 				**	Optimizations differ when dealing with diagonals. Especially when dealing
   1136 				**	with diagonals of 90 degrees. In such a case, 90 degree optimizations can
   1137 				**	only be optimized if the intervening cell is passable. The distance travelled
   1138 				**	is the same, but the path is less circuitous.
   1139 				*/
   1140 				if (*cmd1 & FACING_NE) {
   1141 
   1142 					/*
   1143 					**	Diagonal optimizations are always only 45
   1144 					**	degree adjustments.
   1145 					*/
   1146 					newdir = Next_Direction(*cmd1, (newcmd < FACING_N) ? (FacingType)-1 : (FacingType)1);
   1147 
   1148 					/*
   1149 					**	Diagonal 90 degree changes can be smoothed, although
   1150 					**	the path isn't any shorter.
   1151 					*/
   1152 					if (ABS((int)newcmd) == 1) {
   1153 						if (Passable_Cell(Adjacent_Cell(cell, newdir), newdir, -1, threshhold)) {
   1154 							*cmd2 = newdir;
   1155 							*cmd1 = newdir;
   1156 						}
   1157 						// BOB 16.12.92
   1158 						cell = Adjacent_Cell(cell, *cmd1);
   1159 						cmd2++;
   1160 						continue;
   1161 					}
   1162 				} else {
   1163 					newdir = Next_Direction(*cmd1, newcmd);
   1164 				}
   1165 
   1166 				/*
   1167 				**	Allow shortening turn only on right angle moves that are based on
   1168 				**	90 degrees. Always allow 135 degree optimizations.
   1169 				*/
   1170 				*cmd2 = newdir;
   1171 				*cmd1 = EMPTY;
   1172 
   1173 				/*
   1174 				**	Backup what it thinks is the current cell.
   1175 				*/
   1176 				while (*cmd1 == EMPTY && cmd1 != path->Command) {
   1177 					cmd1--;
   1178 				}
   1179 				if (*cmd1 != EMPTY) {
   1180 					cell = Adjacent_Cell(cell, Next_Direction(*cmd1, FACING_S));
   1181 				} else {
   1182 					cell = path->Start;
   1183 				}
   1184 				continue;
   1185 			}
   1186 
   1187 			/*
   1188 			**	Since we could not make an optimization, we move our
   1189 			**	head pointer forward.
   1190 			*/
   1191 			cell = Adjacent_Cell(cell, *cmd1);
   1192 			cmd2++;
   1193 		}
   1194 	}
   1195 
   1196 	/*
   1197 	**	Pack the command list to remove any EMPTY command entries.
   1198 	*/
   1199 	cmd1 = path->Command;
   1200 	cmd2 = path->Command;
   1201 	cell = path->Start;
   1202 	path->Cost = 0;
   1203 	path->Length = 0;
   1204 	while (*cmd2 != END) {
   1205 		if (*cmd2 != EMPTY) {
   1206 			cell = Adjacent_Cell(cell, *cmd2);
   1207 			path->Cost+= Passable_Cell(cell, *cmd2, -1, threshhold);
   1208 			path->Length++;
   1209 			*cmd1++ = *cmd2;
   1210 		}
   1211 		cmd2++;
   1212 	}
   1213 	path->Length++;
   1214 	*cmd1 = END;
   1215 	return(path->Length);
   1216 }
   1217 
   1218 
   1219 CELL FootClass::Safety_Point(CELL src, CELL dst, int start, int max)
   1220 {
   1221 	FacingType dir;
   1222 	CELL		  next;
   1223 	int 		  lp;
   1224 
   1225 	dir = (FacingType)(CELL_FACING(src, dst) ^ 4) - 1;
   1226 
   1227 	/*
   1228 	** Loop through the different acceptable distances.
   1229 	*/
   1230 	for (int dist = start; dist < max; dist ++) {
   1231 
   1232 		/*
   1233 		** Move to the starting location.
   1234 		*/
   1235 		next = dst;
   1236 
   1237 		for (lp = 0; lp < dist; lp ++) {
   1238 			next = Adjacent_Cell(next, dir);
   1239 		}
   1240 
   1241 		if (dir & 1) {
   1242 			/*
   1243 			** If our direction is diagonal than we need to check
   1244 			** only one side which is as long as both of the old sides
   1245 			** together.
   1246 			*/
   1247 			for (lp = 0; lp < dist << 1; lp ++) {
   1248 				next = Adjacent_Cell(next, dir + 3);
   1249 				if (!Can_Enter_Cell(next)) {
   1250 					return(next);
   1251 				}
   1252 			}
   1253 		} else {
   1254 			/*
   1255 			** If our direction is not diagonal than we need to check two
   1256 			** sides so that we are checking a corner like location.
   1257 			*/
   1258 			for (lp = 0; lp < dist; lp ++) {
   1259 				next = Adjacent_Cell(next, dir + 2);
   1260 				if (!Can_Enter_Cell(next)) {
   1261 					return(next);
   1262 				}
   1263 			}
   1264 
   1265 			for (lp = 0; lp < dist; lp ++) {
   1266 				next = Adjacent_Cell(next, dir + 4);
   1267 				if (!Can_Enter_Cell(next)) {
   1268 					return(next);
   1269 				}
   1270 			}
   1271 		}
   1272 	}
   1273 	return(-1);
   1274 }
   1275 
   1276 
   1277 
   1278 
   1279 int FootClass::Passable_Cell(CELL cell, FacingType face, int threat, MoveType threshhold)
   1280 {
   1281 	MoveType move = Can_Enter_Cell(cell, face);
   1282 
   1283 	if (move < MOVE_MOVING_BLOCK && Distance(Cell_Coord(cell)) > 0x0100) threshhold = MOVE_MOVING_BLOCK;
   1284 
   1285 	if (move > threshhold) return(0);
   1286 
   1287 	if (Session.Type == GAME_NORMAL) {
   1288 		if (threat != -1) {
   1289 			if (::Distance(Cell_Coord(cell), Cell_Coord(DestLocation)) > (THREAT_THRESHOLD * CELL_LEPTON_W)) {
   1290 //			if (Map.Cell_Distance(cell, DestLocation) > THREAT_THRESHOLD) {
   1291 				if (Map.Cell_Threat(cell, Owner()) > threat)
   1292 					return(0);
   1293 			}
   1294 		}
   1295 	}
   1296 
   1297 	static int _value[MOVE_COUNT] = {
   1298 		1,			//	MOVE_OK
   1299 		1,			//	MOVE_CLOAK
   1300 		3,			//	MOVE_MOVING_BLOCK
   1301 		8,			//	MOVE_DESTROYABLE
   1302 		10,		//	MOVE_TEMP
   1303 		0			//	MOVE_NO
   1304 	};
   1305 	return(_value[move]);
   1306 }
   1307