CnC_Remastered_Collection/TIBERIANDAWN/FOOT.CPP

2098 lines
105 KiB
C++
Raw Normal View History

//
// Copyright 2020 Electronic Arts Inc.
//
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
// software: you can redistribute it and/or modify it under the terms of
// the GNU General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
// in the hope that it will be useful, but with permitted additional restrictions
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
// distributed with this program. You should have received a copy of the
// GNU General Public License along with permitted additional restrictions
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
/* $Header: F:\projects\c&c\vcs\code\foot.cpv 2.17 16 Oct 1995 16:51:42 JOE_BOSTIC $ */
/***********************************************************************************************
*** 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 ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : FOOT.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : April 22, 1994 *
* *
* Last Update : August 13, 1995 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* FootClass::Active_Click_With -- Intiates attack or move according to target clicked on. *
* FootClass::Active_Click_With -- Performs action as a result of left mouse click. *
* FootClass::Approach_Target -- Sets the navigation computer to approach target object. *
* FootClass::Assign_Destination -- Assigns specified destination to NavCom. *
* FootClass::Assign_Mission -- Assign mission to foot class object. *
* FootClass::Basic_Path -- Finds the basic path for a ground object. *
* FootClass::Body_Facing -- Set the body rotation/facing. *
* FootClass::Can_Demolish -- Checks to see if this object can be sold back. *
* FootClass::Can_Enter_Cell -- Checks to see if the object can enter cell specified. *
* FootClass::Death_Announcement -- Announces the death of a unit. *
* FootClass::Debug_Dump -- Displays the status of the FootClass to the mono monitor. *
* FootClass::Detach -- Detaches a target from tracking systems. *
* FootClass::Detach_All -- Removes this object from the game system. *
* FootClass::Enters_Building -- When unit enters a building for some reason. *
* FootClass::FootClass -- Default constructor for foot class objects. *
* FootClass::FootClass -- Normal constructor for the foot class object. *
* FootClass::Greatest_Threat -- Fetches the greatest threat to this object. *
* FootClass::Likely_Coord -- Fetches the coordinate the object will be at shortly. *
* FootClass::Limbo -- Intercepts limbo event and handles FootClass processing. *
* FootClass::Mark -- Unit interface to map rendering system. *
* FootClass::Mission_Attack -- AI for heading towards and firing upon target. *
* FootClass::Mission_Capture -- Handles the capture mission. *
* FootClass::Mission_Enter -- Enter (cooperatively) mission handler. *
* FootClass::Mission_Guard_Area -- Causes unit to guard an area about twice weapon range. *
* FootClass::Mission_Hunt -- Handles the default hunt order. *
* FootClass::Mission_Move -- AI process for moving a vehicle to its destination. *
* FootClass::Offload_Tiberium_Bail -- Fetches the Tiberium to offload per step. *
* FootClass::Override_Mission -- temporarily overides a units mission *
* FootClass::Per_Cell_Process -- Perform action based on once-per-cell condition. *
* FootClass::Receive_Message -- Movement related radio messages are handled here. *
* FootClass::Rescue_Mission -- Calls this unit to the rescue. *
* FootClass::Restore_Mission -- Restores an overidden mission *
* FootClass::Sell_Back -- Causes this object to be sold back. *
* FootClass::Set_Speed -- Initiate unit movement physics. *
* FootClass::Sort_Y -- Determine the sort coordinate for foot class objects. *
* FootClass::Start_Driver -- This starts the driver heading to the destination desired. *
* FootClass::Stop_Driver -- This routine clears the driving state of the object. *
* FootClass::Stun -- Prepares a ground travelling object for removal. *
* FootClass::Take_Damage -- Handles taking damage to this object. *
* FootClass::Unlimbo -- Unlimbos object and performs special fixups. *
* FootClass::~FootClass -- Default destructor for foot class objects. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***********************************************************************************************
* FootClass::FootClass -- Default constructor for foot class objects. *
* *
* This is the default constructor for FootClass objects. It sets the foot class values to *
* their default starting settings. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/23/1994 JLB : Created. *
*=============================================================================================*/
FootClass::FootClass(void) : Speed(0)
{
IsDriving = false;
IsInitiated = false;
IsPlanningToLook = false;
IsDeploying = false;
IsNewNavCom = false;
IsFiring = false;
IsRotating = false;
IsUnloading = false;
NavCom = TARGET_NONE;
SuspendedNavCom = TARGET_NONE;
Path[0] = FACING_NONE;
HeadToCoord = NULL;
Member = 0;
Team = 0;
PathDelay = 0;
TryTryAgain = PATH_RETRY;
if (House) {
House->CurUnits++;
}
Group = -1;
}
/***********************************************************************************************
* FootClass::~FootClass -- Default destructor for foot class objects. *
* *
* At this level of the destruction process, the house record of the number of units *
* currently in inventory is decremented to reflect this units destruction. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/10/1995 JLB : Created. *
*=============================================================================================*/
FootClass::~FootClass(void)
{
if (GameActive && House) {
House->CurUnits--;
}
}
/***********************************************************************************************
* FootClass::FootClass -- Normal constructor for the foot class object. *
* *
* This is the normal constructor used when creating a foot class object. *
* *
* INPUT: house -- The house that owns this object. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/29/1994 JLB : Created. *
*=============================================================================================*/
FootClass::FootClass(HousesType house) :
TechnoClass(house),
Speed(0)
{
Member = 0;
Team = 0;
Path[0] = FACING_NONE;
NavCom = TARGET_NONE;
SuspendedNavCom = TARGET_NONE;
IsUnloading = false;
IsDriving = false;
IsInitiated = false;
IsRotating = false;
IsFiring = false;
IsDeploying = false;
IsNewNavCom = false;
IsPlanningToLook = false;
HeadToCoord = 0L;
PathDelay = 0;
Group = -1;
TryTryAgain = PATH_RETRY;
House->CurUnits++;
}
#ifdef CHEAT_KEYS
/***********************************************************************************************
* FootClass::Debug_Dump -- Displays the status of the FootClass to the mono monitor. *
* *
* This routine is used to output the current status of the foot class to the mono *
* monitor. Through this display bugs may be tracked down or eliminated. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/02/1994 JLB : Created. *
* 07/04/1995 JLB : Handles aircraft special case. *
*=============================================================================================*/
void FootClass::Debug_Dump(MonoClass *mono) const
{
static char const * _p2c[9] = {"-","0","1","2","3","4","5","6","7"};
#define Path_To_String(a) _p2c[((ABS((int)a+1))%9)]
/*
** Display the common data for all objects that inherity from FootClass.
*/
mono->Set_Cursor(63, 7);
if (Team) {
mono->Printf("%s(%d)", Team->Class->IniName, Teams.ID(Team));
} else {
mono->Printf("(none)");
}
mono->Set_Cursor(73, 7);mono->Printf("%04X", ArchiveTarget);
mono->Set_Cursor(42, 1);mono->Printf("%04X", NavCom);
mono->Set_Cursor(44, 3);mono->Printf("%d", Speed);
/*
** Although aircraft inherit from FootClass, some of the variables are not
** used and thus should not be displayed.
*/
if (What_Am_I() != RTTI_AIRCRAFT) {
mono->Set_Cursor(50, 3);
mono->Printf("%s%s%s%s%s%s%s%s%s%s%s%s",
Path_To_String(Path[0]),
Path_To_String(Path[1]),
Path_To_String(Path[2]),
Path_To_String(Path[3]),
Path_To_String(Path[4]),
Path_To_String(Path[5]),
Path_To_String(Path[6]),
Path_To_String(Path[7]),
Path_To_String(Path[8]),
Path_To_String(Path[9]),
Path_To_String(Path[10]),
Path_To_String(Path[11]),
Path_To_String(Path[12]));
mono->Set_Cursor(65, 1);mono->Printf("%08lX", Head_To_Coord());
mono->Text_Print("X", 16 + (IsDeploying?2:0), 12);
mono->Text_Print("X", 16 + (IsRotating?2:0), 13);
mono->Text_Print("X", 16 + (IsDriving?2:0), 15);
mono->Text_Print("X", 16 + (IsFiring?2:0), 14);
mono->Text_Print("X", 16 + (IsPlanningToLook?2:0), 16);
}
TechnoClass::Debug_Dump(mono);
}
#endif
/***********************************************************************************************
* FootClass::Set_Speed -- Initiate unit movement physics. *
* *
* This routine is used to set a unit's velocity control structure. *
* The game will then process the unit's movement during the momentum *
* physics calculation. *
* *
* INPUT: unit -- Pointer to the unit to alter. *
* *
* speed -- Throttle setting (0=stop, 255=full throttle). *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/07/1992 JLB : Created. *
* 09/24/1993 JLB : Revised for faster speed. *
* 04/02/1994 JLB : Revised for new system. *
* 04/15/1994 JLB : Converted to member function. *
* 07/21/1994 JLB : Simplified. *
*=============================================================================================*/
void FootClass::Set_Speed(int speed)
{
speed &= 0xFF;
((unsigned char &)Speed) = speed;
}
/***********************************************************************************************
* FootClass::Mark -- Unit interface to map rendering system. *
* *
* This routine is the interface function for units as they relate to *
* the map rendering system. Whenever a unit's imagery changes, this *
* function is called. *
* *
* INPUT: mark -- Type of image change (MARK_UP, _DOWN, _CHANGE) *
* MARK_UP -- Unit is removed. *
* MARK_CHANGE -- Unit alters image but doesn't move. *
* MARK_DOWN -- Unit is overlaid onto existing icons. *
* *
* OUTPUT: bool; Did the marking operation succeed? Failure could be the result of marking *
* down when it is already down, or visa versa. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/14/1991 JLB : Created. *
* 04/15/1994 JLB : Converted to member function. *
* 12/23/1994 JLB : Performs low level check before processing. *
*=============================================================================================*/
bool FootClass::Mark(MarkType mark)
{
if (TechnoClass::Mark(mark)) {
CELL cell = Coord_Cell(Coord);
/*
** Inform the map of the refresh, occupation, and overlap
** request.
** Special case is fixed-wing aircraft, which are never placed
** or picked up since they can never land.
*/
switch (mark) {
case MARK_UP:
if (What_Am_I() != RTTI_AIRCRAFT || !((AircraftClass*)this)->Class->IsFixedWing) {
Map.Pick_Up(cell, this);
}
break;
case MARK_DOWN:
if (What_Am_I() != RTTI_AIRCRAFT || !((AircraftClass*)this)->Class->IsFixedWing) {
Map.Place_Down(cell, this);
}
break;
default:
Map.Refresh_Cells(cell, Overlap_List());
Map.Refresh_Cells(cell, Occupy_List());
break;
}
return(true);
}
return(false);
}
/***********************************************************************************************
* FootClass::Basic_Path -- Finds the basic path for a ground object. *
* *
* This is a common routine used by both infantry and other ground travelling units. It *
* will fill in the unit's basic path to the NavCom destination. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Was a path found? A failure to find a path means either the target cannot *
* be found or the terrain prohibits the unit's movement. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/17/1994 JLB : Created. *
*=============================================================================================*/
bool FootClass::Basic_Path(void)
{
PathType *path; // Pointer to path control structure.
CELL cell;
int skip_path = false;
Path[0] = FACING_NONE;
if (Target_Legal(NavCom)) {
cell = As_Cell(NavCom);
/*
** When the navigation computer is set to a location that is impassible, then
** find a nearby cell that can be entered and try to head toward that instead.
** EXCEPT when that cell is very close -- then just bail.
*/
// IsFindPath = true;
if (Can_Enter_Cell(cell) == MOVE_NO && Distance(NavCom) > 0x0300) {
static int _faceadjust[8] = {0, 1, -1, 2, -2, 3, -3, 4};
FacingType f2 = (FacingType)(((unsigned)::Direction(cell, Coord_Cell(Coord)))>>5);
for (unsigned index = 0; index < (sizeof(_faceadjust) / sizeof(_faceadjust[0])); index++) {
CELL cell2;
cell2 = Adjacent_Cell(cell, (FacingType)((f2+_faceadjust[index])&0x7));
if (Can_Enter_Cell(cell2, FACING_NONE) <= MOVE_CLOAK) {
cell = cell2;
break;
}
}
}
// IsFindPath = false;
#ifdef SPECIAL
if (What_Am_I() == RTTI_INFANTRY) {
CELL mycell = Coord_Cell(Center_Coord());
// Mark(MARK_UP);
ObjectClass *obj = Map[mycell].Cell_Occupier();
while (obj) {
if (obj != this && obj->What_Am_I() == RTTI_INFANTRY) {
InfantryClass *inf = (InfantryClass *)obj;
if (inf->NavCom == NavCom && inf->Path[0] != FACING_NONE) {
if (Coord_Cell(inf->Head_To_Coord()) == Coord_Cell(inf->Coord)) {
Mem_Copy(&inf->Path[1], Path, sizeof(Path)-sizeof(Path[0]));
} else {
Mem_Copy(inf->Path, Path, sizeof(Path));
}
if (Path[0] != FACING_NONE) {
skip_path = true;
}
break;
}
}
obj = obj->Next;
}
// Mark(MARK_DOWN);
}
#endif
if (!skip_path) {
Mark(MARK_UP);
Path[0] = FACING_NONE; // Probably not necessary, but...
/*
** Try to find a path to the destination. If a failure occurs, then keep trying
** with greater determination until either a complete failure occurs, or a decent
** path was found.
*/
bool found1=false; // Found a best path yet?
PathType path1;
FacingType workpath1[200]; // Staging area for path list.
FacingType workpath2[200]; // Staging area for path list.
MoveType maxtype = MOVE_TEMP;
if (!House->IsHuman) {
maxtype = MOVE_DESTROYABLE;
} else {
/*
** For simple movement missions by the human player, then don't
** consider friendly units as passable if close to the destination.
** This will prevent a human controlled unit from just sitting next
** to a destination just because there is another friendly unit
** occupying the destination location.
*/
if (Mission == MISSION_MOVE && Distance(NavCom) < 0x0280) {
maxtype = MOVE_DESTROYABLE;
}
}
/*
** Determine if ANY path could be calculated by first examining the most
** aggressive case. If this fails, then no path will succeed. Further
** scanning is unnecessary.
*/
path = Find_Path(cell, &workpath1[0], sizeof(workpath1), maxtype);
if (path && path->Cost) {
memcpy(&path1, path, sizeof(path1));
found1 = true;
/*
** Scan for the best path possible. If this succeeds, then do a simple
** comparison with the most agressive path. If they are very close, then
** go with the best (easiest) path method.
*/
path = Find_Path(cell, &workpath2[0], sizeof(workpath2), MOVE_CLOAK);
if (path && path->Cost && path->Cost < MAX((path1.Cost + (path1.Cost/2)), 3)) {
memcpy(&path1, path, sizeof(path1));
memcpy(workpath1, workpath2, sizeof(workpath1));
} else {
/*
** The easiest path method didn't result in a satisfactory path. Scan through
** the rest of the path options, looking for the best one.
*/
for (MoveType move = MOVE_MOVING_BLOCK; move < maxtype; move++) {
path = Find_Path(cell, &workpath2[0], sizeof(workpath2), move);
if (path && path->Cost && path->Cost < MAX((path1.Cost + (path1.Cost/2)), 3)) {
memcpy(&path1, path, sizeof(path1));
memcpy(workpath1, workpath2, sizeof(workpath1));
}
}
}
}
#ifdef OBSOLETE
for (MoveType move = MOVE_CLOAK; move <= maxtype; move++) {
if (!found1) {
path = Find_Path(cell, &workpath1[0], sizeof(workpath1), move);
if (path && path->Cost) {
memcpy(&path1, path, sizeof(path1));
found1 = true;
if (path1.Cost < 5) break;
}
} else {
path = Find_Path(cell, &workpath2[0], sizeof(workpath2), move);
if (path) {
if (path->Cost && path->Cost <= path1.Cost/2) {
memcpy(&path1, path, sizeof(path1));
memcpy(workpath1, workpath2, sizeof(workpath1));
}
}
}
}
#endif
/*
** If a good path was found, then record it in the object's path
** list.
*/
if (found1) {
Fixup_Path(&path1);
memcpy(&Path[0], &workpath1[0], MIN(path->Length, (int)sizeof(Path)));
}
Mark(MARK_DOWN);
}
#ifdef NEVER
/*
** Patch at this point to see if we are moving directly into a
** MOVE_TEMP. This allows units to bunch up at a bridge even if there
** is an enormously long way around. This also allows units to give
** up trying to move into the MOVE_TEMP using the normal movement
** retry logic.
*/
CELL cell = Adjacent_Cell(Coord_Cell(Coord), Path[0]);
if (Can_Enter_Cell(cell, FACING_NONE) == MOVEF_TEMP) {
Path[0] = FACING_NONE;
}
#endif
PathDelay = PATH_DELAY;
if (Path[0] != FACING_NONE) return(true);
/*
** If a basic path couldn't be determined, then abort the navigation process.
*/
// NavCom = TARGET_NONE;
Stop_Driver();
}
return(false);
}
/***********************************************************************************************
* FootClass::Mission_Move -- AI process for moving a vehicle to its destination. *
* *
* This simple AI script handles moving the vehicle to its desired destination. Since *
* simple movement is handled directly by the engine, this routine merely waits until *
* the unit has reached its destination, and then causes the unit to enter idle mode. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the delay before calling this routine again. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/18/1994 JLB : Created. *
*=============================================================================================*/
int FootClass::Mission_Move(void)
{
if (!Target_Legal(NavCom) && !IsDriving && MissionQueue == MISSION_NONE) {
Enter_Idle_Mode();
}
if (!Target_Legal(TarCom) && !House->IsHuman) {
Target_Something_Nearby(THREAT_RANGE);
}
return(TICKS_PER_SECOND+3);
}
/***********************************************************************************************
* FootClass::Mission_Capture -- Handles the capture mission. *
* *
* Capture missions are nearly the same as normal movement missions. The only difference *
* is that the final destination is handled in a special way so that it is not marked as *
* impassable. This allows the object (usually infantry) the ability to walk onto the *
* object and thus capture it. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the number of game ticks to delay before calling this routine. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/19/1995 JLB : Created. *
*=============================================================================================*/
int FootClass::Mission_Capture(void)
{
if (!Target_Legal(NavCom) && !In_Radio_Contact()) {
Enter_Idle_Mode();
if (Map[Coord_Cell(Center_Coord())].Cell_Building()) {
Scatter(0, true);
}
}
return(TICKS_PER_SECOND-2);
}
/***********************************************************************************************
* FootClass::Mission_Attack -- AI for heading towards and firing upon target. *
* *
* This AI routine handles heading to within range of the target and then firing upon *
* it until it is destroyed. If the target is destroyed, then the unit will change *
* missions to match its "idle mode" of operation (usually guarding). *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the delay before calling this routine again. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/18/1994 JLB : Created. *
*=============================================================================================*/
int FootClass::Mission_Attack(void)
{
if (Target_Legal(TarCom)) {
Approach_Target();
} else {
Enter_Idle_Mode();
}
return(TICKS_PER_SECOND+2);
}
/***********************************************************************************************
* FootClass::Mission_Guard -- Handles the AI for guarding in place. *
* *
* Units that are performing stationary guard duty use this AI process. They will sit *
* still and target any enemies that get within range. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the delay before calling this routine again. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/18/1994 JLB : Created. *
*=============================================================================================*/
int FootClass::Mission_Guard(void)
{
if (!Target_Something_Nearby(THREAT_RANGE)) {
Random_Animate();
}
return(TICKS_PER_SECOND+Random_Picky((int)0, (int)4, (char*)NULL, (int)0));
}
/***********************************************************************************************
* FootClass::Mission_Hunt -- Handles the default hunt order. *
* *
* This routine is the default hunt order for game objects. It handles searching for a *
* nearby object and heading toward it. The act of targetting will cause it to attack *
* the target it selects. *
* *
* INPUT: none *
* *
* OUTPUT: Returns the game tick delay before calling this routine again. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/17/1994 JLB : Created. *
*=============================================================================================*/
int FootClass::Mission_Hunt(void)
{
if (!Target_Something_Nearby(THREAT_NORMAL)) {
Random_Animate();
} else {
if (What_Am_I() == RTTI_INFANTRY && ((InfantryTypeClass const &)Class_Of()).Type == INFANTRY_E7) {
Assign_Destination(TarCom);
Assign_Mission(MISSION_CAPTURE);
} else {
Approach_Target();
}
}
return(TICKS_PER_SECOND+5);
}
/***********************************************************************************************
* FootClass::Mission_Timed_Hunt -- This is the AI process for multiplayer computer units. *
* *
* For multiplayer games, the computer AI can't just blitz the human players; the humans *
* need a little time to set up their base, or whatever. This state just waits for *
* a certain period of time, then goes into hunt mode. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the delay before calling this routine again. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/18/1994 JLB : Created. *
*=============================================================================================*/
int FootClass::Mission_Timed_Hunt(void)
{
int rndmax;
int changed = 0; // has the unit changed into Hunt mode?
if (!House->IsHuman) {
/*
** Jump into HUNT mode if we're supposed to Blitz, and the EndCountDown
** has expired, or if our owning house has lost more than 1/4 of its units
** (it gets mad at you)
*/
if ( (MPlayerBlitz && House->BlitzTime==0) ||
House->CurUnits < ((House->MaxUnit * 4) / 5)) {
Assign_Mission(MISSION_HUNT);
changed = 1;
}
/*
** Jump into HUNT mode on a random die roll; the computer units will periodically
** "snap out" of their daze, and begin hunting. Try to time it so that all
** units will be hunting within 10 minutes (600 calls to this routine).
*/
if (MPlayerBases) {
rndmax = 5000;
} else {
rndmax = 1000;
}
if (IRandom(0,rndmax) == 1) {
Assign_Mission(MISSION_HUNT);
changed = 1;
}
/*
** If this unit is still just sitting in Timed Hunt mode, call Guard Area
** so it doesn't just sit there stupidly.
*/
if (!changed) {
Mission_Guard_Area();
}
}
return(TICKS_PER_SECOND+Random_Pick(0, 4)); // call me back in 1 second.
}
/***********************************************************************************************
* FootClass::Stop_Driver -- This routine clears the driving state of the object. *
* *
* This is the counterpart routine to the Start_Driver function. It clears the driving *
* status flags and destination coordinate record. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Was driving stopped? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/17/1994 JLB : Created. *
* 12/12/1994 JLB : Greatly simplified. *
*=============================================================================================*/
bool FootClass::Stop_Driver(void)
{
if (HeadToCoord) {
HeadToCoord = NULL;
Set_Speed(0);
IsDriving = false;
return(true);
}
return(false);
}
/***********************************************************************************************
* FootClass::Start_Driver -- This starts the driver heading to the destination desired. *
* *
* Before a unit can move it must be started by this routine. This routine handles *
* reserving the cell and setting the driving flag. *
* *
* INPUT: headto -- The coordinate of the immediate drive destination. This is one cell *
* away from the unit's current location. *
* *
* OUTPUT: bool; Was driving initiated? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/17/1994 JLB : Created. *
* 12/12/1994 JLB : Uses simple spot index finder. *
*=============================================================================================*/
bool FootClass::Start_Driver(COORDINATE &headto)
{
Stop_Driver();
if (headto) {
HeadToCoord = headto;
IsDriving = true;
/*
** Check for crate goodie finder here.
*/
if (Map[Coord_Cell(headto)].Goodie_Check(this)) {
return(true);
}
HeadToCoord = NULL;
IsDriving = false;
}
return(false);
}
/***********************************************************************************************
* FootClass::Sort_Y -- Determine the sort coordinate for foot class objects. *
* *
* This routine will determine the sort coordinate for foot class object. This coordinate *
* is usually the coordinate of the object. The exception is if the object is teathered. *
* In this case (presumes offloading to the north), the sorting coordinate is adjusted *
* so that the object will be drawn on top of the transport unit. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the coordinate to use for sorting. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/17/1994 JLB : Created. *
* 11/04/1994 JLB : Sort value is different when unloading from aircraft. *
*=============================================================================================*/
COORDINATE FootClass::Sort_Y(void) const
{
if (IsUnloading) {
return(Coord_Add(Coord, 0x01000000L));
}
if (In_Radio_Contact() && IsTethered && Contact_With_Whom()->What_Am_I() == RTTI_UNIT) {
return(Coord_Add(Coord, 0x01000000L));
}
return(Coord_Add(Coord, 0x00300000L));
}
/***********************************************************************************************
* FootClass::Stun -- Prepares a ground travelling object for removal. *
* *
* This routine clears the units' navigation computer in preparation for removal from the *
* game. This is probably called as a result of unit destruction in combat. Clearing the *
* navigation computer ensures that the normal AI process won't start it moving again while *
* the object is undergoing any death animations. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/23/1994 JLB : Created. *
*=============================================================================================*/
void FootClass::Stun(void)
{
Assign_Destination(TARGET_NONE);
Path[0] = FACING_NONE;
Stop_Driver();
TechnoClass::Stun();
}
/***********************************************************************************************
* FootClass::Approach_Target -- Sets the navigation computer to approach target object. *
* *
* This routine will set the navigation computer to approach the target indicated by the *
* targeting computer. It is through this function that the unit nears the target so *
* that weapon firing may occur. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/31/1994 JLB : Created. *
* 12/13/1994 JLB : Made part of TechnoClass. *
* 12/22/1994 JLB : Enhanced search algorithm. *
* 05/20/1995 JLB : Always approaches if the object is off the map. *
*=============================================================================================*/
void FootClass::Approach_Target(void)
{
/*
** Determine that if there is an existing target it is still legal
** and within range.
*/
if (Target_Legal(TarCom)) {
/*
** If the target is too far away then head toward it.
*/
int maxrange = MAX(Weapon_Range(0), Weapon_Range(1));
if (!Target_Legal(NavCom) && (!In_Range(TarCom) || !IsLocked)) {
// if (!Target_Legal(NavCom) && (Distance(TarCom) > maxrange || !IsLocked)) {
/*
** If the object that we are attacking is a building adjust the units
** max range so that people can stand far away from the buildings and
** hit them.
*/
BuildingClass * obj = As_Building(TarCom);
if (obj) {
maxrange += ((obj->Class->Width() + obj->Class->Height()) * (0x100 / 4));
}
/*
** Adjust the max range of an infantry unit for where he is standing
** in the room.
*/
maxrange -= 0x00B7;
#ifdef OBSOLETE
if (What_Am_I() == RTTI_INFANTRY) {
maxrange -= 0x0111;
} else {
maxrange -= 0x00B7;
}
#endif
maxrange = MAX(maxrange, 0);
COORDINATE tcoord = ::As_Coord(TarCom);
COORDINATE trycoord = 0;
CELL tcell = Coord_Cell(tcoord);
CELL trycell = tcell;
DirType dir = Direction256(tcoord, Center_Coord());
bool found = false;
/*
** Sweep through the cells between the target and the unit, looking for
** a cell that the unit can enter but which is also within weapon range
** of the target. If after a reasonable search, no appropriate cell could
** be found, then the target will be assigned as the movement destination
** and let "the chips fall where they may."
*/
for (int range = maxrange; range > 0x0080; range -= 0x0100) {
static int _angles[] = {0, 8, -8, 16, -16, 24, -24, 32, -32, 48, -48, 64, -64};
for (int index = 0; index < (sizeof(_angles)/sizeof(_angles[0])); index++) {
trycoord = Coord_Move(tcoord, (DirType)(dir + _angles[index]), range);
if (::Distance(trycoord, tcoord) < range) {
trycell = Coord_Cell(trycoord);
if (Can_Enter_Cell(trycell) <= MOVE_CLOAK && Map.In_Radar(trycell)) {
found = true;
break;
}
}
}
if (found) break;
}
/*
** If a suitable intermediate location was found, then head toward it.
** Otherwise, head toward the enemy unit directly.
** Infantry always head towards the target since they can enter a cell
** in range, but still not be able to hit the target if the spot is out of range.
*/
if (found && What_Am_I() != RTTI_INFANTRY) {
Assign_Destination(::As_Target(trycell));
} else {
Assign_Destination(TarCom);
}
}
}
}
/***********************************************************************************************
* FootClass::Mission_Guard_Area -- Causes unit to guard an area about twice weapon range. *
* *
* This mission routine causes the unit to scan for targets out to twice its weapon range *
* from the home point. If a target was found, then it will be attacked. The unit will *
* chase the target until it gets up to to its weapon range from the home position. *
* In that case, it will return to home position and start scanning for another target. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with time delay before calling this routine again. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/23/1994 JLB : Created. *
* 07/27/1995 JLB : Greatly simplified. *
*=============================================================================================*/
int FootClass::Mission_Guard_Area(void)
{
if (What_Am_I() == RTTI_UNIT && ((UnitClass *)this)->Class->IsToHarvest) {
Assign_Mission(MISSION_HARVEST);
return(1+Random_Pick(1, 10));
}
/*
** Ensure that the archive target is valid.
*/
if (!Target_Legal(ArchiveTarget)) {
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
}
/*
** Ensure units aren't trying to guard cells off the map.
*/
if (Target_Legal(NavCom) && Is_Target_Cell(NavCom)) {
CELL cell = As_Cell(NavCom);
int x = Cell_X(cell);
int y = Cell_Y(cell);
if (x < Map.MapCellX || y < Map.MapCellY || x >= (Map.MapCellX + Map.MapCellWidth) || y >= (Map.MapCellY + Map.MapCellHeight)) {
Assign_Target(TARGET_NONE);
Assign_Destination(TARGET_NONE);
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
}
}
/*
** Make sure that the unit has not strayed too far from the home position.
** If it has, then race back to it.
*/
int maxrange = MAX(Weapon_Range(0), Weapon_Range(1))+0x0100;
if (!Target_Legal(NavCom) && (Distance(ArchiveTarget) > maxrange || (!Target_Legal(TarCom) && Distance(ArchiveTarget) > 0x0200))) {
Assign_Target(TARGET_NONE);
Assign_Destination(ArchiveTarget);
}
if (!Target_Legal(TarCom)) {
COORDINATE old = Coord;
Coord = As_Coord(ArchiveTarget);
Target_Something_Nearby(THREAT_AREA);
Coord = old;
if (Target_Legal(TarCom)) return(1);
Command & Conquer Remastered post-launch patch Improvements to harvester resource finding logic. Don't allow the Advanced Comm Center to be capturable in skirmish or multiplayer. Increased failed pathfinding fudge factor. Buildings accept the Guard command if they can attack. Don't allow force capturing of ally structures. Fixes for laser Orcas in S3cr3t M1ss10n. Properly restore them after save. Reset Orcas after loads. Fixed flag animation rendering in CTF. Potentially fix a crash if aircraft are destroyed outside the map bounds. Fixed legacy Obelisk line rendering. Fix out-of-bounds crash in TD; issue was already fixed in RA. Disable capture flag on Commandos. Drop the flag when entering the limbo state. Fixed end game race condition, winning team ID is always sent before individual player win/lose messages. Fixed Chan spawn on SCB10EA. Don't show enter cursor for enemy units on refineries and repair pads. Changing right-click support for first put building on hold, and then subsequenct right-clicks to decrement that queue count for 1x or 5x; Then, 1x or 5x Left click will resume from hold. Don't debug reveal legacy rendering when a player is defeated. Fixed crash when loading saves of custom campaign maps. Reset harvester archived target when given a direct harvest order. Prevent NOD cargo planes from being force attacked. Fixed unit selection on load. Migrated queued repair pad functionality from RA to TD. Randomly animate infantry in area guard mode. Fixed crash accessing inactive objects. Added some walls in SCG08EB to prevent civilians from killing themselves. TD + RA: Audio: Overiding "Our base is under attack" cooldown timing from legacy from 2 minutes to 30 seconds, so it will be heard 4x as often. Fixed adjacent cell out-of-bounds crash issues. Kill player on disconnect Fixed and improved build time calculations to be consistent between TD and RA. Don't show health bars for cloaked Stealth Tanks in the legacy renderer. Fix selection of individual control groups after mixed selection. More adjustments to SCG08EB; switch C7 to C5, and add civilian AI to avoid Tiberium. Extra safety checks for units that have no weapons and aircraft that can't hunt. Fix loading of multiple infantry onto an APC. Additional safety checks for invalid coordinates. Prevent units from being instantly repaired. Fix map passability. Fail Allied mission 5B if the spy re-boards the starting transport (matches 5A and 5C behavior). Fixed multiplayer formation move causing units to move at light speed. Ignore movement destination checks if a unit is part of a mission-driven team. Fix buffer overrun crash. Ignore mines when determining win conditions. Fixed river passability in Blue Lakes.
2020-06-23 04:43:21 +12:00
Random_Animate();
} else {
Approach_Target();
}
return(TICKS_PER_SECOND+Random_Picky((int)0, (int)4, (char*)NULL, (int)0));
}
/***********************************************************************************************
* FootClass::Unlimbo -- Unlimbos object and performs special fixups. *
* *
* This routine will make sure that the home position for the foot class object gets *
* reset. This is necessary since the home position may change depending on the unit's *
* transition between limbo and non-limbo condition. *
* *
* INPUT: coord -- The coordinate to unlimbo the unit at. *
* *
* dir -- The initial direction to give the unit. *
* *
* OUTPUT: bool; Was the unit unlimboed successfully? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/23/1994 JLB : Created. *
*=============================================================================================*/
bool FootClass::Unlimbo(COORDINATE coord, DirType dir)
{
/*
** Try to unlimbo the unit.
*/
if (TechnoClass::Unlimbo(coord, dir)) {
/*
** Mobile units are always revealed to the house that owns them.
*/
Revealed(House);
/*
** Start in a still (non-moving) state.
*/
Path[0] = FACING_NONE;
return(true);
}
return(false);
}
/***********************************************************************************************
* FootClass::Assign_Mission -- Assign mission to foot class object. *
* *
* When a new mission is assigned, any precalculated path should be truncated. This is *
* in anticipation that the new mission will result in a change of path. *
* *
* INPUT: order -- The new mission to assign to the unit. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/29/1994 JLB : Created. *
*=============================================================================================*/
void FootClass::Assign_Mission(MissionType order)
{
if (What_Am_I() != RTTI_UNIT || *(UnitClass*)this != UNIT_GUNBOAT) {
Path[0] = FACING_NONE;
}
TechnoClass::Assign_Mission(order);
}
/***********************************************************************************************
* FootClass::Limbo -- Intercepts limbo event and handles FootClass processing. *
* *
* When an object of FootClass type is limboed, then it must be removed from any team *
* it may be a member of. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Was the object successfully limboed? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/29/1994 JLB : Created. *
*=============================================================================================*/
bool FootClass::Limbo(void)
{
if (!IsInLimbo) {
if (Team) {
Team->Remove(this);
}
}
return(TechnoClass::Limbo());
}
/***********************************************************************************************
* FootClass::Take_Damage -- Handles taking damage to this object. *
* *
* This routine intercepts the damage assigned to this object and if this object is *
* a member of a team, it informs the team that the damage has occurred. The team may *
* change it's priority or action based on this event. *
* *
* INPUT: damage -- The damage points inflicted on the unit. *
* *
* distance -- The distance from the point of damage to the unit itself. *
* *
* warhead -- The type of damage that is inflicted. *
* *
* source -- The purpitrator of the damage. By knowing who caused the damage, *
* the team know's who to "get even with". *
* *
* OUTPUT: Returns with the result type of the damage. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/30/1994 JLB : Created. *
*=============================================================================================*/
ResultType FootClass::Take_Damage(int & damage, int distance, WarheadType warhead, TechnoClass * source)
{
ResultType result = TechnoClass::Take_Damage(damage, distance, warhead, source);
if (result != RESULT_NONE && Team) {
if (GameToPlay != GAME_NORMAL || (source && !House->Is_Ally(source))) {
Team->Took_Damage(this, result, source);
}
} else {
if (result != RESULT_DESTROYED) {
/*
** Determine if the target that is current being attacked has a weapon that can
** do harm to a ground based unit. This information is needed so that an appropriate
** response will occur when damage is taken.
*/
WeaponType weap = WEAPON_NONE;
if (As_Techno(TarCom)) {
weap = As_Techno(TarCom)->Techno_Type_Class()->Primary;
}
bool tweap = (weap != WEAPON_NONE && weap != WEAPON_NIKE);
/*
** This ensures that if a unit is in sticky mode, then it will snap out of
** it when it takes damage.
*/
if (source && Mission == MISSION_STICKY) {
Enter_Idle_Mode();
}
/*
** If this object is not part of a team and it can retaliate for the damage, then have
** it try to do so. This prevents it from just sitting there and taking damage.
*/
if (
source &&
!House->Is_Ally(source) &&
Techno_Type_Class()->Primary != WEAPON_NONE &&
(source->What_Am_I() != RTTI_AIRCRAFT || BulletTypeClass::As_Reference(Weapons[Techno_Type_Class()->Primary].Fires).IsAntiAircraft) &&
(!Target_Legal(TarCom) || ((!House->IsHuman || Special.IsSmartDefense) && (!tweap || !In_Range(TarCom)))) &&
// !Target_Legal(NavCom) &&
(Mission == MISSION_AMBUSH ||
Mission == MISSION_GUARD ||
Mission == MISSION_RESCUE ||
Mission == MISSION_GUARD_AREA ||
Mission == MISSION_ATTACK ||
Mission == MISSION_TIMED_HUNT)) {
/*
** Assign the source of the damage as the new target. This occurs for the computer
** controled units. For the player, this only occurs if the source of the damage
** is within range.
*/
if (!House->IsHuman) {
/*
** If this unit is in TIMED_HUNT (multiplayer computer-controlled)
** mode, "snap out of it" into HUNT mode; otherwise, assign
** HUNT as the next mission through the normal mission queue.
*/
if (Mission == MISSION_TIMED_HUNT) {
Set_Mission(MISSION_HUNT);
} else {
Assign_Mission(MISSION_HUNT);
}
Assign_Target(source->As_Target());
} else {
if (In_Range(source)) {
Assign_Target(source->As_Target());
} else {
/*
** Simple retaliation cannot occur because the source of the damage
** is too far away. If scatter logic is enabled, then scatter now.
*/
if (Special.IsScatter) {
Scatter(0, true);
}
}
}
} else {
/*
** If this object isn't doing anything important, then scatter.
*/
if (!IsDriving && !Target_Legal(TarCom) && !Target_Legal(NavCom) && Special.IsScatter && What_Am_I() != RTTI_AIRCRAFT) {
Scatter(0, true);
}
}
}
}
return(result);
}
/***********************************************************************************************
* FootClass::Active_Click_With -- Intiates attack or move according to target clicked on. *
* *
* At this level, the object is known to have the ability to attack or move to the *
* target specified (in theory). Perform the attack or move as indicated. *
* *
* INPUT: target -- The target clicked upon that will precipitate action. *
* *
* OUTPUT: Returns with the type of action performed. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/06/1995 JLB : Created. *
*=============================================================================================*/
void FootClass::Active_Click_With(ActionType action, ObjectClass * object)
{
switch (action) {
case ACTION_GUARD_AREA:
if (Can_Player_Fire() && Can_Player_Move()) {
Player_Assign_Mission(MISSION_GUARD_AREA, object->As_Target());
}
break;
case ACTION_SELF:
Player_Assign_Mission(MISSION_UNLOAD);
break;
case ACTION_ATTACK:
if (Can_Player_Fire()) {
Player_Assign_Mission(MISSION_ATTACK, object->As_Target());
}
break;
case ACTION_ENTER:
Command & Conquer Remastered post-launch patch Improvements to harvester resource finding logic. Don't allow the Advanced Comm Center to be capturable in skirmish or multiplayer. Increased failed pathfinding fudge factor. Buildings accept the Guard command if they can attack. Don't allow force capturing of ally structures. Fixes for laser Orcas in S3cr3t M1ss10n. Properly restore them after save. Reset Orcas after loads. Fixed flag animation rendering in CTF. Potentially fix a crash if aircraft are destroyed outside the map bounds. Fixed legacy Obelisk line rendering. Fix out-of-bounds crash in TD; issue was already fixed in RA. Disable capture flag on Commandos. Drop the flag when entering the limbo state. Fixed end game race condition, winning team ID is always sent before individual player win/lose messages. Fixed Chan spawn on SCB10EA. Don't show enter cursor for enemy units on refineries and repair pads. Changing right-click support for first put building on hold, and then subsequenct right-clicks to decrement that queue count for 1x or 5x; Then, 1x or 5x Left click will resume from hold. Don't debug reveal legacy rendering when a player is defeated. Fixed crash when loading saves of custom campaign maps. Reset harvester archived target when given a direct harvest order. Prevent NOD cargo planes from being force attacked. Fixed unit selection on load. Migrated queued repair pad functionality from RA to TD. Randomly animate infantry in area guard mode. Fixed crash accessing inactive objects. Added some walls in SCG08EB to prevent civilians from killing themselves. TD + RA: Audio: Overiding "Our base is under attack" cooldown timing from legacy from 2 minutes to 30 seconds, so it will be heard 4x as often. Fixed adjacent cell out-of-bounds crash issues. Kill player on disconnect Fixed and improved build time calculations to be consistent between TD and RA. Don't show health bars for cloaked Stealth Tanks in the legacy renderer. Fix selection of individual control groups after mixed selection. More adjustments to SCG08EB; switch C7 to C5, and add civilian AI to avoid Tiberium. Extra safety checks for units that have no weapons and aircraft that can't hunt. Fix loading of multiple infantry onto an APC. Additional safety checks for invalid coordinates. Prevent units from being instantly repaired. Fix map passability. Fail Allied mission 5B if the spy re-boards the starting transport (matches 5A and 5C behavior). Fixed multiplayer formation move causing units to move at light speed. Ignore movement destination checks if a unit is part of a mission-driven team. Fix buffer overrun crash. Ignore mines when determining win conditions. Fixed river passability in Blue Lakes.
2020-06-23 04:43:21 +12:00
if (Can_Player_Move() && object && object->Is_Techno() /*&& !((RadioClass *)object)->In_Radio_Contact()*/) {
Player_Assign_Mission(MISSION_ENTER, TARGET_NONE, object->As_Target());
}
break;
case ACTION_CAPTURE:
if (Can_Player_Move()) {
Player_Assign_Mission(MISSION_CAPTURE, TARGET_NONE, object->As_Target());
}
break;
case ACTION_SABOTAGE:
if (Can_Player_Move()) {
Player_Assign_Mission(MISSION_SABOTAGE, TARGET_NONE, object->As_Target());
}
break;
case ACTION_NOMOVE:
case ACTION_MOVE:
if (Can_Player_Move()) {
Player_Assign_Mission(MISSION_MOVE, TARGET_NONE, object->As_Target());
}
break;
case ACTION_NO_DEPLOY:
Speak(VOX_DEPLOY);
break;
default:
break;
}
}
/***********************************************************************************************
* FootClass::Active_Click_With -- Performs action as a result of left mouse click. *
* *
* This routine performs the action requested when the left mouse button was clicked over *
* a cell. Typically, this is just a move command. *
* *
* INPUT: action -- The predetermined action that should occur. *
* *
* cell -- The cell number that the action should occur at. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/19/1995 JLB : Created. *
*=============================================================================================*/
void FootClass::Active_Click_With(ActionType action, CELL cell)
{
switch (action) {
case ACTION_HARVEST:
Player_Assign_Mission(MISSION_HARVEST, TARGET_NONE, ::As_Target(cell));
break;
case ACTION_MOVE:
if (AllowVoice) {
COORDINATE coord = Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y());
OutList.Add(EventClass(ANIM_MOVE_FLASH, PlayerPtr->Class->House, coord, 1 << PlayerPtr->Class->House));
}
// Fall into next case.
case ACTION_NOMOVE:
//using function for IsVisible so we have different results for different players - JAS 2019/09/30
if (What_Am_I() != RTTI_AIRCRAFT || Map[cell].Is_Visible(PlayerPtr)) {
Player_Assign_Mission(MISSION_MOVE, TARGET_NONE, ::As_Target(cell));
}
break;
case ACTION_ATTACK:
Player_Assign_Mission(MISSION_ATTACK, ::As_Target(cell));
break;
// MBL 05.15.2020 - Adding support for CTRL+ALT clicking the ground to have units move to an area and guard it
case ACTION_GUARD_AREA:
if (Can_Player_Fire() && Can_Player_Move()) {
Player_Assign_Mission(MISSION_GUARD_AREA, ::As_Target(cell));
}
break;
// END MBL 05.15.2020
}
}
/***********************************************************************************************
* FootClass::Per_Cell_Process -- Perform action based on once-per-cell condition. *
* *
* This routine is called as this object moves from cell to cell. When the center of the *
* cell is reached, check to see if any trigger should be sprung. For moving units, reduce *
* the path to the distance to the target. This forces path recalculation in an effort to *
* avoid units passing each other. *
* *
* INPUT: center -- Is this the center of the cell? *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/08/1995 JLB : Created. *
* 07/08/1995 JLB : Handles generic enter trigger event. *
* 07/16/1995 JLB : If next to a scanner and cloaked, then shimmer. *
*=============================================================================================*/
void FootClass::Per_Cell_Process(bool center)
{
// if (center) {
/*
** Clear any unloading flag if necessary.
*/
IsUnloading = false;
/*
** If adjacent to an enemy building that has the ability to reveal a stealth tank,
** then shimmer the cloaked object.
*/
if (Cloak == CLOAKED) {
for (FacingType face = FACING_N; face < FACING_COUNT; face++) {
CELL cell = Adjacent_Cell(Coord_Cell(Coord), face);
if (Map.In_Radar(cell)) {
TechnoClass const * techno = Map[cell].Cell_Techno();
if (techno && !House->Is_Ally(techno) && techno->Techno_Type_Class()->IsScanner) {
Do_Shimmer();
break;
}
}
}
}
/*
** Shorten the path if the target is now within weapon range of this
** unit and this unit is on an attack type mission. But only if the target
** is slow enough for leading to make sense.
*/
if (What_Am_I() != RTTI_UNIT || *((UnitClass *)this) != UNIT_GUNBOAT) {
bool inrange = In_Range(TarCom);
TechnoClass const * techno = As_Techno(TarCom);
if (techno && techno->What_Am_I() != RTTI_BUILDING) {
FootClass const * foot = (FootClass const *)techno;
MPHType speed = ((TechnoTypeClass const &)techno->Class_Of()).MaxSpeed;
COORDINATE rangecoord = (speed > MPH_SLOW) ? foot->Likely_Coord() : foot->Target_Coord();
inrange = In_Range(rangecoord);
}
if (Target_Legal(TarCom) && (Mission == MISSION_RESCUE || Mission == MISSION_GUARD_AREA || Mission == MISSION_ATTACK || Mission == MISSION_HUNT) && inrange) {
Assign_Destination(TARGET_NONE);
Path[0] = FACING_NONE;
}
}
/*
** Trigger event associated with the player entering the cell.
*/
TriggerClass * trigger = Map[Coord_Cell(Coord)].Get_Trigger();
if (Cloak != CLOAKED && trigger && trigger->House == Owner()) {
trigger->Spring(EVENT_PLAYER_ENTERED, Coord_Cell(Coord));
}
// }
Map[Coord_Cell(Coord)].Goodie_Check(this, true);
TechnoClass::Per_Cell_Process(center);
}
/***************************************************************************
* FootClass::Override_Mission -- temporarily overides a units mission *
* *
* *
* *
* INPUT: MissionType mission - the mission we want to overide *
* TARGET tarcom - the new target we want to overide *
* TARGET navcom - the new navigation point to overide *
* *
* OUTPUT: none *
* *
* WARNINGS: If a mission is already overidden, the current mission is *
* just re-assigned. *
* *
* HISTORY: *
* 04/28/1995 PWG : Created. *
*=========================================================================*/
void FootClass::Override_Mission(MissionType mission, TARGET tarcom, TARGET navcom)
{
SuspendedNavCom = NavCom;
TechnoClass::Override_Mission(mission, tarcom, navcom);
Assign_Destination(navcom);
}
/***************************************************************************
* FootClass::Restore_Mission -- Restores an overidden mission *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/28/1995 PWG : Created. *
*=========================================================================*/
bool FootClass::Restore_Mission(void)
{
if (TechnoClass::Restore_Mission()) {
Assign_Destination(SuspendedNavCom);
return(true);
}
return(false);
}
/***********************************************************************************************
* FootClass::Receive_Message -- Movement related radio messages are handled here. *
* *
* This routine handles radio message that are related to movement. These are used for *
* complex coordinated maneuvers. *
* *
* INPUT: from -- Pointer to the originator of this radio message. *
* *
* message -- The radio message that is being received. *
* *
* param -- The optional parameter (could be a movement destination). *
* *
* OUTPUT: Returns with the radio response appropriate to the message received. Usually the *
* response is RADIO_ROGER. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/14/1995 JLB : Created. *
*=============================================================================================*/
RadioMessageType FootClass::Receive_Message(RadioClass * from, RadioMessageType message, long & param)
{
switch (message) {
Command & Conquer Remastered post-launch patch Improvements to harvester resource finding logic. Don't allow the Advanced Comm Center to be capturable in skirmish or multiplayer. Increased failed pathfinding fudge factor. Buildings accept the Guard command if they can attack. Don't allow force capturing of ally structures. Fixes for laser Orcas in S3cr3t M1ss10n. Properly restore them after save. Reset Orcas after loads. Fixed flag animation rendering in CTF. Potentially fix a crash if aircraft are destroyed outside the map bounds. Fixed legacy Obelisk line rendering. Fix out-of-bounds crash in TD; issue was already fixed in RA. Disable capture flag on Commandos. Drop the flag when entering the limbo state. Fixed end game race condition, winning team ID is always sent before individual player win/lose messages. Fixed Chan spawn on SCB10EA. Don't show enter cursor for enemy units on refineries and repair pads. Changing right-click support for first put building on hold, and then subsequenct right-clicks to decrement that queue count for 1x or 5x; Then, 1x or 5x Left click will resume from hold. Don't debug reveal legacy rendering when a player is defeated. Fixed crash when loading saves of custom campaign maps. Reset harvester archived target when given a direct harvest order. Prevent NOD cargo planes from being force attacked. Fixed unit selection on load. Migrated queued repair pad functionality from RA to TD. Randomly animate infantry in area guard mode. Fixed crash accessing inactive objects. Added some walls in SCG08EB to prevent civilians from killing themselves. TD + RA: Audio: Overiding "Our base is under attack" cooldown timing from legacy from 2 minutes to 30 seconds, so it will be heard 4x as often. Fixed adjacent cell out-of-bounds crash issues. Kill player on disconnect Fixed and improved build time calculations to be consistent between TD and RA. Don't show health bars for cloaked Stealth Tanks in the legacy renderer. Fix selection of individual control groups after mixed selection. More adjustments to SCG08EB; switch C7 to C5, and add civilian AI to avoid Tiberium. Extra safety checks for units that have no weapons and aircraft that can't hunt. Fix loading of multiple infantry onto an APC. Additional safety checks for invalid coordinates. Prevent units from being instantly repaired. Fix map passability. Fail Allied mission 5B if the spy re-boards the starting transport (matches 5A and 5C behavior). Fixed multiplayer formation move causing units to move at light speed. Ignore movement destination checks if a unit is part of a mission-driven team. Fix buffer overrun crash. Ignore mines when determining win conditions. Fixed river passability in Blue Lakes.
2020-06-23 04:43:21 +12:00
/*
** Answers if this object is located on top of a service depot.
*/
case RADIO_ON_DEPOT:
if (Map[Coord_Cell(Center_Coord())].Cell_Building() != NULL) {
BuildingClass const * building = Map[Coord_Cell(Center_Coord())].Cell_Building();
if (*building == STRUCT_REPAIR) {
return(RADIO_ROGER);
}
}
return(RADIO_NEGATIVE);
/*
** Intercept the repair request and if this object is moving, then no repair
** is possible.
*/
case RADIO_REPAIR:
if (Target_Legal(NavCom)) return(RADIO_NEGATIVE);
break;
/*
** Something bad has happened to the object in contact with. Abort any coordinated
** activity with this object. Basically, ... run away! Run away!
*/
case RADIO_RUN_AWAY:
if (In_Radio_Contact()) {
if (NavCom == Contact_With_Whom()->As_Target()) {
Assign_Destination(TARGET_NONE);
}
}
if (Mission == MISSION_SLEEP) {
Assign_Mission(MISSION_GUARD);
Commence();
}
if (Mission == MISSION_ENTER) {
Assign_Mission(MISSION_GUARD);
}
if (!IsRotating && !Target_Legal(NavCom)) {
Command & Conquer Remastered post-launch patch Improvements to harvester resource finding logic. Don't allow the Advanced Comm Center to be capturable in skirmish or multiplayer. Increased failed pathfinding fudge factor. Buildings accept the Guard command if they can attack. Don't allow force capturing of ally structures. Fixes for laser Orcas in S3cr3t M1ss10n. Properly restore them after save. Reset Orcas after loads. Fixed flag animation rendering in CTF. Potentially fix a crash if aircraft are destroyed outside the map bounds. Fixed legacy Obelisk line rendering. Fix out-of-bounds crash in TD; issue was already fixed in RA. Disable capture flag on Commandos. Drop the flag when entering the limbo state. Fixed end game race condition, winning team ID is always sent before individual player win/lose messages. Fixed Chan spawn on SCB10EA. Don't show enter cursor for enemy units on refineries and repair pads. Changing right-click support for first put building on hold, and then subsequenct right-clicks to decrement that queue count for 1x or 5x; Then, 1x or 5x Left click will resume from hold. Don't debug reveal legacy rendering when a player is defeated. Fixed crash when loading saves of custom campaign maps. Reset harvester archived target when given a direct harvest order. Prevent NOD cargo planes from being force attacked. Fixed unit selection on load. Migrated queued repair pad functionality from RA to TD. Randomly animate infantry in area guard mode. Fixed crash accessing inactive objects. Added some walls in SCG08EB to prevent civilians from killing themselves. TD + RA: Audio: Overiding "Our base is under attack" cooldown timing from legacy from 2 minutes to 30 seconds, so it will be heard 4x as often. Fixed adjacent cell out-of-bounds crash issues. Kill player on disconnect Fixed and improved build time calculations to be consistent between TD and RA. Don't show health bars for cloaked Stealth Tanks in the legacy renderer. Fix selection of individual control groups after mixed selection. More adjustments to SCG08EB; switch C7 to C5, and add civilian AI to avoid Tiberium. Extra safety checks for units that have no weapons and aircraft that can't hunt. Fix loading of multiple infantry onto an APC. Additional safety checks for invalid coordinates. Prevent units from being instantly repaired. Fix map passability. Fail Allied mission 5B if the spy re-boards the starting transport (matches 5A and 5C behavior). Fixed multiplayer formation move causing units to move at light speed. Ignore movement destination checks if a unit is part of a mission-driven team. Fix buffer overrun crash. Ignore mines when determining win conditions. Fixed river passability in Blue Lakes.
2020-06-23 04:43:21 +12:00
Scatter(0, true, true);
}
break;
/*
** Checks to see if this unit needs to move somewhere. If it is already in motion,
** then it doesn't need furthur movement instructions.
*/
case RADIO_NEED_TO_MOVE:
param = (long)NavCom;
if (!Target_Legal(NavCom)) {
return(RADIO_ROGER);
}
return(RADIO_NEGATIVE);
/*
** Radio request to move to location specified. Typically this is used
** for complex loading and unloading missions.
*/
case RADIO_MOVE_HERE:
if (NavCom != (TARGET)param) {
if (::As_Target(Coord_Cell(Coord)) == (TARGET)param) {
return(RADIO_YEA_NOW_WHAT);
} else {
if (Mission == MISSION_GUARD && MissionQueue == MISSION_NONE) {
Assign_Mission(MISSION_MOVE);
}
Assign_Destination((TARGET)param);
}
}
return(RADIO_ROGER);
/*
** Requests if this unit is trying to cooperatively load up. Typically, this occurs
** for passengers and when vehicles need to be repaired.
*/
case RADIO_TRYING_TO_LOAD:
if (Mission == MISSION_ENTER || MissionQueue == MISSION_ENTER) {
TechnoClass::Receive_Message(from, message, param);
return(RADIO_ROGER);
}
break;
}
return(TechnoClass::Receive_Message(from, message, param));
}
/***********************************************************************************************
* FootClass::Mission_Enter -- Enter (cooperatively) mission handler. *
* *
* This mission handler will cooperatively coordinate the object to maneuver into the *
* object it is in radio contact with. This is used by infantry when they wish to load *
* into an APC as well as by vehicles when they wish to enter a repair facility. *
* *
* INPUT: none *
* *
* OUTPUT: Returns the number of game ticks before this routine should be called again. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/15/1995 JLB : Created. *
*=============================================================================================*/
int FootClass::Mission_Enter(void)
{
/*
Command & Conquer Remastered post-launch patch Improvements to harvester resource finding logic. Don't allow the Advanced Comm Center to be capturable in skirmish or multiplayer. Increased failed pathfinding fudge factor. Buildings accept the Guard command if they can attack. Don't allow force capturing of ally structures. Fixes for laser Orcas in S3cr3t M1ss10n. Properly restore them after save. Reset Orcas after loads. Fixed flag animation rendering in CTF. Potentially fix a crash if aircraft are destroyed outside the map bounds. Fixed legacy Obelisk line rendering. Fix out-of-bounds crash in TD; issue was already fixed in RA. Disable capture flag on Commandos. Drop the flag when entering the limbo state. Fixed end game race condition, winning team ID is always sent before individual player win/lose messages. Fixed Chan spawn on SCB10EA. Don't show enter cursor for enemy units on refineries and repair pads. Changing right-click support for first put building on hold, and then subsequenct right-clicks to decrement that queue count for 1x or 5x; Then, 1x or 5x Left click will resume from hold. Don't debug reveal legacy rendering when a player is defeated. Fixed crash when loading saves of custom campaign maps. Reset harvester archived target when given a direct harvest order. Prevent NOD cargo planes from being force attacked. Fixed unit selection on load. Migrated queued repair pad functionality from RA to TD. Randomly animate infantry in area guard mode. Fixed crash accessing inactive objects. Added some walls in SCG08EB to prevent civilians from killing themselves. TD + RA: Audio: Overiding "Our base is under attack" cooldown timing from legacy from 2 minutes to 30 seconds, so it will be heard 4x as often. Fixed adjacent cell out-of-bounds crash issues. Kill player on disconnect Fixed and improved build time calculations to be consistent between TD and RA. Don't show health bars for cloaked Stealth Tanks in the legacy renderer. Fix selection of individual control groups after mixed selection. More adjustments to SCG08EB; switch C7 to C5, and add civilian AI to avoid Tiberium. Extra safety checks for units that have no weapons and aircraft that can't hunt. Fix loading of multiple infantry onto an APC. Additional safety checks for invalid coordinates. Prevent units from being instantly repaired. Fix map passability. Fail Allied mission 5B if the spy re-boards the starting transport (matches 5A and 5C behavior). Fixed multiplayer formation move causing units to move at light speed. Ignore movement destination checks if a unit is part of a mission-driven team. Fix buffer overrun crash. Ignore mines when determining win conditions. Fixed river passability in Blue Lakes.
2020-06-23 04:43:21 +12:00
** Find out who to coordinate with. If in radio contact, then this the transporter is
** defined. If not in radio contact, then try the archive target value to see if that
** is suitable.
*/
Command & Conquer Remastered post-launch patch Improvements to harvester resource finding logic. Don't allow the Advanced Comm Center to be capturable in skirmish or multiplayer. Increased failed pathfinding fudge factor. Buildings accept the Guard command if they can attack. Don't allow force capturing of ally structures. Fixes for laser Orcas in S3cr3t M1ss10n. Properly restore them after save. Reset Orcas after loads. Fixed flag animation rendering in CTF. Potentially fix a crash if aircraft are destroyed outside the map bounds. Fixed legacy Obelisk line rendering. Fix out-of-bounds crash in TD; issue was already fixed in RA. Disable capture flag on Commandos. Drop the flag when entering the limbo state. Fixed end game race condition, winning team ID is always sent before individual player win/lose messages. Fixed Chan spawn on SCB10EA. Don't show enter cursor for enemy units on refineries and repair pads. Changing right-click support for first put building on hold, and then subsequenct right-clicks to decrement that queue count for 1x or 5x; Then, 1x or 5x Left click will resume from hold. Don't debug reveal legacy rendering when a player is defeated. Fixed crash when loading saves of custom campaign maps. Reset harvester archived target when given a direct harvest order. Prevent NOD cargo planes from being force attacked. Fixed unit selection on load. Migrated queued repair pad functionality from RA to TD. Randomly animate infantry in area guard mode. Fixed crash accessing inactive objects. Added some walls in SCG08EB to prevent civilians from killing themselves. TD + RA: Audio: Overiding "Our base is under attack" cooldown timing from legacy from 2 minutes to 30 seconds, so it will be heard 4x as often. Fixed adjacent cell out-of-bounds crash issues. Kill player on disconnect Fixed and improved build time calculations to be consistent between TD and RA. Don't show health bars for cloaked Stealth Tanks in the legacy renderer. Fix selection of individual control groups after mixed selection. More adjustments to SCG08EB; switch C7 to C5, and add civilian AI to avoid Tiberium. Extra safety checks for units that have no weapons and aircraft that can't hunt. Fix loading of multiple infantry onto an APC. Additional safety checks for invalid coordinates. Prevent units from being instantly repaired. Fix map passability. Fail Allied mission 5B if the spy re-boards the starting transport (matches 5A and 5C behavior). Fixed multiplayer formation move causing units to move at light speed. Ignore movement destination checks if a unit is part of a mission-driven team. Fix buffer overrun crash. Ignore mines when determining win conditions. Fixed river passability in Blue Lakes.
2020-06-23 04:43:21 +12:00
TechnoClass * contact = Contact_With_Whom();
if (contact == NULL) {
contact = As_Techno(ArchiveTarget);
}
if (contact == NULL) {
contact = As_Techno(NavCom);
}
Command & Conquer Remastered post-launch patch Improvements to harvester resource finding logic. Don't allow the Advanced Comm Center to be capturable in skirmish or multiplayer. Increased failed pathfinding fudge factor. Buildings accept the Guard command if they can attack. Don't allow force capturing of ally structures. Fixes for laser Orcas in S3cr3t M1ss10n. Properly restore them after save. Reset Orcas after loads. Fixed flag animation rendering in CTF. Potentially fix a crash if aircraft are destroyed outside the map bounds. Fixed legacy Obelisk line rendering. Fix out-of-bounds crash in TD; issue was already fixed in RA. Disable capture flag on Commandos. Drop the flag when entering the limbo state. Fixed end game race condition, winning team ID is always sent before individual player win/lose messages. Fixed Chan spawn on SCB10EA. Don't show enter cursor for enemy units on refineries and repair pads. Changing right-click support for first put building on hold, and then subsequenct right-clicks to decrement that queue count for 1x or 5x; Then, 1x or 5x Left click will resume from hold. Don't debug reveal legacy rendering when a player is defeated. Fixed crash when loading saves of custom campaign maps. Reset harvester archived target when given a direct harvest order. Prevent NOD cargo planes from being force attacked. Fixed unit selection on load. Migrated queued repair pad functionality from RA to TD. Randomly animate infantry in area guard mode. Fixed crash accessing inactive objects. Added some walls in SCG08EB to prevent civilians from killing themselves. TD + RA: Audio: Overiding "Our base is under attack" cooldown timing from legacy from 2 minutes to 30 seconds, so it will be heard 4x as often. Fixed adjacent cell out-of-bounds crash issues. Kill player on disconnect Fixed and improved build time calculations to be consistent between TD and RA. Don't show health bars for cloaked Stealth Tanks in the legacy renderer. Fix selection of individual control groups after mixed selection. More adjustments to SCG08EB; switch C7 to C5, and add civilian AI to avoid Tiberium. Extra safety checks for units that have no weapons and aircraft that can't hunt. Fix loading of multiple infantry onto an APC. Additional safety checks for invalid coordinates. Prevent units from being instantly repaired. Fix map passability. Fail Allied mission 5B if the spy re-boards the starting transport (matches 5A and 5C behavior). Fixed multiplayer formation move causing units to move at light speed. Ignore movement destination checks if a unit is part of a mission-driven team. Fix buffer overrun crash. Ignore mines when determining win conditions. Fixed river passability in Blue Lakes.
2020-06-23 04:43:21 +12:00
/*
** If in contact, then let the transporter handle the movement coordination.
*/
if (contact != NULL) {
/*
** If the transport says to "bug off", then abort the enter mission. The transport may
** likely say all is 'ok' with the "RADIO ROGER", then try again later.
*/
if (Transmit_Message(RADIO_DOCKING, contact) != RADIO_ROGER && !IsTethered) {
Transmit_Message(RADIO_OVER_OUT);
Enter_Idle_Mode();
}
} else {
/*
Command & Conquer Remastered post-launch patch Improvements to harvester resource finding logic. Don't allow the Advanced Comm Center to be capturable in skirmish or multiplayer. Increased failed pathfinding fudge factor. Buildings accept the Guard command if they can attack. Don't allow force capturing of ally structures. Fixes for laser Orcas in S3cr3t M1ss10n. Properly restore them after save. Reset Orcas after loads. Fixed flag animation rendering in CTF. Potentially fix a crash if aircraft are destroyed outside the map bounds. Fixed legacy Obelisk line rendering. Fix out-of-bounds crash in TD; issue was already fixed in RA. Disable capture flag on Commandos. Drop the flag when entering the limbo state. Fixed end game race condition, winning team ID is always sent before individual player win/lose messages. Fixed Chan spawn on SCB10EA. Don't show enter cursor for enemy units on refineries and repair pads. Changing right-click support for first put building on hold, and then subsequenct right-clicks to decrement that queue count for 1x or 5x; Then, 1x or 5x Left click will resume from hold. Don't debug reveal legacy rendering when a player is defeated. Fixed crash when loading saves of custom campaign maps. Reset harvester archived target when given a direct harvest order. Prevent NOD cargo planes from being force attacked. Fixed unit selection on load. Migrated queued repair pad functionality from RA to TD. Randomly animate infantry in area guard mode. Fixed crash accessing inactive objects. Added some walls in SCG08EB to prevent civilians from killing themselves. TD + RA: Audio: Overiding "Our base is under attack" cooldown timing from legacy from 2 minutes to 30 seconds, so it will be heard 4x as often. Fixed adjacent cell out-of-bounds crash issues. Kill player on disconnect Fixed and improved build time calculations to be consistent between TD and RA. Don't show health bars for cloaked Stealth Tanks in the legacy renderer. Fix selection of individual control groups after mixed selection. More adjustments to SCG08EB; switch C7 to C5, and add civilian AI to avoid Tiberium. Extra safety checks for units that have no weapons and aircraft that can't hunt. Fix loading of multiple infantry onto an APC. Additional safety checks for invalid coordinates. Prevent units from being instantly repaired. Fix map passability. Fail Allied mission 5B if the spy re-boards the starting transport (matches 5A and 5C behavior). Fixed multiplayer formation move causing units to move at light speed. Ignore movement destination checks if a unit is part of a mission-driven team. Fix buffer overrun crash. Ignore mines when determining win conditions. Fixed river passability in Blue Lakes.
2020-06-23 04:43:21 +12:00
** Since there is no potential object to enter, then abort this
** mission with some default standby mission.
*/
if (MissionQueue == MISSION_NONE) {
/*
** If this is a harvester, then return to harvesting.
** Set a hacky target so we know to skip to the proper state.
*/
if (What_Am_I() == RTTI_UNIT && ((UnitClass*)this)->Class->IsToHarvest) {
Assign_Mission(MISSION_HARVEST);
Assign_Target(As_Target());
Assign_Destination(TARGET_NONE);
} else {
ArchiveTarget = TARGET_NONE;
Enter_Idle_Mode();
}
}
}
return(TICKS_PER_SECOND/2);
}
/***********************************************************************************************
z * FootClass::Assign_Destination -- Assigns specified destination to NavCom. *
* *
* This routine will assign the specified target to the navigation computer. No legality *
* checks are performed. *
* *
* INPUT: target -- The target value to assign to the navigation computer. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/08/1995 JLB : Created. *
*=============================================================================================*/
void FootClass::Assign_Destination(TARGET target)
{
NavCom = target;
}
/***********************************************************************************************
* FootClass::Detach_All -- Removes this object from the game system. *
* *
* This routine will remove this object from the game system. This routine is called when *
* this object is about to be deleted. All other objects should no longer reference this *
* object in that case. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/08/1995 JLB : Created. *
*=============================================================================================*/
void FootClass::Detach_All(bool all)
{
if (Team) Team->Remove(this);
Team = NULL;
TechnoClass::Detach_All(all);
}
/***********************************************************************************************
* FootClass::Rescue_Mission -- Calls this unit to the rescue. *
* *
* This routine is called when the house determines that it should attack the specified *
* target. This routine will determine if it can attack the target specified and if so, *
* the amount of power it can throw at it. This returned power value is used to allow *
* intelligent distribution of retaliation. *
* *
* INPUT: target -- The target that this object just might be assigned to attack and thus *
* how much power it can bring to bear should be returned. *
* *
* OUTPUT: Returns with the amount of power that this object can bring to bear against the *
* potential target specified. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/08/1995 JLB : Created. *
*=============================================================================================*/
int FootClass::Rescue_Mission(TARGET tarcom)
{
/*
** If the target specified is not legal, then it cannot be attacked. Always return
** zero in this case.
*/
if (!Target_Legal(tarcom)) return(0);
/*
** If the unit is already assigned to destroy the tarcom then we need
** to return a negative value which tells the computer to lower the
** desired threat rating.
*/
if (TarCom == tarcom) {
return(-Risk());
}
/*
** If the unit is currently attacking a target that has a weapon then we
** cannot abandon it as it will destroy us if we return to base.
*/
if (Target_Legal(TarCom)) {
TechnoClass * techno = As_Techno(TarCom);
if (techno && techno->Techno_Type_Class()->Primary != WEAPON_NONE) {
return(0);
}
}
/*
** If the unit is in a harvest mission or is currently attacking
** something, or is not very effective, then it will be of no help
** at all.
*/
if (Team || Mission == MISSION_HARVEST || !Risk()) {
return(0);
}
/*
** Find the distance to the target modified by the range. If the
** the distance is 0, then things are ok.
*/
int dist = Distance(tarcom) - Weapon_Range(0);
int threat = Risk() * 256;
int speed = -1;
if (dist > 0) {
/*
** Next we need to figure out how fast the unit moves because this
** decreases the distance penalty.
*/
speed = Max((unsigned)Techno_Type_Class()->MaxSpeed, (unsigned)1);
int ratio = (speed > 0) ? Max(dist / speed, 1) : 1;
/*
** Finally modify the threat by the distance the unit is away.
*/
threat = Max(threat/ratio, 1);
}
return(threat);
}
/***********************************************************************************************
* FootClass::Death_Announcement -- Announces the death of a unit. *
* *
* This routine is called when a unit (infantry, vehicle, or aircraft) is destroyed. *
* *
* INPUT: source -- The purpetrator of this death. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/01/1995 JLB : Created. *
*=============================================================================================*/
void FootClass::Death_Announcement(TechnoClass const * source) const
{
// Changed for multiplayer. ST - 3/13/2019 5:36PM
if ((GameToPlay == GAME_GLYPHX_MULTIPLAYER && House->IsHuman) || (GameToPlay != GAME_GLYPHX_MULTIPLAYER && Is_Discovered_By_Player() || Is_Owned_By_Player())) { // ST
//if (Is_Discovered_By_Player() || Is_Owned_By_Player()) {
//if (IsDiscoveredByPlayer || IsOwnedByPlayer) {
if (!source || source->What_Am_I() != RTTI_INFANTRY || *((InfantryClass const *)source) != INFANTRY_RAMBO) {
if (What_Am_I() == RTTI_INFANTRY && ((InfantryTypeClass const &)Class_Of()).IsCivilian && !((InfantryClass *)this)->IsTechnician) {
// if (Options.IsDeathAnnounce) Speak(VOX_DEAD_CIV); // MBL 02.06.2020
if (Options.IsDeathAnnounce) Speak(VOX_DEAD_CIV, House, Center_Coord());
}
else {
if (House != PlayerPtr && GameToPlay != GAME_NORMAL) {
// if (Options.IsDeathAnnounce) Speak(VOX_ENEMY_UNIT); // MBL 02.06.2020
if (Options.IsDeathAnnounce) Speak(VOX_ENEMY_UNIT, House);
}
else {
if (((GameToPlay == GAME_GLYPHX_MULTIPLAYER && House->IsHuman) || House == PlayerPtr) || Options.IsDeathAnnounce) { // ST
if (!Options.IsDeathAnnounce) { // MBL 02.06.2020
// Speak(VOX_UNIT_LOST);
Speak(VOX_UNIT_LOST, House, Center_Coord());
}
else {
switch (House->ActLike) {
case HOUSE_GOOD:
// Speak(VOX_DEAD_GDI); // MBL 02.06.2020
Speak(VOX_DEAD_GDI, House, Center_Coord());
break;
case HOUSE_BAD:
// Speak(VOX_DEAD_NOD); // MBL 02.06.2020
Speak(VOX_DEAD_NOD, House, Center_Coord());
break;
default:
break;
}
}
}
}
}
}
}
}
/***********************************************************************************************
* FootClass::Greatest_Threat -- Fetches the greatest threat to this object. *
* *
* This routine will return with the greatest threat (best target) for this object. For *
* movable ground object, they won't automatically return ANY target if this object is *
* cloaked. Otherwise, cloaking is relatively useless. *
* *
* INPUT: method -- The request method (bit flags) to use when scanning for a target. *
* *
* OUTPUT: Returns with the best target to attack. If there is no target that qualifies, then *
* TARGET_NONE is returned. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/08/1995 JLB : Created. *
*=============================================================================================*/
TARGET FootClass::Greatest_Threat(ThreatType method) const
{
/*
** If this object can cloak, then it won't select a target automatically.
*/
if (House->IsHuman && IsCloakable && Mission == MISSION_GUARD) {
return(TARGET_NONE);
}
if (Techno_Type_Class()->Primary != WEAPON_NONE && BulletTypeClass::As_Reference(Weapons[Techno_Type_Class()->Primary].Fires).IsAntiAircraft) {
method = method | THREAT_AIR;
}
if (Techno_Type_Class()->Secondary != WEAPON_NONE && BulletTypeClass::As_Reference(Weapons[Techno_Type_Class()->Secondary].Fires).IsAntiAircraft) {
method = method | THREAT_AIR;
}
return(TechnoClass::Greatest_Threat(method|THREAT_GROUND));
}
/***********************************************************************************************
* FootClass::Detach -- Detaches a target from tracking systems. *
* *
* This routine will detach the specified target from the tracking systems of this object. *
* It will be removed from the navigation computer and any queued mission record. *
* *
* INPUT: target -- The target to be removed from this object. *
* *
* all -- Is the unit really about to be eliminated? If this is true then even *
* friendly contact (i.e., radio) must be eliminated. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/18/1995 JLB : Created. *
*=============================================================================================*/
void FootClass::Detach(TARGET target, bool all)
{
TechnoClass::Detach(target, all);
if (!SpecialFlag) {
if (ArchiveTarget == target) {
ArchiveTarget = TARGET_NONE;
}
}
if (SuspendedNavCom == target) {
SuspendedNavCom = TARGET_NONE;
SuspendedMission = MISSION_NONE;
}
/*
** If the navigation computer is assigned to the target, then the navigation
** computer must be cleared.
*/
if (NavCom == target) {
NavCom = TARGET_NONE;
Path[0] = FACING_NONE;
Restore_Mission();
}
/*
** If targeting the specified object and this unit is obviously heading
** toward the target to get within range, then abort the path.
*/
if (TarCom == target && House->IsHuman) {
Path[0] = FACING_NONE;
}
}
/***********************************************************************************************
* FootClass::Offload_Tiberium_Bail -- Fetches the Tiberium to offload per step. *
* *
* This routine is called when a packet/package/bail of Tiberium needs to be offloaded *
* from the object. This function is overridden for those objects that can contain *
* Tiberium. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the number of credits offloaded from the object. *
* *
* WARNINGS: This routine must be called multiple times in order to completely offload the *
* Tiberium. When this routine return 0, all Tiberium has been offloaded. *
* *
* HISTORY: *
* 07/19/1995 JLB : Created. *
*=============================================================================================*/
int FootClass::Offload_Tiberium_Bail(void)
{
return(0);
}
/***********************************************************************************************
* FootClass::Can_Enter_Cell -- Checks to see if the object can enter cell specified. *
* *
* This routine examines the specified cell to see if the object can enter it. This *
* function is to be overridden for objects that could have the possibility of not being *
* allowed to enter the cell. Typical objects at the FootClass level always return *
* MOVE_OK. *
* *
* INPUT: cell -- The cell to examine. *
* *
* facing -- The direction that this cell might be entered from. *
* *
* OUTPUT: Returns with the move check result type. This will be MOVE_OK if there is not *
* blockage. There are various other values that represent other blockage types. *
* The value returned will indicatd the most severe reason why entry into the cell *
* is blocked. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/19/1995 JLB : Created. *
*=============================================================================================*/
MoveType FootClass::Can_Enter_Cell(CELL , FacingType) const
{
return MOVE_OK;
}
/***********************************************************************************************
* FootClass::Can_Demolish -- Checks to see if this object can be sold back. *
* *
* This routine determines if it is legal to sell the object back. A foot class object can *
* only be sold back if it is sitting on a repair bay. *
* *
* INPUT: none *
* *
* OUTPUT: Was the object successfully sold back? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/13/1995 JLB : Created. *
*=============================================================================================*/
bool FootClass::Can_Demolish(void) const
{
switch (What_Am_I()) {
case RTTI_UNIT:
case RTTI_AIRCRAFT:
if (In_Radio_Contact() &&
Contact_With_Whom()->What_Am_I() == RTTI_BUILDING &&
*((BuildingClass *)Contact_With_Whom()) == STRUCT_REPAIR &&
Distance(Contact_With_Whom()) < 0x0080) {
return(true);
}
break;
default:
break;
}
return(TechnoClass::Can_Demolish());
}
/***********************************************************************************************
* FootClass::Sell_Back -- Causes this object to be sold back. *
* *
* When an object is sold back, a certain amount of money is refunded to the owner and then *
* the object is removed from the game system. *
* *
* INPUT: control -- The action to perform. The only supported action is "1", which means *
* to sell back. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/13/1995 JLB : Created. *
*=============================================================================================*/
void FootClass::Sell_Back(int control)
{
if (control != 0) {
if (House == PlayerPtr) {
Sound_Effect(VOC_CASHTURN);
}
House->Refund_Money(Refund_Amount());
Stun();
Limbo();
Delete_This();
}
}
/***********************************************************************************************
* FootClass::Likely_Coord -- Fetches the coordinate the object will be at shortly. *
* *
* This routine comes in handy when determining where a travelling object will be at *
* when considering the amount of time it would take for a normal unit to travel one cell. *
* Using this information, an intelligent "approach target" logic can be employed. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the coordinate the object is at or soon will be. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/13/1995 JLB : Created. *
*=============================================================================================*/
COORDINATE FootClass::Likely_Coord(void) const
{
if (Head_To_Coord()) {
return(Head_To_Coord());
}
return(Target_Coord());
}