CnC_Remastered_Collection

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

FOOT.CPP (128486B)


      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/FOOT.CPP 2     3/06/97 1:46p 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 : FOOT.CPP                                                     *
     24  *                                                                                             *
     25  *                   Programmer : Joe L. Bostic                                                *
     26  *                                                                                             *
     27  *                   Start Date : April 22, 1994                                               *
     28  *                                                                                             *
     29  *                  Last Update : October 5, 1996 [JLB]                                        *
     30  *                                                                                             *
     31  *---------------------------------------------------------------------------------------------*
     32  * Functions:                                                                                  *
     33  *   FootClass::AI -- Handle general movement AI.                                              *
     34  *   FootClass::Active_Click_With -- Initiates attack or move according to target clicked on.  *
     35  *   FootClass::Active_Click_With -- Performs action as a result of left mouse click.          *
     36  *   FootClass::Adjust_Dest -- Adjust candidate movement cell to account for formation.        *
     37  *   FootClass::Approach_Target -- Sets the navigation computer to approach target object.     *
     38  *   FootClass::Assign_Destination -- Assigns specified destination to NavCom.                 *
     39  *   FootClass::Basic_Path -- Finds the basic path for a ground object.                        *
     40  *   FootClass::Body_Facing -- Set the body rotation/facing.                                   *
     41  *   FootClass::Can_Demolish -- Checks to see if this object can be sold back.                 *
     42  *   FootClass::Can_Enter_Cell -- Checks to see if the object can enter cell specified.        *
     43  *   FootClass::Clear_Navigation_List -- Clears out the navigation queue.                      *
     44  *   FootClass::Death_Announcement -- Announces the death of a unit.                           *
     45  *   FootClass::Debug_Dump -- Displays the status of the FootClass to the mono monitor.        *
     46  *   FootClass::Detach -- Detaches a target from tracking systems.                             *
     47  *   FootClass::Detach_All -- Removes this object from the game system.                        *
     48  *   FootClass::Enters_Building -- When unit enters a building for some reason.                *
     49  *   FootClass::FootClass -- Normal constructor for the foot class object.                     *
     50  *   FootClass::Greatest_Threat -- Fetches the greatest threat to this object.                 *
     51  *   FootClass::Handle_Navigation_List -- Processes the navigation queue.                      *
     52  *   FootClass::Is_Allowed_To_Leave_Map -- Checks to see if it can leave the map and the game. *
     53  *   FootClass::Is_On_Priority_Mission -- Checks to see if this object should be given priority*
     54  *   FootClass::Is_Recruitable -- Determine if this object is recruitable as a team members.   *
     55  *   FootClass::Likely_Coord -- Fetches the coordinate the object will be at shortly.          *
     56  *   FootClass::Mark -- Unit interface to map rendering system.                                *
     57  *   FootClass::Mission_Attack -- AI for heading towards and firing upon target.               *
     58  *   FootClass::Mission_Capture -- Handles the capture mission.                                *
     59  *   FootClass::Mission_Enter -- Enter (cooperatively) mission handler.                        *
     60  *   FootClass::Mission_Guard_Area -- Causes unit to guard an area about twice weapon range.   *
     61  *   FootClass::Mission_Hunt -- Handles the default hunt order.                                *
     62  *   FootClass::Mission_Move -- AI process for moving a vehicle to its destination.            *
     63  *   FootClass::Mission_Retreat -- Handle reatreat from map mission for mobile objects.        *
     64  *   FootClass::Offload_Tiberium_Bail -- Fetches the Tiberium to offload per step.             *
     65  *   FootClass::Override_Mission -- temporarily overrides a units mission                      *
     66  *   FootClass::Per_Cell_Process -- Perform action based on once-per-cell condition.           *
     67  *   FootClass::Queue_Navigation_List -- Add a target to the objects navigation list.          *
     68  *   FootClass::Receive_Message -- Movement related radio messages are handled here.           *
     69  *   FootClass::Rescue_Mission -- Calls this unit to the rescue.                               *
     70  *   FootClass::Restore_Mission -- Restores an overridden mission                              *
     71  *   FootClass::Sell_Back -- Causes this object to be sold back.                               *
     72  *   FootClass::Set_Speed -- Initiate unit movement physics.                                   *
     73  *   FootClass::Sort_Y -- Determine the sort coordinate for foot class objects.                *
     74  *   FootClass::Start_Driver -- This starts the driver heading to the destination desired.     *
     75  *   FootClass::Stop_Driver -- This routine clears the driving state of the object.            *
     76  *   FootClass::Stun -- Prepares a ground travelling object for removal.                       *
     77  *   FootClass::Take_Damage -- Handles taking damage to this object.                           *
     78  *   FootClass::Unlimbo -- Unlimbos object and performs special fixups.                        *
     79  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     80 
     81 #include	"function.h"
     82 
     83 
     84 /***********************************************************************************************
     85  * FootClass::FootClass -- Default constructor for foot class objects.                         *
     86  *                                                                                             *
     87  *    This is the default constructor for FootClass objects. It sets the foot class values to  *
     88  *    their default starting settings.                                                         *
     89  *                                                                                             *
     90  * INPUT:   none                                                                               *
     91  *                                                                                             *
     92  * OUTPUT:  none                                                                               *
     93  *                                                                                             *
     94  * WARNINGS:   none                                                                            *
     95  *                                                                                             *
     96  * HISTORY:                                                                                    *
     97  *   11/23/1994 JLB : Created.                                                                 *
     98  *=============================================================================================*/
     99 FootClass::FootClass(RTTIType rtti, int id, HousesType house) :
    100 	TechnoClass(rtti, id, house),
    101 	IsScanLimited(false),
    102 	IsInitiated(false),
    103 	IsNewNavCom(false),
    104 	IsPlanningToLook(false),
    105 	IsDeploying(false),
    106 	IsFiring(false),
    107 	IsRotating(false),
    108 	IsDriving(false),
    109 	IsUnloading(false),
    110 	IsFormationMove(false),
    111 	IsNavQueueLoop(false),
    112 	IsScattering(false),
    113 	IsMovingOntoBridge(false),
    114 	Speed(0),
    115 	SpeedBias(1),
    116 	XFormOffset(0x80000000),
    117 	YFormOffset(0x80000000),
    118 	NavCom(TARGET_NONE),
    119 	SuspendedNavCom(TARGET_NONE),
    120 	Team(0),
    121 	Group(255),
    122 	Member(0),
    123 	PathThreshhold(MOVE_CLOAK),
    124 	PathDelay(0),
    125 	TryTryAgain(PATH_RETRY),
    126 	BaseAttackTimer(0),
    127 	FormationSpeed(SPEED_FOOT),
    128 	FormationMaxSpeed(MPH_IMMOBILE),
    129 	HeadToCoord(0)
    130 {
    131 	Path[0] = FACING_NONE;
    132 	for (int index = 0; index < ARRAY_SIZE(NavQueue); index++) {
    133 		NavQueue[index] = TARGET_NONE;
    134 	}
    135 }
    136 
    137 
    138 #ifdef CHEAT_KEYS
    139 /***********************************************************************************************
    140  * FootClass::Debug_Dump -- Displays the status of the FootClass to the mono monitor.          *
    141  *                                                                                             *
    142  *    This routine is used to output the current status of the foot class to the mono          *
    143  *    monitor. Through this display bugs may be tracked down or eliminated.                    *
    144  *                                                                                             *
    145  * INPUT:   none                                                                               *
    146  *                                                                                             *
    147  * OUTPUT:  none                                                                               *
    148  *                                                                                             *
    149  * WARNINGS:   none                                                                            *
    150  *                                                                                             *
    151  * HISTORY:                                                                                    *
    152  *   06/02/1994 JLB : Created.                                                                 *
    153  *   07/04/1995 JLB : Handles aircraft special case.                                           *
    154  *=============================================================================================*/
    155 void FootClass::Debug_Dump(MonoClass * mono) const
    156 {
    157 	assert(IsActive);
    158 
    159 	mono->Fill_Attrib(53, 13, 12, 1, IsInitiated ? MonoClass::INVERSE : MonoClass::NORMAL);
    160 	mono->Fill_Attrib(1, 18, 12, 1, IsPlanningToLook ? MonoClass::INVERSE : MonoClass::NORMAL);
    161 	mono->Fill_Attrib(53, 14, 12, 1, IsDeploying ? MonoClass::INVERSE : MonoClass::NORMAL);
    162 	mono->Fill_Attrib(53, 15, 12, 1, IsFiring ? MonoClass::INVERSE : MonoClass::NORMAL);
    163 	mono->Fill_Attrib(53, 16, 12, 1, IsRotating ? MonoClass::INVERSE : MonoClass::NORMAL);
    164 	mono->Fill_Attrib(53, 17, 12, 1, IsDriving ? MonoClass::INVERSE : MonoClass::NORMAL);
    165 	mono->Fill_Attrib(53, 18, 12, 1, IsUnloading ? MonoClass::INVERSE : MonoClass::NORMAL);
    166 	mono->Fill_Attrib(27, 18, 12, 1, IsFormationMove ? MonoClass::INVERSE : MonoClass::NORMAL);
    167 
    168 	mono->Set_Cursor(45, 1);mono->Printf("%02X", Speed);
    169 	if (NavCom) {
    170 		mono->Set_Cursor(29, 5);
    171 		mono->Printf("%08X", NavCom);
    172 	}
    173 	if (SuspendedNavCom) {
    174 		mono->Set_Cursor(38, 5);
    175 		mono->Printf("%08X", SuspendedNavCom);
    176 	}
    177 
    178 	if (Team) Team->Debug_Dump(mono);
    179 	if (Group != 255) {
    180 		mono->Set_Cursor(59, 1);mono->Printf("%d", Group);
    181 	}
    182 
    183 	static char	const * _p2c[9] = {"-","0","1","2","3","4","5","6","7"};
    184 	for (int index = 0; index < min(12, ARRAY_SIZE(Path)); index++) {
    185 		mono->Set_Cursor(54+index, 3);
    186 		mono->Printf("%s", _p2c[((ABS((int)Path[index]+1)) % ARRAY_SIZE(_p2c))]);
    187 	}
    188 	mono->Set_Cursor(54, 5);mono->Printf("%2d", PathThreshhold);
    189 	mono->Set_Cursor(72, 3);mono->Printf("%4d", (long)PathDelay);
    190 	mono->Set_Cursor(67, 3);mono->Printf("%3d", TryTryAgain);
    191 	if (HeadToCoord) {
    192 		mono->Set_Cursor(60, 5);mono->Printf("%08X", HeadToCoord);
    193 	}
    194 
    195 	TechnoClass::Debug_Dump(mono);
    196 }
    197 #endif
    198 
    199 
    200 /***********************************************************************************************
    201  * FootClass::Set_Speed -- Initiate unit movement physics.                                     *
    202  *                                                                                             *
    203  *    This routine is used to set a unit's velocity control structure.                         *
    204  *    The game will then process the unit's movement during the momentum                       *
    205  *    physics calculation.                                                                     *
    206  *                                                                                             *
    207  * INPUT:   unit  -- Pointer to the unit to alter.                                             *
    208  *                                                                                             *
    209  *          speed -- Throttle setting (0=stop, 255=full throttle).                             *
    210  *                                                                                             *
    211  * OUTPUT:  none                                                                               *
    212  *                                                                                             *
    213  * WARNINGS:   none                                                                            *
    214  *                                                                                             *
    215  * HISTORY:                                                                                    *
    216  *   09/07/1992 JLB : Created.                                                                 *
    217  *   09/24/1993 JLB : Revised for faster speed.                                                *
    218  *   04/02/1994 JLB : Revised for new system.                                                  *
    219  *   04/15/1994 JLB : Converted to member function.                                            *
    220  *   07/21/1994 JLB : Simplified.                                                              *
    221  *=============================================================================================*/
    222 void FootClass::Set_Speed(int speed)
    223 {
    224 	assert(IsActive);
    225 
    226 	speed &= 0xFF;
    227 	((unsigned char &)Speed) = speed;
    228 }
    229 
    230 
    231 /***********************************************************************************************
    232  * FootClass::Mark -- Unit interface to map rendering system.                                  *
    233  *                                                                                             *
    234  *    This routine is the interface function for units as they relate to                       *
    235  *    the map rendering system. Whenever a unit's imagery changes, this                        *
    236  *    function is called.                                                                      *
    237  *                                                                                             *
    238  * INPUT:   mark  -- Type of image change (MARK_UP, _DOWN, _CHANGE)                            *
    239  *             MARK_UP  -- Unit is removed.                                                    *
    240  *             MARK_CHANGE -- Unit alters image but doesn't move.                              *
    241  *             MARK_DOWN -- Unit is overlaid onto existing icons.                              *
    242  *                                                                                             *
    243  * OUTPUT:  bool; Did the marking operation succeed? Failure could be the result of marking    *
    244  *                down when it is already down, or visa versa.                                 *
    245  *                                                                                             *
    246  * WARNINGS:   none                                                                            *
    247  *                                                                                             *
    248  * HISTORY:                                                                                    *
    249  *   09/14/1991 JLB : Created.                                                                 *
    250  *   04/15/1994 JLB : Converted to member function.                                            *
    251  *   12/23/1994 JLB : Performs low level check before processing.                              *
    252  *=============================================================================================*/
    253 bool FootClass::Mark(MarkType mark)
    254 {
    255 	assert(this != 0);
    256 	assert(IsActive);
    257 
    258 	if (TechnoClass::Mark(mark)) {
    259 //		short list[32];
    260 		CELL cell = Coord_Cell(Coord);
    261 
    262 #ifndef PARTIAL
    263 		if (In_Which_Layer() != LAYER_GROUND && (mark == MARK_UP || mark == MARK_DOWN)) mark = MARK_CHANGE;
    264 #endif
    265 
    266 		/*
    267 		**	Inform the map of the refresh, occupation, and overlap
    268 		**	request.
    269 		*/
    270 		switch (mark) {
    271 			case MARK_UP:
    272 				Map.Pick_Up(cell, this);
    273 				break;
    274 
    275 			case MARK_DOWN:
    276 				Map.Place_Down(cell, this);
    277 				break;
    278 
    279 			case MARK_CHANGE_REDRAW:
    280 				Map.Refresh_Cells(cell, Overlap_List(true));
    281 				Map.Refresh_Cells(cell, Occupy_List());
    282 				break;
    283 
    284 			default:
    285 				Map.Refresh_Cells(cell, Overlap_List());
    286 				Map.Refresh_Cells(cell, Occupy_List());
    287 				break;
    288 		}
    289 		return(true);
    290 	}
    291 	return(false);
    292 }
    293 
    294 
    295 /***********************************************************************************************
    296  * FootClass::Basic_Path -- Finds the basic path for a ground object.                          *
    297  *                                                                                             *
    298  *    This is a common routine used by both infantry and other ground travelling units. It     *
    299  *    will fill in the unit's basic path to the NavCom destination.                            *
    300  *                                                                                             *
    301  * INPUT:   none                                                                               *
    302  *                                                                                             *
    303  * OUTPUT:  bool; Was a path found? A failure to find a path means either the target cannot    *
    304  *                be found or the terrain prohibits the unit's movement.                       *
    305  *                                                                                             *
    306  * WARNINGS:   none                                                                            *
    307  *                                                                                             *
    308  * HISTORY:                                                                                    *
    309  *   10/17/1994 JLB : Created.                                                                 *
    310  *=============================================================================================*/
    311 bool FootClass::Basic_Path(void)
    312 {
    313 	assert(IsActive);
    314 
    315 	PathType		* path;			// Pointer to path control structure.
    316 	CELL			cell;
    317 	int 			skip_path = false;
    318 
    319 	Path[0] = FACING_NONE;
    320 
    321 	if (Target_Legal(NavCom)) {
    322 		cell = As_Cell(NavCom);
    323 
    324 		/*
    325 		**	When the navigation computer is set to a location that is impassible, then
    326 		**	find a nearby cell that can be entered and try to head toward that instead.
    327 		**	EXCEPT when that cell is very close -- then just bail.
    328 		*/
    329 		int dist = Distance(NavCom);
    330 		int checkdist = Team.Is_Valid() ? Rule.StrayDistance : Rule.CloseEnoughDistance;
    331 		if (Can_Enter_Cell(cell) > MOVE_CLOAK && dist > checkdist) {
    332 			CELL cell2 = Map.Nearby_Location(cell, Techno_Type_Class()->Speed, Map[Coord].Zones[Techno_Type_Class()->MZone], Techno_Type_Class()->MZone);
    333 			if (cell2 != 0 && ::Distance(Cell_Coord(cell), Cell_Coord(cell2)) < dist) cell = cell2;
    334 		}
    335 
    336 		if (What_Am_I() == RTTI_INFANTRY) {
    337 			CELL mycell = Coord_Cell(Center_Coord());
    338 			ObjectClass * obj = Map[mycell].Cell_Occupier();
    339 			while (obj) {
    340 				if (obj != this && obj->What_Am_I() == RTTI_INFANTRY) {
    341 					InfantryClass * inf = (InfantryClass *)obj;
    342 					if (inf->NavCom == NavCom && inf->Path[0] != FACING_NONE) {
    343 						if (Coord_Cell(inf->Head_To_Coord()) == Coord_Cell(inf->Coord)) {
    344 							Mem_Copy(&inf->Path[1], Path, sizeof(Path)-sizeof(Path[0]));
    345 						} else {
    346 							Mem_Copy(inf->Path, Path, sizeof(Path));
    347 						}
    348 						if (Path[0] != FACING_NONE) {
    349 							skip_path = true;
    350 						}
    351 						break;
    352 					}
    353 				}
    354 				obj = obj->Next;
    355 			}
    356 		}
    357 
    358 		if (!skip_path) {
    359 			Mark(MARK_UP);
    360 			Path[0] = FACING_NONE;		// Probably not necessary, but...
    361 
    362 			/*
    363 			**	Try to find a path to the destination. If a failure occurs, then keep trying
    364 			**	with greater determination until either a complete failure occurs, or a decent
    365 			**	path was found.
    366 			*/
    367 			bool			found1=false;		// Found a best path yet?
    368 			PathType	   path1;
    369 			FacingType	workpath1[200];	// Staging area for path list.
    370 //			FacingType	workpath2[200];	// Staging area for path list.
    371 			MoveType		maxtype = MOVE_TEMP;
    372 			if (!House->IsHuman) {
    373 				maxtype = MOVE_TEMP;
    374 //				maxtype = MOVE_DESTROYABLE;
    375 			} else {
    376 
    377 				/*
    378 				**	For simple movement missions by the human player, then don't
    379 				**	consider friendly units as passable if close to the destination.
    380 				**	This will prevent a human controlled unit from just sitting next
    381 				**	to a destination just because there is another friendly unit
    382 				**	occupying the destination location.
    383 				*/
    384 				if (Mission == MISSION_MOVE && Distance(NavCom) < Rule.CloseEnoughDistance) {
    385 					maxtype = MOVE_DESTROYABLE;
    386 				}
    387 			}
    388 
    389 			/*
    390 			**	Try to find a path to the destination. If there is a path
    391 			**	failure, then try a more severe path method until the
    392 			**	maximum severity is reached.
    393 			*/
    394 			for (;;) {
    395 				path = Find_Path(cell, &workpath1[0], sizeof(workpath1), PathThreshhold);
    396 				if (path && path->Cost) {
    397 					memcpy(&path1, path, sizeof(path1));
    398 					found1 = true;
    399 					break;
    400 				}
    401 
    402 				/*
    403 				**	A valid path was not found. Try the next greater path severity
    404 				**	level if the severity can be increased. If not, then consider this
    405 				**	a total failure.
    406 				*/
    407 				PathThreshhold++;
    408 				if (PathThreshhold > maxtype) break;
    409 			}
    410 
    411 #ifdef NEVER
    412 			/*
    413 			**	Determine if ANY path could be calculated by first examining the most
    414 			**	aggressive case. If this fails, then no path will succeed. Further
    415 			**	scanning is unnecessary.
    416 			*/
    417 			path = Find_Path(cell, &workpath1[0], sizeof(workpath1), maxtype);
    418 			if (path && path->Cost) {
    419 				memcpy(&path1, path, sizeof(path1));
    420 				found1 = true;
    421 
    422 				/*
    423 				**	Scan for the best path possible. If this succeeds, then do a simple
    424 				**	comparison with the most aggressive path. If they are very close, then
    425 				**	go with the best (easiest) path method.
    426 				*/
    427 				path = Find_Path(cell, &workpath2[0], sizeof(workpath2), MOVE_CLOAK);
    428 				if (path && path->Cost && path->Cost < max((path1.Cost + (path1.Cost/2)), 3)) {
    429 					memcpy(&path1, path, sizeof(path1));
    430 					memcpy(workpath1, workpath2, sizeof(workpath1));
    431 				} else {
    432 
    433 					/*
    434 					**	The easiest path method didn't result in a satisfactory path. Scan through
    435 					**	the rest of the path options, looking for the best one.
    436 					*/
    437 					for (MoveType move = (MoveType)(MOVE_CLOAK+1); move < (MoveType)(maxtype-1); move++) {
    438 //					for (MoveType move = MOVE_MOVING_BLOCK; move < maxtype-1; move++) {
    439 						path = Find_Path(cell, &workpath2[0], sizeof(workpath2), move);
    440 						if (path && path->Cost && path->Cost < max((path1.Cost + (path1.Cost/2)), 3)) {
    441 							memcpy(&path1, path, sizeof(path1));
    442 							memcpy(workpath1, workpath2, sizeof(workpath1));
    443 						}
    444 					}
    445 				}
    446 			}
    447 #endif
    448 
    449 			/*
    450 			**	If a good path was found, then record it in the object's path
    451 			**	list.
    452 			*/
    453 			if (found1) {
    454 				Fixup_Path(&path1);
    455 				memcpy(&Path[0], &workpath1[0], min(path->Length, (int)sizeof(Path)));
    456 			}
    457 
    458 			Mark(MARK_DOWN);
    459 		}
    460 
    461 		PathDelay = Rule.PathDelay * TICKS_PER_MINUTE;
    462 		if (Path[0] != FACING_NONE) return(true);
    463 
    464 		/*
    465 		**	If a basic path couldn't be determined, then abort the navigation process.
    466 		*/
    467 		Stop_Driver();
    468 	}
    469 	return(false);
    470 }
    471 
    472 
    473 /***********************************************************************************************
    474  * FootClass::Mission_Move -- AI process for moving a vehicle to its destination.              *
    475  *                                                                                             *
    476  *    This simple AI script handles moving the vehicle to its desired destination. Since       *
    477  *    simple movement is handled directly by the engine, this routine merely waits until       *
    478  *    the unit has reached its destination, and then causes the unit to enter idle mode.       *
    479  *                                                                                             *
    480  * INPUT:   none                                                                               *
    481  *                                                                                             *
    482  * OUTPUT:  Returns with the delay before calling this routine again.                          *
    483  *                                                                                             *
    484  * WARNINGS:   none                                                                            *
    485  *                                                                                             *
    486  * HISTORY:                                                                                    *
    487  *   07/18/1994 JLB : Created.                                                                 *
    488  *   10/02/1996 JLB : Player controlled or human owned units don't scan for targets.           *
    489  *=============================================================================================*/
    490 int FootClass::Mission_Move(void)
    491 {
    492 	assert(IsActive);
    493 
    494 	if (!Target_Legal(NavCom) && !IsDriving && MissionQueue == MISSION_NONE) {
    495 		Enter_Idle_Mode();
    496 		return(1);
    497 	}
    498 //	if (!Target_Legal(TarCom) && !House->IsPlayerControl && !House->IsHuman) {
    499 	if (!Target_Legal(TarCom) && !House->IsPlayerControl && !House->IsHuman && (!Team.Is_Valid() || !Team->Class->IsSuicide)) {
    500 		Target_Something_Nearby(THREAT_RANGE);
    501 	}
    502 	return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
    503 }
    504 
    505 
    506 /***********************************************************************************************
    507  * FootClass::Mission_Capture -- Handles the capture mission.                                  *
    508  *                                                                                             *
    509  *    Capture missions are nearly the same as normal movement missions. The only difference    *
    510  *    is that the final destination is handled in a special way so that it is not marked as    *
    511  *    impassable. This allows the object (usually infantry) the ability to walk onto the       *
    512  *    object and thus capture it.                                                              *
    513  *                                                                                             *
    514  * INPUT:   none                                                                               *
    515  *                                                                                             *
    516  * OUTPUT:  Returns with the number of game ticks to delay before calling this routine.        *
    517  *                                                                                             *
    518  * WARNINGS:   none                                                                            *
    519  *                                                                                             *
    520  * HISTORY:                                                                                    *
    521  *   03/19/1995 JLB : Created.                                                                 *
    522  *=============================================================================================*/
    523 int FootClass::Mission_Capture(void)
    524 {
    525 	assert(IsActive);
    526 
    527 	/*
    528 	**	If there is a valid TarCom but the NavCom isn't set, then set the NavCom accordingly.
    529 	*/
    530 	if (Is_Target_Building(TarCom) && !Target_Legal(NavCom) && What_Am_I() == RTTI_INFANTRY && ((InfantryClass *)this)->Class->IsBomber) {
    531 		Assign_Destination(TarCom);
    532 	}
    533 
    534 	if (!Target_Legal(NavCom) /*&& !In_Radio_Contact()*/) {
    535 		Enter_Idle_Mode();
    536 		if (Map[Center_Coord()].Cell_Building()) {
    537 			Scatter(0, true);
    538 		}
    539 	}
    540 	return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
    541 }
    542 
    543 
    544 /***********************************************************************************************
    545  * FootClass::Mission_Attack -- AI for heading towards and firing upon target.                 *
    546  *                                                                                             *
    547  *    This AI routine handles heading to within range of the target and then firing upon       *
    548  *    it until it is destroyed. If the target is destroyed, then the unit will change          *
    549  *    missions to match its "idle mode" of operation (usually guarding).                       *
    550  *                                                                                             *
    551  * INPUT:   none                                                                               *
    552  *                                                                                             *
    553  * OUTPUT:  Returns with the delay before calling this routine again.                          *
    554  *                                                                                             *
    555  * WARNINGS:   none                                                                            *
    556  *                                                                                             *
    557  * HISTORY:                                                                                    *
    558  *   07/18/1994 JLB : Created.                                                                 *
    559  *=============================================================================================*/
    560 int FootClass::Mission_Attack(void)
    561 {
    562 	assert(IsActive);
    563 	if (Target_Legal(TarCom)) {
    564 		Approach_Target();
    565 	} else {
    566 		Enter_Idle_Mode();
    567 	}
    568 	return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
    569 }
    570 
    571 
    572 /***********************************************************************************************
    573  * FootClass::Mission_Guard -- Handles the AI for guarding in place.                           *
    574  *                                                                                             *
    575  *    Units that are performing stationary guard duty use this AI process. They will sit       *
    576  *    still and target any enemies that get within range.                                      *
    577  *                                                                                             *
    578  * INPUT:   none                                                                               *
    579  *                                                                                             *
    580  * OUTPUT:  Returns with the delay before calling this routine again.                          *
    581  *                                                                                             *
    582  * WARNINGS:   none                                                                            *
    583  *                                                                                             *
    584  * HISTORY:                                                                                    *
    585  *   07/18/1994 JLB : Created.                                                                 *
    586  *=============================================================================================*/
    587 int FootClass::Mission_Guard(void)
    588 {
    589 	assert(IsActive);
    590 
    591 	/*
    592 	**	If this unit is on an impassable cell for any reason, it needs to scatter immediately
    593 	*/
    594 	if (What_Am_I() == RTTI_INFANTRY || What_Am_I() == RTTI_UNIT) {
    595 		LandType land = Map[Coord].Land_Type();
    596 		if (!Target_Legal(NavCom) && (land == LAND_ROCK || land == LAND_WATER || land == LAND_RIVER)) {
    597 			Scatter(0, true, true);
    598 			Shorten_Mission_Timer();
    599 		}
    600 	}
    601 
    602 	if (!Target_Something_Nearby(THREAT_RANGE)) {
    603 		Random_Animate();
    604 	}
    605 
    606 	int dtime = MissionControl[Mission].Normal_Delay();
    607 	if (What_Am_I() == RTTI_VESSEL) {
    608 		switch (((VesselClass *)this)->Class->Type) {
    609 			case VESSEL_DD:
    610 			case VESSEL_PT:
    611 				dtime = MissionControl[Mission].AA_Delay();
    612 				break;
    613 
    614 			case VESSEL_CA:
    615 				dtime *= 2;
    616 				break;
    617 
    618 			default:
    619 				break;
    620 		}
    621 	}
    622 	if (What_Am_I() == RTTI_INFANTRY) {
    623 
    624 		/*
    625 		**	If this is a bomber type infantry and the current target is a building, then go into
    626 		**	sabotage mode if not already.
    627 		*/
    628 		if (!House->IsHuman && Is_Target_Building(TarCom) && ((InfantryClass *)this)->Class->IsBomber && Mission != MISSION_SABOTAGE) {
    629 			Assign_Mission(MISSION_SABOTAGE);
    630 		}
    631 
    632 		switch (((InfantryClass *)this)->Class->Type) {
    633 			case INFANTRY_E1:
    634 			case INFANTRY_E3:
    635 				dtime = MissionControl[Mission].AA_Delay();
    636 				break;
    637 
    638 			default:
    639 				break;
    640 		}
    641 	}
    642 
    643 	return((Arm != 0) ? (int)Arm : (dtime+Random_Pick(0, 2)));
    644 }
    645 
    646 
    647 /***********************************************************************************************
    648  * FootClass::Mission_Hunt -- Handles the default hunt order.                                  *
    649  *                                                                                             *
    650  *    This routine is the default hunt order for game objects. It handles searching for a      *
    651  *    nearby object and heading toward it. The act of targeting will cause it to attack        *
    652  *    the target it selects.                                                                   *
    653  *                                                                                             *
    654  * INPUT:   none                                                                               *
    655  *                                                                                             *
    656  * OUTPUT:  Returns the game tick delay before calling this routine again.                     *
    657  *                                                                                             *
    658  * WARNINGS:   none                                                                            *
    659  *                                                                                             *
    660  * HISTORY:                                                                                    *
    661  *   10/17/1994 JLB : Created.                                                                 *
    662  *=============================================================================================*/
    663 int FootClass::Mission_Hunt(void)
    664 {
    665 	assert(IsActive);
    666 	if (!Target_Something_Nearby(THREAT_NORMAL)) {
    667 #if(0)
    668 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
    669 	if (What_Am_I() == RTTI_INFANTRY && *(InfantryClass *)this == INFANTRY_GENERAL && House->Class->House==HOUSE_UKRAINE && Scen.Scenario==47) {
    670 		for(int index=0; index < Buildings.Count(); index++) {
    671 			if(Buildings.Ptr(index)->IsOwnedByPlayer) {
    672 				Assign_Target(Buildings.Ptr(index)->As_Target());
    673 				break;
    674 			}
    675 		}
    676 		for(index=0; index < Units.Count(); index++) {
    677 			if(Units.Ptr(index)->IsOwnedByPlayer) {
    678 				Assign_Target(Units.Ptr(index)->As_Target());
    679 				break;
    680 			}
    681 		}
    682 		for(index=0; index < Infantry.Count(); index++) {
    683 			if(Infantry.Ptr(index)->IsOwnedByPlayer) {
    684 				Assign_Target(Infantry.Ptr(index)->As_Target());
    685 				break;
    686 			}
    687 		}
    688 		for(index=0; index < Aircraft.Count(); index++) {
    689 			if(Aircraft.Ptr(index)->IsOwnedByPlayer) {
    690 				Assign_Target(Aircraft.Ptr(index)->As_Target());
    691 				break;
    692 			}
    693 		}
    694 	}
    695 #endif
    696 #endif
    697 		Random_Animate();
    698 	} else {
    699 		if (What_Am_I() == RTTI_INFANTRY && ( ((InfantryTypeClass const &)Class_Of()).Type == INFANTRY_RENOVATOR || ((InfantryTypeClass const &)Class_Of()).Type == INFANTRY_THIEF) ) {
    700 			Assign_Destination(TarCom);
    701 			Assign_Mission(MISSION_CAPTURE);
    702 		} else {
    703 			if (What_Am_I() == RTTI_INFANTRY && ((InfantryClass *)this)->Class->IsBomber && Is_Target_Building(TarCom)) {
    704 				Assign_Destination(TarCom);
    705 				Assign_Mission(MISSION_SABOTAGE);
    706 			} else {
    707 				Approach_Target();
    708 			}
    709 		}
    710 	}
    711 	return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
    712 }
    713 
    714 
    715 /***********************************************************************************************
    716  * FootClass::Stop_Driver -- This routine clears the driving state of the object.              *
    717  *                                                                                             *
    718  *    This is the counterpart routine to the Start_Driver function. It clears the driving      *
    719  *    status flags and destination coordinate record.                                          *
    720  *                                                                                             *
    721  * INPUT:   none                                                                               *
    722  *                                                                                             *
    723  * OUTPUT:  bool; Was driving stopped?                                                         *
    724  *                                                                                             *
    725  * WARNINGS:   none                                                                            *
    726  *                                                                                             *
    727  * HISTORY:                                                                                    *
    728  *   10/17/1994 JLB : Created.                                                                 *
    729  *   12/12/1994 JLB : Greatly simplified.                                                      *
    730  *=============================================================================================*/
    731 bool FootClass::Stop_Driver(void)
    732 {
    733 	assert(IsActive);
    734 
    735 	if (HeadToCoord) {
    736 		HeadToCoord = NULL;
    737 		Set_Speed(0);
    738 		IsDriving = false;
    739 		IsMovingOntoBridge = false;
    740 		return(true);
    741 	}
    742 	return(false);
    743 }
    744 
    745 
    746 /***********************************************************************************************
    747  * FootClass::Start_Driver -- This starts the driver heading to the destination desired.       *
    748  *                                                                                             *
    749  *    Before a unit can move it must be started by this routine. This routine handles          *
    750  *    reserving the cell and setting the driving flag.                                         *
    751  *                                                                                             *
    752  * INPUT:   headto   -- The coordinate of the immediate drive destination. This is one cell    *
    753  *                      away from the unit's current location.                                 *
    754  *                                                                                             *
    755  * OUTPUT:  bool; Was driving initiated?                                                       *
    756  *                                                                                             *
    757  * WARNINGS:   none                                                                            *
    758  *                                                                                             *
    759  * HISTORY:                                                                                    *
    760  *   10/17/1994 JLB : Created.                                                                 *
    761  *   12/12/1994 JLB : Uses simple spot index finder.                                           *
    762  *=============================================================================================*/
    763 bool FootClass::Start_Driver(COORDINATE &headto)
    764 {
    765 	assert(IsActive);
    766 
    767 	Stop_Driver();
    768 	if (headto) {
    769 		HeadToCoord = headto;
    770 		IsDriving = true;
    771 
    772 		CellClass * cellptr = &Map[headto];
    773 		TemplateType ttype = cellptr->TType;
    774 		IsMovingOntoBridge = (ttype >= TEMPLATE_BRIDGE1 && ttype <= TEMPLATE_BRIDGE2D) || (ttype >= TEMPLATE_BRIDGE_1A && ttype <= TEMPLATE_BRIDGE_3F);
    775 
    776 		/*
    777 		**	Check for crate goodie finder here.
    778 		*/
    779 		if (Map[headto].Goodie_Check(this)) {
    780 			return(true);
    781 		}
    782 		if (!IsActive) return(false);
    783 
    784 		HeadToCoord = NULL;
    785 		IsDriving = false;
    786 	}
    787 	return(false);
    788 }
    789 
    790 
    791 /***********************************************************************************************
    792  * FootClass::Sort_Y -- Determine the sort coordinate for foot class objects.                  *
    793  *                                                                                             *
    794  *    This routine will determine the sort coordinate for foot class object. This coordinate   *
    795  *    is usually the coordinate of the object. The exception is if the object is tethered.     *
    796  *    In this case (presumes offloading to the north), the sorting coordinate is adjusted      *
    797  *    so that the object will be drawn on top of the transport unit.                           *
    798  *                                                                                             *
    799  * INPUT:   none                                                                               *
    800  *                                                                                             *
    801  * OUTPUT:  Returns with the coordinate to use for sorting.                                    *
    802  *                                                                                             *
    803  * WARNINGS:   none                                                                            *
    804  *                                                                                             *
    805  * HISTORY:                                                                                    *
    806  *   10/17/1994 JLB : Created.                                                                 *
    807  *   11/04/1994 JLB : Sort value is different when unloading from aircraft.                    *
    808  *=============================================================================================*/
    809 COORDINATE FootClass::Sort_Y(void) const
    810 {
    811 	assert(IsActive);
    812 
    813 	if (IsUnloading) {
    814 		return(Coord_Add(Coord, 0x01000000L));
    815 	}
    816 	if (In_Radio_Contact() && IsTethered && Contact_With_Whom()->What_Am_I() == RTTI_UNIT) {
    817 		return(Coord_Add(Coord, 0x01000000L));
    818 	}
    819 	return(Coord_Add(Coord, 0x00300000L));
    820 }
    821 
    822 
    823 /***********************************************************************************************
    824  * FootClass::Stun -- Prepares a ground travelling object for removal.                         *
    825  *                                                                                             *
    826  *    This routine clears the units' navigation computer in preparation for removal from the   *
    827  *    game. This is probably called as a result of unit destruction in combat. Clearing the    *
    828  *    navigation computer ensures that the normal AI process won't start it moving again while *
    829  *    the object is undergoing any death animations.                                           *
    830  *                                                                                             *
    831  * INPUT:   none                                                                               *
    832  *                                                                                             *
    833  * OUTPUT:  none                                                                               *
    834  *                                                                                             *
    835  * WARNINGS:   none                                                                            *
    836  *                                                                                             *
    837  * HISTORY:                                                                                    *
    838  *   12/23/1994 JLB : Created.                                                                 *
    839  *=============================================================================================*/
    840 void FootClass::Stun(void)
    841 {
    842 	assert(IsActive);
    843 
    844 	Assign_Destination(TARGET_NONE);
    845 	Path[0] = FACING_NONE;
    846 	Stop_Driver();
    847 	TechnoClass::Stun();
    848 }
    849 
    850 
    851 /***********************************************************************************************
    852  * FootClass::Approach_Target -- Sets the navigation computer to approach target object.       *
    853  *                                                                                             *
    854  *    This routine will set the navigation computer to approach the target indicated by the    *
    855  *    targeting computer. It is through this function that the unit nears the target so        *
    856  *    that weapon firing may occur.                                                            *
    857  *                                                                                             *
    858  * INPUT:   none                                                                               *
    859  *                                                                                             *
    860  * OUTPUT:  none                                                                               *
    861  *                                                                                             *
    862  * WARNINGS:   none                                                                            *
    863  *                                                                                             *
    864  * HISTORY:                                                                                    *
    865  *   05/31/1994 JLB : Created.                                                                 *
    866  *   12/13/1994 JLB : Made part of TechnoClass.                                                *
    867  *   12/22/1994 JLB : Enhanced search algorithm.                                               *
    868  *   05/20/1995 JLB : Always approaches if the object is off the map.                          *
    869  *=============================================================================================*/
    870 void FootClass::Approach_Target(void)
    871 {
    872 	assert(IsActive);
    873 
    874 	/*
    875 	**	Determine that if there is an existing target it is still legal
    876 	**	and within range.
    877 	*/
    878 	if (Target_Legal(TarCom)) {
    879 		int primary = What_Weapon_Should_I_Use(TarCom);
    880 
    881 		/*
    882 		**	If the target is too far away then head toward it.
    883 		*/
    884 		int maxrange = Weapon_Range(primary);
    885 //		int maxrange = max(Weapon_Range(0), Weapon_Range(1));
    886 
    887 		if (!Target_Legal(NavCom) && (!In_Range(TarCom, primary) || !IsLocked)) {
    888 //		if (!Target_Legal(NavCom) && (Distance(TarCom) > maxrange || !IsLocked)) {
    889 
    890 			/*
    891 			** If the object that we are attacking is a building adjust the unit's
    892 			** max range so that people can stand far away from the buildings and
    893 			** hit them.
    894 			*/
    895 			BuildingClass * obj = As_Building(TarCom);
    896 			if (obj) {
    897 				maxrange += ((obj->Class->Width() + obj->Class->Height()) * (0x100 / 4));
    898 			}
    899 
    900 			/*
    901 			** Adjust the max range of an infantry unit for where he is standing
    902 			** in the room.
    903 			*/
    904 			maxrange -= 0x00B7;
    905 #ifdef OBSOLETE
    906 			if (What_Am_I() == RTTI_INFANTRY) {
    907 				maxrange -= 0x0111;
    908 			} else {
    909 				maxrange -= 0x00B7;
    910 			}
    911 #endif
    912 			maxrange = max(maxrange, 0);
    913 
    914 			COORDINATE tcoord = ::As_Coord(TarCom);
    915 			COORDINATE trycoord = 0;
    916 			CELL tcell = Coord_Cell(tcoord);
    917 			CELL trycell = tcell;
    918 			DirType dir = Direction256(tcoord, Center_Coord());
    919 			bool found = false;
    920 
    921 			/*
    922 			**	Sweep through the cells between the target and the unit, looking for
    923 			**	a cell that the unit can enter but which is also within weapon range
    924 			**	of the target. If after a reasonable search, no appropriate cell could
    925 			**	be found, then the target will be assigned as the movement destination
    926 			**	and let "the chips fall where they may."
    927 			*/
    928 			for (int range = maxrange; range > 0x0080; range -= 0x0100) {
    929 				static int _angles[] = {0, 8, -8, 16, -16, 24, -24, 32, -32, 48, -48, 64, -64};
    930 
    931 				for (int index = 0; index < (sizeof(_angles)/sizeof(_angles[0])); index++) {
    932 					trycoord = Coord_Move(tcoord, (DirType)(dir + _angles[index]), range);
    933 
    934 					if (::Distance(trycoord, tcoord) < range) {
    935 						trycell = Coord_Cell(trycoord);
    936 						if (Map.In_Radar(trycell) && Map[trycell].Is_Clear_To_Move(Techno_Type_Class()->Speed, false, false, Map[Coord].Zones[Techno_Type_Class()->MZone], Techno_Type_Class()->MZone)) {
    937 //						if (Can_Enter_Cell(trycell) <= MOVE_CLOAK && Map.In_Radar(trycell)) {
    938 							found = true;
    939 							break;
    940 						}
    941 					}
    942 				}
    943 				if (found) break;
    944 			}
    945 
    946 			/*
    947 			**	If a suitable intermediate location was found, then head toward it.
    948 			**	Otherwise, head toward the enemy unit directly.
    949 			**	Infantry always head towards the target since they can enter a cell
    950 			**	in range, but still not be able to hit the target if the spot is out of range.
    951 			*/
    952 			if (What_Am_I() == RTTI_INFANTRY) {
    953 				Assign_Destination(TarCom);
    954 			} else if (found) {
    955 				Assign_Destination(::As_Target(trycell));
    956 			} else {
    957 
    958 				trycell = Map.Nearby_Location(trycell, Techno_Type_Class()->Speed, Map[Coord].Zones[Techno_Type_Class()->MZone], Techno_Type_Class()->MZone);
    959 				Assign_Destination(::As_Target(trycell));
    960 //				Assign_Destination(TarCom);
    961 			}
    962 		}
    963 	}
    964 }
    965 
    966 
    967 /***********************************************************************************************
    968  * FootClass::Mission_Guard_Area -- Causes unit to guard an area about twice weapon range.     *
    969  *                                                                                             *
    970  *    This mission routine causes the unit to scan for targets out to twice its weapon range   *
    971  *    from the home point. If a target was found, then it will be attacked. The unit will      *
    972  *    chase the target until it gets up to to its weapon range from the home position.         *
    973  *    In that case, it will return to home position and start scanning for another target.     *
    974  *                                                                                             *
    975  * INPUT:   none                                                                               *
    976  *                                                                                             *
    977  * OUTPUT:  Returns with time delay before calling this routine again.                         *
    978  *                                                                                             *
    979  * WARNINGS:   none                                                                            *
    980  *                                                                                             *
    981  * HISTORY:                                                                                    *
    982  *   12/23/1994 JLB : Created.                                                                 *
    983  *   07/27/1995 JLB : Greatly simplified.                                                      *
    984  *=============================================================================================*/
    985 int FootClass::Mission_Guard_Area(void)
    986 {
    987 	assert(IsActive);
    988 
    989 	/*
    990 	**	If this unit is on an impassable cell for any reason, it needs to scatter immediately
    991 	*/
    992 	if (What_Am_I() == RTTI_INFANTRY || What_Am_I() == RTTI_UNIT) {
    993 		LandType land = Map[Coord].Land_Type();
    994 		if (!Target_Legal(NavCom) && (land == LAND_ROCK || land == LAND_WATER || land == LAND_RIVER)) {
    995 			Scatter(0, true, true);
    996 			Shorten_Mission_Timer();
    997 		}
    998 	}
    999 
   1000 	if (What_Am_I() == RTTI_UNIT && ((UnitClass *)this)->Class->IsToHarvest) {
   1001 		Assign_Mission(MISSION_HARVEST);
   1002 		return(1+Random_Pick(1, 10));
   1003 	}
   1004 
   1005 	/*
   1006 	**	Ensure that the archive target is valid.
   1007 	*/
   1008 	if (!Target_Legal(ArchiveTarget)) {
   1009 		ArchiveTarget = ::As_Target(Coord);
   1010 	}
   1011 
   1012 	/*
   1013 	**	Ensure units aren't trying to guard cells off the map.
   1014 	*/
   1015 	if (Target_Legal(NavCom) && Is_Target_Cell(NavCom)) {
   1016 		CELL cell = As_Cell(NavCom);
   1017 		int x = Cell_X(cell);
   1018 		int y = Cell_Y(cell);
   1019 		if (x < Map.MapCellX || y < Map.MapCellY || x >= (Map.MapCellX + Map.MapCellWidth) || y >= (Map.MapCellY + Map.MapCellHeight)) {
   1020 			Assign_Target(TARGET_NONE);
   1021 			Assign_Destination(TARGET_NONE);
   1022 			ArchiveTarget = ::As_Target(Coord);
   1023 		}
   1024 	}
   1025 
   1026 	/*
   1027 	**	If this is a bomber type infantry and the current target is a building, then go into
   1028 	**	sabotage mode if not already.
   1029 	*/
   1030 	if (!House->IsHuman && What_Am_I() ==  RTTI_INFANTRY && Is_Target_Building(TarCom) && ((InfantryClass *)this)->Class->IsBomber && Mission != MISSION_SABOTAGE) {
   1031 		Assign_Mission(MISSION_SABOTAGE);
   1032 		return(1);
   1033 	}
   1034 
   1035 	/*
   1036 	**	Make sure that the unit has not strayed too far from the home position.
   1037 	**	If it has, then race back to it.
   1038 	*/
   1039 	int maxrange = Threat_Range(1)/2;
   1040 
   1041 	if (!IsFiring && !Target_Legal(NavCom) && Distance(ArchiveTarget) > maxrange) {
   1042 		Assign_Target(TARGET_NONE);
   1043 		Assign_Destination(ArchiveTarget);
   1044 	}
   1045 
   1046 	if (!Target_Legal(TarCom)) {
   1047 		COORDINATE old = Coord;
   1048 		Coord = As_Coord(ArchiveTarget);
   1049 		Target_Something_Nearby(THREAT_AREA);
   1050 		Coord = old;
   1051 		if (Target_Legal(TarCom)) {
   1052 			return(1);
   1053 		}
   1054 		Random_Animate();
   1055 	} else {
   1056 		Approach_Target();
   1057 	}
   1058 
   1059 	int dtime = MissionControl[Mission].Normal_Delay();
   1060 	if (What_Am_I() == RTTI_AIRCRAFT) {
   1061 		dtime *= 2;
   1062 	}
   1063 	return(dtime + Random_Pick(1, 5));
   1064 }
   1065 
   1066 
   1067 /***********************************************************************************************
   1068  * FootClass::Unlimbo -- Unlimbos object and performs special fixups.                          *
   1069  *                                                                                             *
   1070  *    This routine will make sure that the home position for the foot class object gets        *
   1071  *    reset. This is necessary since the home position may change depending on the unit's      *
   1072  *    transition between limbo and non-limbo condition.                                        *
   1073  *                                                                                             *
   1074  * INPUT:   coord    -- The coordinate to unlimbo the unit at.                                 *
   1075  *                                                                                             *
   1076  *          dir      -- The initial direction to give the unit.                                *
   1077  *                                                                                             *
   1078  * OUTPUT:  bool; Was the unit unlimboed successfully?                                         *
   1079  *                                                                                             *
   1080  * WARNINGS:   none                                                                            *
   1081  *                                                                                             *
   1082  * HISTORY:                                                                                    *
   1083  *   12/23/1994 JLB : Created.                                                                 *
   1084  *=============================================================================================*/
   1085 bool FootClass::Unlimbo(COORDINATE coord, DirType dir)
   1086 {
   1087 	assert(IsActive);
   1088 
   1089 	/*
   1090 	**	Try to unlimbo the unit.
   1091 	*/
   1092 	if (TechnoClass::Unlimbo(coord, dir)) {
   1093 
   1094 		/*
   1095 		**	Mobile units are always revealed to the house that owns them.
   1096 		*/
   1097 		Revealed(House);
   1098 
   1099 		/*
   1100 		**	Start in a still (non-moving) state.
   1101 		*/
   1102 		Path[0] = FACING_NONE;
   1103 		return(true);
   1104 	}
   1105 	return(false);
   1106 }
   1107 
   1108 
   1109 /***********************************************************************************************
   1110  * FootClass::Take_Damage -- Handles taking damage to this object.                             *
   1111  *                                                                                             *
   1112  *    This routine intercepts the damage assigned to this object and if this object is         *
   1113  *    a member of a team, it informs the team that the damage has occurred. The team may       *
   1114  *    change it's priority or action based on this event.                                      *
   1115  *                                                                                             *
   1116  * INPUT:   damage      -- The damage points inflicted on the unit.                            *
   1117  *                                                                                             *
   1118  *          distance    -- The distance from the point of damage to the unit itself.           *
   1119  *                                                                                             *
   1120  *          warhead     -- The type of damage that is inflicted.                               *
   1121  *                                                                                             *
   1122  *          source      -- The perpetrator of the damage. By knowing who caused the damage,    *
   1123  *                         the team know's who to "get even with".                             *
   1124  *                                                                                             *
   1125  * OUTPUT:  Returns with the result type of the damage.                                        *
   1126  *                                                                                             *
   1127  * WARNINGS:   none                                                                            *
   1128  *                                                                                             *
   1129  * HISTORY:                                                                                    *
   1130  *   12/30/1994 JLB : Created.                                                                 *
   1131  *=============================================================================================*/
   1132 ResultType FootClass::Take_Damage(int & damage, int distance, WarheadType warhead, TechnoClass * source, bool forced)
   1133 {
   1134 	assert(IsActive);
   1135 
   1136 	ResultType result = TechnoClass::Take_Damage(damage, distance, warhead, source, forced);
   1137 
   1138 	if (result != RESULT_NONE && Team) {
   1139 
   1140 		Team->Took_Damage(this, result, source);
   1141 
   1142 	} else {
   1143 
   1144 		if (result != RESULT_DESTROYED && result != RESULT_NONE) {
   1145 
   1146 			/*
   1147 			**	Determine if the target that is currently being attacked has a weapon that can
   1148 			**	do harm to a ground based unit. This information is needed so that an appropriate
   1149 			**	response will occur when damage is taken.
   1150 			*/
   1151 //			bool tweap = false;
   1152 //			if (As_Techno(TarCom)) {
   1153 //				tweap = (As_Techno(TarCom)->Techno_Type_Class()->PrimaryWeapon != NULL);
   1154 //			}
   1155 
   1156 			/*
   1157 			**	This ensures that if a unit is in sticky mode, then it will snap out of
   1158 			**	it when it takes damage.
   1159 			*/
   1160 			if (source != NULL && MissionControl[Mission].IsNoThreat && !MissionControl[Mission].IsZombie) {
   1161 				Enter_Idle_Mode();
   1162 			}
   1163 
   1164 			/*
   1165 			**	If this object is not part of a team and it can retaliate for the damage, then have
   1166 			**	it try to do so. This prevents it from just sitting there and taking damage.
   1167 			*/
   1168 			if (Is_Allowed_To_Retaliate(source)) {
   1169 
   1170 				int primary = What_Weapon_Should_I_Use(source->As_Target());
   1171 				if (In_Range(source, primary) || !House->IsHuman) {
   1172 					Assign_Target(source->As_Target());
   1173 				}
   1174 
   1175 				if (Mission == MISSION_AMBUSH) {
   1176 					Assign_Mission(MISSION_HUNT);
   1177 				}
   1178 
   1179 				/*
   1180 				**	Simple retaliation cannot occur because the source of the damage
   1181 				**	is too far away. If scatter logic is enabled, then scatter now.
   1182 				*/
   1183 				if (!Target_Legal(TarCom) && !Target_Legal(NavCom) && Rule.IsScatter) {
   1184 					Scatter(0, true);
   1185 				}
   1186 
   1187 			} else {
   1188 
   1189 				/*
   1190 				**	If this object isn't doing anything important, then scatter.
   1191 				*/
   1192 				if (MissionControl[Mission].IsScatter && !IsTethered && !IsDriving && !Target_Legal(TarCom) && !Target_Legal(NavCom) && What_Am_I() != RTTI_AIRCRAFT && What_Am_I() != RTTI_VESSEL) {
   1193 					if (!House->IsHuman || Rule.IsScatter) {
   1194 						Scatter(0, true);
   1195 					}
   1196 				}
   1197 			}
   1198 		}
   1199 	}
   1200 	return(result);
   1201 }
   1202 
   1203 
   1204 /***********************************************************************************************
   1205  * FootClass::Active_Click_With -- Initiates attack or move according to target clicked on.    *
   1206  *                                                                                             *
   1207  *    At this level, the object is known to have the ability to attack or move to the          *
   1208  *    target specified (in theory). Perform the attack or move as indicated.                   *
   1209  *                                                                                             *
   1210  * INPUT:   target   -- The target clicked upon that will precipitate action.                  *
   1211  *                                                                                             *
   1212  * OUTPUT:  Returns with the type of action performed.                                         *
   1213  *                                                                                             *
   1214  * WARNINGS:   none                                                                            *
   1215  *                                                                                             *
   1216  * HISTORY:                                                                                    *
   1217  *   01/06/1995 JLB : Created.                                                                 *
   1218  *=============================================================================================*/
   1219 void FootClass::Active_Click_With(ActionType action, ObjectClass * object)
   1220 {
   1221 	assert(IsActive);
   1222 	assert(object != NULL);
   1223 
   1224 	switch (action) {
   1225 		case ACTION_GUARD_AREA:
   1226 			if (Can_Player_Fire() && Can_Player_Move()) {
   1227 				if (What_Am_I() == RTTI_INFANTRY &&
   1228 						((InfantryClass *)this)->Class->IsBomber &&
   1229 						object->What_Am_I() == RTTI_BUILDING &&
   1230 						!House->Is_Ally(object)) {
   1231 
   1232 					Player_Assign_Mission(MISSION_SABOTAGE, TARGET_NONE, object->As_Target());
   1233 				} else {
   1234 					Player_Assign_Mission(MISSION_GUARD_AREA, object->As_Target());
   1235 				}
   1236 			}
   1237 			break;
   1238 
   1239 		case ACTION_SELF:
   1240 			Player_Assign_Mission(MISSION_UNLOAD);
   1241 			break;
   1242 
   1243 		case ACTION_ATTACK:
   1244 			if (Can_Player_Fire()) {
   1245 				Player_Assign_Mission(MISSION_ATTACK, object->As_Target());
   1246 			}
   1247 			break;
   1248 
   1249 		case ACTION_ENTER:
   1250 			if (Can_Player_Move() && object && object->Is_Techno() /*&& !((RadioClass *)object)->In_Radio_Contact()*/) {
   1251 				Player_Assign_Mission(MISSION_ENTER, TARGET_NONE, object->As_Target());
   1252 			}
   1253 			break;
   1254 
   1255 		case ACTION_CAPTURE:
   1256 			if (Can_Player_Move()) {
   1257 				Player_Assign_Mission(MISSION_CAPTURE, TARGET_NONE, object->As_Target());
   1258 			}
   1259 			break;
   1260 
   1261 		case ACTION_SABOTAGE:
   1262 			if (Can_Player_Move()) {
   1263 				Player_Assign_Mission(MISSION_SABOTAGE, TARGET_NONE, object->As_Target());
   1264 			}
   1265 			break;
   1266 
   1267 		case ACTION_NOMOVE:
   1268 		case ACTION_MOVE:
   1269 			if (Can_Player_Move()) {
   1270 
   1271 				TARGET targ = object->As_Target();
   1272 
   1273 				/*
   1274 				**	If the destination object is not the same zone, then pick a nearby location.
   1275 				*/
   1276 				if (object->What_Am_I() != RTTI_AIRCRAFT && Techno_Type_Class()->Speed != SPEED_WINGED && Map[Coord].Zones[Techno_Type_Class()->MZone] != Map[object->Center_Coord()].Zones[Techno_Type_Class()->MZone]) {
   1277 
   1278 #ifdef FIXIT_MINE_PASSABLE
   1279 					// Fixes units not driving onto mines.
   1280 					if (Can_Enter_Cell(Coord_Cell(object->Center_Coord())) > MOVE_OK) {
   1281 						targ = ::As_Target(Map.Nearby_Location(Coord_Cell(object->Center_Coord()), Techno_Type_Class()->Speed, Map[Coord].Zones[Techno_Type_Class()->MZone], Techno_Type_Class()->MZone));
   1282 					}
   1283 #else
   1284 					targ = ::As_Target(Map.Nearby_Location(Coord_Cell(object->Center_Coord()), Techno_Type_Class()->Speed, Map[Coord].Zones[Techno_Type_Class()->MZone], Techno_Type_Class()->MZone));
   1285 #endif
   1286 				}
   1287 
   1288 				Player_Assign_Mission(MISSION_MOVE, TARGET_NONE, targ);
   1289 			}
   1290 			break;
   1291 
   1292 		case ACTION_NO_DEPLOY:
   1293 			Speak(VOX_DEPLOY);
   1294 			break;
   1295 
   1296 		default:
   1297 			break;
   1298 	}
   1299 }
   1300 
   1301 
   1302 /***********************************************************************************************
   1303  * FootClass::Active_Click_With -- Performs action as a result of left mouse click.            *
   1304  *                                                                                             *
   1305  *    This routine performs the action requested when the left mouse button was clicked over   *
   1306  *    a cell. Typically, this is just a move command.                                          *
   1307  *                                                                                             *
   1308  * INPUT:   action   -- The predetermined action that should occur.                            *
   1309  *                                                                                             *
   1310  *          cell     -- The cell number that the action should occur at.                       *
   1311  *                                                                                             *
   1312  * OUTPUT:  none                                                                               *
   1313  *                                                                                             *
   1314  * WARNINGS:   none                                                                            *
   1315  *                                                                                             *
   1316  * HISTORY:                                                                                    *
   1317  *   01/19/1995 JLB : Created.                                                                 *
   1318  *=============================================================================================*/
   1319 void FootClass::Active_Click_With(ActionType action, CELL cell)
   1320 {
   1321 	assert(IsActive);
   1322 
   1323 	action = What_Action(cell);
   1324 	switch (action) {
   1325 		case ACTION_HARVEST:
   1326 			Player_Assign_Mission(MISSION_HARVEST, TARGET_NONE, ::As_Target(cell));
   1327 			break;
   1328 
   1329 		case ACTION_MOVE:
   1330 			if (AllowVoice) {
   1331 				COORDINATE coord = Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y());
   1332 				OutList.Add(EventClass(ANIM_MOVE_FLASH, PlayerPtr->Class->House, coord, 1 << PlayerPtr->Class->House));
   1333 			}
   1334 			// Fall into next case.
   1335 
   1336 		case ACTION_NOMOVE:
   1337 			//using function for IsVisible so we have different results for different players - JAS 2019/09/30
   1338 			if (What_Am_I() != RTTI_AIRCRAFT || Map[cell].Is_Visible(PlayerPtr)) {
   1339 
   1340 				/*
   1341 				** Find the closest same-zoned cell to where the unit currently is.
   1342 				** This will allow the unit to come as close to the destination cell
   1343 				** as is reasonably possible, when clicking on an impassable cell
   1344 				** (as is likely when clicking in the shroud.)  It looks for the
   1345 				** nearest cell using an expanding-radius box, and ignores cells
   1346 				** off the edge of the map.
   1347 				*/
   1348 				CellClass const * cellptr = &Map[::As_Cell(::As_Target(Center_Coord()))];
   1349 				if (What_Am_I() != RTTI_AIRCRAFT) {
   1350 
   1351 					if (Can_Enter_Cell(Coord_Cell(Center_Coord())) == MOVE_OK) {
   1352 						cell = Map.Nearby_Location(cell, Techno_Type_Class()->Speed, cellptr->Zones[Techno_Type_Class()->MZone], Techno_Type_Class()->MZone);
   1353 					} else {
   1354 						cell = Map.Nearby_Location(cell, Techno_Type_Class()->Speed);
   1355 					}
   1356 #ifdef OBSOLETE
   1357 					cell = Map.Nearby_Location(cell, Techno_Type_Class()->Speed, cellptr->Zones[Techno_Type_Class()->MZone], Techno_Type_Class()->MZone);
   1358 #endif
   1359 				}
   1360 
   1361 				Player_Assign_Mission(MISSION_MOVE, TARGET_NONE, ::As_Target(cell));
   1362 			}
   1363 			break;
   1364 
   1365 		case ACTION_ATTACK:
   1366 			Player_Assign_Mission(MISSION_ATTACK, ::As_Target(cell));
   1367 			break;
   1368 
   1369 		/*
   1370 		** Engineer attempting to capture bridge to repair it
   1371 		*/
   1372 		case ACTION_CAPTURE:
   1373 			if (Can_Player_Move()) {
   1374 				Player_Assign_Mission(MISSION_CAPTURE, TARGET_NONE, ::As_Target(cell));
   1375 			}
   1376 			break;
   1377 
   1378 		case ACTION_SABOTAGE:
   1379 			Player_Assign_Mission(MISSION_SABOTAGE, TARGET_NONE, ::As_Target(cell) );
   1380 			break;
   1381 
   1382 		// MBL 05.15.2020 - Adding support for CTRL+ALT clicking the ground to have units move to an area and guard it
   1383 		case ACTION_GUARD_AREA:
   1384 			if (Can_Player_Fire() && Can_Player_Move()) {
   1385 				Player_Assign_Mission(MISSION_GUARD_AREA, ::As_Target(cell));
   1386 			}
   1387 			break;
   1388 		// END MBL 05.15.2020 
   1389 	}
   1390 }
   1391 
   1392 
   1393 /***********************************************************************************************
   1394  * FootClass::Per_Cell_Process -- Perform action based on once-per-cell condition.             *
   1395  *                                                                                             *
   1396  *    This routine is called as this object moves from cell to cell. When the center of the    *
   1397  *    cell is reached, check to see if any trigger should be sprung. For moving units, reduce  *
   1398  *    the path to the distance to the target. This forces path recalculation in an effort to   *
   1399  *    avoid units passing each other.                                                          *
   1400  *                                                                                             *
   1401  * INPUT:   why   -- Specifies the circumstances under which this routine was called.          *
   1402  *                                                                                             *
   1403  * OUTPUT:  none                                                                               *
   1404  *                                                                                             *
   1405  * WARNINGS:   none                                                                            *
   1406  *                                                                                             *
   1407  * HISTORY:                                                                                    *
   1408  *   05/08/1995 JLB : Created.                                                                 *
   1409  *   07/08/1995 JLB : Handles generic enter trigger event.                                     *
   1410  *   07/16/1995 JLB : If next to a scanner and cloaked, then shimmer.                          *
   1411  *=============================================================================================*/
   1412 void FootClass::Per_Cell_Process(PCPType why)
   1413 {
   1414 	assert(IsActive);
   1415 
   1416 	if (why == PCP_END) {
   1417 
   1418 		IsScattering = false;
   1419 
   1420 		/*
   1421 		**	Clear any unloading flag if necessary.
   1422 		*/
   1423 		IsUnloading = false;
   1424 
   1425 		/*
   1426 		**	If adjacent to an enemy techno that has the ability to reveal a sub,
   1427 		**	then shimmer the cloaked object.
   1428 		*/
   1429 		if (Cloak == CLOAKED) {
   1430 			for (FacingType face = FACING_N; face < FACING_COUNT; face++) {
   1431 				CELL cell = Adjacent_Cell(Coord_Cell(Coord), face);
   1432 
   1433 				if (Map.In_Radar(cell)) {
   1434 					TechnoClass const * techno = Map[cell].Cell_Techno();
   1435 
   1436 					if (techno && !techno->House->Is_Ally(this) && techno->Techno_Type_Class()->IsScanner) {
   1437 						Do_Shimmer();
   1438 						break;
   1439 					}
   1440 				}
   1441 			}
   1442 		}
   1443 
   1444 		/*
   1445 		**	Shorten the path if the target is now within weapon range of this
   1446 		**	unit and this unit is on an attack type mission. But only if the target
   1447 		**	is slow enough for leading to make sense.
   1448 		*/
   1449 		if (Target_Legal(TarCom) && (What_Am_I() != RTTI_INFANTRY || !((InfantryClass *)this)->Class->IsDog)) {
   1450 			int primary = What_Weapon_Should_I_Use(TarCom);
   1451 			bool inrange = In_Range(TarCom, primary);
   1452 			TechnoClass const * techno = As_Techno(TarCom);
   1453 			if (techno != NULL && techno->Is_Foot()) {
   1454 				FootClass const * foot = (FootClass const *)techno;
   1455 				MPHType speed = ((TechnoTypeClass const &)techno->Class_Of()).MaxSpeed;
   1456 				COORDINATE rangecoord = (speed > MPH_SLOW) ? foot->Likely_Coord() : foot->Target_Coord();
   1457 				inrange = In_Range(rangecoord, primary);
   1458 			}
   1459 
   1460 			if ((Mission == MISSION_RESCUE || Mission == MISSION_GUARD_AREA || Mission == MISSION_ATTACK || Mission == MISSION_HUNT) && inrange) {
   1461 				Assign_Destination(TARGET_NONE);
   1462 				Path[0] = FACING_NONE;
   1463 			}
   1464 		}
   1465 
   1466 		/*
   1467 		**	Trigger event associated with the player entering the cell.
   1468 		*/
   1469 		if (Cloak != CLOAKED) {
   1470 			TriggerClass * trigger = Map[Coord].Trigger;
   1471 			if (trigger != NULL) {
   1472 				trigger->Spring(TEVENT_PLAYER_ENTERED, this, Coord_Cell(Coord));
   1473 				if (!IsActive) return;
   1474 			}
   1475 
   1476 			/*
   1477 			**	Check for horizontal trigger crossing.
   1478 			*/
   1479 			int x = Cell_X(Coord_Cell(Coord));
   1480 			int y = Cell_Y(Coord_Cell(Coord));
   1481 			int index;
   1482 			for (index = 0; index < Map.MapCellWidth; index++) {
   1483 				trigger = Map[XY_Cell(index+Map.MapCellX, y)].Trigger;
   1484 				if (trigger != NULL) {
   1485 					if (trigger->Class->Event1.Event == TEVENT_CROSS_HORIZONTAL || (trigger->Class->EventControl != MULTI_ONLY && trigger->Class->Event2.Event == TEVENT_CROSS_HORIZONTAL)) {
   1486 						trigger->Spring(TEVENT_CROSS_HORIZONTAL, this, Coord_Cell(Coord));
   1487 						if (!IsActive) return;
   1488 					}
   1489 				}
   1490 			}
   1491 
   1492 			/*
   1493 			**	Check for vertical trigger crossing.
   1494 			*/
   1495 			for (index = 0; index < Map.MapCellHeight; index++) {
   1496 				trigger = Map[XY_Cell(x, index+Map.MapCellY)].Trigger;
   1497 				if (trigger != NULL) {
   1498 					if (trigger->Class->Event1.Event == TEVENT_CROSS_VERTICAL || (trigger->Class->EventControl != MULTI_ONLY && trigger->Class->Event2.Event == TEVENT_CROSS_VERTICAL)) {
   1499 						trigger->Spring(TEVENT_CROSS_VERTICAL, this, Coord_Cell(Coord));
   1500 						if (!IsActive) return;
   1501 					}
   1502 				}
   1503 			}
   1504 
   1505 			/*
   1506 			**	Check for zone entry trigger events.
   1507 			*/
   1508 			for (MapTriggerID = 0; MapTriggerID < MapTriggers.Count(); MapTriggerID++) {
   1509 				trigger = MapTriggers[MapTriggerID];
   1510 				if (trigger->Class->Event1.Event == TEVENT_ENTERS_ZONE || (trigger->Class->EventControl != MULTI_ONLY && trigger->Class->Event2.Event == TEVENT_ENTERS_ZONE)) {
   1511 					if (Map[trigger->Cell].Zones[Techno_Type_Class()->MZone] == Map[Coord].Zones[Techno_Type_Class()->MZone]) {
   1512 						trigger->Spring(TEVENT_ENTERS_ZONE, this, Coord_Cell(Coord));
   1513 						if (!IsActive) return;
   1514 					}
   1515 				}
   1516 			}
   1517 
   1518 			/*
   1519 			**	If any of these triggers cause this unit to be destroyed, then
   1520 			**	stop all further processing for this unit.
   1521 			*/
   1522 			if (!IsActive) return;
   1523 		}
   1524 
   1525 #ifdef OBSOLETE
   1526 		/*
   1527 		** Flag any gap generators to re-draw
   1528 		*/
   1529 		for (int index = 0; index <Buildings.Count(); index++) {
   1530 			BuildingClass * obj = Buildings.Ptr(index);
   1531 			if (obj && *obj == STRUCT_GAP && !obj->IsInLimbo && (HouseClass *)obj->House != PlayerPtr) {
   1532 				int dist = Distance(obj) / CELL_LEPTON_W;
   1533 				if (dist < (6 + Rule.GapShroudRadius) ) {
   1534 	//			if (dist < (6 + obj->Class->SightRange) ) {
   1535 					obj->IsJamming = false;	// lie so it'll re-jam now
   1536 				}
   1537 			}
   1538 		}
   1539 #endif
   1540 
   1541 	}
   1542 
   1543 	TechnoClass::Per_Cell_Process(why);
   1544 }
   1545 
   1546 
   1547 /***************************************************************************
   1548  * FootClass::Override_Mission -- temporarily overrides a units mission    *
   1549  *                                                                         *
   1550  *                                                                         *
   1551  *                                                                         *
   1552  * INPUT:		MissionType mission - the mission we want to override       *
   1553  *					TARGET	   tarcom  - the new target we want to override		*
   1554  *					TARGET		navcom  - the new navigation point to override	*
   1555  *                                                                         *
   1556  * OUTPUT:		none                                                        *
   1557  *                                                                         *
   1558  * WARNINGS:   If a mission is already overridden, the current mission is  *
   1559  *					just re-assigned.															*
   1560  *                                                                         *
   1561  * HISTORY:                                                                *
   1562  *   04/28/1995 PWG : Created.                                             *
   1563  *=========================================================================*/
   1564 void FootClass::Override_Mission(MissionType mission, TARGET tarcom, TARGET navcom)
   1565 {
   1566 	assert(IsActive);
   1567 
   1568  	SuspendedNavCom = NavCom;
   1569 	TechnoClass::Override_Mission(mission, tarcom, navcom);
   1570 
   1571 	Assign_Destination(navcom);
   1572 }
   1573 
   1574 
   1575 /***************************************************************************
   1576  * FootClass::Restore_Mission -- Restores an overridden mission            *
   1577  *                                                                         *
   1578  * INPUT:		none                                                        *
   1579  *                                                                         *
   1580  * OUTPUT:     none                                                        *
   1581  *                                                                         *
   1582  * WARNINGS:   none                                                        *
   1583  *                                                                         *
   1584  * HISTORY:                                                                *
   1585  *   04/28/1995 PWG : Created.                                             *
   1586  *=========================================================================*/
   1587 bool FootClass::Restore_Mission(void)
   1588 {
   1589 	assert(IsActive);
   1590 
   1591 	if (TechnoClass::Restore_Mission()) {
   1592 		Assign_Destination(SuspendedNavCom);
   1593 		return(true);
   1594 	}
   1595 	return(false);
   1596 }
   1597 
   1598 
   1599 /***********************************************************************************************
   1600  * FootClass::Receive_Message -- Movement related radio messages are handled here.             *
   1601  *                                                                                             *
   1602  *    This routine handles radio message that are related to movement. These are used for      *
   1603  *    complex coordinated maneuvers.                                                           *
   1604  *                                                                                             *
   1605  * INPUT:   from     -- Pointer to the originator of this radio message.                       *
   1606  *                                                                                             *
   1607  *          message  -- The radio message that is being received.                              *
   1608  *                                                                                             *
   1609  *          param    -- The optional parameter (could be a movement destination).              *
   1610  *                                                                                             *
   1611  * OUTPUT:  Returns with the radio response appropriate to the message received. Usually the   *
   1612  *          response is RADIO_ROGER.                                                           *
   1613  *                                                                                             *
   1614  * WARNINGS:   none                                                                            *
   1615  *                                                                                             *
   1616  * HISTORY:                                                                                    *
   1617  *   05/14/1995 JLB : Created.                                                                 *
   1618  *=============================================================================================*/
   1619 RadioMessageType FootClass::Receive_Message(RadioClass * from, RadioMessageType message, long & param)
   1620 {
   1621 	assert(IsActive);
   1622 
   1623 	switch (message) {
   1624 
   1625 		/*
   1626 		**	Answers if this object is located on top of a service depot.
   1627 		*/
   1628 		case RADIO_ON_DEPOT:
   1629 			if (Map[Center_Coord()].Cell_Building() != NULL) {
   1630 				BuildingClass const * building = Map[Center_Coord()].Cell_Building();
   1631 				if (*building == STRUCT_REPAIR) {
   1632 					return(RADIO_ROGER);
   1633 				}
   1634 			}
   1635 			return(RADIO_NEGATIVE);
   1636 
   1637 		/*
   1638 		**	Intercept the repair request and if this object is moving, then no repair
   1639 		**	is possible.
   1640 		*/
   1641 		case RADIO_REPAIR:
   1642 			if (Target_Legal(NavCom)) return(RADIO_NEGATIVE);
   1643 			break;
   1644 
   1645 		/*
   1646 		**	Something bad has happened to the object in contact with. Abort any coordinated
   1647 		**	activity with this object. Basically, ... run away! Run away!
   1648 		*/
   1649 		case RADIO_RUN_AWAY:
   1650 			if (In_Radio_Contact()) {
   1651 				if (NavCom == Contact_With_Whom()->As_Target()) {
   1652 					Assign_Destination(TARGET_NONE);
   1653 				}
   1654 			}
   1655 			if (Mission == MISSION_SLEEP) {
   1656 				Assign_Mission(MISSION_GUARD);
   1657 				Commence();
   1658 			}
   1659 			if (Mission == MISSION_ENTER) {
   1660 				Assign_Mission(MISSION_GUARD);
   1661 			}
   1662 			if (!IsRotating && !Target_Legal(NavCom)) {
   1663 				Scatter(0, true, true);
   1664 			}
   1665 			break;
   1666 
   1667 		/*
   1668 		**	Checks to see if this unit needs to move somewhere. If it is already in motion,
   1669 		**	then it doesn't need further movement instructions.
   1670 		*/
   1671 		case RADIO_NEED_TO_MOVE:
   1672 			param = (long)NavCom;
   1673 			if (!Target_Legal(NavCom)) {
   1674 				return(RADIO_ROGER);
   1675 			}
   1676 			return(RADIO_NEGATIVE);
   1677 
   1678 		/*
   1679 		**	Radio request to move to location specified. Typically this is used
   1680 		**	for complex loading and unloading missions.
   1681 		*/
   1682 		case RADIO_MOVE_HERE:
   1683 			if (NavCom != (TARGET)param) {
   1684 				if (::As_Target(Coord_Cell(Coord)) == (TARGET)param) {
   1685 					return(RADIO_YEA_NOW_WHAT);
   1686 				} else {
   1687 					if (Mission == MISSION_GUARD && MissionQueue == MISSION_NONE) {
   1688 						Assign_Mission(MISSION_MOVE);
   1689 					}
   1690 					Assign_Destination((TARGET)param);
   1691 					Shorten_Mission_Timer();
   1692 				}
   1693 			}
   1694 			return(RADIO_ROGER);
   1695 
   1696 		/*
   1697 		** Requests if this unit is trying to cooperatively load up. Typically, this occurs
   1698 		**	for passengers and when vehicles need to be repaired.
   1699 		*/
   1700 		case RADIO_TRYING_TO_LOAD:
   1701 			if (Mission == MISSION_ENTER || MissionQueue == MISSION_ENTER) {
   1702 				TechnoClass::Receive_Message(from, message, param);
   1703 				return(RADIO_ROGER);
   1704 			}
   1705 			break;
   1706 	}
   1707 	return(TechnoClass::Receive_Message(from, message, param));
   1708 }
   1709 
   1710 
   1711 /***********************************************************************************************
   1712  * FootClass::Mission_Enter -- Enter (cooperatively) mission handler.                          *
   1713  *                                                                                             *
   1714  *    This mission handler will cooperatively coordinate the object to maneuver into the       *
   1715  *    object it is in radio contact with. This is used by infantry when they wish to load      *
   1716  *    into an APC as well as by vehicles when they wish to enter a repair facility.            *
   1717  *                                                                                             *
   1718  * INPUT:   none                                                                               *
   1719  *                                                                                             *
   1720  * OUTPUT:  Returns the number of game ticks before this routine should be called again.       *
   1721  *                                                                                             *
   1722  * WARNINGS:   none                                                                            *
   1723  *                                                                                             *
   1724  * HISTORY:                                                                                    *
   1725  *   05/15/1995 JLB : Created.                                                                 *
   1726  *   09/22/1995 JLB : Modified to handle the "on hold" condition.                              *
   1727  *=============================================================================================*/
   1728 int FootClass::Mission_Enter(void)
   1729 {
   1730 	assert(IsActive);
   1731 
   1732 	/*
   1733 	**	Find out who to coordinate with. If in radio contact, then this the transporter is
   1734 	**	defined. If not in radio contact, then try the archive target value to see if that
   1735 	**	is suitable.
   1736 	*/
   1737 	TechnoClass * contact = Contact_With_Whom();
   1738 	if (contact == NULL) {
   1739 		contact = As_Techno(ArchiveTarget);
   1740 	}
   1741 
   1742 	/*
   1743 	**	If in contact, then let the transporter handle the movement coordination.
   1744 	*/
   1745 	if (contact != NULL) {
   1746 
   1747 		/*
   1748 		**	If the transport says to "bug off", then abort the enter mission. The transport may
   1749 		**	likely say all is 'ok' with the "RADIO ROGER", then try again later.
   1750 		*/
   1751 		if (Transmit_Message(RADIO_DOCKING, contact) != RADIO_ROGER && !IsTethered) {
   1752 			Transmit_Message(RADIO_OVER_OUT);
   1753 			Enter_Idle_Mode();
   1754 		}
   1755 
   1756 	} else {
   1757 
   1758 		/*
   1759 		**	Since there is no potential object to enter, then abort this
   1760 		**	mission with some default standby mission.
   1761 		*/
   1762 		if (MissionQueue == MISSION_NONE) {
   1763 			/*
   1764 			**	If this is a harvester, then return to harvesting.
   1765 			**	Set a hacky target so we know to skip to the proper state.
   1766 			*/
   1767 			if (What_Am_I() == RTTI_UNIT && ((UnitClass*)this)->Class->IsToHarvest) {
   1768 				Assign_Mission(MISSION_HARVEST);
   1769 				Assign_Target(As_Target());
   1770 				Assign_Destination(TARGET_NONE);
   1771 			} else {
   1772 				Enter_Idle_Mode();
   1773 			}
   1774 		}
   1775 	}
   1776 
   1777 	return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
   1778 }
   1779 
   1780 
   1781 /***********************************************************************************************
   1782  * FootClass::Assign_Destination -- Assigns specified destination to NavCom.                   *
   1783  *                                                                                             *
   1784  *    This routine will assign the specified target to the navigation computer. No legality    *
   1785  *    checks are performed.                                                                    *
   1786  *                                                                                             *
   1787  * INPUT:   target   -- The target value to assign to the navigation computer.                 *
   1788  *                                                                                             *
   1789  * OUTPUT:  none                                                                               *
   1790  *                                                                                             *
   1791  * WARNINGS:   none                                                                            *
   1792  *                                                                                             *
   1793  * HISTORY:                                                                                    *
   1794  *   07/08/1995 JLB : Created.                                                                 *
   1795  *=============================================================================================*/
   1796 void FootClass::Assign_Destination(TARGET target)
   1797 {
   1798 	assert(IsActive);
   1799 
   1800 	NavCom = target;
   1801 
   1802 	/*
   1803 	**	Presume that the easiest path is tried first. As the findpath proceeds, when
   1804 	**	a failure occurs, this threshhold will be increased until path failure
   1805 	**	cannot be prevent. At this point, all movement should cease.
   1806 	*/
   1807 	PathThreshhold = MOVE_CLOAK;
   1808 }
   1809 
   1810 
   1811 /***********************************************************************************************
   1812  * FootClass::Detach_All -- Removes this object from the game system.                          *
   1813  *                                                                                             *
   1814  *    This routine will remove this object from the game system. This routine is called when   *
   1815  *    this object is about to be deleted. All other objects should no longer reference this    *
   1816  *    object in that case.                                                                     *
   1817  *                                                                                             *
   1818  * INPUT:   none                                                                               *
   1819  *                                                                                             *
   1820  * OUTPUT:  none                                                                               *
   1821  *                                                                                             *
   1822  * WARNINGS:   none                                                                            *
   1823  *                                                                                             *
   1824  * HISTORY:                                                                                    *
   1825  *   07/08/1995 JLB : Created.                                                                 *
   1826  *=============================================================================================*/
   1827 void FootClass::Detach_All(bool all)
   1828 {
   1829 	assert(IsActive);
   1830 
   1831 	if (Team && !ScenarioInit) {
   1832 		Team->Remove(this);
   1833 		Team = NULL;
   1834 	}
   1835 
   1836 	TechnoClass::Detach_All(all);
   1837 }
   1838 
   1839 
   1840 /***********************************************************************************************
   1841  * FootClass::Rescue_Mission -- Calls this unit to the rescue.                                 *
   1842  *                                                                                             *
   1843  *    This routine is called when the house determines that it should attack the specified     *
   1844  *    target. This routine will determine if it can attack the target specified and if so,     *
   1845  *    the amount of power it can throw at it. This returned power value is used to allow       *
   1846  *    intelligent distribution of retaliation.                                                 *
   1847  *                                                                                             *
   1848  * INPUT:   target   -- The target that this object just might be assigned to attack and thus  *
   1849  *                      how much power it can bring to bear should be returned.                *
   1850  *                                                                                             *
   1851  * OUTPUT:  Returns with the amount of power that this object can bring to bear against the    *
   1852  *          potential target specified.                                                        *
   1853  *                                                                                             *
   1854  * WARNINGS:   none                                                                            *
   1855  *                                                                                             *
   1856  * HISTORY:                                                                                    *
   1857  *   07/08/1995 JLB : Created.                                                                 *
   1858  *=============================================================================================*/
   1859 int FootClass::Rescue_Mission(TARGET tarcom)
   1860 {
   1861 	assert(IsActive);
   1862 
   1863 	/*
   1864 	**	If the target specified is not legal, then it cannot be attacked. Always return
   1865 	**	zero in this case.
   1866 	*/
   1867 	if (!Target_Legal(tarcom)) return(0);
   1868 
   1869 	/*
   1870 	** If the unit is already assigned to destroy the tarcom then we need
   1871 	** to return a negative value which tells the computer to lower the
   1872 	** desired threat rating.
   1873 	*/
   1874 	if (TarCom == tarcom) {
   1875 		return(-Risk());
   1876 	}
   1877 
   1878 	/*
   1879 	** If the unit is currently attacking a target that has a weapon then we
   1880 	** cannot abandon it as it will destroy us if we return to base.
   1881 	*/
   1882 	if (Target_Legal(TarCom)) {
   1883 		TechnoClass * techno = As_Techno(TarCom);
   1884 		if (techno != NULL && techno->Is_Weapon_Equipped()) {
   1885 			return(0);
   1886 		}
   1887 	}
   1888 
   1889 	/*
   1890 	** If the unit is in a harvest mission or is currently attacking
   1891 	** something, or is not very effective, then it will be of no help
   1892 	** at all.
   1893 	*/
   1894 	if (Team.Is_Valid() || Mission == MISSION_HARVEST || !Risk()) {
   1895 		return(0);
   1896 	}
   1897 
   1898 	/*
   1899 	** Find the distance to the target modified by the range.  If the
   1900 	** the distance is 0, then things are ok.
   1901 	*/
   1902 	int dist = Distance(tarcom) - Weapon_Range(0);
   1903 	int threat = Risk() * 1024;
   1904 	int speed = -1;
   1905 	if (dist > 0) {
   1906 
   1907 		/*
   1908 		** Next we need to figure out how fast the unit moves because this
   1909 		** decreases the distance penalty.
   1910 		*/
   1911 		speed = max((unsigned)Techno_Type_Class()->MaxSpeed, (unsigned)1);
   1912 
   1913 		int ratio = (speed > 0) ? Max(dist / speed, 1) : 1;
   1914 
   1915 		/*
   1916 		** Finally modify the threat by the distance the unit is away.
   1917 		*/
   1918 		threat = max(threat/ratio, 1);
   1919 	}
   1920 	return(threat);
   1921 }
   1922 
   1923 
   1924 /***********************************************************************************************
   1925  * FootClass::Death_Announcement -- Announces the death of a unit.                             *
   1926  *                                                                                             *
   1927  *    This routine is called when a unit (infantry, vehicle, or aircraft) is destroyed.        *
   1928  *                                                                                             *
   1929  * INPUT:   source   -- The perpetrator of this death.                                         *
   1930  *                                                                                             *
   1931  * OUTPUT:  none                                                                               *
   1932  *                                                                                             *
   1933  * WARNINGS:   none                                                                            *
   1934  *                                                                                             *
   1935  * HISTORY:                                                                                    *
   1936  *   07/01/1995 JLB : Created.                                                                 *
   1937  *=============================================================================================*/
   1938 void FootClass::Death_Announcement(TechnoClass const * ) const
   1939 {
   1940 	assert(IsActive);
   1941 
   1942 	//if (IsOwnedByPlayer) {
   1943 	if ((Session.Type == GAME_GLYPHX_MULTIPLAYER && House->IsHuman) || (Session.Type != GAME_GLYPHX_MULTIPLAYER && IsOwnedByPlayer)) {
   1944 		if (What_Am_I() == RTTI_VESSEL) {
   1945 			// Speak(VOX_SHIP_LOST); // MBL 02.06.2020
   1946 			Speak(VOX_SHIP_LOST, House, Center_Coord());
   1947 		} else {
   1948 			// Speak(VOX_UNIT_LOST); // MBL 02.06.2020
   1949 			Speak(VOX_UNIT_LOST, House, Center_Coord());
   1950 		}
   1951 	}
   1952 }
   1953 
   1954 
   1955 /***********************************************************************************************
   1956  * FootClass::Greatest_Threat -- Fetches the greatest threat to this object.                   *
   1957  *                                                                                             *
   1958  *    This routine will return with the greatest threat (best target) for this object. For     *
   1959  *    movable ground object, they won't automatically return ANY target if this object is      *
   1960  *    cloaked. Otherwise, cloaking is relatively useless.                                      *
   1961  *                                                                                             *
   1962  * INPUT:   method   -- The request method (bit flags) to use when scanning for a target.      *
   1963  *                                                                                             *
   1964  * OUTPUT:  Returns with the best target to attack. If there is no target that qualifies, then *
   1965  *          TARGET_NONE is returned.                                                           *
   1966  *                                                                                             *
   1967  * WARNINGS:   none                                                                            *
   1968  *                                                                                             *
   1969  * HISTORY:                                                                                    *
   1970  *   07/08/1995 JLB : Created.                                                                 *
   1971  *   07/10/1996 JLB : Handles scan range limitation.                                           *
   1972  *=============================================================================================*/
   1973 TARGET FootClass::Greatest_Threat(ThreatType method) const
   1974 {
   1975 	assert(IsActive);
   1976 
   1977 	/*
   1978 	**	If the scan is forced to be limited, then limit the scan now.
   1979 	*/
   1980 	if (IsScanLimited) {
   1981 		method = method & ~THREAT_AREA;
   1982 		method = method | THREAT_RANGE;
   1983 	}
   1984 
   1985 	/*
   1986 	**	If this object can cloak, then it won't select a target automatically.
   1987 	*/
   1988 	if (House->IsHuman && IsCloakable && Mission == MISSION_GUARD) {
   1989 		return(TARGET_NONE);
   1990 	}
   1991 
   1992 	if (!(method & (THREAT_INFANTRY|THREAT_VEHICLES|THREAT_BUILDINGS|THREAT_TIBERIUM|THREAT_BOATS|THREAT_CIVILIANS|THREAT_POWER|THREAT_FAKES|THREAT_FACTORIES|THREAT_BASE_DEFENSE))) {
   1993 		if (What_Am_I() != RTTI_VESSEL) {
   1994 			method = method | THREAT_GROUND;
   1995 		} else {
   1996 			method = method | THREAT_BOATS|THREAT_GROUND;
   1997 		}
   1998 	}
   1999 
   2000 	/*
   2001 	**	Perform the search for the target.
   2002 	*/
   2003 	TARGET target = TechnoClass::Greatest_Threat(method);
   2004 
   2005 	/*
   2006 	**	If no target could be located and this object is under scan range
   2007 	**	restrictions, then this restriction must be lifted now.
   2008 	*/
   2009 	if (IsScanLimited && target == TARGET_NONE) {
   2010 		const_cast<FootClass*>(this)->IsScanLimited = false;		// const_cast ST - 5/8/2019
   2011 	}
   2012 
   2013 	/*
   2014 	**	Return with final target found.
   2015 	*/
   2016 	return(target);
   2017 }
   2018 
   2019 
   2020 /***********************************************************************************************
   2021  * FootClass::Detach -- Detaches a target from tracking systems.                               *
   2022  *                                                                                             *
   2023  *    This routine will detach the specified target from the tracking systems of this object.  *
   2024  *    It will be removed from the navigation computer and any queued mission record.           *
   2025  *                                                                                             *
   2026  * INPUT:   target   -- The target to be removed from this object.                             *
   2027  *                                                                                             *
   2028  *          all      -- Is the unit really about to be eliminated? If this is true then even   *
   2029  *                      friendly contact (i.e., radio) must be eliminated.                     *
   2030  *                                                                                             *
   2031  * OUTPUT:  none                                                                               *
   2032  *                                                                                             *
   2033  * WARNINGS:   none                                                                            *
   2034  *                                                                                             *
   2035  * HISTORY:                                                                                    *
   2036  *   07/18/1995 JLB : Created.                                                                 *
   2037  *   07/24/1996 JLB : Removes target from NavQueue list.                                       *
   2038  *=============================================================================================*/
   2039 void FootClass::Detach(TARGET target, bool all)
   2040 {
   2041 	assert(IsActive);
   2042 
   2043 	TechnoClass::Detach(target, all);
   2044 
   2045 	if (!SpecialFlag) {
   2046 		if (ArchiveTarget == target) {
   2047 			ArchiveTarget = TARGET_NONE;
   2048 		}
   2049 	}
   2050 
   2051 	if (SuspendedNavCom == target) {
   2052 		SuspendedNavCom = TARGET_NONE;
   2053 		SuspendedMission = MISSION_NONE;
   2054 	}
   2055 
   2056 	/*
   2057 	**	If the navigation computer is assigned to the target, then the navigation
   2058 	**	computer must be cleared.
   2059 	*/
   2060 	if (NavCom == target) {
   2061 		NavCom = TARGET_NONE;
   2062 		Path[0] = FACING_NONE;
   2063 		Restore_Mission();
   2064 	}
   2065 
   2066 	/*
   2067 	**	Remove the target from the NavQueue list as well.
   2068 	*/
   2069 	int loop_count = 0;
   2070 	for (int index = 0; index < ARRAY_SIZE(NavQueue); index++) {
   2071 		if (NavQueue[index] == target) {
   2072 			NavQueue[index] = TARGET_NONE;
   2073 			if (index < ARRAY_SIZE(NavQueue)-1) {
   2074 				memmove(&NavQueue[index], &NavQueue[index+1], ((ARRAY_SIZE(NavQueue)-index)-1) * sizeof(NavQueue[0]));
   2075 				NavQueue[ARRAY_SIZE(NavQueue)-1] = TARGET_NONE;
   2076 				index--;
   2077 			}
   2078 		}
   2079 		/*
   2080 		** Extra safety check
   2081 		*/
   2082 		loop_count++;
   2083 		if (loop_count > ARRAY_SIZE(NavQueue)) {
   2084 			break;
   2085 		}
   2086 	}
   2087 
   2088 	/*
   2089 	**	If targeting the specified object and this unit is obviously heading
   2090 	**	toward the target to get within range, then abort the path.
   2091 	*/
   2092 	if (TarCom == target && House->IsHuman) {
   2093 		Path[0] = FACING_NONE;
   2094 	}
   2095 }
   2096 
   2097 
   2098 /***********************************************************************************************
   2099  * FootClass::Offload_Tiberium_Bail -- Fetches the Tiberium to offload per step.               *
   2100  *                                                                                             *
   2101  *    This routine is called when a packet/package/bail of Tiberium needs to be offloaded      *
   2102  *    from the object. This function is overridden for those objects that can contain          *
   2103  *    Tiberium.                                                                                *
   2104  *                                                                                             *
   2105  * INPUT:   none                                                                               *
   2106  *                                                                                             *
   2107  * OUTPUT:  Returns with the number of credits offloaded from the object.                      *
   2108  *                                                                                             *
   2109  * WARNINGS:   This routine must be called multiple times in order to completely offload the   *
   2110  *             Tiberium. When this routine return 0, all Tiberium has been offloaded.          *
   2111  *                                                                                             *
   2112  * HISTORY:                                                                                    *
   2113  *   07/19/1995 JLB : Created.                                                                 *
   2114  *=============================================================================================*/
   2115 int FootClass::Offload_Tiberium_Bail(void)
   2116 {
   2117 	assert(IsActive);
   2118 
   2119 	return(0);
   2120 }
   2121 
   2122 
   2123 /***********************************************************************************************
   2124  * FootClass::Can_Enter_Cell -- Checks to see if the object can enter cell specified.          *
   2125  *                                                                                             *
   2126  *    This routine examines the specified cell to see if the object can enter it. This         *
   2127  *    function is to be overridden for objects that could have the possibility of not being    *
   2128  *    allowed to enter the cell. Typical objects at the FootClass level always return          *
   2129  *    MOVE_OK.                                                                                 *
   2130  *                                                                                             *
   2131  * INPUT:   cell     -- The cell to examine.                                                   *
   2132  *                                                                                             *
   2133  *          facing   -- The direction that this cell might be entered from.                    *
   2134  *                                                                                             *
   2135  * OUTPUT:  Returns with the move check result type. This will be MOVE_OK if there is not      *
   2136  *          blockage. There are various other values that represent other blockage types.      *
   2137  *          The value returned will indicated the most severe reason why entry into the cell   *
   2138  *          is blocked.                                                                        *
   2139  *                                                                                             *
   2140  * WARNINGS:   none                                                                            *
   2141  *                                                                                             *
   2142  * HISTORY:                                                                                    *
   2143  *   07/19/1995 JLB : Created.                                                                 *
   2144  *=============================================================================================*/
   2145 MoveType FootClass::Can_Enter_Cell(CELL , FacingType) const
   2146 {
   2147 	assert(IsActive);
   2148 
   2149 	return MOVE_OK;
   2150 }
   2151 
   2152 
   2153 /***********************************************************************************************
   2154  * FootClass::Can_Demolish -- Checks to see if this object can be sold back.                   *
   2155  *                                                                                             *
   2156  *    This routine determines if it is legal to sell the object back. A foot class object can  *
   2157  *    only be sold back if it is sitting on a repair bay.                                      *
   2158  *                                                                                             *
   2159  * INPUT:   none                                                                               *
   2160  *                                                                                             *
   2161  * OUTPUT:  Was the object successfully sold back?                                             *
   2162  *                                                                                             *
   2163  * WARNINGS:   none                                                                            *
   2164  *                                                                                             *
   2165  * HISTORY:                                                                                    *
   2166  *   08/13/1995 JLB : Created.                                                                 *
   2167  *=============================================================================================*/
   2168 bool FootClass::Can_Demolish(void) const
   2169 {
   2170 	assert(IsActive);
   2171 
   2172 	StructType sell_struct = STRUCT_NONE;
   2173 	switch (What_Am_I()) {
   2174 		case RTTI_UNIT:
   2175 			sell_struct = STRUCT_REPAIR;
   2176 			break;
   2177 		case RTTI_AIRCRAFT:
   2178 			sell_struct = STRUCT_AIRSTRIP;
   2179 			break;
   2180 		default:
   2181 			break;
   2182 	}
   2183 	if (sell_struct != STRUCT_NONE) {
   2184 		if (In_Radio_Contact() &&
   2185 			Contact_With_Whom()->What_Am_I() == RTTI_BUILDING &&
   2186 			*((BuildingClass *)Contact_With_Whom()) == sell_struct &&
   2187 			Distance(Contact_With_Whom()) < 0x0080) {
   2188 			return(true);
   2189 		}
   2190 	}
   2191 	return(TechnoClass::Can_Demolish());
   2192 }
   2193 
   2194 
   2195 /***********************************************************************************************
   2196  * FootClass::Sell_Back -- Causes this object to be sold back.                                 *
   2197  *                                                                                             *
   2198  *    When an object is sold back, a certain amount of money is refunded to the owner and then *
   2199  *    the object is removed from the game system.                                              *
   2200  *                                                                                             *
   2201  * INPUT:   control  -- The action to perform. The only supported action is "1", which means   *
   2202  *                      to sell back.                                                          *
   2203  *                                                                                             *
   2204  * OUTPUT:  none                                                                               *
   2205  *                                                                                             *
   2206  * WARNINGS:   none                                                                            *
   2207  *                                                                                             *
   2208  * HISTORY:                                                                                    *
   2209  *   08/13/1995 JLB : Created.                                                                 *
   2210  *=============================================================================================*/
   2211 void FootClass::Sell_Back(int control)
   2212 {
   2213 	assert(IsActive);
   2214 
   2215 	if (control != 0) {
   2216 		if (House == PlayerPtr) {
   2217 			Speak(VOX_UNIT_SOLD);
   2218 			Sound_Effect(VOC_CASHTURN);
   2219 		}
   2220 		House->Refund_Money(Refund_Amount());
   2221 		Stun();
   2222 		Limbo();
   2223 		delete this;
   2224 	}
   2225 }
   2226 
   2227 
   2228 /***********************************************************************************************
   2229  * FootClass::Likely_Coord -- Fetches the coordinate the object will be at shortly.            *
   2230  *                                                                                             *
   2231  *    This routine comes in handy when determining where a travelling object will be at        *
   2232  *    when considering the amount of time it would take for a normal unit to travel one cell.  *
   2233  *    Using this information, an intelligent "approach target" logic can be employed.          *
   2234  *                                                                                             *
   2235  * INPUT:   none                                                                               *
   2236  *                                                                                             *
   2237  * OUTPUT:  Returns with the coordinate the object is at or soon will be.                      *
   2238  *                                                                                             *
   2239  * WARNINGS:   none                                                                            *
   2240  *                                                                                             *
   2241  * HISTORY:                                                                                    *
   2242  *   08/13/1995 JLB : Created.                                                                 *
   2243  *=============================================================================================*/
   2244 COORDINATE FootClass::Likely_Coord(void) const
   2245 {
   2246 	assert(IsActive);
   2247 
   2248 	if (Head_To_Coord()) {
   2249 		return(Head_To_Coord());
   2250 	}
   2251 	return(Target_Coord());
   2252 }
   2253 
   2254 
   2255 /***********************************************************************************************
   2256  * FootClass::Adjust_Dest -- Adjust candidate movement cell to account for formation.          *
   2257  *                                                                                             *
   2258  *    This routine modify the specified cell if the unit is part of a formation. The           *
   2259  *    adjustment will take into consideration the formation relative offset from the           *
   2260  *    (presumed) center cell specified.                                                        *
   2261  *                                                                                             *
   2262  * INPUT:   cell  -- The cell to presume as the desired center point of the formation.         *
   2263  *                                                                                             *
   2264  * OUTPUT:  Returns with the cell that should be used as the actual destination. If this       *
   2265  *          object is part of a formation, then the cell location will be appropriately        *
   2266  *          adjusted.                                                                          *
   2267  *                                                                                             *
   2268  * WARNINGS:   none                                                                            *
   2269  *                                                                                             *
   2270  * HISTORY:                                                                                    *
   2271  *   03/11/1996 JLB : Created.                                                                 *
   2272  *=============================================================================================*/
   2273 CELL FootClass::Adjust_Dest(CELL cell) const
   2274 {
   2275 	assert(IsActive);
   2276 
   2277 	if (IsFormationMove) {
   2278 		int xdest = Cell_X(cell);
   2279 		int ydest = Cell_Y(cell);
   2280 
   2281 		int newx = Bound(XFormOffset + xdest, Map.MapCellX, Map.MapCellX + Map.MapCellWidth -1);
   2282 		int newy = Bound(YFormOffset + ydest, Map.MapCellY, Map.MapCellY + Map.MapCellHeight -1);
   2283 
   2284 		cell = XY_Cell(newx, newy);
   2285 	}
   2286 	return(cell);
   2287 }
   2288 
   2289 
   2290 /***********************************************************************************************
   2291  * FootClass::Handle_Navigation_List -- Processes the navigation queue.                        *
   2292  *                                                                                             *
   2293  *    This routine will process the navigation queue. If the queue is present and valid and    *
   2294  *    there is currently no navigation target assigned to this object, then the first entry    *
   2295  *    of the queue will be assigned. The remaining entries will move down. If the queue is     *
   2296  *    to be processed as a circular list, then the first entry is appended to the end.         *
   2297  *                                                                                             *
   2298  * INPUT:   none                                                                               *
   2299  *                                                                                             *
   2300  * OUTPUT:  none                                                                               *
   2301  *                                                                                             *
   2302  * WARNINGS:   This routine might end up assigning a movement destination.                     *
   2303  *                                                                                             *
   2304  * HISTORY:                                                                                    *
   2305  *   07/18/1996 JLB : Created.                                                                 *
   2306  *=============================================================================================*/
   2307 void FootClass::Handle_Navigation_List(void)
   2308 {
   2309 	/*
   2310 	**	The navigation queue only needs to be processed if there is
   2311 	**	currently no navigation target for this object.
   2312 	*/
   2313 	if (!Target_Legal(NavCom)) {
   2314 		TARGET target = NavQueue[0];
   2315 
   2316 		/*
   2317 		**	Check to see if the navigation queue even exists and
   2318 		**	has at least one valid entry. If it does, then process it by
   2319 		**	assigning the object's NavCom to the first entry on the list.
   2320 		*/
   2321 		if (Target_Legal(target)) {
   2322 			Assign_Destination(target);
   2323 			memmove(&NavQueue[0], &NavQueue[1], sizeof(NavQueue)-sizeof(NavQueue[0]));
   2324 			NavQueue[ARRAY_SIZE(NavQueue)-1] = TARGET_NONE;
   2325 
   2326 			/*
   2327 			**	If the navigation queue is to loop (indefinately), then append the
   2328 			**	target value from the first part to the end of the queue.
   2329 			*/
   2330 			if (IsNavQueueLoop) {
   2331 				for (int index = 0; index < ARRAY_SIZE(NavQueue); index++) {
   2332 					if (NavQueue[index] == TARGET_NONE) {
   2333 						NavQueue[index] = target;
   2334 						break;
   2335 					}
   2336 				}
   2337 			}
   2338 		}
   2339 	}
   2340 }
   2341 
   2342 
   2343 /***********************************************************************************************
   2344  * FootClass::Queue_Navigation_List -- Add a target to the objects navigation list.            *
   2345  *                                                                                             *
   2346  *    This routine will append the destination target to the object's NavQueue list. After     *
   2347  *    doing so, if the object is not doing anything important, then it will be started on      *
   2348  *    that destination. This is functionally the same as Assign_Destination, but it stores     *
   2349  *    the target to the NavQueue first.                                                        *
   2350  *                                                                                             *
   2351  * INPUT:   target   -- The movement target destination to append the queue.                   *
   2352  *                                                                                             *
   2353  * OUTPUT:  none                                                                               *
   2354  *                                                                                             *
   2355  * WARNINGS:   The queue is of finite size and any queue requests that would exceed that size  *
   2356  *             are ignored. If there are no queue entries pending and the unit is not          *
   2357  *             otherwise occupied, then the queue target might be carried directly into the    *
   2358  *             NavCom.                                                                         *
   2359  *                                                                                             *
   2360  * HISTORY:                                                                                    *
   2361  *   07/18/1996 JLB : Created.                                                                 *
   2362  *=============================================================================================*/
   2363 void FootClass::Queue_Navigation_List(TARGET target)
   2364 {
   2365 	if (Target_Legal(target)) {
   2366 		int count;
   2367 		for (count = 0; count < ARRAY_SIZE(NavQueue); count++) {
   2368 			if (!Target_Legal(NavQueue[count])) break;
   2369 		}
   2370 
   2371 		/*
   2372 		**	If the target is this object itself, then this indicates that the
   2373 		**	queue list is to be processed as a loop. Otherwise, just tack the
   2374 		**	navigation target to the end of the list.
   2375 		*/
   2376 		if (target == As_Target() && count > 0) {
   2377 			IsNavQueueLoop = true;
   2378 		} else {
   2379 			if (count == 0) {
   2380 				IsNavQueueLoop = false;
   2381 			}
   2382 			if (count < ARRAY_SIZE(NavQueue)) {
   2383 				NavQueue[count] = target;
   2384 			}
   2385 		}
   2386 
   2387 		/*
   2388 		**	If this object isn't doing anything, then start acting on the
   2389 		**	navigation queue now.
   2390 		*/
   2391 		if (!Target_Legal(NavCom) && Mission == MISSION_GUARD) {
   2392 			Enter_Idle_Mode();
   2393 		}
   2394 	}
   2395 }
   2396 
   2397 
   2398 /***********************************************************************************************
   2399  * FootClass::Clear_Navigation_List -- Clears out the navigation queue.                        *
   2400  *                                                                                             *
   2401  *    This routine will clear out any values in the navigation queue. This is the preferred    *
   2402  *    way of aborting a navigation queue for a unit. If the unit is already travelling, it     *
   2403  *    won't be interrupted by this routine.                                                    *
   2404  *                                                                                             *
   2405  * INPUT:   none                                                                               *
   2406  *                                                                                             *
   2407  * OUTPUT:  none                                                                               *
   2408  *                                                                                             *
   2409  * WARNINGS:   This will clear the navigation list but not the navigation computer. Thus a     *
   2410  *             unit will still travel to its current immediate destination.                    *
   2411  *                                                                                             *
   2412  * HISTORY:                                                                                    *
   2413  *   07/30/1996 JLB : Created.                                                                 *
   2414  *=============================================================================================*/
   2415 void FootClass::Clear_Navigation_List(void)
   2416 {
   2417 	for (int index = 0; index < ARRAY_SIZE(NavQueue); index++) {
   2418 		NavQueue[index] = TARGET_NONE;
   2419 	}
   2420 }
   2421 
   2422 
   2423 /***********************************************************************************************
   2424  * FootClass::Is_Allowed_To_Leave_Map -- Checks to see if it can leave the map and the game.   *
   2425  *                                                                                             *
   2426  *    This routine will determine if this object has permission to leave the map and thus      *
   2427  *    leave the game. Typical objects with this permission are transports used to drop of      *
   2428  *    reinforcements.                                                                          *
   2429  *                                                                                             *
   2430  * INPUT:   none                                                                               *
   2431  *                                                                                             *
   2432  * OUTPUT:  bool; Does this object have permission to travel off the map edge and leave the    *
   2433  *                game?                                                                        *
   2434  *                                                                                             *
   2435  * WARNINGS:   none                                                                            *
   2436  *                                                                                             *
   2437  * HISTORY:                                                                                    *
   2438  *   08/05/1996 JLB : Created.                                                                 *
   2439  *=============================================================================================*/
   2440 bool FootClass::Is_Allowed_To_Leave_Map(void) const
   2441 {
   2442 	/*
   2443 	**	If the unit hasn't entered the map yet, then don't allow leave the game.
   2444 	*/
   2445 	if (!IsLocked) return(false);
   2446 
   2447 	/*
   2448 	**	A unit that isn't marked as a loaner is a gift to the player. Such objects can never
   2449 	**	leave the map unless they are part of a team that gives it special permision.
   2450 	*/
   2451 	if (!IsALoaner && Mission != MISSION_RETREAT && (!Team.Is_Valid() || !Team->Is_Leaving_Map())) return(false);
   2452 
   2453 	return(true);
   2454 }
   2455 
   2456 
   2457 /***********************************************************************************************
   2458  * FootClass::Is_Recruitable -- Determine if this object is recruitable as a team members.     *
   2459  *                                                                                             *
   2460  *    This will examine this object to determine if it is suitable as a team recruit. Some     *
   2461  *    objects are disqualified if they are otherwise premptively occupied.                     *
   2462  *                                                                                             *
   2463  * INPUT:   house -- Pointer to the house that is trying to recruit this object.               *
   2464  *                                                                                             *
   2465  * OUTPUT:  bool; Is this object suitable for recruitment by a team.                           *
   2466  *                                                                                             *
   2467  * WARNINGS:   none                                                                            *
   2468  *                                                                                             *
   2469  * HISTORY:                                                                                    *
   2470  *   09/14/1996 JLB : Created.                                                                 *
   2471  *=============================================================================================*/
   2472 bool FootClass::Is_Recruitable(HouseClass const * house) const
   2473 {
   2474 	/*
   2475 	**	If not of the correct house presuasion, then recruitment is not allowed.
   2476 	*/
   2477 	if (house != NULL && house != House) {
   2478 		return(false);
   2479 	}
   2480 
   2481 	/*
   2482 	**	If the object is not a playing member of the game, then don't consider it available.
   2483 	*/
   2484 	if (IsInLimbo) {
   2485 		return(false);
   2486 	}
   2487 
   2488 	/*
   2489 	**	If it is already part of another team, then it is not available for
   2490 	**	general recruitment.
   2491 	*/
   2492 	if (Team.Is_Valid()) {
   2493 		return(false);
   2494 	}
   2495 
   2496 	/*
   2497 	**	If it is currently in a mission the precludes recruitment into a team, then
   2498 	**	return with this information.
   2499 	*/
   2500 	if (!Is_Recruitable_Mission(Mission)) {
   2501 		return(false);
   2502 	}
   2503 
   2504 	/*
   2505 	**	It was not disqualified for general team recruitment, so return that
   2506 	**	it is available.
   2507 	*/
   2508 	return(true);
   2509 }
   2510 
   2511 
   2512 /***********************************************************************************************
   2513  * FootClass::AI -- Handle general movement AI.                                                *
   2514  *                                                                                             *
   2515  *    This basically just sees if this object is within weapon range of the target and if      *
   2516  *    so, it will stop movement so that firing may commence. This prevents the occasional      *
   2517  *    case of an attacker driving right up to the defender before firing.                      *
   2518  *                                                                                             *
   2519  * INPUT:   none                                                                               *
   2520  *                                                                                             *
   2521  * OUTPUT:  none                                                                               *
   2522  *                                                                                             *
   2523  * WARNINGS:   none                                                                            *
   2524  *                                                                                             *
   2525  * HISTORY:                                                                                    *
   2526  *   09/17/1996 JLB : Created.                                                                 *
   2527  *=============================================================================================*/
   2528 void FootClass::AI(void)
   2529 {
   2530 	TechnoClass::AI();
   2531 
   2532 // FootClass::Per_Cell_Process does this function already.
   2533 #ifdef OBSOLETE
   2534 	if (IsActive) {
   2535 		if (!IsScattering && !IsTethered && !IsInLimbo && What_Am_I() != RTTI_AIRCRAFT && Target_Legal(TarCom) && In_Range(TarCom)) {
   2536 			Assign_Destination(TARGET_NONE);
   2537 		}
   2538 	}
   2539 #endif
   2540 }
   2541 
   2542 
   2543 /***********************************************************************************************
   2544  * FootClass::Is_On_Priority_Mission -- Checks to see if this object should be given priority. *
   2545  *                                                                                             *
   2546  *    Some objects are on an important mission that must succeed. If the object is on such     *
   2547  *    a mission, then it will be more aggressive in its movement action.                       *
   2548  *                                                                                             *
   2549  * INPUT:   none                                                                               *
   2550  *                                                                                             *
   2551  * OUTPUT:  bool; Is this object on a priority mission?                                        *
   2552  *                                                                                             *
   2553  * WARNINGS:   none                                                                            *
   2554  *                                                                                             *
   2555  * HISTORY:                                                                                    *
   2556  *   09/30/1996 JLB : Created.                                                                 *
   2557  *=============================================================================================*/
   2558 bool FootClass::Is_On_Priority_Mission(void) const
   2559 {
   2560 	if (Mission == MISSION_ENTER) return(true);
   2561 	return(false);
   2562 }
   2563 
   2564 
   2565 /***********************************************************************************************
   2566  * FootClass::Mission_Retreat -- Handle reatreat from map mission for mobile objects.          *
   2567  *                                                                                             *
   2568  *    This will try to make this mobile object leave the map. It does this by assigning a      *
   2569  *    movement destination that is located off the edge of the map.                            *
   2570  *                                                                                             *
   2571  * INPUT:   none                                                                               *
   2572  *                                                                                             *
   2573  * OUTPUT:  Returns with the number of game frames to delay before calling this routine        *
   2574  *          again.                                                                             *
   2575  *                                                                                             *
   2576  * WARNINGS:   none                                                                            *
   2577  *                                                                                             *
   2578  * HISTORY:                                                                                    *
   2579  *   10/05/1996 JLB : Created.                                                                 *
   2580  *=============================================================================================*/
   2581 int FootClass::Mission_Retreat(void)
   2582 {
   2583 	assert(IsActive);
   2584 
   2585 	enum {
   2586 		FIND_EDGE,
   2587 		TRAVELLING
   2588 	};
   2589 
   2590 	switch (Status) {
   2591 
   2592 		/*
   2593 		**	Find a suitable edge to travel to and then assign destination there.
   2594 		*/
   2595 		case FIND_EDGE:
   2596 			if (Target_Legal(NavCom)) {
   2597 				Status = TRAVELLING;
   2598 			} else {
   2599 
   2600 				CELL cell = 0;
   2601 
   2602 				/*
   2603 				**	If this is part of a team, then pick the edge where the team as likely
   2604 				**	entered from.
   2605 				*/
   2606 				if (Team.Is_Valid() && Team->Class->Origin != -1) {
   2607 					cell = Map.Calculated_Cell(House->Control.Edge, Team->Class->Origin, Coord_Cell(Center_Coord()), Techno_Type_Class()->Speed);
   2608 				}
   2609 
   2610 				/*
   2611 				**	If an edge hasn't been found, then try to find one that is not based on any
   2612 				**	team information.
   2613 				*/
   2614 				if (cell == 0) {
   2615 					cell = Map.Calculated_Cell(House->Control.Edge, -1, Coord_Cell(Center_Coord()), Techno_Type_Class()->Speed);
   2616 				}
   2617 
   2618 				assert(cell == 0);		// An edge cell must be found!
   2619 
   2620 				Assign_Destination(::As_Target(cell));
   2621 				Status = TRAVELLING;
   2622 			}
   2623 			break;
   2624 
   2625 		/*
   2626 		**	While travelling, monitor that all is proceeding according to plan.
   2627 		*/
   2628 		case TRAVELLING:
   2629 			if (!Target_Legal(NavCom)) {
   2630 				Status = FIND_EDGE;
   2631 			}
   2632 			break;
   2633 	}
   2634 
   2635 	return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
   2636 }