CnC_Remastered_Collection

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

INFANTRY.CPP (180034B)


      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/INFANTRY.CPP 2     3/03/97 10:35p 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 : INFANTRY.CPP                                                 *
     24  *                                                                                             *
     25  *                   Programmer : Joe L. Bostic                                                *
     26  *                                                                                             *
     27  *                   Start Date : August 15, 1994                                              *
     28  *                                                                                             *
     29  *                  Last Update : October 28, 1996 [JLB]                                       *
     30  *                                                                                             *
     31  *---------------------------------------------------------------------------------------------*
     32  * Functions:                                                                                  *
     33  *   InfantryClass::AI -- Handles the infantry non-graphic related AI processing.              *
     34  *   InfantryClass::Active_Click_With -- Handles action when clicking with infantry soldier.   *
     35  *   InfantryClass::Assign_Destination -- Gives the infantry a movement destination.           *
     36  *   InfantryClass::Assign_Target -- Gives the infantry a combat target.                       *
     37  *   InfantryClass::Can_Enter_Cell -- Determines if the infantry can enter the cell specified. *
     38  *   InfantryClass::Can_Fire -- Can the infantry fire its weapon?                              *
     39  *   InfantryClass::Class_Of -- Returns the class reference for this object.                   *
     40  *   InfantryClass::Clear_Occupy_Bit -- Clears occupy bit and given cell                       *
     41  *   InfantryClass::Debug_Dump -- Displays debug information about infantry unit.              *
     42  *   InfantryClass::Detach -- Removes the specified target from targeting computer.            *
     43  *   InfantryClass::Do_Action -- Launches the infantry into an animation sequence.             *
     44  *   InfantryClass::Doing_AI -- Handles the animation AI processing.                           *
     45  *   InfantryClass::Draw_It -- Draws a unit object.                                            *
     46  *   InfantryClass::Edge_Of_World_AI -- Detects when infantry has left the map.                *
     47  *   InfantryClass::Enter_Idle_Mode -- The infantry unit enters idle mode by this routine.     *
     48  *   InfantryClass::Fear_AI -- Process any fear related affects on this infantry.              *
     49  *   InfantryClass::Fire_At -- Fires projectile from infantry unit.                            *
     50  *   InfantryClass::Firing_AI -- Handles firing and combat AI for the infantry.                *
     51  *   InfantryClass::Full_Name -- Fetches the full name of the infantry unit.                   *
     52  *   InfantryClass::Get_Image_Data -- Fetches the image data for this infantry unit.           *
     53  *   InfantryClass::Greatest_Threat -- Determines greatest threat (target) for infantry unit.  *
     54  *   InfantryClass::InfantryClass -- The constructor for infantry objects.                     *
     55  *   InfantryClass::Init -- Initialize the infantry object system.                             *
     56  *   InfantryClass::Is_Ready_To_Random_Anima -- Checks to see if it is ready to perform an idle*
     57  *   InfantryClass::Limbo -- Performs cleanup operations needed when limboing.                 *
     58  *   InfantryClass::Mission_Attack -- Intercept attack mission for special handling.           *
     59  *   InfantryClass::Movement_AI -- This routine handles all infantry movement logic.           *
     60  *   InfantryClass::Overlap_List -- The list of cells that the infantry overlaps, but doesn't o*
     61  *   InfantryClass::Paradrop -- Handles paradropping infantry.                                 *
     62  *   InfantryClass::Per_Cell_Process -- Handles special operations that occur once per cell.   *
     63  *   InfantryClass::Random_Animate -- Randomly animate the infantry (maybe)                    *
     64  *   InfantryClass::Read_INI -- Reads units from scenario INI file.                            *
     65  *   InfantryClass::Response_Attack -- Plays infantry audio response to attack order.          *
     66  *   InfantryClass::Response_Move -- Plays infantry response to movement order.                *
     67  *   InfantryClass::Response_Select -- Plays infantry audio response due to being selected.    *
     68  *   InfantryClass::Scatter -- Causes the infantry to scatter to nearby cell.                  *
     69  *   InfantryClass::Set_Occupy_Bit -- Sets the occupy bit cell and bit pos	                    *
     70  *   InfantryClass::Set_Primary_Facing -- Change infantry primary facing -- always and instantl*
     71  *   InfantryClass::Shape_Number -- Fetch the shape number for this infantry.                  *
     72  *   InfantryClass::Start_Driver -- Handles giving immediate destination and move orders.      *
     73  *   InfantryClass::Stop_Driver -- Stops the infantry from moving any further.                 *
     74  *   InfantryClass::Take_Damage -- Applies damage to the infantry unit.                        *
     75  *   InfantryClass::Unlimbo -- Unlimbo infantry unit in legal sub-location.                    *
     76  *   InfantryClass::What_Action -- Determines what action to perform for the cell specified.   *
     77  *   InfantryClass::What_Action -- Infantry units might be able to capture -- check.           *
     78  *   InfantryClass::Write_INI -- Store the infantry to the INI database.                       *
     79  *   InfantryClass::operator delete -- Returns the infantry object back to the free pool       *
     80  *   InfantryClass::operator new -- Allocates an infantry object from the free pool.           *
     81  *   InfantryClass::~InfantryClass -- Default destructor for infantry units.                   *
     82  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     83 
     84 #include	"function.h"
     85 
     86 /*
     87 ** New sidebar for GlyphX multiplayer. ST - 8/7/2019 10:10AM
     88 */
     89 #include "SidebarGlyphx.h"
     90 
     91 
     92 int const InfantryClass::HumanShape[32] = {0,0,7,7,7,7,6,6,6,6,5,5,5,5,5,4,4,4,3,3,3,3,2,2,2,2,1,1,1,1,1,0};
     93 
     94 
     95 /***************************************************************************
     96 ** This is the array of constant data associated with infantry maneuvers. It
     97 **	specifies the frame rate as well as if the animation can be aborted.
     98 */
     99 // interruptible, mobile, randomstart, rate
    100 DoStruct const InfantryClass::MasterDoControls[DO_COUNT] = {
    101 	{true,	false,	false,	0},	// DO_STAND_READY
    102 	{true,	false,	false,	0},	// DO_STAND_GUARD
    103 	{true,	false,	false,	0},	// DO_PRONE
    104 	{true,	true,		true,		2},	// DO_WALK
    105 	{true,	false,	false,	1},	// DO_FIRE_WEAPON
    106 	{false,	true,		false,	2},	// DO_LIE_DOWN
    107 	{true,	true,		true,		2},	// DO_CRAWL
    108 	{false,	false,	false,	3},	// DO_GET_UP
    109 	{true,	false,	false,	1},	// DO_FIRE_PRONE
    110 	{true,	false,	false,	2},	// DO_IDLE1
    111 	{true,	false,	false,	2},	// DO_IDLE2
    112 	{false,	false,	false,	2},	// DO_GUN_DEATH
    113 	{false,	false,	false,	2},	// DO_EXPLOSION_DEATH
    114 	{false,	false,	false,	2},	// DO_EXPLOSION2_DEATH
    115 	{false,	false,	false,	2},	// DO_GRENADE_DEATH
    116 	{false,	false,	false,	2},	// DO_FIRE_DEATH
    117 	{false,	false,	false,	2},	// DO_GESTURE1
    118 	{false,	false,	false,	2},	// DO_SALUTE1
    119 	{false,	false,	false,	2},	// DO_GESTURE2
    120 	{false,	false,	false,	2},	// DO_SALUTE2
    121 	{false,	false,	false,	2},	// DO_DOG_MAUL
    122 };
    123 
    124 
    125 #ifdef CHEAT_KEYS
    126 /***********************************************************************************************
    127  * InfantryClass::Debug_Dump -- Displays debug information about infantry unit.                *
    128  *                                                                                             *
    129  *    This routine is used by the debug version to display pertinent information about the     *
    130  *    infantry unit.                                                                           *
    131  *                                                                                             *
    132  * INPUT:   mono  -- The monochrome screen to display the debug information to.                *
    133  *                                                                                             *
    134  * OUTPUT:  none                                                                               *
    135  *                                                                                             *
    136  * WARNINGS:   none                                                                            *
    137  *                                                                                             *
    138  * HISTORY:                                                                                    *
    139  *   09/01/1994 JLB : Created.                                                                 *
    140  *=============================================================================================*/
    141 void InfantryClass::Debug_Dump(MonoClass * mono) const
    142 {
    143 	assert(Infantry.ID(this) == ID);
    144 	assert(IsActive);
    145 
    146 	mono->Set_Cursor(0, 0);
    147 
    148 	mono->Print(Text_String(TXT_DEBUG_INFANTRY));
    149 	mono->Set_Cursor(1, 11);mono->Printf("%3d", Doing);
    150 	mono->Set_Cursor(8, 11);mono->Printf("%3d", Fear);
    151 
    152 	mono->Fill_Attrib(66, 13, 12, 1, IsTechnician ? MonoClass::INVERSE : MonoClass::NORMAL);
    153 	mono->Fill_Attrib(66, 14, 12, 1, IsStoked ? MonoClass::INVERSE : MonoClass::NORMAL);
    154 	mono->Fill_Attrib(66, 15, 12, 1, IsProne ? MonoClass::INVERSE : MonoClass::NORMAL);
    155 
    156 	FootClass::Debug_Dump(mono);
    157 }
    158 #endif
    159 
    160 
    161 /***********************************************************************************************
    162  * InfantryClass::InfantryClass -- The constructor for infantry objects.                       *
    163  *                                                                                             *
    164  *    This is the constructor used when creating an infantry unit. All values are required     *
    165  *    except for facing and position. If these are absent, then the infantry is created in     *
    166  *    a state of limbo -- not placed upon the map.                                             *
    167  *                                                                                             *
    168  * INPUT:   see below...                                                                       *
    169  *                                                                                             *
    170  * OUTPUT:  none                                                                               *
    171  *                                                                                             *
    172  * WARNINGS:   none                                                                            *
    173  *                                                                                             *
    174  * HISTORY:                                                                                    *
    175  *   09/01/1994 JLB : Created.                                                                 *
    176  *=============================================================================================*/
    177 InfantryClass::InfantryClass(InfantryType classid, HousesType house) :
    178 	FootClass(RTTI_INFANTRY, Infantry.ID(this), house),
    179 	Class(InfantryTypes.Ptr((int)classid)),
    180 	Doing(DO_NOTHING),
    181 	Comment(0),
    182 	IsTechnician(false),
    183 	IsStoked(false),
    184 	IsProne(false),
    185 	IsZoneCheat(false),
    186 	WasSelected(false),
    187 	Fear(FEAR_NONE),
    188 	StopDriverFrame(-1),
    189 	LookCell(0)
    190 {
    191 	House->Tracking_Add(this);
    192 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
    193 	IsCloakable = Class->IsCloakable;
    194 #endif
    195 	/*
    196 	**	For two shooters, clear out the second shot flag -- it will be set the first time
    197 	**	the object fires. For non two shooters, set the flag since it will never be cleared
    198 	**	and the second shot flag tells the system that normal rearm times apply -- this is
    199 	**	what is desired for non two shooters.
    200 	*/
    201 	if (Class->Is_Two_Shooter()) {
    202 		IsSecondShot = false;
    203 	} else {
    204 		IsSecondShot = true;
    205 	}
    206 	Strength = Class->MaxStrength;
    207 
    208 	/*
    209 	**	Civilians carry much less ammo than soldiers do.
    210 	*/
    211 	Ammo = Class->MaxAmmo;
    212 }
    213 
    214 
    215 /***********************************************************************************************
    216  * InfantryClass::~InfantryClass -- Default destructor for infantry units.                     *
    217  *                                                                                             *
    218  *    This is the default destructor for infantry type units. It will put the infantry into    *
    219  *    a limbo state if it isn't already in that state and the game is still active.            *
    220  *                                                                                             *
    221  * INPUT:   none                                                                               *
    222  *                                                                                             *
    223  * OUTPUT:  none                                                                               *
    224  *                                                                                             *
    225  * WARNINGS:   none                                                                            *
    226  *                                                                                             *
    227  * HISTORY:                                                                                    *
    228  *   01/10/1995 JLB : Created.                                                                 *
    229  *=============================================================================================*/
    230 InfantryClass::~InfantryClass(void)
    231 {
    232 	if (GameActive && Class.Is_Valid()) {
    233 
    234 		/*
    235 		**	Remove this member from any team it may be associated with. This must occur at the
    236 		**	top most level of the inheritance hierarchy because it may call virtual functions.
    237 		*/
    238 		if (Team.Is_Valid()) {
    239 			Team->Remove(this);
    240 			Team = NULL;
    241 		}
    242 
    243 		House->Tracking_Remove(this);
    244 		Limbo();
    245 	}
    246 	ID = -1;
    247 }
    248 
    249 
    250 /***********************************************************************************************
    251  * InfantryClass::operator new -- Allocates an infantry object from the free pool.             *
    252  *                                                                                             *
    253  *    This will allocate an infantry object from the infantry object free pool. If there is    *
    254  *    no available slot, then NULL is returned.                                                *
    255  *                                                                                             *
    256  * INPUT:   none                                                                               *
    257  *                                                                                             *
    258  * OUTPUT:  Returns with a pointer to the allocated infantry object or NULL if none could be   *
    259  *          allocated.                                                                         *
    260  *                                                                                             *
    261  * WARNINGS:   none                                                                            *
    262  *                                                                                             *
    263  * HISTORY:                                                                                    *
    264  *   09/01/1994 JLB : Created.                                                                 *
    265  *=============================================================================================*/
    266 void * InfantryClass::operator new(size_t)
    267 {
    268 	void * ptr = Infantry.Allocate();
    269 	if (ptr != NULL) {
    270 		((InfantryClass *)ptr)->Set_Active();
    271 	}
    272 	return(ptr);
    273 }
    274 
    275 
    276 /***********************************************************************************************
    277  * InfantryClass::operator delete -- Returns the infantry object back to the free pool         *
    278  *                                                                                             *
    279  *    This routine is used return an infantry object back to the system.                       *
    280  *                                                                                             *
    281  * INPUT:   ptr   -- Pointer to the infantry object to delete.                                 *
    282  *                                                                                             *
    283  * OUTPUT:  none                                                                               *
    284  *                                                                                             *
    285  * WARNINGS:   none                                                                            *
    286  *                                                                                             *
    287  * HISTORY:                                                                                    *
    288  *   09/08/1994 JLB : Created.                                                                 *
    289  *=============================================================================================*/
    290 void InfantryClass::operator delete(void * ptr)
    291 {
    292 	if (ptr != NULL) {
    293 		((InfantryClass *)ptr)->IsActive = false;
    294 	}
    295 	Infantry.Free((InfantryClass *)ptr);
    296 }
    297 
    298 
    299 /***********************************************************************************************
    300  * InfantryClass::Take_Damage -- Applies damage to the infantry unit.                          *
    301  *                                                                                             *
    302  *    This routine applies the damage specified to the infantry object. It is possible that    *
    303  *    this routine will DESTROY the infantry unit in the process.                              *
    304  *                                                                                             *
    305  * INPUT:   damage   -- The damage points to inflict.                                          *
    306  *                                                                                             *
    307  *          distance -- The distance from the damage center point to the object's center point.*
    308  *                                                                                             *
    309  *          warhead  -- The warhead type that is inflicting the damage.                        *
    310  *                                                                                             *
    311  *          source   -- Who is responsible for inflicting the damage.                          *
    312  *                                                                                             *
    313  * OUTPUT:  bool; Was the infantry unit destroyed by this damage?                              *
    314  *                                                                                             *
    315  * WARNINGS:   Since the infantry unit could be destroyed by this routine, be sure to check    *
    316  *             for this in the code that follows the call to Take_Damage().                    *
    317  *                                                                                             *
    318  * HISTORY:                                                                                    *
    319  *   09/08/1994 JLB : Created.                                                                 *
    320  *   11/22/1994 JLB : Shares base damage handler for techno objects.                           *
    321  *   03/31/1995 JLB : Revenge factor.                                                          *
    322  *=============================================================================================*/
    323 ResultType InfantryClass::Take_Damage(int & damage, int distance, WarheadType warhead, TechnoClass * source, bool forced)
    324 {
    325 	assert(Infantry.ID(this) == ID);
    326 	assert(IsActive);
    327 
    328 	ResultType res = RESULT_NONE;
    329 
    330 	/*
    331 	**	Prone infantry take only half damage, but never below one damage point.
    332 	*/
    333 	if (IsProne && damage > 0) {
    334 		damage = damage * Rule.ProneDamageBias;
    335 	}
    336 
    337 	/*
    338 	** If we're taking damage from a dog, we have to decide if we're the
    339 	** target of the dog.  Dogs don't spill collateral damage onto anyone
    340 	** else, so if we're the target of a valid dog, take full damage, but if
    341 	** we're not the target, or the dog doesn't exist, then take no damage.
    342 	*/
    343 	if (source != NULL && source->What_Am_I() == RTTI_INFANTRY && ((InfantryClass *)source)->Class->IsDog) {
    344 		if (source->TarCom == As_Target()) {
    345 			damage = Strength;
    346 		} else {
    347 			damage = 0;
    348 		}
    349 	}
    350 	res = FootClass::Take_Damage(damage, distance, warhead, source, forced);
    351 
    352 	/*
    353 	** hack for dog: if you're hit by a dog, and you're the target, your
    354 	** damage gets upped to max.
    355 	*/
    356 
    357 	if (res == RESULT_NONE) return(res);
    358 
    359 	if (res == RESULT_DESTROYED) {
    360 		if (*this == INFANTRY_TANYA) {
    361 			IsTanyaDead = true;
    362 		}
    363 		Death_Announcement(source);
    364 		Stop_Driver();
    365 		Stun();
    366 		Mission = MISSION_NONE;
    367 		Assign_Mission(MISSION_GUARD);
    368 		Commence();
    369 
    370 		VocType sound;
    371 		VocType altsound;
    372 		sound = Sim_Random_Pick(VOC_SCREAM1, VOC_SCREAM11);
    373 		altsound = VOC_YELL1;
    374 		if (*this == INFANTRY_TANYA) {
    375 			sound = altsound = VOC_TANYA_DIE;
    376 		}
    377 		if (Class->IsDog) {
    378 			sound = altsound = VOC_DOG_HURT;
    379 		}
    380 
    381 		/*
    382 		**	The type of warhead determines the animation the infantry
    383 		**	will perform when killed.
    384 		*/
    385 		bool delthis = false;
    386 		TARGET us = As_Target();
    387 		switch (WarheadTypeClass::As_Pointer(warhead)->InfantryDeath) {
    388 			default:
    389 			case 0:
    390 				delthis = true;
    391 				break;
    392 
    393 			case 1:
    394 				Sound_Effect(sound, Coord);
    395 				Do_Action(DO_GUN_DEATH, true);
    396 				break;
    397 
    398 			case 2:
    399 				Sound_Effect(sound, Coord);
    400 				Do_Action(DO_EXPLOSION_DEATH, true);
    401 				break;
    402 
    403 			case 3:
    404 				Sound_Effect(sound, Coord);
    405 				Do_Action(DO_GRENADE_DEATH, true);
    406 				break;
    407 
    408 			case 4:
    409 				Sound_Effect(altsound, Coord);
    410 				Do_Action(DO_FIRE_DEATH, true);
    411 				break;
    412 
    413 			case 5:
    414 				Sound_Effect(sound, Coord);
    415 				AnimType anim = ANIM_ELECT_DIE;
    416 				if (Class->IsDog) anim = ANIM_DOG_ELECT_DIE;
    417 				new AnimClass(anim, Coord);
    418 				delthis = true;
    419 				break;
    420 		}
    421 
    422 		if (delthis) {
    423 			delete this;
    424 		}
    425 		return(res);
    426 	}
    427 
    428 	/*
    429 	**	When infantry gets hit, it gets scared.
    430 	*/
    431 	if (res != RESULT_DESTROYED) {
    432 		COORDINATE source_coord = (source) ? source->Coord : NULL;
    433 
    434 		/*
    435 		**	If an engineer is damaged and it is just sitting there, then tell it
    436 		**	to go do something since it will definitely die if it doesn't.
    437 		*/
    438 		if (!House->IsHuman && *this == INFANTRY_RENOVATOR && (Mission == MISSION_GUARD || Mission == MISSION_GUARD_AREA)) {
    439 			Assign_Mission(MISSION_HUNT);
    440 		}
    441 
    442 		if (source != NULL) {
    443 			Scatter(source_coord);
    444 		}
    445 
    446 		if (source != NULL && Fear < FEAR_SCARED) {
    447 			if (Class->IsFraidyCat) {
    448 				Fear = FEAR_PANIC;
    449 			} else {
    450 				Fear = FEAR_SCARED;
    451 			}
    452 		} else {
    453 
    454 			/*
    455 			**	Increase the fear of the infantry by a bit. The fear increases more
    456 			**	quickly if the infantry is damaged.
    457 			*/
    458 			int morefear = FEAR_ANXIOUS;
    459 			if (Health_Ratio() > Rule.ConditionRed) morefear /= 2;
    460 			if (Health_Ratio() > Rule.ConditionYellow) morefear /= 2;
    461 			Fear = FearType(min((int)Fear + morefear, FEAR_MAXIMUM));
    462 		}
    463 	}
    464 	return(res);
    465 }
    466 
    467 
    468 /***********************************************************************************************
    469  * InfantryClass::Shape_Number -- Fetch the shape number for this infantry.                    *
    470  *                                                                                             *
    471  *    This will determine the shape number to use for this infantry soldier. The shape number  *
    472  *    is relative to the shape file associated with this infantry unit.                        *
    473  *                                                                                             *
    474  * INPUT:   Window we will be drawing into                                                     *
    475  *                                                                                             *
    476  * OUTPUT:  Returns with the shape number for this infantry object to be used when drawing.    *
    477  *                                                                                             *
    478  * WARNINGS:   none                                                                            *
    479  *                                                                                             *
    480  * HISTORY:                                                                                    *
    481  *   07/29/1996 JLB : Created.                                                                 *
    482  *   9/4/2019 1:45PM ST : Added window parameter                                               *
    483  *=============================================================================================*/
    484 int InfantryClass::Shape_Number(WindowNumberType window) const
    485 {
    486 	/*
    487 	**	Fetch the shape pointer to use for the infantry. This is controlled by what
    488 	**	choreograph sequence the infantry is performing, it's facing, and whether it
    489 	**	is prone.
    490 	*/
    491 	DoType doit = Doing;
    492 	if (doit == DO_NOTHING) doit = DO_STAND_READY;
    493 
    494 	/*
    495 	** Hold the walk pose for a couple of frames after we come to a stop to try and avoid the problem where a moving infantry
    496 	** goes into the stand pose for a single frame when pausing in the assigned cell destination. ST - 9/4/2019 1:39PM
    497 	*/
    498 	if (doit == DO_STAND_READY) {
    499 		if (window == WINDOW_VIRTUAL) {
    500 			if (StopDriverFrame != -1) {
    501 				if (Frame - StopDriverFrame <= 2) {
    502 					if (Path[0] != FACING_NONE) {
    503 						doit = DO_WALK;
    504 					}
    505 				}
    506 			}
    507 		}					  
    508 	}
    509 
    510 	/*
    511 	** The animation frame numbers may be different when rendering in legacy mode vs. exporting for render in GlyphX. ST - 9/5/2019 12:34PM
    512 	*/
    513 	const DoInfoStruct *do_controls = (window == WINDOW_VIRTUAL) ? Class->DoControlsVirtual : Class->DoControls;
    514 	if (window != WINDOW_VIRTUAL && !IsOwnedByPlayer && *this == INFANTRY_SPY) {
    515 		do_controls = InfantryTypeClass::As_Reference(INFANTRY_E1).DoControls;
    516 	}
    517 			
    518 	/*
    519 	**	The infantry shape is always modulo the number of animation frames
    520 	**	of the action stage that the infantry is doing.
    521 	*/
    522 	int shapenum = Fetch_Stage() % max(do_controls[doit].Count, 1);
    523 
    524 	/*
    525 	**	If facing makes a difference, then the shape number will be incremented
    526 	**	by the facing accordingly.
    527 	*/
    528 	if (do_controls[doit].Jump) {
    529 		shapenum += HumanShape[Dir_To_32(PrimaryFacing.Current())] * do_controls[doit].Jump;
    530 	}
    531 	
    532 	/*
    533 	**	Finally, the shape number is biased according to the starting frame number for
    534 	**	that action in the infantry shape file.
    535 	*/
    536 	shapenum += do_controls[doit].Frame;
    537 
    538 	/*
    539 	**	Return with the final infantry shape number.
    540 	*/
    541 	return(shapenum);
    542 }
    543 
    544 
    545 /***********************************************************************************************
    546  * InfantryClass::Draw_It -- Draws a unit object.                                              *
    547  *                                                                                             *
    548  *    This routine is the one that actually draws a unit object. It displays the unit          *
    549  *    according to its current state flags and centered at the location specified.             *
    550  *                                                                                             *
    551  * INPUT:   x,y   -- The X and Y coordinate of where to draw the unit.                         *
    552  *                                                                                             *
    553  *          window   -- The clipping window to use.                                            *
    554  *                                                                                             *
    555  * OUTPUT:  none                                                                               *
    556  *                                                                                             *
    557  * WARNINGS:   none                                                                            *
    558  *                                                                                             *
    559  * HISTORY:                                                                                    *
    560  *   06/20/1994 JLB : Created.                                                                 *
    561  *   06/27/1994 JLB : Takes a window parameter.                                                *
    562  *   08/15/1994 JLB : Converted to infantry support.                                           *
    563  *   08/14/1996 JLB : Simplified.                                                              *
    564  *=============================================================================================*/
    565 void InfantryClass::Draw_It(int x, int y, WindowNumberType window) const
    566 {
    567 	assert(Infantry.ID(this) == ID);
    568 	assert(IsActive);
    569 
    570 	/*
    571 	**	Verify the legality of the unit class by seeing if there is shape imagery for it. If
    572 	**	there is no shape image, then it certainly can't be drawn -- bail.
    573 	*/
    574 	void const * shapefile = Get_Image_Data();
    575 
    576 	if (shapefile == NULL) return;
    577 
    578 	y += 4;
    579 	x -= 2;
    580 
    581 	/*
    582 	**	Actually draw the root body of the unit.
    583 	*/
    584 	Techno_Draw_Object(shapefile, Shape_Number(window), x, y, window);
    585 
    586 	FootClass::Draw_It(x, y, window);
    587 }
    588 
    589 extern bool MPSuperWeaponDisable;
    590 
    591 /***********************************************************************************************
    592  * InfantryClass::Per_Cell_Process -- Handles special operations that occur once per cell.     *
    593  *                                                                                             *
    594  *    This routine will handle any special operations that need to be performed once each      *
    595  *    cell travelled. This includes radioing a transport that it is now clear and the          *
    596  *    transport is free to leave.                                                              *
    597  *                                                                                             *
    598  * INPUT:   why   -- Specifies the circumstances under which this routine was called.          *
    599  *                                                                                             *
    600  * OUTPUT:  none                                                                               *
    601  *                                                                                             *
    602  * WARNINGS:   none                                                                            *
    603  *                                                                                             *
    604  * HISTORY:                                                                                    *
    605  *   09/08/1994 JLB : Created.                                                                 *
    606  *   03/01/1995 JLB : Capture building options.                                                *
    607  *   05/31/1995 JLB : Capture is always successful now.                                        *
    608  *=============================================================================================*/
    609 void InfantryClass::Per_Cell_Process(PCPType why)
    610 {
    611 	assert(Infantry.ID(this) == ID);
    612 	assert(IsActive);
    613 
    614 	BStart(BENCH_PCP);
    615 	CellClass * cellptr = &Map[Coord];
    616 
    617 	if (why == PCP_END) {
    618 
    619 		/*
    620 		**	If the infantry unit is entering a cell that contains the building it is trying to
    621 		**	capture, then capture it.
    622 		*/
    623 		if (Mission == MISSION_CAPTURE) {
    624 			TechnoClass * tech = cellptr->Cell_Building();
    625 			if (tech != NULL) {
    626 				if ((tech->As_Target() == NavCom || tech->As_Target() == TarCom) && !tech->Can_Capture()) {
    627 					tech = NULL;
    628 					Assign_Destination(TARGET_NONE);
    629 				}
    630 			} else {
    631 				tech = cellptr->Cell_Techno();
    632 			}
    633 			if (tech != NULL && (tech->As_Target() == NavCom || tech->As_Target() == TarCom)) {
    634 				if (*this == INFANTRY_RENOVATOR) {
    635 
    636 					/*
    637 					**	An engineer will either mega-repair a friendly or allied
    638 					**	building or it will damage/capture an enemy building. Whether
    639 					**	it damages or captures depends on how badly damaged the
    640 					**	enemy building is.
    641 					*/
    642 #ifdef FIXIT_ENGINEER_CAPTURE
    643 					if (House->Is_Ally(tech)) {
    644 #else
    645 					if (tech->House->Is_Ally(House)) {
    646 #endif
    647 						if (tech->Trigger.Is_Valid()) {
    648 							tech->Trigger->Spring(TEVENT_PLAYER_ENTERED, this);
    649 						}
    650 						tech->Renovate();
    651 					} else {
    652 						bool iscapturable = false;
    653 						if (tech->What_Am_I() == RTTI_BUILDING) {
    654 							iscapturable = tech->Can_Capture();
    655 						}
    656 #ifdef FIXIT_ENGINEER	//	checked - ajw 9/28/98
    657 						if (tech->Health_Ratio() <= EngineerCaptureLevel && iscapturable) {
    658 #else
    659 						if (tech->Health_Ratio() <= Rule.ConditionRed && iscapturable) {
    660 #endif
    661 							if (tech->Trigger.Is_Valid()) {
    662 								tech->Trigger->Spring(TEVENT_PLAYER_ENTERED, this);
    663 							}
    664 							tech->House->IsThieved = true;
    665 							tech->Captured(House);
    666 						} else {
    667 #ifdef FIXIT_ENGINEER	//	checked - ajw 9/28/98
    668 							int damage = min( (short)((int)(tech->Techno_Type_Class()->MaxStrength) * EngineerDamage), tech->Strength-1);
    669 #else
    670 							int damage = min( (tech->Techno_Type_Class()->MaxStrength) / 3, tech->Strength-1);
    671 #endif
    672 							tech->Take_Damage(damage, 0, WARHEAD_HE, this, true);
    673 						}
    674 						BEnd(BENCH_PCP);
    675 						delete this;
    676 						return;
    677 					}
    678 
    679 				} else {
    680 					if (*this != INFANTRY_SPY && tech->Trigger.Is_Valid()) {
    681 						tech->Trigger->Spring(TEVENT_PLAYER_ENTERED, this);
    682 					}
    683 
    684 					if (*this == INFANTRY_SPY) {
    685 						int housespy = (1 << (House->Class->House));
    686 //						tech->House->IsSpied = true;
    687 
    688 						if (tech->Trigger.Is_Valid()) {
    689 							tech->Trigger->Spring(TEVENT_SPIED, this);
    690 						}
    691 
    692 						if (IsOwnedByPlayer) Speak(VOX_BUILDING_INFILTRATED);
    693 
    694 						tech->Mark(MARK_OVERLAP_UP);
    695 						tech->SpiedBy |= housespy;
    696 						tech->Mark(MARK_OVERLAP_DOWN);
    697 						if (tech->What_Am_I() == RTTI_BUILDING) {
    698 							StructType build = *(BuildingClass *)tech;
    699 							if (build == STRUCT_RADAR /* || build == STRUCT_EYE */ ) {
    700 								tech->House->RadarSpied |= housespy;
    701 							}
    702 							
    703 							if (Session.Type == GAME_NORMAL || !MPSuperWeaponDisable) {
    704 							
    705 								// If they're spying on a sub pen, give 'em a sonar pulse
    706 								if (build == STRUCT_SUB_PEN) {
    707 									House->SuperWeapon[SPC_SONAR_PULSE].Enable(false, true, false);
    708 									// Add to Glyphx multiplayer sidebar. ST - 8/7/2019 10:13AM
    709 									if (Session.Type == GAME_GLYPHX_MULTIPLAYER) {
    710 										if (House->IsHuman) {
    711 											Sidebar_Glyphx_Add(RTTI_SPECIAL, SPC_SONAR_PULSE, House);
    712 										}
    713 									} else {
    714 										if (IsOwnedByPlayer) {
    715 											Map.Add(RTTI_SPECIAL, SPC_SONAR_PULSE);
    716 											Map.Column[1].Flag_To_Redraw();
    717 										}
    718 									}
    719 								}
    720 								// If they're spying on an airfield, they get Parabombs
    721 								if (build == STRUCT_AIRSTRIP) {
    722 									House->SuperWeapon[SPC_PARA_BOMB].Enable(true, true, false);
    723 									// Add to Glyphx multiplayer sidebar. ST - 8/7/2019 10:13AM
    724 									if (Session.Type == GAME_GLYPHX_MULTIPLAYER) {
    725 										if (House->IsHuman) {
    726 											Sidebar_Glyphx_Add(RTTI_SPECIAL, SPC_PARA_BOMB, House);
    727 										}
    728 									}
    729 									else {
    730 										if (IsOwnedByPlayer) {
    731 											Map.Add(RTTI_SPECIAL, SPC_PARA_BOMB);
    732 											Map.Column[1].Flag_To_Redraw();
    733 										}
    734 									}
    735 								}
    736 							}
    737 						}
    738 
    739 					} else {
    740 
    741 						if (*this == INFANTRY_THIEF) {	// Thief just raided a storage facility
    742 							tech->House->IsThieved = true;
    743 
    744 							if (tech->What_Am_I() == RTTI_BUILDING) {
    745 								BuildingClass * bldg = (BuildingClass *)tech;
    746 								if (bldg->Class->Capacity) {
    747 
    748 									/*
    749 									** If we just raided a storage facility (refinery or silo)
    750 									** then give the thief up to half the capacity of the
    751 									** storage facility.
    752 									*/
    753 									if (IsOwnedByPlayer || bldg->IsOwnedByPlayer) Speak(VOX_MONEY_STOLEN);
    754 #ifdef OBSOLETE
    755 									long capacity = bldg->Class->Capacity * 256;
    756 									capacity /= (bldg->House->Tiberium+1);
    757 									int bldgcap = bldg->Class->Capacity;
    758 
    759 									long cash = (bldgcap * 256) / (capacity+1);
    760 									if (cash > (bldgcap / 2)) cash = bldgcap / 2;
    761 #else
    762 									long cash = bldg->House->Available_Money() / 2;
    763 #endif
    764 									bldg->House->Spend_Money(cash);
    765 									House->Refund_Money(cash);
    766 								}
    767 							}
    768 						}
    769 					}
    770 				}
    771 				BEnd(BENCH_PCP);
    772 				delete this;
    773 				return;
    774 
    775 			} else {
    776 
    777 	#ifdef OBSOLETE
    778 				// are we trying to repair a bridge?
    779 				if (Is_Target_Cell(TarCom) ) {
    780 					CELL cell = Coord_Cell(Coord);
    781 					if (cell == ::As_Cell(NavCom)) {
    782 						TemplateType tt = cellptr->TType;
    783 						int icon = cellptr->TIcon;
    784 						int w = TemplateTypeClass::As_Reference(cellptr->TType).Width;
    785 						int h = TemplateTypeClass::As_Reference(cellptr->TType).Height;
    786 
    787 						cell -= icon % w;
    788 						cell -= MAP_CELL_W * (icon / w);
    789 						if (tt == TEMPLATE_BRIDGE1D || tt == TEMPLATE_BRIDGE2D) {
    790 							new TemplateClass(TemplateType(cellptr->TType-1), cell);
    791 							Map.Zone_Reset(MZONEF_ALL);
    792 							delete this;
    793 							return;
    794 						} else {
    795 
    796 							// Trying to repair multi-segment bridge.  Look for the
    797 							// start tile, then fix it, and determine the direction to
    798 							// go in and repair it all that way.
    799 							TemplateType newtt = TEMPLATE_BRIDGE_1A;
    800 							int xmov = -1;	// coords to move to for next template
    801 							int ymov = 2;
    802 							bool valid = false;
    803 							switch (tt) {
    804 								case TEMPLATE_BRIDGE_1B:
    805 								case TEMPLATE_BRIDGE_1C:
    806 									valid = true;
    807 									break;
    808 								case TEMPLATE_BRIDGE_2B:
    809 								case TEMPLATE_BRIDGE_2C:
    810 									newtt = TEMPLATE_BRIDGE_2A;
    811 									xmov = 2;
    812 									ymov = -1;
    813 									valid = true;
    814 									break;
    815 								case TEMPLATE_BRIDGE_3C:
    816 								case TEMPLATE_BRIDGE_3D:
    817 									newtt = TEMPLATE_BRIDGE_3A;
    818 									valid = true;
    819 									break;
    820 								case TEMPLATE_BRIDGE_3E:
    821 									newtt = TEMPLATE_BRIDGE_3A;
    822 									xmov = 2;
    823 									ymov = -1;
    824 									valid = true;
    825 									break;
    826 							}
    827 
    828 							// Did we find a valid repairable bridge piece?
    829 							if (valid) {
    830 								bool doing = true;
    831 								while (doing) {
    832 									new TemplateClass(TemplateType(newtt), cell);
    833 									cell += (MAP_CELL_W * ymov) + xmov;
    834 									if (xmov < 0) {
    835 										xmov = -1;
    836 										ymov = 1;
    837 									} else {
    838 										xmov = 1;
    839 										ymov = -1;
    840 									}
    841 									cellptr = &Map[cell];
    842 									tt = cellptr->TType;
    843 									if ((tt >= TEMPLATE_BRIDGE_3B && tt <= TEMPLATE_BRIDGE_3F) ||
    844 										  tt == TEMPLATE_BRIDGE_1B || tt == TEMPLATE_BRIDGE_1C ||
    845 										  tt == TEMPLATE_BRIDGE_2B || tt == TEMPLATE_BRIDGE_2C ) {
    846 
    847 										if (tt >= TEMPLATE_BRIDGE_3B) {
    848 											newtt = TEMPLATE_BRIDGE_3A;
    849 										} else {
    850 											if (tt < TEMPLATE_BRIDGE_2A) {
    851 												newtt = TEMPLATE_BRIDGE_1A;
    852 											} else {
    853 												newtt = TEMPLATE_BRIDGE_2A;
    854 											}
    855 										}
    856 										icon = cellptr->TIcon;
    857 										w = TemplateTypeClass::As_Reference(cellptr->TType).Width;
    858 										h = TemplateTypeClass::As_Reference(cellptr->TType).Height;
    859 
    860 										cell -= icon % w;
    861 										cell -= MAP_CELL_W * (icon / w);
    862 									} else {
    863 										doing = false;
    864 									}
    865 								}
    866 								Map.Zone_Reset(MZONEF_ALL);
    867 								delete this;
    868 								return;
    869 							}
    870 						}
    871 					}
    872 				} else {
    873 	#endif
    874 					if (!Target_Legal(NavCom)) {
    875 						Enter_Idle_Mode();
    876 						if (Map[Coord].Cell_Building()) {
    877 							Scatter(0, true);
    878 						}
    879 					}
    880 	#ifdef OBSOLETE
    881 				}
    882 	#endif
    883 			}
    884 		}
    885 
    886 		/*
    887 		**	Infantry entering a transport vehicle will break radio contact
    888 		**	at attach itself to the transporter.
    889 		*/
    890 		TechnoClass * techno = Contact_With_Whom();
    891 		if (Mission == MISSION_ENTER && techno != NULL && Coord_Cell(Coord) == Coord_Cell(techno->Coord) && techno == As_Techno(NavCom)) {
    892 			if (Transmit_Message(RADIO_IM_IN) == RADIO_ATTACH) {
    893 				Limbo();
    894 				techno->Attach(this);
    895 			}
    896 			BEnd(BENCH_PCP);
    897 			return;
    898 		}
    899 
    900 		/*
    901 		**	If the infantry unit is entering a cell that contains the building it is trying to
    902 		**	sabotage, then sabotage it.
    903 		*/
    904 		if (Mission == MISSION_SABOTAGE) {
    905 			BuildingClass * building = cellptr->Cell_Building();
    906 			if (building != NULL && building->As_Target() == NavCom) {
    907 				if (!building->IronCurtainCountDown && building->Mission != MISSION_DECONSTRUCTION) {
    908 					building->IsGoingToBlow = true;
    909 					building->Clicked_As_Target(PlayerPtr->Class->House, (Rule.C4Delay * TICKS_PER_MINUTE) / 2); // 2019/09/20 JAS - Added record of who clicked on the object
    910 					building->Clicked_As_Target(building->Owner(), (Rule.C4Delay * TICKS_PER_MINUTE) / 2);
    911 					building->CountDown = Rule.C4Delay * TICKS_PER_MINUTE;
    912 					building->WhomToRepay = As_Target();
    913 				}
    914 				NavCom = TARGET_NONE;
    915 				Do_Uncloak();
    916 				Arm = Rearm_Delay(true);
    917 				Scatter(building->Center_Coord(), true, true);	// RUN AWAY!
    918 				BEnd(BENCH_PCP);
    919 				return;
    920 			} else {
    921 				if (::As_Target(Coord_Cell(Center_Coord())) == NavCom) {
    922 					Explosion_Damage(Coord, Rule.BridgeStrength, this, WARHEAD_HE);
    923 
    924 					Stop_Driver();
    925 					Scatter(Adjacent_Cell(Coord, PrimaryFacing), true, true);
    926 					Assign_Mission(MISSION_MOVE);
    927 
    928 					CELL cell = Coord_Cell(Center_Coord());
    929 					CellClass * cellptr = &Map[cell];
    930 					if (!Target_Legal(NavCom) || Map[As_Cell(NavCom)].Land_Type() == LAND_WATER) {
    931 						Mark(MARK_DOWN);		// Needed only so that Tanya will get destroyed by the explosion.
    932 					}
    933 					Explosion_Damage(Coord, Rule.BridgeStrength, NULL, WARHEAD_HE);
    934 					Explosion_Damage(Coord, Rule.BridgeStrength, NULL, WARHEAD_HE);
    935 					if (!IsActive) {
    936 						BEnd(BENCH_PCP);
    937 						return;
    938 					}
    939 
    940 					Mark(MARK_DOWN);
    941 				}
    942 			}
    943 		}
    944 
    945 		/*
    946 		**	If this unit is on a teather, then cut it at this time so that
    947 		**	the "parent" unit is free to proceed. Note that the parent
    948 		**	unit might actually be a building.
    949 		*/
    950 		if (IsTethered) {
    951 			Transmit_Message(RADIO_UNLOADED);
    952 			if (House->ActLike == HOUSE_USSR || House->ActLike == HOUSE_UKRAINE) {
    953 				Do_Action(DO_GESTURE1);
    954 			} else  {
    955 				Do_Action(DO_GESTURE2);
    956 			}
    957 
    958 			/*
    959 			**	Special voice play.
    960 			*/
    961 			if (*this ==  INFANTRY_TANYA) {
    962 				Sound_Effect(VOC_TANYA_LAUGH, Coord);
    963 			}
    964 
    965 			/*
    966 			**	If the cell is now full of infantry, tell them all to scatter
    967 			**	in order to make room for more.
    968 			*/
    969 			if ((cellptr->Flag.Composite & 0x01F) == 0x01F) {
    970 				cellptr->Incoming(0, true, true);
    971 //				cellptr->Incoming(0, true);
    972 			}
    973 		}
    974 
    975 		/*
    976 		**	When the infantry reaches the center of the cell, it may begin a new mission.
    977 		*/
    978 		if (MissionQueue == MISSION_NONE && !Target_Legal(NavCom) && !Target_Legal(TarCom) && !In_Radio_Contact()) {
    979 			Enter_Idle_Mode();
    980 		}
    981 		Commence();
    982 
    983 		/*
    984 		** If entering a cell with a land mine in it, blow up the mine.
    985 		*/
    986 		BuildingClass * bldng = cellptr->Cell_Building();
    987 		if (bldng != NULL && *bldng == STRUCT_APMINE) {
    988 			/*
    989 			** Show the animation and get rid of the land mine
    990 			*/
    991 			COORDINATE blcoord = bldng->Center_Coord();
    992 			new AnimClass(Combat_Anim(Rule.APMineDamage, WARHEAD_HE, cellptr->Land_Type()), blcoord);
    993 			delete bldng;
    994 			int damage;
    995 			for (int index = 0; index < Infantry.Count(); index++) {
    996 				InfantryClass * obj = Infantry.Ptr(index);
    997 				if (obj != NULL && !obj->IsInLimbo) {
    998 					int dist = ::Distance(obj->Coord, blcoord);
    999 					if (dist <= 0xC0) {
   1000 						damage = Rule.APMineDamage;
   1001 						obj->Take_Damage(damage, 0, WARHEAD_HE);
   1002 					}
   1003 				}
   1004 			}
   1005 			if (!IsActive) {
   1006 				BEnd(BENCH_PCP);
   1007 				return;
   1008 			}
   1009 		}
   1010 
   1011 		/*
   1012 		**	If the last cell we looked from isn't adjacent to our current cell,
   1013 		**	perform a full look.
   1014 		*/
   1015 		CELL cell = Coord_Cell(Coord);
   1016 		if (::Distance(Cell_X(cell), Cell_Y(cell), Cell_X(LookCell), Cell_Y(LookCell)) > 1) {
   1017 			Look(false);
   1018 		} else {
   1019 			Look(true);
   1020 		}
   1021 
   1022 #if 1
   1023 /*
   1024 **	If after all is said and done, the unit finishes its move on an impassable cell, then
   1025 **	it must presume that it is in the case of a unit driving onto a bridge that blows up
   1026 **	before the unit completes it's move. In such a case the unit should have been destroyed
   1027 **	anyway, so blow it up now.
   1028 */
   1029 LandType land = Map[Coord].Land_Type();
   1030 if (!IsDriving && !Class->IsBomber && (land == LAND_ROCK || land == LAND_WATER || land == LAND_RIVER)) {
   1031 	int damage = Strength;
   1032 	Take_Damage(damage, 0, WARHEAD_AP, NULL, true);
   1033 	return;
   1034 }
   1035 #endif
   1036 
   1037 	}
   1038 
   1039 	if (IsActive) {
   1040 		FootClass::Per_Cell_Process(why);
   1041 	}
   1042 	BEnd(BENCH_PCP);
   1043 }
   1044 
   1045 
   1046 /***********************************************************************************************
   1047  * InfantryClass::Detach -- Removes the specified target from targeting computer.              *
   1048  *                                                                                             *
   1049  *    This is a support routine that removes the target specified from any targeting or        *
   1050  *    navigation computers. When a target is destroyed or removed from the game system,        *
   1051  *    the target must be removed from any tracking systems of the other units. This routine    *
   1052  *    handles removal for infantry units.                                                      *
   1053  *                                                                                             *
   1054  * INPUT:   target   -- The target to remove from the infantry unit's tracking systems.        *
   1055  *                                                                                             *
   1056  *          all      -- Is the target going away for good as opposed to just cloaking/hiding?  *
   1057  *                                                                                             *
   1058  * OUTPUT:  none                                                                               *
   1059  *                                                                                             *
   1060  * WARNINGS:   none                                                                            *
   1061  *                                                                                             *
   1062  * HISTORY:                                                                                    *
   1063  *   09/08/1994 JLB : Created.                                                                 *
   1064  *=============================================================================================*/
   1065 void InfantryClass::Detach(TARGET target, bool all)
   1066 {
   1067 	assert(Infantry.ID(this) == ID);
   1068 	assert(IsActive);
   1069 
   1070 	if (TarCom == target) {
   1071 		Mark(MARK_OVERLAP_UP);
   1072 		IsFiring = false;
   1073 		Mark(MARK_OVERLAP_DOWN);
   1074 	}
   1075 	FootClass::Detach(target, all);
   1076 }
   1077 
   1078 
   1079 /***********************************************************************************************
   1080  * InfantryClass::Init -- Initialize the infantry object system.                               *
   1081  *                                                                                             *
   1082  *    This routine will force the infantry object system into its empty initial state. It      *
   1083  *    is called when the scenario needs to be cleared in preparation for a scenario load.      *
   1084  *                                                                                             *
   1085  * INPUT:   none                                                                               *
   1086  *                                                                                             *
   1087  * OUTPUT:  none                                                                               *
   1088  *                                                                                             *
   1089  * WARNINGS:   none                                                                            *
   1090  *                                                                                             *
   1091  * HISTORY:                                                                                    *
   1092  *   09/08/1994 JLB : Created.                                                                 *
   1093  *=============================================================================================*/
   1094 void InfantryClass::Init(void)
   1095 {
   1096 	Infantry.Free_All();
   1097 }
   1098 
   1099 
   1100 /***********************************************************************************************
   1101  * InfantryClass::Assign_Destination -- Gives the infantry a movement destination.             *
   1102  *                                                                                             *
   1103  *    This routine updates the infantry's navigation computer so that the infantry will        *
   1104  *    travel to the destination target specified.                                              *
   1105  *                                                                                             *
   1106  * INPUT:   target   -- The target to have the infantry unit move to.                          *
   1107  *                                                                                             *
   1108  * OUTPUT:  none                                                                               *
   1109  *                                                                                             *
   1110  * WARNINGS:   none                                                                            *
   1111  *                                                                                             *
   1112  * HISTORY:                                                                                    *
   1113  *   09/08/1994 JLB : Created.                                                                 *
   1114  *=============================================================================================*/
   1115 void InfantryClass::Assign_Destination(TARGET target)
   1116 {
   1117 	assert(Infantry.ID(this) == ID);
   1118 	assert(IsActive);
   1119 
   1120 	/*
   1121 	**	Special flag so that infantry will start heading in the right direction immediately.
   1122 	*/
   1123 	if (IsDriving && !IsFormationMove && Target_Legal(target) && Map[Center_Coord()].Is_Clear_To_Move(Class->Speed, true, false)) {
   1124 		Stop_Driver();
   1125 	}
   1126 
   1127 	/*
   1128 	**	When telling an infantry soldier to move to a location twice, then this
   1129 	**	means that movement is more important than safety. Get up and run!
   1130 	*/
   1131 	if (House->IsHuman && Target_Legal(target) && NavCom == target && IsProne && !Class->IsFraidyCat && !Class->IsDog) {
   1132 		Do_Action(DO_GET_UP);
   1133 	}
   1134 
   1135 	/*
   1136 	** If telling a dog to attack a human, start the dog running
   1137 	*/
   1138 	TechnoClass * tech = As_Techno(target);
   1139 
   1140 	/*
   1141 	**	Handle entry logic here.
   1142 	*/
   1143 	if (Mission == MISSION_ENTER || MissionQueue == MISSION_ENTER) {
   1144 
   1145 		/*
   1146 		**	If not already in radio contact (presumed with the transport), then
   1147 		**	either try to establish contact if allowed, or just move close and
   1148 		**	wait until radio contact can be established.
   1149 		*/
   1150 		if (!In_Radio_Contact()) {
   1151 			TechnoClass * techno = As_Techno(target);
   1152 			if (techno != NULL) {
   1153 
   1154 				/*
   1155 				**	Determine if the transport is already in radio contact. If so, then just move
   1156 				**	toward the transport and try to establish contact at a later time.
   1157 				*/
   1158 				if (techno->In_Radio_Contact()) {
   1159 // TCTCTC -- call for an update from the transport to get a good rendezvous position.
   1160 
   1161 					ArchiveTarget = target;
   1162 				} else {
   1163 					if (Transmit_Message(RADIO_HELLO, techno) == RADIO_ROGER) {
   1164 						if (Transmit_Message(RADIO_DOCKING) != RADIO_ROGER) {
   1165 							Transmit_Message(RADIO_OVER_OUT);
   1166 						} else {
   1167 							//BG: keep retransmitted navcom from radio-move-here.
   1168 							return;
   1169 						}
   1170 					}
   1171 				}
   1172 			}
   1173 		} else {
   1174 			Path[0] = FACING_NONE;
   1175 		}
   1176 	} else {
   1177 		Path[0] = FACING_NONE;
   1178 	}
   1179 	FootClass::Assign_Destination(target);
   1180 }
   1181 
   1182 
   1183 /***********************************************************************************************
   1184  * InfantryClass::Assign_Target -- Gives the infantry a combat target.                         *
   1185  *                                                                                             *
   1186  *    This routine will update the infantry's targeting computer so that it will try to        *
   1187  *    attack the target specified. This might result in it moving to be within range and thus  *
   1188  *    also cause adjustment of the navigation computer.                                        *
   1189  *                                                                                             *
   1190  * INPUT:   target   -- The target that this infantry should attack.                           *
   1191  *                                                                                             *
   1192  * OUTPUT:  none                                                                               *
   1193  *                                                                                             *
   1194  * WARNINGS:   none                                                                            *
   1195  *                                                                                             *
   1196  * HISTORY:                                                                                    *
   1197  *   09/08/1994 JLB : Created.                                                                 *
   1198  *   06/30/1995 JLB : Tries to capture target if possible.                                     *
   1199  *=============================================================================================*/
   1200 void InfantryClass::Assign_Target(TARGET target)
   1201 {
   1202 	assert(Infantry.ID(this) == ID);
   1203 	assert(IsActive);
   1204 
   1205 	Path[0] = FACING_NONE;
   1206 	if (Class->IsDog) {
   1207 		if (::As_Object(target) && ::As_Object(target)->What_Am_I() != RTTI_INFANTRY) {
   1208 			target = TARGET_NONE;
   1209 		}
   1210 	}
   1211 	FootClass::Assign_Target(target);
   1212 
   1213 	/*
   1214 	**	If this is an infantry that can only capture, then also assign its destination to the
   1215 	**	target specified.
   1216 	*/
   1217 	if (!Target_Legal(NavCom) && Class->IsCapture && !Is_Weapon_Equipped()) {
   1218 		BuildingClass const * building = As_Building(target);
   1219 		if (building != NULL && building->Can_Capture()) {
   1220 			Assign_Destination(target);
   1221 		}
   1222 	}
   1223 }
   1224 
   1225 
   1226 /***********************************************************************************************
   1227  * InfantryClass::AI -- Handles the infantry non-graphic related AI processing.                *
   1228  *                                                                                             *
   1229  *    This routine is used to handle the non-graphic AI processing the infantry requires.      *
   1230  *    Call this routine ONCE per game frame.                                                   *
   1231  *                                                                                             *
   1232  * INPUT:   none                                                                               *
   1233  *                                                                                             *
   1234  * OUTPUT:  none                                                                               *
   1235  *                                                                                             *
   1236  * WARNINGS:   none                                                                            *
   1237  *                                                                                             *
   1238  * HISTORY:                                                                                    *
   1239  *   09/08/1994 JLB : Created.                                                                 *
   1240  *   08/14/1996 JLB : Simplified.                                                              *
   1241  *=============================================================================================*/
   1242 void InfantryClass::AI(void)
   1243 {
   1244 	assert(Infantry.ID(this) == ID);
   1245 	assert(IsActive);
   1246 
   1247 	FootClass::AI();
   1248 
   1249 	if (!IsActive) {
   1250 		return;
   1251 	}
   1252 
   1253 	if (IsUnloading) Mark(MARK_CHANGE_REDRAW);
   1254 
   1255 	/*
   1256 	**	Infantry that are not on the ground should always be redrawn. Such is
   1257 	**	the case when they are parachuting to the ground.
   1258 	*/
   1259 	if (In_Which_Layer() != LAYER_GROUND) {
   1260 		Mark(MARK_CHANGE);
   1261 	}
   1262 
   1263 	/*
   1264 	**	Special hack to make sure that if this infantry is in firing animation, but the
   1265 	**	stage class isn't set, then abort the firing flag.
   1266 	*/
   1267 	if (IsFiring && Fetch_Rate() == 0) {
   1268 		Mark(MARK_OVERLAP_UP);
   1269 		IsFiring = false;
   1270 		Do_Action(DO_STAND_READY);
   1271 		Mark(MARK_OVERLAP_DOWN);
   1272 	}
   1273 
   1274 	/*
   1275 	**	Delete this unit if it finds itself off the edge of the map and it is in
   1276 	**	guard or other static mission mode.
   1277 	*/
   1278 	if (Edge_Of_World_AI()) {
   1279 		return;
   1280 	}
   1281 
   1282 	/*
   1283 	**	Act on new orders if the unit is at a good position to do so.
   1284 	*/
   1285 	if (!IsFiring && !IsFalling && !IsDriving && (Doing == DO_NOTHING || MasterDoControls[Doing].Interrupt)) {
   1286 		if (Mission == MISSION_NONE && MissionQueue == MISSION_NONE) Enter_Idle_Mode();
   1287 		Commence();
   1288 	}
   1289 
   1290 	/*
   1291 	**	Special hack to make sure the dog never attacks a cell.
   1292 	*/
   1293 	if (Class->IsDog && Target_Legal(TarCom) && Is_Target_Cell(TarCom)) {
   1294 		Assign_Target(TARGET_NONE);
   1295 	}
   1296 
   1297 	/*
   1298 	**	Handle any infantry fear logic or related actions.
   1299 	*/
   1300 	Fear_AI();
   1301 
   1302 	/*
   1303 	**	Special victory dance action.
   1304 	*/
   1305 	if (!Target_Legal(NavCom) && !IsProne && IsStoked && Comment == 0) {
   1306 		IsStoked = false;
   1307 		Do_Action(Percent_Chance(50) ? DO_GESTURE1 : DO_GESTURE2);
   1308 	}
   1309 
   1310 	/*
   1311 	**	Determine if this infantry unit should fire off an
   1312 	**	attack or not.
   1313 	*/
   1314 	Firing_AI();
   1315 
   1316 	/*
   1317 	**	Handle the completion of the animation sequence.
   1318 	*/
   1319 	Doing_AI();
   1320 
   1321 	/*
   1322 	**	Perform movement operations at this time.
   1323 	*/
   1324 	Movement_AI();
   1325 }
   1326 
   1327 
   1328 /***********************************************************************************************
   1329  * InfantryClass::Can_Enter_Cell -- Determines if the infantry can enter the cell specified.   *
   1330  *                                                                                             *
   1331  *    This routine is used to examine the cell specified and determine if the infantry is      *
   1332  *    allowed to enter it. It is used by the path finding algorithm.                           *
   1333  *                                                                                             *
   1334  * INPUT:   cell  -- The cell to examine.                                                      *
   1335  *                                                                                             *
   1336  * OUTPUT:  Returns the type of blockage in the cell.                                          *
   1337  *                                                                                             *
   1338  * WARNINGS:   none                                                                            *
   1339  *                                                                                             *
   1340  * HISTORY:                                                                                    *
   1341  *   09/01/1994 JLB : Created.                                                                 *
   1342  *=============================================================================================*/
   1343 MoveType InfantryClass::Can_Enter_Cell(CELL cell, FacingType ) const
   1344 {
   1345 	assert(Infantry.ID(this) == ID);
   1346 	assert(IsActive);
   1347 
   1348 	/*
   1349 	** If we are moving into an illegal cell, then we can't do that.
   1350 	*/
   1351 	if ((unsigned)cell >= MAP_CELL_TOTAL) return(MOVE_NO);
   1352 
   1353 	/*
   1354 	**	If moving off the edge of the map, then consider that an illegal move.
   1355 	*/
   1356 	if (!ScenarioInit && !Map.In_Radar(cell) && !Is_Allowed_To_Leave_Map()) {
   1357 		return(MOVE_NO);
   1358 	}
   1359 
   1360 	CellClass * cellptr = &Map[cell];
   1361 
   1362 	/*
   1363 	**	Walls are considered impassable for infantry UNLESS the wall has a hole
   1364 	**	in it.
   1365 	*/
   1366 	if (cellptr->Overlay != OVERLAY_NONE) {
   1367 		OverlayTypeClass const & otype = OverlayTypeClass::As_Reference(cellptr->Overlay);
   1368 
   1369 		if (otype.IsCrate && !((Session.Type == GAME_NORMAL) ? House->IsPlayerControl : House->IsHuman) && Session.Type == GAME_NORMAL) {
   1370 			return(MOVE_NO);
   1371 		}
   1372 
   1373 		if (otype.IsWall) {
   1374 			if ((cellptr->OverlayData / 16) != otype.DamageLevels) {
   1375 
   1376 				/*
   1377 				**	If the wall can be destroyed, then return this fact instead of
   1378 				**	a complete failure to enter.
   1379 				*/
   1380 				if (Is_Weapon_Equipped() && Class->PrimaryWeapon->Is_Wall_Destroyer()) {
   1381 					return(MOVE_DESTROYABLE);
   1382 				}
   1383 				return(MOVE_NO);
   1384 			}
   1385 		}
   1386 	}
   1387 
   1388 	/*
   1389 	** Loop through all of the objects in the square setting a bit
   1390 	** for how they affect movement.
   1391 	*/
   1392 	MoveType retval = MOVE_OK;
   1393 	ObjectClass * obj = cellptr->Cell_Occupier();
   1394 	while (obj != NULL) {
   1395 
   1396 		if (obj != this) {
   1397 
   1398 			/*
   1399 			**	Always allow movement if the cell is the object to be captured or sabotaged.
   1400 			*/
   1401 			if (((Mission == MISSION_ENTER && In_Radio_Contact()) || Mission == MISSION_CAPTURE || Mission == MISSION_SABOTAGE) &&
   1402 				(obj->As_Target() == NavCom || obj->As_Target() == TarCom)) {
   1403 
   1404 				return(MOVE_OK);
   1405 			}
   1406 
   1407 			/*
   1408 			**	Guard area should not allow the guarding unit to enter the cell with the
   1409 			**	guarded unit.
   1410 			*/
   1411 			if (Mission == MISSION_GUARD_AREA && ArchiveTarget == obj->As_Target() && Is_Target_Unit(ArchiveTarget)) {
   1412 				return(MOVE_NO);
   1413 			}
   1414 
   1415 			/*
   1416 			** If object is a land mine, allow movement
   1417 			*/
   1418 			if (obj->What_Am_I() == RTTI_BUILDING) {
   1419 				if ((*(BuildingClass *)obj) == STRUCT_AVMINE) {
   1420 					obj = obj->Next;
   1421 					continue;
   1422 				} else {
   1423 					if (!Rule.IsMineAware || !((BuildingClass *)obj)->House->Is_Ally(House)) {
   1424 						if ((*(BuildingClass *)obj) == STRUCT_APMINE) {
   1425 							obj = obj->Next;
   1426 							continue;
   1427 						}
   1428 					}
   1429 				}
   1430 			}
   1431 
   1432 			/*
   1433 			**	Special case check so that a landed aircraft that is in radio contact, will not block
   1434 			**	a capture attempt. It is presumed that this case happens when a helicopter is landed
   1435 			**	at a helipad.
   1436 			*/
   1437 //			if ((Mission != MISSION_CAPTURE && Mission != MISSION_SABOTAGE) || obj->What_Am_I() != RTTI_AIRCRAFT || !((AircraftClass *)obj)->In_Radio_Contact()) {
   1438 
   1439 				/*
   1440 				**	Special check to always allow entry into the building that this infantry
   1441 				**	is trying to capture.
   1442 				*/
   1443 //				if (obj->What_Am_I() == RTTI_BUILDING || obj->What_Am_I() == RTTI_AIRCRAFT || obj->What_Am_I() == RTTI_UNIT) {
   1444 //					if ((Mission == MISSION_CAPTURE || Mission == MISSION_SABOTAGE) && (obj->As_Target() == NavCom || obj->As_Target() == TarCom)) {
   1445 //						return(MOVE_OK);
   1446 //					}
   1447 //				}
   1448 
   1449 				/*
   1450 				**	Special check to always allow entry into the building that this infantry
   1451 				**	is trying to capture.
   1452 				*/
   1453 				if (Mission == MISSION_ENTER && obj->As_Target() == NavCom && IsTethered) {
   1454 					return(MOVE_OK);
   1455 				}
   1456 
   1457 				/*
   1458 				**	Allied objects block movement using different rules than for enemy
   1459 				**	objects.
   1460 				*/
   1461 				if (House->Is_Ally(obj) || ScenarioInit) {
   1462 					switch (obj->What_Am_I()) {
   1463 
   1464 						/*
   1465 						**	A unit blocks as either a moving blockage or a stationary temp blockage.
   1466 						**	This depends on whether the unit is currently moving or not.
   1467 						*/
   1468 						case RTTI_UNIT:
   1469 							if (((UnitClass *)obj)->IsDriving || Target_Legal(((UnitClass *)obj)->NavCom)) {
   1470 								if (retval < MOVE_MOVING_BLOCK) retval = MOVE_MOVING_BLOCK;
   1471 							} else {
   1472 								if (retval < MOVE_TEMP) retval = MOVE_TEMP;
   1473 							}
   1474 							break;
   1475 
   1476 						/*
   1477 						**	Aircraft and buildings always block movement. If for some reason there is an
   1478 						**	allied terrain object, that blocks movement as well.
   1479 						*/
   1480 						case RTTI_TERRAIN:
   1481 						case RTTI_AIRCRAFT:
   1482 						case RTTI_BUILDING:
   1483 							return(MOVE_NO);
   1484 
   1485 						default:
   1486 							break;
   1487 					}
   1488 
   1489 				} else {
   1490 
   1491 					/*
   1492 					**	Cloaked enemy objects are not considered if this is a Find_Path()
   1493 					**	call.
   1494 					*/
   1495 					if (!obj->Is_Techno() || !((TechnoClass *)obj)->Is_Cloaked(this)) {
   1496 
   1497 						/*
   1498 						**	Any non-allied blockage is considered impassible if the infantry
   1499 						**	is not equipped with a weapon.
   1500 						*/
   1501 						if (Combat_Damage() <= 0) return(MOVE_NO);
   1502 
   1503 						/*
   1504 						**	Some kinds of terrain are considered destroyable if the infantry is equipped
   1505 						**	with the weapon that can destroy it. Otherwise, the terrain is considered
   1506 						**	impassable.
   1507 						*/
   1508 						switch (obj->What_Am_I()) {
   1509 							case RTTI_TERRAIN:
   1510 #ifdef OBSOLETE
   1511 								if (((TerrainClass *)obj)->Class->Armor == ARMOR_WOOD &&
   1512 										Class->PrimaryWeapon->WarheadPtr->IsWoodDestroyer) {
   1513 
   1514 									if (retval < MOVE_DESTROYABLE) retval = MOVE_DESTROYABLE;
   1515 								} else {
   1516 									return(MOVE_NO);
   1517 								}
   1518 								break;
   1519 #else
   1520 								return(MOVE_NO);
   1521 #endif
   1522 							case RTTI_INFANTRY:
   1523 								if ( *(InfantryClass *)obj == INFANTRY_SPY && !Class->IsDog) {
   1524 									retval = MOVE_TEMP;
   1525 									break;
   1526 								}
   1527 								// otherwise, fall thru.
   1528 							default:
   1529 								if (retval < MOVE_DESTROYABLE) retval = MOVE_DESTROYABLE;
   1530 								break;
   1531 						}
   1532 					} else {
   1533 						if (retval < MOVE_CLOAK) retval = MOVE_CLOAK;
   1534 					}
   1535 				}
   1536 //			}
   1537 		}
   1538 
   1539 		/*
   1540 		**	Move to next object in chain.
   1541 		*/
   1542 		obj = obj->Next;
   1543 	}
   1544 
   1545 	/*
   1546 	**	If foot soldiers cannot travel on the cell -- consider it impassable.
   1547 	*/
   1548 	if (retval == MOVE_OK && !IsTethered && Ground[cellptr->Land_Type()].Cost[SPEED_FOOT] == 0) {
   1549 
   1550 #ifdef OBSOLETE
   1551 		/*
   1552 		** Special case - if it's an engineer, and the cell under consideration
   1553 		** is his NavCom, and his mission is mission_capture, then he's most
   1554 		** likely moving to his final destination to repair a bridge, so we
   1555 		** should let him.
   1556 		*/
   1557 		if (*this == INFANTRY_RENOVATOR && Is_Target_Cell(TarCom) && (cell == ::As_Cell(NavCom)) && (cellptr->TType == TEMPLATE_BRIDGE1D || cellptr->TType == TEMPLATE_BRIDGE2D || (cellptr->TType >= TEMPLATE_BRIDGE_1C && cellptr->TType <= TEMPLATE_BRIDGE_3E) ) ) {
   1558 			return(MOVE_OK);
   1559 		}
   1560 #endif
   1561 		return(MOVE_NO);
   1562 	}
   1563 
   1564 	/*
   1565 	** if a unit has the cell reserved then we just can't go in there.
   1566 	*/
   1567 	if (retval == MOVE_OK && cellptr->Flag.Occupy.Vehicle) {
   1568 		return(MOVE_NO);
   1569 	}
   1570 
   1571 	/*
   1572 	** if a block of infantry has the cell reserved then there are two
   1573 	** possibilities...
   1574 	*/
   1575 	if (cellptr->InfType != HOUSE_NONE) {
   1576 		if (House->Is_Ally(cellptr->InfType)) {
   1577 			if ((cellptr->Flag.Composite & 0x1F) == 0x1f) {
   1578 				if (retval < MOVE_MOVING_BLOCK) retval = MOVE_MOVING_BLOCK;
   1579 			}
   1580 		} else {
   1581 			if (Combat_Damage() > 0) {
   1582 				if (retval < MOVE_DESTROYABLE) {
   1583 					retval = MOVE_DESTROYABLE;
   1584 				}
   1585 			} else {
   1586 				return(MOVE_NO);
   1587 			}
   1588 		}
   1589 	}
   1590 
   1591 	/*
   1592 	**	If it is still ok to move the infantry, then perform the last check
   1593 	**	to see if the cell is already full of infantry.
   1594 	*/
   1595 	if (retval == MOVE_OK && (cellptr->Flag.Composite & 0x1F) == 0x1F) {
   1596 		return(MOVE_NO);
   1597 	}
   1598 
   1599 	/*
   1600 	**	Return with the most severe reason why this cell would be impassable.
   1601 	*/
   1602 	return(retval);
   1603 }
   1604 
   1605 
   1606 /***********************************************************************************************
   1607  * InfantryClass::Overlap_List -- The list of cells that the infantry overlaps, but doesn't occ*
   1608  *                                                                                             *
   1609  *    This is a rendering support routine that will return a pointer to a list of cell offsets *
   1610  *    that specify the cells the infantry unit is currently overlapping (graphic wise) but     *
   1611  *    is not considered to occupy. This list is used to update the map display.                *
   1612  *                                                                                             *
   1613  * INPUT:   none                                                                               *
   1614  *                                                                                             *
   1615  * OUTPUT:  Returns a pointer to an offset list for cells that the unit overlaps but doesn't   *
   1616  *          occupy.                                                                            *
   1617  *                                                                                             *
   1618  * WARNINGS:   none                                                                            *
   1619  *                                                                                             *
   1620  * HISTORY:                                                                                    *
   1621  *   09/01/1994 JLB : Created.                                                                 *
   1622  *=============================================================================================*/
   1623 #ifdef PARTIAL
   1624 short const * InfantryClass::Overlap_List(bool redraw) const
   1625 #else
   1626 short const * InfantryClass::Overlap_List(bool ) const
   1627 #endif
   1628 {
   1629 	assert(Infantry.ID(this) == ID);
   1630 	assert(IsActive);
   1631 
   1632 	if (Class->IsDog) {
   1633 		return(Coord_Spillage_List(Coord, 24 + (Doing == DO_DOG_MAUL ? 40 : 0) + (Doing >= DO_GUN_DEATH && Doing <= DO_FIRE_DEATH ? 40 : 0) ));
   1634 	} else {
   1635 
   1636 		/*
   1637 		**	The default infantry rectangle will be as large as the largest shape the infantry
   1638 		**	can be.
   1639 		*/
   1640 
   1641 #ifdef PARTIAL
   1642 		Rect rect(-16, -24, 32, 36);
   1643 
   1644 		/*
   1645 		**	If this is for a visual change redraw, then the overlap list will be based
   1646 		**	on the actual dimensions of the shape data. If the dimensions have already
   1647 		**	been calculated then use them, otherwise, use the default large rectangle
   1648 		**	previously created.
   1649 		*/
   1650 		if (Height == 0 && !Is_Selected_By_Player() && redraw && Class->DimensionData != NULL) {
   1651 			int shapenum = Shape_Number();
   1652 			if (!Class->DimensionData[shapenum].Is_Valid()) {
   1653 				Class->DimensionData[shapenum] = Shape_Dimensions(Get_Image_Data(), shapenum);
   1654 			}
   1655 			rect = Class->DimensionData[shapenum];
   1656 			rect.Y += 4;
   1657 			rect.X -= 2;
   1658 		}
   1659 		return(Coord_Spillage_List(Coord, rect, true));
   1660 #else
   1661 
   1662 		static Rect rect(-16, -24, 32, 36);
   1663 		return(Coord_Spillage_List(Coord, rect, true));
   1664 #endif
   1665 
   1666 //		return(Coord_Spillage_List(Coord, 24 /*+ ((Doing > DO_WALK || IsSelected)?12:0)*/ ));
   1667 	}
   1668 }
   1669 
   1670 
   1671 /***********************************************************************************************
   1672  * InfantryClass::Can_Fire -- Can the infantry fire its weapon?                                *
   1673  *                                                                                             *
   1674  *    Determines if the infantry unit can fire on the target. If it can't fire, then the       *
   1675  *    reason why is returned.                                                                  *
   1676  *                                                                                             *
   1677  * INPUT:   target   -- The target to determine if the infantry can fire upon.                 *
   1678  *                                                                                             *
   1679  * OUTPUT:  Returns the fire error type that indicates if the infantry can fire and if it      *
   1680  *          can't, why not.                                                                    *
   1681  *                                                                                             *
   1682  * WARNINGS:   none                                                                            *
   1683  *                                                                                             *
   1684  * HISTORY:                                                                                    *
   1685  *   09/01/1994 JLB : Created.                                                                 *
   1686  *   06/27/1995 JLB : Flame thrower can fire while prone now.                                  *
   1687  *=============================================================================================*/
   1688 FireErrorType InfantryClass::Can_Fire(TARGET target, int which) const
   1689 {
   1690 	assert(Infantry.ID(this) == ID);
   1691 	assert(IsActive);
   1692 
   1693 	/*
   1694 	**	Don't allow firing if the infantry is still firing on previous target.
   1695 	*/
   1696 //	if (IsFiring) return(FIRE_REARM);
   1697 
   1698 	/*
   1699 	** If a medic is shooting at a healed target, let's declare the target
   1700 	** illegal so he won't be constantly healing healed infantrymen.
   1701 	*/
   1702 	if (Combat_Damage() < 0) {
   1703 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   1704 		TechnoClass * targ = As_Techno(target);
   1705 #else
   1706 		InfantryClass * targ = As_Infantry(target);
   1707 #endif
   1708 		if (targ == NULL || targ->Health_Ratio() >= Rule.ConditionGreen) {
   1709 			return(FIRE_ILLEGAL);
   1710 		}
   1711 	}
   1712 
   1713 	/*
   1714 	**	If this unit cannot fire while moving, then bail.
   1715 	*/
   1716 	if (IsDriving || (Target_Legal(NavCom) && Doing != DO_NOTHING && !MasterDoControls[Doing].Interrupt)) {
   1717 		return(FIRE_MOVING);
   1718 	}
   1719 
   1720 	/*
   1721 	** Only one dog can fire on an infantry at a time
   1722 	*/
   1723 	if (Class->IsDog) {
   1724 		for (int index = 0; index < Infantry.Count(); index++) {
   1725 			InfantryClass *dog = Infantry.Ptr(index);
   1726 			if (dog != this && dog->Class->IsDog && (dog->IsFiring || dog->IsInLimbo) && dog->TarCom == target) {
   1727 				return(FIRE_ILLEGAL);
   1728 			}
   1729 		}
   1730 	}
   1731 
   1732 	return(FootClass::Can_Fire(target, which));
   1733 }
   1734 
   1735 
   1736 /***********************************************************************************************
   1737  * TechnoClass::Fire_Coord -- Determine the coordinate where bullets appear.                   *
   1738  *                                                                                             *
   1739  *    This routine will determine the coordinate to use when this infantry fires. The          *
   1740  *    coordinate is the location where bullets appear (or fire effects appear) when the        *
   1741  *    object fires its weapon.                                                                 *
   1742  *                                                                                             *
   1743  * INPUT:   which -- Which weapon is the coordinate to be calculated for? 0 means primary      *
   1744  *                   weapon, 1 means secondary weapon.                                         *
   1745  *                                                                                             *
   1746  * OUTPUT:  Returns with the coordinate that any bullets fired from the specified weapon       *
   1747  *          should appear.                                                                     *
   1748  *                                                                                             *
   1749  * WARNINGS:   none                                                                            *
   1750  *                                                                                             *
   1751  * HISTORY:                                                                                    *
   1752  *   11/12/2019 SKY : Created.                                                                 *
   1753  *=============================================================================================*/
   1754 COORDINATE InfantryClass::Fire_Coord(int which) const
   1755 {
   1756 	COORDINATE coord = FootClass::Fire_Coord(which);
   1757 
   1758 	/*
   1759 	**  Since electric weapons draw a zap between start and end points, prone infantry that fire one
   1760 	**  need to adjust their fire coordinate so the start point looks correct.
   1761 	*/
   1762 	if (IsProne) {
   1763 		TechnoTypeClass const & tclass = *Techno_Type_Class();
   1764 		WeaponTypeClass const * weapon = (which == 0) ? tclass.PrimaryWeapon : tclass.SecondaryWeapon;
   1765 		if (weapon && weapon->IsElectric) {
   1766 			coord = Coord_Add(coord, XY_Coord(0, 48));
   1767 		}
   1768 	}
   1769 
   1770 	return coord;
   1771 }
   1772 
   1773 
   1774 /***********************************************************************************************
   1775  * InfantryClass::Enter_Idle_Mode -- The infantry unit enters idle mode by this routine.       *
   1776  *                                                                                             *
   1777  *    Use this routine when the infantry unit as accomplished its task and needs to find       *
   1778  *    something to do. The default behavior is to enter some idle state such as guarding.      *
   1779  *                                                                                             *
   1780  * INPUT:   initial  -- Is this called when the unit just leaves a factory or is initially     *
   1781  *                      or is initially placed on the map?                                     *
   1782  *                                                                                             *
   1783  * OUTPUT:  none                                                                               *
   1784  *                                                                                             *
   1785  * WARNINGS:   none                                                                            *
   1786  *                                                                                             *
   1787  * HISTORY:                                                                                    *
   1788  *   09/01/1994 JLB : Created.                                                                 *
   1789  *=============================================================================================*/
   1790 void InfantryClass::Enter_Idle_Mode(bool )
   1791 {
   1792 	assert(Infantry.ID(this) == ID);
   1793 	assert(IsActive);
   1794 
   1795 	MissionType order = MISSION_GUARD;
   1796 
   1797 	if (Target_Legal(TarCom)) {
   1798 		order = MISSION_ATTACK;
   1799 		if (Mission == MISSION_SABOTAGE) {
   1800 			order = MISSION_SABOTAGE;
   1801 		}
   1802 		if (Mission == MISSION_CAPTURE) {
   1803 			order = MISSION_CAPTURE;
   1804 		}
   1805 	} else {
   1806 
   1807 		Handle_Navigation_List();
   1808 
   1809 		if (Target_Legal(NavCom)) {
   1810 			order = MISSION_MOVE;
   1811 			if (Mission == MISSION_CAPTURE) {
   1812 				order = MISSION_CAPTURE;
   1813 			}
   1814 			if (Mission == MISSION_SABOTAGE) {
   1815 				order = MISSION_SABOTAGE;
   1816 			}
   1817 		} else {
   1818 
   1819 			if (Mission == MISSION_GUARD || Mission == MISSION_GUARD_AREA || MissionControl[Mission].IsZombie || MissionControl[Mission].IsParalyzed) {
   1820 				return;
   1821 			}
   1822 
   1823 			if (Class->IsDog) {
   1824 				if (House->IsHuman || Team.Is_Valid()) {
   1825 					order = MISSION_GUARD;
   1826 				} else {
   1827 					order = MISSION_GUARD_AREA;
   1828 					ArchiveTarget = ::As_Target(Coord_Cell(Center_Coord()));
   1829 				}
   1830 			} else {
   1831 				if (House->IsHuman || Team.Is_Valid()) {
   1832 					order = MISSION_GUARD;
   1833 				} else {
   1834 					if (House->IQ < Rule.IQGuardArea) {
   1835 						order = MISSION_GUARD;
   1836 					} else {
   1837 						if (Is_Weapon_Equipped()) {
   1838 							order = MISSION_GUARD_AREA;
   1839 						} else {
   1840 							order = MISSION_GUARD;
   1841 						}
   1842 					}
   1843 				}
   1844 			}
   1845 		}
   1846 	}
   1847 	Assign_Mission(order);
   1848 }
   1849 
   1850 
   1851 /***********************************************************************************************
   1852  * InfantryClass::Random_Animate -- Randomly animate the infantry (maybe)                      *
   1853  *                                                                                             *
   1854  *    This routine is the random animator initiator for infantry units. This routine should    *
   1855  *    be called regularly. On occasion, it will cause the infantry to go into an idle          *
   1856  *    animation.                                                                               *
   1857  *                                                                                             *
   1858  * INPUT:   none                                                                               *
   1859  *                                                                                             *
   1860  * OUTPUT:  none                                                                               *
   1861  *                                                                                             *
   1862  * WARNINGS:   none                                                                            *
   1863  *                                                                                             *
   1864  * HISTORY:                                                                                    *
   1865  *   09/01/1994 JLB : Created.                                                                 *
   1866  *   12/13/1994 JLB : Does random facing change.                                               *
   1867  *   07/02/1995 JLB : Nikoomba special effects.                                                *
   1868  *=============================================================================================*/
   1869 bool InfantryClass::Random_Animate(void)
   1870 {
   1871 	assert(Infantry.ID(this) == ID);
   1872 	assert(IsActive);
   1873 
   1874 	if (Is_Ready_To_Random_Animate()) {
   1875 		IdleTimer = Random_Pick(Rule.RandomAnimateTime * (TICKS_PER_MINUTE/2), Rule.RandomAnimateTime * (TICKS_PER_MINUTE*2));
   1876 
   1877 		/*
   1878 		**	Scared infantry will always follow the golden rule of civilians;
   1879 		**		"When in darkness or in doubt, run in circles, scream, and shout!"
   1880 		*/
   1881 		if (Class->IsFraidyCat && !House->IsHuman && Fear > FEAR_ANXIOUS) {
   1882 			Scatter(NULL, true);
   1883 			return(true);
   1884 		}
   1885 
   1886 		switch (Random_Pick(0, 10)) {
   1887 			case 0:
   1888 				if (Class->IsDog) {
   1889 					Do_Action(DO_IDLE1);
   1890 				}
   1891 				break;
   1892 
   1893 			case 1:
   1894 				Do_Action(DO_SALUTE1);
   1895 				break;
   1896 
   1897 			case 2:
   1898 				Do_Action(DO_SALUTE2);
   1899 				break;
   1900 
   1901 			case 3:
   1902 				Do_Action(DO_GESTURE1);
   1903 				break;
   1904 
   1905 			case 4:
   1906 				Do_Action(DO_GESTURE2);
   1907 				break;
   1908 
   1909 			case 5:
   1910 				Do_Action(DO_IDLE1);
   1911 				break;
   1912 
   1913 			case 6:
   1914 				Mark(MARK_CHANGE_REDRAW);
   1915 				PrimaryFacing.Set(Facing_Dir(Random_Pick(FACING_N, FACING_NW)));
   1916 				Mark(MARK_CHANGE_REDRAW);
   1917 				break;
   1918 
   1919 			case 7:
   1920 				Do_Action(DO_IDLE2);
   1921 				Mark(MARK_CHANGE_REDRAW);
   1922 				PrimaryFacing.Set(Facing_Dir(Random_Pick(FACING_N, FACING_NW)));
   1923 				Mark(MARK_CHANGE_REDRAW);
   1924 				if (!Is_Selected_By_Player() && IsOwnedByPlayer && *this == INFANTRY_TANYA && Sim_Random_Pick(0, 2) == 0) {
   1925 					Sound_Effect(VOC_TANYA_SHAKE, Coord);
   1926 				}
   1927 				break;
   1928 
   1929 			/*
   1930 			**	On occasion, civilian types will wander about.
   1931 			*/
   1932 			case 8:
   1933 				Mark(MARK_CHANGE_REDRAW);
   1934 				PrimaryFacing.Set(Facing_Dir(Random_Pick(FACING_N, FACING_NW)));
   1935 				Mark(MARK_CHANGE_REDRAW);
   1936 				if (!House->IsHuman && Class->IsFraidyCat) {
   1937 					Scatter(NULL, true);
   1938 				}
   1939 				break;
   1940 
   1941 			case 9:
   1942 			case 10:
   1943 				Mark(MARK_CHANGE_REDRAW);
   1944 				PrimaryFacing.Set(Facing_Dir(Random_Pick(FACING_N, FACING_NW)));
   1945 				Mark(MARK_CHANGE_REDRAW);
   1946 
   1947 		}
   1948 		return(true);
   1949 	}
   1950 	return(false);
   1951 }
   1952 
   1953 
   1954 /***********************************************************************************************
   1955  * InfantryClass::Scatter -- Causes the infantry to scatter to nearby cell.                    *
   1956  *                                                                                             *
   1957  *    This routine is used when the infantry should scatter to a nearby cell. Scattering       *
   1958  *    occurs as an occasional consequence of being fired upon. It is one of the features       *
   1959  *    that makes infantry so "charming".                                                       *
   1960  *                                                                                             *
   1961  * INPUT:   threat   -- The coordinate source of the threat that is causing the infantry to    *
   1962  *                      scatter. If the threat isn't from a particular direction, then this    *
   1963  *                      parameter will be NULL.                                                *
   1964  *                                                                                             *
   1965  *          forced   -- The threat is real and a serious effort to scatter should be made.     *
   1966  *                                                                                             *
   1967  *          nokidding-- The scatter should affect the player's infantry even if it otherwise   *
   1968  *                      wouldn't have.                                                         *
   1969  *                                                                                             *
   1970  * OUTPUT:  none                                                                               *
   1971  *                                                                                             *
   1972  * WARNINGS:   none                                                                            *
   1973  *                                                                                             *
   1974  * HISTORY:                                                                                    *
   1975  *   09/24/1994 JLB : Created.                                                                 *
   1976  *   12/12/1994 JLB : Flame thrower infantry always scatter.                                   *
   1977  *   08/02/1996 JLB : Added the nokidding parameter                                            *
   1978  *=============================================================================================*/
   1979 void InfantryClass::Scatter(COORDINATE threat, bool forced, bool nokidding)
   1980 {
   1981 	assert(Infantry.ID(this) == ID);
   1982 	assert(IsActive);
   1983 
   1984 	/*
   1985 	**	A unit that is in the process of going somewhere will never scatter.
   1986 	*/
   1987 	if (IsDriving) forced = false;
   1988 
   1989 	/*
   1990 	**	Certain missions prevent scattering regardless of whether it would be
   1991 	**	a good idea or not.
   1992 	*/
   1993 	if (!MissionControl[Mission].IsScatter && !forced) return;
   1994 
   1995 	/*
   1996 	**	If the infantry is currently engaged in legitimate combat, then don't
   1997 	**	scatter unless forced to.
   1998 	*/
   1999 	if (!Class->IsFraidyCat && Target_Legal(TarCom) && !forced) return;
   2000 
   2001 	/*
   2002 	**	Don't scatter if performing an action that can't be interrupted.
   2003 	*/
   2004 	if (Doing != DO_NOTHING && !MasterDoControls[Doing].Interrupt) return;
   2005 
   2006 	/*
   2007 	**	For human players, don't scatter the infantry, if the special
   2008 	**	flag has not been enabled that allows infantry scatter.
   2009 	*/
   2010 	if (!Rule.IsScatter && !nokidding && House->IsHuman && !forced && !Team.Is_Valid()) return;
   2011 
   2012 	if (forced || Class->IsFraidyCat /*|| !(Random_Pick(1, 4) == 1)*/) {
   2013 		FacingType	toface;
   2014 
   2015 		if (threat) {
   2016 			toface = Dir_Facing(Direction8(threat, Coord));
   2017 			toface = toface + FacingType(Random_Pick(0, 4)-2);
   2018 		} else {
   2019 			COORDINATE coord = Coord_Fraction(Center_Coord());
   2020 
   2021 			if (coord != 0x00800080L) {
   2022 				toface = Dir_Facing((DirType)Desired_Facing8(0x0080, 0x0080, Coord_X(coord), Coord_Y(coord)));
   2023 			} else {
   2024 				toface = Dir_Facing(PrimaryFacing.Current());
   2025 			}
   2026 			toface = toface + FacingType(Random_Pick(0, 4)-2);
   2027 		}
   2028 
   2029 		CELL newcell = 0;
   2030 		CELL altcell = 0;
   2031 		FacingType face;
   2032 		for (face = FACING_N; face < FACING_COUNT; face++) {
   2033 			FacingType newface = toface + face;
   2034 			newcell = Adjacent_Cell(Coord_Cell(Coord), newface);
   2035 
   2036 			if (Map.In_Radar(newcell) && Can_Enter_Cell(newcell) == MOVE_OK) {
   2037 				if (altcell == 0) altcell = newcell;
   2038 				if (!Map[newcell].Is_Bridge_Here()) break;
   2039 //				Assign_Mission(MISSION_MOVE);
   2040 //				Assign_Destination(::As_Target(newcell));
   2041 			}
   2042 		}
   2043 		if (face == FACING_COUNT) {
   2044 			newcell = 0;
   2045 		}
   2046 
   2047 		if (newcell == 0) {
   2048 			newcell = altcell;
   2049 		}
   2050 
   2051 		if (newcell != 0) {
   2052 			Assign_Mission(MISSION_MOVE);
   2053 			Assign_Destination(::As_Target(newcell));
   2054 		}
   2055 	}
   2056 }
   2057 
   2058 
   2059 /***********************************************************************************************
   2060  * InfantryClass::Look -- Performs a look around (map reveal) action.                          *
   2061  *                                                                                             *
   2062  *    This routine will reveal the map around this object.                                     *
   2063  *                                                                                             *
   2064  * INPUT:   incremental -- This parameter can enable a more efficient map reveal logic.        *
   2065  *                         If it is absolutely known that the object has only moved one        *
   2066  *                         cell from its previous location that it performed a Look() at,      *
   2067  *                         then set this parameter to TRUE. It will only perform the look      *
   2068  *                         check on the perimeter cells.                                       *
   2069  *                                                                                             *
   2070  * OUTPUT:  none                                                                               *
   2071  *                                                                                             *
   2072  * WARNINGS:   This routine is slow, try to call it only when necessary.                       *
   2073  *                                                                                             *
   2074  * HISTORY:                                                                                    *
   2075  *   03/14/1996 JLB : Created.                                                                 *
   2076  *=============================================================================================*/
   2077 void InfantryClass::Look(bool incremental)
   2078 {
   2079 	LookCell = Coord_Cell(Coord);
   2080 	FootClass::Look(incremental);
   2081 }
   2082 
   2083 
   2084 /***********************************************************************************************
   2085  * InfantryClass::Do_Action -- Launches the infantry into an animation sequence.               *
   2086  *                                                                                             *
   2087  *    This starts the infantry into a choreographed animation sequence. These sequences can    *
   2088  *    be as simple as standing up or lying down, but can also be complex, such as dying or     *
   2089  *    performing some idle animation.                                                          *
   2090  *                                                                                             *
   2091  * INPUT:   todo     -- The choreographed sequence to start.                                   *
   2092  *                                                                                             *
   2093  *          force    -- Force starting this animation even if the current animation is flagged *
   2094  *                      as uninterruptible. This is necessary for death animations.            *
   2095  *                                                                                             *
   2096  * OUTPUT:  bool; Was the animation started?                                                   *
   2097  *                                                                                             *
   2098  * WARNINGS:   none                                                                            *
   2099  *                                                                                             *
   2100  * HISTORY:                                                                                    *
   2101  *   09/24/1994 JLB : Created.                                                                 *
   2102  *=============================================================================================*/
   2103 bool InfantryClass::Do_Action(DoType todo, bool force)
   2104 {
   2105 	assert(Infantry.ID(this) == ID);
   2106 	assert(IsActive);
   2107 
   2108 	if (todo == DO_NOTHING || Class->DoControls[todo].Count == 0) {
   2109 		return(false);
   2110 	}
   2111 
   2112 	if (*this == INFANTRY_SPY && todo >= DO_GESTURE1) {
   2113 		todo = (DoType)(DO_IDLE1 + Random_Pick(0,1));
   2114 	}
   2115 
   2116 	if (todo != Doing && (Doing == DO_NOTHING || force || MasterDoControls[Doing].Interrupt)) {
   2117 		Mark(MARK_OVERLAP_UP);
   2118 		Doing = todo;
   2119 		Mark(MARK_OVERLAP_DOWN);
   2120 		if (todo == DO_IDLE1 || todo == DO_IDLE2) {
   2121 			Set_Rate(Options.Normalize_Delay(MasterDoControls[Doing].Rate));
   2122 		} else {
   2123 			Set_Rate(MasterDoControls[Doing].Rate);
   2124 		}
   2125 		Set_Stage(0);
   2126 
   2127 		/*
   2128 		**	Kludge to make sure that if infantry is in the dying animation, it isn't still
   2129 		**	moving as well.
   2130 		*/
   2131 		if (Strength == 0) {
   2132 			Stop_Driver();
   2133 		}
   2134 
   2135 		/*
   2136 		**	Make sure dogs don't try to go somewhere while they're mauling
   2137 		*/
   2138 		if (todo == DO_DOG_MAUL) {
   2139 			Stop_Driver();
   2140 			Assign_Destination(TARGET_NONE);
   2141 		}
   2142 
   2143 		/*
   2144 		**	Since the animation sequence might be interrupted. Set any flags
   2145 		**	necessary so that if interrupted, the affect on the infantry is
   2146 		**	still accomplished.
   2147 		*/
   2148 		switch (todo) {
   2149 			case DO_LIE_DOWN:
   2150 				IsProne = true;
   2151 				break;
   2152 
   2153 			case DO_GET_UP:
   2154 				IsProne = false;
   2155 				break;
   2156 
   2157 			default:
   2158 				break;
   2159 		}
   2160 
   2161 		return(true);
   2162 	}
   2163 
   2164 	return(false);
   2165 }
   2166 
   2167 
   2168 /***********************************************************************************************
   2169  * InfantryClass::Stop_Driver -- Stops the infantry from moving any further.                   *
   2170  *                                                                                             *
   2171  *    This is used to stop the infantry from animating in movement. This function will stop    *
   2172  *    the infantry moving and revert it to either a prone or standing.                         *
   2173  *                                                                                             *
   2174  * INPUT:   none                                                                               *
   2175  *                                                                                             *
   2176  * OUTPUT:  bool; Was the driving stopped?                                                     *
   2177  *                                                                                             *
   2178  * WARNINGS:   none                                                                            *
   2179  *                                                                                             *
   2180  * HISTORY:                                                                                    *
   2181  *   09/24/1994 JLB : Created.                                                                 *
   2182  *=============================================================================================*/
   2183 bool InfantryClass::Stop_Driver(void)
   2184 {
   2185 	assert(Infantry.ID(this) == ID);
   2186 	assert(IsActive);
   2187 
   2188 	if (Head_To_Coord()) {
   2189 
   2190 		/*
   2191 		**	Remove the "reservation" bit in the destination location.
   2192 		*/
   2193 		Clear_Occupy_Bit(Head_To_Coord());
   2194 	}
   2195 
   2196 	/*
   2197 	**	Set the occupation bit at the current location.
   2198 	*/
   2199 	Set_Occupy_Bit(Coord);
   2200 
   2201 	if (Doing != DO_STAND_READY) {
   2202 		StopDriverFrame = Frame;
   2203 	}
   2204 
   2205 	if (Class->IsDog) {
   2206 		Do_Action(DO_STAND_READY);
   2207 	} else {
   2208 		if (IsProne) {
   2209 			Do_Action(DO_PRONE);
   2210 		} else {
   2211 			Do_Action(DO_STAND_READY);
   2212 		}
   2213 	}
   2214 
   2215 	if (Can_Enter_Cell(Coord_Cell(Coord)) == MOVE_OK) {
   2216 		IsZoneCheat = false;
   2217 	} else {
   2218 		IsZoneCheat = true;
   2219 	}
   2220 
   2221 	return(FootClass::Stop_Driver());
   2222 }
   2223 
   2224 
   2225 /***********************************************************************************************
   2226  * InfantryClass::Start_Driver -- Handles giving immediate destination and move orders.        *
   2227  *                                                                                             *
   2228  *    Use this routine to being the infantry moving toward the destination specified. The      *
   2229  *    destination is first checked to see if there is a free spot available. Then the infantry *
   2230  *    reserves that spot and begins movement toward it.                                        *
   2231  *                                                                                             *
   2232  * INPUT:   headto   -- The coordinate location desired for the infantry to head to.           *
   2233  *                                                                                             *
   2234  * OUTPUT:  bool; Was the infantry successfully started on its journey? Failure may be because *
   2235  *                the specified destination could not contain the infantry unit.               *
   2236  *                                                                                             *
   2237  * WARNINGS:   none                                                                            *
   2238  *                                                                                             *
   2239  * HISTORY:                                                                                    *
   2240  *   12/21/1994 JLB : Created.                                                                 *
   2241  *   05/14/1995 JLB : Tries to move to closest spot possible.                                  *
   2242  *   05/15/1995 JLB : Uses closest spot if moving onto transport.                              *
   2243  *=============================================================================================*/
   2244 bool InfantryClass::Start_Driver(COORDINATE & headto)
   2245 {
   2246 	assert(Infantry.ID(this) == ID);
   2247 	assert(IsActive);
   2248 
   2249 	COORDINATE old = headto;
   2250 
   2251 	/*
   2252 	**	Convert the head to coordinate to a legal sub-position location.
   2253 	*/
   2254 	headto = Map[headto].Closest_Free_Spot(Coord_Move(headto, Direction(headto)+DIR_S, 0x007C));
   2255 	if (!headto && Can_Enter_Cell(Coord_Cell(old)) == MOVE_OK) {
   2256 		headto = Map[old].Closest_Free_Spot(Coord_Move(old, Direction(headto)+DIR_S, 0x0080), true);
   2257 	}
   2258 
   2259 	/*
   2260 	**	If the infantry started moving, then fixup the occupation bits.
   2261 	*/
   2262 	if (headto && FootClass::Start_Driver(headto)) {
   2263 		if (!IsActive) return(false);
   2264 
   2265 		/*
   2266 		**	Remove the occupation bit from the infantry's current location.
   2267 		*/
   2268   		Clear_Occupy_Bit(Coord);
   2269 
   2270 		/*
   2271 		**	Set the occupation bit for the new headto location.
   2272 		*/
   2273 		Set_Occupy_Bit(headto);
   2274 		return(true);
   2275 	}
   2276 
   2277 	return(false);
   2278 }
   2279 
   2280 
   2281 /***********************************************************************************************
   2282  * InfantryClass::Limbo -- Performs cleanup operations needed when limboing.                   *
   2283  *                                                                                             *
   2284  *    This routine will clean up the infantry occupation bits (as necessary) as well as stop   *
   2285  *    the infantry movement process when it gets limboed.                                      *
   2286  *                                                                                             *
   2287  * INPUT:   none                                                                               *
   2288  *                                                                                             *
   2289  * OUTPUT:  bool; Was the infantry unit limboed?                                               *
   2290  *                                                                                             *
   2291  * WARNINGS:   none                                                                            *
   2292  *                                                                                             *
   2293  * HISTORY:                                                                                    *
   2294  *   12/22/1994 JLB : Created.                                                                 *
   2295  *=============================================================================================*/
   2296 bool InfantryClass::Limbo(void)
   2297 {
   2298 	assert(Infantry.ID(this) == ID);
   2299 	assert(IsActive);
   2300 
   2301 	if (!IsInLimbo) {
   2302 		Stop_Driver();
   2303 
   2304 		Clear_Occupy_Bit(Coord);
   2305 	}
   2306 	return(FootClass::Limbo());
   2307 }
   2308 
   2309 
   2310 /***********************************************************************************************
   2311  * InfantryClass::Fire_At -- Fires projectile from infantry unit.                              *
   2312  *                                                                                             *
   2313  *    Use this routine when the infantry unit wishes to fire a projectile. This routine        *
   2314  *    will launch the projectile and perform any other necessary infantry specific operations. *
   2315  *                                                                                             *
   2316  * INPUT:   target   -- The target of the attack.                                              *
   2317  *                                                                                             *
   2318  *          which    -- Which weapon to use for firing. 0=primary, 1=secondary.                *
   2319  *                                                                                             *
   2320  * OUTPUT:  Returns with pointer to the projectile launched. If none could be launched, then   *
   2321  *          NULL is returned. If there is already the maximum bullet objects in play, then     *
   2322  *          this could happen.                                                                 *
   2323  *                                                                                             *
   2324  * WARNINGS:   none                                                                            *
   2325  *                                                                                             *
   2326  * HISTORY:                                                                                    *
   2327  *   12/26/1994 JLB : Created.                                                                 *
   2328  *=============================================================================================*/
   2329 BulletClass * InfantryClass::Fire_At(TARGET target, int which)
   2330 {
   2331 	assert(Infantry.ID(this) == ID);
   2332 	assert(IsActive);
   2333 
   2334 	Mark(MARK_OVERLAP_UP);
   2335 	IsFiring = false;
   2336 	Mark(MARK_OVERLAP_DOWN);
   2337 
   2338 	BulletClass * bullet = FootClass::Fire_At(target, which);
   2339 	if (bullet != NULL && !IsInLimbo) {
   2340 
   2341 		/*
   2342 		**	For fraidycat infantry that run out of ammo, always go into
   2343 		**	a maximum fear state at that time.
   2344 		*/
   2345 		if (Class->IsFraidyCat && !Ammo) {
   2346 			Fear = FEAR_MAXIMUM;
   2347 			if (Mission == MISSION_ATTACK || Mission == MISSION_HUNT) {
   2348 				Assign_Mission(MISSION_GUARD);
   2349 			}
   2350 		}
   2351 	}
   2352 	return(bullet);
   2353 }
   2354 
   2355 
   2356 /***********************************************************************************************
   2357  * InfantryClass::Unlimbo -- Unlimbo infantry unit in legal sub-location.                      *
   2358  *                                                                                             *
   2359  *    This will attempt to unlimbo the infantry unit at the designated coordinate, but will    *
   2360  *    ensure that the coordinate is a legal subposition.                                       *
   2361  *                                                                                             *
   2362  * INPUT:   coord    -- The coordinate to unlimbo the infantry at.                             *
   2363  *                                                                                             *
   2364  *          facing   -- The desired initial facing for the infantry unit.                      *
   2365  *                                                                                             *
   2366  *          strength -- The desired initial strength for the infantry unit.                    *
   2367  *                                                                                             *
   2368  *          mission  -- The desired initial mission for the infantry unit.                     *
   2369  *                                                                                             *
   2370  * OUTPUT:  bool; Was the infantry unlimboed successfully?                                     *
   2371  *                                                                                             *
   2372  * WARNINGS:   none                                                                            *
   2373  *                                                                                             *
   2374  * HISTORY:                                                                                    *
   2375  *   12/26/1994 JLB : Created.                                                                 *
   2376  *=============================================================================================*/
   2377 bool InfantryClass::Unlimbo(COORDINATE coord, DirType facing)
   2378 {
   2379 	assert(Infantry.ID(this) == ID);
   2380 	assert(IsActive);
   2381 
   2382 	/*
   2383 	**	Make sure that the infantry start in a legal position on the map.
   2384 	*/
   2385 	coord = Map[coord].Closest_Free_Spot(coord, ScenarioInit);
   2386 	if (coord == NULL) {
   2387 		return(false);
   2388 	}
   2389 
   2390 	if (FootClass::Unlimbo(coord, facing)) {
   2391 
   2392 		/*
   2393 		**	Ensure that the owning house knows about the
   2394 		**	new object.
   2395 		*/
   2396 		House->IScan |= (1L << Class->Type);
   2397 		House->ActiveIScan |= (1L << Class->Type);
   2398 
   2399 		/*
   2400 		**	If there is no sight range, then this object isn't discovered by the player unless
   2401 		**	it actually appears in a cell mapped by the player.
   2402 		*/
   2403 		if (Class->SightRange == 0) {
   2404 			IsDiscoveredByPlayer = false;
   2405 		}
   2406 
   2407 		Set_Occupy_Bit(coord);
   2408 		return(true);
   2409 	}
   2410 	return(false);
   2411 }
   2412 
   2413 
   2414 /***********************************************************************************************
   2415  * InfantryClass::Greatest_Threat -- Determines greatest threat (target) for infantry unit.    *
   2416  *                                                                                             *
   2417  *    This routine intercepts the Greatest_Threat request and adds the appropriate target      *
   2418  *    types to search for. For regular infantry, this consists of all the ground types. For    *
   2419  *    rocket launching infantry, this also includes aircraft.                                  *
   2420  *                                                                                             *
   2421  * INPUT:   threat   -- The basic threat control value.                                        *
   2422  *                                                                                             *
   2423  * OUTPUT:  Returns with the best target for this infantry unit to attack. If no suitable      *
   2424  *          target could be found, then TARGET_NONE is returned.                               *
   2425  *                                                                                             *
   2426  * WARNINGS:   none                                                                            *
   2427  *                                                                                             *
   2428  * HISTORY:                                                                                    *
   2429  *   01/01/1995 JLB : Created.                                                                 *
   2430  *   09/28/1995 JLB : Engineers try to recapture buildings first.                              *
   2431  *=============================================================================================*/
   2432 TARGET InfantryClass::Greatest_Threat(ThreatType threat) const
   2433 {
   2434 	assert(Infantry.ID(this) == ID);
   2435 	assert(IsActive);
   2436 
   2437 	/*
   2438 	**	Engineers consider only buildings that can be captured as being a threat. All others
   2439 	**	are ignored. If there is a building that needs to be recaptured and it is nearby
   2440 	**	then automatically head toward it to recapture it.
   2441 	*/
   2442 	if (!House->IsHuman && Class->IsCapture && !Is_Weapon_Equipped()) {
   2443 		if (House->ToCapture != TARGET_NONE && Distance(House->ToCapture) < 0x0F00) {
   2444 			return(House->ToCapture);
   2445 		}
   2446 		threat = threat | THREAT_CAPTURE;
   2447 	}
   2448 
   2449 	if (!Is_Weapon_Equipped()) {
   2450 		if (!Class->IsCapture && *this != INFANTRY_RENOVATOR && *this != INFANTRY_SPY && *this != INFANTRY_THIEF) {
   2451 			return(TARGET_NONE);
   2452 		}
   2453 	}
   2454 
   2455 	/*
   2456 	**	Special hack to make Tanya not auto-fire if controlled by a
   2457 	**	human player.
   2458 	*/
   2459 	if (*this == INFANTRY_TANYA && House->IsHuman) {
   2460 		return(TARGET_NONE);
   2461 	}
   2462 
   2463 	if (Class->PrimaryWeapon != NULL) {
   2464 		threat = threat | Class->PrimaryWeapon->Allowed_Threats();
   2465 	}
   2466 	if (Class->SecondaryWeapon != NULL) {
   2467 		threat = threat | Class->SecondaryWeapon->Allowed_Threats();
   2468 	}
   2469 
   2470 	/*
   2471 	**	Organic weapon types don't consider anything but infantry to be a threat. Such
   2472 	**	weapon types would be the dog jaw and the medic first aid kit.
   2473 	*/
   2474 	if (Is_Weapon_Equipped() && Class->PrimaryWeapon->WarheadPtr->IsOrganic) {
   2475 		threat = threat & ~(THREAT_BUILDINGS|THREAT_VEHICLES|THREAT_BOATS|THREAT_AIR);
   2476 	}
   2477 
   2478 	/*
   2479 	**	Human controlled infantry don't automatically fire upon buildings.
   2480 	*/
   2481 	if (Is_Weapon_Equipped() && House->IsHuman) {
   2482 		threat = threat & ~THREAT_BUILDINGS;
   2483 	}
   2484 
   2485 	/*
   2486 	**	If this is a bomber type, then allow buildings to be considered a threat.
   2487 	*/
   2488 	if (Class->IsBomber && !House->IsHuman) {
   2489 		threat = threat | THREAT_BUILDINGS;
   2490 	}
   2491 
   2492 	/*
   2493 	** Special hack: if it's a thief, then the only possible objects to
   2494 	** consider are tiberium-processing objects (silos & refineries).
   2495 	*/
   2496 	if (*this == INFANTRY_THIEF) {
   2497 		threat = threat | THREAT_CAPTURE | THREAT_TIBERIUM;
   2498 //		threat = (ThreatType)(THREAT_CAPTURE | THREAT_TIBERIUM);
   2499 	}
   2500 	return(FootClass::Greatest_Threat(threat));
   2501 }
   2502 
   2503 
   2504 /***********************************************************************************************
   2505  * InfantryClass::Response_Select -- Plays infantry audio response due to being selected.      *
   2506  *                                                                                             *
   2507  *    This routine handles playing an audio response as a result of the player selecting the   *
   2508  *    infantry unit. This occurs prior to giving it an order and may not be followed by any    *
   2509  *    order at all.                                                                            *
   2510  *                                                                                             *
   2511  * INPUT:   none                                                                               *
   2512  *                                                                                             *
   2513  * OUTPUT:  none                                                                               *
   2514  *                                                                                             *
   2515  * WARNINGS:   none                                                                            *
   2516  *                                                                                             *
   2517  * HISTORY:                                                                                    *
   2518  *   01/01/1995 JLB : Created.                                                                 *
   2519  *   05/05/1995 JLB : Rambo response types added.                                              *
   2520  *=============================================================================================*/
   2521 void InfantryClass::Response_Select(void)
   2522 {
   2523 	assert(Infantry.ID(this) == ID);
   2524 	assert(IsActive);
   2525 
   2526 	if (!AllowVoice) return;
   2527 
   2528 	if (Class->IsCivilian && *this != INFANTRY_EINSTEIN) {
   2529 		VocType response = VOC_NONE;
   2530 		if (Class->IsFemale) {
   2531 			response = VOC_GIRL_YEAH;
   2532 		} else {
   2533 			response = VOC_GUY_YEAH;
   2534 		}
   2535 		Sound_Effect(response, fixed(1), ID+1);
   2536 
   2537 	} else {
   2538 		static VocType _eng_response[] = {VOC_ENG_YES,VOC_ENG_ENG};
   2539 		static VocType _ein_response[] = {VOC_E_AH};
   2540 		static VocType _dog_response[] = {VOC_DOG_YES};
   2541 		static VocType _spy_response[] = {VOC_SPY_COMMANDER,VOC_SPY_YESSIR};
   2542 		static VocType _medic_response[] = {VOC_MED_REPORTING,VOC_MED_YESSIR};
   2543 		static VocType _tanya_response[] = {VOC_TANYA_YEA,VOC_TANYA_YES,VOC_TANYA_WHATS};
   2544 		static VocType _thief_response[] = {VOC_THIEF_YEA,VOC_THIEF_WHAT};
   2545 		static VocType _default_response[] = {VOC_ACKNOWL,VOC_REPORT,VOC_REPORT,VOC_YESSIR,VOC_YESSIR,VOC_READY,VOC_AWAIT};
   2546 		static VocType _stavros[] = {VOC_STAVCMDR,VOC_STAVYES};
   2547 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2548 		static VocType _mechanic_response[] = {VOC_MECHHOWDY1,VOC_MECHHUH1,VOC_MECHLAFF1};
   2549 		static VocType _shock_response[] = {VOC_STYES1,VOC_STJUMP1,VOC_STJUICE1};
   2550 #endif
   2551 
   2552 		int size = 0;
   2553 		VocType * response = NULL;
   2554 		HousesType house = PlayerPtr->ActLike;
   2555 		switch (Class->Type) {
   2556 			case INFANTRY_GENERAL:
   2557 				if (house != HOUSE_USSR && house != HOUSE_BAD) {
   2558 					response = _stavros;
   2559 					size = ARRAY_SIZE(_stavros);
   2560 				} else {
   2561 					response = _default_response;
   2562 					size = ARRAY_SIZE(_default_response);
   2563 				}
   2564 				house = HOUSE_USSR;
   2565 				break;
   2566 
   2567 			case INFANTRY_DOG:
   2568 				response = _dog_response;
   2569 				size = ARRAY_SIZE(_dog_response);
   2570 				break;
   2571 
   2572 			case INFANTRY_EINSTEIN:
   2573 				response = _ein_response;
   2574 				size = ARRAY_SIZE(_ein_response);
   2575 				break;
   2576 
   2577 			case INFANTRY_SPY:
   2578 				response = _spy_response;
   2579 				size = ARRAY_SIZE(_spy_response);
   2580 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2581 				if(house == HOUSE_USSR) {
   2582 					response = _default_response;
   2583 					size = ARRAY_SIZE(_default_response);
   2584 				}
   2585 #endif
   2586 				break;
   2587 
   2588 			case INFANTRY_MEDIC:
   2589 				response = _medic_response;
   2590 				size = ARRAY_SIZE(_medic_response);
   2591 				break;
   2592 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2593 			case INFANTRY_MECHANIC:
   2594 				response = _mechanic_response;
   2595 				size = ARRAY_SIZE(_mechanic_response);
   2596 				break;
   2597 			case INFANTRY_SHOCK:
   2598 				response = _shock_response;
   2599 				size = ARRAY_SIZE(_shock_response);
   2600 				break;
   2601 #endif
   2602 			case INFANTRY_TANYA:
   2603 				response = _tanya_response;
   2604 				size = ARRAY_SIZE(_tanya_response);
   2605 				break;
   2606 
   2607 			case INFANTRY_THIEF:
   2608 				response = _thief_response;
   2609 				size = ARRAY_SIZE(_thief_response);
   2610 				break;
   2611 
   2612 			case INFANTRY_RENOVATOR:
   2613 				response = _eng_response;
   2614 				size = ARRAY_SIZE(_eng_response);
   2615 				break;
   2616 
   2617 			default:
   2618 				response = _default_response;
   2619 				size = ARRAY_SIZE(_default_response);
   2620 				break;
   2621 		}
   2622 		if (response != NULL) {
   2623 			Sound_Effect(response[Sim_Random_Pick(0, size-1)], fixed(1), ID+1, 0, house);
   2624 		}
   2625 	}
   2626 }
   2627 
   2628 
   2629 /***********************************************************************************************
   2630  * InfantryClass::Response_Move -- Plays infantry response to movement order.                  *
   2631  *                                                                                             *
   2632  *    When the infantry is given the order to move, this routine handles the audio response    *
   2633  *    generated by the infantry unit.                                                          *
   2634  *                                                                                             *
   2635  * INPUT:   none                                                                               *
   2636  *                                                                                             *
   2637  * OUTPUT:  none                                                                               *
   2638  *                                                                                             *
   2639  * WARNINGS:   none                                                                            *
   2640  *                                                                                             *
   2641  * HISTORY:                                                                                    *
   2642  *   01/01/1995 JLB : Created.                                                                 *
   2643  *   05/05/1995 JLB : Rambo response types added.                                              *
   2644  *=============================================================================================*/
   2645 void InfantryClass::Response_Move(void)
   2646 {
   2647 	assert(Infantry.ID(this) == ID);
   2648 	assert(IsActive);
   2649 
   2650 	if (!AllowVoice) return;
   2651 
   2652 	if (Class->IsCivilian && *this != INFANTRY_EINSTEIN) {
   2653 		VocType response;
   2654 		if (Class->IsFemale) {
   2655 			response = VOC_GIRL_OKAY;
   2656 		} else {
   2657 			response = VOC_GUY_OKAY;
   2658 		}
   2659 		Sound_Effect(response, fixed(1), ID+1);
   2660 
   2661 	} else {
   2662 		static VocType _eng_response[] = {VOC_ENG_AFFIRM,VOC_ENG_AFFIRM};
   2663 		static VocType _ein_response[] = {VOC_E_OK,VOC_E_YES};
   2664 		static VocType _dog_response[] = {VOC_DOG_BARK};
   2665 		static VocType _spy_response[] = {VOC_SPY_ONWAY,VOC_SPY_KING,VOC_SPY_INDEED};
   2666 		static VocType _medic_response[] = {VOC_MED_AFFIRM,VOC_MED_MOVEOUT};
   2667 #ifdef ENGLISH
   2668 		static VocType _tanya_response[] = {VOC_TANYA_THERE,VOC_TANYA_ROCK};
   2669 #else
   2670 		static VocType _tanya_response[] = {VOC_TANYA_THERE,VOC_TANYA_GIVE};
   2671 #endif
   2672 		static VocType _thief_response[] = {VOC_THIEF_MOVEOUT,VOC_THIEF_OKAY,VOC_THIEF_AFFIRM};
   2673 		static VocType _default_response[] = {VOC_ROGER,VOC_RIGHT_AWAY,VOC_UGOTIT,VOC_AFFIRM,VOC_AFFIRM};
   2674 		static VocType _stavros[] = {VOC_STAVMOV,VOC_STAVCRSE};
   2675 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2676 		static VocType _mechanic[] = {VOC_MECHYES1,VOC_MECHRISE1,VOC_MECHHEAR1,VOC_MECHBOSS1};
   2677 		static VocType _shock[] = {VOC_STPOWER1,VOC_STDANCE1,VOC_STCHRGE1};
   2678 #endif
   2679 
   2680 		int size = 0;
   2681 		VocType * response = NULL;
   2682 		HousesType house = PlayerPtr->ActLike;
   2683 		switch (Class->Type) {
   2684 			case INFANTRY_GENERAL:
   2685 				if (house != HOUSE_USSR && house != HOUSE_BAD) {
   2686 					response = _stavros;
   2687 					size = ARRAY_SIZE(_stavros);
   2688 				} else {
   2689 					response = _default_response;
   2690 					size = ARRAY_SIZE(_default_response);
   2691 				}
   2692 				house = HOUSE_USSR;
   2693 				break;
   2694 
   2695 			case INFANTRY_DOG:
   2696 				response = _dog_response;
   2697 				size = ARRAY_SIZE(_dog_response);
   2698 				break;
   2699 
   2700 			case INFANTRY_EINSTEIN:
   2701 				response = _ein_response;
   2702 				size = ARRAY_SIZE(_ein_response);
   2703 				break;
   2704 
   2705 			case INFANTRY_RENOVATOR:
   2706 				response = _eng_response;
   2707 				size = ARRAY_SIZE(_eng_response);
   2708 				break;
   2709 
   2710 			case INFANTRY_SPY:
   2711 				response = _spy_response;
   2712 				size = ARRAY_SIZE(_spy_response);
   2713 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2714 				if(house == HOUSE_USSR) {
   2715 					response = _default_response;
   2716 					size = ARRAY_SIZE(_default_response);
   2717 				}
   2718 #endif
   2719 				break;
   2720 
   2721 			case INFANTRY_MEDIC:
   2722 				response = _medic_response;
   2723 				size = ARRAY_SIZE(_medic_response);
   2724 				break;
   2725 
   2726 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2727 			case INFANTRY_MECHANIC:
   2728 				response = _mechanic;
   2729 				size = ARRAY_SIZE(_mechanic);
   2730 				break;
   2731 
   2732 			case INFANTRY_SHOCK:
   2733 				response = _shock;
   2734 				size = ARRAY_SIZE(_shock);
   2735 				break;
   2736 
   2737 #endif
   2738 			case INFANTRY_TANYA:
   2739 				response = _tanya_response;
   2740 				size = ARRAY_SIZE(_tanya_response);
   2741 				break;
   2742 
   2743 			case INFANTRY_THIEF:
   2744 				response = _thief_response;
   2745 				size = ARRAY_SIZE(_thief_response);
   2746 				break;
   2747 
   2748 			default:
   2749 				response = _default_response;
   2750 				size = ARRAY_SIZE(_default_response);
   2751 				break;
   2752 		}
   2753 		if (response != NULL) {
   2754 			Sound_Effect(response[Sim_Random_Pick(0, size-1)], fixed(1), ID+1, 0, house);
   2755 		}
   2756 	}
   2757 }
   2758 
   2759 
   2760 /***********************************************************************************************
   2761  * InfantryClass::Response_Attack -- Plays infantry audio response to attack order.            *
   2762  *                                                                                             *
   2763  *    When the player gives an infantry unit the order to attack, this routine handles         *
   2764  *    the audio response by that unit.                                                         *
   2765  *                                                                                             *
   2766  * INPUT:   none                                                                               *
   2767  *                                                                                             *
   2768  * OUTPUT:  none                                                                               *
   2769  *                                                                                             *
   2770  * WARNINGS:   none                                                                            *
   2771  *                                                                                             *
   2772  * HISTORY:                                                                                    *
   2773  *   01/01/1995 JLB : Created.                                                                 *
   2774  *   05/05/1995 JLB : Rambo response types added.                                              *
   2775  *=============================================================================================*/
   2776 void InfantryClass::Response_Attack(void)
   2777 {
   2778 	assert(Infantry.ID(this) == ID);
   2779 	assert(IsActive);
   2780 
   2781 	if (!AllowVoice) return;
   2782 
   2783 	if (Class->IsCivilian && *this != INFANTRY_EINSTEIN) {
   2784 		VocType response;
   2785 		if (Class->IsFemale) {
   2786 			response = VOC_GIRL_OKAY;
   2787 		} else {
   2788 			response = VOC_GUY_OKAY;
   2789 		}
   2790 		Sound_Effect(response, fixed(1), ID+1);
   2791 
   2792 	} else {
   2793 		static VocType _eng_response[] = {VOC_ENG_AFFIRM,VOC_ENG_AFFIRM};
   2794 		static VocType _dog_response[] = {VOC_DOG_GROWL2};
   2795 		static VocType _ein_response[] = {VOC_E_OK,VOC_E_YES};
   2796 		static VocType _spy_response[] = {VOC_SPY_ONWAY,VOC_SPY_KING,VOC_SPY_INDEED};
   2797 		static VocType _medic_response[] = {VOC_MED_AFFIRM,VOC_MED_MOVEOUT};
   2798 #ifdef ENGLISH
   2799 		static VocType _tanya_response[] = {VOC_TANYA_CHEW,VOC_TANYA_CHING,VOC_TANYA_LAUGH};
   2800 #else
   2801 		static VocType _tanya_response[] = {VOC_TANYA_CHEW,VOC_TANYA_CHING,VOC_TANYA_LAUGH,VOC_TANYA_ROCK};
   2802 #endif
   2803 		static VocType _thief_response[] = {VOC_NONE};
   2804 		static VocType _default_response[] = {VOC_RIGHT_AWAY,VOC_AFFIRM,VOC_AFFIRM,VOC_UGOTIT,VOC_NO_PROB,VOC_YESSIR,VOC_YESSIR,VOC_YESSIR};
   2805 		static VocType _stavros[] = {VOC_STAVCRSE};
   2806 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2807 		static VocType _mechanic[] = {VOC_MECHYEEHAW1,VOC_MECHHOTDIG1,VOC_MECHWRENCH1};
   2808 		static VocType _shock[] = {VOC_STLIGHT1,VOC_STBURN1,VOC_STCRISP1,VOC_STSHOCK1};
   2809 #endif
   2810 
   2811 		int size = 0;
   2812 		VocType * response = NULL;
   2813 		HousesType house = PlayerPtr->ActLike;
   2814 		switch (Class->Type) {
   2815 			case INFANTRY_GENERAL:
   2816 				if (house != HOUSE_USSR && house != HOUSE_BAD) {
   2817 					response = _stavros;
   2818 					size = ARRAY_SIZE(_stavros);
   2819 				} else {
   2820 					response = _default_response;
   2821 					size = ARRAY_SIZE(_default_response);
   2822 				}
   2823 				house = HOUSE_USSR;
   2824 				break;
   2825 
   2826 			case INFANTRY_DOG:
   2827 				response = _dog_response;
   2828 				size = ARRAY_SIZE(_dog_response);
   2829 				break;
   2830 
   2831 			case INFANTRY_SPY:
   2832 				response = _spy_response;
   2833 				size = ARRAY_SIZE(_spy_response);
   2834 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2835 				if(house == HOUSE_USSR) {
   2836 					response = _default_response;
   2837 					size = ARRAY_SIZE(_default_response);
   2838 				}
   2839 #endif
   2840 				break;
   2841 
   2842 			case INFANTRY_EINSTEIN:
   2843 				response = _ein_response;
   2844 				size = ARRAY_SIZE(_ein_response);
   2845 				break;
   2846 
   2847 			case INFANTRY_RENOVATOR:
   2848 				response = _eng_response;
   2849 				size = ARRAY_SIZE(_eng_response);
   2850 				break;
   2851 
   2852 			case INFANTRY_MEDIC:
   2853 				response = _medic_response;
   2854 				size = ARRAY_SIZE(_medic_response);
   2855 				break;
   2856 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2857 			case INFANTRY_MECHANIC:
   2858 				response = _mechanic;
   2859 				size = ARRAY_SIZE(_mechanic);
   2860 				break;
   2861 
   2862 			case INFANTRY_SHOCK:
   2863 				response = _shock;
   2864 				size = ARRAY_SIZE(_shock);
   2865 				break;
   2866 #endif
   2867 			case INFANTRY_TANYA:
   2868 				response = _tanya_response;
   2869 				size = ARRAY_SIZE(_tanya_response);
   2870 				break;
   2871 
   2872 			case INFANTRY_THIEF:
   2873 				response = _thief_response;
   2874 				size = ARRAY_SIZE(_thief_response);
   2875 				break;
   2876 
   2877 			default:
   2878 				response = _default_response;
   2879 				size = ARRAY_SIZE(_default_response);
   2880 				break;
   2881 		}
   2882 		if (response != NULL) {
   2883 			Sound_Effect(response[Sim_Random_Pick(0, size-1)], fixed(1), ID+1, 0, house);
   2884 		}
   2885 	}
   2886 }
   2887 
   2888 
   2889 /***********************************************************************************************
   2890  * InfantryClass::What_Action -- Infantry units might be able to capture -- check.             *
   2891  *                                                                                             *
   2892  *    This routine checks to see if the infantry unit can capture the specified object rather  *
   2893  *    than merely attacking it. If this is the case, then ACTION_CAPTURE will be returned.     *
   2894  *                                                                                             *
   2895  * INPUT:   object   -- The object that the mouse is currently over.                           *
   2896  *                                                                                             *
   2897  * OUTPUT:  Returns the action that will be performed if the mouse were clicked over the       *
   2898  *          object specified.                                                                  *
   2899  *                                                                                             *
   2900  * WARNINGS:   none                                                                            *
   2901  *                                                                                             *
   2902  * HISTORY:                                                                                    *
   2903  *   03/01/1995 JLB : Created.                                                                 *
   2904  *=============================================================================================*/
   2905 ActionType InfantryClass::What_Action(ObjectClass const * object) const
   2906 {
   2907 	assert(Infantry.ID(this) == ID);
   2908 	assert(IsActive);
   2909 	assert(object != NULL);
   2910 
   2911 	ActionType action = FootClass::What_Action(object);
   2912 
   2913 	/*
   2914 	** If this is an engineer/renovator, we have to make some adjustments.
   2915 	** If the cursor is over an enemy building, return action-none.  If it's
   2916 	** over a friendly building, we have to return action-capture so he can
   2917 	** renovate it.
   2918 	** However, abort the whole thing if the building is a barrel or mine.
   2919 	*/
   2920 	if (*this == INFANTRY_RENOVATOR && object->What_Am_I() == RTTI_BUILDING && House->IsPlayerControl) {
   2921 		BuildingClass const * bldg = (BuildingClass *)object;
   2922 		if (bldg->Class->IsRepairable) {
   2923 			if (House->Is_Ally(bldg)) {
   2924 				if (bldg->Health_Ratio() == 1) {
   2925 					return(ACTION_NO_GREPAIR);
   2926 				}
   2927 				return(ACTION_GREPAIR);
   2928 			} else {
   2929 
   2930 				if (bldg->Can_Capture()) {
   2931 #ifdef FIXIT_ENGINEER	//	checked - ajw 9/28/98
   2932 					if (bldg->Health_Ratio() <= EngineerCaptureLevel) {
   2933 #else
   2934 					if (bldg->Health_Ratio() <= Rule.ConditionRed) {
   2935 #endif
   2936 						return(ACTION_CAPTURE);
   2937 					}
   2938 					return(ACTION_DAMAGE);
   2939 				}
   2940 
   2941 //				if (bldg->Health_Ratio() <= Rule.ConditionRed && bldg->Can_Capture()) {
   2942 			}
   2943 		}
   2944 	}
   2945 
   2946 	/*
   2947 	** If this is a medic, and the cursor's over a friendly infantryman,
   2948 	** execute an action-attack.  In CSII, if this is a mechanic and the
   2949 	** cursor's over a friendly vehicle, execute an action-attack.
   2950 	*/
   2951 	if (Combat_Damage() < 0 && House->IsPlayerControl) {
   2952 		if (House->Is_Ally(object)) {
   2953 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2954 			if( (object->What_Am_I() == RTTI_INFANTRY && object != this && *this == INFANTRY_MEDIC) ||
   2955 			    (*this == INFANTRY_MECHANIC && (object->What_Am_I() == RTTI_UNIT || object->What_Am_I() == RTTI_AIRCRAFT) ) ) {
   2956 
   2957 					if (object->Health_Ratio() < Rule.ConditionGreen) {
   2958 // If it's a mechanic force-moving into an APC, don't try to heal it.
   2959 						if(*this == INFANTRY_MECHANIC && object->What_Am_I() == RTTI_UNIT && *(UnitClass *)object == UNIT_APC && (Keyboard->Down(Options.KeyForceMove1) || Keyboard->Down(Options.KeyForceMove2)) ) {
   2960 						} else {
   2961 							return(ACTION_HEAL);
   2962 						}
   2963 					}
   2964 			}
   2965 #else
   2966 			if(object->What_Am_I() == RTTI_INFANTRY && object != this) {
   2967 				if (object->Health_Ratio() < Rule.ConditionGreen) {
   2968 					return(ACTION_HEAL);
   2969 				}
   2970 			}
   2971 #endif
   2972 			if(!object->Is_Techno() || !((TechnoClass *)object)->Techno_Type_Class()->Max_Passengers()) {
   2973 				if (action == ACTION_GUARD_AREA || action == ACTION_MOVE) {
   2974 					return(action);
   2975 				}
   2976 				return ((action == ACTION_TOGGLE_SELECT) ? ACTION_TOGGLE_SELECT : ACTION_SELECT);
   2977 			}
   2978 		} else {
   2979 			return(ACTION_NOMOVE);
   2980 		}
   2981 	}
   2982 
   2983 #ifdef OBSOLETE
   2984 	/*
   2985 	** See if it's a thief attacking an enemy vehicle, let him CAPTURE it.
   2986 	*/
   2987 	if (*this == INFANTRY_THIEF && object->What_Am_I() == RTTI_UNIT) {
   2988 		if (((UnitClass *)object)->House != House) {
   2989 			return(ACTION_CAPTURE);
   2990 		}
   2991 	}
   2992 #endif
   2993 
   2994 	/*
   2995 	** Dogs can only attack infantrymen
   2996 	*/
   2997 	if (Class->IsDog && action == ACTION_ATTACK && object->What_Am_I() != RTTI_INFANTRY) {
   2998 		action = ACTION_NONE;
   2999 	}
   3000 
   3001 	/*
   3002 	**	See if it's a commando, and if he's attacking a building,
   3003 	** have him return ACTION_SABOTAGE instead
   3004 	*/
   3005 	if (Class->IsBomber && action == ACTION_ATTACK && object->What_Am_I() == RTTI_BUILDING) {
   3006 		BuildingClass const * obj = (BuildingClass *)object;
   3007 		/*
   3008 		** Hack: Tanya should shoot barrels, bomb other structures.
   3009 		*/
   3010 		if (obj->Class->IsRepairable) {
   3011 //		if (*obj != STRUCT_BARREL && *obj != STRUCT_BARREL3) {
   3012 			return(ACTION_SABOTAGE);
   3013 		} else {
   3014 			return(ACTION_ATTACK);
   3015 		}
   3016 	}
   3017 
   3018 	/*
   3019 	** See if this infantry is trying to move onto where a land mine is.
   3020 	*/
   3021 	if (action == ACTION_NONE && object->What_Am_I() == RTTI_BUILDING && House->IsPlayerControl) {
   3022 		StructType blah = *((BuildingClass *)object);
   3023 		if (blah == STRUCT_AVMINE || blah == STRUCT_APMINE) return(ACTION_MOVE);
   3024 	}
   3025 
   3026 	/*
   3027 	**	There is no self-select action available for infantry types.
   3028 	*/
   3029 	if (action == ACTION_SELF) {
   3030 		action = ACTION_NONE;
   3031 	}
   3032 
   3033 	/*
   3034 	**	Check to see if it can enter a transporter.
   3035 	*/
   3036 	if (
   3037 		House->Is_Ally(object) &&
   3038 		House->IsPlayerControl && object->Is_Techno()) {
   3039 #ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
   3040  if (object->What_Am_I() != RTTI_VESSEL || *(VesselClass *)object != VESSEL_CARRIER) {
   3041 #endif
   3042 		switch (((InfantryClass *)this)->Transmit_Message(RADIO_CAN_LOAD, (TechnoClass*)object)) {
   3043 			case RADIO_ROGER:
   3044 				action = ACTION_ENTER;
   3045 				break;
   3046 
   3047 			case RADIO_NEGATIVE:
   3048 				action = ACTION_NO_ENTER;
   3049 				break;
   3050 
   3051 			default:
   3052 				break;
   3053 		}
   3054 #ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
   3055  }
   3056 #endif
   3057 	}
   3058 
   3059 	if (Class->IsCapture && action == ACTION_ATTACK) {
   3060 		if (!House->Is_Ally(object) && (
   3061 //Disable capturing of helicopters			 (object->What_Am_I() == RTTI_AIRCRAFT && ((AircraftClass *)object)->Pip_Count() == 0 && *((AircraftClass *)object) == AIRCRAFT_TRANSPORT) ||
   3062 			 (object->What_Am_I() == RTTI_BUILDING && object->Can_Capture()) )
   3063 			) {
   3064 
   3065 				if (*this == INFANTRY_THIEF && (object->What_Am_I() == RTTI_BUILDING && ((BuildingClass *)object)->Class->Capacity == 0)) {
   3066 					action = ACTION_NONE;
   3067 				} else {
   3068 
   3069 					/*
   3070 					** If we're trying to capture a building, make sure we can get
   3071 					** to it.  Find an adjacent cell that's the same zone as us.
   3072 					** The target circumstance is a naval yard that doesn't touch
   3073 					** the shore - a total island.  In that case, we can't capture
   3074 					** it, so we shouldn't show the action-capture cursor.
   3075 					*/
   3076 					action = ACTION_CAPTURE;
   3077 					if (object->What_Am_I() == RTTI_BUILDING) {
   3078 						CELL cell = ::As_Cell(object->As_Target());
   3079 						int targzone = Map[::As_Cell(As_Target())].Zones[Class->MZone];
   3080 						short const *list = ((BuildingClass *)object)->Class->Occupy_List(false);
   3081 						bool found = false;
   3082 						while (*list != REFRESH_EOL && !found) {
   3083 							CELL newcell = cell + *list++;
   3084 							for (FacingType i=FACING_N; i < FACING_COUNT; i++) {
   3085 								CELL adjcell = Adjacent_Cell(newcell, i);
   3086 								if ((unsigned)adjcell >= MAP_CELL_TOTAL) continue;
   3087 								if (Map[adjcell].Zones[Class->MZone] == targzone) {
   3088 									found = true;
   3089 									break;
   3090 								}
   3091 							}
   3092 						}
   3093 						if (!found) {
   3094 							action = ACTION_NONE;
   3095 						}
   3096 					}
   3097 				}
   3098 		} else {
   3099 			if (!Is_Weapon_Equipped()) {
   3100 				action = ACTION_NONE;
   3101 			}
   3102 		}
   3103 	}
   3104 
   3105 	/*
   3106 	**	If it doesn't know what to do with the object, then just
   3107 	**	say it can't move there.
   3108 	*/
   3109 	if (action == ACTION_NONE) action = ACTION_NOMOVE;
   3110 
   3111 	return(action);
   3112 }
   3113 
   3114 
   3115 /***********************************************************************************************
   3116  * InfantryClass::Active_Click_With -- Handles action when clicking with infantry soldier.     *
   3117  *                                                                                             *
   3118  *    This routine is called when the player clicks over an object while this infantry soldier *
   3119  *    is selected. Capture attempts are prohibited if the infantry cannot capture. The         *
   3120  *    command might respond if told to sabotage something.                                     *
   3121  *                                                                                             *
   3122  * INPUT:   action   -- The action that is nominally to be performed.                          *
   3123  *                                                                                             *
   3124  *          object   -- The object over which the mouse was clicked.                           *
   3125  *                                                                                             *
   3126  * OUTPUT:  none                                                                               *
   3127  *                                                                                             *
   3128  * WARNINGS:   none                                                                            *
   3129  *                                                                                             *
   3130  * HISTORY:                                                                                    *
   3131  *   05/08/1995 JLB : Created.                                                                 *
   3132  *=============================================================================================*/
   3133 void InfantryClass::Active_Click_With(ActionType action, ObjectClass * object)
   3134 {
   3135 	assert(Infantry.ID(this) == ID);
   3136 	assert(IsActive);
   3137 
   3138 	action = What_Action(object);
   3139 
   3140 	switch (action) {
   3141 		case ACTION_GREPAIR:
   3142 		case ACTION_DAMAGE:
   3143 		case ACTION_CAPTURE:
   3144 			action = ACTION_CAPTURE;
   3145 			break;
   3146 
   3147 		case ACTION_HEAL:
   3148 			action = ACTION_ATTACK;
   3149 			break;
   3150 
   3151 //		case ACTION_ENTER:
   3152 //			action = ACTION_MOVE;
   3153 //			break;
   3154 
   3155 		case ACTION_SABOTAGE:
   3156 		case ACTION_ATTACK:
   3157 		case ACTION_GUARD_AREA:
   3158 		case ACTION_MOVE:
   3159 			action = action;
   3160 			break;
   3161 
   3162 		default:
   3163 //			action = ACTION_NONE;
   3164 			break;
   3165 	}
   3166 
   3167 	FootClass::Active_Click_With(action, object);
   3168 }
   3169 
   3170 
   3171 /***********************************************************************************************
   3172  * InfantryClass::Set_Occupy_Bit -- Sets the occupy bit cell and bit pos                       *
   3173  *                                                                                             *
   3174  * INPUT:      CELL      - the cell we are setting the bit in                                  *
   3175  *                                                                                             *
   3176  *               int      - the spot index we are setting the bit for                          *
   3177  *                                                                                             *
   3178  * OUTPUT:     none                                                                            *
   3179  *                                                                                             *
   3180  * HISTORY:                                                                                    *
   3181  *   06/08/1995 PWG : Created.                                                                 *
   3182  *=============================================================================================*/
   3183 void InfantryClass::Set_Occupy_Bit(CELL cell, int spot_index)
   3184 {
   3185 	assert(Infantry.ID(this) == ID);
   3186 	assert(IsActive);
   3187 
   3188 	/*
   3189 	** Set the occupy position for the spot that we passed in
   3190 	*/
   3191 	Map[cell].Flag.Composite |= (1 << spot_index);
   3192 
   3193 	/*
   3194 	** Record the type of infantry that now owns the cell
   3195 	*/
   3196 	Map[cell].InfType = Owner();
   3197 }
   3198 
   3199 
   3200 /***************************************************************************
   3201  * InfantryClass::Clear_Occupy_Bit -- Clears occupy bit and given cell		*
   3202  *                                                                         *
   3203  * INPUT:                                                                  *
   3204  *                                                                         *
   3205  * OUTPUT:                                                                 *
   3206  *                                                                         *
   3207  * WARNINGS:                                                               *
   3208  *                                                                         *
   3209  * HISTORY:                                                                *
   3210  *   06/08/1995 PWG : Created.                                             *
   3211  *=========================================================================*/
   3212 void InfantryClass::Clear_Occupy_Bit(CELL cell, int spot_index)
   3213 {
   3214 	assert(Infantry.ID(this) == ID);
   3215 	assert(IsActive);
   3216 
   3217 	/*
   3218 	** Clear the occupy bit for the infantry in that cell
   3219 	*/
   3220 	Map[cell].Flag.Composite &= ~(1 << spot_index);
   3221 
   3222 	/*
   3223 	** If he was the last infantry recorded in the cell then
   3224 	** remove the infantry ownership flag.
   3225 	*/
   3226 	if (!(Map[cell].Flag.Composite & 0x1F)) {
   3227 		Map[cell].InfType = HOUSE_NONE;
   3228 	}
   3229 }
   3230 
   3231 
   3232 /***********************************************************************************************
   3233  * InfantryClass::Full_Name -- Fetches the full name of the infantry unit.                     *
   3234  *                                                                                             *
   3235  *    This routine will return with the full name (as a text number) for this infantry         *
   3236  *    unit. Typically, this is the normal name, but in cases of civilian type survivors from   *
   3237  *    a building explosion, it might be a technician instead. In such a case, the special      *
   3238  *    technician name number is returned instead.                                              *
   3239  *                                                                                             *
   3240  * INPUT:   none                                                                               *
   3241  *                                                                                             *
   3242  * OUTPUT:  Returns with the full name to use for this infantry unit.                          *
   3243  *                                                                                             *
   3244  * WARNINGS:   none                                                                            *
   3245  *                                                                                             *
   3246  * HISTORY:                                                                                    *
   3247  *   06/30/1995 JLB : Created.                                                                 *
   3248  *   10/28/1996 JLB : Spy returns "enemy soldier" text name.                                   *
   3249  *=============================================================================================*/
   3250 int InfantryClass::Full_Name(void) const
   3251 {
   3252 	assert(Infantry.ID(this) == ID);
   3253 	assert(IsActive);
   3254 
   3255 	if (IsTechnician) {
   3256 		return(TXT_TECHNICIAN);
   3257 	}
   3258 
   3259 	if (*this == INFANTRY_SPY && !House->IsPlayerControl) {
   3260 		return(TXT_E1);
   3261 	}
   3262 
   3263 	return(Class->Full_Name());
   3264 }
   3265 
   3266 
   3267 /***********************************************************************************************
   3268  * InfantryClass::Mission_Attack -- Intercept attack mission for special handling.             *
   3269  *                                                                                             *
   3270  *    This routine intercepts the normal attack mission and if an engineer is detected and the *
   3271  *    target is a building, then the engineer will be automatically assigned the capture       *
   3272  *    mission. In other cases, the normal attack logic will proceed.                           *
   3273  *                                                                                             *
   3274  * INPUT:   none                                                                               *
   3275  *                                                                                             *
   3276  * OUTPUT:  Returns with the number of game frames to delay before calling this routine again. *
   3277  *                                                                                             *
   3278  * WARNINGS:   none                                                                            *
   3279  *                                                                                             *
   3280  * HISTORY:                                                                                    *
   3281  *   08/07/1995 JLB : Created.                                                                 *
   3282  *   04/15/1996 BWG : Engineers can only attack their own house's buildings now.               *
   3283  *   05/29/1996 JLB : Engineers can now damage/capture enemy buildings.                        *
   3284  *=============================================================================================*/
   3285 int InfantryClass::Mission_Attack(void)
   3286 {
   3287 	assert(Infantry.ID(this) == ID);
   3288 	assert(IsActive);
   3289 
   3290 	if (Class->IsBomber && As_Building(TarCom)) {
   3291 		Assign_Destination(TarCom);
   3292 		Assign_Mission(MISSION_SABOTAGE);
   3293 		return(1);
   3294 	}
   3295 
   3296 	if (Class->IsCapture && As_Building(TarCom) != NULL && As_Building(TarCom)->Can_Capture()) {
   3297 		Assign_Destination(TarCom);
   3298 		Assign_Mission(MISSION_CAPTURE);
   3299 		return(1);
   3300 	}
   3301 
   3302 	return(FootClass::Mission_Attack());
   3303 }
   3304 
   3305 
   3306 /***********************************************************************************************
   3307  * InfantryClass::What_Action -- Determines what action to perform for the cell specified.     *
   3308  *                                                                                             *
   3309  *    This routine will determine what action to perform if the mouse was clicked on the cell  *
   3310  *    specified. This is just a courier function since the lower level classes actually        *
   3311  *    perform the work. The need for this routine at this level is due to the existence of     *
   3312  *    a similarly named function at this level as well.  C++ namespace rules require this      *
   3313  *    function courier to be in place or an error will result.                                 *
   3314  *                                                                                             *
   3315  * INPUT:   cell  -- The cell that the mouse might be clicked upon.                            *
   3316  *                                                                                             *
   3317  * OUTPUT:  Returns with the action that would be given to this infantry unit if the mouse     *
   3318  *          were clicked at the cell specified.                                                *
   3319  *                                                                                             *
   3320  * WARNINGS:   none                                                                            *
   3321  *                                                                                             *
   3322  * HISTORY:                                                                                    *
   3323  *   09/21/1995 JLB : Created.                                                                 *
   3324  *=============================================================================================*/
   3325 ActionType InfantryClass::What_Action(CELL cell) const
   3326 {
   3327 	assert(Infantry.ID(this) == ID);
   3328 	assert(IsActive);
   3329 
   3330 	ActionType action = FootClass::What_Action(cell);
   3331 
   3332 	/*
   3333 	** Dogs can only attack infantrymen
   3334 	*/
   3335 	if (Class->IsDog && action == ACTION_ATTACK) {
   3336 		action = ACTION_NONE;
   3337 	}
   3338 
   3339 	/*
   3340 	** If this is a medic, and the cursor's over a friendly infantryman,
   3341 	** execute an action-attack.
   3342 	*/
   3343 	if (Combat_Damage() < 0 && House->IsPlayerControl) {
   3344 		if (action == ACTION_ATTACK) {
   3345 			action = ACTION_NOMOVE;
   3346 		}
   3347 	}
   3348 
   3349 	/*
   3350 	**	Demolitioners may destroy a bridge
   3351 	*/
   3352 	if (Class->IsBomber && action == ACTION_MOVE && !Special.IsCaptureTheFlag) {
   3353 		switch (Map[cell].TType) {
   3354 			case TEMPLATE_BRIDGE1:
   3355 			case TEMPLATE_BRIDGE2:
   3356 			case TEMPLATE_BRIDGE1H:
   3357 			case TEMPLATE_BRIDGE2H:
   3358 			case TEMPLATE_BRIDGE_1A:
   3359 			case TEMPLATE_BRIDGE_1B:
   3360 			case TEMPLATE_BRIDGE_2A:
   3361 			case TEMPLATE_BRIDGE_2B:
   3362 //			case TEMPLATE_BRIDGE_3A:
   3363 //			case TEMPLATE_BRIDGE_3B:
   3364 				return(ACTION_SABOTAGE);
   3365 		}
   3366 	}
   3367 
   3368 #ifdef OBSOLETE
   3369 	/*
   3370 	** Engineers may repair a destroyed bridge.
   3371 	*/
   3372 	if (*this == INFANTRY_RENOVATOR && action == ACTION_NOMOVE) {
   3373 		/*
   3374 		** If they're pointing on the wrong side of the bridge, ignore it
   3375 		** 'cause we can't get there.
   3376 		*/
   3377 		TemplateType tt = Map[cell].TType;
   3378 		if (tt == TEMPLATE_BRIDGE1D || tt == TEMPLATE_BRIDGE2D ||
   3379 			tt == TEMPLATE_BRIDGE_1C || tt == TEMPLATE_BRIDGE_2C ||
   3380 			(tt >= TEMPLATE_BRIDGE_3C && tt <= TEMPLATE_BRIDGE_3E) ) {
   3381 			/*
   3382 			** We know they're pointing at a destroyed bridge cell.  If the cell
   3383 			** they're pointing at is surrounded by impassables, return this
   3384 			** cell as impassable.  But, if any cell surrounding this cell is
   3385 			** passable, return that this is a capturable cell.
   3386 			*/
   3387 			if (Map[cell].Land_Type() == LAND_ROCK) {
   3388 				if (tt == TEMPLATE_BRIDGE_3C) return(ACTION_CAPTURE);
   3389 
   3390 				if (tt == TEMPLATE_BRIDGE_3C) return(ACTION_CAPTURE);
   3391 				int y = Cell_Y(cell);
   3392 				if (y) {
   3393 					LandType above = Map[(CELL)(cell-(MAP_CELL_W-1))].Land_Type();
   3394 					if (above == LAND_CLEAR || above == LAND_ROAD) {
   3395 						if (Map[(CELL)(cell-(MAP_CELL_W-1))].Zone == Map[As_Cell(As_Target())].Zone) {
   3396 							return(ACTION_CAPTURE);
   3397 						}
   3398 						return(ACTION_NOMOVE);
   3399 					}
   3400 				}
   3401 				if (y < MAP_CELL_H) {
   3402 					LandType below = Map[(CELL)(cell + MAP_CELL_W-1)].Land_Type();
   3403 					if (below == LAND_CLEAR || below == LAND_ROAD) {
   3404 						if (Map[(CELL)(cell+MAP_CELL_W-1)].Zone == Map[As_Cell(As_Target())].Zone) {
   3405 							return(ACTION_CAPTURE);
   3406 						}
   3407 						return(ACTION_NOMOVE);
   3408 					}
   3409 				}
   3410 			}
   3411 			return(ACTION_NOMOVE);
   3412 		}
   3413 	}
   3414 #endif
   3415 	return(action);
   3416 }
   3417 
   3418 
   3419 /***********************************************************************************************
   3420  * InfantryClass::Class_Of -- Returns the class reference for this object.                     *
   3421  *                                                                                             *
   3422  *    This routine will return a reference to the infantry type class object that describes    *
   3423  *    this infantry's characteristics.                                                         *
   3424  *                                                                                             *
   3425  * INPUT:   none                                                                               *
   3426  *                                                                                             *
   3427  * OUTPUT:  Returns with a reference to the InfantryTypeClass object associated with this      *
   3428  *          infantry object.                                                                   *
   3429  *                                                                                             *
   3430  * WARNINGS:   none                                                                            *
   3431  *                                                                                             *
   3432  * HISTORY:                                                                                    *
   3433  *   09/21/1995 JLB : Created.                                                                 *
   3434  *=============================================================================================*/
   3435 ObjectTypeClass const & InfantryClass::Class_Of(void) const
   3436 {
   3437 	assert(Infantry.ID(this) == ID);
   3438 	assert(IsActive);
   3439 
   3440 	return(*Class);
   3441 }
   3442 
   3443 
   3444 /***********************************************************************************************
   3445  * InfantryClass::Read_INI -- Reads units from scenario INI file.                              *
   3446  *                                                                                             *
   3447  *    This routine is used to read all the starting units from the                             *
   3448  *    scenario control INI file. The units are created and placed on the                       *
   3449  *    map by this routine.                                                                     *
   3450  *                                                                                             *
   3451  *    INI entry format:                                                                        *
   3452  *      Housename, Typename, Strength, Cellnum, CellSublocation, Missionname,                  *
   3453  *         Facingnum, Triggername                                                              *
   3454  *                                                                                             *
   3455  * INPUT:   buffer   -- Pointer to the loaded scenario INI file.                               *
   3456  *                                                                                             *
   3457  * OUTPUT:  none                                                                               *
   3458  *                                                                                             *
   3459  * WARNINGS:   none                                                                            *
   3460  *                                                                                             *
   3461  * HISTORY:                                                                                    *
   3462  *   05/24/1994 JLB : Created.                                                                 *
   3463  *=============================================================================================*/
   3464 void InfantryClass::Read_INI(CCINIClass & ini)
   3465 {
   3466 	InfantryClass	* infantry;			// Working infantry pointer.
   3467 	HousesType		inhouse;			// Infantry house.
   3468 	InfantryType	classid;			// Infantry class.
   3469 	char				buf[128];
   3470 	char				* validation;
   3471 	DirType 			dir;
   3472 	TriggerTypeClass	* tp;
   3473 
   3474 	int len = ini.Entry_Count(INI_Name());
   3475 	for (int index = 0; index < len; index++) {
   3476 		char const * entry = ini.Get_Entry(INI_Name(), index);
   3477 
   3478 		/*
   3479 		**	Get an infantry entry
   3480 		*/
   3481 		ini.Get_String(INI_Name(), entry, NULL, buf, sizeof(buf));
   3482 
   3483 		/*
   3484 		**	1st token: house name.
   3485 		*/
   3486 		inhouse = HouseTypeClass::From_Name(strtok(buf, ",\n\r"));
   3487 		if (inhouse != HOUSE_NONE) {
   3488 
   3489 			/*
   3490 			**	2nd token: infantry type name.
   3491 			*/
   3492 			classid = InfantryTypeClass::From_Name(strtok(NULL, ",\n\r"));
   3493 
   3494 			if (classid != INFANTRY_NONE) {
   3495 
   3496 				if (HouseClass::As_Pointer(inhouse) != NULL) {
   3497 					infantry = new InfantryClass(classid, inhouse);
   3498 					if (infantry != NULL) {
   3499 
   3500 						/*
   3501 						**	3rd token: strength.
   3502 						*/
   3503 						int strength = atoi(strtok(NULL, ",\n\r"));
   3504 
   3505 						/*
   3506 						**	4th token: cell #.
   3507 						*/
   3508 						CELL cell = atoi(strtok(NULL, ",\n\r"));
   3509 						COORDINATE coord = Cell_Coord(cell);
   3510 
   3511 						/*
   3512 						**	5th token: cell sub-location.
   3513 						*/
   3514 						int sub = atoi(strtok(NULL, ","));
   3515 						coord = Coord_Add(Coord_Whole(coord), StoppingCoordAbs[ sub ]);
   3516 
   3517 						/*
   3518 						**	Fetch the mission and facing.
   3519 						*/
   3520 						MissionType mission = MissionClass::Mission_From_Name(strtok(NULL, ",\n\r"));
   3521 						validation = strtok(NULL, ",\n\r");
   3522 						if (validation) {
   3523 							dir = (DirType)atoi(validation);
   3524 							validation = strtok(NULL, ",\n\r");
   3525 							if (validation) {
   3526 								tp = TriggerTypeClass::From_Name(validation);
   3527 							} else {
   3528 								tp = NULL;
   3529 							}
   3530 						} else {
   3531 							dir = (DirType)0;
   3532 							tp = NULL;
   3533 						}
   3534 
   3535 						infantry->Trigger = NULL;
   3536 						if (tp != NULL) {
   3537 							TriggerClass * tt = Find_Or_Make(tp);
   3538 							if (tt != NULL) {
   3539 								tt->AttachCount++;
   3540 								infantry->Trigger = tt;
   3541 							}
   3542 						}
   3543 
   3544 						if (infantry->Unlimbo(coord, dir)) {
   3545 							infantry->Strength = (int)infantry->Class_Of().MaxStrength * fixed(strength, 256);
   3546 							if (infantry->Strength > infantry->Class->MaxStrength-3) infantry->Strength = infantry->Class->MaxStrength;
   3547 	//						infantry->Strength = Fixed_To_Cardinal(infantry->Class_Of().MaxStrength, strength);
   3548 							if (Session.Type == GAME_NORMAL || infantry->House->IsHuman) {
   3549 								infantry->Assign_Mission(mission);
   3550 								infantry->Commence();
   3551 							} else {
   3552 								infantry->Enter_Idle_Mode();
   3553 							}
   3554 						} else {
   3555 
   3556 							/*
   3557 							**	If the infantry could not be unlimboed, then this is a big error.
   3558 							**	Delete the infantry.
   3559 							*/
   3560 							delete infantry;
   3561 						}
   3562 					}
   3563 				}
   3564 			}
   3565 		}
   3566 	}
   3567 }
   3568 
   3569 
   3570 /***********************************************************************************************
   3571  * InfantryClass::Write_INI -- Store the infantry to the INI database.                         *
   3572  *                                                                                             *
   3573  *    This will store all the infantry objects to the INI database specified.                  *
   3574  *                                                                                             *
   3575  * INPUT:   ini   -- Reference to the INI database to store the infantry data to.              *
   3576  *                                                                                             *
   3577  * OUTPUT:  none                                                                               *
   3578  *                                                                                             *
   3579  * WARNINGS:   none                                                                            *
   3580  *                                                                                             *
   3581  * HISTORY:                                                                                    *
   3582  *   07/03/1996 JLB : Created.                                                                 *
   3583  *=============================================================================================*/
   3584 void InfantryClass::Write_INI(CCINIClass & ini)
   3585 {
   3586 	/*
   3587 	**	First, clear out all existing infantry data from the ini file.
   3588 	*/
   3589 	ini.Clear(INI_Name());
   3590 
   3591 	/*
   3592 	**	Write the infantry data out.
   3593 	*/
   3594 	for (int index = 0; index < Infantry.Count(); index++) {
   3595 		InfantryClass * infantry = Infantry.Ptr(index);
   3596 		if (!infantry->IsInLimbo) {
   3597 			char	uname[10];
   3598 			char	buf[128];
   3599 
   3600 			sprintf(uname, "%d", index);
   3601 			sprintf(buf, "%s,%s,%d,%u,%d,%s,%d,%s",
   3602 					infantry->House->Class->IniName,
   3603 					infantry->Class->IniName,
   3604 					infantry->Health_Ratio()*256,
   3605 					Coord_Cell(infantry->Coord),
   3606 					CellClass::Spot_Index(infantry->Coord),
   3607 					MissionClass::Mission_Name((infantry->Mission == MISSION_NONE) ?
   3608 						infantry->MissionQueue : infantry->Mission),
   3609 					infantry->PrimaryFacing.Current(),
   3610 					infantry->Trigger.Is_Valid() ? infantry->Trigger->Class->IniName : "None"
   3611 				);
   3612 			ini.Put_String(INI_Name(), uname, buf);
   3613 		}
   3614 	}
   3615 }
   3616 
   3617 
   3618 /***********************************************************************************************
   3619  * InfantryClass::Fear_AI -- Process any fear related affects on this infantry.                *
   3620  *                                                                                             *
   3621  *    Use this routine to handle the fear logic for this infantry. It will slowly increase     *
   3622  *    the bravery of the infantry as well as cause it to stand up or lie down as appropriate.  *
   3623  *    It will even handle the special fraidy cat logic for civilian infantry.                  *
   3624  *                                                                                             *
   3625  * INPUT:   none                                                                               *
   3626  *                                                                                             *
   3627  * OUTPUT:  none                                                                               *
   3628  *                                                                                             *
   3629  * WARNINGS:   Only call this once per game logic loop per infantry unit.                      *
   3630  *                                                                                             *
   3631  * HISTORY:                                                                                    *
   3632  *   07/29/1996 JLB : Created.                                                                 *
   3633  *=============================================================================================*/
   3634 void InfantryClass::Fear_AI(void)
   3635 {
   3636 	/*
   3637 	**	After a time, the infantry will gain courage.
   3638 	*/
   3639 	if (Fear > 0) {
   3640 
   3641 		Fear--;
   3642 
   3643 		/*
   3644 		**	When an armed civilian becomes unafraid, he will then reload
   3645 		**	another clip into his pistol.
   3646 		*/
   3647 		if (Fear == 0 && Ammo == 0 && Is_Weapon_Equipped()) {
   3648 			Ammo = Class->MaxAmmo;
   3649 		}
   3650 
   3651 		/*
   3652 		**	Stand up if brave and lie down if afraid.
   3653 		*/
   3654 		if (IsProne) {
   3655 			if (Fear < FEAR_ANXIOUS) {
   3656 				Do_Action(DO_GET_UP);
   3657 			}
   3658 		} else  {
   3659 
   3660 			/*
   3661 			**	Drop to the ground if anxious. Don't drop to the ground while moving
   3662 			**	and the special elite flag is active.
   3663 			*/
   3664 			if (!Class->IsDog && Height == 0 && Fear >= FEAR_ANXIOUS && ((!Target_Legal(NavCom) && !IsDriving))) {
   3665 				Do_Action(DO_LIE_DOWN);
   3666 			}
   3667 		}
   3668 	}
   3669 
   3670 	/*
   3671 	**	When in darkness or in doubt,
   3672 	**		run in circles, scream, and shout.
   3673 	*/
   3674 	if (Class->IsFraidyCat && Fear > FEAR_ANXIOUS && !IsFalling && !IsDriving && !Target_Legal(NavCom)) {
   3675 		Scatter(0, true);
   3676 	}
   3677 }
   3678 
   3679 
   3680 /***********************************************************************************************
   3681  * InfantryClass::Edge_Of_World_AI -- Detects when infantry has left the map.                  *
   3682  *                                                                                             *
   3683  *    This routine will detect when the infantry has left the edge of the world and will       *
   3684  *    delete it as necessary.                                                                  *
   3685  *                                                                                             *
   3686  * INPUT:   none                                                                               *
   3687  *                                                                                             *
   3688  * OUTPUT:  bool; Was the infantry unit deleted by this routine?                               *
   3689  *                                                                                             *
   3690  * WARNINGS:   Be sure the check the return value and if true, abort any further processing    *
   3691  *             for this infantry unit.                                                         *
   3692  *                                                                                             *
   3693  * HISTORY:                                                                                    *
   3694  *   07/29/1996 JLB : Created.                                                                 *
   3695  *=============================================================================================*/
   3696 bool InfantryClass::Edge_Of_World_AI(void)
   3697 {
   3698 	/*
   3699 	**	Delete this unit if it finds itself off the edge of the map and it is in
   3700 	**	guard or other static mission mode.
   3701 	*/
   3702 	if (Team.Is_Valid() && IsLocked) Team->IsLeaveMap = true;
   3703 
   3704 	if (!Team.Is_Valid() && Mission == MISSION_GUARD && !Map.In_Radar(Coord_Cell(Coord))) {
   3705 		Stun();
   3706 		delete this;
   3707 		return(true);
   3708 	}
   3709 	return(false);
   3710 }
   3711 
   3712 
   3713 /***********************************************************************************************
   3714  * InfantryClass::Firing_AI -- Handles firing and combat AI for the infantry.                  *
   3715  *                                                                                             *
   3716  *    This will examine the infantry and determine what firing action is required. It will     *
   3717  *    search for targets, starting firing animations, and launch bullets as necessary.         *
   3718  *                                                                                             *
   3719  * INPUT:   none                                                                               *
   3720  *                                                                                             *
   3721  * OUTPUT:  none                                                                               *
   3722  *                                                                                             *
   3723  * WARNINGS:   Only call this routine once per infantry per game logic loop.                   *
   3724  *                                                                                             *
   3725  * HISTORY:                                                                                    *
   3726  *   07/29/1996 JLB : Created.                                                                 *
   3727  *=============================================================================================*/
   3728 void InfantryClass::Firing_AI(void)
   3729 {
   3730 	if (Target_Legal(TarCom)) {
   3731 		int primary = What_Weapon_Should_I_Use(TarCom);
   3732 
   3733 		if (!IsFiring) {
   3734 			switch (Can_Fire(TarCom, primary)) {
   3735 				case FIRE_ILLEGAL:
   3736 					if (Combat_Damage(primary) < 0) {
   3737 						ObjectClass * targ= As_Object(TarCom);
   3738 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   3739 						if (targ) {
   3740 							if( (targ->What_Am_I() == RTTI_INFANTRY && *this == INFANTRY_MEDIC) ||
   3741 								 (*this == INFANTRY_MECHANIC && (targ->What_Am_I() == RTTI_AIRCRAFT || targ->What_Am_I() == RTTI_UNIT )) ) {
   3742 
   3743 									if (targ->Health_Ratio() >= Rule.ConditionGreen) {
   3744 										Assign_Target(TARGET_NONE);
   3745 									}
   3746 							}
   3747 						} else {
   3748 							Assign_Target(TARGET_NONE);
   3749 						}
   3750 #else
   3751 						if (targ && targ->What_Am_I() == RTTI_INFANTRY) {
   3752 							if (targ->Health_Ratio() >= Rule.ConditionGreen) {
   3753 								Assign_Target(TARGET_NONE);
   3754 							}
   3755 						} else {
   3756 							Assign_Target(TARGET_NONE);
   3757 						}
   3758 #endif
   3759 					} else if (Class->IsDog) {
   3760 						Assign_Target(TARGET_NONE);
   3761 					}
   3762 					break;
   3763 
   3764 				case FIRE_CLOAKED:
   3765 					Do_Uncloak();
   3766 					break;
   3767 
   3768 				case FIRE_OK:
   3769 					/*
   3770 					**	Start firing animation.
   3771 					*/
   3772 					if (IsProne) {
   3773 						Do_Action(DO_FIRE_PRONE);
   3774 					} else {
   3775 						Do_Action(DO_FIRE_WEAPON);
   3776 					}
   3777 
   3778 					Mark(MARK_OVERLAP_UP);
   3779 					IsFiring = true;
   3780 					Mark(MARK_OVERLAP_DOWN);
   3781 
   3782 					PrimaryFacing.Set(Direction8(Center_Coord(), As_Coord(TarCom)));
   3783 
   3784 					/*
   3785 					**	If the target is in range, and the NavCom is the same, then just
   3786 					**	stop and keep firing.
   3787 					*/
   3788 					if (TarCom == NavCom) {
   3789 						NavCom = TARGET_NONE;
   3790 						Path[0] = FACING_NONE;
   3791 					}
   3792 					break;
   3793 			}
   3794 		}
   3795 
   3796 		/*
   3797 		**	If in the middle of firing animation, then only
   3798 		**	process that. Infantry cannot fire and move simultaneously.
   3799 		**	At some point in the firing animation process, a projectile
   3800 		**	will be launched. When the required animation frames have
   3801 		**	been completed, the firing animation stops.
   3802 		*/
   3803 		int firestage = Class->FireLaunch;
   3804 		if (IsProne) firestage = Class->ProneLaunch;
   3805 
   3806 		if (IsFiring && Fetch_Stage() == firestage) {
   3807 
   3808 			/*
   3809 			**	Target might have changed during the firing animation
   3810 			*/
   3811 			if (Can_Fire(TarCom, primary) == FIRE_OK) {
   3812 				Fire_At(TarCom, primary);
   3813 
   3814 				/*
   3815 				**	Run away from slowly approaching projectiles.
   3816 				*/
   3817 				if (Class->PrimaryWeapon->MaxSpeed < Rule.Incoming) {
   3818 					Map[::As_Cell(TarCom)].Incoming(Coord, true);
   3819 				}
   3820 
   3821 				/*
   3822 				** If it's a dog, get rid of him (he'll be re-created when he hits)
   3823 				*/
   3824 				if (Class->IsDog) {
   3825 					WasSelected = IsSelected;
   3826 					ScenarioInit++;
   3827 					Limbo();
   3828 					ScenarioInit--;
   3829 				}
   3830 			} else {
   3831 				Mark(MARK_OVERLAP_UP);
   3832 				IsFiring = false;
   3833 				Mark(MARK_OVERLAP_DOWN);
   3834 			}
   3835 		}
   3836 	} else {
   3837 		if (IsFiring) {
   3838 			Mark(MARK_OVERLAP_UP);
   3839 			IsFiring = false;
   3840 			Mark(MARK_OVERLAP_DOWN);
   3841 		}
   3842 	}
   3843 }
   3844 
   3845 
   3846 /***********************************************************************************************
   3847  * InfantryClass::Doing_AI -- Handles the animation AI processing.                             *
   3848  *                                                                                             *
   3849  *    Infantry can be in one of many different animation sequences. At the conclusion of each  *
   3850  *    sequence, the infantry will quite likely transition to a new animation state. This       *
   3851  *    routine handles detecting when that trasition should occur and starting the infantry     *
   3852  *    into its new state.                                                                      *
   3853  *                                                                                             *
   3854  * INPUT:   none                                                                               *
   3855  *                                                                                             *
   3856  * OUTPUT:  none                                                                               *
   3857  *                                                                                             *
   3858  * WARNINGS:   Only call this routine once per infantry unit per game logic loop.              *
   3859  *                                                                                             *
   3860  * HISTORY:                                                                                    *
   3861  *   07/29/1996 JLB : Created.                                                                 *
   3862  *=============================================================================================*/
   3863 void InfantryClass::Doing_AI(void)
   3864 {
   3865 	if (Doing == DO_NOTHING || Fetch_Stage() >= Class->DoControls[Doing].Count) {
   3866 		switch (Doing) {
   3867 			default:
   3868 				if (IsDriving) {
   3869 					if (Class->IsDog) {
   3870 
   3871 						/*
   3872 						**	Dog crawl animation is actually the run animation.
   3873 						*/
   3874 						if (Target_Legal(TarCom)) {
   3875 							Do_Action(DO_CRAWL, true);
   3876 						} else {
   3877 							Do_Action(DO_WALK, true);
   3878 						}
   3879 					} else {
   3880 						if (IsProne) {
   3881 							Do_Action(DO_CRAWL, true);
   3882 						} else {
   3883 							Do_Action(DO_WALK, true);
   3884 						}
   3885 					}
   3886 				} else {
   3887 					if (Class->IsDog) {
   3888 						Do_Action(DO_STAND_READY, true);
   3889 					} else {
   3890 						if (IsProne) {
   3891 							Do_Action(DO_PRONE, true);
   3892 						} else {
   3893 							Do_Action(DO_STAND_READY, true);
   3894 						}
   3895 					}
   3896 				}
   3897 				break;
   3898 
   3899 			case DO_DOG_MAUL:
   3900 				Do_Action(DO_STAND_READY, true);
   3901 				break;
   3902 
   3903 			case DO_GUN_DEATH:
   3904 			case DO_EXPLOSION_DEATH:
   3905 			case DO_EXPLOSION2_DEATH:
   3906 			case DO_GRENADE_DEATH:
   3907 			case DO_FIRE_DEATH:
   3908 				if (Fetch_Stage() >= Class->DoControls[Doing].Count) {
   3909 					AnimClass* anim = NULL;
   3910 					LandType land = Map[Center_Coord()].Land_Type();
   3911 					if (land != LAND_ROCK && land != LAND_WATER && land != LAND_RIVER) {
   3912 						if (Doing == DO_GUN_DEATH && !Class->IsDog && Height==0) {
   3913 							anim = new AnimClass(ANIM_CORPSE1, Coord_Add(Center_Coord(), XYP_Coord(-2, 4)));
   3914 						}
   3915 						if (Doing == DO_GRENADE_DEATH && !Class->IsDog && Height==0) {
   3916 							anim = new AnimClass(ANIM_CORPSE1, Coord_Add(Center_Coord(), XYP_Coord(-10, 3)));
   3917 						}
   3918 						if (Doing == DO_EXPLOSION_DEATH && !Class->IsDog && Height==0) {
   3919 							anim = new AnimClass(ANIM_CORPSE3, Coord_Add(Center_Coord(), XYP_Coord(-2, 4)));
   3920 						}
   3921 						if (Doing == DO_EXPLOSION2_DEATH && !Class->IsDog && Height==0) {
   3922 							anim = new AnimClass(ANIM_CORPSE2, Center_Coord());
   3923 						}
   3924 					}
   3925 					if (anim != NULL) {
   3926 						anim->Set_Owner(House->Class->House);
   3927 					}
   3928 					delete this;
   3929 					return;
   3930 				}
   3931 		}
   3932 	}
   3933 }
   3934 
   3935 
   3936 /***********************************************************************************************
   3937  * InfantryClass::Movement_AI -- This routine handles all infantry movement logic.             *
   3938  *                                                                                             *
   3939  *    It examines the infantry state and determines what movement action should be initiated   *
   3940  *    or processed. It handles the actual movement of the infantry as well as any path finding *
   3941  *    or infantry startup logic.                                                               *
   3942  *                                                                                             *
   3943  * INPUT:   none                                                                               *
   3944  *                                                                                             *
   3945  * OUTPUT:  none                                                                               *
   3946  *                                                                                             *
   3947  * WARNINGS:   Only call this routine once per infantry unit per game logic loop.              *
   3948  *                                                                                             *
   3949  * HISTORY:                                                                                    *
   3950  *   07/29/1996 JLB : Created.                                                                 *
   3951  *=============================================================================================*/
   3952 void InfantryClass::Movement_AI(void)
   3953 {
   3954 	/*
   3955 	**	Special hack check to ensure that infantry will never get stuck in a movement order if
   3956 	**	there is no place to go.
   3957 	*/
   3958 	if (Mission == MISSION_MOVE && !Target_Legal(NavCom)) {
   3959 		Enter_Idle_Mode();
   3960 	}
   3961 
   3962 	if (!IsFiring && !IsFalling && Doing != DO_DOG_MAUL) {
   3963 		if (!IsDriving) {
   3964 
   3965 			/*
   3966 			**	When in guard mode, never allow a valid navcom.
   3967 			*/
   3968 			if (Mission == MISSION_GUARD && MissionQueue == MISSION_NONE && Target_Legal(NavCom)) {
   3969 				Assign_Destination(TARGET_NONE);
   3970 //				if (IsTethered) Scatter(0, true);
   3971 			}
   3972 
   3973 			/*
   3974 			**	Scatter infantry off buildings in guard modes.
   3975 			*/
   3976 			if (!IsTethered && (Mission == MISSION_GUARD || Mission == MISSION_GUARD_AREA) && MissionQueue == MISSION_NONE && Map[Coord].Cell_Building() != NULL) {
   3977 				Scatter(0, true, true);
   3978 			}
   3979 
   3980 			/*
   3981 			**	Double check to make sure it doesn't have a movement destination into a zone
   3982 			**	that it can't travel to. In such a case, abort the movement process by clearing
   3983 			**	the navigation computer.
   3984 			*/
   3985 			if ((!IsZoneCheat || Can_Enter_Cell(Coord_Cell(Coord)) != MOVE_NO) && !IsDriving && !IsTethered && Target_Legal(NavCom) && IsLocked && Map[Coord].Zones[Class->MZone] != Map[As_Cell(NavCom)].Zones[Class->MZone]) {
   3986 // hack: if it's tanya, spy, or engineer, let 'em move there anyway.
   3987 				if (!Class->IsCapture && Mission != MISSION_ENTER) {
   3988 //				if (*this != INFANTRY_TANYA && *this != INFANTRY_SPY && *this != INFANTRY_RENOVATOR) {
   3989 					Assign_Destination(TARGET_NONE);
   3990 				}
   3991 			}
   3992 
   3993 			/*
   3994 			**	A head to coordinate is needed. If there is no path
   3995 			**	available, then create one.
   3996 			*/
   3997 			if (Target_Legal(NavCom) && Strength && Mission != MISSION_GUARD) {
   3998 
   3999 				/*
   4000 				**	Determine if the next cell in the list is available
   4001 				**	to be entered. If not, then abort the path and try
   4002 				**	again.
   4003 				*/
   4004 				if (Path[0] != FACING_NONE && Can_Enter_Cell(Adjacent_Cell(Coord_Cell(Center_Coord()), Path[0])) != MOVE_OK) {
   4005 					Path[0] = FACING_NONE;
   4006 				}
   4007 
   4008 				/*
   4009 				**	Check to see if the target is closer than expected. This occurs
   4010 				**	when heading toward a moving object and that object is heading
   4011 				**	toward the unit. Shorten the precalculated path to be no longer
   4012 				**	than the distance to the target.
   4013 				*/
   4014 				int d = Lepton_To_Cell(Distance(NavCom));
   4015 				if (d < CONQUER_PATH_MAX) {
   4016 					Path[d] = FACING_NONE;
   4017 				}
   4018 
   4019 				/*
   4020 				**	Find a path to follow if one isn't already calculated.
   4021 				*/
   4022 				if (Path[0] == FACING_NONE) {
   4023 
   4024 					/*
   4025 					**	Calculate the path from the current location to the
   4026 					**	destination indicated by the navigation computer. If there
   4027 					**	was a fundamental error with finding a path, then this
   4028 					**	indicates that basic path & movement logic needs to be
   4029 					**	aborted.
   4030 					*/
   4031 					if (PathDelay != 0) {
   4032 						return;
   4033 					}
   4034 					if (!Basic_Path()) {
   4035 
   4036 						/*
   4037 						**	Check to ensure that if a computer controlled unit is in
   4038 						**	hunt mode, but cannot reach the target it would like to,
   4039 						**	abort the target tracking and let the normal hunt logic
   4040 						**	assign a new one.
   4041 						*/
   4042 						if (!House->IsHuman && Mission == MISSION_HUNT) {
   4043 							Assign_Destination(TARGET_NONE);
   4044 							Assign_Target(TARGET_NONE);
   4045 						} else {
   4046 
   4047 							/*
   4048 							**	If the infantry unit is close enough to the target, then
   4049 							**	tell it to stop.
   4050 							*/
   4051 							if (Distance(NavCom) < Rule.CloseEnoughDistance && !IsTethered) {
   4052 								Assign_Destination(TARGET_NONE);
   4053 							} else {
   4054 
   4055 								/*
   4056 								**	Update the try try again counter so that this
   4057 								**	infantry unit will try again at a later time.
   4058 								*/
   4059 								if (TryTryAgain) {
   4060 									TryTryAgain--;
   4061 								} else {
   4062 									if (IsNewNavCom) Sound_Effect(VOC_SCOLD);
   4063 									IsNewNavCom = false;
   4064 
   4065 									//If we're trying to enter a transport we need to fail so others can try to enter. - LLL 4/17/2020
   4066 									if (Mission == MISSION_ENTER) {
   4067 										Mission = MISSION_NONE;
   4068 										Assign_Mission(MISSION_GUARD);
   4069 										Commence();
   4070 
   4071 										Transmit_Message(RADIO_OVER_OUT);
   4072 									}
   4073 
   4074 									/*
   4075 									**	Abort the target and destination process since the path
   4076 									**	could not be found. In such a case, processing should stop
   4077 									**	or else the game will bog down with repeated path failures.
   4078 									**	Only perform the abort of the target is in a different zone.
   4079 									*/
   4080 									if ((!IsZoneCheat || Can_Enter_Cell(Coord_Cell(Coord)) != MOVE_NO) && IsLocked && Target_Legal(NavCom) && Map[As_Cell(NavCom)].Zones[Class->MZone] != Map[Coord].Zones[Class->MZone]) {
   4081 										Assign_Destination(TARGET_NONE);
   4082 									}
   4083 									if (IsLocked && Target_Legal(TarCom) && Map[As_Cell(TarCom)].Zones[Class->MZone] != Map[Coord].Zones[Class->MZone]) {
   4084 										Assign_Target(TARGET_NONE);
   4085 									}
   4086 								}
   4087 							}
   4088 						}
   4089 						Stop_Driver();
   4090 						return;
   4091 					}
   4092 					TryTryAgain = PATH_RETRY;
   4093 				}
   4094 
   4095 				/*
   4096 				**	Determine the coordinate to head to based on the infantry's
   4097 				**	current location and the next location in the path.
   4098 				*/
   4099 				COORDINATE acoord = Adjacent_Cell(Coord, Path[0]);
   4100 				CELL acell = Coord_Cell(acoord);
   4101 
   4102 				if (Can_Enter_Cell(acell) != MOVE_OK) {
   4103 
   4104 					if ((Mission == MISSION_MOVE || Mission == MISSION_ENTER) && !IsTethered /*&& House->IsHuman*/ && Distance(NavCom) < Rule.CloseEnoughDistance) {
   4105 						Assign_Destination(TARGET_NONE);
   4106 					} else {
   4107 
   4108 						/*
   4109 						** If blocked by a moving block then just exit start of move and
   4110 						** try again next tick.
   4111 						*/
   4112 						if (Can_Enter_Cell(acell) == MOVE_DESTROYABLE) {
   4113 							if (Map[acell].Cell_Object()) {
   4114 								if (!House->Is_Ally(Map[acell].Cell_Object())) {
   4115 									Override_Mission(MISSION_ATTACK, Map[acell].Cell_Object()->As_Target(), TARGET_NONE);
   4116 								}
   4117 							} else {
   4118 								if (Map[acell].Overlay != OVERLAY_NONE && OverlayTypeClass::As_Reference(Map[acell].Overlay).IsWall) {
   4119 									Override_Mission(MISSION_ATTACK, ::As_Target(acell), TARGET_NONE);
   4120 								}
   4121 							}
   4122 						}
   4123 					}
   4124 
   4125 					Path[0] = FACING_NONE;
   4126 					Stop_Driver();
   4127 					if (IsNewNavCom) Sound_Effect(VOC_SCOLD);
   4128 					IsNewNavCom = false;
   4129 
   4130 				} else {
   4131 					if (Start_Driver(acoord)) {
   4132 						if (!IsActive) return;
   4133 						PrimaryFacing.Set(Direction8(Center_Coord(), Head_To_Coord()));
   4134 						if (IsFormationMove) {
   4135 							Set_Speed(Ground[Map[Coord].Land_Type()].Cost[FormationSpeed] * 255);
   4136 						} else {
   4137 							Set_Speed(0xFF);
   4138 						}
   4139 
   4140 						if (Class->IsDog) {
   4141 
   4142 							/*
   4143 							**	Dog crawl animation is actually the run animation.
   4144 							*/
   4145 							if (Target_Legal(TarCom)) {
   4146 								Do_Action(DO_CRAWL);
   4147 							} else {
   4148 								Do_Action(DO_WALK);
   4149 							}
   4150 						} else {
   4151 							if (IsProne) {
   4152 								Do_Action(DO_CRAWL);
   4153 							} else {
   4154 								Do_Action(DO_WALK);
   4155 							}
   4156 						}
   4157 					}
   4158 				}
   4159 			}
   4160 
   4161 		} else {
   4162 
   4163 			/*
   4164 			**	The infantry knows where it should be headed, so head there. Check
   4165 			**	to see if the infantry is "close enough" to the desired location that
   4166 			**	it should just consider itself to have arrived. In this case, force
   4167 			**	the infantry to the destination location and mark this path step
   4168 			**	as complete.
   4169 			*/
   4170 			Mark(MARK_UP);
   4171 			if (Distance(Head_To_Coord()) < 0x0010) {
   4172 
   4173 				memcpy(&Path[0], &Path[1], sizeof(Path)-sizeof(Path[0]));
   4174 				Path[(sizeof(Path)/sizeof(Path[0]))-1] = FACING_NONE;
   4175 				Coord = Head_To_Coord();
   4176 				Per_Cell_Process(PCP_END);
   4177 				if (!IsActive || IsInLimbo) return;
   4178 
   4179 				Stop_Driver();
   4180 				if (!IsActive || IsInLimbo) return;
   4181 
   4182 				if (Coord_Cell(Coord) == As_Cell(NavCom)) {
   4183 					NavCom = TARGET_NONE;
   4184 					if (Mission == MISSION_MOVE) {
   4185 						Enter_Idle_Mode();
   4186 					}
   4187 					//Stop_Driver();
   4188 					Path[0] = FACING_NONE;
   4189 				}
   4190 			} else {
   4191 				int	movespeed = Speed;
   4192 
   4193 				/*
   4194 				**	When prone, the infantry moves at half speed or double
   4195 				**	speed. This depends on whether the infantry actually has
   4196 				**	prone animation stages. Civilians don't, and so they
   4197 				**	run instead.
   4198 				*/
   4199 				if (Class->IsDog && Target_Legal(TarCom)) {
   4200 					movespeed *= 2;
   4201 				}
   4202 
   4203 				if (IsProne && !Class->IsDog) {
   4204 					if ((Class->IsFraidyCat && !Class->IsCrawling) ) {
   4205 						movespeed = Speed*2;
   4206 					} else {
   4207 						movespeed = Speed/2;
   4208 					}
   4209 				}
   4210 
   4211 				if (IsTethered) {
   4212 					Transmit_Message(RADIO_REDRAW);
   4213 				}
   4214 
   4215 				/*
   4216 				**	Advance the infantry as far as it should go.
   4217 				*/
   4218 				MPHType maxspeed = MPHType(min(Class->MaxSpeed * SpeedBias * House->GroundspeedBias, MPH_LIGHT_SPEED));
   4219 
   4220 				if (IsFormationMove) maxspeed = FormationMaxSpeed;
   4221 
   4222 				Coord = Coord_Move(Coord, Direction(Head_To_Coord()), maxspeed * fixed(movespeed, 256));
   4223 			}
   4224 			Mark(MARK_DOWN);
   4225 		}
   4226 		IsNewNavCom = false;
   4227 	}
   4228 }
   4229 
   4230 
   4231 /***********************************************************************************************
   4232  * InfantryClass::Get_Image_Data -- Fetches the image data for this infantry unit.             *
   4233  *                                                                                             *
   4234  *    The image data for the infantry differs from normal if this is a spy. A spy always       *
   4235  *    appears like a minigunner to the non-owning players.                                     *
   4236  *                                                                                             *
   4237  * INPUT:   none                                                                               *
   4238  *                                                                                             *
   4239  * OUTPUT:  Returns with a pointer to the image data to use for this infantry soldier.         *
   4240  *                                                                                             *
   4241  * WARNINGS:   none                                                                            *
   4242  *                                                                                             *
   4243  * HISTORY:                                                                                    *
   4244  *   08/06/1996 JLB : Created.                                                                 *
   4245  *=============================================================================================*/
   4246 void const * InfantryClass::Get_Image_Data(void) const
   4247 {
   4248 	if (!IsOwnedByPlayer && *this == INFANTRY_SPY) {
   4249 		return(MFCD::Retrieve("E1.SHP"));
   4250 	}
   4251 	return(TechnoClass::Get_Image_Data());
   4252 }
   4253 
   4254 
   4255 /***********************************************************************************************
   4256  * InfantryClass::Is_Ready_To_Random_Anima -- Checks to see if it is ready to perform an idle  *
   4257  *                                                                                             *
   4258  *    This routine will examine this infantry and determine if it is allowed and ready to      *
   4259  *    perform an idle animation. The conditions under which idle animations can be performed   *
   4260  *    are restrictive. Hence this routine.                                                     *
   4261  *                                                                                             *
   4262  * INPUT:   none                                                                               *
   4263  *                                                                                             *
   4264  * OUTPUT:  bool; Is this infantry ready to do an idle animation?                              *
   4265  *                                                                                             *
   4266  * WARNINGS:   none                                                                            *
   4267  *                                                                                             *
   4268  * HISTORY:                                                                                    *
   4269  *   10/01/1996 JLB : Created.                                                                 *
   4270  *=============================================================================================*/
   4271 bool InfantryClass::Is_Ready_To_Random_Animate(void) const
   4272 {
   4273 	/*
   4274 	**	See if the base classes (more rudimentary checking) determines that idle animations
   4275 	**	cannot occur. If they cannot, then return with the failure code.
   4276 	*/
   4277 	if (!FootClass::Is_Ready_To_Random_Animate()) {
   4278 		return(false);
   4279 	}
   4280 
   4281 	/*
   4282 	**	While the infantry is in the air (such as when paradropping), it won't be allowed
   4283 	**	to idle animate.
   4284 	*/
   4285 	if (Height > 0) {
   4286 		return(false);
   4287 	}
   4288 
   4289 	/*
   4290 	**	When the infantry is walking or otherwise engauged in travel, it won't idle animate.
   4291 	*/
   4292 	if (IsDriving) {
   4293 		return(false);
   4294 	}
   4295 
   4296 	/*
   4297 	**	When prone, idle animations cannot occur. This is primarily because there are no prone
   4298 	**	idle animations.
   4299 	*/
   4300 	if (IsProne) {
   4301 		return(false);
   4302 	}
   4303 
   4304 	/*
   4305 	**	When firing, the infantry should not perform any idle animations.
   4306 	*/
   4307 	if (IsFiring) {
   4308 		return(false);
   4309 	}
   4310 
   4311 	/*
   4312 	**	Only if the infantry is in guard or ready stance is idle animations allowed. This is
   4313 	**	because the idle animations start and end with these frames.
   4314 	*/
   4315 	if (Doing != DO_STAND_GUARD && Doing != DO_STAND_READY) {
   4316 		return(false);
   4317 	}
   4318 
   4319 	/*
   4320 	**	Since no reason was found to indicate it is not a good time to idle
   4321 	**	animate, then it must be a good time to do so.
   4322 	*/
   4323 	return(true);
   4324 }
   4325 
   4326 
   4327 /***********************************************************************************************
   4328  * InfantryClass::Paradrop -- Handles paradropping infantry.                                   *
   4329  *                                                                                             *
   4330  *    This routine will paradrop this soldier at the location specified. It will cause the     *
   4331  *    soldier to hunt if controlled by the computer and to guard if controlledy by the         *
   4332  *    human.                                                                                   *
   4333  *                                                                                             *
   4334  * INPUT:   coord -- The coordinate to paradrop the soldier to.                                *
   4335  *                                                                                             *
   4336  * OUTPUT:  bool; Was the paradrop successful?                                                 *
   4337  *                                                                                             *
   4338  * WARNINGS:   none                                                                            *
   4339  *                                                                                             *
   4340  * HISTORY:                                                                                    *
   4341  *   10/19/1996 JLB : Created.                                                                 *
   4342  *=============================================================================================*/
   4343 bool InfantryClass::Paradrop(COORDINATE coord)
   4344 {
   4345 	if (FootClass::Paradrop(coord)) {
   4346 		if (House->IsHuman) {
   4347 			Assign_Mission(MISSION_GUARD);
   4348 		} else {
   4349 			Assign_Mission(MISSION_HUNT);
   4350 		}
   4351 		return(true);
   4352 	}
   4353 	return(false);
   4354 }