CnC_Remastered_Collection

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

UNIT.CPP (224086B)


      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/UNIT.CPP 1     3/03/97 10:26a 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 : UNIT.CPP                                                     *
     24  *                                                                                             *
     25  *                   Programmer : Joe L. Bostic                                                *
     26  *                                                                                             *
     27  *                   Start Date : September 10, 1993                                           *
     28  *                                                                                             *
     29  *                  Last Update : November 3, 1996 [JLB]                                       *
     30  *                                                                                             *
     31  *---------------------------------------------------------------------------------------------*
     32  * Functions:                                                                                  *
     33  *   Recoil_Adjust -- Adjust pixel values in direction specified.                              *
     34  *   UnitClass::AI -- AI processing for the unit.                                              *
     35  *   UnitClass::APC_Close_Door -- Closes an APC door.                                          *
     36  *   UnitClass::APC_Open_Door -- Opens an APC door.                                            *
     37  *   UnitClass::Active_Click_With -- Intercepts the active click to see if deployment is possib*
     38  *   UnitClass::Active_Click_With -- Performs specified action on specified cell.              *
     39  *   UnitClass::Approach_Target -- Handles approaching the target in order to attack it.       *
     40  *   UnitClass::Assign_Destination -- Assign a destination to a unit.                          *
     41  *   UnitClass::Blocking_Object -- Determines how a object blocks a unit                       *
     42  *   UnitClass::Can_Enter_Cell -- Determines cell entry legality.                              *
     43  *   UnitClass::Can_Fire -- Determines if turret can fire upon target.                         *
     44  *   UnitClass::Click_With -- Handles player map clicking while this unit is selected.         *
     45  *   UnitClass::Credit_Load -- Fetch the full credit value of cargo carried.                   *
     46  *   UnitClass::Crew_Type -- Fetches the kind of crew that this object produces.               *
     47  *   UnitClass::Debug_Dump -- Displays the status of the unit to the mono monitor.             *
     48  *   UnitClass::Desired_Load_Dir -- Determines the best cell and facing for loading.           *
     49  *   UnitClass::Draw_It -- Draws a unit object.                                                *
     50  *   UnitClass::Edge_Of_World_AI -- Check for falling off the edge of the world.               *
     51  *   UnitClass::Enter_Idle_Mode -- Unit enters idle mode state.                                *
     52  *   UnitClass::Fire_Direction -- Determines the direction of firing.                          *
     53  *   UnitClass::Firing_AI -- Handle firing logic for this unit.                                *
     54  *   UnitClass::Flag_Attach -- Attaches a house flag to this unit.                             *
     55  *   UnitClass::Flag_Remove -- Removes the house flag from this unit.                          *
     56  *   UnitClass::Goto_Clear_Spot -- Finds a clear spot to deploy.                               *
     57  *   UnitClass::Goto_Tiberium -- Search for and head toward nearest available Tiberium patch.  *
     58  *   UnitClass::Greatest_Threat -- Fetches the greatest threat for this unit.                  *
     59  *   UnitClass::Harvesting -- Harvests tiberium at the current location.                       *
     60  *   UnitClass::Init -- Clears all units for scenario preparation.                             *
     61  *   UnitClass::Limbo -- Limbo this unit.                                                      *
     62  *   UnitClass::Mission_Guard -- Special guard mission override processor.                     *
     63  *   UnitClass::Mission_Guard_Area -- Guard area logic for units.                              *
     64  *   UnitClass::Mission_Harvest -- Handles the harvesting process used by harvesters.          *
     65  *   UnitClass::Mission_Hunt -- This is the AI process for aggressive enemy units.             *
     66  *   UnitClass::Mission_Move -- Handles special move mission overrides.                        *
     67  *   UnitClass::Mission_Repair -- Handles finding and proceeding on a repair mission.          *
     68  *   UnitClass::Mission_Unload -- Handles unloading cargo.                                     *
     69  *   UnitClass::Offload_Tiberium_Bail -- Offloads one Tiberium quantum from the object.        *
     70  *   UnitClass::Ok_To_Move -- Queries whether the vehicle can move.                            *
     71  *   UnitClass::Overlap_List -- Determines overlap list for units.                             *
     72  *   UnitClass::Overrun_Square -- Handles vehicle overrun of a cell.                           *
     73  *   UnitClass::Per_Cell_Process -- Performs operations necessary on a per cell basis.         *
     74  *   UnitClass::Pip_Count -- Fetches the number of pips to display on unit.                    *
     75  *   UnitClass::Random_Animate -- Handles random idle animation for the unit.                  *
     76  *   UnitClass::Read_INI -- Reads units from scenario INI file.                                *
     77  *   UnitClass::Receive_Message -- Handles receiving a radio message.                          *
     78  *   UnitClass::Reload_AI -- Perform reload logic for this unit.                               *
     79  *   UnitClass::Rotation_AI -- Process any turret or body rotation.                            *
     80  *   UnitClass::Scatter -- Causes the unit to scatter to a nearby location.                    *
     81  *   UnitClass::Set_Speed -- Initiate unit movement physics.                                   *
     82  *   UnitClass::Shape_Number -- Fetch the shape number to use for this unit.                   *
     83  *   UnitClass::Should_Crush_It -- Determines if this unit should crush an object.             *
     84  *   UnitClass::Sort_Y -- Give Y coordinate sort value for unit.                               *
     85  *   UnitClass::Start_Driver -- Starts driving and reserves destination cell.                  *
     86  *   UnitClass::Take_Damage -- Inflicts damage points on a unit.                               *
     87  *   UnitClass::Tiberium_Check -- Search for and head toward nearest available Tiberium patch. *
     88  *   UnitClass::Tiberium_Load -- Determine the Tiberium load as a percentage.                  *
     89  *   UnitClass::Try_To_Deploy -- The unit attempts to "deploy" at current location.            *
     90  *   UnitClass::UnitClass -- Constructor for units.                                            *
     91  *   UnitClass::Unlimbo -- Removes unit from stasis.                                           *
     92  *   UnitClass::What_Action -- Determines action to perform on specified cell.                 *
     93  *   UnitClass::What_Action -- Determines what action would occur if clicked on object.        *
     94  *   UnitClass::Write_INI -- Store the units to the INI database.                              *
     95  *   UnitClass::delete -- Deletion operator for units.                                         *
     96  *   UnitClass::new -- Allocate a unit slot and adjust access arrays.                          *
     97  *   UnitClass::~UnitClass -- Destructor for unit objects.                                     *
     98  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     99 
    100 #include	"function.h"
    101 #include "COORDA.h"
    102 
    103 
    104 extern void Logic_Switch_Player_Context(ObjectClass *object);
    105 extern void Logic_Switch_Player_Context(HouseClass *object);
    106 extern void On_Special_Weapon_Targetting(const HouseClass* player_ptr, SpecialWeaponType weapon_type);
    107 extern bool Is_Legacy_Render_Enabled(void);
    108 
    109 
    110 static int _GapShroudXTable[]={
    111 		-1, 0, 1,
    112 	-2,-1, 0, 1, 2,
    113 	-2,-1, 0, 1, 2,
    114 	-2,-1, 0, 1, 2,
    115 	-2,-1, 0, 1, 2,
    116 	-2,-1, 0, 1, 2,
    117 		-1, 0, 1
    118 };
    119 static int _GapShroudYTable[]={
    120 		-3,-3,-3,
    121 	-2,-2,-2,-2,-2,
    122 	-1,-1,-1,-1,-1,
    123 	 0, 0, 0, 0, 0,
    124 	 1, 1, 1, 1, 1,
    125 	 2, 2, 2, 2, 2,
    126 		 3, 3, 3
    127 };
    128 
    129 /***********************************************************************************************
    130  * Recoil_Adjust -- Adjust pixel values in direction specified.                                *
    131  *                                                                                             *
    132  *    This is a helper routine that modifies the pixel coordinates provided according to the   *
    133  *    direction specified. The effect is the simulate recoil effects by moving an object 'back'*
    134  *    one pixel. Since the pixels moved depend on facing, this routine handles the pixel       *
    135  *    adjustment quickly.                                                                      *
    136  *                                                                                             *
    137  * INPUT:   dir   -- The direction to base the recoil on.                                      *
    138  *                                                                                             *
    139  *          x,y   -- References to the pixel coordinates that will be adjusted.                *
    140  *                                                                                             *
    141  * OUTPUT:  none                                                                               *
    142  *                                                                                             *
    143  * WARNINGS:   none                                                                            *
    144  *                                                                                             *
    145  * HISTORY:                                                                                    *
    146  *   05/08/1995 JLB : Created.                                                                 *
    147  *=============================================================================================*/
    148 void Recoil_Adjust(DirType dir, int &x, int &y)
    149 {
    150 	static struct {
    151 		signed char X,Y;
    152 	} _adjust[32] = {
    153 		{0,	1},	// N
    154 		{0,	1},
    155 		{0,	1},
    156 		{-1,	1},
    157 		{-1,	1},	// NE
    158 		{-1,	1},
    159 		{-1,	0},
    160 		{-1,	0},
    161 		{-1,	0},	// E
    162 		{-1,	0},
    163 		{-1,	-1},
    164 		{-1,	-1},
    165 		{-1,	-1},	// SE
    166 		{-1,	-1},
    167 		{-1,	-1},
    168 		{0,	-1},
    169 		{0,	-1},	// S
    170 		{0,	-1},
    171 		{0,	-1},
    172 		{1,	-1},
    173 		{1,	-1},	// SW
    174 		{1,	-1},
    175 		{1,	0},
    176 		{1,	0},
    177 		{1,	0},	// W
    178 		{1,	0},
    179 		{1,	1},
    180 		{1,	1},
    181 		{1,	1},	// NW
    182 		{1,	1},
    183 		{0,	1},
    184 		{0,	1}
    185 	};
    186 
    187 	int index = Dir_To_32(dir);
    188 	x += _adjust[index].X;
    189 	y += _adjust[index].Y;
    190 }
    191 
    192 
    193 /***********************************************************************************************
    194  * UnitClass::new -- Allocate a unit slot and adjust access arrays.                            *
    195  *                                                                                             *
    196  *    This routine will allocate a unit from the available unit pool and                       *
    197  *    fixup all the access lists to match. It will allocate a unit slot                        *
    198  *    from within the range allowed for the specified unit type. If no                         *
    199  *    slot was found, then it will fail.                                                       *
    200  *                                                                                             *
    201  * INPUT:   none                                                                               *
    202  *                                                                                             *
    203  * OUTPUT:  Returns with a pointer to the allocated unit.                                      *
    204  *                                                                                             *
    205  * WARNINGS:   none                                                                            *
    206  *                                                                                             *
    207  * HISTORY:                                                                                    *
    208  *   04/11/1994 JLB : Created.                                                                 *
    209  *   04/21/1994 JLB : Converted to operator new.                                               *
    210  *=============================================================================================*/
    211 void * UnitClass::operator new(size_t)
    212 {
    213 	void * ptr = Units.Alloc();
    214 	if (ptr != NULL) {
    215 		((UnitClass *)ptr)->Set_Active();
    216 	}
    217 	return(ptr);
    218 }
    219 
    220 
    221 /***********************************************************************************************
    222  * UnitClass::delete -- Deletion operator for units.                                           *
    223  *                                                                                             *
    224  *    This removes the unit from the local allocation system. Since this                       *
    225  *    is a fixed block of memory, not much has to be done to delete the                        *
    226  *    unit. Merely marking it as inactive is enough.                                           *
    227  *                                                                                             *
    228  * INPUT:   ptr   -- Pointer to the unit to delete.                                            *
    229  *                                                                                             *
    230  * OUTPUT:  none                                                                               *
    231  *                                                                                             *
    232  * WARNINGS:   none                                                                            *
    233  *                                                                                             *
    234  * HISTORY:                                                                                    *
    235  *   04/21/1994 JLB : Created.                                                                 *
    236  *=============================================================================================*/
    237 void UnitClass::operator delete(void * ptr)
    238 {
    239 	if (ptr != NULL) {
    240 		((UnitClass *)ptr)->IsActive = false;
    241 	}
    242 	Units.Free((UnitClass *)ptr);
    243 }
    244 
    245 
    246 /***********************************************************************************************
    247  * UnitClass::~UnitClass -- Destructor for unit objects.                                       *
    248  *                                                                                             *
    249  *    This destructor will lower the unit count for the owning house as well as inform any     *
    250  *    other units in communication, that this unit is about to leave reality.                  *
    251  *                                                                                             *
    252  * INPUT:   none                                                                               *
    253  *                                                                                             *
    254  * OUTPUT:  none                                                                               *
    255  *                                                                                             *
    256  * WARNINGS:   none                                                                            *
    257  *                                                                                             *
    258  * HISTORY:                                                                                    *
    259  *   08/15/1994 JLB : Created.                                                                 *
    260  *=============================================================================================*/
    261 UnitClass::~UnitClass(void)
    262 {
    263 	if (GameActive && Class.Is_Valid()) {
    264 
    265 		/*
    266 		**	Remove this member from any team it may be associated with. This must occur at the
    267 		**	top most level of the inheritance hierarchy because it may call virtual functions.
    268 		*/
    269 		if (Team.Is_Valid()) {
    270 			Team->Remove(this);
    271 			Team = NULL;
    272 		}
    273 
    274 		House->Tracking_Remove(this);
    275 
    276 		/*
    277 		**	If there are any cargo members, delete them.
    278 		*/
    279 		while (Is_Something_Attached()) {
    280 			delete Detach_Object();
    281 		}
    282 
    283 		Limbo();
    284 	}
    285 	ID = -1;
    286 }
    287 
    288 
    289 /***********************************************************************************************
    290  * UnitClass::UnitClass -- Constructor for units.                                              *
    291  *                                                                                             *
    292  *    This constructor for units will initialize the unit into the game                        *
    293  *    system. It will be placed in all necessary tracking lists. The initial condition will    *
    294  *    be in a state of limbo.                                                                  *
    295  *                                                                                             *
    296  * INPUT:   classid  -- The type of unit to create.                                            *
    297  *                                                                                             *
    298  *          house -- The house owner of this unit.                                             *
    299  *                                                                                             *
    300  * OUTPUT:  none                                                                               *
    301  *                                                                                             *
    302  * WARNINGS:   none                                                                            *
    303  *                                                                                             *
    304  * HISTORY:                                                                                    *
    305  *   04/21/1994 JLB : Created.                                                                 *
    306  *=============================================================================================*/
    307 UnitClass::UnitClass(UnitType classid, HousesType house) :
    308 	DriveClass(RTTI_UNIT, Units.ID(this), house),
    309 	Class(UnitTypes.Ptr((int)classid)),
    310 	Flagged(HOUSE_NONE),
    311 	IsDumping(false),
    312 	Gems(0),
    313 	Gold(0),
    314 	Tiberium(0),
    315 	IsToScatter(false),
    316 	ShroudBits(0xFFFFFFFFUL),
    317 	ShroudCenter(0),
    318 	Reload(0),
    319 	SecondaryFacing(PrimaryFacing),
    320 	TiberiumUnloadRefinery(TARGET_NONE)
    321 {
    322 	Reload = 0;
    323 	House->Tracking_Add(this);
    324 	Ammo = Class->MaxAmmo;
    325 	IsCloakable = Class->IsCloakable;
    326 	if (Class->IsAnimating) Set_Rate(Options.Normalize_Delay(3));
    327 
    328 	/*
    329 	**	For two shooters, clear out the second shot flag -- it will be set the first time
    330 	**	the object fires. For non two shooters, set the flag since it will never be cleared
    331 	**	and the second shot flag tells the system that normal rearm times apply -- this is
    332 	**	what is desired for non two shooters.
    333 	*/
    334 	IsSecondShot = !Class->Is_Two_Shooter();
    335 	Strength = Class->MaxStrength;
    336 
    337 	/*
    338 	** Keep count of the number of units created.
    339 	*/
    340 //	if (Session.Type == GAME_INTERNET) {
    341 //		House->UnitTotals->Increment_Unit_Total((int)classid);
    342 //	}
    343 }
    344 
    345 
    346 #ifdef CHEAT_KEYS
    347 /***********************************************************************************************
    348  * UnitClass::Debug_Dump -- Displays the status of the unit to the mono monitor.               *
    349  *                                                                                             *
    350  *    This displays the current status of the unit class to the mono monitor. By this display  *
    351  *    bugs may be tracked down or prevented.                                                   *
    352  *                                                                                             *
    353  * INPUT:   none                                                                               *
    354  *                                                                                             *
    355  * OUTPUT:  none                                                                               *
    356  *                                                                                             *
    357  * WARNINGS:   none                                                                            *
    358  *                                                                                             *
    359  * HISTORY:                                                                                    *
    360  *   06/02/1994 JLB : Created.                                                                 *
    361  *=============================================================================================*/
    362 void UnitClass::Debug_Dump(MonoClass * mono) const
    363 {
    364 	assert(Units.ID(this) == ID);
    365 	assert(IsActive);
    366 
    367 	mono->Set_Cursor(0, 0);
    368 	mono->Print(Text_String(TXT_DEBUG_VEHICLE));
    369 	mono->Set_Cursor(47, 5);mono->Printf("%02X:%02X", SecondaryFacing.Current(), SecondaryFacing.Desired());
    370 
    371 	mono->Set_Cursor(1, 11);mono->Printf("%03", Gems);
    372 	mono->Set_Cursor(7, 11);mono->Printf("%03", Gold);
    373 
    374 	mono->Fill_Attrib(66, 13, 12, 1, IsDumping ? MonoClass::INVERSE : MonoClass::NORMAL);
    375 
    376 	DriveClass::Debug_Dump(mono);
    377 }
    378 #endif
    379 
    380 
    381 /***********************************************************************************************
    382  * UnitClass::Sort_Y -- Give Y coordinate sort value for unit.                                 *
    383  *                                                                                             *
    384  *    This routine is used by the rendering system in order to sort the                        *
    385  *    game objects in a back to front order. This is now the correct                           *
    386  *    overlap effect is achieved.                                                              *
    387  *                                                                                             *
    388  * INPUT:   none                                                                               *
    389  *                                                                                             *
    390  * OUTPUT:  Returns with a coordinate value that can be used for sorting.                      *
    391  *                                                                                             *
    392  * WARNINGS:   none                                                                            *
    393  *                                                                                             *
    394  * HISTORY:                                                                                    *
    395  *   05/17/1994 JLB : Created.                                                                 *
    396  *=============================================================================================*/
    397 COORDINATE UnitClass::Sort_Y(void) const
    398 {
    399 	assert(Units.ID(this) == ID);
    400 	assert(IsActive);
    401 
    402 	return(Coord_Add(Coord, 0x00800000L));
    403 }
    404 
    405 
    406 /***********************************************************************************************
    407  * UnitClass::AI -- AI processing for the unit.                                                *
    408  *                                                                                             *
    409  *    This routine will perform the AI processing necessary for the unit. These are non-       *
    410  *    graphic related operations.                                                              *
    411  *                                                                                             *
    412  * INPUT:   none                                                                               *
    413  *                                                                                             *
    414  * OUTPUT:  none                                                                               *
    415  *                                                                                             *
    416  * WARNINGS:   none                                                                            *
    417  *                                                                                             *
    418  * HISTORY:                                                                                    *
    419  *   05/31/1994 JLB : Created.                                                                 *
    420  *=============================================================================================*/
    421 void UnitClass::AI(void)
    422 {
    423 	assert(Units.ID(this) == ID);
    424 	assert(IsActive);
    425 	/*
    426 	**	Act on new orders if the unit is at a good position to do so.
    427 	*/
    428 	if (Height == 0 && !IsDumping && !IsDriving && Is_Door_Closed() /*&& Mission != MISSION_UNLOAD*/) {
    429 //		if (MissionQueue == MISSION_NONE) Enter_Idle_Mode();
    430 		Commence();
    431 	}
    432 	DriveClass::AI();
    433 	if (!IsActive || Height > 0) {
    434 		return;
    435 	}
    436 
    437 	/*
    438 	**	Hack check to ensure that a harvester won't harvest if it is not harvesting.
    439 	*/
    440 	if (Mission != MISSION_HARVEST) {
    441 		IsHarvesting = false;
    442 	}
    443 
    444 	/*
    445 	**	Handle combat logic for this unit. It will determine if it has a target and
    446 	**	if so, if conditions are favorable for firing. When conditions permit, the
    447 	**	unit will fire upon its target.
    448 	*/
    449 	Firing_AI();
    450 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
    451 	if (!IsActive) {
    452 		return;
    453 	}
    454 #endif
    455 	/*
    456 	**	Turret rotation processing. Handles rotating radar dish
    457 	**	as well as conventional turrets if present. If no turret present, but
    458 	**	it decides that the body should face its target, then body rotation
    459 	**	would occur by this process as well.
    460 	*/
    461 	Rotation_AI();
    462 
    463 	/*
    464 	**	Scatter units off buildings in guard modes.
    465 	*/
    466 	if (!IsTethered && !IsFiring && !IsDriving && !IsRotating && (Mission == MISSION_GUARD || Mission == MISSION_GUARD_AREA) && MissionQueue == MISSION_NONE && Map[Coord].Cell_Building() != NULL) {
    467 		Scatter(0, true, true);
    468 	}
    469 
    470 	/*
    471 	**	Delete this unit if it finds itself off the edge of the map and it is in
    472 	**	guard or other static mission mode.
    473 	*/
    474 	if (Edge_Of_World_AI()) {
    475 		return;
    476 	}
    477 
    478 	/*
    479 	**	Units will reload every so often if they are under the burden of
    480 	**	being required to reload between shots.
    481 	*/
    482 	Reload_AI();
    483 
    484 	/*
    485 	**	Transporters require special logic handled here since there isn't a MISSION_WAIT_FOR_PASSENGERS
    486 	**	mission that they can follow. Passenger loading is merely a part of their normal operation.
    487 	*/
    488 	if (Class->Max_Passengers() > 0) {
    489 
    490 		/*
    491 		**	Double check that there is a passenger that is trying to load or unload.
    492 		**	If not, then close the door.
    493 		*/
    494 		if (!Is_Door_Closed() && Mission != MISSION_UNLOAD && Transmit_Message(RADIO_TRYING_TO_LOAD) != RADIO_ROGER) {
    495 			APC_Close_Door();
    496 		}
    497 	}
    498 
    499 	/*
    500 	**	Don't start a new mission unless the vehicle is in the center of
    501 	**	a cell (not driving) and the door (if any) is closed.
    502 	*/
    503 	if (!IsDumping && !IsDriving && Is_Door_Closed()/*&& Mission != MISSION_UNLOAD*/) {
    504 		Commence();
    505 	}
    506 
    507 	/*
    508 	**	A cloaked object that is carrying the flag will always shimmer.
    509 	*/
    510 	if (Cloak == CLOAKED && Flagged != HOUSE_NONE) {
    511 		Do_Shimmer();
    512 	}
    513 
    514 	/*
    515 	**	Mobile gap generators regenerate their gap every so often (just in case).
    516 	*/
    517 	if (Class->IsGapper && !IsDriving && (Frame % TICKS_PER_SECOND) == 0) {
    518 		Shroud_Regen();
    519 	}
    520 }
    521 
    522 
    523 /***********************************************************************************************
    524  * UnitClass::Rotation_AI -- Process any turret or body rotation.                              *
    525  *                                                                                             *
    526  *    This routine will handle the rotation logic for the unit's turret (if it has one) as     *
    527  *    well as its normal body shape.                                                           *
    528  *                                                                                             *
    529  * INPUT:   none                                                                               *
    530  *                                                                                             *
    531  * OUTPUT:  none                                                                               *
    532  *                                                                                             *
    533  * WARNINGS:   none                                                                            *
    534  *                                                                                             *
    535  * HISTORY:                                                                                    *
    536  *   07/30/1996 JLB : Created.                                                                 *
    537  *=============================================================================================*/
    538 void UnitClass::Rotation_AI(void)
    539 {
    540 	if (Target_Legal(TarCom) && !IsRotating) {
    541 		DirType dir = Direction(TarCom);
    542 
    543 		if (Class->IsTurretEquipped) {
    544 			SecondaryFacing.Set_Desired(dir);
    545 		} else {
    546 
    547 			/*
    548 			**	Non turret equipped vehicles will rotate their body to face the target only
    549 			**	if the vehicle isn't currently moving or facing the correct direction. This
    550 			**	applies only to tracked vehicles. Wheeled vehicles never rotate to face the
    551 			**	target, since they aren't maneuverable enough.
    552 			*/
    553 			if ((Class->Speed == SPEED_TRACK /* || *this == UNIT_BIKE */ ) && !Target_Legal(NavCom) && !IsDriving && PrimaryFacing.Difference(dir)) {
    554 				PrimaryFacing.Set_Desired(dir);
    555 			}
    556 		}
    557 	}
    558 
    559 	if (Class->IsRadarEquipped) {
    560 		Mark(MARK_CHANGE_REDRAW);
    561 		SecondaryFacing.Set((DirType)(SecondaryFacing.Current() + 8));
    562 		Mark(MARK_CHANGE_REDRAW);
    563 	} else {
    564 
    565 		IsRotating = false;
    566 		if (Class->IsTurretEquipped) {
    567 			if (IsTurretLockedDown) {
    568 				SecondaryFacing.Set_Desired(PrimaryFacing.Current());
    569 			}
    570 
    571 			if (SecondaryFacing.Is_Rotating()) {
    572 				Mark(MARK_CHANGE_REDRAW);
    573 				if (SecondaryFacing.Rotation_Adjust(Class->ROT+1)) {
    574 					Mark(MARK_CHANGE_REDRAW);
    575 				}
    576 
    577 				/*
    578 				**	If no further rotation is necessary, flag that the rotation
    579 				**	has stopped.
    580 				*/
    581 				if (!Class->IsRadarEquipped) {
    582 					IsRotating = SecondaryFacing.Is_Rotating();
    583 				}
    584 			} else {
    585 				if (!IsTurretLockedDown && !Target_Legal(TarCom)) {
    586 					if (!Target_Legal(NavCom)) {
    587 						SecondaryFacing.Set_Desired(PrimaryFacing.Current());
    588 					} else {
    589 						SecondaryFacing.Set_Desired(Direction(NavCom));
    590 					}
    591 				}
    592 			}
    593 		}
    594 	}
    595 }
    596 
    597 
    598 /***********************************************************************************************
    599  * UnitClass::Edge_Of_World_AI -- Check for falling off the edge of the world.                 *
    600  *                                                                                             *
    601  *    When a unit leaves the map it will be eliminated. This routine checks for this case      *
    602  *    and eliminates the unit accordingly.                                                     *
    603  *                                                                                             *
    604  * INPUT:   none                                                                               *
    605  *                                                                                             *
    606  * OUTPUT:  bool; Was the unit eliminated by this routine?                                     *
    607  *                                                                                             *
    608  * WARNINGS:   Be sure to check for the return value and if 'true' abort any further processing*
    609  *             of the unit since it is dead. Only call this routine once per unit per          *
    610  *             game logic loop.                                                                *
    611  *                                                                                             *
    612  * HISTORY:                                                                                    *
    613  *   07/30/1996 JLB : Created.                                                                 *
    614  *=============================================================================================*/
    615 bool UnitClass::Edge_Of_World_AI(void)
    616 {
    617 	if (Mission == MISSION_GUARD && !Map.In_Radar(Coord_Cell(Coord)) && IsLocked) {
    618 		if (Team.Is_Valid()) Team->IsLeaveMap = true;
    619 		Stun();
    620 		delete this;
    621 		return(true);
    622 	}
    623 	return(false);
    624 }
    625 
    626 
    627 /***********************************************************************************************
    628  * UnitClass::Reload_AI -- Perform reload logic for this unit.                                 *
    629  *                                                                                             *
    630  *    Some units require special reload logic. The V2 rocket launcher in particular. Perform   *
    631  *    this reload logic with this routine.                                                     *
    632  *                                                                                             *
    633  * INPUT:   none                                                                               *
    634  *                                                                                             *
    635  * OUTPUT:  none                                                                               *
    636  *                                                                                             *
    637  * WARNINGS:   Only call this routine once per unit per game logic loop.                       *
    638  *                                                                                             *
    639  * HISTORY:                                                                                    *
    640  *   07/30/1996 JLB : Created.                                                                 *
    641  *=============================================================================================*/
    642 void UnitClass::Reload_AI(void)
    643 {
    644 	if (*this == UNIT_V2_LAUNCHER && Ammo < Class->MaxAmmo) {
    645 		if (IsDriving) {
    646 			Reload = Reload + 1;
    647 		} else {
    648 			if (Reload == 0) {
    649 				Ammo++;
    650 				if (Ammo < Class->MaxAmmo) {
    651 					Reload = TICKS_PER_SECOND*30;
    652 				}
    653 				Mark(MARK_CHANGE);
    654 			}
    655 		}
    656 	}
    657 }
    658 
    659 
    660 /***********************************************************************************************
    661  * UnitClass::Firing_AI -- Handle firing logic for this unit.                                  *
    662  *                                                                                             *
    663  *    This routine wil check for and perform any firing logic required of this unit.           *
    664  *                                                                                             *
    665  * INPUT:   none                                                                               *
    666  *                                                                                             *
    667  * OUTPUT:  none                                                                               *
    668  *                                                                                             *
    669  * WARNINGS:   This should be called only once per unit per game logic loop.                   *
    670  *                                                                                             *
    671  * HISTORY:                                                                                    *
    672  *   07/30/1996 JLB : Created.                                                                 *
    673  *=============================================================================================*/
    674 void UnitClass::Firing_AI(void)
    675 {
    676 	if (Target_Legal(TarCom) && Class->PrimaryWeapon != NULL) {
    677 
    678 		/*
    679 		**	Determine which weapon can fire. First check for the primary weapon. If that weapon
    680 		**	cannot fire, then check any secondary weapon. If neither weapon can fire, then the
    681 		**	failure code returned is that from the primary weapon.
    682 		*/
    683 		int primary = What_Weapon_Should_I_Use(TarCom);
    684 		FireErrorType ok = Can_Fire(TarCom, primary);
    685 		switch (ok) {
    686 			case FIRE_OK:
    687 				if (!((UnitClass *)this)->Class->IsFireAnim) {
    688 					Mark(MARK_OVERLAP_UP);
    689 					IsFiring = false;
    690 					Mark(MARK_OVERLAP_DOWN);
    691 				}
    692 
    693 				Fire_At(TarCom, primary);
    694 				break;
    695 
    696 			case FIRE_FACING:
    697 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
    698 				if (Class->IsLockTurret || Class->Type == UNIT_DEMOTRUCK) {
    699 #else
    700 				if (Class->IsLockTurret) {
    701 #endif
    702 					if (!Target_Legal(NavCom) && !IsDriving) {
    703 						PrimaryFacing.Set_Desired(Direction(TarCom));
    704 						SecondaryFacing.Set_Desired(PrimaryFacing.Desired());
    705 					}
    706 				} else {
    707 					SecondaryFacing.Set_Desired(Direction(TarCom));
    708 				}
    709 				break;
    710 
    711 			case FIRE_CLOAKED:
    712 				Mark(MARK_OVERLAP_UP);
    713 				IsFiring = false;
    714 				Mark(MARK_OVERLAP_DOWN);
    715 				Do_Uncloak();
    716 				break;
    717 		}
    718 	}
    719 }
    720 
    721 
    722 /***********************************************************************************************
    723  * UnitClass::Receive_Message -- Handles receiving a radio message.                            *
    724  *                                                                                             *
    725  *    This is the handler function for when a unit receives a radio                            *
    726  *    message. Typical use of this is when a unit unloads from a hover                         *
    727  *    class so that clearing of the transport is successful.                                   *
    728  *                                                                                             *
    729  * INPUT:   from     -- Pointer to the originator of the message.                              *
    730  *                                                                                             *
    731  *          message  -- The radio message received.                                            *
    732  *                                                                                             *
    733  *          param    -- Reference to an optional parameter the might be needed to return       *
    734  *                      information back to the originator of the message.                     *
    735  *                                                                                             *
    736  * OUTPUT:  Returns with the radio message response.                                           *
    737  *                                                                                             *
    738  * WARNINGS:   none                                                                            *
    739  *                                                                                             *
    740  * HISTORY:                                                                                    *
    741  *   05/22/1994 JLB : Created.                                                                 *
    742  *=============================================================================================*/
    743 RadioMessageType UnitClass::Receive_Message(RadioClass * from, RadioMessageType message, long & param)
    744 {
    745 	assert(Units.ID(this) == ID);
    746 	assert(IsActive);
    747 
    748 	switch (message) {
    749 		/*
    750 		**	Checks to see if this object is in need of service depot processing.
    751 		*/
    752 		case RADIO_NEED_REPAIR:
    753 			if (!IsDriving && !Target_Legal(NavCom) && (Health_Ratio() >= 1 && (*this != UNIT_MINELAYER || Ammo >= Class->MaxAmmo))) return(RADIO_NEGATIVE);
    754 			break;
    755 //			return(RADIO_ROGER);
    756 
    757 		/*
    758 		**	Asks if the passenger can load on this transport.
    759 		*/
    760 		case RADIO_CAN_LOAD:
    761 			if (Class->Max_Passengers() == 0 || from == NULL || !House->Is_Ally(from->Owner())) return(RADIO_STATIC);
    762 			if (How_Many() < Class->Max_Passengers()) {
    763 				return(RADIO_ROGER);
    764 			}
    765 			return(RADIO_NEGATIVE);
    766 
    767 		/*
    768 		**	The refinery has told this harvester that it should begin the backup procedure
    769 		**	so that proper unloading may take place.
    770 		*/
    771 		case RADIO_BACKUP_NOW:
    772 			DriveClass::Receive_Message(from, message, param);
    773 			if (!IsRotating && PrimaryFacing != DIR_W) {
    774 				Do_Turn(DIR_W);
    775 			} else {
    776 				if (!IsDriving) {
    777 					TechnoClass	* whom = Contact_With_Whom();
    778 					if (IsTethered && whom != NULL) {
    779 						if (whom->What_Am_I() == RTTI_BUILDING && Mission == MISSION_ENTER) {
    780 							if (Transmit_Message(RADIO_IM_IN, whom) == RADIO_ROGER) {
    781 								Transmit_Message(RADIO_UNLOADED, whom);
    782 							}
    783 						}
    784 					}
    785 				}
    786 			}
    787 			return(RADIO_ROGER);
    788 
    789 		/*
    790 		**	This message is sent by the passenger when it determines that it has
    791 		**	entered the transport.
    792 		*/
    793 		case RADIO_IM_IN:
    794 			if (How_Many() == Class->Max_Passengers()) {
    795 				APC_Close_Door();
    796 			}
    797 			return(RADIO_ATTACH);
    798 
    799 		/*
    800 		**	Docking maintenance message received. Check to see if new orders should be given
    801 		**	to the impatient unit.
    802 		*/
    803 		case RADIO_DOCKING:
    804 
    805 			/*
    806 			**	If this transport is moving, then always abort the docking request.
    807 			*/
    808 			if (IsDriving || Target_Legal(NavCom)) {
    809 				return(RADIO_NEGATIVE);
    810 			}
    811 
    812 			/*
    813 			**	Check for the case of a docking message arriving from a unit that does not
    814 			**	have formal radio contact established. This might be a unit that is standing
    815 			**	by. If this transport is free to proceed with normal docking operation, then
    816 			**	establish formal contact now. If the transport is completely full, then break
    817 			**	off contact. In all other cases, just tell the pending unit to stand by.
    818 			*/
    819 			if (Contact_With_Whom() != from) {
    820 
    821 				/*
    822 				**	Can't ever load up so tell the passenger to bug off.
    823 				*/
    824 				if (How_Many() >= Class->Max_Passengers()) {
    825 					return(RADIO_NEGATIVE);
    826 				}
    827 
    828 				/*
    829 				**	Establish contact and let the loading process proceed normally.
    830 				*/
    831 				if (!In_Radio_Contact()) {
    832 					Transmit_Message(RADIO_HELLO, from);
    833 				} else {
    834 
    835 					/*
    836 					**	This causes the potential passenger to think that all is ok and to
    837 					**	hold on for a bit.
    838 					*/
    839 					return(RADIO_ROGER);
    840 				}
    841 			}
    842 
    843 			if (Class->Max_Passengers() > 0 && How_Many() < Class->Max_Passengers()) {
    844 				DriveClass::Receive_Message(from, message, param);
    845 
    846 				if (!IsDriving && !IsRotating && !IsTethered) {
    847 
    848 					/*
    849 					**	If the potential passenger needs someplace to go, then figure out a good
    850 					**	spot and tell it to go.
    851 					*/
    852 					if (Transmit_Message(RADIO_NEED_TO_MOVE, from) == RADIO_ROGER) {
    853 
    854 						CELL cell;
    855 						DirType dir = Desired_Load_Dir(from, cell);
    856 
    857 						/*
    858 						**	If no adjacent free cells are detected, then passenger loading
    859 						**	cannot occur. Break radio contact.
    860 						*/
    861 						if (cell == 0) {
    862 							Transmit_Message(RADIO_OVER_OUT, from);
    863 						} else {
    864 							param = (long)::As_Target(cell);
    865 							Do_Turn(dir);
    866 
    867 							/*
    868 							**	If it is now facing the correct direction, then open the
    869 							**	transport doors. Close the doors if the transport is or needs
    870 							**	to rotate.
    871 							*/
    872 #ifdef FIXIT_PHASETRANSPORT	//	checked - ajw 9/28/98
    873 							if (*this == UNIT_APC || *this == UNIT_PHASE) {
    874 #else
    875 							if (*this == UNIT_APC) {
    876 #endif
    877 								if (IsRotating) {
    878 									if (!Is_Door_Closed()) {
    879 										APC_Close_Door();
    880 									}
    881 								} else {
    882 									if (!Is_Door_Open()) {
    883 										APC_Open_Door();
    884 									}
    885 								}
    886 							}
    887 
    888 							/*
    889 							**	Tell the potential passenger where it should go. If the passenger is
    890 							**	already at the staging location, then tell it to move onto the transport
    891 							**	directly.
    892 							*/
    893 							if (Transmit_Message(RADIO_MOVE_HERE, param, from) == RADIO_YEA_NOW_WHAT) {
    894 #ifdef FIXIT_PHASETRANSPORT	//	checked - ajw 9/28/98
    895 								if ( (*this != UNIT_APC && *this != UNIT_PHASE) || Is_Door_Open()) {
    896 #else
    897 								if (*this != UNIT_APC || Is_Door_Open()) {
    898 #endif
    899 									param = (long)As_Target();
    900 									Transmit_Message(RADIO_TETHER);
    901 									if (Transmit_Message(RADIO_MOVE_HERE, param, from) != RADIO_ROGER) {
    902 										Transmit_Message(RADIO_OVER_OUT, from);
    903 									} else {
    904 										Contact_With_Whom()->Unselect();
    905 									}
    906 								}
    907 							}
    908 						}
    909 					}
    910 				}
    911 				return(RADIO_ROGER);
    912 			}
    913 			break;
    914 
    915 		/*
    916 		**	Something bad has happened to the object in contact with. Abort any coordinated
    917 		**	activity with this object. Basically, ... run away! Run away!
    918 		*/
    919 		case RADIO_RUN_AWAY:
    920 			if (Class->IsToHarvest && In_Radio_Contact() && Mission == MISSION_ENTER) {
    921 				TechnoClass * contact = Contact_With_Whom();
    922 				if (contact->What_Am_I() == RTTI_BUILDING && *((BuildingClass*)contact) == STRUCT_REFINERY) {
    923 					// Slight hack; set a target so the harvest mission knows to skip to finding home state
    924 					Assign_Mission(MISSION_HARVEST);
    925 					TarCom = As_Target();
    926 					return(RADIO_ROGER);
    927 				}
    928 			}
    929 			return(DriveClass::Receive_Message(from, message, param));
    930 
    931 		/*
    932 		**	When this message is received, it means that the other object
    933 		**	has already turned its radio off. Turn this radio off as well.
    934 		*/
    935 		case RADIO_OVER_OUT:
    936 			if (Mission == MISSION_RETURN) {
    937 				Assign_Mission(MISSION_GUARD);
    938 			}
    939 			DriveClass::Receive_Message(from, message, param);
    940 			return(RADIO_ROGER);
    941 
    942 	}
    943 	return(DriveClass::Receive_Message(from, message, param));
    944 }
    945 
    946 
    947 /***********************************************************************************************
    948  * UnitClass::Unlimbo -- Removes unit from stasis.                                             *
    949  *                                                                                             *
    950  *    This routine will place a unit into the game and out of its limbo                        *
    951  *    state. This occurs whenever a unit is unloaded from a transport.                         *
    952  *                                                                                             *
    953  * INPUT:   coord    -- The coordinate to make the unit appear.                                *
    954  *                                                                                             *
    955  *          dir      -- The initial facing to impart upon the unit.                            *
    956  *                                                                                             *
    957  * OUTPUT:  bool; Was the unit unlimboed successfully?  If the desired                         *
    958  *                coordinate is illegal, then this might very well return                      *
    959  *                false.                                                                       *
    960  *                                                                                             *
    961  * WARNINGS:   none                                                                            *
    962  *                                                                                             *
    963  * HISTORY:                                                                                    *
    964  *   05/22/1994 JLB : Created.                                                                 *
    965  *=============================================================================================*/
    966 bool UnitClass::Unlimbo(COORDINATE coord, DirType dir)
    967 {
    968 	assert(Units.ID(this) == ID);
    969 	assert(IsActive);
    970 
    971 	/*
    972 	**	All units must start out facing one of the 8 major directions.
    973 	*/
    974 	dir = Facing_Dir(Dir_Facing(dir));
    975 	if (DriveClass::Unlimbo(coord, dir)) {
    976 
    977 		SecondaryFacing = dir;
    978 		/*
    979 		**	Ensure that the owning house knows about the
    980 		**	new object.
    981 		*/
    982 		House->UScan |= (1L << Class->Type);
    983 		House->ActiveUScan |= (1L << Class->Type);
    984 
    985 		/*
    986 		**	If it starts off the edge of the map, then it already starts cloaked.
    987 		*/
    988 		if (IsCloakable && !IsLocked) Cloak = CLOAKED;
    989 
    990 		/*
    991 		**	Units default to no special animation.
    992 		*/
    993 		Set_Rate(0);
    994 		Set_Stage(0);
    995 
    996 		return(true);
    997 	}
    998 	return(false);
    999 }
   1000 
   1001 
   1002 /***********************************************************************************************
   1003  * UnitClass::Take_Damage -- Inflicts damage points on a unit.                                 *
   1004  *                                                                                             *
   1005  *    This routine will inflict the specified number of damage points on                       *
   1006  *    the given unit. If the unit is destroyed, then this routine will                         *
   1007  *    remove the unit cleanly from the game. The return value indicates                        *
   1008  *    whether the unit was destroyed. This will allow appropriate death                        *
   1009  *    animation or whatever.                                                                   *
   1010  *                                                                                             *
   1011  * INPUT:   damage-- The number of damage points to inflict.                                   *
   1012  *                                                                                             *
   1013  *          distance -- The distance from the damage center point to the object's center point.*
   1014  *                                                                                             *
   1015  *          warhead--The type of damage to inflict.                                            *
   1016  *                                                                                             *
   1017  *          source   -- Who is responsible for this damage?                                    *
   1018  *                                                                                             *
   1019  * OUTPUT:  Returns the result of the damage process. This can range from RESULT_NONE up to    *
   1020  *          RESULT_DESTROYED.                                                                  *
   1021  *                                                                                             *
   1022  * WARNINGS:   none                                                                            *
   1023  *                                                                                             *
   1024  * HISTORY:                                                                                    *
   1025  *   05/30/1991 JLB : Created.                                                                 *
   1026  *   07/12/1991 JLB : Script initiated by unit destruction.                                    *
   1027  *   04/15/1994 JLB : Converted to member function.                                            *
   1028  *   04/16/1994 JLB : Warhead modifier.                                                        *
   1029  *   06/03/1994 JLB : Added the source of the damage target value.                             *
   1030  *   06/20/1994 JLB : Source is a base class pointer.                                          *
   1031  *   11/22/1994 JLB : Shares base damage handler for techno objects.                           *
   1032  *   06/30/1995 JLB : Lasers do maximum damage against gunboat.                                *
   1033  *   08/16/1995 JLB : Harvester crushing doesn't occur on early missions.                      *
   1034  *=============================================================================================*/
   1035 ResultType UnitClass::Take_Damage(int & damage, int distance, WarheadType warhead, TechnoClass * source, bool forced)
   1036 {
   1037 	assert(Units.ID(this) == ID);
   1038 	assert(IsActive);
   1039 
   1040 	ResultType res = RESULT_NONE;
   1041 
   1042 	/*
   1043 	**	Remember if this object was selected. If it was and it gets destroyed and it has
   1044 	**	passengers that pop out, then the passengers will inherit the select state.
   1045 	*/
   1046 	//bool select = (IsSelected && House->IsPlayerControl);
   1047 	bool select = (Is_Selected_By_Player() );//&& House->IsPlayerControl);
   1048 
   1049 	/*
   1050 	**	In order for a this to be damaged, it must either be a unit
   1051 	**	with a crew or a sandworm.
   1052 	*/
   1053 	res = DriveClass::Take_Damage(damage, distance, warhead, source, forced);
   1054 
   1055 	if (res == RESULT_DESTROYED) {
   1056 		Death_Announcement(source);
   1057 		Shroud_Regen();	// remove the shroud if it's a gap generator
   1058 		if (Class->Explosion != ANIM_NONE) {
   1059 			AnimType anim = Class->Explosion;
   1060 
   1061 			/*
   1062 			**	SSM launchers will really explode big if they are carrying
   1063 			**	missiles at the time of the explosion.
   1064 			*/
   1065 			if (*this == UNIT_V2_LAUNCHER && Ammo) {
   1066 				anim = ANIM_NAPALM3;
   1067 			}
   1068 
   1069 			new AnimClass(anim, Coord);
   1070 
   1071 			/*
   1072 			**	Harvesters explode with a force equal to the amount of
   1073 			**	Tiberium they are carrying.
   1074 			*/
   1075 			if (Tiberium > 0 && Rule.IsExplosiveHarvester) {
   1076 				Wide_Area_Damage(Coord, CELL_LEPTON_W + CELL_LEPTON_W/2, Credit_Load()+Class->MaxStrength, this, WARHEAD_HE);
   1077 			}
   1078 
   1079 			/*
   1080 			**	Very strong units that have an explosion will also rock the
   1081 			**	screen when they are destroyed.
   1082 			*/
   1083 			if (Class->MaxStrength > 400) {
   1084 				Shake_The_Screen(3, Owner());
   1085 				if (source && Owner() != source->Owner()) {
   1086 					Shake_The_Screen(3, source->Owner());
   1087 				}
   1088 			}
   1089 		}
   1090 
   1091 		/*
   1092 		**	Possibly have the crew member run away.
   1093 		*/
   1094 		CELL cell = Coord_Cell(Center_Coord());
   1095 		Mark(MARK_UP);
   1096 
   1097 		if (Class->IsCrew && Class->Max_Passengers() == 0) {
   1098 			if (Percent_Chance(50)) {
   1099 				InfantryClass * i = 0;
   1100 
   1101 				if (Class->PrimaryWeapon == NULL) {
   1102 					i = new InfantryClass(INFANTRY_C1, House->Class->House);
   1103 					if (i != NULL) i->IsTechnician = true;
   1104 				} else {
   1105 					i = new InfantryClass(INFANTRY_E1, House->Class->House);
   1106 				}
   1107 				if (i != NULL) {
   1108 					if (i->Unlimbo(Coord, DIR_N)) {
   1109 						i->Strength = Random_Pick(5, (int)i->Class->MaxStrength/2);
   1110 						i->Scatter(0, true);
   1111 						if (!House->IsHuman) {
   1112 							i->Assign_Mission(MISSION_HUNT);
   1113 						} else {
   1114 							i->Assign_Mission(MISSION_GUARD);
   1115 						}
   1116 						if (select) i->Select();
   1117 					} else {
   1118 						delete i;
   1119 					}
   1120 				}
   1121 			}
   1122 		} else {
   1123 			while (Is_Something_Attached()) {
   1124 				FootClass * object = Detach_Object();
   1125 
   1126 				if (object == NULL) break;		// How can this happen?
   1127 
   1128 				/*
   1129 				**	Only infantry can run from a destroyed vehicle. Even then, it is not a sure
   1130 				**	thing.
   1131 				*/
   1132 				if (object->Is_Infantry() && object->Unlimbo(Coord, DIR_N)) {
   1133 					object->Look(false);
   1134 					object->Scatter(0, true);
   1135 					if (select) object->Select();
   1136 				} else {
   1137 					object->Record_The_Kill(source);
   1138 					delete object;
   1139 				}
   1140 			}
   1141 		}
   1142 
   1143 		/*
   1144 		**	If this is a truck, there is a possibility that a crate will drop out
   1145 		**	if the scenario so indicates and there is room.
   1146 		*/
   1147 		if (Scen.IsTruckCrate && *this == UNIT_TRUCK) {
   1148 			cell = Nearby_Location();
   1149 			if (cell != 0) {
   1150 				new OverlayClass(OVERLAY_WOOD_CRATE, cell);
   1151 			}
   1152 		}
   1153 
   1154 		if (*this == UNIT_MCV) {
   1155 			if (House) {
   1156 				House->Check_Pertinent_Structures();
   1157 			}
   1158 		}
   1159 
   1160 		/*
   1161 		**	Finally, delete the vehicle.
   1162 		*/
   1163 		delete this;
   1164 
   1165 	} else {
   1166 
   1167 		/*
   1168 		**	When damaged and below half strength, start smoking if
   1169 		**	it isn't already smoking.
   1170 		*/
   1171 		if (Health_Ratio() <= Rule.ConditionYellow && !IsAnimAttached) {
   1172 #ifdef FIXIT_ANTS
   1173 			if (*this != UNIT_ANT1 && *this != UNIT_ANT2 && *this != UNIT_ANT3)  {
   1174 #endif
   1175 				AnimClass * anim = new AnimClass(ANIM_SMOKE_M, Coord_Add(Coord, XYP_Coord(0, -8)));
   1176 				if (anim) anim->Attach_To(this);
   1177 #ifdef FIXIT_ANTS
   1178 			}
   1179 #endif
   1180 		   }
   1181 
   1182 		/*
   1183 		**	Try to crush anyone that fires on this unit if possible. The harvester
   1184 		**	typically is the only one that will qualify here.
   1185 		*/
   1186 		if (!Team.Is_Valid() && source != NULL && !IsTethered && !House->Is_Ally(source) && (!House->IsHuman || Rule.IsAutoCrush)) {
   1187 
   1188 			/*
   1189 			**	Try to crush the attacker if it can be crushed by this unit and this unit is
   1190 			**	not equipped with a flame type weapon. If this unit has a weapon and the target
   1191 			**	is not very close, then fire on it instead. In easy mode, they never run over the
   1192 			**	player. In hard mode, they always do. In normal mode, they only overrun past
   1193 			**	mission #8.
   1194 			*/
   1195 			if (Should_Crush_It(source)) {
   1196 				Assign_Destination(source->As_Target());
   1197 				Assign_Mission(MISSION_MOVE);
   1198 			} else {
   1199 
   1200 				/*
   1201 				**	Try to return to base if possible.
   1202 				*/
   1203 				if (*this == UNIT_HARVESTER && Pip_Count() && Health_Ratio() <= Rule.ConditionYellow) {
   1204 
   1205 					/*
   1206 					**	Find nearby refinery and head to it?
   1207 					*/
   1208 					BuildingClass * building = Find_Docking_Bay(STRUCT_REFINERY, false);
   1209 
   1210 					/*
   1211 					**	Since the refinery said it was ok to load, establish radio
   1212 					**	contact with the refinery and then await docking orders.
   1213 					*/
   1214 					if (building != NULL && Transmit_Message(RADIO_HELLO, building) == RADIO_ROGER) {
   1215 						Assign_Mission(MISSION_ENTER);
   1216 					}
   1217 				}
   1218 			}
   1219 		}
   1220 
   1221 		/*
   1222 		**	Computer controlled harvester will radio for help if they are attacked.
   1223 		*/
   1224 		if (*this == UNIT_HARVESTER && !House->IsHuman && source) {
   1225 			Base_Is_Attacked(source);
   1226 		}
   1227 	}
   1228 	return(res);
   1229 }
   1230 
   1231 
   1232 /***********************************************************************************************
   1233  * UnitClass::Active_Click_With -- Intercepts the active click to see if deployment is possible*
   1234  *                                                                                             *
   1235  *    This routine intercepts the active click operation. It check to see if this is a self    *
   1236  *    deployment request (MCV's have this ability). If it is, then the object is initiated     *
   1237  *    to self deploy. In the other cases, it passes the operation down to the lower            *
   1238  *    classes for processing.                                                                  *
   1239  *                                                                                             *
   1240  * INPUT:   action   -- The action requested of the unit.                                      *
   1241  *                                                                                             *
   1242  *          object   -- The object that the mouse pointer is over.                             *
   1243  *                                                                                             *
   1244  * OUTPUT:  none                                                                               *
   1245  *                                                                                             *
   1246  * WARNINGS:   none                                                                            *
   1247  *                                                                                             *
   1248  * HISTORY:                                                                                    *
   1249  *   03/10/1995 JLB : Created.                                                                 *
   1250  *=============================================================================================*/
   1251 void UnitClass::Active_Click_With(ActionType action, ObjectClass * object)
   1252 {
   1253 	assert(Units.ID(this) == ID);
   1254 	assert(IsActive);
   1255 
   1256 	if (action != What_Action(object)) {
   1257 		action = What_Action(object);
   1258 		switch (action) {
   1259 			case ACTION_SABOTAGE:
   1260 			case ACTION_CAPTURE:
   1261 				action = ACTION_ATTACK;
   1262 				break;
   1263 
   1264 			case ACTION_ENTER:
   1265 				action = ACTION_MOVE;
   1266 				break;
   1267 
   1268 			default:
   1269 				break;
   1270 		}
   1271 	}
   1272 
   1273 	/*
   1274 	**	Short circuit out if trying to tell a unit to "nomove" to itself. This bypass of the
   1275 	**	normal active click with logic prevents any disturbance to the vehicle's state. Without
   1276 	**	this bypass, a unit on a repair bay would stop repairing because it would break radio
   1277 	**	contact.
   1278 	*/
   1279 	if (object == this && action == ACTION_NOMOVE) {
   1280 		return;
   1281 	}
   1282 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   1283 	if (*this == UNIT_MAD && (IsDumping || Gold)) {
   1284 	} else {
   1285 		DriveClass::Active_Click_With(action, object);
   1286 	}
   1287 #else
   1288 	DriveClass::Active_Click_With(action, object);
   1289 #endif
   1290 }
   1291 
   1292 
   1293 /***********************************************************************************************
   1294  * UnitClass::Active_Click_With -- Performs specified action on specified cell.                *
   1295  *                                                                                             *
   1296  *    This routine is called when the mouse has been clicked over a cell and this unit must    *
   1297  *    now respond. Notice that this is merely a placeholder function that exists because there *
   1298  *    is another function of the same name that needs to be overloaded. C++ has scoping        *
   1299  *    restrictions when there are two identically named functions that are overridden in       *
   1300  *    different classes -- it handles it badly, hence the existence of this routine.           *
   1301  *                                                                                             *
   1302  * INPUT:   action   -- The action to perform on the cell specified.                           *
   1303  *                                                                                             *
   1304  *          cell     -- The cell that the action is to be performed on.                        *
   1305  *                                                                                             *
   1306  * OUTPUT:  none                                                                               *
   1307  *                                                                                             *
   1308  * WARNINGS:   none                                                                            *
   1309  *                                                                                             *
   1310  * HISTORY:                                                                                    *
   1311  *   09/21/1995 JLB : Created.                                                                 *
   1312  *=============================================================================================*/
   1313 void UnitClass::Active_Click_With(ActionType action, CELL cell)
   1314 {
   1315 	assert(Units.ID(this) == ID);
   1316 	assert(IsActive);
   1317 
   1318 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   1319 	if (*this == UNIT_MAD && (IsDumping || Gold)) {
   1320 	} else {
   1321 		DriveClass::Active_Click_With(action, cell);
   1322 	}
   1323 #else
   1324 	DriveClass::Active_Click_With(action, cell);
   1325 #endif
   1326 }
   1327 
   1328 
   1329 void UnitClass::Player_Assign_Mission(MissionType mission, TARGET target, TARGET destination)
   1330 {
   1331 	assert(Units.ID(this) == ID);
   1332 	assert(IsActive);
   1333 
   1334 	if (mission == MISSION_HARVEST) {
   1335 		ArchiveTarget = TARGET_NONE;
   1336 	} else if (mission == MISSION_ENTER) {
   1337 		BuildingClass* building = As_Building(destination);
   1338 		if (building != NULL && *building == STRUCT_REFINERY && building->In_Radio_Contact()) {
   1339 			building->Transmit_Message(RADIO_OVER_OUT);
   1340 		}
   1341 	}
   1342 	DriveClass::Player_Assign_Mission(mission, target, destination);
   1343 }
   1344 
   1345 
   1346 /***********************************************************************************************
   1347  * UnitClass::Enter_Idle_Mode -- Unit enters idle mode state.                                  *
   1348  *                                                                                             *
   1349  *    This routine is called when the unit completes one mission but does not have a clear     *
   1350  *    follow up mission to perform. In such a case, the unit should enter a default idle       *
   1351  *    state. This idle state varies depending on what the current internal computer            *
   1352  *    settings of the unit is as well as what kind of unit it is.                              *
   1353  *                                                                                             *
   1354  * INPUT:   initial  -- Is this called when the unit just leaves a factory or is initially     *
   1355  *                      or is initially placed on the map?                                     *
   1356  *                                                                                             *
   1357  * OUTPUT:  none                                                                               *
   1358  *                                                                                             *
   1359  * WARNINGS:   none                                                                            *
   1360  *                                                                                             *
   1361  * HISTORY:                                                                                    *
   1362  *   05/31/1994 JLB : Created.                                                                 *
   1363  *   06/03/1994 JLB : Fixed to handle non-combat vehicles.                                     *
   1364  *   06/18/1995 JLB : Allows a harvester to stop harvesting.                                   *
   1365  *=============================================================================================*/
   1366 void UnitClass::Enter_Idle_Mode(bool initial)
   1367 {
   1368 	assert(Units.ID(this) == ID);
   1369 	assert(IsActive);
   1370 
   1371 	MissionType	order = MISSION_GUARD;
   1372 
   1373 	if (IsToScatter) {
   1374 		IsToScatter = false;
   1375 		Scatter(0, true);
   1376 	}
   1377 
   1378 	/*
   1379 	**	A movement mission without a NavCom would be pointless to have a radio contact since
   1380 	**	no radio coordination occurs on a just a simple movement mission.
   1381 	*/
   1382 	if (Mission == MISSION_MOVE && !Target_Legal(NavCom)) {
   1383 		Transmit_Message(RADIO_OVER_OUT);
   1384 	}
   1385 
   1386 	Handle_Navigation_List();
   1387 	if (Target_Legal(NavCom)) {
   1388 		order = MISSION_MOVE;
   1389 	} else {
   1390 
   1391 		if (!Is_Weapon_Equipped()) {
   1392 			if (Class->IsToHarvest) {
   1393 				if (!In_Radio_Contact() && Mission != MISSION_HARVEST && MissionQueue != MISSION_HARVEST) {
   1394 					if (initial || !House->IsHuman || Map[Coord].Land_Type() == LAND_TIBERIUM) {
   1395 						order = MISSION_HARVEST;
   1396 					} else {
   1397 						order = MISSION_GUARD;
   1398 					}
   1399 					Assign_Target(TARGET_NONE);
   1400 					Assign_Destination(TARGET_NONE);
   1401 				} else {
   1402 					return;
   1403 				}
   1404 			} else {
   1405 				if (IsALoaner && Class->Max_Passengers() > 0 && Is_Something_Attached() && !Team.Is_Valid()) {
   1406 					order = MISSION_UNLOAD;
   1407 				} else {
   1408 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   1409 	if(*this == UNIT_MAD && Mission == MISSION_UNLOAD) {
   1410 		order = MISSION_UNLOAD;
   1411 	} else {
   1412 #endif
   1413 					order = MISSION_GUARD;
   1414 					Assign_Target(TARGET_NONE);
   1415 					Assign_Destination(TARGET_NONE);
   1416 				}
   1417 			}
   1418 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   1419 	}
   1420 #endif
   1421 		} else {
   1422 
   1423 			if (Mission == MISSION_GUARD || Mission == MISSION_GUARD_AREA || MissionControl[Mission].IsParalyzed || MissionControl[Mission].IsZombie) {
   1424 				return;
   1425 			}
   1426 
   1427 			if (House->IQ < Rule.IQGuardArea || Team.Is_Valid()) {
   1428 				order = MISSION_GUARD;
   1429 			} else {
   1430 				order = MISSION_GUARD_AREA;
   1431 			}
   1432 		}
   1433 	}
   1434 	Assign_Mission(order);
   1435 }
   1436 
   1437 
   1438 /***********************************************************************************************
   1439  * UnitClass::Goto_Clear_Spot -- Finds a clear spot to deploy.                                 *
   1440  *                                                                                             *
   1441  *    This routine is used by the MCV to find a clear spot to deploy. If a clear spot          *
   1442  *    is found, then the MCV will assign that location to its navigation computer. This only   *
   1443  *    occurs if the MCV isn't already heading toward a spot.                                   *
   1444  *                                                                                             *
   1445  * INPUT:   none                                                                               *
   1446  *                                                                                             *
   1447  * OUTPUT:  bool;  Is the located at a spot where it can deploy?                               *
   1448  *                                                                                             *
   1449  * WARNINGS:   none                                                                            *
   1450  *                                                                                             *
   1451  * HISTORY:                                                                                    *
   1452  *   06/27/1994 JLB : Created.                                                                 *
   1453  *=============================================================================================*/
   1454 bool UnitClass::Goto_Clear_Spot(void)
   1455 {
   1456 	assert(Units.ID(this) == ID);
   1457 	assert(IsActive);
   1458 
   1459 	Mark(MARK_UP);
   1460 	if (!Target_Legal(NavCom) && BuildingTypeClass::As_Reference(STRUCT_CONST).Legal_Placement(Adjacent_Cell(Coord_Cell(Center_Coord()), FACING_NW))) {
   1461 		Mark(MARK_DOWN);
   1462 		return(true);
   1463 	}
   1464 
   1465 	if (!Target_Legal(NavCom)) {
   1466 		/*
   1467 		**	This scan table is skewed to north scanning only. This should
   1468 		**	probably be converted to a more flexible method.
   1469 		*/
   1470 		static int _offsets[] = {
   1471 			-MAP_CELL_W*1,
   1472 			-MAP_CELL_W*2,
   1473 			-(MAP_CELL_W*2)+1,
   1474 			-(MAP_CELL_W*2)-1,
   1475 			-MAP_CELL_W*3,
   1476 			-(MAP_CELL_W*3)+1,
   1477 			-(MAP_CELL_W*3)-1,
   1478 			-(MAP_CELL_W*3)+2,
   1479 			-(MAP_CELL_W*3)-2,
   1480 			-MAP_CELL_W*4,
   1481 			-(MAP_CELL_W*4)+1,
   1482 			-(MAP_CELL_W*4)-1,
   1483 			-(MAP_CELL_W*4)+2,
   1484 			-(MAP_CELL_W*4)-2,
   1485 //BG: Added south scanning
   1486 			MAP_CELL_W*1,
   1487 			MAP_CELL_W*2,
   1488 			(MAP_CELL_W*2)+1,
   1489 			(MAP_CELL_W*2)-1,
   1490 			MAP_CELL_W*3,
   1491 			(MAP_CELL_W*3)+1,
   1492 			(MAP_CELL_W*3)-1,
   1493 			(MAP_CELL_W*3)+2,
   1494 			(MAP_CELL_W*3)-2,
   1495 			MAP_CELL_W*4,
   1496 			(MAP_CELL_W*4)+1,
   1497 			(MAP_CELL_W*4)-1,
   1498 			(MAP_CELL_W*4)+2,
   1499 			(MAP_CELL_W*4)-2,
   1500 
   1501 //BG: Added some token east/west scanning
   1502 			-1,-2,-3,-4,
   1503 
   1504 			 1, 2, 3, 4,
   1505 			0
   1506 		};
   1507 		int * ptr;
   1508 
   1509 		ptr = &_offsets[0];
   1510 		while (*ptr) {
   1511 			CELL	cell = Coord_Cell(Coord)+*ptr++;
   1512 			CELL	check_cell = Adjacent_Cell(cell, FACING_NW);
   1513 			if (BuildingTypeClass::As_Reference(STRUCT_CONST).Legal_Placement(check_cell)) {
   1514 				Assign_Destination(::As_Target(cell));
   1515 				break;
   1516 			}
   1517 		}
   1518 	}
   1519 	Mark(MARK_DOWN);
   1520 
   1521 	/*
   1522 	** If we couldn't find a destination to go to, let's try random movement
   1523 	** to see if that brings us to a better spot.
   1524 	*/
   1525 	if(!Target_Legal(NavCom) && !House->IsHuman) {
   1526 		Scatter(0);
   1527 	}
   1528 
   1529 	return(false);
   1530 }
   1531 
   1532 
   1533 /***********************************************************************************************
   1534  * UnitClass::Try_To_Deploy -- The unit attempts to "deploy" at current location.              *
   1535  *                                                                                             *
   1536  *    Certain units have the ability to deploy into a building. When this routine is called    *
   1537  *    for one of those units, it will attempt to deploy at its current location. If the unit   *
   1538  *    is in motion to a destination or it isn't one of the special units that can deploy or    *
   1539  *    it isn't allowed to deploy at this location for some reason it won't deploy. In all      *
   1540  *    other cases, it will begin to deploy and once it begins only a player abort action will  *
   1541  *    stop it.                                                                                 *
   1542  *                                                                                             *
   1543  * INPUT:   none                                                                               *
   1544  *                                                                                             *
   1545  * OUTPUT:  bool; Was deployment begun?                                                        *
   1546  *                                                                                             *
   1547  * WARNINGS:   none                                                                            *
   1548  *                                                                                             *
   1549  * HISTORY:                                                                                    *
   1550  *   06/18/1994 JLB : Created.                                                                 *
   1551  *=============================================================================================*/
   1552 bool UnitClass::Try_To_Deploy(void)
   1553 {
   1554 	assert(Units.ID(this) == ID);
   1555 	assert(IsActive);
   1556 
   1557 	if (!Target_Legal(NavCom) && !IsRotating) {
   1558 		if (*this == UNIT_MCV) {
   1559 
   1560 			/*
   1561 			**	Determine if it is legal to deploy at this location. If not, tell the
   1562 			**	player.
   1563 			*/
   1564 			Mark(MARK_UP);
   1565 			CELL cell = Coord_Cell(Adjacent_Cell(Center_Coord(), FACING_NW));
   1566 			if (!BuildingTypeClass::As_Reference(STRUCT_CONST).Legal_Placement(cell)) {
   1567 				if (PlayerPtr == House) {
   1568 					Speak(VOX_DEPLOY);
   1569 				}
   1570 				if (!House->IsHuman) {
   1571 					BuildingTypeClass::As_Reference(STRUCT_CONST).Flush_For_Placement(cell, House);
   1572 				}
   1573 				Mark(MARK_DOWN);
   1574 				IsDeploying = false;
   1575 				return(false);
   1576 			}
   1577 			Mark(MARK_DOWN);
   1578 
   1579 			/*
   1580 			**	If the unit is not facing the correct direction, then start it rotating
   1581 			**	toward the right facing, but still flag it as if it had deployed. This is
   1582 			**	because it will deploy as soon as it reaches the correct facing.
   1583 			*/
   1584 			if (PrimaryFacing.Current() != DIR_SW) {
   1585 				Do_Turn(DIR_SW);
   1586 //				PrimaryFacing.Set_Desired(DIR_SW);
   1587 				IsDeploying = true;
   1588 				return(true);
   1589 			}
   1590 
   1591 			/*
   1592 			**	Since the unit is already facing the correct direction, actually do the
   1593 			**	deploy logic. If for some reason this cannot occur, then don't delete the
   1594 			**	unit, just mark it as not deploying.
   1595 			*/
   1596 			Mark(MARK_UP);
   1597 			BuildingClass * building = new BuildingClass(STRUCT_CONST, House->Class->House);
   1598 			if (building != NULL) {
   1599 				if (building->Unlimbo(Adjacent_Cell(Coord, FACING_NW))) {
   1600 
   1601 					/*
   1602 					**	Play the buildup sound for the player if this is the players
   1603 					**	MCV.
   1604 					*/
   1605 					if (building->House == PlayerPtr) {
   1606 						Sound_Effect(VOC_PLACE_BUILDING_DOWN, Center_Coord());
   1607 					} else {
   1608 						building->IsToRebuild = true;
   1609 						building->IsToRepair = true;
   1610 					}
   1611 
   1612 					/*
   1613 					**	Always reveal the construction yard to the player that owned the
   1614 					**	mobile construction vehicle.
   1615 					*/
   1616 					building->Revealed(House);
   1617 
   1618 					/*
   1619 					**	When the MCV deploys, always consider production to have started
   1620 					**	for the owning house. This ensures that in multiplay, computer
   1621 					**	opponents will begin construction as soon as they start their
   1622 					**	base.
   1623 					*/
   1624 					House->IsStarted = true;
   1625 
   1626 					/*
   1627 					**	Force the newly placed construction yard to be in the same strength
   1628 					**	ratio as the MCV that deployed into it.
   1629 					*/
   1630 					building->Strength = Health_Ratio() * (int)building->Class->MaxStrength;
   1631 
   1632 					/*
   1633 					** Force the MCV to drop any flag it was carrying.  This will also set
   1634 					** the owner house's flag home cell (since the house's FlagHome is
   1635 					** presumably 0 at this point).
   1636 					*/
   1637 					Stun();
   1638 
   1639 					/*
   1640 					** If this MCV was teleported here, clear the gray flag so
   1641 					** the screen will go back to color.
   1642 					*/
   1643 					if (IsMoebius && !Scen.IsFadingColor) {
   1644 						Scen.IsFadingBW = false;
   1645 						Scen.IsFadingColor = true;
   1646 						Scen.FadeTimer = GRAYFADETIME;
   1647 					}
   1648 					delete this;
   1649 					return(true);
   1650 				} else {
   1651 
   1652 					/*
   1653 					**	Could not deploy the construction yard at this location! Just revert
   1654 					**	back to normal "just sitting there" mode and await further instructions.
   1655 					*/
   1656 					delete building;
   1657 				}
   1658 			}
   1659 			Mark(MARK_DOWN);
   1660 			IsDeploying = false;
   1661 		}
   1662 	}
   1663 	return(false);
   1664 }
   1665 
   1666 
   1667 /***********************************************************************************************
   1668  * UnitClass::Per_Cell_Process -- Performs operations necessary on a per cell basis.           *
   1669  *                                                                                             *
   1670  *    This routine will perform the operations necessary that occur when a unit is at the      *
   1671  *    center of a cell. These operations could entail deploying into a construction yard,      *
   1672  *    radioing a transport unit, and looking around for the enemy.                             *
   1673  *                                                                                             *
   1674  * INPUT:   why   -- Specifies the circumstances under which this routine was called.          *
   1675  *                                                                                             *
   1676  * OUTPUT:  none                                                                               *
   1677  *                                                                                             *
   1678  * WARNINGS:   none                                                                            *
   1679  *                                                                                             *
   1680  * HISTORY:                                                                                    *
   1681  *   06/18/1994 JLB : Created.                                                                 *
   1682  *   06/17/1995 JLB : Handles case when building says "NO!"                                    *
   1683  *   06/30/1995 JLB : Gunboats head back and forth now.                                        *
   1684  *=============================================================================================*/
   1685 void UnitClass::Per_Cell_Process(PCPType why)
   1686 {
   1687 	assert(Units.ID(this) == ID);
   1688 	assert(IsActive);
   1689 
   1690 	CELL	cell = Coord_Cell(Coord);
   1691 	HousesType house;
   1692 
   1693 	if (why == PCP_END || why == PCP_ROTATION) {
   1694 		/*
   1695 		**	Check to see if this is merely the end of a rotation for the MCV as it is
   1696 		**	preparing to deploy. In this case, it should begin its deploy process.
   1697 		*/
   1698 		if (IsDeploying) {
   1699 			Try_To_Deploy();
   1700 			if (!IsActive) return;			// Unit no longer exists -- bail.
   1701 		}
   1702 	}
   1703 
   1704 	BStart(BENCH_PCP);
   1705 	if (why == PCP_END) {
   1706 		/*
   1707 		**	If this is a unit that is driving onto a building then the unit must enter
   1708 		**	the building as the final step.
   1709 		*/
   1710 		TechnoClass	* whom = Contact_With_Whom();
   1711 		if (IsTethered && whom != NULL) {
   1712 			if (whom->What_Am_I() == RTTI_BUILDING && Mission == MISSION_ENTER) {
   1713 				if (whom == Map[CELL(cell-MAP_CELL_W)].Cell_Building()) {
   1714 					switch (Transmit_Message(RADIO_IM_IN, whom)) {
   1715 						case RADIO_ROGER:
   1716 							break;
   1717 
   1718 						case RADIO_ATTACH:
   1719 							break;
   1720 
   1721 						default:
   1722 							Scatter(0, true);
   1723 							break;
   1724 					}
   1725 				}
   1726 			}
   1727 		}
   1728 
   1729 		/*
   1730 		**	Unit entering a transport vehicle will break radio contact
   1731 		**	and attach itself to the transporter.
   1732 		*/
   1733 		TechnoClass * techno = Contact_With_Whom();
   1734 		if (Mission == MISSION_ENTER && techno && Coord_Cell(Coord) == Coord_Cell(techno->Coord) && techno == As_Techno(NavCom)) {
   1735 			if (Transmit_Message(RADIO_IM_IN) == RADIO_ATTACH) {
   1736 				Limbo();
   1737 				techno->Attach(this);
   1738 			}
   1739 			BEnd(BENCH_PCP);
   1740 			return;
   1741 		}
   1742 
   1743 		/*
   1744 		**	When breaking away from a transport object or building, possibly
   1745 		**	scatter or otherwise begin normal unit operations.
   1746 		*/
   1747 		if (IsTethered && (Mission != MISSION_ENTER ||
   1748 				(As_Techno(NavCom) != NULL && Contact_With_Whom() != As_Techno(NavCom))
   1749 				) &&
   1750 				Mission != MISSION_UNLOAD) {
   1751 
   1752 			/*
   1753 			**	Special hack check to make sure that even though it has moved one
   1754 			**	cell, if it is still on the building (e.g., service depot), have
   1755 			**	it scatter again.
   1756 			*/
   1757 			if	(Map[Coord].Cell_Building() != NULL && !Target_Legal(NavCom)) {
   1758 				Scatter(0, true, true);
   1759 			} else {
   1760 				TechnoClass * contact = Contact_With_Whom();
   1761 				if (Transmit_Message(RADIO_UNLOADED) == RADIO_RUN_AWAY) {
   1762 					if (*this == UNIT_HARVESTER && contact && contact->What_Am_I() == RTTI_BUILDING && *((BuildingClass*)contact) != STRUCT_REPAIR) {
   1763 						Assign_Mission(MISSION_HARVEST);
   1764 					} else if (!Target_Legal(NavCom)) {
   1765 						Scatter(0, true);
   1766 					} else {
   1767 
   1768 						/*
   1769 						**	Special case hack to allow automatic transition to loading
   1770 						**	onto a transport (or other situation) if the destination
   1771 						**	so indicates.
   1772 						*/
   1773 						TechnoClass * techno = As_Techno(NavCom);
   1774 						if (techno != NULL) {
   1775 							Transmit_Message(RADIO_DOCKING, techno);
   1776 						}
   1777 					}
   1778 				} else {
   1779 					if (*this == UNIT_HARVESTER) {
   1780 						if (Target_Legal(ArchiveTarget)) {
   1781 							Assign_Mission(MISSION_HARVEST);
   1782 							Assign_Destination(ArchiveTarget);
   1783 							ArchiveTarget = TARGET_NONE;
   1784 						} else {
   1785 
   1786 							/*
   1787 							**	Since there is no place to go, move away to clear
   1788 							**	the pad for another harvester.
   1789 							*/
   1790 							if (!Target_Legal(NavCom)) {
   1791 								Scatter(0, true);
   1792 							}
   1793 						}
   1794 					}
   1795 				}
   1796 			}
   1797 		}
   1798 
   1799 		/*
   1800 		**	If this is a loaner unit and is is off the edge of the
   1801 		**	map, then it gets eliminated. That is, unless it is carrying cargo. This means that
   1802 		**	it is probably carrying an incoming reinforcement and it should not be eliminated.
   1803 		*/
   1804 		if (Edge_Of_World_AI()) {
   1805 			BEnd(BENCH_PCP);
   1806 			return;
   1807 		}
   1808 
   1809 		/*
   1810 		**	The unit performs looking around at this time. If the
   1811 		**	unit moved further than one square during the last track
   1812 		**	move, don't do an incremental look. Do a full look around
   1813 		**	instead.
   1814 		*/
   1815 		if (IsPlanningToLook) {
   1816 			IsPlanningToLook = false;
   1817 			Look(false);
   1818 		} else {
   1819 			Look(true);
   1820 		}
   1821 
   1822 		/*
   1823 		** If this is a mobile gap generator, restore the shroud where appropriate
   1824 		** and re-shroud around us.
   1825 		*/
   1826 		if (Class->IsGapper && !House->IsPlayerControl) {
   1827 			Shroud_Regen();
   1828 		}
   1829 
   1830 		/*
   1831 		**	Act on new orders if the unit is at a good position to do so.
   1832 		*/
   1833 		if (!IsDumping) {
   1834 			Commence();
   1835 		}
   1836 
   1837 		/*
   1838 		**	Certain units require some setup time after they come to a halt.
   1839 		*/
   1840 		if (!Target_Legal(NavCom) && Path[0] == FACING_NONE) {
   1841 			if (Class->IsNoFireWhileMoving) {
   1842 				Arm = Rearm_Delay(true)/4;
   1843 			}
   1844 		}
   1845 
   1846 		/*
   1847 		**	If there is a house flag here, then this unit just might pick it up.
   1848 		*/
   1849 		if (Flagged == HOUSE_NONE) {
   1850 
   1851 			if (Map[cell].IsFlagged && !House->Is_Ally(Map[cell].Owner)) {
   1852 				HouseClass::As_Pointer(Map[cell].Owner)->Flag_Attach(this);
   1853 			}
   1854 		}
   1855 
   1856 		/*
   1857 		**	If this is the unit's own flag-home-cell and the unit is carrying
   1858 		** a flag, destroy the house of the flag the unit is carrying.
   1859 		*/
   1860 		if (Flagged != HOUSE_NONE) {
   1861 
   1862 			/*
   1863 			**	If this vehicle is carrying your flag, then it will reveal the
   1864 			**	map for you as well as itself. This gives you and opportunity to
   1865 			**	attack the unit.
   1866 			*/
   1867 			if (!IsOwnedByPlayer && Flagged == PlayerPtr->Class->House) {
   1868 				Map.Sight_From(Coord_Cell(Coord), Class->SightRange, House, true);
   1869 			}
   1870 
   1871 			/*
   1872 			**	If the flag reaches the home cell for the player, then the flag's
   1873 			**	owner will be destroyed.
   1874 			*/
   1875 			if (cell == HouseClass::As_Pointer(Owner())->FlagHome) {
   1876 				house = Flagged; // Flag_Remove will clear 'Flagged', so save it
   1877 				HouseClass::As_Pointer(house)->Flag_Remove(As_Target(), true);
   1878 				HouseClass::As_Pointer(house)->Flag_To_Die();
   1879 			}
   1880 		}
   1881 
   1882 		/*
   1883 		** If entering a cell with a land mine in it, blow up the mine.
   1884 		*/
   1885 		BuildingClass * bldng = Map[cell].Cell_Building();
   1886 		if (bldng != NULL && (*bldng == STRUCT_AVMINE || *bldng == STRUCT_APMINE) && !bldng->House->Is_Ally(this)) {
   1887 
   1888 			/*
   1889 			** Special case: if it's a land mine deployer, and it ran over the
   1890 			** type of mine it deploys (only possible if it just dropped it
   1891 			** down) then ignore the mine.
   1892 			*/
   1893 			if (*this != UNIT_MINELAYER || bldng->House != House) {
   1894 
   1895 				COORDINATE blcoord = bldng->Center_Coord();
   1896 
   1897 				new AnimClass(ANIM_MINE_EXP1, blcoord);
   1898 //				new AnimClass(Combat_Anim(Rule.AVMineDamage, WARHEAD_HE, Map[cell].Land_Type()), blcoord);
   1899 
   1900 				/*
   1901 				** Vehicles blow up both mines, but they only take significant damage from AV mines.
   1902 				*/
   1903 				if (*bldng == STRUCT_AVMINE) {
   1904 					int damage = Rule.AVMineDamage;
   1905 					Take_Damage(damage, 0, WARHEAD_HE);
   1906 				} else {
   1907 					int damage = 10;
   1908 					Take_Damage(damage, 0, WARHEAD_HE);
   1909 				}
   1910 				delete bldng;
   1911 				if (!IsActive) {
   1912 					BEnd(BENCH_PCP);
   1913 					return;
   1914 				}
   1915 			}
   1916 		}
   1917 
   1918 		/*
   1919 		**	If after all is said and done, the unit finishes its move on an impassable cell, then
   1920 		**	it must presume that it is in the case of a unit driving onto a bridge that blows up
   1921 		**	before the unit completes it's move. In such a case the unit should have been destroyed
   1922 		**	anyway, so blow it up now.
   1923 		*/
   1924 		LandType land = Map[Coord].Land_Type();
   1925 		if (!IsDriving && IsMovingOntoBridge && (land == LAND_ROCK || land == LAND_WATER || land == LAND_RIVER)) {
   1926 			new AnimClass(Combat_Anim(Strength, WARHEAD_AP, land), Coord);
   1927 			int damage = Strength;
   1928 			Take_Damage(damage, 0, WARHEAD_AP, NULL, true);
   1929 			return;
   1930 		}
   1931 	}
   1932 
   1933 	/*
   1934 	**	Destroy any crushable wall that is driven over by a tracked vehicle.
   1935 	*/
   1936 	CellClass * cellptr = &Map[cell];
   1937 	if (Class->IsCrusher && cellptr->Overlay != OVERLAY_NONE) {
   1938 //	if (Class->Speed == SPEED_TRACK && cellptr->Overlay != OVERLAY_NONE) {
   1939 		OverlayTypeClass const * optr = &OverlayTypeClass::As_Reference(cellptr->Overlay);
   1940 
   1941 		if (optr->IsCrushable) {
   1942 			if (optr->Type == OVERLAY_SANDBAG_WALL) {
   1943 				Sound_Effect(VOC_SANDBAG, Center_Coord());
   1944 			} else {
   1945 				Sound_Effect(VOC_WALLKILL2, Center_Coord());
   1946 			}
   1947 			cellptr->Reduce_Wall(-1);
   1948 		}
   1949 	}
   1950 
   1951 	/*
   1952 	**	Check to see if crushing of any unfortunate infantry is warranted.
   1953 	*/
   1954 	Overrun_Square(Coord_Cell(Coord), false);
   1955 
   1956 	if (!IsActive) {
   1957 		BEnd(BENCH_PCP);
   1958 		return;
   1959 	}
   1960 	DriveClass::Per_Cell_Process(why);
   1961 	BEnd(BENCH_PCP);
   1962 }
   1963 
   1964 
   1965 /***********************************************************************************************
   1966  * UnitClass::Shape_Number -- Fetch the shape number to use for this unit.                     *
   1967  *                                                                                             *
   1968  *    This routine will calculate the shape number for this unit. The shape number is used     *
   1969  *    for the body of the unit.                                                                *
   1970  *                                                                                             *
   1971  * INPUT:   none                                                                               *
   1972  *                                                                                             *
   1973  * OUTPUT:  Returns with the shape number to be used for this unit.                            *
   1974  *                                                                                             *
   1975  * WARNINGS:   none                                                                            *
   1976  *                                                                                             *
   1977  * HISTORY:                                                                                    *
   1978  *   07/29/1996 JLB : Created.                                                                 *
   1979  *=============================================================================================*/
   1980 int UnitClass::Shape_Number(void) const
   1981 {
   1982 	assert(Units.ID(this) == ID);
   1983 	assert(IsActive);
   1984 
   1985 	int			shapenum;		// Working shape number.
   1986 	int			facing = Dir_To_32(PrimaryFacing);
   1987 	int			tfacing = Dir_To_32(SecondaryFacing);
   1988 	DirType		rotation = DIR_N;
   1989 
   1990 #ifdef FIXIT_ANTS
   1991 	/*
   1992 	**	This handles the ant case.
   1993 	*/
   1994 	if (Class->Rotation == 8)  {
   1995 
   1996 		/*
   1997 		**	The starting frame is based on the facing of the unit.
   1998 		*/
   1999 		shapenum = ((UnitClass::BodyShape[facing]+2)/4) & 0x07;
   2000 
   2001 		/*
   2002 		**	If the unit is driving, then it has an animation adjustment to the frame number.
   2003 		*/
   2004 		if (IsDriving)  {
   2005 			shapenum = 8 + (shapenum * 8) + ((::Frame+ID)/2) % 8;
   2006 		} else {
   2007 
   2008 			/*
   2009 			**	If in combat, then do combat anims.
   2010 			*/
   2011 			if (Arm > 0)  {
   2012 				shapenum = 8 + 64 + (shapenum * 4) + ((::Frame+ID)/2) % 4;
   2013 			}
   2014 		}
   2015 	} else {
   2016 #endif
   2017 
   2018 	/*
   2019 	**	Fetch the harvesting animation stage as appropriate.
   2020 	*/
   2021 	if (IsHarvesting && !PrimaryFacing.Is_Rotating() && !NavCom && !IsDriving) {
   2022 //			static char _hstage[] = {0, 1, 2, 3, 4, 5, 6, 7, 0};
   2023 		unsigned stage = Fetch_Stage();
   2024 		if (stage >= ARRAY_SIZE(Class->Harvester_Load_List)) stage = ARRAY_SIZE(Class->Harvester_Load_List)-1;
   2025 		shapenum = 32 + (((UnitClass::BodyShape[facing]+2)/4)*Class->Harvester_Load_Count)+Class->Harvester_Load_List[stage];
   2026 	} else {
   2027 		/*
   2028 		** If the harvester's dumping a load of ore, show that animation
   2029 		*/
   2030 		if (IsDumping) {
   2031 			unsigned stage = Fetch_Stage();
   2032 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2033 			if (*this == UNIT_MAD) {
   2034 				if (stage >= 8) {
   2035 					stage = 7;
   2036 				}
   2037 				shapenum = 32 + stage + (UnitClass::BodyShape[facing]/4)*8;
   2038 			} else {
   2039 				if (stage >= ARRAY_SIZE(Class->Harvester_Dump_List)) stage = ARRAY_SIZE(Class->Harvester_Dump_List)-1;
   2040 				shapenum = Class->Harvester_Dump_List[stage]+96;
   2041 			}
   2042 #else
   2043 			if (stage >= ARRAY_SIZE(Class->Harvester_Dump_List)) stage = ARRAY_SIZE(Class->Harvester_Dump_List)-1;
   2044 			shapenum = Class->Harvester_Dump_List[stage]+96;
   2045 #endif
   2046 		} else {
   2047 			shapenum = UnitClass::BodyShape[facing];
   2048 
   2049 			if (Class->IsAnimating) {
   2050 				shapenum = Fetch_Stage();
   2051 			}
   2052 
   2053 			/*
   2054 			**	Door opening and closing animation must be handled carefully. There are only
   2055 			**	certain directions where this door animation will work.
   2056 			*/
   2057 			if (!Is_Door_Closed() && (PrimaryFacing == DIR_NW || PrimaryFacing == DIR_NE)) {
   2058 				if (PrimaryFacing == DIR_NE) {
   2059 					shapenum = 32;
   2060 				} else {
   2061 					if (PrimaryFacing == DIR_NW) {
   2062 						shapenum = 35;
   2063 					}
   2064 				}
   2065 				shapenum += Door_Stage();
   2066 			}
   2067 		}
   2068 	}
   2069 
   2070 #ifdef FIXIT_ANTS
   2071 	}
   2072 #endif
   2073 
   2074 	/*
   2075 	**	The body of the V2 launcher indicates whether it is loaded with a missile
   2076 	**	or not.
   2077 	*/
   2078 	if (*this == UNIT_V2_LAUNCHER) {
   2079 		if (Ammo == 0) shapenum += 32;
   2080 	}
   2081 
   2082 	return(shapenum);
   2083 }
   2084 
   2085 
   2086 /***********************************************************************************************
   2087  * UnitClass::Draw_It -- Draws a unit object.                                                  *
   2088  *                                                                                             *
   2089  *    This routine is the one that actually draws a unit object. It displays the unit          *
   2090  *    according to its current state flags and centered at the location specified.             *
   2091  *                                                                                             *
   2092  * INPUT:   x,y   -- The X and Y coordinate of where to draw the unit.                         *
   2093  *                                                                                             *
   2094  *          window   -- The clipping window to use.                                            *
   2095  *                                                                                             *
   2096  * OUTPUT:  none                                                                               *
   2097  *                                                                                             *
   2098  * WARNINGS:   none                                                                            *
   2099  *                                                                                             *
   2100  * HISTORY:                                                                                    *
   2101  *   06/20/1994 JLB : Created.                                                                 *
   2102  *   06/27/1994 JLB : Takes a window parameter.                                                *
   2103  *   08/15/1994 JLB : Removed infantry support.                                                *
   2104  *   01/07/1995 JLB : Harvester animation support.                                             *
   2105  *   07/08/1995 JLB : Uses general purpose draw routine.                                       *
   2106  *=============================================================================================*/
   2107 void UnitClass::Draw_It(int x, int y, WindowNumberType window) const
   2108 {
   2109 	assert(Units.ID(this) == ID);
   2110 	assert(IsActive);
   2111 
   2112 	int			shapenum;		// Working shape number.
   2113 	void const	* shapefile;		// Working shape file pointer.
   2114 	int			facing = Dir_To_32(PrimaryFacing);
   2115 	int			tfacing = Dir_To_32(SecondaryFacing);
   2116 	DirType		rotation = DIR_N;
   2117 	int			scale = 0x0100;
   2118 
   2119 	/*
   2120 	**	Verify the legality of the unit class.
   2121 	*/
   2122 	shapefile = Get_Image_Data();
   2123 	if (shapefile == NULL) return;
   2124 
   2125 	/*
   2126 	**	If drawing of this unit is not explicitly prohibited, then proceed
   2127 	**	with the render process.
   2128 	*/
   2129 	const bool is_hidden = (Visual_Character() == VISUAL_HIDDEN) && (window != WINDOW_VIRTUAL);
   2130 	if (!is_hidden) {
   2131 		shapenum = Shape_Number();
   2132 
   2133 		/*
   2134 		**	The artillery unit should have its entire body recoil when it fires.
   2135 		*/
   2136 		if (*this == UNIT_ARTY && IsInRecoilState) {
   2137 			Recoil_Adjust(PrimaryFacing.Current(), x, y);
   2138 		}
   2139 
   2140 		/*
   2141 		**	Actually perform the draw. Overlay an optional shimmer effect as necessary.
   2142 		*/
   2143 		Techno_Draw_Object(shapefile, shapenum, x, y, window, rotation, scale);
   2144 
   2145 		/*
   2146 		**	If there is a rotating radar dish, draw it now.
   2147 		*/
   2148 		if (Class->IsRadarEquipped) {
   2149 			if (*this == UNIT_MGG) {
   2150 				int x2 = x, y2 = y;
   2151 				shapenum = 32 + (Frame & 7);
   2152 				Class->Turret_Adjust(PrimaryFacing, x2, y2);
   2153 				Techno_Draw_Object(shapefile, shapenum, x2, y2, window);
   2154 			} else {
   2155 //#ifdef FIXIT_PHASETRANSPORT	//	checked - ajw 9/28/98
   2156 //				if (*this == UNIT_PHASE) {
   2157 //					shapenum = 38 + (Frame & 7);
   2158 //				} else {
   2159 //					shapenum = 32 + (Frame % 32);
   2160 //				}
   2161 //#else
   2162 				shapenum = 32 + (Frame % 32);
   2163 //#endif
   2164 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2165 				if (*this == UNIT_TESLATANK) {
   2166 					Techno_Draw_Object(shapefile, shapenum, x, y, window);
   2167 				} else {
   2168 					Techno_Draw_Object(shapefile, shapenum, x, y-5, window);
   2169 				}
   2170 #else
   2171 				Techno_Draw_Object(shapefile, shapenum, x, y-5, window);
   2172 #endif
   2173 			}
   2174 		}
   2175 
   2176 		/*
   2177 		**	If there is a turret, then it must be rendered as well. This may include
   2178 		**	firing animation if required.
   2179 		*/
   2180 		if (/*!Class->IsChunkyShape &&*/ Class->IsTurretEquipped) {
   2181 			int xx = x;
   2182 			int yy = y;
   2183 
   2184 			/*
   2185 			**	Determine which turret shape to use. This depends on if there
   2186 			**	is any firing animation in progress.
   2187 			*/
   2188 			shapenum = TechnoClass::BodyShape[tfacing]+32;
   2189 #ifdef FIXIT_PHASETRANSPORT	//	checked - ajw 9/28/98
   2190 			if (*this == UNIT_PHASE) {
   2191 				shapenum += 6;
   2192 			}
   2193 #endif
   2194 			/*
   2195 			**	A recoiling turret moves "backward" one pixel.
   2196 			*/
   2197 			if (IsInRecoilState) {
   2198 				Recoil_Adjust(SecondaryFacing, xx, yy);
   2199 			}
   2200 
   2201 			Class->Turret_Adjust(PrimaryFacing, xx, yy);
   2202 
   2203 			/*
   2204 			**	Actually perform the draw. Overlay an optional shimmer effect as necessary.
   2205 			*/
   2206 			Techno_Draw_Object(shapefile, shapenum, xx, yy, window);
   2207 		}
   2208 	}
   2209 
   2210 	/*
   2211 	**	If this unit is carrying the flag, then draw that on top of everything else.
   2212 	*/
   2213 	if (Flagged != HOUSE_NONE) {
   2214 		shapefile = MFCD::Retrieve("FLAGFLY.SHP");
   2215 		int flag_x = x + (ICON_PIXEL_W / 2) - 2;
   2216 		int flag_y = y + (3 * ICON_PIXEL_H / 4) - Get_Build_Frame_Height(shapefile);
   2217 		CC_Draw_Shape(this, "FLAGFLY", shapefile, Frame % 14, flag_x, flag_y, window, SHAPE_CENTER|SHAPE_FADING|SHAPE_GHOST, HouseClass::As_Pointer(Flagged)->Remap_Table(false, Class->Remap), Map.UnitShadow, DIR_N, 0x0100, Flagged);
   2218 	}
   2219 
   2220 	DriveClass::Draw_It(x, y, window);
   2221 }
   2222 
   2223 
   2224 /***********************************************************************************************
   2225  * UnitClass::Tiberium_Check -- Search for and head toward nearest available Tiberium patch.   *
   2226  *                                                                                             *
   2227  *    This routine is used to move a harvester to a place where it can load up with            *
   2228  *    Tiberium. It will return true only if it can start harvesting. Otherwise, it sets        *
   2229  *    the navigation computer toward the nearest Tiberium and lets the unit head there         *
   2230  *    automatically.                                                                           *
   2231  *                                                                                             *
   2232  * INPUT:   center   -- Reference to the center of the radius scan.                            *
   2233  *                                                                                             *
   2234  *          x,y      -- Relative offset from the center cell to perform the check upon.        *
   2235  *                                                                                             *
   2236  * OUTPUT:  int; Amount of Tiberium at this location.                                          *
   2237  *                                                                                             *
   2238  * WARNINGS:   none                                                                            *
   2239  *                                                                                             *
   2240  * HISTORY:                                                                                    *
   2241  *   07/18/1994 JLB : Created.                                                                 *
   2242  *=============================================================================================*/
   2243 int UnitClass::Tiberium_Check(CELL & center, int x, int y)
   2244 {
   2245 	assert(Units.ID(this) == ID);
   2246 	assert(IsActive);
   2247 
   2248 	/*
   2249 	**	If the specified offset from the origin will cause it
   2250 	**	to spill past the map edge, then abort this cell check.
   2251 	*/
   2252 	if (Cell_X(center)+x < Map.MapCellX) return(0);
   2253 	if (Cell_X(center)+x >= Map.MapCellX+Map.MapCellWidth) return(0);
   2254 	if (Cell_Y(center)+y < Map.MapCellY) return(0);
   2255 	if (Cell_Y(center)+y >= Map.MapCellY+Map.MapCellHeight) return(0);
   2256 
   2257 	center = XY_Cell(Cell_X(center)+x, Cell_Y(center)+y);
   2258 
   2259 	if ((Session.Type != GAME_NORMAL || (!IsOwnedByPlayer || Map[center].Is_Mapped(PlayerPtr)))) {
   2260 		if (Map[Coord].Zones[Class->MZone] != Map[center].Zones[Class->MZone]) return(0);
   2261 		if (!Map[center].Cell_Techno() && Map[center].Land_Type() == LAND_TIBERIUM) {
   2262 			int value = 0;
   2263 			switch (Map[center].Overlay) {
   2264 				case OVERLAY_GOLD1:
   2265 				case OVERLAY_GOLD2:
   2266 				case OVERLAY_GOLD3:
   2267 				case OVERLAY_GOLD4:
   2268 					value = Rule.GoldValue;
   2269 					break;
   2270 				case OVERLAY_GEMS1:
   2271 				case OVERLAY_GEMS2:
   2272 				case OVERLAY_GEMS3:
   2273 				case OVERLAY_GEMS4:
   2274 					value = Rule.GemValue*4;
   2275 					break;
   2276 			}
   2277 			return((Map[center].OverlayData+1)*value);
   2278 		}
   2279 	}
   2280 	return(0);
   2281 }
   2282 
   2283 
   2284 /***********************************************************************************************
   2285  * UnitClass::Goto_Tiberium -- Searches for and heads toward tiberium.                         *
   2286  *                                                                                             *
   2287  *    This routine will cause the unit to search for and head toward nearby Tiberium. When     *
   2288  *    the Tiberium is reached, then this routine should not be called again until such time    *
   2289  *    as additional harvesting is required. When this routine returns false, then it should    *
   2290  *    be called again until such time as it returns true.                                      *
   2291  *                                                                                             *
   2292  * INPUT:   rad = size of ring to search                                                       *
   2293  *                                                                                             *
   2294  * OUTPUT:  Has the unit reached Tiberium and harvesting should begin?                         *
   2295  *                                                                                             *
   2296  * WARNINGS:   none                                                                            *
   2297  *                                                                                             *
   2298  * HISTORY:                                                                                    *
   2299  *   09/22/1995 JLB : Created.                                                                 *
   2300  *=============================================================================================*/
   2301 bool UnitClass::Goto_Tiberium(int rad)
   2302 {
   2303 	assert(Units.ID(this) == ID);
   2304 	assert(IsActive);
   2305 
   2306 	if (!Target_Legal(NavCom)) {
   2307 		CELL center = Coord_Cell(Center_Coord());
   2308 		if (Map[center].Land_Type() == LAND_TIBERIUM) {
   2309 			return(true);
   2310 		} else {
   2311 
   2312 			/*
   2313 			**	Perform a ring search outward from the center.
   2314 			*/
   2315 			for (int radius = 1; radius < rad; radius++) {
   2316 				CELL cell = center;
   2317 				CELL bestcell = 0;
   2318 				int tiberium = 0;
   2319 				int besttiberium = 0;
   2320 				for (int x = -radius; x <= radius; x++) {
   2321 
   2322 					/*
   2323 					**	Randomize the corners.
   2324 					*/
   2325 					int corner[2];
   2326 					int corners[4][2] = {
   2327 						{x, -radius},
   2328 						{x, +radius},
   2329 						{-radius, x},
   2330 						{+radius, x}
   2331 					};
   2332 					for (int i = 0; i < 3; i++) {
   2333 						int j = i + rand() / (RAND_MAX / (4 - i) + 1);
   2334 						memcpy(&corner, &corners[j], sizeof(corner));
   2335 						memcpy(&corners[j], &corners[i], sizeof(corner));
   2336 						memcpy(&corners[i], corner, sizeof(corner));
   2337 					}
   2338 
   2339 					cell = center;
   2340 					tiberium = Tiberium_Check(cell, corners[0][0], corners[0][1]);
   2341 					if (tiberium > besttiberium) {
   2342 						bestcell = cell;
   2343 						besttiberium = tiberium;
   2344 					}
   2345 
   2346 					cell = center;
   2347 					tiberium = Tiberium_Check(cell, corners[1][0], corners[1][1]);
   2348 					if (tiberium > besttiberium) {
   2349 						bestcell = cell;
   2350 						besttiberium = tiberium;
   2351 					}
   2352 
   2353 					cell = center;
   2354 					tiberium = Tiberium_Check(cell, corners[2][0], corners[2][1]);
   2355 					if (tiberium > besttiberium) {
   2356 						bestcell = cell;
   2357 						besttiberium = tiberium;
   2358 					}
   2359 
   2360 					cell = center;
   2361 					tiberium = Tiberium_Check(cell, corners[3][0], corners[3][1]);
   2362 					if (tiberium > besttiberium) {
   2363 						bestcell = cell;
   2364 						besttiberium = tiberium;
   2365 					}
   2366 				}
   2367 				if (bestcell) {
   2368 					Assign_Destination(::As_Target(bestcell));
   2369 					return(false);
   2370 				}
   2371 			}
   2372 		}
   2373 	}
   2374 
   2375 	return(false);
   2376 }
   2377 
   2378 
   2379 /***********************************************************************************************
   2380  * UnitClass::Harvesting -- Harvests tiberium at the current location.                         *
   2381  *                                                                                             *
   2382  *    This routine is used to by the harvester to harvest Tiberium at the current location.    *
   2383  *    When harvesting is complete, this routine will return true.                              *
   2384  *                                                                                             *
   2385  * INPUT:   none                                                                               *
   2386  *                                                                                             *
   2387  * OUTPUT:  bool; Is harvesting complete?                                                      *
   2388  *                                                                                             *
   2389  * WARNINGS:   none                                                                            *
   2390  *                                                                                             *
   2391  * HISTORY:                                                                                    *
   2392  *   07/18/1994 JLB : Created.                                                                 *
   2393  *=============================================================================================*/
   2394 bool UnitClass::Harvesting(void)
   2395 {
   2396 	assert(Units.ID(this) == ID);
   2397 	assert(IsActive);
   2398 
   2399 	CELL	cell = Coord_Cell(Coord);
   2400 	CellClass * ptr = &Map[cell];
   2401 
   2402 	/*
   2403 	**	Keep waiting if still heading toward a spot to harvest.
   2404 	*/
   2405 	if (Target_Legal(NavCom)) return(true);
   2406 
   2407 	if (Tiberium_Load() < 1 && ptr->Land_Type() == LAND_TIBERIUM) {
   2408 
   2409 		/*
   2410 		**	Lift some Tiberium from the ground. Try to lift a complete
   2411 		**	"level" of Tiberium. A level happens to be 6 steps. If there
   2412 		**	is a partial level, then lift that instead. Never lift more
   2413 		**	than the harvester can carry.
   2414 		*/
   2415 //		int reducer = (ptr->OverlayData % 6) + 1;
   2416 		int reducer = 1;
   2417 		OverlayType overlay = ptr->Overlay;
   2418 		reducer = ptr->Reduce_Tiberium(min(reducer, Rule.BailCount-Tiberium));
   2419 		Tiberium += reducer;
   2420 		switch (overlay) {
   2421 			case OVERLAY_GOLD1:
   2422 			case OVERLAY_GOLD2:
   2423 			case OVERLAY_GOLD3:
   2424 			case OVERLAY_GOLD4:
   2425 				Gold += reducer;
   2426 				break;
   2427 
   2428 			case OVERLAY_GEMS1:
   2429 			case OVERLAY_GEMS2:
   2430 			case OVERLAY_GEMS3:
   2431 			case OVERLAY_GEMS4:
   2432 				Gems += reducer;
   2433 				if (Rule.BailCount > Tiberium) {Gems++;Tiberium++;}
   2434 				if (Rule.BailCount > Tiberium) {Gems++;Tiberium++;}
   2435 				if (Rule.BailCount > Tiberium) {Gems++;Tiberium++;}
   2436 				break;
   2437 
   2438 			default:
   2439 				break;
   2440 		}
   2441 		Set_Stage(0);
   2442 		Set_Rate(Rule.OreDumpRate);
   2443 
   2444 	} else {
   2445 
   2446 		/*
   2447 		**	If the harvester is stopped on a non Tiberium field and the harvester
   2448 		**	isn't loaded with Tiberium, then no further action can be performed
   2449 		**	by this logic routine. Bail with a failure and thus cause a branch to
   2450 		**	a better suited logic processor.
   2451 		*/
   2452 		Set_Stage(0);
   2453 		Set_Rate(0);
   2454 		return(false);
   2455 	}
   2456 	return(true);
   2457 }
   2458 
   2459 
   2460 /***********************************************************************************************
   2461  * UnitClass::Mission_Unload -- Handles unloading cargo.                                       *
   2462  *                                                                                             *
   2463  *    This is the AI control sequence for when a transport desires to unload its cargo and     *
   2464  *    then exit the map.                                                                       *
   2465  *                                                                                             *
   2466  * INPUT:   none                                                                               *
   2467  *                                                                                             *
   2468  * OUTPUT:  Returns with the delay before calling this routine again.                          *
   2469  *                                                                                             *
   2470  * WARNINGS:   none                                                                            *
   2471  *                                                                                             *
   2472  * HISTORY:                                                                                    *
   2473  *   07/18/1994 JLB : Created.                                                                 *
   2474  *=============================================================================================*/
   2475 int UnitClass::Mission_Unload(void)
   2476 {
   2477 	assert(Units.ID(this) == ID);
   2478 	assert(IsActive);
   2479 
   2480 	enum {
   2481 		INITIAL_CHECK,
   2482 		MANEUVERING,
   2483 		OPENING_DOOR,
   2484 		UNLOADING,
   2485 		CLOSING_DOOR
   2486 	};
   2487 	DirType	dir;
   2488 	CELL		cell;
   2489 
   2490 	switch (Class->Type) {
   2491 		case UNIT_HARVESTER:
   2492 			if (PrimaryFacing != DIR_W) {
   2493 				if (!IsRotating) {
   2494 					Do_Turn(DIR_W);
   2495 				}
   2496 				return(5);
   2497 			}
   2498 
   2499 			if (!IsDumping) {
   2500 				IsDumping = true;
   2501 				Set_Stage(0);
   2502 				Set_Rate(Rule.OreDumpRate);
   2503 				break;
   2504 			}
   2505 			if (Fetch_Stage() < ARRAY_SIZE(Class->Harvester_Dump_List)-1) break;
   2506 
   2507 			IsDumping = false;
   2508 			if (Tiberium) {
   2509 				Tiberium = 0;
   2510 				int credits = Credit_Load();
   2511 				House->Harvested(credits);
   2512 				Tiberium = Gold = Gems = 0;
   2513 			}
   2514 			Transmit_Message(RADIO_OVER_OUT);
   2515 
   2516 			Assign_Mission(MISSION_HARVEST);
   2517 			break;
   2518 
   2519 		case UNIT_TRUCK:
   2520 			switch (Status) {
   2521 				case INITIAL_CHECK:
   2522 					dir = Desired_Load_Dir(NULL, cell);
   2523 					if (How_Many() && cell != 0) {
   2524 						Do_Turn(dir);
   2525 						Status = MANEUVERING;
   2526 						return(1);
   2527 					} else {
   2528 						Assign_Mission(MISSION_GUARD);
   2529 					}
   2530 					break;
   2531 
   2532 				case MANEUVERING:
   2533 					if (!IsRotating) {
   2534 						Status = UNLOADING;
   2535 						return(1);
   2536 					}
   2537 					break;
   2538 
   2539 				case UNLOADING:
   2540 					if (How_Many()) {
   2541 						FootClass * passenger = Detach_Object();
   2542 
   2543 						if (passenger != NULL) {
   2544 							DirType toface = DIR_S + PrimaryFacing;
   2545 							bool placed = false;
   2546 
   2547 							for (FacingType face = FACING_N; face < FACING_COUNT; face++) {
   2548 								DirType newface = toface + Facing_Dir(face);
   2549 								CELL newcell = Adjacent_Cell(Coord_Cell(Coord), newface);
   2550 
   2551 								if (passenger->Can_Enter_Cell(newcell) == MOVE_OK) {
   2552 									ScenarioInit++;
   2553 									passenger->Unlimbo(Coord_Move(Coord, newface, 0x0080), newface);
   2554 									ScenarioInit--;
   2555 									passenger->Assign_Mission(MISSION_MOVE);
   2556 									passenger->Assign_Destination(::As_Target(newcell));
   2557 									placed = true;
   2558 									break;
   2559 								}
   2560 							}
   2561 
   2562 							/*
   2563 							** If the attached unit could NOT be deployed, then re-attach
   2564 							**	it and then bail out of this deploy process.
   2565 							*/
   2566 							if (!placed) {
   2567 								Attach(passenger);
   2568 								Status = CLOSING_DOOR;
   2569 							}
   2570 							else {
   2571 								passenger->Look(false);
   2572 							}
   2573 						}
   2574 					} else {
   2575 						Status = CLOSING_DOOR;
   2576 					}
   2577 					break;
   2578 
   2579 				/*
   2580 				**	Close APC door in preparation for normal operation.
   2581 				*/
   2582 				case CLOSING_DOOR:
   2583 					Assign_Mission(MISSION_GUARD);
   2584 					break;
   2585 			}
   2586 			break;
   2587 
   2588 		case UNIT_APC:
   2589 #ifdef FIXIT_PHASETRANSPORT	//	checked - ajw 9/28/98
   2590 		case UNIT_PHASE:
   2591 #endif
   2592 			switch (Status) {
   2593 				case INITIAL_CHECK:
   2594 					dir = Desired_Load_Dir(NULL, cell);
   2595 					if (How_Many() && cell != 0) {
   2596 						Do_Turn(dir);
   2597 						Status = MANEUVERING;
   2598 						return(1);
   2599 					} else {
   2600 						Assign_Mission(MISSION_GUARD);
   2601 					}
   2602 					break;
   2603 
   2604 				case MANEUVERING:
   2605 					if (!IsRotating) {
   2606 						APC_Open_Door();
   2607 						if (Is_Door_Opening()) {
   2608 							Status = OPENING_DOOR;
   2609 							return(1);
   2610 						}
   2611 					}
   2612 					break;
   2613 
   2614 				case OPENING_DOOR:
   2615 					if (Is_Door_Open()) {
   2616 						Status = UNLOADING;
   2617 						return(1);
   2618 					} else {
   2619 						if (!Is_Door_Opening()) {
   2620 							Status = INITIAL_CHECK;
   2621 						}
   2622 					}
   2623 					break;
   2624 
   2625 				case UNLOADING:
   2626 					if (How_Many()) {
   2627 						FootClass * passenger = Detach_Object();
   2628 
   2629 						if (passenger != NULL) {
   2630 							DirType toface = DIR_S + PrimaryFacing;
   2631 							bool placed = false;
   2632 
   2633 							for (FacingType face = FACING_N; face < FACING_COUNT; face++) {
   2634 								DirType newface = toface + Facing_Dir(face);
   2635 								CELL newcell = Adjacent_Cell(Coord_Cell(Coord), newface);
   2636 
   2637 								if (passenger->Can_Enter_Cell(newcell) == MOVE_OK) {
   2638 									ScenarioInit++;
   2639 									passenger->Unlimbo(Coord_Move(Coord, newface, 0x0080), newface);
   2640 									ScenarioInit--;
   2641 									passenger->Assign_Mission(MISSION_MOVE);
   2642 									passenger->Assign_Destination(::As_Target(newcell));
   2643 									placed = true;
   2644 									break;
   2645 								}
   2646 							}
   2647 
   2648 							/*
   2649 							** If the attached unit could NOT be deployed, then re-attach
   2650 							**	it and then bail out of this deploy process.
   2651 							*/
   2652 							if (!placed) {
   2653 								Attach(passenger);
   2654 								Status = CLOSING_DOOR;
   2655 							}
   2656 							else {
   2657 								passenger->Look(false);
   2658 							}
   2659 						}
   2660 					} else {
   2661 						Status = CLOSING_DOOR;
   2662 					}
   2663 					break;
   2664 
   2665 				/*
   2666 				**	Close APC door in preparation for normal operation.
   2667 				*/
   2668 				case CLOSING_DOOR:
   2669 					if (Is_Door_Open()) {
   2670 						APC_Close_Door();
   2671 					}
   2672 					if (Is_Door_Closed()) {
   2673 						Assign_Mission(MISSION_GUARD);
   2674 					}
   2675 					break;
   2676 			}
   2677 			break;
   2678 
   2679 		case UNIT_MCV:
   2680 			switch (Status) {
   2681 				case 0:
   2682 					Path[0] = FACING_NONE;
   2683 					Status = 1;
   2684 					break;
   2685 
   2686 				case 1:
   2687 					if (!IsDriving) {
   2688 						Try_To_Deploy();
   2689 						if (IsActive) {
   2690 							if (IsDeploying) {
   2691 								Status = 2;
   2692 							} else {
   2693 								if (!House->IsHuman && Session.Type != GAME_NORMAL) {
   2694 									Assign_Mission(MISSION_HUNT);
   2695 								} else {
   2696 									Assign_Mission(MISSION_GUARD);
   2697 								}
   2698 							}
   2699 						}
   2700 					}
   2701 					break;
   2702 
   2703 				case 2:
   2704 					if (!IsDeploying) {
   2705 						Assign_Mission(MISSION_GUARD);
   2706 					}
   2707 					break;
   2708 			}
   2709 			return(1);
   2710 
   2711 		case UNIT_MINELAYER:
   2712 			switch (Status) {
   2713 				case INITIAL_CHECK:
   2714 					dir = DIR_NE;
   2715 					if (Ammo > 0) {
   2716 						Do_Turn(dir);
   2717 						Status = MANEUVERING;
   2718 						return(1);
   2719 					} else {
   2720 						Assign_Mission(MISSION_GUARD);
   2721 					}
   2722 					break;
   2723 
   2724 				case MANEUVERING:
   2725 					if (!IsRotating) {
   2726 						APC_Open_Door();
   2727 						if (Is_Door_Opening()) {
   2728 							Status = OPENING_DOOR;
   2729 							return(1);
   2730 						}
   2731 					}
   2732 					break;
   2733 
   2734 				case OPENING_DOOR:
   2735 					if (Is_Door_Open()) {
   2736 						Status = UNLOADING;
   2737 						return(1);
   2738 					} else {
   2739 						if (!Is_Door_Opening()) {
   2740 							Status = INITIAL_CHECK;
   2741 						}
   2742 					}
   2743 					break;
   2744 
   2745 				case UNLOADING:
   2746 					if (Ammo > 0) {
   2747 						if (!Map[Center_Coord()].Cell_Building()) {
   2748 							Mark(MARK_UP);
   2749 							BuildingClass * building = new BuildingClass((House->ActLike == HOUSE_USSR || House->ActLike == HOUSE_UKRAINE || House->ActLike == HOUSE_BAD) ? STRUCT_APMINE : STRUCT_AVMINE, House->Class->House);
   2750 							if (building != NULL) {
   2751 								ScenarioInit = true;
   2752 								if (building->Unlimbo(Coord)) {
   2753 									Sound_Effect(VOC_MINELAY1, Coord);
   2754 									ScenarioInit = false;
   2755 									building->Revealed(House);
   2756 									Ammo--;
   2757 								}
   2758 								ScenarioInit = false;
   2759 							}
   2760 							Status = CLOSING_DOOR;
   2761 							Mark(MARK_DOWN);
   2762 						} else {
   2763 							Status = CLOSING_DOOR;
   2764 						}
   2765 					} else {
   2766 						Status = CLOSING_DOOR;
   2767 					}
   2768 					break;
   2769 
   2770 				/*
   2771 				**	Close APC door in preparation for normal operation.
   2772 				*/
   2773 				case CLOSING_DOOR:
   2774 					if (Is_Door_Open()) {
   2775 						APC_Close_Door();
   2776 					}
   2777 					if (Is_Door_Closed()) {
   2778 						Assign_Mission(MISSION_GUARD);
   2779 					}
   2780 					break;
   2781 			}
   2782 			break;
   2783 
   2784 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   2785 		case UNIT_MAD:
   2786 			if (!Gems && !IsDumping) {
   2787 				Gems = 1;
   2788 				Gold = 0;
   2789 				Arm = QuakeDelay * House->ROFBias;
   2790 #ifdef ENGLISH
   2791 				Speak(VOX_MADTANK_DEPLOYED);	// this voice only exists in English
   2792 #else
   2793 				Sound_Effect(VOC_BUZZY1,Center_Coord());
   2794 #endif
   2795 				Set_Stage(0);
   2796 				Set_Rate(Rule.OreDumpRate*2);
   2797 				IsDumping = true;
   2798 
   2799 #if 1
   2800 				InfantryClass *crew = new InfantryClass(INFANTRY_C1, House->Class->House);
   2801 				if (crew != NULL) crew->IsTechnician = true;
   2802 
   2803 				if (crew != NULL) {
   2804 					DirType toface = DIR_S + PrimaryFacing;
   2805 
   2806 					for (FacingType face = FACING_N; face < FACING_COUNT; face++) {
   2807 						DirType newface = toface + Facing_Dir(face);
   2808 						CELL newcell = Adjacent_Cell(Coord_Cell(Coord), newface);
   2809 						if (crew->Can_Enter_Cell(newcell) == MOVE_OK) {
   2810 							ScenarioInit++;
   2811 							crew->Unlimbo(Coord_Move(Coord, newface, 0x0080), newface);
   2812 							ScenarioInit--;
   2813 							crew->Assign_Mission(MISSION_MOVE);
   2814 							crew->Assign_Destination(::As_Target(newcell));
   2815 							break;
   2816 						}
   2817 					}
   2818 				}
   2819 #endif
   2820 			}
   2821 
   2822 			if ( (Arm && !Gold) || IronCurtainCountDown) {
   2823 				Set_Stage(Fetch_Stage() & 1);
   2824 				return(1);
   2825 			}
   2826 
   2827 			if (!Gold) {
   2828 				Sound_Effect(VOC_MAD_CHARGE, Center_Coord());
   2829 				Set_Stage(0);
   2830 				Gold = 1;
   2831 				return(1);
   2832 			}
   2833 
   2834 			if (Fetch_Stage() < 7) {
   2835 				return(1);
   2836 			}
   2837 
   2838 			IsDumping = false;
   2839 
   2840 			Sound_Effect(VOC_MAD_EXPLODE, Center_Coord());
   2841 
   2842 			Strength = 1;			// assure destruction
   2843 			PendingTimeQuake = true;		// trigger a time quake
   2844 			TimeQuakeCenter = ::As_Target(Center_Coord());
   2845 			break;
   2846 
   2847 		case UNIT_CHRONOTANK:
   2848 			if (IsOwnedByPlayer) {
   2849 				Map.IsTargettingMode = SPC_CHRONO2;
   2850 				HouseClass* old_player_ptr = PlayerPtr;
   2851 				Logic_Switch_Player_Context(this);
   2852 				Unselect_All();
   2853 				On_Special_Weapon_Targetting(PlayerPtr, Map.IsTargettingMode);
   2854 				Logic_Switch_Player_Context(old_player_ptr);
   2855 			}
   2856 			House->UnitToTeleport = As_Target();
   2857 
   2858 			Assign_Mission(MISSION_GUARD);
   2859 			break;
   2860 #endif
   2861 		default:
   2862 			break;
   2863 	}
   2864 	return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
   2865 }
   2866 
   2867 
   2868 /***********************************************************************************************
   2869  * UnitClass::Mission_Harvest -- Handles the harvesting process used by harvesters.            *
   2870  *                                                                                             *
   2871  *    This is the AI process used by harvesters when they are doing their harvesting action.   *
   2872  *    This entails searching for nearby Tiberium, heading there, harvesting, and then          *
   2873  *    returning to a refinery for unloading.                                                   *
   2874  *                                                                                             *
   2875  * INPUT:   none                                                                               *
   2876  *                                                                                             *
   2877  * OUTPUT:  Returns with the delay before calling this routine again.                          *
   2878  *                                                                                             *
   2879  * WARNINGS:   none                                                                            *
   2880  *                                                                                             *
   2881  * HISTORY:                                                                                    *
   2882  *   07/18/1994 JLB : Created.                                                                 *
   2883  *   06/21/1995 JLB : Force guard mode if no Tiberium found.                                   *
   2884  *   09/28/1995 JLB : Aborts harvesting if there are no more refineries.                       *
   2885  *=============================================================================================*/
   2886 int UnitClass::Mission_Harvest(void)
   2887 {
   2888 	assert(Units.ID(this) == ID);
   2889 	assert(IsActive);
   2890 
   2891 	enum {
   2892 		LOOKING,
   2893 		HARVESTING,
   2894 		FINDHOME,
   2895 		HEADINGHOME,
   2896 		GOINGTOIDLE,
   2897 	};
   2898 
   2899 	/*
   2900 	**	A non-harvesting type unit will just sit still if it is given the harvest mission. This
   2901 	**	allows combat units to act "brain dead".
   2902 	*/
   2903 	if (!Class->IsToHarvest) return(TICKS_PER_SECOND*30);
   2904 
   2905 	/*
   2906 	**	If there are no more refineries, then drop into guard mode.
   2907 	*/
   2908 	if (!(House->ActiveBScan & STRUCTF_REFINERY)) {
   2909 		Assign_Mission(MISSION_GUARD);
   2910 		return(1);
   2911 	}
   2912 
   2913 	switch (Status) {
   2914 
   2915 		/*
   2916 		**	Go and find a Tiberium field to harvest.
   2917 		*/
   2918 		case LOOKING:
   2919 			/*
   2920 			**	Slightly hacky; if TarCom is set then skip to finding home state.
   2921 			*/
   2922 			if (Target_Legal(TarCom)) {
   2923 				Assign_Target(TARGET_NONE);
   2924 				Status = FINDHOME;
   2925 				return(1);
   2926 			}
   2927 
   2928 			/*
   2929 			** Look for ore where we last found some - mine the same patch
   2930 			*/
   2931 			if (Target_Legal(ArchiveTarget)) {
   2932 				Assign_Destination(ArchiveTarget);
   2933 				ArchiveTarget = 0;
   2934 			}
   2935 			IsHarvesting = false;
   2936 			if (Goto_Tiberium(Rule.TiberiumLongScan / CELL_LEPTON_W)) {
   2937 				IsHarvesting = true;
   2938 				Set_Rate(2);
   2939 				Set_Stage(0);
   2940 				Status = HARVESTING;
   2941 				ArchiveTarget = ::As_Target(Coord_Cell(Coord));
   2942 				return(1);
   2943 			} else {
   2944 
   2945 				/*
   2946 				**	If the harvester isn't on Tiberium and it is not heading toward Tiberium, then
   2947 				**	force it to go into guard mode. This will prevent the harvester from repeatedly
   2948 				**	searching for Tiberium.
   2949 				*/
   2950 				if (!Target_Legal(NavCom)) {
   2951 
   2952 					/*
   2953 					**	If the archive target is legal, then head there since it is presumed
   2954 					**	that the archive target points to the last place it harvested at. This might
   2955 					**	solve the case where the harvester gets stuck and can't find Tiberium just because
   2956 					**	it is greater than 32 squares away.
   2957 					*/
   2958 					if (Target_Legal(ArchiveTarget)) {
   2959 						Assign_Destination(ArchiveTarget);
   2960 					} else {
   2961 						Status = GOINGTOIDLE;
   2962 						IsUseless = true;
   2963 						House->IsTiberiumShort = true;
   2964 						return(TICKS_PER_SECOND*7);
   2965 					}
   2966 				} else {
   2967 					IsUseless = false;
   2968 				}
   2969 			}
   2970 			break;
   2971 
   2972 		/*
   2973 		**	Harvest at current location until full or Tiberium exhausted.
   2974 		*/
   2975 		case HARVESTING:
   2976 //			if (Fetch_Stage() > ARRAY_SIZE(Class->Harvester_Load_List)) {
   2977 //				Set_Stage(0);
   2978 //			}
   2979 			if (Fetch_Rate() == 0) {
   2980 				Set_Stage(0);
   2981 				Set_Rate(Rule.OreDumpRate);
   2982 			}
   2983 
   2984 			if (Fetch_Stage() < ARRAY_SIZE(Class->Harvester_Load_List)) return(1);
   2985 			if (!Harvesting()) {
   2986 				IsHarvesting = false;
   2987 				if (Tiberium_Load() == 1) {
   2988 					Status = FINDHOME;
   2989 				} else {
   2990 					if (!Goto_Tiberium(Rule.TiberiumShortScan / CELL_LEPTON_W) && !Target_Legal(NavCom))	{
   2991 					  	ArchiveTarget = TARGET_NONE;
   2992 						Status = FINDHOME;
   2993 					} else {
   2994 						Status = HARVESTING;
   2995 						IsHarvesting = true;
   2996 					}
   2997 				}
   2998 				return(1);
   2999 			} else if (!Target_Legal(NavCom) && ArchiveTarget == TARGET_NONE) {
   3000 				ArchiveTarget = ::As_Target(Coord_Cell(Coord));
   3001 			}
   3002 			return(1);
   3003 //			return(TICKS_PER_SECOND*Rule.OreDumpRate);
   3004 
   3005 		/*
   3006 		**	Find and head to refinery.
   3007 		*/
   3008 		case FINDHOME:
   3009 			if (!Target_Legal(NavCom)) {
   3010 
   3011 				/*
   3012 				**	Find best refinery.
   3013 				*/
   3014 				BuildingClass * nearest = Find_Best_Refinery();
   3015 
   3016 				/*
   3017 				**	Since the refinery said it was ok to load, establish radio
   3018 				**	contact with the refinery and then await docking orders.
   3019 				*/
   3020 				if (nearest != NULL && Transmit_Message(RADIO_HELLO, nearest) == RADIO_ROGER) {
   3021 					Status = HEADINGHOME;
   3022 					if (nearest->House == PlayerPtr && (PlayerPtr->Capacity - PlayerPtr->Tiberium) < 300 && PlayerPtr->Capacity > 500 && (PlayerPtr->ActiveBScan & (STRUCTF_REFINERY | STRUCTF_CONST))) {
   3023 						Speak(VOX_NEED_MO_CAPACITY);
   3024 					}
   3025 				} else {
   3026 					ScenarioInit++;
   3027 					nearest = Find_Best_Refinery();
   3028 					ScenarioInit--;
   3029 					if (nearest != NULL) {
   3030 						Assign_Destination(::As_Target(Nearby_Location(nearest)));
   3031 					}
   3032 				}
   3033 			}
   3034 			break;
   3035 
   3036 		/*
   3037 		**	In communication with refinery so that it will successfully dock and
   3038 		**	unload. If, for some reason, radio contact was lost, then hunt for
   3039 		**	another refinery to unload at.
   3040 		*/
   3041 		case HEADINGHOME:
   3042 			Assign_Mission(MISSION_ENTER);
   3043 			return(1);
   3044 
   3045 		/*
   3046 		**	The harvester has nothing to do. There is no Tiberium nearby and
   3047 		**	no where to go.
   3048 		*/
   3049 		case GOINGTOIDLE:
   3050 			if (IsUseless) {
   3051 				if (House->ActiveBScan & STRUCTF_REPAIR) {
   3052 					Assign_Mission(MISSION_REPAIR);
   3053 				} else {
   3054 					Assign_Mission(MISSION_HUNT);
   3055 				}
   3056 			}
   3057 			Assign_Mission(MISSION_GUARD);
   3058 			break;
   3059 
   3060 	}
   3061 	return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
   3062 }
   3063 
   3064 
   3065 /***********************************************************************************************
   3066  * UnitClass::Mission_Hunt -- This is the AI process for aggressive enemy units.               *
   3067  *                                                                                             *
   3068  *    Computer controlled units must be intelligent enough to find enemies as well as to       *
   3069  *    attack them. This AI process will handle both the simple attack process as well as the   *
   3070  *    scanning for enemy units to attack.                                                      *
   3071  *                                                                                             *
   3072  * INPUT:   none                                                                               *
   3073  *                                                                                             *
   3074  * OUTPUT:  Returns with the delay before calling this routine again.                          *
   3075  *                                                                                             *
   3076  * WARNINGS:   none                                                                            *
   3077  *                                                                                             *
   3078  * HISTORY:                                                                                    *
   3079  *   07/18/1994 JLB : Created.                                                                 *
   3080  *=============================================================================================*/
   3081 int UnitClass::Mission_Hunt(void)
   3082 {
   3083 	assert(Units.ID(this) == ID);
   3084 	assert(IsActive);
   3085 
   3086 	if (*this == UNIT_MCV) {
   3087 		enum {
   3088 			FIND_SPOT,
   3089 			WAITING
   3090 		};
   3091 
   3092 		switch (Status) {
   3093 
   3094 			/*
   3095 			**	This stage handles locating a convenient spot, rotating to face the correct
   3096 			**	direction and then commencing the deployment operation.
   3097 			*/
   3098 			case FIND_SPOT:
   3099 				if (Goto_Clear_Spot()) {
   3100 					if (Try_To_Deploy()) {
   3101 						Status = WAITING;
   3102 					}
   3103 				}
   3104 				break;
   3105 
   3106 			/*
   3107 			**	This stage watchdogs the deployment operation and if for some reason, the deployment
   3108 			**	is aborted (the IsDeploying flag becomes false), then it reverts back to hunting for
   3109 			**	a convenient spot to deploy.
   3110 			*/
   3111 			case WAITING:
   3112 				if (!IsDeploying) {
   3113 					Status = FIND_SPOT;
   3114 				}
   3115 				break;
   3116 		}
   3117 	} else {
   3118 
   3119 		return(DriveClass::Mission_Hunt());
   3120 	}
   3121 	return(MissionControl[Mission].Normal_Delay()+Random_Pick(0, 2));
   3122 }
   3123 
   3124 
   3125 /***********************************************************************************************
   3126  * UnitClass::Overlap_List -- Determines overlap list for units.                               *
   3127  *                                                                                             *
   3128  *    The unit overlap list is used to keep track of which cells are to                        *
   3129  *    be marked for redraw. This is critical in order to keep the units                        *
   3130  *    displayed correctly.                                                                     *
   3131  *                                                                                             *
   3132  * INPUT:   none                                                                               *
   3133  *                                                                                             *
   3134  * OUTPUT:  Returns with the overlap list pointer for the unit at its                          *
   3135  *          present position.                                                                  *
   3136  *                                                                                             *
   3137  * WARNINGS:   none                                                                            *
   3138  *                                                                                             *
   3139  * HISTORY:                                                                                    *
   3140  *   05/26/1994 JLB : Created.                                                                 *
   3141  *   06/19/1994 JLB : Uses Coord_Spillable_List function.                                      *
   3142  *=============================================================================================*/
   3143 short const * UnitClass::Overlap_List(bool redraw) const
   3144 {
   3145 	assert(Units.ID(this) == ID);
   3146 	assert(IsActive);
   3147 
   3148 #ifdef PARTIAL
   3149 	if (Height == 0 && redraw && Class->DimensionData != NULL) {
   3150 		Rect rect;
   3151 		int shapenum = Shape_Number();
   3152 		if (Class->DimensionData[shapenum].Is_Valid()) {
   3153 			rect = Class->DimensionData[shapenum];
   3154 		} else {
   3155 			rect = Class->DimensionData[shapenum] = Shape_Dimensions(Get_Image_Data(), shapenum);
   3156 		}
   3157 
   3158 		if (Is_Selected_By_Player()) {
   3159 			rect = Union(rect, Rect(-15, -15, 30, 30));
   3160 		}
   3161 
   3162 		if (Class->IsTurretEquipped || Class->IsRadarEquipped) {
   3163 			rect = Union(rect, Rect(-15, -15, 30, 30));
   3164 		}
   3165 
   3166 		return(Coord_Spillage_List(Coord, rect, true));
   3167 	}
   3168 #else
   3169 	redraw = redraw;
   3170 #endif
   3171 
   3172 	int size = ICON_PIXEL_W;
   3173 
   3174 	if (redraw && (Is_Selected_By_Player() || IsFiring)) {
   3175 		size += 24;
   3176 	}
   3177 	if (Class->IsGigundo || IsAnimAttached) {
   3178 		size = ICON_PIXEL_W*2;
   3179 	}
   3180 
   3181 	return(Coord_Spillage_List(Coord, size)+1);
   3182 }
   3183 
   3184 
   3185 /***********************************************************************************************
   3186  * UnitClass::Can_Enter_Cell -- Determines cell entry legality.                                *
   3187  *                                                                                             *
   3188  *    Use this routine to determine if the unit can enter the cell                             *
   3189  *    specified and given the direction of entry specified. Typically,                         *
   3190  *    this is used when determining unit travel path.                                          *
   3191  *                                                                                             *
   3192  * INPUT:   cell     -- The cell to examine.                                                   *
   3193  *                                                                                             *
   3194  *          facing   -- The facing that the unit would enter the specified                     *
   3195  *                      cell. If this value is -1, then don't consider                         *
   3196  *                      facing when performing the check.                                      *
   3197  *                                                                                             *
   3198  * OUTPUT:  Returns the reason why it couldn't enter the cell or MOVE_OK if movement is        *
   3199  *          allowed.                                                                           *
   3200  *                                                                                             *
   3201  * WARNINGS:   none                                                                            *
   3202  *                                                                                             *
   3203  * HISTORY:                                                                                    *
   3204  *   09/07/1992 JLB : Created.                                                                 *
   3205  *   04/16/1994 JLB : Converted to member function.                                            *
   3206  *   07/04/1995 JLB : Allowed to drive on building trying to enter it.                         *
   3207  *=============================================================================================*/
   3208 MoveType UnitClass::Can_Enter_Cell(CELL cell, FacingType ) const
   3209 {
   3210 	assert(Units.ID(this) == ID);
   3211 	assert(IsActive);
   3212 
   3213 	bool cancrush = false;
   3214 
   3215 	CellClass const * cellptr = &Map[cell];
   3216 
   3217 	if ((unsigned)cell >= MAP_CELL_TOTAL) return(MOVE_NO);
   3218 
   3219 	/*
   3220 	**	Moving off the edge of the map is not allowed unless
   3221 	**	this is a loaner vehicle.
   3222 	*/
   3223 	if (!ScenarioInit && !Map.In_Radar(cell) && !Is_Allowed_To_Leave_Map() && IsLocked) {
   3224 		return(MOVE_NO);
   3225 	}
   3226 
   3227 	MoveType retval = MOVE_OK;
   3228 
   3229 	/*
   3230 	**	Certain vehicles can drive over walls. Check for this case and
   3231 	**	and return the appropriate flag. Other units treat walls as impassable.
   3232 	*/
   3233 	if (cellptr->Overlay != OVERLAY_NONE) {
   3234 		OverlayTypeClass const * optr = &OverlayTypeClass::As_Reference(cellptr->Overlay);
   3235 
   3236 		if (optr->IsCrate && !((Session.Type == GAME_NORMAL) ? House->IsPlayerControl : House->IsHuman) && Session.Type == GAME_NORMAL) {
   3237 			return(MOVE_NO);
   3238 		}
   3239 
   3240 		if (optr->IsWall) {
   3241 
   3242 			/*
   3243 			**	If the blocking wall is crushable (and not owned by this player or one of this players
   3244 			**	allies, then record that it is crushable and let the normal logic take over. The end
   3245 			**	result should cause this unit to consider the cell passable.
   3246 			*/
   3247 			if (optr->IsCrushable && Class->IsCrusher) {
   3248 				cancrush = !House->Is_Ally(cellptr->Owner);
   3249 			}
   3250 
   3251 			if (!cancrush && Is_Weapon_Equipped()) {
   3252 				WarheadTypeClass const * whead = Class->PrimaryWeapon->WarheadPtr;
   3253 
   3254 				if (whead->IsWallDestroyer || (whead->IsWoodDestroyer && optr->IsWooden)) {
   3255 //					if (!House->IsHuman && !House->Is_Ally(cellptr->Owner)) {
   3256 						if (retval < MOVE_DESTROYABLE) retval = MOVE_DESTROYABLE;
   3257 //					} else {
   3258 //						return(MOVE_NO);
   3259 //					}
   3260 				} else {
   3261 					return(MOVE_NO);
   3262 				}
   3263 			}
   3264 		}
   3265 	}
   3266 
   3267 	/*
   3268 	** Loop through all of the objects in the square setting a bit
   3269 	** for how they affect movement.
   3270 	*/
   3271 	bool crushable = false;
   3272 	ObjectClass * obj = cellptr->Cell_Occupier();
   3273 	while (obj != NULL) {
   3274 
   3275 		if (obj != this) {
   3276 
   3277 			/*
   3278 			** If object is a land mine, allow movement if possible.
   3279 			*/
   3280 			if (obj->What_Am_I() == RTTI_BUILDING && (!Rule.IsMineAware || !((BuildingClass *)obj)->House->Is_Ally(House))) {
   3281 				if ((*(BuildingClass *)obj) == STRUCT_APMINE) return(MOVE_OK);
   3282 				if ((*(BuildingClass *)obj) == STRUCT_AVMINE) return(MOVE_OK);
   3283 			}
   3284 
   3285 			/*
   3286 			**	Always allow entry if trying to move on a cell with
   3287 			**	authorization from the occupier.
   3288 			*/
   3289 			if (obj == Contact_With_Whom() && (IsTethered || (obj->What_Am_I() ==  RTTI_BUILDING && *((BuildingClass *)obj) == STRUCT_REPAIR))) {
   3290 				return(MOVE_OK);
   3291 			}
   3292 
   3293 			/*
   3294 			**	Special check to allow entry into the sea transport this vehicle
   3295 			**	is trying to enter.
   3296 			*/
   3297 			if (Mission == MISSION_ENTER && obj->As_Target() == NavCom && IsTethered) {
   3298 				return(MOVE_OK);
   3299 			}
   3300 
   3301 			/*
   3302 			**	Guard area should not allow the guarding unit to enter the cell with the
   3303 			**	guarded unit.
   3304 			*/
   3305 			if (Mission == MISSION_GUARD_AREA && ArchiveTarget == obj->As_Target()) {
   3306 				return(MOVE_NO);
   3307 			}
   3308 
   3309 			bool is_moving = obj->Is_Foot() &&
   3310 						(Target_Legal(((FootClass *)obj)->NavCom) || ((FootClass *)obj)->PrimaryFacing.Is_Rotating() || ((FootClass *)obj)->IsDriving);
   3311 //						(((FootClass *)obj)->PrimaryFacing.Is_Rotating() || ((FootClass *)obj)->IsDriving);
   3312 //						(((FootClass *)obj)->IsRotating || ((FootClass *)obj)->IsDriving);
   3313 //						(Target_Legal(((FootClass *)obj)->NavCom) || ((FootClass *)obj)->IsDriving);
   3314 
   3315 			if (House->Is_Ally(obj)) {
   3316 				if (is_moving) {
   3317 					int face 		= Dir_Facing(PrimaryFacing);
   3318 					int techface	= Dir_Facing(((FootClass const *)obj)->PrimaryFacing) ^4;
   3319 					if (face == techface && Distance((AbstractClass const *)obj) <= 0x1FF) {
   3320 						return(MOVE_NO);
   3321 					}
   3322 					if (retval < MOVE_MOVING_BLOCK) retval = MOVE_MOVING_BLOCK;
   3323 				} else {
   3324 					if (obj->What_Am_I() == RTTI_BUILDING) return(MOVE_NO);
   3325 
   3326 					/*
   3327 					**	If the blocking object is not in the same zone, then it certainly
   3328 					**	isn't a temporary block, it is a permanent one.
   3329 					*/
   3330 					if (Map[Coord].Zones[Class->MZone] != cellptr->Zones[Class->MZone]) return(MOVE_NO);
   3331 
   3332 					if (retval < MOVE_TEMP) retval = MOVE_TEMP;
   3333 				}
   3334 			} else {
   3335 
   3336 				/*
   3337 				**	Cloaked enemy objects are not considered if this is a Find_Path()
   3338 				**	call.
   3339 				*/
   3340 				if (!obj->Is_Techno() || !((TechnoClass *)obj)->Is_Cloaked(this)) {
   3341 
   3342 					/*
   3343 					**	If this unit can crush infantry, and there is an enemy infantry in the
   3344 					**	cell, don't consider the cell impassible. This is true even if the unit
   3345 					**	doesn't contain a legitimate weapon.
   3346 					*/
   3347 					bool crusher = Class->IsCrusher;
   3348 					if (!crusher || !obj->Class_Of().IsCrushable) {
   3349 
   3350 						/*
   3351 						**	Any non-allied blockage is considered impassable if the unit
   3352 						**	is not equipped with a weapon.
   3353 						*/
   3354 						if (Class->PrimaryWeapon == NULL) return(MOVE_NO);
   3355 
   3356 						/*
   3357 						**	Some kinds of terrain are considered destroyable if the unit is equipped
   3358 						**	with the weapon that can destroy it. Otherwise, the terrain is considered
   3359 						**	impassable.
   3360 						*/
   3361 						switch (obj->What_Am_I()) {
   3362 							case RTTI_TERRAIN:
   3363 
   3364 #ifdef TOFIX
   3365 								if (((TerrainClass *)obj)->Class->Armor == ARMOR_WOOD &&
   3366 										Class->PrimaryWeapon->WarheadPtr->IsWoodDestroyer) {
   3367 
   3368 									if (retval < MOVE_DESTROYABLE) retval = MOVE_DESTROYABLE;
   3369 								} else {
   3370 									return(MOVE_NO);
   3371 								}
   3372 								break;
   3373 #else
   3374 								return(MOVE_NO);
   3375 #endif
   3376 
   3377 							default:
   3378 								if (retval < MOVE_DESTROYABLE) retval = MOVE_DESTROYABLE;
   3379 								break;
   3380 						}
   3381 					} else {
   3382 						crushable = true;
   3383 					}
   3384 				} else {
   3385 					if (retval < MOVE_CLOAK) retval = MOVE_CLOAK;
   3386 				}
   3387 			}
   3388 		}
   3389 
   3390 		/*
   3391 		**	Move to next object in chain.
   3392 		*/
   3393 		obj = obj->Next;
   3394 	}
   3395 
   3396 	/*
   3397 	**	If the cell is out and out impassable because of underlying terrain, then
   3398 	**	return this immutable fact.
   3399 	*/
   3400 	if (!cancrush && retval != MOVE_DESTROYABLE && Ground[cellptr->Land_Type()].Cost[Class->Speed] == 0) {
   3401 		return(MOVE_NO);
   3402 	}
   3403 
   3404 	/*
   3405 	**	If some allied object has reserved the cell, then consider the cell
   3406 	**	as blocked by a moving object.
   3407 	*/
   3408 	if (retval == MOVE_OK && !crushable && (cellptr->Flag.Composite & 0x3F) != 0) {
   3409 
   3410 		/*
   3411 		**	If reserved by a vehicle, then consider this blocked terrain.
   3412 		*/
   3413 		if (cellptr->Flag.Occupy.Vehicle) {
   3414 			retval = MOVE_MOVING_BLOCK;
   3415 		} else {
   3416 			if (cellptr->InfType != HOUSE_NONE && House->Is_Ally(cellptr->InfType)) {
   3417 				retval = MOVE_MOVING_BLOCK;
   3418 			} else {
   3419 
   3420 				/*
   3421 				**	Enemy infantry have reserved the cell. If this unit can crush
   3422 				**	infantry, consider the cell passable. If not, then consider the
   3423 				**	cell destroyable if it has a weapon. If neither case applies, then
   3424 				**	this vehicle should avoid the cell altogether.
   3425 				*/
   3426 				if (!Class->IsCrusher) {
   3427 					if (Class->PrimaryWeapon != NULL && Class->PrimaryWeapon->Bullet->IsAntiGround) {
   3428 						retval = MOVE_DESTROYABLE;
   3429 					} else {
   3430 						return(MOVE_NO);
   3431 					}
   3432 				}
   3433 			}
   3434 		}
   3435 	}
   3436 
   3437 	/*
   3438 	** If its ok to move into the cell because we can crush whats in the cell, then
   3439 	** make sure no one else is already moving into the cell to crush something.
   3440 	*/
   3441 	if (retval == MOVE_OK && crushable && cellptr->Flag.Occupy.Vehicle) {
   3442 
   3443 		/*
   3444 		**	However, if the cell is occupied by a crushable vehicle, then we can
   3445 		**	never be sure if some other friendly vehicle is also trying to crush
   3446 		**	the cell at the same time. In the case of a crushable vehicle in the
   3447 		**	cell, then allow entry.
   3448 		*/
   3449 		if (!cellptr->Cell_Unit() || !cellptr->Cell_Unit()->Class->IsCrushable) {
   3450 			return(MOVE_MOVING_BLOCK);
   3451 		}
   3452 	}
   3453 
   3454 	/*
   3455 	**	Return with the most severe reason why this cell would be impassable.
   3456 	*/
   3457 	return(retval);
   3458 }
   3459 
   3460 
   3461 /***********************************************************************************************
   3462  * UnitClass::Init -- Clears all units for scenario preparation.                               *
   3463  *                                                                                             *
   3464  *    This routine will zero out the unit list and unit objects. This routine is typically     *
   3465  *    used in preparation for a new scenario load. All units are guaranteed to be eliminated   *
   3466  *    by this routine.                                                                         *
   3467  *                                                                                             *
   3468  * INPUT:   none                                                                               *
   3469  *                                                                                             *
   3470  * OUTPUT:  none                                                                               *
   3471  *                                                                                             *
   3472  * WARNINGS:   none                                                                            *
   3473  *                                                                                             *
   3474  * HISTORY:                                                                                    *
   3475  *   08/15/1994 JLB : Created.                                                                 *
   3476  *=============================================================================================*/
   3477 void UnitClass::Init(void)
   3478 {
   3479 	Units.Free_All();
   3480 }
   3481 
   3482 
   3483 /***********************************************************************************************
   3484  * UnitClass::Start_Driver -- Starts driving and reserves destination cell.                    *
   3485  *                                                                                             *
   3486  *    This routine will start the vehicle moving by marking the destination cell as            *
   3487  *    reserved. Cells must be reserved in this fashion or else they might become occupied as   *
   3488  *    the vehicle is proceeding toward it.                                                     *
   3489  *                                                                                             *
   3490  * INPUT:   headto   -- The location where the vehicle will be heading.                        *
   3491  *                                                                                             *
   3492  * OUTPUT:  bool; Was the vehicle started to move? Failure could be the result of the cell     *
   3493  *                being occupied.                                                              *
   3494  *                                                                                             *
   3495  * WARNINGS:   none                                                                            *
   3496  *                                                                                             *
   3497  * HISTORY:                                                                                    *
   3498  *   12/22/1994 JLB : Created.                                                                 *
   3499  *=============================================================================================*/
   3500 bool UnitClass::Start_Driver(COORDINATE & headto)
   3501 {
   3502 	assert(Units.ID(this) == ID);
   3503 	assert(IsActive);
   3504 
   3505 	if (DriveClass::Start_Driver(headto) && IsActive) {//BG IsActive can be cleared by Start_Driver
   3506 		Mark_Track(headto, MARK_DOWN);
   3507 		return(true);
   3508 	}
   3509 	return(false);
   3510 }
   3511 
   3512 
   3513 /***********************************************************************************************
   3514  * UnitClass::What_Action -- Determines what action would occur if clicked on object.          *
   3515  *                                                                                             *
   3516  *    Use this function to determine what action would likely occur if the specified object    *
   3517  *    were clicked on while this unit was selected as current. This function controls, not     *
   3518  *    only the action to perform, but indirectly controls the cursor shape to use as well.     *
   3519  *                                                                                             *
   3520  * INPUT:   object   -- The object that to check for against "this" object.                    *
   3521  *                                                                                             *
   3522  * OUTPUT:  Returns with the default action to perform. If no clear action can be determined,  *
   3523  *          then ACTION_NONE is returned.                                                      *
   3524  *                                                                                             *
   3525  * WARNINGS:   none                                                                            *
   3526  *                                                                                             *
   3527  * HISTORY:                                                                                    *
   3528  *   01/11/1995 JLB : Created.                                                                 *
   3529  *=============================================================================================*/
   3530 ActionType UnitClass::What_Action(ObjectClass const * object) const
   3531 {
   3532 	assert(Units.ID(this) == ID);
   3533 	assert(IsActive);
   3534 
   3535 	ActionType action = DriveClass::What_Action(object);
   3536 
   3537 	/*
   3538 	** Allow units to move onto land mines.
   3539 	*/
   3540 	if (action == ACTION_NONE && object->What_Am_I() == RTTI_BUILDING) {
   3541 		StructType blah = *((BuildingClass *)object);
   3542 		if (blah == STRUCT_AVMINE || blah == STRUCT_APMINE) return(ACTION_MOVE);
   3543 	}
   3544 
   3545 	/*
   3546 	**	If the unit doesn't have a weapon, but can crush the object, then consider
   3547 	**	the object as a movable location.
   3548 	*/
   3549 	if (action == ACTION_ATTACK && !Can_Player_Fire()) {
   3550 		if (Class->IsCrusher && object->Class_Of().IsCrushable) {
   3551 			action = ACTION_MOVE;
   3552 		} else {
   3553 			action = ACTION_SELECT;
   3554 		}
   3555 	}
   3556 
   3557 	/*
   3558 	**	Don't allow special deploy action unless there is something to deploy.
   3559 	*/
   3560 	if (action == ACTION_SELF) {
   3561 		if (*this == UNIT_MCV) {
   3562 
   3563 			/*
   3564 			**	The MCV will get the no-deploy cursor if it couldn't
   3565 			**	deploy at its current location.
   3566 			*/
   3567 			((ObjectClass &)(*this)).Mark(MARK_UP);
   3568 			if (!BuildingTypeClass::As_Reference(STRUCT_CONST).Legal_Placement(Coord_Cell(Adjacent_Cell(Center_Coord(), FACING_NW)))) {
   3569 				action = ACTION_NO_DEPLOY;
   3570 			}
   3571 			((ObjectClass &)(*this)).Mark(MARK_DOWN);
   3572 
   3573 		} else {
   3574 
   3575 			/*
   3576 			**	The mine layer can "deploy" its mines if it currently isn't
   3577 			**	sitting on top of a mine and it still has mines available.
   3578 			*/
   3579 			if (*this == UNIT_MINELAYER) {
   3580 				if (!Ammo || Map[Center_Coord()].Cell_Building() || (Map[Center_Coord()].Smudge != SMUDGE_NONE && SmudgeTypeClass::As_Reference(Map[Center_Coord()].Smudge).IsBib)) {
   3581 					action = ACTION_NO_DEPLOY;
   3582 				}
   3583 			} else {
   3584 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   3585 				if (*this == UNIT_CHRONOTANK || *this == UNIT_MAD) {
   3586 					if (*this == UNIT_CHRONOTANK) {
   3587 // If the chrono tank's counter is still charging up, don't allow deploy.  Or,
   3588 // if it's a player-controlled chrono tank, and the player's currently trying
   3589 // to teleport a different unit, don't allow teleporting this unit.
   3590 						if(MoebiusCountDown || (IsOwnedByPlayer && House->UnitToTeleport && Map.IsTargettingMode == SPC_CHRONO2)) {
   3591 							action = ACTION_NO_DEPLOY;
   3592 						}
   3593 					}
   3594 				} else {
   3595 #endif
   3596 				/*
   3597 				**	All other units can "deploy" their passengers if they in-fact have
   3598 				**	passengers and are a transport vehicle. Otherwise, they cannot
   3599 				**	perform any self action.
   3600 				*/
   3601 				if (Class->Max_Passengers() > 0) {
   3602 					if (How_Many() == 0) {
   3603 						action = ACTION_NO_DEPLOY;
   3604 					}
   3605 				} else {
   3606 					action = ACTION_NONE;
   3607 				}
   3608 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   3609 				}
   3610 #endif
   3611 			}
   3612 		}
   3613 	}
   3614 
   3615 	/*
   3616 	**	Special return to friendly refinery action.
   3617 	*/
   3618 	bool is_player_controlled = (Session.Type == GAME_NORMAL)
   3619 		? (House->IsPlayerControl && object->Owner() != HOUSE_NONE && HouseClass::As_Pointer(object->Owner())->IsPlayerControl)
   3620 		: (Is_Owned_By_Player() && House->Class->House == object->Owner());
   3621 	if (is_player_controlled && object->What_Am_I() == RTTI_BUILDING && ((UnitClass *)this)->Transmit_Message(RADIO_CAN_LOAD, (TechnoClass*)object) == RADIO_ROGER) {
   3622 		action = ACTION_ENTER;
   3623 	}
   3624 
   3625 	/*
   3626 	**	Special return to friendly repair factory action.
   3627 	*/
   3628 	if (is_player_controlled && action == ACTION_SELECT && object->What_Am_I() == RTTI_BUILDING) {
   3629 		BuildingClass * building = (BuildingClass *)object;
   3630 		if (building->Class->Type == STRUCT_REPAIR && ((UnitClass *)this)->Transmit_Message(RADIO_CAN_LOAD, building) == RADIO_ROGER && !building->In_Radio_Contact() && !building->Is_Something_Attached()) {
   3631 			action = ACTION_MOVE;
   3632 		}
   3633 	}
   3634 
   3635 	/*
   3636 	**	Check to see if it can enter a transporter.
   3637 	*/
   3638 	if (
   3639 		House->Is_Ally(object) &&
   3640 		House->IsPlayerControl && object->Is_Techno() && object->What_Am_I() == RTTI_VESSEL) {
   3641 #ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
   3642  if( *(VesselClass *)object != VESSEL_CARRIER) {
   3643 #endif
   3644 		switch (((UnitClass *)this)->Transmit_Message(RADIO_CAN_LOAD, (TechnoClass*)object)) {
   3645 			case RADIO_ROGER:
   3646 				action = ACTION_ENTER;
   3647 				break;
   3648 
   3649 			case RADIO_NEGATIVE:
   3650 				action = ACTION_NO_ENTER;
   3651 				break;
   3652 
   3653 			default:
   3654 				action = ACTION_NONE;
   3655 				break;
   3656 		}
   3657 #ifdef FIXIT_CARRIER	//	checked - ajw 9/28/98
   3658  }
   3659 #endif
   3660 	}
   3661 
   3662 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   3663 	if (*this == UNIT_MAD && (IsDumping || Gold)) {
   3664 		action = ACTION_NONE;
   3665 	}
   3666 #endif
   3667 	/*
   3668 	**	If it doesn't know what to do with the object, then just
   3669 	**	say it can't move there.
   3670 	*/
   3671 	if (action == ACTION_NONE) action = ACTION_NOMOVE;
   3672 
   3673 	return(action);
   3674 }
   3675 
   3676 
   3677 /***********************************************************************************************
   3678  * UnitClass::What_Action -- Determines action to perform on specified cell.                   *
   3679  *                                                                                             *
   3680  *    This routine will determine what action to perform if the mouse were clicked over the    *
   3681  *    cell specified. At the unit level, only the harvester is checked for. The lower          *
   3682  *    classes determine the regular action response.                                           *
   3683  *                                                                                             *
   3684  * INPUT:   cell  -- The cell that the mouse might be clicked on.                              *
   3685  *                                                                                             *
   3686  * OUTPUT:  Returns with the action type that this unit will perform if the mouse were         *
   3687  *          clicked of the cell specified.                                                     *
   3688  *                                                                                             *
   3689  * WARNINGS:   none                                                                            *
   3690  *                                                                                             *
   3691  * HISTORY:                                                                                    *
   3692  *   09/21/1995 JLB : Created.                                                                 *
   3693  *=============================================================================================*/
   3694 ActionType UnitClass::What_Action(CELL cell) const
   3695 {
   3696 	assert(Units.ID(this) == ID);
   3697 	assert(IsActive);
   3698 
   3699 	ActionType action = DriveClass::What_Action(cell);
   3700 	if (action == ACTION_MOVE && Map[cell].Land_Type() == LAND_TIBERIUM && Class->IsToHarvest) {
   3701 		return(ACTION_HARVEST);
   3702 	}
   3703 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   3704 	if (*this == UNIT_MAD && (IsDumping || Gold)) {
   3705 		action = ACTION_NOMOVE;
   3706 	}
   3707 #endif
   3708 	return(action);
   3709 }
   3710 
   3711 
   3712 /***********************************************************************************************
   3713  * UnitClass::Exit_Repair -- Drive the unit off the repair facility.                           *
   3714  *                                                                                             *
   3715  * INPUT:   none                                                                               *
   3716  *                                                                                             *
   3717  * OUTPUT:  none                                                                               *
   3718  *                                                                                             *
   3719  * WARNINGS:   none                                                                            *
   3720  *                                                                                             *
   3721  * HISTORY:                                                                                    *
   3722  *   04/03/1995 BWG : Created.                                                                 *
   3723  *=============================================================================================*/
   3724 #define XYCELL(x, y)	(y*MAP_CELL_W+x)
   3725 void UnitClass::Exit_Repair(void)
   3726 {
   3727 	assert(Units.ID(this) == ID);
   3728 	assert(IsActive);
   3729 
   3730 	int	i;
   3731 	CELL	cell;
   3732 	bool	found = false;
   3733 	static short const ExitRepair[] = {
   3734 		XYCELL(0,	-2),
   3735 		XYCELL(1,	-1),
   3736 		XYCELL(2,	0),
   3737 		XYCELL(1,	1),
   3738 		XYCELL(0,	2),
   3739 		XYCELL(-1,	1),
   3740 		XYCELL(-2,	0),
   3741 		XYCELL(-1,	-1)
   3742 	};
   3743 
   3744 	cell = Coord_Cell(Coord) + ExitRepair[Dir_Facing(PrimaryFacing.Current())];
   3745 	if (Can_Enter_Cell(cell) == MOVE_OK) found = true;
   3746 
   3747 	if (!found) for (i=0; i<8; i++) {
   3748 		cell = Coord_Cell(Coord) + ExitRepair[i];
   3749 		if (Can_Enter_Cell(cell) == MOVE_OK) {
   3750 			found = true;
   3751 			break;
   3752 		}
   3753 	}
   3754 	if (found) {
   3755 //		DirType	dir = Direction(cell);
   3756 
   3757 		Assign_Mission(MISSION_MOVE);
   3758 		Assign_Destination(::As_Target(cell));
   3759 	}
   3760 }
   3761 
   3762 
   3763 /***********************************************************************************************
   3764  * UnitClass::Mission_Guard -- Special guard mission override processor.                       *
   3765  *                                                                                             *
   3766  *    Handles the guard mission for the unit. If the IQ is high enough and the unit is         *
   3767  *    a harvester, it will begin to harvest automatically. An MCV might autodeploy.            *
   3768  *                                                                                             *
   3769  * INPUT:   none                                                                               *
   3770  *                                                                                             *
   3771  * OUTPUT:  Returns the time delay before this command is executed again.                      *
   3772  *                                                                                             *
   3773  * WARNINGS:   none                                                                            *
   3774  *                                                                                             *
   3775  * HISTORY:                                                                                    *
   3776  *   05/08/1995 JLB : Created.                                                                 *
   3777  *   05/08/1995 JLB : Fixes gunboat problems.                                                  *
   3778  *=============================================================================================*/
   3779 int UnitClass::Mission_Guard(void)
   3780 {
   3781 	assert(Units.ID(this) == ID);
   3782 	assert(IsActive);
   3783 	if (/*House->IsBaseBuilding &&*/ !House->IsHuman && Class->IsToHarvest && House->Get_Quantity(STRUCT_REFINERY) > 0 && !House->IsTiberiumShort) {
   3784 		Assign_Mission(MISSION_HARVEST);
   3785 		return(1);
   3786 //		return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
   3787 	}
   3788 
   3789 	if (*this == UNIT_MCV && House->IsBaseBuilding) {
   3790 		Assign_Mission(MISSION_UNLOAD);
   3791 		return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
   3792 	}
   3793 	return(DriveClass::Mission_Guard());
   3794 }
   3795 
   3796 
   3797 /***********************************************************************************************
   3798  * UnitClass::Mission_Move -- Handles special move mission overrides.                          *
   3799  *                                                                                             *
   3800  *    This routine intercepts the normal move mission and if a gunboat is being processed,     *
   3801  *    changes its mission to hunt. This is an attempt to keep the gunboat on the hunt mission  *
   3802  *    regardless of what the player did.                                                       *
   3803  *                                                                                             *
   3804  * INPUT:   none                                                                               *
   3805  *                                                                                             *
   3806  * OUTPUT:  Returns the number of ticks before this routine should be called again.            *
   3807  *                                                                                             *
   3808  * WARNINGS:   none                                                                            *
   3809  *                                                                                             *
   3810  * HISTORY:                                                                                    *
   3811  *   05/09/1995 JLB : Created.                                                                 *
   3812  *   09/28/1995 JLB : Harvester stick in guard mode if no more refineries.                     *
   3813  *=============================================================================================*/
   3814 int UnitClass::Mission_Move(void)
   3815 {
   3816 	assert(Units.ID(this) == ID);
   3817 	assert(IsActive);
   3818 
   3819 	IsHarvesting = false;
   3820 
   3821 	/*
   3822 	**	Always make sure that that transport door is closed if the vehicle is moving.
   3823 	*/
   3824 	if (!Is_Door_Closed()) {
   3825 		APC_Close_Door();
   3826 	}
   3827 
   3828 	return(DriveClass::Mission_Move());
   3829 }
   3830 
   3831 
   3832 int UnitClass::Mission_Enter(void)
   3833 {
   3834 	assert(Units.ID(this) == ID);
   3835 	assert(IsActive);
   3836 
   3837 	if (Class->IsToHarvest) {
   3838 		TechnoClass * contact = Contact_With_Whom();
   3839 		if (contact == NULL) {
   3840 			contact = As_Techno(ArchiveTarget);
   3841 		}
   3842 		if (contact != NULL &&
   3843 			contact->What_Am_I() == RTTI_BUILDING &&
   3844 			*((BuildingClass*)contact) == STRUCT_REFINERY) {
   3845 			TiberiumUnloadRefinery = contact->As_Target();
   3846 		}
   3847 	}
   3848 
   3849 	return(DriveClass::Mission_Enter());
   3850 }
   3851 
   3852 
   3853 /***********************************************************************************************
   3854  * UnitClass::Desired_Load_Dir -- Determines the best cell and facing for loading.             *
   3855  *                                                                                             *
   3856  *    This routine examines the unit and adjacent cells in order to find the best facing       *
   3857  *    for the transport and best staging cell for the potential passengers. This location is   *
   3858  *    modified by adjacent cell passability and direction of the potential passenger.          *
   3859  *                                                                                             *
   3860  * INPUT:   passenger   -- Pointer to the potential passenger.                                 *
   3861  *                                                                                             *
   3862  *          moveto      -- Reference to the cell number that specifies where the potential     *
   3863  *                         passenger should move to first.                                     *
   3864  *                                                                                             *
   3865  * OUTPUT:  Returns with the direction the transport should face before opening the transport  *
   3866  *          door.                                                                              *
   3867  *                                                                                             *
   3868  * WARNINGS:   none                                                                            *
   3869  *                                                                                             *
   3870  * HISTORY:                                                                                    *
   3871  *   05/23/1995 JLB : Created.                                                                 *
   3872  *=============================================================================================*/
   3873 DirType UnitClass::Desired_Load_Dir(ObjectClass * passenger, CELL & moveto) const
   3874 {
   3875 	assert(Units.ID(this) == ID);
   3876 	assert(IsActive);
   3877 
   3878 	/*
   3879 	**	Determine the ideal facing that provides the least resistance. This would be the direction
   3880 	**	of the potential passenger or the current transport facing if it is going to unload.
   3881 	*/
   3882 	DirType faceto;
   3883 	if (passenger != NULL) {
   3884 		faceto = Direction(passenger);
   3885 	} else {
   3886 		faceto = PrimaryFacing.Current() + DIR_S;
   3887 	}
   3888 
   3889 	/*
   3890 	**	Sweep through the adjacent cells in order to find the best candidate.
   3891 	*/
   3892 	FacingType bestdir = FACING_N;
   3893 	int bestval = -1;
   3894 	for (FacingType face = FACING_N; face < FACING_COUNT; face++) {
   3895 		int value = 0;
   3896 		CELL cellnum = Adjacent_Cell(Coord_Cell(Coord), face);
   3897 
   3898 		/*
   3899 		**	Base the initial value of the potential cell according to whether the passenger is
   3900 		**	allowed to enter the cell. If it can't, then give such a negative value to the
   3901 		**	cell so that it is prevented from ever choosing that cell for load/unload.
   3902 		*/
   3903 		if (passenger != NULL) {
   3904 			value = (passenger->Can_Enter_Cell(cellnum) == MOVE_OK || Coord_Cell(passenger->Coord) == cellnum) ? 128 : -128;
   3905 		} else {
   3906 			CellClass * cell = &Map[cellnum];
   3907 			if (Ground[cell->Land_Type()].Cost[SPEED_FOOT] == 0 || cell->Flag.Occupy.Building || cell->Flag.Occupy.Vehicle || cell->Flag.Occupy.Monolith || (cell->Flag.Composite & 0x01F) == 0x01F) {
   3908 				value = -128;
   3909 			} else {
   3910 				if (cell->Cell_Techno() && !House->Is_Ally(cell->Cell_Techno())) {
   3911 					value = -128;
   3912 				} else {
   3913 					value = 128;
   3914 				}
   3915 			}
   3916 		}
   3917 
   3918 		/*
   3919 		**	Give more weight to the cells that require the least rotation of the transport or the
   3920 		**	least roundabout movement for the potential passenger.
   3921 		*/
   3922 		value -= (int)ABS((int)(signed char)Facing_Dir(face) - (int)(signed char)faceto);
   3923 		if (face == FACING_S) {
   3924 			value -= 100;
   3925 		}
   3926 		if (face == FACING_SW || face == FACING_SE) value += 64;
   3927 
   3928 		/*
   3929 		**	If the value for the potential cell is greater than the last recorded potential
   3930 		**	value, then record this cell as the best candidate.
   3931 		*/
   3932 		if (bestval == -1 || value > bestval) {
   3933 			bestval = value;
   3934 			bestdir = face;
   3935 		}
   3936 	}
   3937 
   3938 	/*
   3939 	**	If a suitable direction was found, then return with the direction value.
   3940 	*/
   3941 	moveto = 0;
   3942 	if (bestval > 0) {
   3943 		static DirType _desired_to_actual[FACING_COUNT] = {DIR_S, DIR_SW, DIR_NW, DIR_NW, DIR_NE, DIR_NE, DIR_NE, DIR_SE};
   3944 
   3945 		moveto = Adjacent_Cell(Coord_Cell(Coord), bestdir);
   3946 		return(_desired_to_actual[bestdir]);
   3947 	}
   3948 	return(DIR_S);
   3949 }
   3950 
   3951 
   3952 /***********************************************************************************************
   3953  * UnitClass::Flag_Attach -- Attaches a house flag to this unit.                               *
   3954  *                                                                                             *
   3955  *    This routine will attach a house flag to this unit.                                      *
   3956  *                                                                                             *
   3957  * INPUT:   house -- The house that is having its flag attached to it.                         *
   3958  *                                                                                             *
   3959  * OUTPUT:  Was the house flag successfully attached to this unit?                             *
   3960  *                                                                                             *
   3961  * WARNINGS:   A unit can only carry one flag at a time. This might be a reason for failure    *
   3962  *             of this routine.                                                                *
   3963  *                                                                                             *
   3964  * HISTORY:                                                                                    *
   3965  *   05/23/1995 JLB : Created.                                                                 *
   3966  *=============================================================================================*/
   3967 bool UnitClass::Flag_Attach(HousesType house)
   3968 {
   3969 	assert(Units.ID(this) == ID);
   3970 	assert(IsActive);
   3971 
   3972 	if (house != HOUSE_NONE && Flagged == HOUSE_NONE)	{
   3973 		Flagged = house;
   3974 		Mark(MARK_CHANGE);
   3975 		return(true);
   3976 	}
   3977 	return(false);
   3978 }
   3979 
   3980 
   3981 /***********************************************************************************************
   3982  * UnitClass::Flag_Remove -- Removes the house flag from this unit.                            *
   3983  *                                                                                             *
   3984  *    This routine will remove the house flag that is attached to this unit.                   *
   3985  *                                                                                             *
   3986  * INPUT:   none                                                                               *
   3987  *                                                                                             *
   3988  * OUTPUT:  Was the flag successfully removed?                                                 *
   3989  *                                                                                             *
   3990  * WARNINGS:   This routine doesn't put the flag into a new location. That operation must      *
   3991  *             be performed or else the house flag will cease to exist.                        *
   3992  *                                                                                             *
   3993  * HISTORY:                                                                                    *
   3994  *   05/23/1995 JLB : Created.                                                                 *
   3995  *=============================================================================================*/
   3996 bool UnitClass::Flag_Remove(void)
   3997 {
   3998 	assert(Units.ID(this) == ID);
   3999 	assert(IsActive);
   4000 
   4001 	if (Flagged != HOUSE_NONE) {
   4002 		Flagged = HOUSE_NONE;
   4003 		Mark(MARK_CHANGE);
   4004 		return(true);
   4005 	}
   4006 	return(false);
   4007 }
   4008 
   4009 
   4010 /***********************************************************************************************
   4011  * UnitClass::Pip_Count -- Fetches the number of pips to display on unit.                      *
   4012  *                                                                                             *
   4013  *    This routine is used to fetch the number of "fullness" pips to display on the unit.      *
   4014  *    This will either be the number of passengers or the percentage full (in 1/5ths) of       *
   4015  *    a harvester.                                                                             *
   4016  *                                                                                             *
   4017  * INPUT:   none                                                                               *
   4018  *                                                                                             *
   4019  * OUTPUT:  Returns with the number of pips to draw on this unit.                              *
   4020  *                                                                                             *
   4021  * WARNINGS:   none                                                                            *
   4022  *                                                                                             *
   4023  * HISTORY:                                                                                    *
   4024  *   06/25/1995 JLB : Created.                                                                 *
   4025  *=============================================================================================*/
   4026 int UnitClass::Pip_Count(void) const
   4027 {
   4028 	assert(Units.ID(this) == ID);
   4029 	assert(IsActive);
   4030 
   4031 	if (Class->Max_Passengers() > 0) {
   4032 		return(How_Many());
   4033 	}
   4034 
   4035 	if (*this == UNIT_MINELAYER) {
   4036 		int retval = 0;
   4037 		if (Ammo > 0) {
   4038 			retval = Class->Max_Pips() * fixed(Ammo, Class->MaxAmmo);
   4039 			if (!retval) retval = 1;
   4040 		}
   4041 		return(retval);
   4042 	}
   4043 
   4044 	if (*this == UNIT_HARVESTER) {
   4045 		return((Gold + Gems) / 4);
   4046 	}
   4047 
   4048 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   4049 	if (*this == UNIT_CHRONOTANK) {
   4050 		int fulldur = ChronoTankDuration * TICKS_PER_MINUTE;
   4051 		return( (fulldur - MoebiusCountDown) / (fulldur / 5));
   4052 	}
   4053 #endif
   4054 	return(0);
   4055 }
   4056 
   4057 
   4058 /***********************************************************************************************
   4059  * UnitClass::APC_Close_Door -- Closes an APC door.                                            *
   4060  *                                                                                             *
   4061  *    This routine will initiate closing of the APC door.                                      *
   4062  *                                                                                             *
   4063  * INPUT:   none                                                                               *
   4064  *                                                                                             *
   4065  * OUTPUT:  none                                                                               *
   4066  *                                                                                             *
   4067  * WARNINGS:   none                                                                            *
   4068  *                                                                                             *
   4069  * HISTORY:                                                                                    *
   4070  *   06/25/1995 JLB : Created.                                                                 *
   4071  *=============================================================================================*/
   4072 void UnitClass::APC_Close_Door(void)
   4073 {
   4074 	assert(Units.ID(this) == ID);
   4075 	assert(IsActive);
   4076 
   4077 	Close_Door(10, 2);
   4078 }
   4079 
   4080 
   4081 /***********************************************************************************************
   4082  * UnitClass::APC_Open_Door -- Opens an APC door.                                              *
   4083  *                                                                                             *
   4084  *    This routine will initiate opening of the APC door.                                      *
   4085  *                                                                                             *
   4086  * INPUT:   none                                                                               *
   4087  *                                                                                             *
   4088  * OUTPUT:  none                                                                               *
   4089  *                                                                                             *
   4090  * WARNINGS:   none                                                                            *
   4091  *                                                                                             *
   4092  * HISTORY:                                                                                    *
   4093  *   06/25/1995 JLB : Created.                                                                 *
   4094  *=============================================================================================*/
   4095 void UnitClass::APC_Open_Door(void)
   4096 {
   4097 	assert(Units.ID(this) == ID);
   4098 	assert(IsActive);
   4099 
   4100 	if (!IsDriving && !IsRotating) {
   4101 		if (PrimaryFacing == DIR_NW || PrimaryFacing == DIR_NE) {
   4102 			Open_Door(10, 2);
   4103 		} else {
   4104 			Open_Door(1, 2);
   4105 		}
   4106 	}
   4107 }
   4108 
   4109 
   4110 /***********************************************************************************************
   4111  * UnitClass::Crew_Type -- Fetches the kind of crew that this object produces.                 *
   4112  *                                                                                             *
   4113  *    When a unit is destroyed, a crew member might be generated. This routine will return     *
   4114  *    with the infantry type to produce for this unit. This routine will be called for every   *
   4115  *    survivor that is generated.                                                              *
   4116  *                                                                                             *
   4117  * INPUT:   none                                                                               *
   4118  *                                                                                             *
   4119  * OUTPUT:  Returns with a suggested infantry type to generate as a survivor from this unit.   *
   4120  *                                                                                             *
   4121  * WARNINGS:   none                                                                            *
   4122  *                                                                                             *
   4123  * HISTORY:                                                                                    *
   4124  *   08/13/1995 JLB : Created.                                                                 *
   4125  *=============================================================================================*/
   4126 InfantryType UnitClass::Crew_Type(void) const
   4127 {
   4128 	assert(Units.ID(this) == ID);
   4129 	assert(IsActive);
   4130 
   4131 	if (Class->PrimaryWeapon == NULL) {
   4132 		if (Percent_Chance(50)) {
   4133 			return(INFANTRY_C1);
   4134 		} else {
   4135 			return(INFANTRY_C7);
   4136 		}
   4137 	}
   4138 	return(DriveClass::Crew_Type());
   4139 }
   4140 
   4141 
   4142 /***********************************************************************************************
   4143  * UnitClass::Mission_Repair -- Handles finding and proceeding on a repair mission.            *
   4144  *                                                                                             *
   4145  *    This mission handler will look for a repair facility. If one is found then contact       *
   4146  *    is established and then the normal Mission_Enter logic is performed. The repair facility *
   4147  *    will take over the actual repair coordination process.                                   *
   4148  *                                                                                             *
   4149  * INPUT:   none                                                                               *
   4150  *                                                                                             *
   4151  * OUTPUT:  Returns the number of game frames to delay before calling this routine again.      *
   4152  *                                                                                             *
   4153  * WARNINGS:   none                                                                            *
   4154  *                                                                                             *
   4155  * HISTORY:                                                                                    *
   4156  *   10/02/1995 JLB : Created.                                                                 *
   4157  *=============================================================================================*/
   4158 int UnitClass::Mission_Repair(void)
   4159 {
   4160 	assert(Units.ID(this) == ID);
   4161 	assert(IsActive);
   4162 
   4163 	BuildingClass * nearest = Find_Docking_Bay(STRUCT_REFINERY, true);
   4164 
   4165 	IsHarvesting = false;
   4166 
   4167 	/*
   4168 	**	If there is no available repair facility, then check to see if there
   4169 	**	are any repair facilities at all. If not, then enter this unit
   4170 	**	into idle state.
   4171 	*/
   4172 	if (nearest == NULL) {
   4173 		if (!(House->ActiveBScan & STRUCTF_REFINERY)) {
   4174 			Enter_Idle_Mode();
   4175 		}
   4176 	} else {
   4177 
   4178 		/*
   4179 		**	Try to establish radio contact with the repair facility. If contact
   4180 		**	was established, then proceed with normal enter mission, which handles
   4181 		**	the repair process.
   4182 		*/
   4183 		if (Transmit_Message(RADIO_HELLO, nearest) == RADIO_ROGER) {
   4184 			Assign_Mission(MISSION_ENTER);
   4185 			return(1);
   4186 		}
   4187 	}
   4188 
   4189 	/*
   4190 	**	If no action could be performed at this time, then wait
   4191 	**	around for a bit before trying again.
   4192 	*/
   4193 	return(MissionControl[Mission].Normal_Delay());
   4194 }
   4195 
   4196 
   4197 /***********************************************************************************************
   4198  * UnitClass::Fire_Direction -- Determines the direction of firing.                            *
   4199  *                                                                                             *
   4200  *    This routine will return with the facing that a projectile will travel if it was         *
   4201  *    fired at this instant. The facing should match the turret facing for those units         *
   4202  *    equipped with a turret. If the unit doesn't have a turret, then it will be the facing    *
   4203  *    of the body.                                                                             *
   4204  *                                                                                             *
   4205  * INPUT:   none                                                                               *
   4206  *                                                                                             *
   4207  * OUTPUT:  Returns with the default firing direction for a projectile.                        *
   4208  *                                                                                             *
   4209  * WARNINGS:   none                                                                            *
   4210  *                                                                                             *
   4211  * HISTORY:                                                                                    *
   4212  *   06/25/1995 JLB : Created.                                                                 *
   4213  *=============================================================================================*/
   4214 DirType UnitClass::Fire_Direction(void) const
   4215 {
   4216 	assert(Units.ID(this) == ID);
   4217 	assert(IsActive);
   4218 
   4219 	if (Class->IsTurretEquipped) {
   4220 		if (*this == UNIT_V2_LAUNCHER) {
   4221 			int diff1 = SecondaryFacing.Difference(DIR_E);
   4222 			int diff2 = SecondaryFacing.Difference(DIR_W);
   4223 			diff1 = ABS(diff1);
   4224 			diff2 = ABS(diff2);
   4225 			int diff = min(diff1, diff2);
   4226 			int adj = Fixed_To_Cardinal(ABS(SecondaryFacing.Difference(DIR_N)), 64-diff);
   4227 			if (SecondaryFacing.Difference(DIR_N) < 0) {
   4228 				return(DirType)(SecondaryFacing - (DirType)adj);
   4229 			} else {
   4230 				return(DirType)(SecondaryFacing + (DirType)adj);
   4231 			}
   4232 		}
   4233 		return(SecondaryFacing.Current());
   4234 	}
   4235 
   4236 	return(DriveClass::Fire_Direction());
   4237 }
   4238 
   4239 
   4240 /***********************************************************************************************
   4241  * UnitClass::Ok_To_Move -- Queries whether the vehicle can move.                              *
   4242  *                                                                                             *
   4243  *    This virtual routine is used to determine if the vehicle is allowed                      *
   4244  *    to start moving. It is typically called when the vehicle desires                         *
   4245  *    to move but needs confirmation from the turret logic before                              *
   4246  *    proceeding. This happens when dealing with a vehicle that must have                      *
   4247  *    its turret face the same direction as the body before the vehicle                        *
   4248  *    may begin movement.                                                                      *
   4249  *                                                                                             *
   4250  * INPUT:   dir      -- The facing the unit wants to travel in.                                *
   4251  *                                                                                             *
   4252  * OUTPUT:  bool; Can the unit begin forward movement now?                                     *
   4253  *                                                                                             *
   4254  * WARNINGS:   none                                                                            *
   4255  *                                                                                             *
   4256  * HISTORY:                                                                                    *
   4257  *   05/12/1994 JLB : Created.                                                                 *
   4258  *=============================================================================================*/
   4259 bool UnitClass::Ok_To_Move(DirType dir) const
   4260 {
   4261 	assert(Units.ID(this) == ID);
   4262 	assert(IsActive);
   4263 
   4264 	if (Class->IsLockTurret) {
   4265 		if (IsRotating) {
   4266 			return(false);
   4267 		} else {
   4268 			if (SecondaryFacing.Difference(dir)) {
   4269 				((UnitClass *)this)->SecondaryFacing.Set_Desired(dir);
   4270 				return(false);
   4271 			}
   4272 		}
   4273 	}
   4274 	return(true);
   4275 }
   4276 
   4277 
   4278 /***********************************************************************************************
   4279  * UnitClass::Can_Fire -- Determines if turret can fire upon target.                           *
   4280  *                                                                                             *
   4281  *    This routine determines if the turret can fire upon the target                           *
   4282  *    specified.                                                                               *
   4283  *                                                                                             *
   4284  * INPUT:   target   -- The target to fire upon.                                               *
   4285  *                                                                                             *
   4286  *          which    -- Which weapon to use to determine legality to fire. 0=primary,          *
   4287  *                      1=secondary.                                                           *
   4288  *                                                                                             *
   4289  * OUTPUT:  Returns the fire status type that indicates if firing is allowed and if not, why.  *
   4290  *                                                                                             *
   4291  * WARNINGS:   none                                                                            *
   4292  *                                                                                             *
   4293  * HISTORY:                                                                                    *
   4294  *   04/26/1994 JLB : Created.                                                                 *
   4295  *   06/01/1994 JLB : Returns reason why it can't fire.                                        *
   4296  *=============================================================================================*/
   4297 FireErrorType UnitClass::Can_Fire(TARGET target, int which) const
   4298 {
   4299 	assert(Units.ID(this) == ID);
   4300 	assert(IsActive);
   4301 
   4302 	DirType			dir;					// The facing to impart upon the projectile.
   4303 	int				diff;
   4304 	FireErrorType	fire = DriveClass::Can_Fire(target, which);
   4305 
   4306 	if (fire == FIRE_OK) {
   4307 		WeaponTypeClass const * weapon = (which == 0) ? Class->PrimaryWeapon : Class->SecondaryWeapon;
   4308 
   4309 		/*
   4310 		**	If this unit cannot fire while moving, then bail.
   4311 		*/
   4312 		if ((Class->IsNoFireWhileMoving /*!Class->IsTurretEquipped || Class->IsLockTurret*/) && Target_Legal(NavCom)) {
   4313 			return(FIRE_MOVING);
   4314 		}
   4315 
   4316 		/*
   4317 		**	If the turret is rotating and the projectile isn't a homing type, then
   4318 		**	firing must be delayed until the rotation stops.
   4319 		*/
   4320 		if (!IsFiring && IsRotating && weapon->Bullet->ROT == 0) {
   4321 			return(FIRE_ROTATING);
   4322 		}
   4323 
   4324 		dir = Direction(target);
   4325 
   4326 		/*
   4327 		**	Determine if the turret facing isn't too far off of facing the target.
   4328 		*/
   4329 		if (Class->IsTurretEquipped) {
   4330 			diff = SecondaryFacing.Difference(dir);
   4331 		} else {
   4332 			diff = PrimaryFacing.Difference(dir);
   4333 		}
   4334 		diff = ABS(diff);
   4335 
   4336 		if (weapon->Bullet->ROT != 0) {
   4337 			diff >>= 2;
   4338 		}
   4339 		if (diff < 8) {
   4340 			return(DriveClass::Can_Fire(target, which));
   4341 		}
   4342 		return(FIRE_FACING);
   4343 	}
   4344 	return(fire);
   4345 }
   4346 
   4347 
   4348 /***********************************************************************************************
   4349  * UnitClass::Fire_At -- Try to fire upon the target specified.                                *
   4350  *                                                                                             *
   4351  *    This routine is the auto-fire logic for the turret. It will check                        *
   4352  *    to see if firing is technically legal given the specified target.                        *
   4353  *    If it is legal to fire, it does so. It is safe to call this routine                      *
   4354  *    every game tick.                                                                         *
   4355  *                                                                                             *
   4356  * INPUT:   target   -- The target to fire upon.                                               *
   4357  *                                                                                             *
   4358  *          which    -- Which weapon to use when firing. 0=primary, 1=secondary.               *
   4359  *                                                                                             *
   4360  * OUTPUT:  bool; Did firing occur?                                                            *
   4361  *                                                                                             *
   4362  * WARNINGS:   none                                                                            *
   4363  *                                                                                             *
   4364  * HISTORY:                                                                                    *
   4365  *   04/26/1994 JLB : Created.                                                                 *
   4366  *=============================================================================================*/
   4367 BulletClass * UnitClass::Fire_At(TARGET target, int which)
   4368 {
   4369 	assert(Units.ID(this) == ID);
   4370 	assert(IsActive);
   4371 
   4372 	BulletClass * bullet = NULL;
   4373 	WeaponTypeClass const * weap = (which == 0) ? Class->PrimaryWeapon : Class->SecondaryWeapon;
   4374 	if (weap == NULL) return(NULL);
   4375 
   4376 	if (Can_Fire(target, which) == FIRE_OK) {
   4377 		bullet = DriveClass::Fire_At(target, which);
   4378 
   4379 		if (bullet != NULL) {
   4380 #ifdef FIXIT_CSII	//	checked - ajw 9/28/98
   4381 if(Class->Type == UNIT_DEMOTRUCK && IsActive) delete this;
   4382 #endif
   4383 			/*
   4384 			**	Possible reload timer set.
   4385 			*/
   4386 			if ((*this == UNIT_V2_LAUNCHER) && Reload == 0) {
   4387 				Reload = TICKS_PER_SECOND * 30;
   4388 			}
   4389 		}
   4390 	}
   4391 
   4392 	return(bullet);
   4393 }
   4394 
   4395 
   4396 /***********************************************************************************************
   4397  * UnitClass::Class_Of -- Fetches a reference to the class type for this object.               *
   4398  *                                                                                             *
   4399  *    This routine will fetch a reference to the TypeClass of this object.                     *
   4400  *                                                                                             *
   4401  * INPUT:   none                                                                               *
   4402  *                                                                                             *
   4403  * OUTPUT:  Returns with reference to the type class of this object.                           *
   4404  *                                                                                             *
   4405  * WARNINGS:   none                                                                            *
   4406  *                                                                                             *
   4407  * HISTORY:                                                                                    *
   4408  *   07/29/1995 JLB : Created.                                                                 *
   4409  *=============================================================================================*/
   4410 ObjectTypeClass const & UnitClass::Class_Of(void) const
   4411 {
   4412 	assert(Units.ID(this) == ID);
   4413 	assert(IsActive);
   4414 
   4415 	return(*Class);
   4416 }
   4417 
   4418 
   4419 /***********************************************************************************************
   4420  * UnitClass::Tiberium_Load -- Determine the Tiberium load as a percentage.                    *
   4421  *                                                                                             *
   4422  *    Use this routine to determine what the Tiberium load is (as a fixed point percentage).   *
   4423  *                                                                                             *
   4424  * INPUT:   none                                                                               *
   4425  *                                                                                             *
   4426  * OUTPUT:  Returns with the current "fullness" rating for the object.                         *
   4427  *                                                                                             *
   4428  * WARNINGS:   none                                                                            *
   4429  *                                                                                             *
   4430  * HISTORY:                                                                                    *
   4431  *   03/17/1995 JLB : Created.                                                                 *
   4432  *=============================================================================================*/
   4433 fixed UnitClass::Tiberium_Load(void) const
   4434 {
   4435 	assert(IsActive);
   4436 
   4437 	if (*this == UNIT_HARVESTER) {
   4438 		return(fixed(Tiberium, Rule.BailCount));
   4439 	}
   4440 	return(0);
   4441 }
   4442 
   4443 
   4444 BuildingClass* UnitClass::Find_Best_Refinery(void) const
   4445 {
   4446 	/*
   4447 	**	Remember our last refinery and prefer that one, if still available and valid.
   4448 	*/
   4449 	if (Target_Legal(TiberiumUnloadRefinery)) {
   4450 		BuildingClass * refinery = As_Building(TiberiumUnloadRefinery);
   4451 		if (refinery != NULL &&
   4452 			refinery->House == House &&
   4453 			!refinery->IsInLimbo &&
   4454 			refinery->Mission != MISSION_DECONSTRUCTION &&
   4455 			*refinery == STRUCT_REFINERY &&
   4456 			Map[refinery->Center_Coord()].Zones[Techno_Type_Class()->MZone] == Map[Center_Coord()].Zones[Techno_Type_Class()->MZone]) {
   4457 			return refinery;
   4458 		} else {
   4459 			TiberiumUnloadRefinery = TARGET_NONE;
   4460 		}
   4461 	}
   4462 
   4463 	/*
   4464 	**	Find nearby refinery and head to it?
   4465 	*/
   4466 	return Find_Docking_Bay(STRUCT_REFINERY, false);
   4467 }
   4468 
   4469 
   4470 /***********************************************************************************************
   4471  * UnitClass::Offload_Tiberium_Bail -- Offloads one Tiberium quantum from the object.          *
   4472  *                                                                                             *
   4473  *    This routine will offload one Tiberium packet/quantum/bail from the object. Multiple     *
   4474  *    calls to this routine are needed in order to fully offload all Tiberium.                 *
   4475  *                                                                                             *
   4476  * INPUT:   none                                                                               *
   4477  *                                                                                             *
   4478  * OUTPUT:  Returns with the number of credits offloaded for the one call. If zero is returned,*
   4479  *          then this indicates that all Tiberium has been offloaded.                          *
   4480  *                                                                                             *
   4481  * WARNINGS:   none                                                                            *
   4482  *                                                                                             *
   4483  * HISTORY:                                                                                    *
   4484  *   07/19/1995 JLB : Created.                                                                 *
   4485  *=============================================================================================*/
   4486 int UnitClass::Offload_Tiberium_Bail(void)
   4487 {
   4488 	assert(IsActive);
   4489 
   4490 	if (Tiberium) {
   4491 		Tiberium--;
   4492 
   4493 // MBL 05.15.2020: Note, if the below code is ever reeanbled for some ready, make sure to see fix in 
   4494 // Tiberian Dawn's DriveClass::Offload_Tiberium_Bail() for AI players
   4495 
   4496 #ifdef TOFIX
   4497 		if (House->IsHuman) {
   4498 			return(UnitTypeClass::FULL_LOAD_CREDITS/UnitTypeClass::STEP_COUNT);
   4499 		}
   4500 		return(UnitTypeClass::FULL_LOAD_CREDITS+(UnitTypeClass::FULL_LOAD_CREDITS/3)/UnitTypeClass::STEP_COUNT);
   4501 #endif
   4502 	}
   4503 	return(0);
   4504 }
   4505 
   4506 
   4507 /***********************************************************************************************
   4508  * UnitClass::Approach_Target -- Handles approaching the target in order to attack it.         *
   4509  *                                                                                             *
   4510  *    This routine will check to see if the target is infantry and it can be overrun. It will  *
   4511  *    try to overrun the infantry rather than attack it. This only applies to computer         *
   4512  *    controlled vehicles. If it isn't the infantry overrun case, then it falls into the       *
   4513  *    base class for normal (complex) approach algorithm.                                      *
   4514  *                                                                                             *
   4515  * INPUT:   none                                                                               *
   4516  *                                                                                             *
   4517  * OUTPUT:  none                                                                               *
   4518  *                                                                                             *
   4519  * WARNINGS:   none                                                                            *
   4520  *                                                                                             *
   4521  * HISTORY:                                                                                    *
   4522  *   03/17/1995 JLB : Created.                                                                 *
   4523  *   07/12/1995 JLB : Flamethrower tanks don't overrun -- their weapon is better.              *
   4524  *=============================================================================================*/
   4525 void UnitClass::Approach_Target(void)
   4526 {
   4527 	assert(IsActive);
   4528 
   4529 	/*
   4530 	**	Only if there is a legal target should the approach check occur.
   4531 	*/
   4532 	if (!House->IsHuman && Target_Legal(TarCom) && !Target_Legal(NavCom)) {
   4533 
   4534 		/*
   4535 		**	Special case:
   4536 		**	If this is for a unit that can crush infantry, and the target is
   4537 		**	infantry, AND the infantry is pretty darn close, then just try
   4538 		**	to drive over the infantry instead of firing on it.
   4539 		*/
   4540 		TechnoClass * target = As_Techno(TarCom);
   4541 		if (Class->IsCrusher && Distance(TarCom) < Rule.CrushDistance && target && ((TechnoTypeClass const &)(target->Class_Of())).IsCrushable) {
   4542 			Assign_Destination(TarCom);
   4543 			return;
   4544 		}
   4545 	}
   4546 
   4547 	/*
   4548 	**	In the other cases, uses the more complex "get to just within weapon range"
   4549 	**	algorithm.
   4550 	*/
   4551 	DriveClass::Approach_Target();
   4552 }
   4553 
   4554 
   4555 /***********************************************************************************************
   4556  * DriveClass::Overrun_Square -- Handles vehicle overrun of a cell.                            *
   4557  *                                                                                             *
   4558  *    This routine is called when a vehicle enters a square or when it is about to enter a     *
   4559  *    square (controlled by parameter). When a vehicle that can crush infantry enters a        *
   4560  *    cell that contains infantry, then the infantry will be destroyed (regardless of          *
   4561  *    affiliation). When a vehicle threatens to overrun a square, all occupying infantry       *
   4562  *    will attempt to get out of the way.                                                      *
   4563  *                                                                                             *
   4564  * INPUT:   cell     -- The cell that is, or soon will be, entered by a vehicle.               *
   4565  *                                                                                             *
   4566  *          threaten -- Don't kill, but just threaten to enter the cell.                       *
   4567  *                                                                                             *
   4568  * OUTPUT:  none                                                                               *
   4569  *                                                                                             *
   4570  * WARNINGS:   none                                                                            *
   4571  *                                                                                             *
   4572  * HISTORY:                                                                                    *
   4573  *   01/19/1995 JLB : Created.                                                                 *
   4574  *=============================================================================================*/
   4575 void UnitClass::Overrun_Square(CELL cell, bool threaten)
   4576 {
   4577 	assert(IsActive);
   4578 
   4579 	CellClass * cellptr = &Map[cell];
   4580 
   4581 	if (Class->IsCrusher) {
   4582 		if (threaten) {
   4583 
   4584 			/*
   4585 			**	If the cell contains infantry, then they will panic when a vehicle tries
   4586 			**	drive over them. Have the infantry run away instead.
   4587 			*/
   4588 			if (cellptr->Flag.Composite & 0x1F) {
   4589 
   4590 				/*
   4591 				**	Scattering is controlled by the game difficulty level.
   4592 				*/
   4593 				cellptr->Incoming(0, true);
   4594 			}
   4595 		} else {
   4596 			ObjectClass * object = cellptr->Cell_Occupier();
   4597 			int crushed = false;
   4598 			while (object != NULL) {
   4599 				if (object->Class_Of().IsCrushable && !House->Is_Ally(object) && Distance(object->Center_Coord()) < CELL_LEPTON_W/2) {
   4600 
   4601 #ifdef OBSOLETE
   4602 					/*
   4603 					** If we're running over infantry, let's see if the infantry we're
   4604 					** squashing is a thief trying to capture us.  If so, let him succeed.
   4605 					*/
   4606 					if (object->What_Am_I() == RTTI_INFANTRY && *((InfantryClass *)object) == INFANTRY_THIEF && ((InfantryClass *)object)->NavCom == As_Target()) {
   4607 						ObjectClass * next = object->Next;
   4608 						IsOwnedByPlayer = ((InfantryClass *)object)->IsOwnedByPlayer;
   4609 						House = ((InfantryClass *)object)->House;
   4610 						delete object;
   4611 						object = next;
   4612 					} else {
   4613 #endif
   4614 						ObjectClass * next = object->Next;
   4615 						crushed = true;
   4616 
   4617 						/*
   4618 						** Record credit for the kill(s)
   4619 						*/
   4620 						Sound_Effect(VOC_SQUISH, Coord);
   4621 						if (object->Height == 0) {
   4622 							AnimClass* anim = new AnimClass(ANIM_CORPSE1, object->Center_Coord());
   4623 							if (anim != NULL) {
   4624 								anim->Set_Owner(object->Owner());
   4625 							}
   4626 						}
   4627 						object->Record_The_Kill(this);
   4628 						object->Mark(MARK_UP);
   4629 						object->Limbo();
   4630 						delete object;
   4631 						//new OverlayClass(OVERLAY_SQUISH, Coord_Cell(Coord));
   4632 
   4633 						object = next;
   4634 #ifdef OBSOLETE
   4635 					}
   4636 #endif
   4637 				} else {
   4638 					object = object->Next;
   4639 				}
   4640 			}
   4641 			if (crushed) Do_Uncloak();
   4642 		}
   4643 	}
   4644 }
   4645 
   4646 
   4647 /***********************************************************************************************
   4648  * UnitClass::Assign_Destination -- Assign a destination to a unit.                            *
   4649  *                                                                                             *
   4650  *    This will assign the specified destination to the unit. It is presumed that doing is     *
   4651  *    is all that is needed in order to cause the unit to move to the specified destination.   *
   4652  *                                                                                             *
   4653  * INPUT:   target   -- The target (location) to move to.                                      *
   4654  *                                                                                             *
   4655  * OUTPUT:  none                                                                               *
   4656  *                                                                                             *
   4657  * WARNINGS:   none                                                                            *
   4658  *                                                                                             *
   4659  * HISTORY:                                                                                    *
   4660  *   07/09/1996 JLB : Created.                                                                 *
   4661  *=============================================================================================*/
   4662 void UnitClass::Assign_Destination(TARGET target)
   4663 {
   4664 	assert(IsActive);
   4665 
   4666 	/*
   4667 	**	Abort early if there is anything wrong with the parameters
   4668 	**	or the unit already is assigned the specified destination.
   4669 	*/
   4670 	if (target == NavCom) return;
   4671 
   4672 	/*
   4673 	**	Transport vehicles must tell all passengers that are about to load, that they
   4674 	**	cannot proceed. This is accomplished with a radio message to this effect.
   4675 	*/
   4676 	if (In_Radio_Contact() && Class->Max_Passengers() > 0 && Contact_With_Whom()->Is_Infantry()) {
   4677 		Transmit_Message(RADIO_OVER_OUT);
   4678 	}
   4679 
   4680 	BuildingClass * b = As_Building(target);
   4681 
   4682 	/*
   4683 	**	Handle entry logic here.
   4684 	*/
   4685 	if (Mission == MISSION_ENTER || MissionQueue == MISSION_ENTER) {
   4686 
   4687 		/*
   4688 		**	If not already in radio contact (presumed with the transport), then
   4689 		**	either try to establish contact if allowed, or just move close and
   4690 		**	wait until radio contact can be established.
   4691 		*/
   4692 		if (!In_Radio_Contact()) {
   4693 			if (b != NULL) {
   4694 
   4695 				/*
   4696 				**	Determine if the transport is already in radio contact. If so, then just move
   4697 				**	toward the transport and try to establish contact at a later time.
   4698 				*/
   4699 				if (b->In_Radio_Contact()) {
   4700 // TCTCTC -- call for an update from the transport to get a good rendezvous position.
   4701 					ArchiveTarget = target;
   4702 
   4703 /*
   4704 **	HACK ALERT: The repair bay is counting on the assignment of the NavCom by this routine.
   4705 **	The refinery must NOT have the navcom assigned by this routine.
   4706 */
   4707 if (*b != STRUCT_REPAIR) {
   4708 	target = TARGET_NONE;
   4709 }
   4710 				} else {
   4711 					if (Transmit_Message(RADIO_DOCKING, b) != RADIO_ROGER) {
   4712 						Transmit_Message(RADIO_OVER_OUT);
   4713 						if (*b == STRUCT_REPAIR) {
   4714 							ArchiveTarget = target;
   4715 						}
   4716 					}
   4717 if (*b != STRUCT_REPAIR) {
   4718 	ArchiveTarget = target;
   4719 	target = TARGET_NONE;
   4720 }
   4721 				}
   4722 			} else {
   4723 				TechnoClass * techno = As_Techno(target);
   4724 				if (techno != NULL) {
   4725 
   4726 					/*
   4727 					**	Determine if the transport is already in radio contact. If so, then just move
   4728 					**	toward the transport and try to establish contact at a later time.
   4729 					*/
   4730 					if (techno->In_Radio_Contact()) {
   4731 	// TCTCTC -- call for an update from the transport to get a good rendezvous position.
   4732 
   4733 						ArchiveTarget = target;
   4734 					} else {
   4735 						if (Transmit_Message(RADIO_HELLO, techno) == RADIO_ROGER) {
   4736 							if (Transmit_Message(RADIO_DOCKING) != RADIO_ROGER) {
   4737 								Transmit_Message(RADIO_OVER_OUT);
   4738 							} else {
   4739 								//BG: keep retransmitted navcom from radio-move-here.
   4740 								return;
   4741 							}
   4742 						}
   4743 					}
   4744 				}
   4745 
   4746 			}
   4747 		} else {
   4748 			Path[0] = FACING_NONE;
   4749 		}
   4750 	} else {
   4751 		Path[0] = FACING_NONE;
   4752 	}
   4753 
   4754 	/*
   4755 	**	If the player clicked on a friendly repair facility and the repair
   4756 	**	facility is currently not involved with some other unit (radio or unloading).
   4757 	*/
   4758 	if (b != NULL && *b == STRUCT_REPAIR) {
   4759 		if (b->In_Radio_Contact() && (b->Contact_With_Whom() != this) ) {
   4760 //			if (target != NULL) {
   4761 				ArchiveTarget = target;
   4762 //			}
   4763 //			target = TARGET_NONE;
   4764 		} else {
   4765 
   4766 			/*
   4767 			**	Establish radio contact protocol. If the facility responds correctly,
   4768 			**	then remain in radio contact and proceed toward the desired destination.
   4769 			*/
   4770 			if (Transmit_Message(RADIO_HELLO, b) == RADIO_ROGER) {
   4771 
   4772 				/*
   4773 				**	Last check to make sure that the loading square is free from permanent
   4774 				**	occupation (such as a building).
   4775 				*/
   4776 				CELL cell = (CELL)(Coord_Cell(b->Center_Coord()) + (MAP_CELL_W-1));
   4777 				if (Ground[Map[cell].Land_Type()].Cost[Techno_Type_Class()->Speed] > 0) {
   4778 					if (Transmit_Message(RADIO_DOCKING) == RADIO_ROGER) {
   4779 						FootClass::Assign_Destination(target);
   4780 						Path[0] = FACING_NONE;
   4781 						return;
   4782 					}
   4783 
   4784 					/*
   4785 					**	Failure to establish a docking relationship with the refinery.
   4786 					**	Bail & await further instructions.
   4787 					*/
   4788 					Transmit_Message(RADIO_OVER_OUT);
   4789 				}
   4790 			}
   4791 		}
   4792 	}
   4793 
   4794 	DriveClass::Assign_Destination(target);
   4795 }
   4796 
   4797 
   4798 /***********************************************************************************************
   4799  * UnitClass::Greatest_Threat -- Fetches the greatest threat for this unit.                    *
   4800  *                                                                                             *
   4801  *    This routine will search the map looking for a good target to attack. It takes into      *
   4802  *    consideration the type of weapon it is equipped with.                                    *
   4803  *                                                                                             *
   4804  * INPUT:   threat   -- The threat type to search for.                                         *
   4805  *                                                                                             *
   4806  * OUTPUT:  Returns with a target value of the target that this unit should pursue. If there   *
   4807  *          is no suitable target, then TARGET_NONE is returned.                               *
   4808  *                                                                                             *
   4809  * WARNINGS:   none                                                                            *
   4810  *                                                                                             *
   4811  * HISTORY:                                                                                    *
   4812  *   07/09/1996 JLB : Created.                                                                 *
   4813  *=============================================================================================*/
   4814 TARGET UnitClass::Greatest_Threat(ThreatType threat) const
   4815 {
   4816 	assert(IsActive);
   4817 	if (Class->PrimaryWeapon != NULL) {
   4818 		threat = threat | Class->PrimaryWeapon->Allowed_Threats();
   4819 	}
   4820 	if (Class->SecondaryWeapon != NULL) {
   4821 		threat = threat | Class->SecondaryWeapon->Allowed_Threats();
   4822 	}
   4823 
   4824 #ifdef OBSOLETE
   4825 	if (House->IsHuman) {
   4826 		threat = threat & ~THREAT_BUILDINGS;
   4827 	}
   4828 #endif
   4829 
   4830 	return(FootClass::Greatest_Threat(threat));
   4831 }
   4832 
   4833 
   4834 /***********************************************************************************************
   4835  * UnitClass::Read_INI -- Reads units from scenario INI file.                                  *
   4836  *                                                                                             *
   4837  *    This routine is used to read all the starting units from the                             *
   4838  *    scenario control INI file. The units are created and placed on the                       *
   4839  *    map by this routine.                                                                     *
   4840  *                                                                                             *
   4841  *    INI entry format:                                                                        *
   4842  *      Housename, Typename, Strength, Coord, Facingnum, Missionname, Triggername              *
   4843  *                                                                                             *
   4844  * INPUT:   buffer   -- Pointer to the loaded scenario INI file.                               *
   4845  *                                                                                             *
   4846  * OUTPUT:  none                                                                               *
   4847  *                                                                                             *
   4848  * WARNINGS:   none                                                                            *
   4849  *                                                                                             *
   4850  * HISTORY:                                                                                    *
   4851  *   05/24/1994 JLB : Created.                                                                 *
   4852  *=============================================================================================*/
   4853 void UnitClass::Read_INI(CCINIClass & ini)
   4854 {
   4855 	UnitClass	* unit;			// Working unit pointer.
   4856 	HousesType	inhouse;			// Unit house.
   4857 	UnitType		classid;			// Unit class.
   4858 	char			buf[128];
   4859 
   4860 	int len = ini.Entry_Count(INI_Name());
   4861 
   4862 	for (int index = 0; index < len; index++) {
   4863 		char const * entry = ini.Get_Entry(INI_Name(), index);
   4864 
   4865 		ini.Get_String(INI_Name(), entry, NULL, buf, sizeof(buf));
   4866 
   4867 		inhouse = HouseTypeClass::From_Name(strtok(buf, ","));
   4868 		if (inhouse != HOUSE_NONE) {
   4869 			classid = UnitTypeClass::From_Name(strtok(NULL, ","));
   4870 
   4871 			if (classid != UNIT_NONE) {
   4872 
   4873 				if (HouseClass::As_Pointer(inhouse) != NULL) {
   4874 					unit = new UnitClass(classid, inhouse);
   4875 					if (unit != NULL) {
   4876 
   4877 						/*
   4878 						**	Read the raw data.
   4879 						*/
   4880 						int strength = atoi(strtok(NULL, ",\r\n"));
   4881 
   4882 						CELL cell = atoi(strtok(NULL, ",\r\n"));
   4883 
   4884 						COORDINATE coord = Cell_Coord(cell);
   4885 
   4886 						DirType dir = (DirType)atoi(strtok(NULL, ",\r\n"));
   4887 						MissionType mission = MissionClass::Mission_From_Name(strtok(NULL, ",\n\r"));
   4888 
   4889 						unit->Trigger = NULL;
   4890 						TriggerTypeClass * tp = TriggerTypeClass::From_Name(strtok(NULL,",\r\n"));
   4891 						if (tp != NULL) {
   4892 							TriggerClass * tt = Find_Or_Make(tp);
   4893 							if (tt != NULL) {
   4894 								tt->AttachCount++;
   4895 								unit->Trigger = tt;
   4896 							}
   4897 						}
   4898 
   4899 						if (unit->Unlimbo(coord, dir)) {
   4900 							unit->Strength = (int)unit->Class->MaxStrength * fixed(strength, 256);
   4901 							if (unit->Strength > unit->Class->MaxStrength-3) unit->Strength = unit->Class->MaxStrength;
   4902 							if (Session.Type == GAME_NORMAL || unit->House->IsHuman) {
   4903 								unit->Assign_Mission(mission);
   4904 								unit->Commence();
   4905 							} else {
   4906 								unit->Enter_Idle_Mode();
   4907 							}
   4908 
   4909 						} else {
   4910 
   4911 							/*
   4912 							**	If the unit could not be unlimboed, then this is a catastrophic error
   4913 							**	condition. Delete the unit.
   4914 							*/
   4915 							delete unit;
   4916 						}
   4917 					}
   4918 				}
   4919 			}
   4920 		}
   4921 	}
   4922 }
   4923 
   4924 
   4925 /***********************************************************************************************
   4926  * UnitClass::Write_INI -- Store the units to the INI database.                                *
   4927  *                                                                                             *
   4928  *    This routine will store all the unit data to the INI database.                           *
   4929  *                                                                                             *
   4930  * INPUT:   ini   -- Reference to the INI database object to store to.                         *
   4931  *                                                                                             *
   4932  * OUTPUT:  none                                                                               *
   4933  *                                                                                             *
   4934  * WARNINGS:   none                                                                            *
   4935  *                                                                                             *
   4936  * HISTORY:                                                                                    *
   4937  *   07/03/1996 JLB : Created.                                                                 *
   4938  *=============================================================================================*/
   4939 void UnitClass::Write_INI(CCINIClass & ini)
   4940 {
   4941 	/*
   4942 	**	First, clear out all existing unit data from the ini file.
   4943 	*/
   4944 	ini.Clear(INI_Name());
   4945 
   4946 	/*
   4947 	**	Write the unit data out.
   4948 	*/
   4949 	for (int index = 0; index < Units.Count(); index++) {
   4950 		UnitClass * unit = Units.Ptr(index);
   4951 		if (unit != NULL && !unit->IsInLimbo && unit->IsActive) {
   4952 			char	uname[10];
   4953 			char	buf[128];
   4954 
   4955 			sprintf(uname, "%d", index);
   4956 			sprintf(buf, "%s,%s,%d,%u,%d,%s,%s",
   4957 				unit->House->Class->IniName,
   4958 				unit->Class->IniName,
   4959 				unit->Health_Ratio()*256,
   4960 				Coord_Cell(unit->Coord),
   4961 				unit->PrimaryFacing.Current(),
   4962 				MissionClass::Mission_Name(unit->Mission),
   4963 				unit->Trigger.Is_Valid() ? unit->Trigger->Class->IniName : "None"
   4964 				);
   4965 			ini.Put_String(INI_Name(), uname, buf);
   4966 		}
   4967 	}
   4968 }
   4969 
   4970 
   4971 /***********************************************************************************************
   4972  * UnitClass::Credit_Load -- Fetch the full credit value of cargo carried.                     *
   4973  *                                                                                             *
   4974  *    This will determine the value of the cargo carried (limited to considering only gold     *
   4975  *    and gems) and return that value. Use this to determine how 'valuable' a harvester is.    *
   4976  *                                                                                             *
   4977  * INPUT:   none                                                                               *
   4978  *                                                                                             *
   4979  * OUTPUT:  Returns with the credit value of the cargo load of this unit (harvester).          *
   4980  *                                                                                             *
   4981  * WARNINGS:   none                                                                            *
   4982  *                                                                                             *
   4983  * HISTORY:                                                                                    *
   4984  *   07/29/1996 JLB : Created.                                                                 *
   4985  *=============================================================================================*/
   4986 int UnitClass::Credit_Load(void) const
   4987 {
   4988 	return((Gold * Rule.GoldValue) + (Gems * Rule.GemValue));
   4989 }
   4990 
   4991 
   4992 /***********************************************************************************************
   4993  * UnitClass::Should_Crush_It -- Determines if this unit should crush an object.               *
   4994  *                                                                                             *
   4995  *    Call this routine to determine if this unit should crush the object specified. The       *
   4996  *    test for crushable action depends on proximity and ability of the unit. If a unit        *
   4997  *    should crush the object, then it should be given a movement order to enter the cell      *
   4998  *    where the object is located.                                                             *
   4999  *                                                                                             *
   5000  * INPUT:   it -- The object to see if it should be crushed.                                   *
   5001  *                                                                                             *
   5002  * OUTPUT:  bool; Should "it" be crushed by this unit?                                         *
   5003  *                                                                                             *
   5004  * WARNINGS:   none                                                                            *
   5005  *                                                                                             *
   5006  * HISTORY:                                                                                    *
   5007  *   07/29/1996 JLB : Created.                                                                 *
   5008  *=============================================================================================*/
   5009 bool UnitClass::Should_Crush_It(TechnoClass const * it) const
   5010 {
   5011 	assert(IsActive);
   5012 
   5013 	/*
   5014 	**	If this unit cannot crush anything or the candidate object cannot be crushed,
   5015 	**	then it obviously should not try to crush it -- return negative answer.
   5016 	*/
   5017 	if (!Class->IsCrusher || it == NULL || !it->Techno_Type_Class()->IsCrushable) return(false);
   5018 
   5019 	/*
   5020 	**	Objects that are far away should really be fired upon rather than crushed.
   5021 	*/
   5022 	if (Distance(it) > Rule.CrushDistance) return(false);
   5023 
   5024 	/*
   5025 	**	Human controlled units don't automatically crush. Neither do computer controlled ones
   5026 	**	if they are at difficult setting.
   5027 	*/
   5028 	if (House->IsHuman || House->Difficulty == DIFF_HARD) return(false);
   5029 
   5030 	/*
   5031 	**	If the weapon this unit is equipped with is very good against crushable objects then
   5032 	**	fire the weapon instead. It is presumed that a wood destroying weapon is good against
   5033 	**	most crushable object types (infantry).
   5034 	*/
   5035 	if (Class->PrimaryWeapon != NULL && Class->PrimaryWeapon->WarheadPtr->IsWoodDestroyer) return(false);
   5036 
   5037 	/*
   5038 	**	If the house IQ indicates that crushing should not be allowed, then don't
   5039 	**	suggest that crushing be done.
   5040 	*/
   5041 	if (House->IQ < Rule.IQCrush) return(false);
   5042 
   5043 	/*
   5044 	** Don't allow crushing of spies by computer-controlled vehicles.
   5045 	*/
   5046 	if (it->What_Am_I() == RTTI_INFANTRY && *(InfantryClass *)it == INFANTRY_SPY) {
   5047 		return(false);
   5048 	}
   5049 
   5050 	return(true);
   5051 }
   5052 
   5053 
   5054 /***********************************************************************************************
   5055  * UnitClass::Scatter -- Causes the unit to scatter to a nearby location.                      *
   5056  *                                                                                             *
   5057  *    This scatter logic will actually look for a nearby location rather than an adjacent      *
   5058  *    free location. This is necessary because sometimes a unit is required to scatter more    *
   5059  *    than one cell. A vehicle on a service depot is a prime example.                          *
   5060  *                                                                                             *
   5061  * INPUT:   threat   -- The coordinate that a potential threat resides. If this is a non       *
   5062  *                      threat related scatter, then this parameter will be zero.              *
   5063  *                                                                                             *
   5064  *          forced   -- Should the scatter be performed even if it would be otherwise          *
   5065  *                      inconvenient?                                                          *
   5066  *                                                                                             *
   5067  *          nokidding-- Should the scatter be performed even if it would otherwise be          *
   5068  *                      illegal?                                                               *
   5069  *                                                                                             *
   5070  * OUTPUT:  none                                                                               *
   5071  *                                                                                             *
   5072  * WARNINGS:   none                                                                            *
   5073  *                                                                                             *
   5074  * HISTORY:                                                                                    *
   5075  *   10/02/1996 JLB : Created.                                                                 *
   5076  *=============================================================================================*/
   5077 void UnitClass::Scatter(COORDINATE threat, bool forced, bool nokidding)
   5078 {
   5079 	assert(IsActive);
   5080 
   5081 	if (Mission == MISSION_SLEEP || Mission == MISSION_STICKY || Mission == MISSION_UNLOAD) return;
   5082 
   5083 	/*
   5084 	**	Certain missions prevent scattering regardless of whether it would be
   5085 	**	a good idea or not.
   5086 	*/
   5087 	if (!MissionControl[Mission].IsScatter && !forced) return;
   5088 
   5089 	if (PrimaryFacing.Is_Rotating()) return;
   5090 //	if (IsRotating) return;
   5091 
   5092 	if (Target_Legal(NavCom) && !nokidding) return;
   5093 
   5094 	if (threat == 0) {
   5095 		Assign_Destination(::As_Target(Map.Nearby_Location(Coord_Cell(Coord), Class->Speed)));
   5096 	} else {
   5097 		DriveClass::Scatter(threat, forced, nokidding);
   5098 	}
   5099 }
   5100 
   5101 
   5102 /***********************************************************************************************
   5103  * UnitClass::Limbo -- Limbo this unit.                                                        *
   5104  *                                                                                             *
   5105  *    This will cause the unit to go into a limbo state. If it was carrying a flag, then       *
   5106  *    the flag will be dropped where the unit is at.                                           *
   5107  *                                                                                             *
   5108  * INPUT:   none                                                                               *
   5109  *                                                                                             *
   5110  * OUTPUT:  bool; Was this unit limboed?                                                       *
   5111  *                                                                                             *
   5112  * WARNINGS:   none                                                                            *
   5113  *                                                                                             *
   5114  * HISTORY:                                                                                    *
   5115  *   10/08/1996 JLB : Created.                                                                 *
   5116  *=============================================================================================*/
   5117 bool UnitClass::Limbo(void)
   5118 {
   5119 	if (DriveClass::Limbo()) {
   5120 		if (Flagged != HOUSE_NONE) {
   5121 			HouseClass::As_Pointer(Flagged)->Flag_Attach(Coord_Cell(Coord));
   5122 			Flagged = HOUSE_NONE;
   5123 		}
   5124 		return(true);
   5125 	}
   5126 	return(false);
   5127 }
   5128 
   5129 
   5130 
   5131 /***********************************************************************************************
   5132  * UnitClass::Apply_Temporary_Jamming_Shroud -- Apply a temporary gap generator shroud effect  *
   5133  *                                                                                             *
   5134  *    This is intended as a temporary effect that is active only during export of the          *
   5135  *    shroud data                                                                              *
   5136  *                                                                                             *
   5137  * INPUT:   House to apply effect for                                                          *
   5138  *                                                                                             *
   5139  * OUTPUT:  Bitmask of cells that effect was applied to                                        *
   5140  *                                                                                             *
   5141  * WARNINGS:   none                                                                            *
   5142  *                                                                                             *
   5143  * HISTORY:                                                                                    *
   5144  *   8/19/2020 12:13PM ST : Created.                                                           *
   5145  *=============================================================================================*/
   5146 unsigned int UnitClass::Apply_Temporary_Jamming_Shroud(HouseClass *house_to_apply_for)
   5147 {
   5148 	unsigned int shroud_bits_applied = 0;
   5149 
   5150 	if (!IsActive || !Strength) {
   5151 		return shroud_bits_applied;
   5152 	}
   5153 
   5154 	if (!Class->IsGapper) {
   5155 		return shroud_bits_applied;
   5156 	}
   5157 
   5158 	CELL shroud_center = Coord_Cell(Center_Coord());
   5159 	int centerx = Cell_X(shroud_center);
   5160 	int centery = Cell_Y(shroud_center);
   5161 	CELL trycell;
   5162 
   5163 	for (int index = 0; index < 31; index++) {
   5164 		shroud_bits_applied <<= 1;
   5165 		trycell = XY_Cell(centerx + _GapShroudXTable[index], centery + _GapShroudYTable[index]);
   5166 		if (Map[trycell].Is_Mapped(house_to_apply_for)) {
   5167 			Map.Jam_Cell(trycell, House);
   5168 			shroud_bits_applied |= 1;
   5169 		}
   5170 	}
   5171 
   5172 	if (shroud_bits_applied) {
   5173 		Map.Constrained_Look(Coord, 5 * CELL_LEPTON_W, house_to_apply_for);
   5174 	}
   5175 	
   5176 	return shroud_bits_applied;
   5177 }	
   5178 	
   5179 	
   5180 			  
   5181 /***********************************************************************************************
   5182  * UnitClass::Unapply_Temporary_Jamming_Shroud -- Remove temporary gap generator shroud effect *
   5183  *                                                                                             *
   5184  *    Remove gap effect added by Apply_Temporary_Jamming_Shroud                                *
   5185  *                                                                                             *
   5186  * INPUT:   House to unapply effect for                                                        *
   5187  *          Bitmask of cells that effect was applied to                                        *
   5188  *                                                                                             *
   5189  * OUTPUT:                                                                                     *
   5190  *                                                                                             *
   5191  * WARNINGS:   none                                                                            *
   5192  *                                                                                             *
   5193  * HISTORY:                                                                                    *
   5194  *   8/19/2020 12:16PM ST : Created.                                                           *
   5195  *=============================================================================================*/
   5196 void UnitClass::Unapply_Temporary_Jamming_Shroud(HouseClass *house_to_unapply_for, unsigned int shroud_bits_applied)
   5197 {
   5198 	if (!IsActive || !Strength) {
   5199 		return;
   5200 	}
   5201 
   5202 	if (!Class->IsGapper) {
   5203 		return;
   5204 	}
   5205 
   5206 	CELL shroud_center = Coord_Cell(Center_Coord());
   5207 	int centerx = Cell_X(shroud_center);
   5208 	int centery = Cell_Y(shroud_center);
   5209 	CELL trycell;
   5210 
   5211 	for (int index = 30; index >= 0 && shroud_bits_applied; index--) {
   5212 		if (shroud_bits_applied & 1) {
   5213 			trycell = XY_Cell(centerx + _GapShroudXTable[index], centery + _GapShroudYTable[index]);
   5214 			Map.UnJam_Cell(trycell, House);
   5215 			Map.Map_Cell(trycell, house_to_unapply_for);
   5216 		}
   5217 		shroud_bits_applied >>= 1;
   5218 	}
   5219 }	
   5220 
   5221 
   5222 
   5223 /*
   5224 ** Updated for client/server multiplayer - ST 8/12/2019 11:46AM
   5225 */
   5226 void UnitClass::Shroud_Regen(void)
   5227 {
   5228 	if (Class->IsGapper/*KO && !House->IsPlayerControl*/) {
   5229 		
   5230 		int index;
   5231 		int centerx, centery;
   5232 		CELL trycell;
   5233 
   5234 		if (Session.Type != GAME_GLYPHX_MULTIPLAYER || Is_Legacy_Render_Enabled()) {
   5235 			// Only restore under the shroud if it's a valid field.
   5236 			if (ShroudBits != (unsigned)-1L) {
   5237 				centerx = Cell_X(ShroudCenter);
   5238 				centery = Cell_Y(ShroudCenter);
   5239 				for (index = 30; index >= 0 && ShroudBits; index--) {
   5240 					if (ShroudBits & 1) {
   5241 						trycell = XY_Cell(centerx + _GapShroudXTable[index], centery + _GapShroudYTable[index]);
   5242 	#if(0)
   5243 						Map.Map_Cell(trycell, PlayerPtr);
   5244 	#else
   5245 					Map.UnJam_Cell(trycell, House);
   5246 					Map.Map_Cell(trycell, House);
   5247 	#endif
   5248 					}
   5249 					ShroudBits >>= 1;
   5250 				}
   5251 			}
   5252 
   5253 			if(IsActive && Strength) {
   5254 				// Now shroud around the new center
   5255 				ShroudBits = 0L;
   5256 				ShroudCenter = Coord_Cell(Center_Coord());
   5257 				centerx = Cell_X(ShroudCenter);
   5258 				centery = Cell_Y(ShroudCenter);
   5259 				for (index = 0; index < 31; index++) {
   5260 					ShroudBits <<= 1;
   5261 					trycell = XY_Cell(centerx + _GapShroudXTable[index], centery + _GapShroudYTable[index]);
   5262 					if (Map[trycell].Is_Mapped(House)) {
   5263 						Map.Jam_Cell(trycell, House);
   5264 						ShroudBits |= 1;
   5265 					}
   5266 				}
   5267 			}
   5268 		}
   5269 
   5270 		/*
   5271 		** Updated for client/server multiplayer. ST - 8/12/2019 3:25PM
   5272 		*/
   5273 		if (Session.Type != GAME_GLYPHX_MULTIPLAYER) {
   5274 			if (House->IsPlayerControl) {
   5275 				Map.Constrained_Look(Coord, 5 * CELL_LEPTON_W, PlayerPtr);
   5276 			}
   5277 		
   5278 		} else {
   5279 		
   5280 			if (Is_Legacy_Render_Enabled()) {
   5281 				for (int i = 0; i < Session.Players.Count(); i++) {
   5282 					HouseClass *player_house = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
   5283 					if (player_house->IsHuman && player_house != House) {
   5284 						Map.Constrained_Look(Coord, 5 * CELL_LEPTON_W, player_house);
   5285 					}
   5286 				}
   5287 			}
   5288 		}
   5289 	}
   5290 }
   5291 
   5292 
   5293 /***********************************************************************************************
   5294  * UnitClass::Mission_Guard_Area -- Guard area logic for units.                                *
   5295  *                                                                                             *
   5296  *    This logic is similar to normal guard area except that APCs owned by the computer will   *
   5297  *    try to load up with nearby infantry. This will give the computer some fake intelligence  *
   5298  *    when playing in skirmish mode.                                                           *
   5299  *                                                                                             *
   5300  * INPUT:   none                                                                               *
   5301  *                                                                                             *
   5302  * OUTPUT:  Returns with the delay to use before calling this routine again.                   *
   5303  *                                                                                             *
   5304  * WARNINGS:   none                                                                            *
   5305  *                                                                                             *
   5306  * HISTORY:                                                                                    *
   5307  *   11/03/1996 JLB : Created.                                                                 *
   5308  *=============================================================================================*/
   5309 int UnitClass::Mission_Guard_Area(void)
   5310 {
   5311 	assert(IsActive);
   5312 
   5313 	/*
   5314 	**	Check to see if this is an APC that is largely empty and not otherwise doing anything.
   5315 	**	Such an APC should load up with infantry.
   5316 	*/
   5317 	if (Session.Type != GAME_NORMAL &&
   5318 #ifdef FIXIT_PHASETRANSPORT	//	checked - ajw 9/28/98
   5319 			(*this == UNIT_APC || *this == UNIT_PHASE ) &&
   5320 #else
   5321 			*this == UNIT_APC &&
   5322 #endif
   5323 			!Target_Legal(TarCom) &&
   5324 			!In_Radio_Contact() &&
   5325 			House->Which_Zone(this) != ZONE_NONE &&
   5326 			!House->IsHuman) {
   5327 
   5328 
   5329 		int needed = Class->Max_Passengers() - How_Many();
   5330 		for (int index = 0; index < Infantry.Count(); index++) {
   5331 			if (needed == 0) break;
   5332 
   5333 			InfantryClass * infantry = Infantry.Ptr(index);
   5334 
   5335 			if (infantry != NULL &&
   5336 					infantry->IsActive &&
   5337 					!infantry->IsInLimbo &&
   5338 					infantry->Strength > 0 &&
   5339 					infantry->House == House &&
   5340 					!Target_Legal(infantry->TarCom) &&
   5341 					!Target_Legal(infantry->NavCom) &&
   5342 					Distance(infantry) < 7 * CELL_LEPTON_W &&
   5343 					(infantry->Mission == MISSION_GUARD || infantry->Mission == MISSION_GUARD_AREA)) {
   5344 
   5345 				infantry->Assign_Mission(MISSION_ENTER);
   5346 				infantry->ArchiveTarget = As_Target();
   5347 				needed--;
   5348 			}
   5349 		}
   5350 	}
   5351 	return(DriveClass::Mission_Guard_Area());
   5352 }