CnC_Remastered_Collection/TIBERIANDAWN/UNIT.CPP

4438 lines
185 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\unit.cpv 2.17 16 Oct 1995 16:48:28 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 : UNIT.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : September 10, 1993 *
* *
* Last Update : August 16, 1995 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Recoil_Adjust -- Adjust pixel values in direction specified. *
* Turret_Adjust -- Turret adjustment routine for MLRS and MSAM units. *
* UnitClass::AI -- AI processing for the unit. *
* UnitClass::APC_Close_Door -- Closes an APC door. *
* UnitClass::APC_Open_Door -- Opens an APC door. *
* UnitClass::Active_Click_With -- Intercepts the active click to see if deployment is possib*
* UnitClass::As_Target -- Returns the unit as a target value. *
* UnitClass::Blocking_Object -- Determines how a object blocks a unit *
* UnitClass::Can_Enter_Building -- Determines building entry legality. *
* UnitClass::Can_Fire -- Determines if this unit can fire. *
* UnitClass::Can_Player_Move -- Determines if the player is legally allowed to move it. *
* UnitClass::Click_With -- Handles player map clicking while this unit is selected. *
* UnitClass::Crew_Type -- Fetches the kind of crew that this object produces. *
* UnitClass::Debug_Dump -- Displays the status of the unit to the mono monitor. *
* UnitClass::Desired_Load_Dir -- Determines the best cell and facing for loading. *
* UnitClass::Draw_It -- Draws a unit object. *
* UnitClass::Enter_Idle_Mode -- Unit enters idle mode state. *
* UnitClass::Find_LZ -- Maintenance function for transport units. *
* UnitClass::Flag_Attach -- Attaches a house flag to this unit. *
* UnitClass::Flag_Remove -- Removes the house flag from this unit. *
* UnitClass::Goto_Clear_Spot -- Finds a clear spot to deploy. *
* UnitClass::Goto_Tiberium -- Search for and head toward nearest available Tiberium patch. *
* UnitClass::Harvesting -- Harvests tiberium at the current location. *
* UnitClass::Init -- Clears all units for scenario preparation. *
* UnitClass::Limbo -- Prepares vehicle and then limbos it. *
* UnitClass::Look -- Perform map revelation from a unit's position. *
* UnitClass::Mission_Attack -- Handles the mission attack logic. *
* UnitClass::Mission_Guard -- Special guard mission override processor. *
* UnitClass::Mission_Harvest -- Handles the harvesting process used by harvesters. *
* UnitClass::Mission_Hunt -- This is the AI process for aggressive enemy units. *
* UnitClass::Mission_Move -- Handles special move mission overrides. *
* UnitClass::Mission_Unload -- Handles unloading cargo. *
* UnitClass::Overlap_List -- Determines overlap list for units. *
* UnitClass::Per_Cell_Process -- Performs operations necessary on a per cell basis. *
* UnitClass::Pip_Count -- Fetchs the number of pips to display on unit. *
* UnitClass::Random_Animate -- Handles random idle animation for the unit. *
* UnitClass::Read_INI -- Reads units from scenario INI file. *
* UnitClass::Receive_Message -- Handles receiving a radio message. *
* UnitClass::Remap_Table -- Fetches the remap table to use for this object. *
* UnitClass::Response_Attack -- Voice feedback when ordering the unit to attack a target. *
* UnitClass::Response_Move -- Voice feedback when ordering the unit to move. *
* UnitClass::Response_Select -- Voice feedback when selecting the unit. *
* UnitClass::Scatter -- Causes the unit to travel to a nearby safe cell. *
* UnitClass::Set_Speed -- Initiate unit movement physics. *
* UnitClass::Sort_Y -- Give Y coordinate sort value for unit. *
* UnitClass::Start_Driver -- Starts driving and reserves destination cell. *
* UnitClass::Stop_Driver -- Handles removing occupation bits when driving stops. *
* UnitClass::Stun -- Stuns the unit in preparation for unit removal. *
* UnitClass::Take_Damage -- Inflicts damage points on a unit. *
* UnitClass::Target_Coord -- The coordinate to use when targeting this unit. *
* UnitClass::Try_To_Deploy -- The unit attempts to "deploy" at current location. *
* UnitClass::UnitClass -- Constructor for units. *
* UnitClass::Unlimbo -- Removes unit from stasis. *
* UnitClass::Unload_Hovercraft_Process -- Handles unloading hovercraft transport. *
* UnitClass::Validate -- validates unit pointer. *
* UnitClass::What_Action -- Determines what action would occur if clicked on object. *
* UnitClass::What_Am_I -- Returns with the RTTI type this object is. *
* UnitClass::Write_INI -- Writes all the units out to an INI file. *
* UnitClass::delete -- Deletion operator for units. *
* UnitClass::new -- Allocate a unit slot and adjust access arrays. *
* UnitClass::~UnitClass -- Destructor for unit objects. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/*
** This contains the value of the Virtual Function Table Pointer
*/
void * UnitClass::VTable;
/***********************************************************************************************
* UnitClass::Validate -- validates unit pointer. *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* 1 = ok, 0 = error *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 08/09/1995 BRR : Created. *
*=============================================================================================*/
#ifdef CHEAT_KEYS
int UnitClass::Validate(void) const
{
int num;
num = Units.ID(this);
if (num < 0 || num >= UNIT_MAX) {
Validate_Error("UNIT");
return (0);
}
else
return (1);
}
#else
#define Validate()
#endif
/***********************************************************************************************
* Recoil_Adjust -- Adjust pixel values in direction specified. *
* *
* This is a helper routine that modifies the pixel coordinates provided according to the *
* direction specified. The effect is the simulate recoil effects by moving an object 'back'*
* one pixel. Since the pixels moved depend on facing, this routine handles the pixel *
* adjustment quickly. *
* *
* INPUT: dir -- The direction to base the recoil on. *
* *
* x,y -- References to the pixel coordinates that will be adjusted. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/08/1995 JLB : Created. *
*=============================================================================================*/
void Recoil_Adjust(DirType dir, int &x, int &y)
{
static struct {
signed char X,Y;
} _adjust[32] = {
{0,1}, // N
{0,1},
{0,1},
{-1,1},
{-1,1}, // NE
{-1,1},
{-1,0},
{-1,0},
{-1,0}, // E
{-1,0},
{-1,-1},
{-1,-1},
{-1,-1}, // SE
{-1,-1},
{-1,-1},
{0,-1},
{0,-1}, // S
{0,-1},
{0,-1},
{1,-1},
{1,-1}, // SW
{1,-1},
{1,0},
{1,0},
{1,0}, // W
{1,0},
{1,1},
{1,1},
{1,1}, // NW
{1,1},
{0,1},
{0,1}
};
int index = Facing_To_32(dir);
x += _adjust[index].X;
y += _adjust[index].Y;
}
/***********************************************************************************************
* Turret_Adjust -- Turret adjustment routine for MLRS and MSAM units. *
* *
* This routine adjusts the pixel coordinates specified to account for the displacement of *
* the turret on the MLRS and MSAM vehicles. *
* *
* INPUT: dir -- The direction of the body of the vehicle. *
* *
* x,y -- References to the turret center pixel position. These will be modified as *
* necessary. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/08/1995 JLB : Created. *
*=============================================================================================*/
void Turret_Adjust(DirType dir, int &x, int &y)
{
static struct {
signed char X,Y;
} _adjust[32] = {
{1,2}, // N
{-1,1},
{-2,0},
{-3,0},
{-3,1}, // NW
{-4,-1},
{-4,-1},
{-5,-2},
{-5,-3}, // W
{-5,-3},
{-3,-3},
{-3,-4},
{-3,-4}, // SW
{-3,-5},
{-2,-5},
{-1,-5},
{0,-5}, // S
{1,-6},
{2,-5},
{3,-5},
{4,-5}, // SE
{6,-4},
{6,-3},
{6,-3},
{6,-3}, // E
{5,-1},
{5,-1},
{4,0},
{3,0}, // NE
{2,0},
{2,1},
{1,2}
};
int index = Facing_To_32(dir);
x += _adjust[index].X;
y += _adjust[index].Y;
}
/***********************************************************************************************
* UnitClass::As_Target -- Returns the unit as a target value. *
* *
* This routine will convert the unit into a target value that is then returned. Target *
* values are typically used for navigation and other computer uses. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with target value of unit. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/19/1994 JLB : Created. *
*=============================================================================================*/
TARGET UnitClass::As_Target(void) const
{
Validate();
return(Build_Target(KIND_UNIT, Units.ID(this)));
}
#ifdef CHEAT_KEYS
/***********************************************************************************************
* UnitClass::Debug_Dump -- Displays the status of the unit to the mono monitor. *
* *
* This displays the current status of the unit class to the mono monitor. By this display *
* bugs may be tracked down or prevented. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/02/1994 JLB : Created. *
*=============================================================================================*/
void UnitClass::Debug_Dump(MonoClass *mono) const
{
Validate();
mono->Set_Cursor(0, 0);
mono->Print(
"<EFBFBD>Name:<3A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Mission:<3A><><EFBFBD><EFBFBD>TarCom:<3A>NavCom:<3A>Radio:<3A>Coord:<3A><><EFBFBD>HeadTo:<3A><>St:Ŀ\n"
"<EFBFBD> <20> <20> <20> <20> <20> <20> <20> <20>\n"
"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>N<EFBFBD>Y<EFBFBD>Health:<3A><>Body:<3A>Turret:<3A>Speed:<3A>Path:<3A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Cargo:<3A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ\n"
"<EFBFBD>Active........<2E> <20> <20> <20> <20> <20> <20> <20> <20>\n"
"<EFBFBD>Limbo.........<2E> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ\n"
"<EFBFBD>Owned.........<2E> <20> <20>Last Message: <20>\n"
"<EFBFBD>Discovered....<2E> <20> <20>Timer:<3A>Arm:<3A>Track:<3A>Tiberium:<3A>Flash:<3A>Stage:<3A>Team:<3A><><EFBFBD><EFBFBD><EFBFBD>Arch:<3A>\n"
"<EFBFBD>Selected......<2E> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20>\n"
"<EFBFBD>Teathered.....<2E> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\n"
"<EFBFBD>Locked on Map.<2E> <20> <20> \n"
"<EFBFBD>Turret Locked.<2E> <20> <20> \n"
"<EFBFBD>Is A Loaner...<2E> <20> <20> \n"
"<EFBFBD>Deploying.....<2E> <20> <20> \n"
"<EFBFBD>Rotating......<2E> <20> <20> \n"
"<EFBFBD>Firing........<2E> <20> <20> \n"
"<EFBFBD>Driving.......<2E> <20> <20> \n"
"<EFBFBD>To Look.......<2E> <20> <20> \n"
"<EFBFBD>Recoiling.....<2E> <20> <20> \n"
"<EFBFBD>To Display....<2E> <20> <20> \n"
"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> \n");
mono->Set_Cursor(1, 1);mono->Printf("%s:%s", House->Class->IniName, Class->IniName);
CargoClass::Debug_Dump(mono);
MissionClass::Debug_Dump(mono);
TarComClass::Debug_Dump(mono);
}
#endif
/***********************************************************************************************
* UnitClass::Sort_Y -- Give Y coordinate sort value for unit. *
* *
* This routine is used by the rendering system in order to sort the *
* game objects in a back to front order. This is now the correct *
* overlap effect is achieved. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with a coordinate value that can be used for sorting. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/17/1994 JLB : Created. *
*=============================================================================================*/
COORDINATE UnitClass::Sort_Y(void) const
{
Validate();
if (IsTethered && *this == UNIT_HOVER) {
return(Coord_Add(Coord, 0xFF800000L));
}
return(Coord_Add(Coord, 0x00800000L));
}
/***********************************************************************************************
* UnitClass::AI -- AI processing for the unit. *
* *
* This routine will perform the AI processing necessary for the unit. These are non- *
* graphic related operations. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/31/1994 JLB : Created. *
*=============================================================================================*/
void UnitClass::AI(void)
{
Validate();
/*
** Act on new orders if the unit is at a good position to do so.
*/
if (!IsDriving && Is_Door_Closed() /*Mission != MISSION_UNLOAD*/) {
Commence();
}
TarComClass::AI();
/*
** Delete this unit if it finds itself off the edge of the map and it is in
** guard or other static mission mode.
*/
if (!Team && Mission == MISSION_GUARD && MissionQueue == MISSION_NONE && !Map.In_Radar(Coord_Cell(Coord))) {
Stun();
Delete_This();
return;
}
/*
** Rocket launchers will reload every so often.
*/
if (*this == UNIT_MSAM && Ammo < Class->MaxAmmo) {
if (IsDriving) {
Reload = Reload + 1;
} else {
if (Reload.Expired()) {
Ammo++;
if (Ammo < Class->MaxAmmo) {
Reload = TICKS_PER_SECOND*30;
}
Mark(MARK_CHANGE);
}
}
}
/*
** Hover landers always are flagged to redraw since they don't record themselves
** on the map in the normal fashion.
*/
if (*this == UNIT_HOVER) {
// Mark_For_Redraw();
//if (IsDown) Mono_Printf("*");
Mark(MARK_CHANGE);
}
/*
** If this is a vehicle that heals itself (e.g., Mammoth Tank), then it will perform
** the heal logic here.
*/
if (*this == UNIT_HTANK && (Frame % 16) == 0 && Health_Ratio() < 0x0080) {
Strength++;
Mark(MARK_CHANGE);
}
if (*this == UNIT_VICE && Map[Coord_Cell(Coord)].Land_Type() == LAND_TIBERIUM && Health_Ratio() < 0x0100 && (Frame % 16) == 0) {
Strength++;
Mark(MARK_CHANGE);
}
/*
** Transporters require special logic handled here since there isn't a MISSION_WAIT_FOR_PASSENGERS
** mission that they can follow. Passenger loading is merely a part of their normal operation.
*/
if (Class->IsTransporter) {
/*
** Double check that there is a passenger that is trying to load or unload.
** If not, then close the door.
*/
if (!Is_Door_Closed() && Mission != MISSION_UNLOAD && Transmit_Message(RADIO_TRYING_TO_LOAD) != RADIO_ROGER) {
APC_Close_Door();
}
}
/*
** Don't start a new mission unless the vehicle is in the center of
** a cell (not driving) and the door (if any) is closed.
*/
if (!IsDriving && Is_Door_Closed()/*&& Mission != MISSION_UNLOAD*/) {
Commence();
}
/*
** Handle recoil recovery here.
*/
if (IsInRecoilState) {
IsInRecoilState = false;
Mark(MARK_CHANGE);
}
/*
** For animating objects such as Visceroids, max-out their animation
** stages here
*/
if (Class->IsAnimating) {
if (!Fetch_Rate()) Set_Rate(2);
StageClass::Graphic_Logic();
if (Fetch_Stage() >= Get_Build_Frame_Count(Class->Get_Image_Data())-1) {
Set_Stage(0);
}
}
/*
** for Jurassic objects, animate them if they're walking
*/
// Assume funpark mode might be required. ST - 10/14/2019 11:53AM
if (Class->IsPieceOfEight) { // && Special.IsJurassic && AreThingiesEnabled) {
// Only animate if they're walking
if (IsDriving || IsFiring) {
if (!Fetch_Rate()) {
Set_Rate(Options.Normalize_Delay(2));
Set_Stage(0);
}
StageClass::Graphic_Logic();
if (Fetch_Stage() >= ( (IsDriving || *this == UNIT_TREX || *this == UNIT_RAPT) ? 8 : 12) ) {
Set_Stage(0);
if (IsFiring) {
Set_Rate(0);
IsFiring = false;
}
}
}
}
/*
** Scatter units off buildings in guard modes.
*/
if (!IsTethered && !IsFiring && !IsDriving && !IsRotating && (Mission == MISSION_GUARD || Mission == MISSION_GUARD_AREA) && MissionQueue == MISSION_NONE && Map[Coord_Cell(Coord)].Cell_Building() != NULL) {
Scatter(0, true, true);
}
/*
** A cloaked object that is carrying the flag will always shimmer.
*/
if (Cloak == CLOAKED && Flagged != HOUSE_NONE) {
Do_Shimmer();
}
}
/***********************************************************************************************
* UnitClass::Can_Fire -- Determines if this unit can fire. *
* *
* INPUT: target -- The target that is desired to fire upon. *
* *
* which -- The weapon (primary=0, secondary=1) to fire. *
* *
* OUTPUT: Returns with the fire error number if it cannot fire or else FIRE_OK. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/08/1995 JLB : Created. *
*=============================================================================================*/
FireErrorType UnitClass::Can_Fire(TARGET target, int which) const
{
Validate();
FireErrorType cf;
cf = TarComClass::Can_Fire(target, which);
if (cf == FIRE_OK) {
/*
** If it's a dinosaur, when it's OK to fire we should start the firing
** animation, but wait for the proper attack stage before starting the
** bullet, so things won't die prematurely.
*/
if (Class->IsFireAnim) {
if (!IsFiring) {
UnitClass *nonconst;
nonconst = (UnitClass *)this;
nonconst->Set_Rate(Options.Normalize_Delay(2));
nonconst->Set_Stage(0);
// Cast out the const. ST - 12/18/2018 1:03PM
((UnitClass*)this)->IsFiring = true;
cf = FIRE_BUSY;
} else {
if (Fetch_Stage() < 4) cf = FIRE_BUSY;
}
}
}
return(cf);
}
/***********************************************************************************************
* UnitClass::Receive_Message -- Handles receiving a radio message. *
* *
* This is the handler function for when a unit receives a radio *
* message. Typical use of this is when a unit unloads from a hover *
* class so that clearing of the transport is successful. *
* *
* INPUT: from -- Pointer to the originator of the message. *
* *
* message -- The radio message received. *
* *
* param -- Reference to an optional parameter the might be needed to return *
* information back to the originator of the message. *
* *
* OUTPUT: Returns with the radio message response. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/22/1994 JLB : Created. *
*=============================================================================================*/
RadioMessageType UnitClass::Receive_Message(RadioClass * from, RadioMessageType message, long & param)
{
Validate();
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
/*
** Checks to see if this object is in need of service depot processing.
*/
case RADIO_NEED_REPAIR:
if (!IsDriving && !Target_Legal(NavCom) && Health_Ratio() >= 0x100) return(RADIO_NEGATIVE);
break;
/*
** Asks if the passenger can load on this transport.
*/
case RADIO_CAN_LOAD:
if (Class->IsTransporter && How_Many() < Class->Max_Passengers() && from && House->Class->House == from->Owner()) {
return(RADIO_ROGER);
}
return(RADIO_NEGATIVE);
/*
** The refinery has told this harvester that it should begin the backup procedure
** so that proper unloading may take place.
*/
case RADIO_BACKUP_NOW:
TarComClass::Receive_Message(from, message, param);
if (!IsRotating && PrimaryFacing != DIR_SW) {
Do_Turn(DIR_SW);
} else {
if (!IsDriving) {
Force_Track(BACKUP_INTO_REFINERY, Adjacent_Cell(Center_Coord(), FACING_N));
Set_Speed(128);
}
}
return(RADIO_ROGER);
/*
** This message is sent by the passenger when it determines that it has
** entered the transport.
*/
case RADIO_IM_IN:
if (How_Many() == Class->Max_Passengers()) {
APC_Close_Door();
}
return(RADIO_ATTACH);
/*
** Docking maintenance message received. Check to see if new orders should be given
** to the impatient unit.
*/
case RADIO_DOCKING:
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
/*
** Check for the case of a docking message arriving from a unit that does not
** have formal radio contact established. This might be a unit that is standing
** by. If this transport is free to proceed with normal docking operation, then
** establish formal contact now. If the transport is completely full, then break
** off contact. In all other cases, just tell the pending unit to stand by.
*/
if (Contact_With_Whom() != from) {
/*
** Can't ever load up so tell the passenger to bug off.
*/
if (How_Many() >= Class->Max_Passengers()) {
return(RADIO_NEGATIVE);
}
/*
** Establish contact and let the loading process proceed normally.
*/
if (!In_Radio_Contact()) {
Transmit_Message(RADIO_HELLO, from);
} else {
/*
** This causes the potential passenger to think that all is ok and to
** hold on for a bit.
*/
return(RADIO_ROGER);
}
}
if (Class->IsTransporter && *this == UNIT_APC && How_Many() < Class->Max_Passengers()) {
TarComClass::Receive_Message(from, message, param);
/*
** Check if the APC is busy with an order
*/
bool is_busy = Mission == MISSION_MOVE;
if ((!IsRotating || Target_Legal(TarCom)) && !IsTethered) {
/*
** If the potential passenger needs someplace to go, then figure out a good
** spot and tell it to go.
*/
if (Transmit_Message(RADIO_NEED_TO_MOVE, from) == RADIO_ROGER) {
/*
** If the unit has a target, don't bother with turning logic
*/
CELL cell;
DirType dir;
if (Target_Legal(TarCom)) {
dir = PrimaryFacing.Current();
cell = Adjacent_Cell(Coord_Cell(Coord), Direction(from));
}
else {
dir = Desired_Load_Dir(from, cell);
}
/*
** If no adjacent free cells are detected, then passenger loading
** cannot occur. Break radio contact.
*/
if (cell == 0) {
Transmit_Message(RADIO_OVER_OUT, from);
} else {
param = (long)::As_Target(cell);
if (!is_busy && !IsDriving) {
Do_Turn(dir);
/*
** If it is now facing the correct direction, then open the
** transport doors. Close the doors if the transport is or needs
** to rotate.
*/
if (IsRotating) {
if (!Is_Door_Closed()) {
APC_Close_Door();
}
} else {
if (!Is_Door_Open()) {
APC_Open_Door();
}
}
}
/*
** Tell the potential passenger where it should go. If the passenger is
** already at the staging location, then tell it to move onto the transport
** directly.
*/
if (Transmit_Message(RADIO_MOVE_HERE, param, from) == RADIO_YEA_NOW_WHAT) {
if (Is_Door_Open() || Target_Legal(TarCom)) {
param = (long)As_Target();
Transmit_Message(RADIO_TETHER);
if (Transmit_Message(RADIO_MOVE_HERE, param, from) != RADIO_ROGER) {
Transmit_Message(RADIO_OVER_OUT, from);
} else {
Contact_With_Whom()->Unselect();
}
}
}
}
}
}
return(RADIO_ROGER);
}
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 (Class->IsToHarvest && In_Radio_Contact() && Mission == MISSION_ENTER) {
TechnoClass * contact = Contact_With_Whom();
if (contact->What_Am_I() == RTTI_BUILDING && *((BuildingClass*)contact) == STRUCT_REFINERY) {
// Slight hack; set a target so the harvest mission knows to skip to finding home state
Assign_Mission(MISSION_HARVEST);
TarCom = As_Target();
return(RADIO_ROGER);
}
}
return(DriveClass::Receive_Message(from, message, param));
/*
** When this message is received, it means that the other object
** has already turned its radio off. Turn this radio off as well.
*/
case RADIO_OVER_OUT:
if (Mission == MISSION_RETURN) {
Assign_Mission(MISSION_GUARD);
}
TarComClass::Receive_Message(from, message, param);
return(RADIO_ROGER);
}
return(TarComClass::Receive_Message(from, message, param));
}
/***********************************************************************************************
* UnitClass::Unlimbo -- Removes unit from stasis. *
* *
* This routine will place a unit into the game and out of its limbo *
* state. This occurs whenever a unit is unloaded from a transport. *
* *
* INPUT: coord -- The coordinate to make the unit appear. *
* *
* dir -- The initial facing to impart upon the unit. *
* *
* OUTPUT: bool; Was the unit unlimboed successfully? If the desired *
* coordinate is illegal, then this might very well return *
* false. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/22/1994 JLB : Created. *
*=============================================================================================*/
bool UnitClass::Unlimbo(COORDINATE coord, DirType dir)
{
Validate();
/*
** All units must start out facing one of the 8 major directions.
*/
dir = Facing_Dir(Dir_Facing(dir));
if (TarComClass::Unlimbo(coord, dir)) {
/*
** Ensure that the owning house knows about the
** new object.
*/
House->UScan |= (1L << Class->Type);
House->ActiveUScan |= (1L << Class->Type);
/*
** If it starts off the edge of the map, then it already starts cloaked.
*/
if (IsCloakable && !IsLocked) Cloak = CLOAKED;
/*
** Units default to no special animation.
*/
Set_Rate(0);
Set_Stage(0);
/*
** A gun boat and a hover craft are allowed to exit the map thus we
** flag them so they can. This undoes the work of Techno::Unlimbo which
** stole their IsALoaner flag.
*/
if (*this == UNIT_GUNBOAT || *this == UNIT_HOVER) {
IsALoaner = true;
}
/*
** Start the gunboat animating when it is unlimboed.
*/
if (*this == UNIT_GUNBOAT) {
Set_Rate(2);
Set_Stage(0);
}
return(true);
}
return(false);
}
/***********************************************************************************************
* UnitClass::Take_Damage -- Inflicts damage points on a unit. *
* *
* This routine will inflict the specified number of damage points on *
* the given unit. If the unit is destroyed, then this routine will *
* remove the unit cleanly from the game. The return value indicates *
* whether the unit was destroyed. This will allow appropriate death *
* animation or whatever. *
* *
* INPUT: damage-- The number of damage points to inflict. *
* *
* distance -- The distance from the damage center point to the object's center point.*
* *
* warhead--The type of damage to inflict. *
* *
* source -- Who is responsible for this damage? *
* *
* OUTPUT: Returns the result of the damage process. This can range from RESULT_NONE up to *
* RESULT_DESTROYED. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/30/1991 JLB : Created. *
* 07/12/1991 JLB : Script initiated by unit destruction. *
* 04/15/1994 JLB : Converted to member function. *
* 04/16/1994 JLB : Warhead modifier. *
* 06/03/1994 JLB : Added the source of the damage target value. *
* 06/20/1994 JLB : Source is a base class pointer. *
* 11/22/1994 JLB : Shares base damage handler for techno objects. *
* 06/30/1995 JLB : Lasers do maximum damage against gunboat. *
* 08/16/1995 JLB : Harvester crushing doesn't occur on early missions. *
*=============================================================================================*/
ResultType UnitClass::Take_Damage(int & damage, int distance, WarheadType warhead, TechnoClass * source)
{
Validate();
ResultType res = RESULT_NONE;
/*
** Special case: If this is a laser attacking a gunboat, then the gunboat is ALWAYS toasted.
*/
if (*this == UNIT_GUNBOAT && warhead == WARHEAD_LASER) {
damage = Strength*3;
}
/*
** Remember if this object was selected. If it was and it gets destroyed and it has
** passengers that pop out, then the passengers will inherit the select state.
*/
bool select = (Is_Selected_By_Player() && Is_Owned_By_Player()); // Fox for GlyphX multiplayer. ST - 4/16/2019 9:46AM
/*
** In order for a this to be damaged, it must either be a unit
** with a crew or a sandworm.
*/
res = TarComClass::Take_Damage(damage, distance, warhead, source);
if (res == RESULT_DESTROYED) {
Death_Announcement(source);
if (Class->Explosion != ANIM_NONE) {
AnimType anim = Class->Explosion;
/*
** SSM launchers will really explode big if they are carrying
** missiles at the time of the explosion.
*/
if (*this == UNIT_MSAM && Ammo) {
anim = ANIM_NAPALM3;
}
if (*this == UNIT_TRIC || *this == UNIT_TREX || *this == UNIT_RAPT || *this == UNIT_STEG) {
Sound_Effect(VOC_DINODIE1, Coord);
}
new AnimClass(anim, Coord);
/*
** When the flame tank blows up, it really blows up. It is
** equivalent to a napalm strike.
*/
if (Class->Explosion == ANIM_NAPALM3) {
Explosion_Damage(Coord, 200, source, WARHEAD_FIRE);
}
/*
** Very strong units that have an explosion will also rock the
** screen when they are destroyed.
*/
if (Class->MaxStrength > 400) {
Shake_The_Screen(3, Owner());
if (source && Owner() != source->Owner()) {
Shake_The_Screen(3, source->Owner());
}
}
}
/*
** Possibly have the crew member run away.
*/
Mark(MARK_UP);
if (Class->IsCrew && !Class->IsTransporter) {
if (Random_Pick(0, 1) == 0) {
InfantryClass * i = 0;
if (Class->Primary == WEAPON_NONE) {
i = new InfantryClass(INFANTRY_C1, House->Class->House);
i->IsTechnician = true;
} else {
i = new InfantryClass(INFANTRY_E1, House->Class->House);
}
if (i) {
if (i->Unlimbo(Coord, DIR_N)) {
i->Strength = Random_Pick(5, (int)i->Class->MaxStrength/2);
i->Scatter(0, true);
if (!House->IsHuman) {
i->Assign_Mission(MISSION_HUNT);
} else {
i->Assign_Mission(MISSION_GUARD);
}
if (select) i->Select();
} else {
delete i;
}
}
}
} else {
if (*this != UNIT_HOVER) {
while (Is_Something_Attached()) {
FootClass * object = Detach_Object();
if (!object) break; // How can this happen?
/*
** Only infantry can run from a destroyed vehicle. Even then, it is not a sure
** thing.
*/
if (object->Is_Infantry() && object->Unlimbo(Coord, DIR_N)) {
// object->Strength = Random_Pick(5, (int)((InfantryClass*)object)->Class->MaxStrength/2);
object->Look(false);
object->Scatter(0, true);
if (select) object->Select();
} else {
object->Record_The_Kill(source);
delete object;
}
}
} else {
Kill_Cargo(source);
}
}
/*
** When the mobile head quarters blows up, the entire side blows up.
*/
if (*this == UNIT_MHQ) {
House->Flag_To_Die();
}
if (*this == UNIT_MCV) {
if (House) {
House->Check_Pertinent_Structures();
}
}
/*
** Finally, delete the vehicle.
*/
Delete_This();
} else {
/*
** When damaged and below half strength, start smoking if
** it isn't already smoking.
*/
if (Health_Ratio() < 0x0080 && !IsAnimAttached && *this != UNIT_VICE && *this != UNIT_STEG && *this != UNIT_TREX && *this != UNIT_TRIC && *this != UNIT_RAPT) {
AnimClass * anim = new AnimClass(ANIM_SMOKE_M, Coord_Add(Coord, XYP_Coord(0, -8)));
if (anim) anim->Attach_To(this);
}
/*
** If at half damage, then start smoking or burning as appropriate.
*/
if (res == RESULT_HALF) {
if (*this == UNIT_GUNBOAT) {
AnimClass * anim = new AnimClass(ANIM_ON_FIRE_MED, Coord_Add(Coord, XYP_Coord(Random_Pick(0, 16)-8, -2)));
if (anim) anim->Attach_To(this);
}
}
/*
** Try to crush anyone that fires on this unit if possible. The harvester
** typically is the only one that will qualify here.
*/
if (!Team && source && !IsTethered && !House->Is_Ally(source) && (!House->IsHuman || Special.IsSmartDefense)) {
/*
** Try to crush the attacker if it can be crushed by this unit and this unit is
** not equipped with a flame type weapon. If this unit has a weapon and the target
** is not very close, then fire on it instead. In easy mode, they never run over the
** player. In hard mode, they always do. In normal mode, they only overrun past
** mission #8.
*/
if ((Class->Primary == WEAPON_NONE || (Distance(source) < 0x0180 && BulletTypeClass::As_Reference(Weapons[Class->Primary].Fires).Warhead != WARHEAD_FIRE)) &&
(GameToPlay != GAME_NORMAL ||
*this != UNIT_HARVESTER ||
BuildLevel > 8 ||
PlayerPtr->Difficulty == DIFF_HARD) &&
!(GameToPlay == GAME_NORMAL && PlayerPtr->Difficulty == DIFF_EASY) &&
Class->IsCrusher && source->Is_Techno() && ((TechnoTypeClass const &)source->Class_Of()).IsCrushable) {
Assign_Destination(source->As_Target());
Assign_Mission(MISSION_MOVE);
} else {
/*
** Try to return to base if possible.
*/
if (*this == UNIT_HARVESTER && Pip_Count() && Health_Ratio() < 0x0080) {
/*
** Find nearby refinery and head to it?
*/
BuildingClass * building = Find_Docking_Bay(STRUCT_REFINERY, false);
/*
** Since the refinery said it was ok to load, establish radio
** contact with the refinery and then await docking orders.
*/
if (building && Transmit_Message(RADIO_HELLO, building) == RADIO_ROGER) {
Assign_Mission(MISSION_ENTER);
}
}
}
}
/*
** Computer controlled harvester will radio for help if they are attacked.
*/
if (*this == UNIT_HARVESTER && !House->IsHuman && source) {
Base_Is_Attacked(source);
}
}
return(res);
}
/***********************************************************************************************
* UnitClass::new -- Allocate a unit slot and adjust access arrays. *
* *
* This routine will allocate a unit from the available unit pool and *
* fixup all the access lists to match. It will allocate a unit slot *
* from within the range allowed for the specified unit type. If no *
* slot was found, then it will fail. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with a pointer to the allocated unit. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/11/1994 JLB : Created. *
* 04/21/1994 JLB : Converted to operator new. *
*=============================================================================================*/
void * UnitClass::operator new(size_t)
{
void * ptr = (UnitClass *)Units.Allocate();
if (ptr) {
((UnitClass *)ptr)->Set_Active();
}
return(ptr);
}
/***********************************************************************************************
* UnitClass::delete -- Deletion operator for units. *
* *
* This removes the unit from the local allocation system. Since this *
* is a fixed block of memory, not much has to be done to delete the *
* unit. Merely marking it as inactive is enough. *
* *
* INPUT: ptr -- Pointer to the unit to delete. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/21/1994 JLB : Created. *
*=============================================================================================*/
void UnitClass::operator delete(void *ptr)
{
if (ptr) {
((UnitClass *)ptr)->IsActive = false;
}
Units.Free((UnitClass *)ptr);
//Map.Validate();
}
/***********************************************************************************************
* UnitClass::~UnitClass -- Destructor for unit objects. *
* *
* This destructor will lower the unit count for the owning house as well as inform any *
* other units in communication, that this unit is about to leave reality. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/15/1994 JLB : Created. *
*=============================================================================================*/
UnitClass::~UnitClass(void)
{
if (GameActive && Class) {
#ifdef USE_RA_AI
//
// Added for RA AI in TD. ST - 7/26/2019 9:12AM
//
House->Tracking_Remove(this);
#endif // USE_RA_AI
/*
** If there are any cargo members, delete them.
*/
while (Is_Something_Attached()) {
delete Detach_Object();
}
Limbo();
}
if (GameActive && Team) Team->Remove(this);
}
/***********************************************************************************************
* UnitClass::UnitClass -- Constructor for units. *
* *
* This constructor for units will initialize the unit into the game *
* system. It will be placed in all necessary tracking lists. The initial condition will *
* be in a state of limbo. *
* *
* INPUT: classid -- The type of unit to create. *
* *
* house -- The house owner of this unit. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/21/1994 JLB : Created. *
*=============================================================================================*/
UnitClass::UnitClass(UnitType classid, HousesType house) :
TarComClass(classid, house)
{
Flagged = HOUSE_NONE;
Reload = 0;
Ammo = Class->MaxAmmo;
IsCloakable = Class->IsCloakable;
TiberiumUnloadRefinery = NULL;
if (Class->IsAnimating) Set_Rate(Options.Normalize_Delay(3));
/*
** Keep count of the number of units created.
*/
if (GameToPlay == GAME_INTERNET){
House->UnitTotals->Increment_Unit_Total((int)classid);
}
#ifdef USE_RA_AI
//
// Added for RA AI in TD. ST - 7/26/2019 9:12AM
//
House->Tracking_Add(this);
#endif // USE_RA_AI
}
/***********************************************************************************************
* UnitClass::Active_Click_With -- Intercepts the active click to see if deployment is possible*
* *
* This routine intercepts the active click operation. It check to see if this is a self *
* deployment request (MCV's have this ability). If it is, then the object is initiated *
* to self deploy. In the other cases, it passes the operation down to the lower *
* classes for processing. *
* *
* INPUT: action -- The action requested of the unit. *
* *
* object -- The object that the mouse pointer is over. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/10/1995 JLB : Created. *
*=============================================================================================*/
void UnitClass::Active_Click_With(ActionType action, ObjectClass * object)
{
Validate();
if (action != What_Action(object)) {
switch (action) {
case ACTION_SABOTAGE:
case ACTION_CAPTURE:
action = ACTION_ATTACK;
break;
case ACTION_ENTER:
action = ACTION_MOVE;
break;
default:
action = ACTION_NONE;
break;
}
}
TarComClass::Active_Click_With(action, object);
}
void UnitClass::Active_Click_With(ActionType action, CELL cell) {TarComClass::Active_Click_With(action, cell);};
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
void UnitClass::Player_Assign_Mission(MissionType mission, TARGET target, TARGET destination)
{
Validate();
if (mission == MISSION_HARVEST) {
ArchiveTarget = TARGET_NONE;
} else if (mission == MISSION_ENTER) {
BuildingClass* building = As_Building(destination);
if (building != NULL && *building == STRUCT_REFINERY && building->In_Radio_Contact()) {
building->Transmit_Message(RADIO_OVER_OUT);
}
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
}
TarComClass::Player_Assign_Mission(mission, target, destination);
}
/***********************************************************************************************
* UnitClass::Enter_Idle_Mode -- Unit enters idle mode state. *
* *
* This routine is called when the unit completes one mission but does not have a clear *
* follow up mission to perform. In such a case, the unit should enter a default idle *
* state. This idle state varies depending on what the current internal computer *
* settings of the unit is as well as what kind of unit it is. *
* *
* INPUT: initial -- Is this called when the unit just leaves a factory or is initially *
* or is initially placed on the map? *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/31/1994 JLB : Created. *
* 06/03/1994 JLB : Fixed to handle non-combat vehicles. *
* 06/18/1995 JLB : Allows a harvester to stop harvesting. *
*=============================================================================================*/
void UnitClass::Enter_Idle_Mode(bool initial)
{
Validate();
MissionType order;
/*
** A movement mission without a NavCom would be pointless to have a radio contact since
** no radio coordination occurs on a just a simple movement mission.
*/
if (Mission == MISSION_MOVE && !Target_Legal(NavCom)) {
Transmit_Message(RADIO_OVER_OUT);
}
if (Class->Primary == WEAPON_NONE) {
if (Class->IsToHarvest) {
if (!In_Radio_Contact() && Mission != MISSION_HARVEST) {
if (initial || !House->IsHuman || Map[Coord_Cell(Coord)].Land_Type() == LAND_TIBERIUM) {
order = MISSION_HARVEST;
} else {
order = MISSION_GUARD;
}
Assign_Target(TARGET_NONE);
Assign_Destination(TARGET_NONE);
} else {
return;
}
} else {
if (IsALoaner && Class->IsTransporter && Is_Something_Attached() && !Team) {
order = MISSION_UNLOAD;
} else {
order = MISSION_GUARD;
Assign_Target(TARGET_NONE);
Assign_Destination(TARGET_NONE);
}
}
} else {
if (Target_Legal(TarCom)) {
order = MISSION_ATTACK;
} else {
if (Target_Legal(NavCom)) {
order = MISSION_MOVE;
} else {
if (GameToPlay == GAME_NORMAL || House->IsHuman) {
order = MISSION_GUARD;
} else {
//if (GameToPlay != GAME_NORMAL) {
#ifndef USE_RA_AI
// Don't use MISSION_TIMED_HUNT since this can trigger the Blitz behavior
order = MISSION_TIMED_HUNT;
#else
//
// Added for RA AI in TD. ST - 7/26/2019 9:12AM
//
// This applies only to non-human houses in a non-normal game type
//
order = MISSION_GUARD;
if (Mission == MISSION_GUARD || Mission == MISSION_GUARD_AREA) {
return;
}
if (!Team) {
if (House->IQ >= Rule.IQGuardArea) {
if (Is_Weapon_Equipped()) {
order = MISSION_GUARD_AREA;
}
}
}
#endif
//} else {
// order = MISSION_HUNT;
//}
}
}
}
}
Assign_Mission(order);
}
/***********************************************************************************************
* UnitClass::Find_LZ -- Maintenance function for transport units. *
* *
* This is a maintenance function for transport units. It checks to see if it is loaded *
* with cargo, but it doesn't know where to put it. In such a case, the unit must look *
* for a landing zone (LZ) to unload the cargo. This routine should be called every so *
* often. Typically, calling this routine is controlled by the scripts. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/31/1994 JLB : Created. *
*=============================================================================================*/
void UnitClass::Find_LZ(void)
{
Validate();
CELL cell; // Map exit cell number.
if (*this == UNIT_HOVER) {
if (!IsRotating && Is_Something_Attached() && !Target_Legal(NavCom)) {
cell = Map.Calculated_Cell(SOURCE_BEACH, House->Class->House);
Assign_Destination(::As_Target(cell));
}
}
}
/***********************************************************************************************
* UnitClass::Unload_Hovercraft_Process -- Handles unloading hovercraft transport. *
* *
* This is a maintenance routine to handle the special operations necessary for a *
* hovercraft transport. This routine checks to see if special unloading operations are *
* necessary and performs them. These operations can include unloading the transported *
* object, finding a new beach cell, and rotating to a convenient unloading facing. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Has the transport finished its unloading mission? This is true after the *
* hovercraft has completely dispatched its cargo. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/31/1994 JLB : Created. *
* 07/31/1995 JLB : Second infantry unloaded MUST be the one tethered. *
*=============================================================================================*/
bool UnitClass::Unload_Hovercraft_Process(void)
{
Validate();
bool unloaded = false;
FootClass *unit; // The unit to be unloaded.
CELL cell; // Cell to unload to.
/*
** If the hovercraft is currently waiting for the last unit
** to completely unload, then don't do anything.
*/
if (IsTethered || IsRotating) {
return(false);
}
if (Is_Something_Attached()) {
/*
** Only unload if the hovercraft has reached the beach.
*/
if (!Target_Legal(NavCom)) {
cell = Coord_Cell(Adjacent_Cell(Coord, Dir_Facing(PrimaryFacing.Current())));
unit = (FootClass *)Attached_Object();
Mark(MARK_UP);
if (Map.In_Radar(cell) && !Map[cell].Cell_Unit()) {
if (unit->Can_Enter_Cell(cell, FACING_NONE) == MOVE_OK) {
/*
** Place all the transported units onto the map.
*/
int count = 0;
bool first = true;
FootClass * secondary = 0;
while (Attached_Object()) {
FootClass * u = (FootClass *)Detach_Object();
if (!first && !secondary) secondary = u;
first = false;
/*
** Place the unit on the map and start it heading in the right direction.
*/
ScenarioInit++;
if (u->Unlimbo(Coord_Add(Coord & 0xFF00FF00L, StoppingCoordAbs[count]), DIR_N)) {
u->Assign_Mission(MISSION_MOVE);
u->NavCom = ::As_Target(cell);
u->Path[0] = Dir_Facing(u->PrimaryFacing.Current());
u->Path[1] = FACING_NONE;
u->Set_Speed(0x80);
u->IsUnloading = true;
u->Look(false);
} else {
/*
** Couldn't unlimbo for some strange reason. Kill the unit off.
*/
delete u;
}
ScenarioInit--;
count++;
}
if (secondary) unit = secondary;
/*
** Establish radio contact bond with the transport
** hovercraft. This bond tells the hovercraft to
** not move until the unit has completely unloaded.
*/
if (Transmit_Message(RADIO_HELLO, unit) == RADIO_ROGER) {
Transmit_Message(RADIO_UNLOAD);
}
Mark(MARK_DOWN);
Map.Layer[LAYER_GROUND].Sort();
Map.Layer[LAYER_GROUND].Sort();
Map.Layer[LAYER_GROUND].Sort();
return(false);
} else {
/*
** If the attached object cannot unload because the desired destination
** cell is impassable, then abort the landing. This is faked by pretending
** that the unload was successful. The controlling routine will cause
** the transport to leave.
*/
Mark(MARK_DOWN);
return(false);
// return(true);
}
}
Mark(MARK_DOWN);
}
} else {
return(true);
}
return(unloaded);
}
/***********************************************************************************************
* UnitClass::Goto_Clear_Spot -- Finds a clear spot to deploy. *
* *
* This routine is used by the MCV to find a clear spot to deploy. If a clear spot *
* is found, then the MCV will assign that location to its navigation computer. This only *
* occurs if the MCV isn't already heading toward a spot. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Is the located at a spot where it can deploy? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/27/1994 JLB : Created. *
*=============================================================================================*/
bool UnitClass::Goto_Clear_Spot(void)
{
Validate();
Mark(MARK_UP);
if (!Target_Legal(NavCom) && BuildingTypeClass::As_Reference(STRUCT_CONST).Legal_Placement(Coord_Cell(Adjacent_Cell(Center_Coord(), FACING_NW)))) {
Mark(MARK_DOWN);
return(true);
}
if (!Target_Legal(NavCom)) {
#ifndef USE_RA_AI
/*
** This scan table is skewed to north scanning only. This should
** probably be converted to a more flexible method.
*/
static int _offsets[] = {
-MAP_CELL_W*1,
-MAP_CELL_W*2,
-(MAP_CELL_W*2)+1,
-(MAP_CELL_W*2)-1,
-MAP_CELL_W*3,
-(MAP_CELL_W*3)+1,
-(MAP_CELL_W*3)-1,
-(MAP_CELL_W*3)+2,
-(MAP_CELL_W*3)-2,
-MAP_CELL_W*4,
-(MAP_CELL_W*4)+1,
-(MAP_CELL_W*4)-1,
-(MAP_CELL_W*4)+2,
-(MAP_CELL_W*4)-2,
0
};
int *ptr;
ptr = &_offsets[0];
while (*ptr) {
CELL cell = Coord_Cell(Coord)+*ptr++;
if (BuildingTypeClass::As_Reference(STRUCT_CONST).Legal_Placement(cell)) {
Assign_Destination(::As_Target(cell));
break;
}
}
#else //USE_RA_AI
//
// Pulled in the extra offsets from RA, and started at a random position in the array. ST - 7/26/2019 2:07PM
//
static int _offset_count = 36;
static int _offsets[] = {
-MAP_CELL_W*1,
-MAP_CELL_W*2,
-(MAP_CELL_W*2)+1,
-(MAP_CELL_W*2)-1,
-MAP_CELL_W*3,
-(MAP_CELL_W*3)+1,
-(MAP_CELL_W*3)-1,
-(MAP_CELL_W*3)+2,
-(MAP_CELL_W*3)-2,
-MAP_CELL_W*4,
-(MAP_CELL_W*4)+1,
-(MAP_CELL_W*4)-1,
-(MAP_CELL_W*4)+2,
-(MAP_CELL_W*4)-2,
//BG: Added south scanning
MAP_CELL_W*1,
MAP_CELL_W*2,
(MAP_CELL_W*2)+1,
(MAP_CELL_W*2)-1,
MAP_CELL_W*3,
(MAP_CELL_W*3)+1,
(MAP_CELL_W*3)-1,
(MAP_CELL_W*3)+2,
(MAP_CELL_W*3)-2,
MAP_CELL_W*4,
(MAP_CELL_W*4)+1,
(MAP_CELL_W*4)-1,
(MAP_CELL_W*4)+2,
(MAP_CELL_W*4)-2,
//BG: Added some token east/west scanning
-1,-2,-3,-4,
1, 2, 3, 4,
0
};
int offset_index = Random_Pick(0, _offset_count);
for (int i=0 ; i<_offset_count ; i++) {
CELL cell = Coord_Cell(Coord) + _offsets[offset_index++];
if (offset_index >= _offset_count || _offsets[offset_index] == 0) {
offset_index = 0;
}
if (BuildingTypeClass::As_Reference(STRUCT_CONST).Legal_Placement(cell)) {
Assign_Destination(::As_Target(cell));
break;
}
}
#endif //USE_RA_AI
}
Mark(MARK_DOWN);
return(false);
}
/***********************************************************************************************
* UnitClass::Try_To_Deploy -- The unit attempts to "deploy" at current location. *
* *
* Certain units have the ability to deploy into a building. When this routine is called *
* for one of those units, it will attempt to deploy at its current location. If the unit *
* is in motion to a destination or it isn't one of the special units that can deploy or *
* it isn't allowed to deploy at this location for some reason it won't deploy. In all *
* other cases, it will begin to deploy and once it begins only a player abort action will *
* stop it. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Was deployment begun? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/18/1994 JLB : Created. *
*=============================================================================================*/
bool UnitClass::Try_To_Deploy(void)
{
Validate();
if (!Target_Legal(NavCom) && !IsRotating) {
if (*this == UNIT_MCV) {
/*
** Determine if it is legal to deploy at this location. If not, tell the
** player.
*/
Mark(MARK_UP);
if (!BuildingTypeClass::As_Reference(STRUCT_CONST).Legal_Placement(Coord_Cell(Adjacent_Cell(Center_Coord(), FACING_NW)))) {
if (PlayerPtr == House) {
Speak(VOX_DEPLOY);
}
Mark(MARK_DOWN);
IsDeploying = false;
return(false);
}
Mark(MARK_DOWN);
/*
** If the unit is not facing the correct direction, then start it rotating
** toward the right facing, but still flag it as if it had deployed. This is
** because it will deploy as soon as it reaches the correct facing.
*/
if (PrimaryFacing.Current() != DIR_SW) {
Do_Turn(DIR_SW);
// PrimaryFacing.Set_Desired(DIR_SW);
IsDeploying = true;
return(true);
}
/*
** Since the unit is already facing the correct direction, actually do the
** deploy logic. If for some reason this cannot occur, then don't delete the
** unit, just mark it as not deploying.
*/
Mark(MARK_UP);
BuildingClass * building = new BuildingClass(STRUCT_CONST, House->Class->House);
if (building) {
if (building->Unlimbo(Adjacent_Cell(Coord, FACING_NW))) {
/*
** Always reveal the construction yard to the player that owned the
** mobile construction vehicle.
*/
building->Revealed(House);
/*
** Force the newly placed construction yard to be in the same strength
** ratio as the MCV that deployed into it.
*/
int ratio = Health_Ratio();
building->Strength = Fixed_To_Cardinal(building->Class->MaxStrength, ratio);
/*
** Force the MCV to drop any flag it was carrying. This will also set
** the owner house's flag home cell (since the house's FlagHome is
** presumably 0 at this point).
*/
Stun();
Delete_This();
return(true);
} else {
/*
** Could not deploy the construction yard at this location! Just revert
** back to normal "just sitting there" mode and await further instructions.
*/
delete building;
}
}
Mark(MARK_DOWN);
IsDeploying = false;
}
}
return(false);
}
/***********************************************************************************************
* UnitClass::Per_Cell_Process -- Performs operations necessary on a per cell basis. *
* *
* This routine will perform the operations necessary that occur when a unit is at the *
* center of a cell. These operations could entail deploying into a construction yard, *
* radioing a transport unit, and looking around for the enemy. *
* *
* INPUT: center -- Is the unit safely at the center of a cell? If it is merely "close" *
* to the center, then this parameter will be false. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/18/1994 JLB : Created. *
* 06/17/1995 JLB : Handles case when building says "NO!" *
* 06/30/1995 JLB : Gunboats head back and forth now. *
*=============================================================================================*/
void UnitClass::Per_Cell_Process(bool center)
{
Validate();
CELL cell = Coord_Cell(Coord);
TechnoClass * whom;
HousesType house;
/*
** If this is a unit that is driving onto a building then the unit must enter
** the building as the final step.
*/
whom = Contact_With_Whom();
if (IsTethered && whom && center) {
if (whom->What_Am_I() == RTTI_BUILDING && Mission == MISSION_ENTER) {
if (whom == Map[cell].Cell_Building()) {
switch (Transmit_Message(RADIO_IM_IN, whom)) {
case RADIO_ROGER:
break;
case RADIO_ATTACH:
Mark(MARK_UP);
SpecialFlag = true;
Limbo();
SpecialFlag = false;
whom->Attach(this);
return;
default:
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);
break;
}
}
}
}
/*
** When breaking away from a transport object or building, possibly
** scatter or otherwise begin normal unit operations.
*/
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 (IsTethered && center &&
(Mission != MISSION_ENTER || (As_Techno(NavCom) != NULL && Contact_With_Whom() != As_Techno(NavCom))) &&
Mission != MISSION_UNLOAD) {
/*
** Special hack check to make sure that even though it has moved one
** cell, if it is still on the building (e.g., service depot), have
** it scatter again.
*/
if (Map[cell].Cell_Building() != NULL && !Target_Legal(NavCom)) {
Scatter(0, true, true);
} 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
TechnoClass * contact = Contact_With_Whom();
if (Transmit_Message(RADIO_UNLOADED) == RADIO_RUN_AWAY) {
if (*this == UNIT_HARVESTER && contact && contact->What_Am_I() == RTTI_BUILDING && *((BuildingClass*)contact) != STRUCT_REPAIR) {
Assign_Mission(MISSION_HARVEST);
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
} else if (!Target_Legal(NavCom)) {
Scatter(0, true);
}
} else {
if (*this == UNIT_HARVESTER) {
if (Target_Legal(ArchiveTarget)) {
Assign_Mission(MISSION_HARVEST);
Assign_Destination(ArchiveTarget);
ArchiveTarget = TARGET_NONE;
} 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 place to go, move away to clear
** the pad for another harvester.
*/
if (!Target_Legal(NavCom)) {
Scatter(0, true);
}
}
}
}
}
}
#ifdef OBSOLETE
/*
** If this unit is on a teather, then cut it at this time so that
** the "parent" unit is free to proceed. Note that the parent
** unit might actually be a building.
*/
if (IsTethered && center && !Map[cell].Cell_Building()) {
if (!Tiberium || *this != UNIT_HARVESTER) {
Transmit_Message(RADIO_UNLOADED);
if (*this == UNIT_HARVESTER) {
if (Target_Legal(ArchiveTarget)) {
Assign_Mission(MISSION_HARVEST);
Assign_Destination(ArchiveTarget);
ArchiveTarget = TARGET_NONE;
} else {
/*
** Since there is no place to go, move away to clear
** the pad for another harvester.
*/
Scatter(0, true);
}
}
}
}
#endif
#ifdef OBSOLETE
/*
** If the unit is at the center of the repair facility, and that was his
** destination, then start him repairing.
*/
if (center && !IsRepairing) {
BuildingClass * b = As_Building(NavCom);
if (b && *b==STRUCT_REPAIR && Coord == b->Center_Coord()) {
NavCom = 0;
IsRepairing = true;
Transmit_Message(RADIO_REPAIR_BEGIN_ANIM);
}
}
#endif
/*
** Check to see if this is merely the end of a rotation for the MCV as it is
** preparing to deploy. In this case, it should begin its deploy process.
*/
if (center && IsDeploying) {
Try_To_Deploy();
if (!IsActive) return; // Unit no longer exists -- bail.
}
/*
** If this is a loaner unit and is is off the edge of the
** map, then it gets eliminated. That is, unless it is carrying cargo. This means that
** it is probably carrying an incoming reinforcement and it should not be eliminated.
*/
if (center && IsALoaner && !Map.In_Radar(cell)) {
if (IsReturning || !Is_Something_Attached()) {
if (*this == UNIT_GUNBOAT) {
CELL cell = Coord_Cell(Coord);
if (Cell_X(cell) <= Map.MapCellX) {
Assign_Mission(MISSION_HUNT);
Assign_Destination(::As_Target(XY_Cell(Map.MapCellX+Map.MapCellWidth, Cell_Y(cell))));
Set_Speed(255);
PrimaryFacing = DIR_E;
} else {
Assign_Mission(MISSION_HUNT);
Assign_Destination(::As_Target(XY_Cell(Map.MapCellX-1, Cell_Y(cell))));
Set_Speed(255);
PrimaryFacing = DIR_W;
}
Mark(MARK_DOWN);
} else {
Mark(MARK_DOWN);
Stun();
Delete_This();
return;
}
}
}
#ifdef OBSOLETE
/*
** Destroy any crushable wall that is driven over by a tracked vehicle.
*/
CellClass * cellptr = &Map[cell];
if (center && Class->Speed == SPEED_TRACK && cellptr->Overlay != OVERLAY_NONE) {
OverlayTypeClass const * optr = &OverlayTypeClass::As_Reference(cellptr->Overlay);
if (optr->IsCrushable) {
cellptr->Reduce_Wall(100);
cellptr->Reduce_Wall(100);
cellptr->Reduce_Wall(100);
cellptr->Reduce_Wall(100);
cellptr->Reduce_Wall(100);
cellptr->Reduce_Wall(100);
}
}
#endif
/*
** Check to see if crushing of any unfortunate infantry is warranted.
*/
Overrun_Square(Coord_Cell(Coord), false);
/*
** The unit performs looking around at this time. If the
** unit moved further than one square during the last track
** move, don't do an incremental look. Do a full look around
** instead.
*/
if (IsPlanningToLook) {
IsPlanningToLook = false;
Look(false);
} else {
Look(true);
}
/*
** Act on new orders if the unit is at a good position to do so.
*/
if (center) {
Commence();
}
/*
** Certain units require some setup time after they come to a halt.
*/
if (Special.IsDefenderAdvantage && /*center &&*/ !Target_Legal(NavCom) && Path[0] == FACING_NONE) {
if (*this == UNIT_MLRS || *this == UNIT_ARTY || *this == UNIT_MSAM) {
Arm = Rearm_Delay(false)*2;
}
}
/*
** If there is a house flag here, then this unit just might pick it up.
*/
if (center && Flagged == HOUSE_NONE) {
if (Map[cell].IsFlagged && !House->Is_Ally(Map[cell].Owner)) {
HouseClass::As_Pointer(Map[cell].Owner)->Flag_Attach(this);
}
}
/*
** If this is the unit's own flag-home-cell and the unit is carrying
** a flag, destroy the house of the flag the unit is carrying.
*/
if (Flagged != HOUSE_NONE) {
/*
** If this vehicle is carrying your flag, then it will reveal the
** map for you as well as itself. This gives you and opportunity to
** attack the unit.
*/
if (!IsOwnedByPlayer && Flagged == PlayerPtr->Class->House) {
Map.Sight_From(House, Coord_Cell(Coord), Class->SightRange, true); // Passed our house into Map.Sight_From since it now needs to know who it is performing the action on behalf of. ST - 3/28/2019 2:55PM
}
/*
** If the flag reaches the home cell for the player, then the flag's
** owner will be destroyed.
*/
if (cell == HouseClass::As_Pointer(Owner())->FlagHome && center) {
house = Flagged; // Flag_Remove will clear 'Flagged', so save it
HouseClass::As_Pointer(house)->Flag_Remove(As_Target(),true);
HouseClass::As_Pointer(house)->Flag_To_Die();
}
}
TarComClass::Per_Cell_Process(center);
}
/***********************************************************************************************
* UnitClass::Draw_It -- Draws a unit object. *
* *
* This routine is the one that actually draws a unit object. It displays the unit *
* according to its current state flags and centered at the location specified. *
* *
* INPUT: x,y -- The X and Y coordinate of where to draw the unit. *
* *
* window -- The clipping window to use. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/20/1994 JLB : Created. *
* 06/27/1994 JLB : Takes a window parameter. *
* 08/15/1994 JLB : Removed infantry support. *
* 01/07/1995 JLB : Harvester animation support. *
* 07/08/1995 JLB : Uses general purpose draw routine. *
*=============================================================================================*/
void UnitClass::Draw_It(int x, int y, WindowNumberType window)
{
Validate();
int shapenum; // Working shape number.
void const *shapefile; // Working shape file pointer.
int facing = Facing_To_32(PrimaryFacing.Current());
int tfacing = Facing_To_32(SecondaryFacing.Current());
int shapestart;
int xx, yy;
/*
** Verify the legality of the unit class.
*/
shapefile = Class->Get_Image_Data();
if (!shapefile) return;
/*
** If drawing of this unit is not explicitly prohibited, then proceed
** with the render process.
*/
const bool is_hidden = (Visual_Character() == VISUAL_HIDDEN) && (window != WINDOW_VIRTUAL);
if (!is_hidden) {
/*
** For eight facing units, adjust the facing number accordingly.
*/
if (Class->IsPieceOfEight) {
facing = Dir_Facing(PrimaryFacing.Current());
}
/*
** Calculations for special wake drawing.
*/
xx = x;
yy = y;
switch (Dir_Facing(PrimaryFacing.Current())) {
case FACING_NE:
case FACING_E:
case FACING_SE:
shapenum = UnitClass::BodyShape[tfacing] + 96;
shapestart = 0;
//xx -= 4;
break;
case FACING_W:
default:
shapenum = UnitClass::BodyShape[tfacing];
shapestart = 6;
xx += 4;
break;
}
/*
** Some units have only four facings, but are equipped with a turret
** that has 32 facings.
*/
if (Class->IsChunkyShape) {
/*
** Special wake drawing occurs here for non-virtual rendering
*/
if (*this == UNIT_GUNBOAT) {
if (window != WINDOW_VIRTUAL) {
//Added this and wake name parameters. ST - 8/20/2019 10:54AM
CC_Draw_Shape(this, "WAKE", UnitTypeClass::WakeShapes, shapestart + (Fetch_Stage() % 6), xx-1, yy+3, window, SHAPE_CENTER|SHAPE_WIN_REL);
}
if (Health_Ratio() < 0x0080) shapenum += 32;
if (Health_Ratio() < 0x0040) shapenum += 32;
} else {
/*
** Special hovercraft shape is ALWAYS N/S.
*/
shapenum = 0;
//shapenum = ((UnitClass::BodyShape[facing] + 4) / 8) & 0x03;
}
} else {
/*
** Fetch the harvesting animation stage as appropriate.
*/
if (IsHarvesting && !PrimaryFacing.Is_Rotating() && !NavCom && !IsDriving) {
static char _hstage[6] = {
0, 1, 2, 3, 2, 1
};
shapenum = 32 + (((UnitClass::BodyShape[facing]+2)/4)*4)+_hstage[Fetch_Stage()%sizeof(_hstage)];
} else {
shapenum = UnitClass::BodyShape[facing];
if (Class->IsAnimating) {
shapenum = Fetch_Stage();
}
if (Class->IsPieceOfEight) {
shapenum = 0;
int numshapes = (IsDriving || (*this == UNIT_TREX) || (*this == UNIT_RAPT)) ? 8 : 12;
if (facing) shapenum = UnitClass::BodyShape[24+facing];
if (IsDriving) shapenum = (Fetch_Stage()%numshapes) + 16 + (shapenum*numshapes);
else if (IsFiring) shapenum = (Fetch_Stage()%numshapes) + 80 + (shapenum*numshapes);
} else {
/*
** Door opening and closing animation must be handled carefully. There are only
** certain directions where this door animation will work.
*/
if (!Is_Door_Closed() && (PrimaryFacing == DIR_NW || PrimaryFacing == DIR_NE)) {
if (PrimaryFacing == DIR_NE) {
shapenum = 32;
} else {
if (PrimaryFacing == DIR_NW) {
shapenum = 35;
}
}
shapenum += Door_Stage();
}
}
}
}
/*
** The artillery unit should have its entire body recoil when it fires.
*/
if (*this == UNIT_ARTY && IsInRecoilState) {
Recoil_Adjust(PrimaryFacing.Current(), x, y);
}
/*
** Actually perform the draw. Overlay an optional shimmer effect as necessary.
*/
//if (*this == UNIT_HOVER) {
// Mono_Printf("Display hover %p %d.\n", shapefile, shapenum);
//}
Techno_Draw_Object(shapefile, shapenum, x, y, window);
/*
** Special wake drawing occurs here for virtual rendering
*/
if (Class->IsChunkyShape && (*this == UNIT_GUNBOAT) && (window == WINDOW_VIRTUAL)) {
//Added this and wake name parameters. ST - 8/20/2019 10:54AM
CC_Draw_Shape(this, "WAKE", UnitTypeClass::WakeShapes, shapestart + (Fetch_Stage() % 6), xx-1, yy+3, window, SHAPE_CENTER|SHAPE_WIN_REL);
}
/*
** If there is a rotating radar dish, draw it now.
*/
if (Class->IsRadarEquipped) {
shapenum = 32 + (Frame % 32);
Techno_Draw_Object(shapefile, shapenum, x, y-5, window);
}
/*
** If there is a turret, then it must be rendered as well. This may include
** firing animation if required.
*/
if (!Class->IsChunkyShape && Class->IsTurretEquipped) {
int x1 = x;
int y1 = y;
/*
** Determine which turret shape to use. This depends on if there
** is any firing animation in progress.
*/
shapenum = TechnoClass::BodyShape[tfacing]+32;
/*
** The shape to use for the rocket launcher is dependant on the
** ammo remaining.
*/
if (*this == UNIT_MSAM) {
if (Ammo == 0) shapenum += 64;
if (Ammo == 1) shapenum += 32;
}
/*
** A recoiling turret moves "backward" one pixel.
*/
if (IsInRecoilState) {
Recoil_Adjust(SecondaryFacing.Current(), x1, y1);
}
/*
** The Mobile SAM and the Missile Launchers need their turrets moved based
** on the facing of the vehicle.
*/
if (*this == UNIT_MSAM || *this == UNIT_MLRS) {
Turret_Adjust(PrimaryFacing, x1, y1);
}
if (*this == UNIT_JEEP || *this == UNIT_BUGGY) {
y1 -= 4;
}
/*
** Actually perform the draw. Overlay an optional shimmer effect as necessary.
*/
Techno_Draw_Object(shapefile, shapenum, x1, y1, window);
}
/*
** If this unit has "piggy back" unit(s), then render it at the same time.
*/
if (*this == UNIT_HOVER && Is_Something_Attached()) {
TechnoClass * u = (TechnoClass *)Attached_Object();
int counter = 0;
for (;;) {
int x1,y1;
if (Map.Coord_To_Pixel(Coord_Add(Coord_Add(Coord, 0xFF80FF80L), StoppingCoordAbs[counter++]), x1, y1)) {
// Pass the window through, so that the virtual window will also work. ST - 6/18/2019 12:00PM
//u->Draw_It(x1, y1, WINDOW_TACTICAL);
u->Draw_It(x1, y1, window);
}
if (!u->Next) break;
u = (TechnoClass *)u->Next;
}
}
}
/*
** If this unit is carrying the flag, then draw that on top of everything else.
*/
if (Flagged != HOUSE_NONE) {
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
shapefile = MixFileClass::Retrieve("FLAGFLY.SHP");
int flag_x = x + (ICON_PIXEL_W / 2) - 2;
int flag_y = y + (3 * ICON_PIXEL_H / 4) - Get_Build_Frame_Height(shapefile);
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, false), Map.UnitShadow, Flagged);
}
TarComClass::Draw_It(x, y, window);
}
/***********************************************************************************************
* UnitClass::Goto_Tiberium -- Search for and head toward nearest available Tiberium patch. *
* *
* This routine is used to move a harvester to a place where it can load up with *
* Tiberium. It will return true only if it can start harvesting. Otherwise, it sets *
* the navigation computer toward the nearest Tiberium and lets the unit head there *
* automatically. *
* *
* INPUT: none *
* *
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
* OUTPUT: int; Amount of Tiberium at this location. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/18/1994 JLB : Created. *
*=============================================================================================*/
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
int UnitClass::Tiberium_Check(CELL &center, int x, int y)
{
Validate();
/*
** If the specified offset from the origin will cause it
** to spill past the map edge, then abort this cell check.
*/
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 (Cell_X(center)+x < Map.MapCellX) return(0);
if (Cell_X(center)+x >= Map.MapCellX+Map.MapCellWidth) return(0);
if (Cell_Y(center)+y < Map.MapCellY) return(0);
if (Cell_Y(center)+y >= Map.MapCellY+Map.MapCellHeight) return(0);
center = XY_Cell(Cell_X(center)+x, Cell_Y(center)+y);
//using function for IsVisible so we have different results for different players - JAS 2019/09/30
if ((GameToPlay != GAME_NORMAL || (!IsOwnedByPlayer || Map[center].Is_Visible(PlayerPtr)))) {
if (!Map[center].Cell_Techno() && Map[center].Land_Type() == LAND_TIBERIUM) {
return(Map[center].OverlayData+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
return(0);
}
bool UnitClass::Goto_Tiberium(void)
{
Validate();
if (!Target_Legal(NavCom)) {
CELL center = Coord_Cell(Center_Coord());
if (Map[center].Land_Type() == LAND_TIBERIUM) {
return(true);
} else {
/*
** Perform a ring search outward from the center.
*/
for (int radius = 1; radius < 64; radius++) {
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
CELL cell = center;
CELL bestcell = 0;
int tiberium = 0;
int besttiberium = 0;
for (int x = -radius; x <= radius; x++) {
/*
** Randomize the corners.
*/
int corner[2];
int corners[4][2] = {
{x, -radius},
{x, +radius},
{-radius, x},
{+radius, x}
};
for (int i = 0; i < 3; i++) {
int j = i + rand() / (RAND_MAX / (4 - i) + 1);
memcpy(&corner, &corners[j], sizeof(corner));
memcpy(&corners[j], &corners[i], sizeof(corner));
memcpy(&corners[i], corner, sizeof(corner));
}
cell = center;
tiberium = Tiberium_Check(cell, corners[0][0], corners[0][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
if (tiberium > besttiberium) {
bestcell = cell;
besttiberium = tiberium;
}
cell = center;
tiberium = Tiberium_Check(cell, corners[1][0], corners[1][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
if (tiberium > besttiberium) {
bestcell = cell;
besttiberium = tiberium;
}
cell = center;
tiberium = Tiberium_Check(cell, corners[2][0], corners[2][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
if (tiberium > besttiberium) {
bestcell = cell;
besttiberium = tiberium;
}
cell = center;
tiberium = Tiberium_Check(cell, corners[3][0], corners[3][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
if (tiberium > besttiberium) {
bestcell = cell;
besttiberium = tiberium;
}
}
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 (bestcell) {
Assign_Destination(::As_Target(bestcell));
return(false);
}
}
}
}
return(false);
}
BuildingClass* UnitClass::Find_Best_Refinery(void) const
{
/*
** Remember our last refinery and prefer that one, if still available and valid.
*/
if (TiberiumUnloadRefinery != NULL) {
if (TiberiumUnloadRefinery->House == House &&
!TiberiumUnloadRefinery->IsInLimbo &&
TiberiumUnloadRefinery->Mission != MISSION_DECONSTRUCTION &&
*TiberiumUnloadRefinery == STRUCT_REFINERY) {
return TiberiumUnloadRefinery;
} else {
TiberiumUnloadRefinery = NULL;
}
}
/*
** Find nearby refinery and head to it?
*/
return Find_Docking_Bay(STRUCT_REFINERY, false);
}
/***********************************************************************************************
* UnitClass::Harvesting -- Harvests tiberium at the current location. *
* *
* This routine is used to by the harvester to harvest Tiberium at the current location. *
* When harvesting is complete, this routine will return true. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Is harvesting complete? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/18/1994 JLB : Created. *
*=============================================================================================*/
bool UnitClass::Harvesting(void)
{
Validate();
CELL cell = Coord_Cell(Coord);
CellClass * ptr = &Map[cell];
/*
** Keep waiting if still heading toward a spot to harvest or the harvest timer hasn't expired yet.
*/
if (Target_Legal(NavCom) || !HarvestTimer.Expired() || IsDriving || IsRotating) return(true);
if (Tiberium_Load() < 0x0100 && ptr->Land_Type() == LAND_TIBERIUM) {
/*
** Lift some Tiberium from the ground. Try to lift a complete
** "level" of Tiberium. A level happens to be 6 steps. If there
** is a partial level, then lift that instead. Never lift more
** than the harvester can carry.
*/
int reducer = (ptr->OverlayData % 6) + 1;
reducer = ptr->Reduce_Tiberium(MIN(reducer, UnitTypeClass::STEP_COUNT-Tiberium));
Tiberium += reducer;
Set_Stage(0);
Set_Rate(2);
HarvestTimer = TICKS_PER_SECOND;
} else {
/*
** If the harvester is stopped on a non Tiberium field and the harvester
** isn't loaded with Tiberium, then no further action can be performed
** by this logic routine. Bail with a failure and thus cause a branch to
** a better suited logic processor.
*/
Set_Stage(0);
Set_Rate(0);
return(false);
}
return(true);
}
/***********************************************************************************************
* UnitClass::Mission_Unload -- Handles unloading cargo. *
* *
* This is the AI control sequence for when a transport desires to unload its cargo and *
* then exit the map. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the delay before calling this routine again. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/18/1994 JLB : Created. *
*=============================================================================================*/
int UnitClass::Mission_Unload(void)
{
Validate();
enum {
INITIAL_CHECK,
MANEUVERING,
OPENING_DOOR,
UNLOADING,
CLOSING_DOOR
};
DirType dir;
CELL cell;
switch (Class->Type) {
case UNIT_APC:
switch (Status) {
case INITIAL_CHECK:
dir = Desired_Load_Dir(NULL, cell);
if (How_Many() && cell != 0) {
Do_Turn(dir);
Status = MANEUVERING;
return(1);
} else {
Assign_Mission(MISSION_GUARD);
}
break;
case MANEUVERING:
if (!IsRotating) {
APC_Open_Door();
if (Is_Door_Opening()) {
Status = OPENING_DOOR;
return(1);
}
}
break;
case OPENING_DOOR:
if (Is_Door_Open()) {
Status = UNLOADING;
return(1);
} else {
if (!Is_Door_Opening()) {
Status = INITIAL_CHECK;
}
}
break;
case UNLOADING:
if (How_Many()) {
FootClass * passenger = Detach_Object();
if (passenger) {
DirType toface = DIR_S + PrimaryFacing;
bool placed = false;
for (FacingType face = FACING_N; face < FACING_COUNT; face++) {
DirType newface = toface + face;
CELL newcell = Adjacent_Cell(Coord_Cell(Coord), newface);
if (passenger->Can_Enter_Cell(newcell) == MOVE_OK) {
ScenarioInit++;
passenger->Unlimbo(Coord_Move(Coord, newface, 0x0080), newface);
ScenarioInit--;
passenger->Assign_Mission(MISSION_MOVE);
passenger->Assign_Destination(::As_Target(newcell));
placed = true;
break;
}
}
/*
** If the attached unit could NOT be deployed, then re-attach
** it and then bail out of this deploy process.
*/
if (!placed) {
Attach(passenger);
Status = CLOSING_DOOR;
}
else {
passenger->Look(false);
}
}
} else {
Status = CLOSING_DOOR;
}
break;
/*
** Close APC door in preparation for normal operation.
*/
case CLOSING_DOOR:
if (Is_Door_Open()) {
APC_Close_Door();
}
if (Is_Door_Closed()) {
Assign_Mission(MISSION_GUARD);
}
break;
}
break;
case UNIT_MCV:
switch (Status) {
case 0:
Path[0] = FACING_NONE;
Status = 1;
break;
case 1:
if (!IsDriving) {
Try_To_Deploy();
if (IsDeploying) {
Status = 2;
} else {
/*
** Functionality from Red Alert for AI. ST - 7/25/2019 3:09PM
*/
#ifndef USE_RA_AI
Assign_Mission(MISSION_GUARD);
#else //USE_RA_AI
if (!House->IsHuman && GameToPlay != GAME_NORMAL) {
Assign_Mission(MISSION_HUNT);
} else {
Assign_Mission(MISSION_GUARD);
}
#endif //USE_RA_AI
}
}
break;
case 2:
#ifdef USE_RA_AI
/*
** Functionality from Red Alert for AI. ST - 7/25/2019 3:09PM
*/
if (GameToPlay != GAME_NORMAL) {
if (!IsDeploying) {
Assign_Mission(MISSION_GUARD);
}
}
#endif // USE_RA_AI
break;
}
return(1);
case UNIT_HOVER:
switch (Status) {
case 0:
if (Unload_Hovercraft_Process()) {
Status = 1;
}
break;
/*
** Hovercraft always leave the map when they finish
** unloading.
*/
case 1:
if (Team) {
Team->Remove(this);
}
Exit_Map();
break;
}
break;
}
return(TICKS_PER_SECOND);
}
/***********************************************************************************************
* UnitClass::Mission_Harvest -- Handles the harvesting process used by harvesters. *
* *
* This is the AI process used by harvesters when they are doing their harvesting action. *
* This entails searching for nearby Tiberium, heading there, harvesting, and then *
* returning to a refinery for unloading. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the delay before calling this routine again. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/18/1994 JLB : Created. *
* 06/21/1995 JLB : Force guard mode if no Tiberium found. *
*=============================================================================================*/
int UnitClass::Mission_Harvest(void)
{
Validate();
enum {
LOOKING,
HARVESTING,
FINDHOME,
HEADINGHOME,
GOINGTOIDLE,
};
/*
** A non-harvesting type unit will just sit still if it is given the harvest mission. This
** allows combat units to act "brain dead".
*/
if (!Class->IsToHarvest) return(TICKS_PER_SECOND*30);
switch (Status) {
/*
** Go and find a Tiberium field to harvest.
*/
case LOOKING:
IsHarvesting = false;
/*
** Slightly hacky; if TarCom is set then skip to finding home state.
*/
if (Target_Legal(TarCom)) {
Assign_Target(TARGET_NONE);
Status = FINDHOME;
return(1);
} else if (Goto_Tiberium()) {
IsHarvesting = true;
Set_Rate(2);
Set_Stage(0);
Status = HARVESTING;
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
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
return(1);
} else {
/*
** If the harvester isn't on Tiberium and it is not heading toward Tiberium, then
** force it to go into guard mode. This will prevent the harvester from repeatedly
** searching for Tiberium.
*/
if (!Target_Legal(NavCom)) {
/*
** If the archive target is legal, then head there since it is presumed
** that the archive target points to the last place it harvested at. This might
** solve the case where the harvester gets stuck and can't find Tiberium just because
** it is greater than 32 squares away.
*/
if (Target_Legal(ArchiveTarget)) {
Assign_Destination(ArchiveTarget);
} else {
Status = GOINGTOIDLE;
return(TICKS_PER_SECOND*15);
}
}
}
break;
/*
** Harvest at current location until full or Tiberium exhausted.
*/
case HARVESTING:
if (!Harvesting()) {
IsHarvesting = false;
if (Tiberium_Load() == 0x0100) {
Status = FINDHOME;
} else {
if (!Goto_Tiberium() && !Target_Legal(NavCom)) {
ArchiveTarget = TARGET_NONE;
Status = FINDHOME;
} else {
Status = HARVESTING;
IsHarvesting = true;
}
}
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
} else if (!Target_Legal(NavCom) && ArchiveTarget == TARGET_NONE) {
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
}
break;
/*
** Find and head to refinery.
*/
case FINDHOME:
if (!Target_Legal(NavCom)) {
/*
** Find best refinery.
*/
BuildingClass * nearest = Find_Best_Refinery();
/*
** Since the refinery said it was ok to load, establish radio
** contact with the refinery and then await docking orders.
*/
if (nearest && Transmit_Message(RADIO_HELLO, nearest) == RADIO_ROGER) {
Status = HEADINGHOME;
} else {
ScenarioInit++;
nearest = Find_Best_Refinery();
ScenarioInit--;
if (nearest) {
Assign_Destination(::As_Target(nearest->Nearby_Location(this)));
}
}
}
break;
/*
** In communication with refinery so that it will successfully dock and
** unload. If, for some reason, radio contact was lost, then hunt for
** another refinery to unload at.
*/
case HEADINGHOME:
Assign_Mission(MISSION_ENTER);
return(1);
case GOINGTOIDLE:
Assign_Mission(MISSION_GUARD);
break;
}
return(TICKS_PER_SECOND);
}
/***********************************************************************************************
* UnitClass::Mission_Hunt -- This is the AI process for aggressive enemy units. *
* *
* Computer controlled units must be intelligent enough to find enemies as well as to *
* attack them. This AI process will handle both the simple attack process as well as the *
* scanning for enemy units to attack. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the delay before calling this routine again. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/18/1994 JLB : Created. *
*=============================================================================================*/
int UnitClass::Mission_Hunt(void)
{
Validate();
if (*this == UNIT_MCV) {
switch (Status) {
/*
** This stage handles locating a convenient spot, rotating to face the correct
** direction and then commencing the deployment operation.
*/
case 0:
if (Goto_Clear_Spot()) {
if (Try_To_Deploy()) {
Status = 1;
}
}
break;
/*
** This stage watchdogs the deployment operation and if for some reason, the deployment
** is aborted (the IsDeploying flag becomes false), then it reverts back to hunting for
** a convenient spot to deploy.
*/
case 1:
if (!IsDeploying) {
Status = 0;
}
break;
}
} else {
if (*this == UNIT_GUNBOAT) {
if (!Target_Legal(NavCom)) {
if (PrimaryFacing == DIR_W) {
Assign_Destination( ::As_Target(XY_Cell(Map.MapCellX-1, Cell_Y(Coord_Cell(Coord)))) );
} else {
Assign_Destination( ::As_Target(XY_Cell(Map.MapCellX+Map.MapCellWidth, Cell_Y(Coord_Cell(Coord)))) );
}
Set_Speed(255);
}
if (!Speed) {
Set_Speed(255);
}
if (!Target_Legal(TarCom) || !In_Range(TarCom, 0)) {
Target_Something_Nearby(THREAT_AREA);
}
} else {
return(TarComClass::Mission_Hunt());
}
}
return(TICKS_PER_SECOND);
}
int UnitClass::Mission_Enter(void)
{
Validate();
if (Class->IsToHarvest) {
TechnoClass * contact = Contact_With_Whom();
if (contact == NULL) {
contact = As_Techno(ArchiveTarget);
}
if (contact == NULL) {
contact = As_Techno(NavCom);
}
if (contact != NULL &&
contact->What_Am_I() == RTTI_BUILDING &&
*((BuildingClass*)contact) == STRUCT_REFINERY) {
TiberiumUnloadRefinery = (BuildingClass*)contact;
}
}
return(TarComClass::Mission_Enter());
}
/***********************************************************************************************
* UnitClass::Look -- Perform map revelation from a unit's position. *
* *
* Reveal the map around the specified unit with the sighting range *
* associated with the specified unit. *
* *
* INPUT: incremental -- If looking is to process only the cells in the *
* outer ring of the unit's search radius, then *
* set this parameter to true. This method is *
* quite a bit faster than processing all cells, *
* but must be used with caution. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/08/1992 JLB : Created. *
* 03/08/1994 JLB : Added incremental option. *
* 04/15/1994 JLB : Converted to member function. *
*=============================================================================================*/
void UnitClass::Look(bool incremental)
{
Validate();
//if (!IsInLimbo && IsOwnedByPlayer) { // Changed for mapping of multiple players
if (!IsInLimbo && House && (House->IsHuman || GameToPlay != GAME_NORMAL)) {
int sight = Class->SightRange;
if (sight) {
Map.Sight_From(House, Coord_Cell(Coord), sight, (*this == UNIT_GUNBOAT) ? false : incremental); // Passed our house into Map.Sight_From since it now needs to know who it is performing the action on behalf of. ST - 3/28/2019 2:55PM
}
}
}
/***********************************************************************************************
* UnitClass::Overlap_List -- Determines overlap list for units. *
* *
* The unit overlap list is used to keep track of which cells are to *
* be marked for redraw. This is critical in order to keep the units *
* displayed correctly. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the overlap list pointer for the unit at its *
* present position. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/26/1994 JLB : Created. *
* 06/19/1994 JLB : Uses Coord_Spillable_List function. *
*=============================================================================================*/
short const * UnitClass::Overlap_List(void) const
{
Validate();
static short const _gunboat[] = {-3, -2, 2, 3, REFRESH_EOL};
int size;
/*
** The gunboat is a special case.
*/
if (*this == UNIT_GUNBOAT) {
return(&_gunboat[0]);
}
size = ICON_PIXEL_W;
if (Is_Selected_By_Player() || IsFiring) {
size += 24;
}
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 (Is_Selected_By_Player() || Class->IsGigundo || IsAnimAttached || Flagged != HOUSE_NONE) {
size = ICON_PIXEL_W*2;
}
return(Coord_Spillage_List(Coord, size)+1);
}
#ifdef NEVER
/********************************************************************************************* *
* UnitClass::Blocking_Object -- Determines how a object blocks a unit *
* *
* This routine is used by the Can_Enter_Cell logic when an object is in the desired cell *
* and it needs to know if that causes blockage. If blocked, this routine will return why. *
* *
* INPUT: TechnoClass * pointer to object that is blocking unit *
* *
* CELL the cell the unit is being blocked in *
* *
* OUTPUT: MoveBitType the way that the object is blocking the unit *
* *
* HISTORY: *
* 06/08/1995 PWG : Created. *
*=============================================================================================*/
MoveBitType UnitClass::Blocking_Object(TechnoClass const *techno, CELL cell) const
{
Validate();
/*
** There are some extra checks we need to make if the techno is a unit
*/
bool unit = (techno->What_Am_I() == RTTI_INFANTRY || techno->What_Am_I() == RTTI_UNIT);
CellClass const * cellptr = &Map[cell];
if (House->Is_Ally(techno)) {
if (techno == Contact_With_Whom() && IsTethered) {
return(MOVE_BIT_OK);
}
if (unit) {
/*
** If the unit in question has a destination than we should
** be prepared to wait for the unit to get out of our way.
*/
if (((FootClass *)techno)->NavCom != TARGET_NONE) {
int face = Dir_Facing(PrimaryFacing);
int techface = Dir_Facing(((FootClass const *)techno)->PrimaryFacing) ^4;
if (face != techface && Distance((AbstractClass const *)techno) > 0x1FF) {
return(MOVE_BIT_MOVING_BLOCK);
} else {
// Mono_Printf("Move No!\r");
return(MOVE_BIT_NO);
}
}
return(MOVE_BIT_TEMP);
}
} else {
/*
** If its an enemy unit, things are dealt with a little differently
*/
if (unit) {
#ifdef NEVER
/*
** If this is an enemy unit and we are not doing a find path then
** we need to tell the unit to uncloak just in case it is a
** stealth tank.
*/
if (!IsFindPath) {
techno->Do_Uncloak();
}
#endif
/*
** Can we just run it over?
*/
if (techno->Class_Of().IsCrushable && (cellptr->Flag.Composite & 0xE0) == 0 && Class->IsCrusher) {
/*
** Now lets run it over.
*/
return(MOVE_BIT_OK);
}
/*
** If the object is cloaked, then consider it passable for findpath purposes,
** but not so for all other cases.
*/
if (techno->Cloak == CLOAKED) {
if (House == techno->House) return(MOVE_BIT_NO);
if (IsFindPath) return(MOVE_BIT_OK);
return(MOVE_BIT_CLOAK);
}
/*
** If our vehicle is weapon equipped, then report that the cell occupier
** needs only to be destroyed in order to make the cell passable.
*/
if (Class->Primary != WEAPON_NONE) {
return(MOVE_BIT_DESTROYABLE);
}
}
}
return(MOVE_BIT_NO);
}
#endif
/***********************************************************************************************
* UnitClass::Can_Enter_Cell -- Determines cell entry legality. *
* *
* Use this routine to determine if the unit can enter the cell *
* specified and given the direction of entry specified. Typically, *
* this is used when determining unit travel path. *
* *
* INPUT: cell -- The cell to examine. *
* *
* facing -- The facing that the unit would enter the specified *
* cell. If this value is -1, then don't consider *
* facing when performing the check. *
* *
* OUTPUT: Returns the reason why it couldn't enter the cell or MOVE_OK if movement is *
* allowed. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/07/1992 JLB : Created. *
* 04/16/1994 JLB : Converted to member function. *
* 07/04/1995 JLB : Allowed to drive on building trying to enter it. *
*=============================================================================================*/
MoveType UnitClass::Can_Enter_Cell(CELL cell, FacingType ) const
{
Validate();
CellClass const * cellptr = &Map[cell];
if ((unsigned)cell >= MAP_CELL_TOTAL) return(MOVE_NO);
/*
** The gunboat can always move. This prevents it from trying to move around possible hover
** craft blockage.
*/
if (*this == UNIT_GUNBOAT) return(MOVE_OK);
/*
** Moving off the edge of the map is not allowed unless
** this is a loaner vehicle.
*/
if (IsLocked && !IsALoaner && !ScenarioInit && !Map.In_Radar(cell)) {
return(MOVE_NO);
}
MoveType retval = MOVE_OK;
/*
** Certain vehicles can drive over walls. Check for this case and
** and return the appropriate flag. Other units treat walls as impassable.
*/
if (cellptr->Overlay != OVERLAY_NONE) {
OverlayTypeClass const * optr = &OverlayTypeClass::As_Reference(cellptr->Overlay);
if (optr->IsCrate && !House->IsHuman) {
return(MOVE_NO);
}
if (optr->IsWall) {
if (Class->Primary != WEAPON_NONE) {
WarheadTypeClass const * whead = &Warheads[BulletTypeClass::As_Reference(Weapons[Class->Primary].Fires).Warhead];
if (whead->IsWallDestroyer || (whead->IsWoodDestroyer && optr->IsWooden)) {
if (!House->IsHuman && !House->Is_Ally(cellptr->Owner)) {
if (retval < MOVE_DESTROYABLE) retval = MOVE_DESTROYABLE;
} else {
return(MOVE_NO);
}
} else {
return(MOVE_NO);
}
} else {
return(MOVE_NO);
}
}
}
/*
** If the cell is out and out impassable because of underlying terrain, then
** return this immutable fact.
*/
#ifdef ADVANCED
if (retval != MOVE_DESTROYABLE && !Ground[cellptr->Land_Type()].Cost[Class->Speed]) {
#else
if (!Ground[cellptr->Land_Type()].Cost[Class->Speed]) {
#endif
return(MOVE_NO);
}
/*
** Loop through all of the objects in the square setting a bit
** for how they affect movement.
*/
bool crushable = false;
ObjectClass *obj = cellptr->Cell_Occupier();
while (obj) {
if (obj != this) {
/*
** Always allow entry if trying to move on a cell with
** authorization from the occupier.
*/
if (obj == Contact_With_Whom() && (IsTethered || (obj->What_Am_I() == RTTI_BUILDING && *((BuildingClass *)obj) == STRUCT_REPAIR))) {
return(MOVE_OK);
}
bool is_moving = (obj->What_Am_I() == RTTI_INFANTRY || obj->What_Am_I() == RTTI_UNIT) && Target_Legal(((FootClass *)obj)->NavCom);
if (House->Is_Ally(obj)) {
if (is_moving) {
int face = Dir_Facing(PrimaryFacing);
int techface = Dir_Facing(((FootClass const *)obj)->PrimaryFacing) ^4;
if (face == techface && Distance((AbstractClass const *)obj) <= 0x1FF) {
return(MOVE_NO);
}
if (retval < MOVE_MOVING_BLOCK) retval = MOVE_MOVING_BLOCK;
} else {
if (obj->What_Am_I() == RTTI_BUILDING) return(MOVE_NO);
if (retval < MOVE_TEMP) retval = MOVE_TEMP;
}
} else {
/*
** Cloaked enemy objects are not considered if this is a Find_Path()
** call.
*/
if (!obj->Is_Techno() || ((TechnoClass *)obj)->Cloak != CLOAKED) {
/*
** If this unit can crush infantry, and there is an enemy infantry in the
** cell, don't consider the cell impassible. This is true even if the unit
** doesn't contain a legitimate weapon.
*/
if (!Class->IsCrusher || !obj->Class_Of().IsCrushable) {
/*
** Any non-allied blockage is considered impassible if the unit
** is not equipped with a weapon.
*/
if (Class->Primary == WEAPON_NONE) return(MOVE_NO);
/*
** Some kinds of terrain are considered destroyable if the unit is equipped
** with the weapon that can destroy it. Otherwise, the terrain is considered
** impassable.
*/
switch (obj->What_Am_I()) {
case RTTI_TERRAIN:
if (((TerrainClass *)obj)->Class->IsFlammable &&
BulletTypeClass::As_Reference(Weapons[Class->Primary].Fires).Warhead == WARHEAD_FIRE) {
if (retval < MOVE_DESTROYABLE) retval = MOVE_DESTROYABLE;
} else {
return(MOVE_NO);
}
break;
default:
if (retval < MOVE_DESTROYABLE) retval = MOVE_DESTROYABLE;
break;
}
} else {
crushable = true;
}
} else {
if (retval < MOVE_CLOAK) retval = MOVE_CLOAK;
}
}
}
/*
** Move to next object in chain.
*/
obj = obj->Next;
}
/*
** If some allied object has reserved the cell, then consider the cell
** as blocked by a moving object.
*/
if (retval == MOVE_OK && !crushable && cellptr->Flag.Composite) {
/*
** If reserved by a vehicle, then consider this blocked terrain.
*/
if (cellptr->Flag.Occupy.Vehicle) {
retval = MOVE_MOVING_BLOCK;
} else {
if (cellptr->InfType != HOUSE_NONE && House->Is_Ally(cellptr->InfType)) {
retval = MOVE_MOVING_BLOCK;
} else {
/*
** Enemy infantry have reserved the cell. If this unit can crush
** infantry, consider the cell passable. If not, then consider the
** cell destroyable if it has a weapon. If neither case applies, then
** this vehicle should avoid the cell altogether.
*/
if (!Class->IsCrusher) {
if (Class->Primary != WEAPON_NONE) {
retval = MOVE_DESTROYABLE;
} else {
return(MOVE_NO);
}
}
}
}
}
/*
** If its ok to move into the cell because we can crush whats in the cell, then
** make sure no one else is already moving into the cell to crush something.
*/
if (retval == MOVE_OK && crushable && cellptr->Flag.Occupy.Vehicle) {
#ifdef ADVANCED
/*
** However, if the cell is occupied by a crushable vehicle, then we can
** never be sure if some other friendly vehicle is also trying to crush
** the cell at the same time. In the case of a crushable vehicle in the
** cell, then allow entry.
*/
if (!cellptr->Cell_Unit() || !cellptr->Cell_Unit()->Class->IsCrushable) {
return(MOVE_MOVING_BLOCK);
}
#else
return(MOVE_MOVING_BLOCK);
#endif
}
/*
** Return with the most severe reason why this cell would be impassable.
*/
return(retval);
}
/***********************************************************************************************
* UnitClass::Init -- Clears all units for scenario preparation. *
* *
* This routine will zero out the unit list and unit objects. This routine is typically *
* used in preparation for a new scenario load. All units are guaranteed to be eliminated *
* by this routine. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/15/1994 JLB : Created. *
*=============================================================================================*/
void UnitClass::Init(void)
{
UnitClass * ptr;
Units.Free_All();
ptr = new UnitClass();
VTable = ((void **)(((char *)ptr) + sizeof(AbstractClass) - 4))[0];
delete ptr;
}
/***********************************************************************************************
* UnitClass::Target_Coord -- The coordinate to use when targeting this unit. *
* *
* Sometimes the coordinate to use when targeting an object is not the same as its center *
* coordinate. This is especially true for boats since leading their movement is needed *
* in order have any chance of hitting. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the coordinate to fire upon when attacking the unit. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/19/1994 JLB : Created. *
*=============================================================================================*/
COORDINATE UnitClass::Target_Coord(void) const
{
Validate();
// if (*this == UNIT_GUNBOAT) {
// return(Coord_Move(Coord, PrimaryFacing.Current(), 0x0080));
// }
return(TarComClass::Center_Coord());
}
/***********************************************************************************************
* UnitClass::Scatter -- Causes the unit to travel to a nearby safe cell. *
* *
* This routine is called when the unit discovers that it should get out of the "hot seat" *
* and move to an adjacent cell. Since the safety of the adjacent cell is not determined *
* before the move begins, it will appear that the unit is just scattering (which it *
* should). *
* *
* INPUT: threat -- The coordinate of the source of the threat. The unit will try to move *
* roughly away from the threat. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/25/1994 JLB : Created. *
*=============================================================================================*/
void UnitClass::Scatter(COORDINATE threat, bool forced, bool nokidding)
{
Validate();
if (*this != UNIT_GUNBOAT && *this != UNIT_HOVER) {
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 (PrimaryFacing.Is_Rotating()) return;
if (Target_Legal(NavCom) && !nokidding) return;
if (threat == 0) {
Assign_Destination(::As_Target(Map.Nearby_Location(Coord_Cell(Coord))));
} else if (((!Target_Legal(TarCom) && !Target_Legal(NavCom)) || forced || nokidding || Random_Pick(1, 4) == 1)) {
FacingType toface;
FacingType newface;
CELL newcell;
if (threat) {
toface = Dir_Facing(Direction8(threat, Coord));
toface = toface + (Random_Pick(0, 2)-1);
} else {
toface = Dir_Facing(PrimaryFacing.Current());
}
for (FacingType face = FACING_N; face < FACING_COUNT; face++) {
newface = toface + face;
newcell = Adjacent_Cell(Coord_Cell(Coord), newface);
if (Map.In_Radar(newcell) && Can_Enter_Cell(newcell) == MOVE_OK) {
Assign_Destination(::As_Target(newcell));
}
}
}
}
}
/***********************************************************************************************
* UnitClass::Stop_Driver -- Handles removing occupation bits when driving stops. *
* *
* This routine will remove the "reservation" flag (if present) when the vehicle is *
* required to stop movement. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Was the vehicle stopped? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/22/1994 JLB : Created. *
*=============================================================================================*/
bool UnitClass::Stop_Driver(void)
{
Validate();
/*
** We only need to do something if the vehicle is actually going
** somewhere.
*/
if (Head_To_Coord()) {
/*
** Safe off whether the vehicle is down or not so we know whether
** we have to put it back down.
*/
int temp = IsDown;
/*
** If the vehicle is down, pick it up so it doesnt interfere with
** our flags.
*/
if (temp) {
Mark(MARK_UP);
}
/*
** Call the drive class function which will let us release the
** reserved track.
*/
Mark_Track(Head_To_Coord(), MARK_UP);
/*
** If it was down it should be down when we are done.
*/
if (temp) {
Mark(MARK_DOWN);
}
}
return(TarComClass::Stop_Driver());
}
/***********************************************************************************************
* UnitClass::Start_Driver -- Starts driving and reserves destination cell. *
* *
* This routine will start the vehicle moving by marking the destination cell as *
* reserved. Cells must be reserved in this fashion or else they might become occupied as *
* the vehicle is proceeding toward it. *
* *
* INPUT: headto -- The location where the vehicle will be heading. *
* *
* OUTPUT: bool; Was the vehicle started to move? Failure could be the result of the cell *
* being occupied. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/22/1994 JLB : Created. *
*=============================================================================================*/
bool UnitClass::Start_Driver(COORDINATE & headto)
{
Validate();
if (TarComClass::Start_Driver(headto)) {
Mark_Track(headto, MARK_DOWN);
return(true);
}
return(false);
}
/***********************************************************************************************
* UnitClass::Limbo -- Prepares vehicle and then limbos it. *
* *
* This routine removes the occupation bits for the vehicle and also handles cleaning up *
* any vehicle reservation bits. After this, it then proceeds with limboing the unit. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Was the vehicle limboed? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/22/1994 JLB : Created. *
*=============================================================================================*/
bool UnitClass::Limbo(void)
{
Validate();
if (!IsInLimbo) {
Stop_Driver();
}
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 (TarComClass::Limbo()) {
if (Flagged != HOUSE_NONE) {
HouseClass::As_Pointer(Flagged)->Flag_Attach(Coord_Cell(Coord));
}
return(true);
}
return(false);
}
/***********************************************************************************************
* UnitClass::Response_Select -- Voice feedback when selecting the unit. *
* *
* This is the voice to play when the unit is selected. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/30/1994 JLB : Created. *
*=============================================================================================*/
void UnitClass::Response_Select(void)
{
Validate();
static VocType _response[] = {
VOC_VEHIC,
VOC_UNIT,
VOC_YESSIR,
VOC_YESSIR,
VOC_YESSIR,
VOC_AWAIT
};
VocType response = _response[Sim_Random_Pick(0, (int)(sizeof(_response) / sizeof(_response[0]))-1)];
if (*this == UNIT_TRIC || *this == UNIT_TREX || *this == UNIT_RAPT || *this == UNIT_STEG) {
response = VOC_DINOYES;
}
if (AllowVoice) {
Sound_Effect(response, 0, -(Units.ID(this)+1));
}
}
/***********************************************************************************************
* UnitClass::Response_Move -- Voice feedback when ordering the unit to move. *
* *
* This plays the audio feedback when ordering this unit to move to a new destination. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/30/1994 JLB : Created. *
*=============================================================================================*/
void UnitClass::Response_Move(void)
{
Validate();
static VocType _response[] = {
VOC_MOVEOUT,
VOC_MOVEOUT,
VOC_MOVEOUT,
VOC_ACKNOWL,
VOC_AFFIRM,
VOC_AFFIRM
};
VocType response = _response[Sim_Random_Pick(0, (int)(sizeof(_response) / sizeof(_response[0]))-1)];
if (*this == UNIT_TRIC || *this == UNIT_TREX || *this == UNIT_RAPT || *this == UNIT_STEG) {
response = VOC_DINOMOUT;
}
if (AllowVoice) {
Sound_Effect(response, 0, -(Units.ID(this)+1));
}
}
/***********************************************************************************************
* UnitClass::Response_Attack -- Voice feedback when ordering the unit to attack a target. *
* *
* This plays the audio feedback when ordering this unit to attack. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 12/30/1994 JLB : Created. *
*=============================================================================================*/
void UnitClass::Response_Attack(void)
{
Validate();
static VocType _response[] = {
VOC_AFFIRM,
VOC_ACKNOWL,
VOC_YESSIR,
VOC_YESSIR,
VOC_YESSIR
};
VocType response = _response[Sim_Random_Pick(0, (int)(sizeof(_response) / sizeof(_response[0]))-1)];
if (*this == UNIT_TRIC || *this == UNIT_TREX || *this == UNIT_RAPT || *this == UNIT_STEG) {
response = VOC_DINOMOUT;
}
if (AllowVoice) {
Sound_Effect(response, 0, -(Units.ID(this)+1));
}
}
/***********************************************************************************************
* UnitClass::What_Action -- Determines what action would occur if clicked on object. *
* *
* Use this function to determine what action would likely occur if the specified object *
* were clicked on while this unit was selected as current. This function controls, not *
* only the action to perform, but indirectly controls the cursor shape to use as well. *
* *
* INPUT: object -- The object that to check for against "this" object. *
* *
* OUTPUT: Returns with the default action to perform. If no clear action can be determined, *
* then ACTION_NONE is returned. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/11/1995 JLB : Created. *
*=============================================================================================*/
ActionType UnitClass::What_Action(ObjectClass * object) const
{
Validate();
ActionType action = TarComClass::What_Action(object);
/*
** If the unit doesn't have a weapon, but can crush the object, then consider
** the object as a movable location.
*/
if (action == ACTION_ATTACK && !Can_Player_Fire()) {
if (Class->IsCrusher && object->Class_Of().IsCrushable) {
action = ACTION_MOVE;
} else {
action = ACTION_SELECT;
}
}
/*
** Don't allow special deploy action unless there is something to deploy.
*/
if (action == ACTION_SELF) {
if (*this != UNIT_MCV) {
if (!Class->IsTransporter || !How_Many()) {
action = ACTION_NONE;
}
} else {
((ObjectClass &)(*this)).Mark(MARK_UP);
if (!BuildingTypeClass::As_Reference(STRUCT_CONST).Legal_Placement(Coord_Cell(Adjacent_Cell(Center_Coord(), FACING_NW)))) {
action = ACTION_NO_DEPLOY;
}
((ObjectClass &)(*this)).Mark(MARK_DOWN);
}
}
/*
** Special return to friendly refinery action.
*/
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 (Is_Owned_By_Player() && House->Class->House == object->Owner() && object->What_Am_I() == RTTI_BUILDING && ((UnitClass *)this)->Transmit_Message(RADIO_CAN_LOAD, (TechnoClass*)object) == RADIO_ROGER) {
action = ACTION_ENTER;
}
/*
** Special return to friendly repair factory action.
*/
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 (Is_Owned_By_Player() && House->Class->House == object->Owner() && action == ACTION_SELECT && object->What_Am_I() == RTTI_BUILDING) {
BuildingClass * building = (BuildingClass *)object;
if (building->Class->Type == STRUCT_REPAIR && !building->In_Radio_Contact() && !building->Is_Something_Attached()) {
action = ACTION_MOVE;
}
}
return(action);
}
ActionType UnitClass::What_Action(CELL cell) const
{
Validate();
ActionType action = TarComClass::What_Action(cell);
if (action == ACTION_MOVE && Map[cell].Land_Type() == LAND_TIBERIUM && Class->IsToHarvest) {
return(ACTION_HARVEST);
}
return(action);
}
/***********************************************************************************************
* UnitClass::Can_Player_Move -- Determines if the player is legally allowed to move it. *
* *
* Use this routine to see if the player can move this object. If the player can move the *
* object, even only in theory, then this function returns true. In all other cases, such *
* as for enemy units, gunboats, or hovercraft, it returns false. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Can the player give this object a movement order? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/19/1995 JLB : Created. *
*=============================================================================================*/
bool UnitClass::Can_Player_Move(void) const
{
Validate();
return(TarComClass::Can_Player_Move() && *this != UNIT_GUNBOAT && *this != UNIT_HOVER);
}
/***********************************************************************************************
* UnitClass::Read_INI -- Reads units from scenario INI file. *
* *
* This routine is used to read all the starting units from the *
* scenario control INI file. The units are created and placed on the *
* map by this routine. *
* *
* INI entry format: *
* Housename, Typename, Strength, Coord, Facingnum, Missionname, Triggername *
* *
* INPUT: buffer -- Pointer to the loaded scenario INI file. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/24/1994 JLB : Created. *
*=============================================================================================*/
void UnitClass::Read_INI(char *buffer)
{
UnitClass *unit; // Working unit pointer.
char *tbuffer; // Accumulation buffer of unit IDs.
HousesType inhouse; // Unit house.
UnitType classid; // Unit class.
int len; // Length of data in buffer.
char buf[128];
len = strlen(buffer) + 2;
tbuffer = buffer + len;
WWGetPrivateProfileString(INI_Name(), NULL, NULL, tbuffer, ShapeBufferSize-len, buffer);
while (*tbuffer != '\0') {
WWGetPrivateProfileString(INI_Name(), tbuffer, NULL, buf, sizeof(buf)-1, buffer);
inhouse = HouseTypeClass::From_Name(strtok(buf, ","));
if (inhouse != HOUSE_NONE) {
classid = UnitTypeClass::From_Name(strtok(NULL, ","));
if (classid != UNIT_NONE) {
if (HouseClass::As_Pointer(inhouse) != NULL) {
unit = new UnitClass(classid, inhouse);
if (unit) {
/*
** Read the raw data.
*/
int strength = atoi(strtok(NULL, ",\r\n"));
COORDINATE coord = Cell_Coord((CELL)atoi(strtok(NULL, ",\r\n")));
DirType dir = (DirType)atoi(strtok(NULL, ",\r\n"));
MissionType mission = MissionClass::Mission_From_Name(strtok(NULL, ",\n\r"));
unit->Trigger = TriggerClass::As_Pointer(strtok(NULL,",\r\n"));
if (unit->Trigger) {
unit->Trigger->AttachCount++;
}
if (unit->Unlimbo(coord, dir)) {
unit->Strength = Fixed_To_Cardinal(unit->Class->MaxStrength, strength);
if (GameToPlay == GAME_NORMAL || unit->House->IsHuman) {
unit->Assign_Mission(mission);
unit->Commence();
} else {
unit->Enter_Idle_Mode();
}
/*
** The gunboat is a special case: It must "drive" off the edge of the map.
** Just pick the map edge that it is facing and set that as the destination
** of the drive.
*/
if (*unit == UNIT_GUNBOAT) {
unit->PrimaryFacing.Set_Desired(DIR_W);
unit->PrimaryFacing.Set_Current(DIR_W);
unit->Assign_Mission(MISSION_HUNT);
unit->Commence();
unit->Assign_Destination( ::As_Target(XY_Cell(Map.MapCellX-1, Cell_Y(Coord_Cell(unit->Coord)))));
}
} else {
/*
** If the unit could not be unlimboed, then this is a catastrophic error
** condition. Delete the unit.
*/
delete unit;
}
}
}
}
}
tbuffer += strlen(tbuffer)+1;
}
}
/***********************************************************************************************
* UnitClass::Write_INI -- Writes all the units out to an INI file. *
* *
* This routine writes all of the units in the game out to an INI file. This is used *
* in the scenario editor when the game needs to be saved. *
* *
* INI entry format: *
* Housename, Typename, Strength, Coord, Facingnum, Missionname, Triggername *
* *
* INPUT: buffer -- A pointer to the loaded INI file staging area. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/28/1994 JLB : Created. *
*=============================================================================================*/
void UnitClass::Write_INI(char *buffer)
{
int index;
char uname[10];
char buf[128];
char *tbuffer; // Accumulation buffer of unit IDs.
/*
** First, clear out all existing unit data from the ini file.
*/
tbuffer = buffer + strlen(buffer) + 2;
WWGetPrivateProfileString(INI_Name(), NULL, NULL, tbuffer, ShapeBufferSize-strlen(buffer), buffer);
while (*tbuffer != '\0') {
WWWritePrivateProfileString(INI_Name(), tbuffer, NULL, buffer);
tbuffer += strlen(tbuffer)+1;
}
/*
** Write the unit data out.
*/
for (index = 0; index < Units.Count(); index++) {
UnitClass * unit;
unit = Units.Ptr(index);
if (!unit->IsInLimbo && unit->IsActive) {
sprintf(uname, "%03d", index);
sprintf(buf, "%s,%s,%d,%u,%d,%s,%s",
unit->House->Class->IniName,
unit->Class->IniName,
unit->Health_Ratio(),
Coord_Cell(unit->Coord),
unit->PrimaryFacing.Current(),
MissionClass::Mission_Name(unit->Mission),
unit->Trigger ? unit->Trigger->Get_Name() : "None"
);
WWWritePrivateProfileString(INI_Name(), uname, buf, buffer);
}
}
}
/***********************************************************************************************
* UnitClass::Exit_Repair -- Drive the unit off the repair facility. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/03/1995 BWG : Created. *
*=============================================================================================*/
#define XYCELL(x,y) (y*MAP_CELL_W+x)
void UnitClass::Exit_Repair(void)
{
Validate();
int i;
CELL cell;
bool found = false;
static short const ExitRepair[] = {
XYCELL(0,-2),
XYCELL(1,-1),
XYCELL(2, 0),
XYCELL(1, 1),
XYCELL(0, 2),
XYCELL(-1,1),
XYCELL(-2,0),
XYCELL(-1,-1)
};
cell = Coord_Cell(Coord) + ExitRepair[Dir_Facing(PrimaryFacing.Current())];
if (Can_Enter_Cell(cell) == MOVE_OK) found = true;
if (!found) for (i=0; i<8; i++) {
cell = Coord_Cell(Coord) + ExitRepair[i];
if (Can_Enter_Cell(cell) == MOVE_OK) {
found = true;
break;
}
}
if (found) {
DirType dir = Direction(cell);
Assign_Mission(MISSION_MOVE);
Assign_Destination(::As_Target(cell));
}
}
/***********************************************************************************************
* UnitClass::Mission_Guard -- Special guard mission override processor. *
* *
* This routine will intercept the guard mission and if it is for a hovercraft, assign *
* it the unload mission instead. This prevents the hovercraft from being stuck in the *
* water if something unexpected causes it to drop into guard mode. *
* *
* INPUT: none *
* *
* OUTPUT: Returns the time delay before this command is executed again. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/08/1995 JLB : Created. *
* 05/08/1995 JLB : Fixes gunboat problems. *
*=============================================================================================*/
int UnitClass::Mission_Guard(void)
{
Validate();
if (*this == UNIT_HOVER) {
if (Is_Something_Attached()) {
Assign_Mission(MISSION_UNLOAD);
Find_LZ();
} else {
Exit_Map();
}
return(TICKS_PER_SECOND);
}
if (*this == UNIT_GUNBOAT) {
Assign_Mission(MISSION_HUNT);
return(TICKS_PER_SECOND);
}
if (*this == UNIT_HARVESTER && !House->IsHuman) {
Assign_Mission(MISSION_HARVEST);
return(TICKS_PER_SECOND);
}
#ifdef USE_RA_AI
/*
** Copied functionality from RA for AI. ST - 7/25/2019 3:11PM
*/
if (GameToPlay != GAME_NORMAL) {
if (*this == UNIT_MCV && House->IsBaseBuilding && House->IsHuman == false) {
Assign_Mission(MISSION_UNLOAD);
return(TICKS_PER_SECOND + Random_Pick(0, 2));
}
}
#endif // USE_RA_AI
return(TarComClass::Mission_Guard());
}
/***********************************************************************************************
* UnitClass::Mission_Move -- Handles special move mission overrides. *
* *
* This routine intercepts the normal move mission and if a gunboat is being processed, *
* changes its mission to hunt. This is an attempt to keep the gunboat on the hunt mission *
* regardless of what the player did. *
* *
* INPUT: none *
* *
* OUTPUT: Returns the number of ticks before this routine should be called again. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/09/1995 JLB : Created. *
*=============================================================================================*/
int UnitClass::Mission_Move(void)
{
Validate();
IsHarvesting = false;
/*
** Always make sure that that transport door is closed if the vehcile is moving.
*/
if (!Is_Door_Closed()) {
APC_Close_Door();
}
/*
** Gunboats must always have the hunt mission.
*/
if (*this == UNIT_GUNBOAT) {
Assign_Mission(MISSION_HUNT);
return(TICKS_PER_SECOND);
}
return(TarComClass::Mission_Move());
}
/***********************************************************************************************
* UnitClass::Desired_Load_Dir -- Determines the best cell and facing for loading. *
* *
* This routine examines the unit and adjacent cells in order to find the best facing *
* for the transport and best staging cell for the potential passengers. This location is *
* modified by adjacent cell passability and direction of the potential passenger. *
* *
* INPUT: passenger -- Pointer to the potential passenger. *
* *
* moveto -- Reference to the cell number that specifies where the potential *
* passenger should move to first. *
* *
* OUTPUT: Returns with the direction the transport should face before opening the transport *
* door. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/23/1995 JLB : Created. *
*=============================================================================================*/
DirType UnitClass::Desired_Load_Dir(ObjectClass * passenger, CELL & moveto) const
{
Validate();
/*
** Determine the ideal facing that provides the least resistance. This would be the direction
** of the potential passenger or the current transport facing if it is going to unload.
*/
DirType faceto;
if (passenger) {
faceto = Direction(passenger);
} else {
faceto = PrimaryFacing.Current() + DIR_S;
}
/*
** Sweep through the adjacent cells in order to find the best candidate.
*/
FacingType bestdir;
int bestval = -1;
for (FacingType face = FACING_N; face < FACING_COUNT; face++) {
int value = 0;
CELL cellnum = Adjacent_Cell(Coord_Cell(Coord), face);
/*
** Base the initial value of the potential cell according to whether the passenger is
** allowed to enter the cell. If it can't, then give such a negative value to the
** cell so that it is prevented from ever choosing that cell for load/unload.
*/
if (passenger) {
value = (passenger->Can_Enter_Cell(cellnum) == MOVE_OK || Coord_Cell(passenger->Coord) == cellnum) ? 128 : -128;
} else {
CellClass * cell = &Map[cellnum];
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) {
value = -128;
} else {
if (cell->Cell_Techno() && !House->Is_Ally(cell->Cell_Techno())) {
value = -128;
} else {
value = 128;
}
}
}
/*
** Give more weight to the cells that require the least rotation of the transport or the
** least roundabout movement for the potential passenger.
*/
value -= (int)ABS(Dir_Diff(Facing_Dir(face), faceto));
if (face == FACING_S) {
value -= 100;
}
if (face == FACING_SW || face == FACING_SE) value += 64;
/*
** If the value for the potiential cell is greater than the last recorded potential
** value, then record this cell as the best candidate.
*/
if (bestval == -1 || value > bestval) {
bestval = value;
bestdir = face;
}
}
/*
** If a suitable direction was found, then return with the direction value.
*/
moveto = 0;
if (bestval > 0) {
static DirType _desired_to_actual[FACING_COUNT] = {DIR_S, DIR_SW, DIR_NW, DIR_NW, DIR_NE, DIR_NE, DIR_NE, DIR_SE};
moveto = Adjacent_Cell(Coord_Cell(Coord), bestdir);
return(_desired_to_actual[bestdir]);
}
return(DIR_S);
}
/***********************************************************************************************
* UnitClass::Mission_Attack -- Handles the mission attack logic. *
* *
* This routine intercepts the normal mission attack logic. If a gunboat is assigned the *
* attack mission then it must be converted back to a hunt mission. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the time before calling this routine again. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/23/1995 JLB : Created. *
*=============================================================================================*/
int UnitClass::Mission_Attack(void)
{
Validate();
if (*this == UNIT_GUNBOAT) {
Assign_Mission(MISSION_HUNT);
return(TICKS_PER_SECOND);
}
return(TarComClass::Mission_Attack());
}
/***********************************************************************************************
* UnitClass::Flag_Attach -- Attaches a house flag to this unit. *
* *
* This routine will attach a house flag to this unit. *
* *
* INPUT: house -- The house that is having its flag attached to it. *
* *
* OUTPUT: Was the house flag successfully attached to this unit? *
* *
* WARNINGS: A unit can only carry one flag at a time. This might be a reason for failure *
* of this routine. *
* *
* HISTORY: *
* 05/23/1995 JLB : Created. *
*=============================================================================================*/
bool UnitClass::Flag_Attach(HousesType house)
{
Validate();
if (house != HOUSE_NONE && Flagged == HOUSE_NONE) {
Flagged = house;
Mark(MARK_CHANGE);
return(true);
}
return(false);
}
/***********************************************************************************************
* UnitClass::Flag_Remove -- Removes the house flag from this unit. *
* *
* This routine will remove the house flag that is attached to this unit. *
* *
* INPUT: none *
* *
* OUTPUT: Was the flag successfully removed? *
* *
* WARNINGS: This routine doesn't put the flag into a new location. That operation must *
* be performed or else the house flag will cease to exist. *
* *
* HISTORY: *
* 05/23/1995 JLB : Created. *
*=============================================================================================*/
bool UnitClass::Flag_Remove(void)
{
Validate();
if (Flagged != HOUSE_NONE) {
Flagged = HOUSE_NONE;
Mark(MARK_CHANGE);
return(true);
}
return(false);
}
/***********************************************************************************************
* UnitClass::Stun -- Stuns the unit in preparation for unit removal. *
* *
* This routine intercepts the stun operation for the unit and if there is a house flag *
* attached, it will drop it to the ground. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/23/1995 JLB : Created. *
*=============================================================================================*/
void UnitClass::Stun(void)
{
Validate();
if (Flagged != HOUSE_NONE) {
HouseClass::As_Pointer(Flagged)->Flag_Attach(Coord_Cell(Coord));
}
TarComClass::Stun();
}
/***********************************************************************************************
* UnitClass::Pip_Count -- Fetchs the number of pips to display on unit. *
* *
* This routine is used to fetch the number of "fullness" pips to display on the unit. *
* This will either be the number of passengers or the percentage full (in 1/5ths) of *
* a harvester. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the number of pips to draw on this unit. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/25/1995 JLB : Created. *
*=============================================================================================*/
int UnitClass::Pip_Count(void) const
{
Validate();
if (Class->IsTransporter) {
return(How_Many());
}
if (Class->IsToHarvest) {
return(Fixed_To_Cardinal(UnitTypeClass::FULL_LOAD_CREDITS/100, Tiberium_Load()));
}
return(0);
}
/***********************************************************************************************
* UnitClass::APC_Close_Door -- Closes an APC door. *
* *
* This routine will initiate closing of the APC door. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/25/1995 JLB : Created. *
*=============================================================================================*/
void UnitClass::APC_Close_Door(void)
{
Validate();
Close_Door(10, 2);
}
/***********************************************************************************************
* UnitClass::APC_Open_Door -- Opens an APC door. *
* *
* This routine will initiate opening of the APC door. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/25/1995 JLB : Created. *
*=============================================================================================*/
void UnitClass::APC_Open_Door(void)
{
Validate();
if (!IsDriving && !IsRotating) {
if (PrimaryFacing == DIR_NW || PrimaryFacing == DIR_NE) {
Open_Door(10, 2);
} else {
Open_Door(1, 2);
}
}
}
/***********************************************************************************************
* UnitClass::Remap_Table -- Fetches the remap table to use for this object. *
* *
* Use this routine to determine the rendering remap table to use for this object. The *
* remap table is normally the unit remap table, except for the MCV and the Harvestor. *
* These units use the building remap table since these units become part of the building *
* animation. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with a pointer to the remap table to use for this unit. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/08/1995 JLB : Created. *
*=============================================================================================*/
void const * UnitClass::Remap_Table(void)
{
Validate();
if (*this == UNIT_MCV || *this == UNIT_HARVESTER) {
return(House->Remap_Table(IsBlushing, false));
}
return(TarComClass::Remap_Table());
}
/***********************************************************************************************
* UnitClass::Crew_Type -- Fetches the kind of crew that this object produces. *
* *
* When a unit is destroyed, a crew member might be generated. This routine will return *
* with the infantry type to produce for this unit. This routine will be called for every *
* survivor that is generated. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with a suggested infantry type to generate as a survivor from this unit. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/13/1995 JLB : Created. *
*=============================================================================================*/
InfantryType UnitClass::Crew_Type(void) const
{
Validate();
if (Class->Primary == WEAPON_NONE) {
if (Random_Pick(0, 1) == 0) {
return(INFANTRY_C1);
} else {
return(INFANTRY_C7);
}
}
return(TarComClass::Crew_Type());
}
/***********************************************************************************************
* UnitClass::What_Am_I -- Returns with the RTTI type this object is. *
* *
* This will return that this is a normal vehicle unit type. Each object class overrides *
* this function in order to provide run time type identification support. *
* *
* INPUT: none *
* *
* OUTPUT: Returns the RTTI type that this object is (i.e., RTTI_UNIT). *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/13/1995 JLB : Created. *
*=============================================================================================*/
RTTIType UnitClass::What_Am_I(void) const
{
Validate();
return(RTTI_UNIT);
}