CnC_Remastered_Collection/REDALERT/OBJECT.CPP

2505 lines
143 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: /CounterStrike/OBJECT.CPP 1 3/03/97 10:25a 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 : OBJECT.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : April 29, 1994 *
* *
* Last Update : October 6, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* ObjectClass::AI -- Handles generic object AI processing. *
* ObjectClass::Active_Click_With -- Dispatches action on the object specified. *
* ObjectClass::Active_Click_With -- Dispatches action on the specified cell. *
* ObjectClass::Attach_Trigger -- Attach specified trigger to object. *
* ObjectClass::Can_Demolish -- Queries whether this object can be sold back. *
* ObjectClass::Can_Player_Fire -- Can the player give this object an attack mission? *
* ObjectClass::Can_Player_Move -- Can the player give this object a movement mission? *
* ObjectClass::Can_Repair -- Queries whether this object can be repaired. *
* ObjectClass::Catch_Fire -- Called when animation is attached to this object. *
* ObjectClass::Center_Coord -- Fetches the center coordinate for the object. *
* ObjectClass::Clicked_As_Target -- Triggers target selection animation. *
* ObjectClass::Debug_Dump -- Displays status of the object class to the mono monitor. *
* ObjectClass::Detach -- Detach the specified target from this object. *
* ObjectClass::Detach_All -- Removes the object from all tracking systems. *
* ObjectClass::Do_Shimmer -- Shimmers this object if it is cloaked. *
* ObjectClass::Docking_Coord -- Fetches the coordinate to dock at this object. *
* ObjectClass::Exit_Coord -- Return with the exit coordinate for this object. *
* ObjectClass::Exit_Object -- Causes the specified object to leave this object. *
* ObjectClass::Fire_Coord -- Fetches the coordinate a projectile will launch from. *
* ObjectClass::Fire_Out -- Informs object that attached animation has finished. *
* ObjectClass::Get_Mission -- Fetches the current mission of this object. *
* ObjectClass::Get_Ownable -- Fetches the house owner legality options for this object. *
* ObjectClass::Hidden -- Called when this object becomes hidden from the player. *
* ObjectClass::In_Range -- Determines if the coordinate is within weapon range. *
* ObjectClass::In_Which_Layer -- Fetches what layer this object is located in. *
* ObjectClass::Init -- Initializes the basic object system. *
* ObjectClass::Limbo -- Brings the object into a state of limbo. *
* ObjectClass::Look -- Called when this object needs to reveal terrain. *
* ObjectClass::Mark -- Handles basic marking logic. *
* ObjectClass::Mark_For_Redraw -- Marks object and system for redraw. *
* ObjectClass::Move -- Moves (by force) the object in the desired direction. *
* ObjectClass::Name -- Fetches the identification name of this object. *
* ObjectClass::ObjectClass -- Default constructor for objects. *
* ObjectClass::Paradrop -- Unlimbos object in paradrop mode. *
* ObjectClass::Passive_Click_With -- Right mouse button click process. *
* ObjectClass::Receive_Message -- Processes an incoming radio message. *
* ObjectClass::Record_The_Kill -- Records this object as killed by the specified object. *
* ObjectClass::Render -- Displays the object onto the map. *
* ObjectClass::Render_Coord -- Fetches the coordinate to draw this object at. *
* ObjectClass::Repair -- Handles object repair control. *
* ObjectClass::Revealed -- Reveals this object to the house specified. *
* ObjectClass::Scatter -- Tries to scatter this object. *
* ObjectClass::Select -- Try to make this object the "selected" object. *
* ObjectClass::Sell_Back -- Sells the object -- if possible. *
* ObjectClass::Sort_Y -- Returns the coordinate used for display order sorting. *
* ObjectClass::Take_Damage -- Applies damage to the object. *
* ObjectClass::Target_Coord -- Fetches the coordinate if this object is a target. *
* ObjectClass::Unlimbo -- Brings the object into the game system. *
* ObjectClass::Unselect -- This will un-select the object if it was selected. *
* ObjectClass::Value -- Fetches the target value of this object. *
* ObjectClass::Weapon_Range -- Returns the weapon range for the weapon specified. *
* ObjectClass::What_Action -- Determines what action to perform on specified object. *
* ObjectClass::What_Action -- Returns with the action to perform for this object. *
* ObjectTypeClass::Cost_Of -- Returns the cost to buy this unit. *
* ObjectTypeClass::Dimensions -- Gets the dimensions of the object in pixels. *
* ObjectTypeClass::Get_Cameo_Data -- Fetches pointer to cameo data for this object type. *
* ObjectTypeClass::Max_Pips -- Fetches the maximum pips allowed for this object. *
* ObjectTypeClass::ObjectTypeClass -- Normal constructor for object type class objects. *
* ObjectTypeClass::Occupy_List -- Returns with simple occupation list for object. *
* ObjectTypeClass::One_Time -- Handles one time processing for object types. *
* ObjectTypeClass::Overlap_List -- Returns a pointer to a simple overlap list. *
* ObjectTypeClass::Time_To_Build -- Fetches the time to construct this object. *
* ObjectTypeClass::Who_Can_Build_Me -- Determine what building can build this object type. *
* ObjectTypeClass::Who_Can_Build_Me -- Finds the factory building that can build this object*
* ObjectClass::Get_Image_Data -- Fetches the image data to use for this object. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/*
** Selected objects have a special marking box around them. This is the shapes that are
** used for this purpose.
*/
void const * ObjectTypeClass::SelectShapes = 0;
void const * ObjectTypeClass::PipShapes = 0;
/***********************************************************************************************
* ObjectClass::ObjectClass -- Default constructor for objects. *
* *
* This is the default constructor for objects. It is called as an inherent part of the *
* construction process for all the normal game objects instantiated. It serves merely to *
* initialize the object values to a common (default) state. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: Objects always start in a state of limbo. They must be Unlimbo()ed before they *
* can be used. *
* *
* HISTORY: *
* 09/24/1994 JLB : Created. *
*=============================================================================================*/
ObjectClass::ObjectClass(RTTIType rtti, int id) :
AbstractClass(rtti, id),
IsDown(false),
IsToDamage(false),
IsToDisplay(false),
IsInLimbo(true),
IsSelected(false),
IsAnimAttached(false),
IsFalling(false),
Riser(0),
Next(0),
Trigger(NULL),
Strength(255),
IsSelectedMask(0) // Mask showing who has selected this object
{
}
/***********************************************************************************************
* ObjectClass::Get_Image_Data -- Fetches the image data to use for this object. *
* *
* This routine will return with a pointer to the image data that should be used when *
* this object is drawn. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with a pointer to the shape data for this object. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/06/1996 JLB : Created. *
*=============================================================================================*/
void const * ObjectClass::Get_Image_Data(void) const
{
return(Class_Of().Get_Image_Data());
}
/***********************************************************************************************
* ObjectClass::Name -- Fetches the identification name of this object. *
* *
* This routine will return a pointer to the identifier name for this object. This name *
* is usually short and is used in the INI files to identify this object. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with a pointer to the text identifier name of this object. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/29/1996 JLB : Created. *
*=============================================================================================*/
char const * ObjectClass::Name(void) const
{
return(Class_Of().Name());
}
/***********************************************************************************************
* ObjectClass::Exit_Coord -- Return with the exit coordinate for this object. *
* *
* Ths exit coordinate is the location that a piggy back or newly produced object will *
* appear at when it exits this object. Transports and factory buildings will utilize this *
* routine. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the coordinate that an object will appear at when exiting this *
* object. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/29/1996 JLB : Created. *
*=============================================================================================*/
COORDINATE ObjectClass::Exit_Coord(void) const
{
return(Center_Coord());
}
/***********************************************************************************************
* ObjectClass::AI -- Handles generic object AI processing. *
* *
* This routine is used to handle the AI processing that occurs for all object types. *
* Typically, this isn't much, but there is the concept of falling that all objects can *
* be subjected to (e.g., grenades). *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 02/07/1996 JLB : Created. *
*=============================================================================================*/
void ObjectClass::AI(void)
{
assert(this != 0);
assert(IsActive);
/*
** Falling logic is handled here.
*/
if (IsFalling) {
LayerType layer = In_Which_Layer();
Height += Riser;
if (Height <= 0) {
Height = 0;
IsFalling = false;
Per_Cell_Process(PCP_END);
Shorten_Attached_Anims(this);
}
if (IsAnimAttached) {
Riser -= 1;
Riser = max(Riser, -3);
} else {
Riser -= Rule.Gravity;
// Riser -= GRAVITY;
Riser = max(Riser, -100);
}
if (layer != In_Which_Layer()) {
Map.Remove(this, layer);
Map.Submit(this, In_Which_Layer());
if (Class_Of().IsFootprint) {
if (In_Which_Layer() == LAYER_GROUND) {
Map.Place_Down(Coord_Cell(Center_Coord()), this);
} else {
Map.Pick_Up(Coord_Cell(Center_Coord()), this);
}
}
}
}
}
/***********************************************************************************************
* ObjectClass::What_Action -- Determines what action to perform on specified object. *
* *
* This routine will return that action that this object could perform if the mouse were *
* clicked over the object specified. *
* *
* INPUT: object -- Pointer to the object to check this object against when determining *
* the action to perform. *
* *
* OUTPUT: It returns that action that will be performed if the mouse were clicked over the *
* object. Since non-derived objects cannot do anything, and cannot even be *
* instantiated, this routine will always return ACTION_NONE. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/19/1995 JLB : Created. *
*=============================================================================================*/
ActionType ObjectClass::What_Action(ObjectClass const *) const
{
assert(this != 0);
assert(IsActive);
return(ACTION_NONE);
}
/***********************************************************************************************
* ObjectClass::What_Action -- Returns with the action to perform for this object. *
* *
* This routine is called when information on a potential action if the mouse were clicked *
* on the cell specified. This routine merely serves as a virtual placeholder so that *
* object types that can actually perform some action will override this routine to provide *
* true functionality. *
* *
* INPUT: cell -- The cell that the mouse is over and might be clicked on. *
* *
* OUTPUT: Returns with the action that this object would try to perform if the mouse were *
* clicked. Since objects at this level have no ability to do anything, this routine *
* will always returns ACTION_NONE unless it is overridden. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/13/1995 JLB : Created. *
*=============================================================================================*/
ActionType ObjectClass::What_Action(CELL) const
{
assert(this != 0);
assert(IsActive);
return(ACTION_NONE);
}
/***********************************************************************************************
* ObjectClass::In_Which_Layer -- Fetches what layer this object is located in. *
* *
* The default layer for object location is the LAYER_GROUND. Aircraft will override this *
* routine and make adjustments as necessary according to the aircraft's altitude. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the layer that this object is located in. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/13/1995 JLB : Created. *
*=============================================================================================*/
LayerType ObjectClass::In_Which_Layer(void) const
{
assert(this != 0);
assert(IsActive);
if (Height < (FLIGHT_LEVEL - (FLIGHT_LEVEL/3))) {
return(LAYER_GROUND);
}
return(LAYER_TOP);
}
/***********************************************************************************************
* ObjectClass::Get_Ownable -- Fetches the house owner legality options for this object. *
* *
* This routine will return the ownable bits for this object. Objects at this level can't *
* really be owned by anyone, but return the full spectrum of legality just to be safe. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the ownable flags (as a combined bitfield) for this object. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/13/1995 JLB : Created. *
*=============================================================================================*/
int ObjectClass::Get_Ownable(void) const
{
assert(this != 0);
assert(IsActive);
return(HOUSEF_ALLIES | HOUSEF_SOVIET | HOUSEF_OTHERS);
}
/***********************************************************************************************
* ObjectClass::Can_Repair -- Queries whether this object can be repaired. *
* *
* Most objects cannot be repaired. This routine defaults to returning "false", but is *
* overridden by derived functions defined by object types that can support repair. *
* *
* INPUT: none *
* *
* OUTPUT: Can this object be repaired? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/13/1995 JLB : Created. *
*=============================================================================================*/
bool ObjectClass::Can_Repair(void) const
{
assert(this != 0);
assert(IsActive);
return(false);
}
/***********************************************************************************************
* ObjectClass::Can_Demolish -- Queries whether this object can be sold back. *
* *
* This routine is used to determine if this object can be sold. Most objects cannot be *
* but for those objects that can, this routine will be overridden as necessary. *
* *
* INPUT: none *
* *
* OUTPUT: Can this object be sold back? Typically, the answer is no. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/13/1995 JLB : Created. *
*=============================================================================================*/
bool ObjectClass::Can_Demolish(void) const
{
assert(this != 0);
assert(IsActive);
return(false);
}
bool ObjectClass::Can_Demolish_Unit(void) const
{
assert(this != 0);
assert(IsActive);
return(false);
}
bool ObjectClass::Can_Capture(void) const
{
assert(this != 0);
assert(IsActive);
return(false);
}
/***********************************************************************************************
* ObjectClass::Can_Player_Fire -- Can the player give this object an attack mission? *
* *
* This routine is used to determine if attacking is an option under player control with *
* respect to this unit. This routine will be overridden as necessary for those objects *
* that have the ability to attack. *
* *
* INPUT: none *
* *
* OUTPUT: Can this object be given an attack order by the player? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/13/1995 JLB : Created. *
*=============================================================================================*/
bool ObjectClass::Can_Player_Fire(void) const
{
assert(this != 0);
assert(IsActive);
return(false);
}
/***********************************************************************************************
* ObjectClass::Can_Player_Move -- Can the player give this object a movement mission? *
* *
* This routine is used to determine if the player has the ability to command this object *
* with a movement mission. This routine will be overridden as necessary to support this *
* ability. *
* *
* INPUT: none *
* *
* OUTPUT: Can this object be given a movement mission by the player? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/13/1995 JLB : Created. *
*=============================================================================================*/
bool ObjectClass::Can_Player_Move(void) const
{
assert(this != 0);
assert(IsActive);
return(false);
}
/***********************************************************************************************
* ObjectClass::Target_Coord -- Fetches the coordinate if this object is a target. *
* *
* When the coordinate to use when firing at this object is needed, this routine will *
* provide it. Normal objects just use the center of the object for this, but there are *
* some more sophisticated objects that are not fired upon the center. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the coordinate to fire at if this object is a target. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/13/1995 JLB : Created. *
*=============================================================================================*/
COORDINATE ObjectClass::Target_Coord(void) const
{
assert(this != 0);
assert(IsActive);
return(Coord_Add(XY_Coord(0, -Height), Center_Coord()));
// return(Center_Coord());
}
/***********************************************************************************************
* ObjectClass::Center_Coord -- Fetches the center coordinate for the object. *
* *
* This routine will return the center coordinate for the object. The center coordinate is *
* typically the coordinate recorded in the object structure. Exceptions to this include *
* the trees and other terrain elements. *
* *
* INPUT: none *
* *
* OUTPUT: Returns the coordinate that is considered the center point of this object. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
COORDINATE ObjectClass::Center_Coord(void) const
{
assert(this != 0);
assert(IsActive);
return(Coord);
}
/***********************************************************************************************
* ObjectClass::Render_Coord -- Fetches the coordinate to draw this object at. *
* *
* This routine will return the coordinate to base the drawing of this object's graphic *
* at. This is adjusted according to the nature of the graphic associated with this *
* object. *
* *
* INPUT: none *
* *
* OUTPUT: Returns the coordinate to draw the graphic of this object at. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
COORDINATE ObjectClass::Render_Coord(void) const
{
assert(this != 0);
assert(IsActive);
return(Center_Coord());
}
/***********************************************************************************************
* ObjectClass::Docking_Coord -- Fetches the coordinate to dock at this object. *
* *
* This routine returns the coordinate that a potential docking object should home in on. *
* Typically, this the center of the object, but in certain cases it is adjusted off center *
* according to the object type. An example of this would be the airfield. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the coordinate that a docking object should head for. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
COORDINATE ObjectClass::Docking_Coord(void) const
{
assert(this != 0);
assert(IsActive);
return(Center_Coord());
}
/***********************************************************************************************
* ObjectClass::Sort_Y -- Returns the coordinate used for display order sorting. *
* *
* This routine will return the value to be used for object sorting. The sorting ensures *
* that the object are rendered from a top to bottom order. Certain object use a sorting *
* value different from their center coordinate. This is true if the object "touches the *
* ground" at a point that is different from the object's center point. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the value to use as the Y sorting value. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
COORDINATE ObjectClass::Sort_Y(void) const
{
assert(this != 0);
assert(IsActive);
return(Coord);
}
/***********************************************************************************************
* ObjectClass::Fire_Coord -- Fetches the coordinate a projectile will launch from. *
* *
* For those objects that fire, the coordinate that the projectile it launches will appear *
* at the location specified by the return value from this function. *
* *
* INPUT: which -- Which weapon to consider when determining fire coordinate? *
* 0: primary weapon *
* 1: secondary weapon *
* *
* OUTPUT: Returns with the coordinate that a launched projectile will appear at if this *
* object were to fire the weapon specified. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
FireDataType ObjectClass::Fire_Data(int which) const
{
assert(this != 0);
assert(IsActive);
return{Fire_Coord(which),0};
}
COORDINATE ObjectClass::Fire_Coord(int ) const
{
assert(this != 0);
assert(IsActive);
return(Coord);
}
/***********************************************************************************************
* ObjectClass::Record_The_Kill -- Records this object as killed by the specified object. *
* *
* This routine is called when this object is killed. If the source of the death is known, *
* then a pointer to the responsible object is provided as a parameter. *
* *
* INPUT: source -- Pointer to the cause of this unit's death. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Record_The_Kill(TechnoClass * )
{
assert(this != 0);
assert(IsActive);
}
/***********************************************************************************************
* ObjectClass::Do_Shimmer -- Shimmers this object if it is cloaked. *
* *
* When an object is cloaked, there are several conditions that would cause it to shimmer *
* and thus reveal itself. When such a condition arrises, this function is called. If the *
* object is cloaked, then it will shimmer. At this derivation level, cloaking is *
* undefined. Objects that can cloak will override this function as necessary. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Do_Shimmer(void)
{
assert(this != 0);
assert(IsActive);
}
/***********************************************************************************************
* ObjectClass::Exit_Object -- Causes the specified object to leave this object. *
* *
* This routine is called, typically, by a transport building type that requires an object *
* to leave it. This routine will place the object at a suitable location or return *
* a value indicating why not. *
* *
* INPUT: object -- Pointer to the object that wishes to leave this object. *
* *
* OUTPUT: Returns the success value of the attempt: *
* 0: Object could not be placed -- ever *
* 1: Object placement is temporarily delayed -- try again later. *
* 2: Object placement proceeded normally *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
int ObjectClass::Exit_Object(TechnoClass *)
{
assert(this != 0);
assert(IsActive);
return(0);
}
/***********************************************************************************************
* ObjectClass::Hidden -- Called when this object becomes hidden from the player. *
* *
* This routine is called when the object becomes hidden from the player. It can result in *
* lost targeting and tracking abilities with respect to the hidden object. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Hidden(void)
{
assert(this != 0);
assert(IsActive);
}
/***********************************************************************************************
* ObjectClass::Look -- Called when this object needs to reveal terrain. *
* *
* This routine is called when the object needs to look around the terrain. For player *
* owned objects, the terrain is revealed. For non-player objects, not effect occurs. *
* *
* INPUT: incremental -- If true, then the looking algorithm will only examine the edges *
* of the sight range. This is more efficient and work well if the *
* object has only moved one cell since the last time it has performed *
* the look operation. *
* *
* OUTPUT: none *
* *
* WARNINGS: This can be a time consuming operation. Call only when necessary. *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Look(bool )
{
assert(this != 0);
assert(IsActive);
}
/***********************************************************************************************
* ObjectClass::Active_Click_With -- Dispatches action on the object specified. *
* *
* This routine is called when this object is selected and the mouse was clicked on the *
* tactical map. An action is required from the object. The object that the mouse was *
* over and the tentative action to perform are provided as parameters. *
* *
* INPUT: action -- The requested action to perform with the object specified. *
* *
* object -- The object that the action should be performed on. This object is *
* what the mouse was over when the click occurred. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Active_Click_With(ActionType , ObjectClass *)
{
assert(this != 0);
assert(IsActive);
}
/***********************************************************************************************
* ObjectClass::Active_Click_With -- Dispatches action on the specified cell. *
* *
* This routine will dispatch the action requested upon the cell specified. It is called *
* when the mouse is clicked over a cell while this object is selected. *
* *
* INPUT: action -- The action to perform. *
* *
* cell -- The location (cell) to perform this action upon. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Active_Click_With(ActionType , CELL )
{
assert(this != 0);
assert(IsActive);
}
/***********************************************************************************************
* ObjectClass::Clicked_As_Target -- Triggers target selection animation. *
* *
* This routine is called when this object is the target of some player click action. *
* For more sophisticated object, this will trigger the object to begin flashing a few *
* times. At this level, no action is performed. *
* *
* INPUT: flashes -- The requested number of times to flash this object. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Clicked_As_Target(HousesType house, int) // 2019/09/20 JAS - Added record of who clicked on the object
{
assert(this != 0);
assert(IsActive);
}
/***********************************************************************************************
* ObjectClass::In_Range -- Determines if the coordinate is within weapon range. *
* *
* This routine will determine if the specified coordinate is within weapon range. *
* *
* INPUT: coord -- The coordinate to check to see if it is within weapon range. *
* *
* which -- The weapon to check against. *
* 0: primary weapon *
* 1: secondary weapon *
* *
* OUTPUT: bool; Is the specified coordinate within weapon range for the weapon type *
* specified? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
bool ObjectClass::In_Range(COORDINATE , int) const
{
assert(this != 0);
assert(IsActive);
return(false);
}
/***********************************************************************************************
* ObjectClass::Weapon_Range -- Returns the weapon range for the weapon specified. *
* *
* This routine will return the weapon range according to the type of weapon specified. *
* *
* INPUT: which -- The weapon to fetch the range from. *
* 0: primary weapon *
* 1: secondary weapon *
* *
* OUTPUT: Returns with the range (in leptons) of the weapon specified. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
int ObjectClass::Weapon_Range(int) const
{
assert(this != 0);
assert(IsActive);
return(0);
}
/***********************************************************************************************
* ObjectClass::Scatter -- Tries to scatter this object. *
* *
* This routine is used when the object should scatter from its current location. It *
* applies to units that have the ability to move. *
* *
* INPUT: coord -- The source of the threat that is causing the scatter. *
* *
* forced-- Whether this scatter attempt is serious and scattering should occur *
* regardless of what is doing now. *
* *
* OUTPUT: none *
* *
* WARNINGS: This may or may not cause the object to scatter. It is merely a request to the *
* object that it would be good if it were to scatter. *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Scatter(COORDINATE , bool, bool)
{
assert(this != 0);
assert(IsActive);
}
/***********************************************************************************************
* ObjectClass::Catch_Fire -- Called when animation is attached to this object. *
* *
* This routine is called when an animation is attached to this object. It might be a *
* fire animation (hence the name), but it might also be smoke or any other animation *
* as well. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Was the object caught on fire by this routine? Actually, this is really *
* the answer to this question; "Is this animation attaching to this object *
* that doesn't already have an animation attached?" *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/21/1995 JLB : Created. *
*=============================================================================================*/
bool ObjectClass::Catch_Fire(void)
{
assert(this != 0);
assert(IsActive);
return false;
}
/***********************************************************************************************
* ObjectClass::Fire_Out -- Informs object that attached animation has finished. *
* *
* This routine is called if there is an attached animation on this object and that *
* animation has finished. Typically, this is necessary for when trees are on fire. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/24/1995 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Fire_Out(void)
{
assert(this != 0);
assert(IsActive);
}
/***********************************************************************************************
* ObjectClass::Value -- Fetches the target value of this object. *
* *
* This routine will return the target value of this object. The higher the number, the *
* better the object will be as a target. This routine is called when searching for *
* targets. Generic objects have no target potential, and this routine returns zero to *
* reflect that. Other object types will override this routine to return the appropriate *
* target value. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the value of this object as a target. Higher values mean better *
* target. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/24/1995 JLB : Created. *
*=============================================================================================*/
int ObjectClass::Value(void) const
{
assert(this != 0);
assert(IsActive);
return(0);
}
/***********************************************************************************************
* ObjectClass::Get_Mission -- Fetches the current mission of this object. *
* *
* Generic objects don't have a mission, so this routine will just return MISSION_NONE. *
* However, techno objects do have a mission and this routine is overloaded to handle *
* those objects in order to return the correct mission value. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the current mission being followed by this object. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/24/1995 JLB : Created. *
*=============================================================================================*/
MissionType ObjectClass::Get_Mission(void) const
{
assert(this != 0);
assert(IsActive);
return(MISSION_NONE);
}
/***********************************************************************************************
* ObjectClass::Repair -- Handles object repair control. *
* *
* This routine will control object repair mode. At the object level, no repair is *
* possible, so it is expected that any object that can repair will override this function *
* as necessary. *
* *
* INPUT: control -- The repair control parameter. *
* 0 = turn repair off *
* 1 = turn repair on *
* -1 = toggle repair state *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/24/1995 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Repair(int )
{
assert(this != 0);
assert(IsActive);
}
/***********************************************************************************************
* ObjectClass::Sell_Back -- Sells the object -- if possible. *
* *
* This routine is called to sell back the object. Override this routine for the more *
* sophisticated objects that can actually be sold back. Normal objects can't be sold and *
* this routine does nothing as a consequence. *
* *
* INPUT: control -- How to control the sell state of this object. *
* 0 = stop selling. *
* 1 = start selling. *
* -1 = toggle selling state. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/19/1995 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Sell_Back(int )
{
assert(this != 0);
assert(IsActive);
}
/***********************************************************************************************
* ObjectClass::Move -- Moves (by force) the object in the desired direction. *
* *
* This routine will instantly move the object one cell in the specified direction. It *
* moves the object by force. This is typically ONLY used by the scenario editor *
* process. *
* *
* INPUT: facing -- The direction to move the object. *
* *
* OUTPUT: none *
* *
* WARNINGS: Naturally, this can cause illegal placement situations -- use with caution. *
* *
* HISTORY: *
* 06/19/1994 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Move(FacingType facing)
{
assert(this != 0);
assert(IsActive);
COORDINATE coord;
Mark(MARK_UP);
coord = Adjacent_Cell(Coord, facing);
if (Can_Enter_Cell(Coord_Cell(coord)) == MOVE_OK) {
Coord = coord;
}
Mark(MARK_DOWN);
}
// Object selection list is switched with player context for GlyphX. ST - 4/17/2019 9:42AM
extern void Logic_Switch_Player_Context(ObjectClass *object);
/***********************************************************************************************
* ObjectClass::Unselect -- This will un-select the object if it was selected. *
* *
* This routine brings a currently selected object into an unselected state. This is *
* needed when another object becomes selected as well as if the object is destroyed. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/19/1994 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Unselect(void)
{
assert(this != 0);
assert(IsActive);
//if (IsSelected) {
// Updated to function for multiplayer - 6/26/2019 JAS
if (Is_Selected_By_Player()) {
if (In_Which_Layer() == LAYER_GROUND) Mark(MARK_OVERLAP_UP);
IsSelected = false;
// Updated to function for multiplayer - 6/26/2019 JAS
Set_Unselected_By_Player();
if (In_Which_Layer() == LAYER_GROUND) Mark(MARK_OVERLAP_DOWN);
}
}
/***********************************************************************************************
* ObjectClass::Unselect_All_Players -- This will un-select the object if it was selected *
* from all players *
* *
* This routine brings a currently selected object into an unselected state for all players.*
* This is needed when the object is destroyed. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/25/2019 JAS : Created. *
*=============================================================================================*/
void ObjectClass::Unselect_All_Players(void)
{
CurrentObject.Delete_All(this);
if (In_Which_Layer() == LAYER_GROUND) {
Mark(MARK_OVERLAP_UP);
}
IsSelected = false;
IsSelectedMask = 0;
if (In_Which_Layer() == LAYER_GROUND) {
Mark(MARK_OVERLAP_DOWN);
}
}
/***********************************************************************************************
* ObjectClass::Unselect_All_Players_Except_Owner -- This will un-select the object if it was *
* selected for all players except for the object's owner *
* *
* This routine brings a currently selected object into an unselected state for all players.*
* This is needed when the object cloaks. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/28/2019 JAS : Created. *
*=============================================================================================*/
void ObjectClass::Unselect_All_Players_Except_Owner(void)
{
CurrentObject.Delete_All_Except(this, Owner());
if (In_Which_Layer() == LAYER_GROUND) {
Mark(MARK_OVERLAP_UP);
}
int owner_mask = 1 << Owner();
if (IsSelectedMask & owner_mask)
{
IsSelected = true;
IsSelectedMask = owner_mask;
}
else
{
IsSelected = false;
IsSelectedMask = 0;
}
if (In_Which_Layer() == LAYER_GROUND) {
Mark(MARK_OVERLAP_DOWN);
}
}
/***********************************************************************************************
* ObjectClass::Select -- Try to make this object the "selected" object. *
* *
* This routine is used to make this object into the one that is "selected". A selected *
* object usually displays a floating bar graph and is available to be given orders from *
* the player's I/O. *
* *
* INPUT: allow_mixed -- Allow a mix of player and non-player controlled units? *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/19/1994 JLB : Created. *
* 06/12/1995 JLB : Cannot select a loaner object. *
* 07/23/1995 JLB : Adds to head or tail depending on leader type flag. *
*=============================================================================================*/
bool ObjectClass::Select(bool allow_mixed)
{
assert(this != 0);
assert(IsActive);
//if (!Debug_Map && (IsSelected || !Class_Of().IsSelectable)) {
// return(false);
//}
// Updated to function for multiplayer - 6/26/2019 JAS
if (!Debug_Map && (Is_Selected_By_Player() || !Class_Of().IsSelectable)) {
return(false);
}
if (!Debug_Map && Can_Player_Move() && Is_Techno() && ((TechnoClass *)this)->IsALoaner) {
return(false);
}
/*
** Don't allow selection if the object is still in the air.
*/
if (Height > 0 && (What_Am_I() == RTTI_UNIT || What_Am_I() == RTTI_VESSEL || What_Am_I() == RTTI_INFANTRY)) {
return(false);
}
/*
** Don't allow selection of object when in building placement mode.
*/
if (Map.PendingObject) {
return(false);
}
if (!allow_mixed) {
/*
** If selecting an object of a different house than the player's, make sure that
** the entire selection list is cleared.
*/
for (int i = 0; i < CurrentObject.Count(); i++) {
HouseClass * tryhptr = HouseClass::As_Pointer(Owner());
HouseClass * oldhptr = HouseClass::As_Pointer(CurrentObject[i]->Owner());
// if (Owner() != CurrentObject[0]->Owner() || CurrentObject[0]->Owner() != PlayerPtr->Class->House) {
if (oldhptr->IsPlayerControl != tryhptr->IsPlayerControl) {
Unselect_All();
break;
}
}
}
if (In_Which_Layer() == LAYER_GROUND) Mark(MARK_OVERLAP_UP);
//IsSelected = true;
// Updated to function for multiplayer - 6/26/2019 JAS
Set_Selected_By_Player();
if (In_Which_Layer() == LAYER_GROUND) Mark(MARK_OVERLAP_DOWN);
return(true);
}
/***********************************************************************************************
* ObjectClass::Render -- Displays the object onto the map. *
* *
* This routine will determine the location of the object and if it is roughly on the *
* visible screen, it will display it. Not displaying objects that are not on the screen *
* will save valuable time. *
* *
* INPUT: bool; Should the render be forced regardless of whether the object is flagged to *
* be redrawn? *
* *
* OUTPUT: bool; Was the draw code called for this object? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/19/1994 JLB : Created. *
*=============================================================================================*/
bool ObjectClass::Render(bool forced) const
{
assert(this != 0);
assert(IsActive);
int x, y;
COORDINATE coord = Render_Coord();
CELL cell = Coord_Cell(coord);
if (Debug_Map || Debug_Unshroud || ((forced || IsToDisplay) && IsDown && !IsInLimbo)) {
const_cast<ObjectClass*>(this)->IsToDisplay = false; // added const_cast ST - 5/9/2019
if (Map.Coord_To_Pixel(coord, x, y)) {
/*
** Draw the object itself
*/
Draw_It(x, y, WINDOW_TACTICAL);
#ifdef SCENARIO_EDITOR
/*
** Draw the trigger attached to the object. Draw_It is window-
** relative, so add the window's x-coord to 'x'.
*/
if (Debug_Map && Trigger.Is_Valid()) {
Fancy_Text_Print(Trigger->Class->IniName,
x + (WinX), y,
&ColorRemaps[PCOLOR_RED], TBLACK,
TPF_CENTER | TPF_NOSHADOW | TPF_6POINT);
}
#endif
return(true);
}
}
return(false);
}
#ifdef CHEAT_KEYS
/***********************************************************************************************
* ObjectClass::Debug_Dump -- Displays status of the object class to the mono monitor. *
* *
* This routine is used to display the current status of the object class to the mono *
* monitor. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/02/1994 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Debug_Dump(MonoClass * mono) const
{
mono->Set_Cursor(1, 1);mono->Printf("%-18.18s", Text_String(Full_Name()));
if (Next != NULL) {
mono->Set_Cursor(20, 5);mono->Printf("%08X", Next->As_Target());
}
if (Trigger.Is_Valid()) {
mono->Text_Print(Trigger->Class->IniName, 11, 3);
}
mono->Set_Cursor(34, 1);mono->Printf("%3d", Strength);
mono->Fill_Attrib(1, 13, 12, 1, IsDown ? MonoClass::INVERSE : MonoClass::NORMAL);
mono->Fill_Attrib(1, 14, 12, 1, IsToDamage ? MonoClass::INVERSE : MonoClass::NORMAL);
mono->Fill_Attrib(1, 15, 12, 1, IsToDisplay ? MonoClass::INVERSE : MonoClass::NORMAL);
mono->Fill_Attrib(1, 16, 12, 1, IsInLimbo ? MonoClass::INVERSE : MonoClass::NORMAL);
// Updated to function for multiplayer - 6/26/2019 JAS
mono->Fill_Attrib(1, 17, 12, 1, Is_Selected_By_Player() ? MonoClass::INVERSE : MonoClass::NORMAL);
mono->Fill_Attrib(14, 13, 12, 1, IsAnimAttached ? MonoClass::INVERSE : MonoClass::NORMAL);
mono->Set_Cursor(23, 14);mono->Printf("%d", Riser);
mono->Fill_Attrib(14, 12, 14, 1, IsFalling ? MonoClass::INVERSE : MonoClass::NORMAL);
AbstractClass::Debug_Dump(mono);
}
#endif
/***********************************************************************************************
* ObjectClass::Mark_For_Redraw -- Marks object and system for redraw. *
* *
* This routine will mark the object and inform the display system *
* that appropriate rendering is needed. Whenever it is determined *
* that an object needs to be redrawn, call this routine. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: This is a subordinate function to the function Mark(). If an object needs to *
* be redrawn it is probably better to call the function Mark(MARK_CHANGE) rather *
* than this function. This function does not inform the map system that *
* overlapping objects are to be redrawn and thus unless you are really sure that *
* this routine should be called, don't. *
* *
* HISTORY: *
* 05/08/1994 JLB : Created. *
* 12/23/1994 JLB : Flags map and flags unit only. *
*=============================================================================================*/
void ObjectClass::Mark_For_Redraw(void)
{
assert(this != 0);
assert(IsActive);
if (!IsToDisplay) {
IsToDisplay = true;
/*
** This tells the map rendering logic to "go through the motions" and call the
** rendering function. In the rendering function, it will sort out what gets
** rendered and what doesn't.
*/
Map.Flag_To_Redraw(false);
}
}
/***********************************************************************************************
* ObjectClass::Limbo -- Brings the object into a state of limbo. *
* *
* An object brought into a state of limbo by this routine can be safely deleted. This *
* routine will remove the object from all game lists and tracking systems. It is called *
* prior to deleting the object or placing the object "on ice". *
* *
* INPUT: none *
* *
* OUTPUT: bool; Was the object successfully placed in limbo? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/24/1994 JLB : Created. *
*=============================================================================================*/
bool ObjectClass::Limbo(void)
{
assert(this != 0);
assert(IsActive);
if (GameActive && !IsInLimbo) {
//Unselect();
// Updated to function for multiplayer - 6/26/2019 JAS
Unselect_All_Players();
Detach_All();
Mark(MARK_UP);
/*
** Remove the object from the appropriate display list.
*/
Map.Remove(this, In_Which_Layer());
/*
** Remove the object from the logic processing list.
*/
if (Class_Of().IsSentient) {
Logic.Delete(this);
}
Hidden();
IsInLimbo = true;
IsToDisplay = false;
return(true);
}
return(false);
}
/***********************************************************************************************
* ObjectClass::Unlimbo -- Brings the object into the game system. *
* *
* This routine will place the object into the game tracking and display systems. It is *
* called as a consequence of creating the object. Every game object must be unlimboed at *
* some point. *
* *
* INPUT: coord -- The coordinate to place the object into the game system. *
* *
* dir (optional) -- initial facing direction for this object *
* *
* OUTPUT: bool; Was the game object successfully unlimboed? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/24/1994 JLB : Created. *
* 12/23/1994 JLB : Sets object strength. *
*=============================================================================================*/
bool ObjectClass::Unlimbo(COORDINATE coord, DirType )
{
assert(this != 0);
assert(IsActive);
if (GameActive && IsInLimbo && !IsDown) {
if (ScenarioInit || Can_Enter_Cell(Coord_Cell(coord), FACING_NONE) == MOVE_OK) {
IsInLimbo = false;
IsToDisplay = false;
Coord = Class_Of().Coord_Fixup(coord);
if (Mark(MARK_DOWN)) {
if (IsActive) {
/*
** Add the object to the appropriate map layer. This layer is used
** for rendering purposes.
*/
if (In_Which_Layer() != LAYER_NONE) {
Map.Submit(this, In_Which_Layer());
}
if (Class_Of().IsSentient) {
Logic.Submit(this);
}
}
return(true);
}
}
}
return(false);
}
/***********************************************************************************************
* ObjectClass::Detach -- Detach the specified target from this object. *
* *
* This routine is called when the object (as specified) is to be removed from the game *
* engine and thus, all references to it must be severed. Typically, the only thing *
* checked for at this level is the attached trigger. *
* *
* INPUT: target -- The target that will be removed from the game system. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/29/1996 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Detach(TARGET target, bool )
{
if (Trigger.Is_Valid() && Is_Target_Trigger(target) && Trigger->As_Target() == target) {
Attach_Trigger(NULL);
}
}
/***********************************************************************************************
* ObjectClass::Detach_All -- Removes the object from all tracking systems. *
* *
* This routine will take the object and see that it is removed from all miscellaneous *
* tracking systems in the game. This operation is vital when deleting an object. It is *
* necessary so that when the object is removed from the game, existing game objects won't *
* be referencing a now invalid game object. This typically affects the targeting *
* and navigation computers of other game objects. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/24/1994 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Detach_All(bool all)
{
assert(this != 0);
assert(IsActive);
/*
** Unselect this object if it was selected.
*/
//if (all || Owner() != PlayerPtr->Class->House) {
// Unselect();
//}
//Added some error handling incase there was an issue removing the object - JAS 6/28/2019
if (all) {
//Unselect();
// Updated to function for multiplayer - 6/28/2019 JAS
Unselect_All_Players();
}
else
{
Unselect_All_Players_Except_Owner();
}
//End of change - JAS 6/28/2019
Map.Detach(this);
/*
** Remove from targeting computers.
*/
Detach_This_From_All(As_Target(), all);
}
/***********************************************************************************************
* ObjectClass::Receive_Message -- Processes an incoming radio message. *
* *
* Any radio message received that applies to objects in general are handled by this *
* routine. Typically, this is the "redraw" message, which occurs when another object is *
* loading or unloading and thus overlapping. *
* *
* INPUT: message -- The message received. *
* *
* OUTPUT: Returns with the appropriate radio response. If the message was recognized, then *
* RADIO_ROGER is returned, otherwise, just RADIO_STATIC is returned. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/24/1994 JLB : Created. *
*=============================================================================================*/
RadioMessageType ObjectClass::Receive_Message(RadioClass *, RadioMessageType message, long & )
{
assert(this != 0);
assert(IsActive);
switch (message) {
/*
** This message serves as a rendering convenience. It lets the system
** know that there might be a visual conflict and the unit in radio
** contact should be redrawn. This typically occurs when a vehicle
** is being unloaded from a hover lander.
*/
case RADIO_REDRAW:
Mark(MARK_CHANGE);
return(RADIO_ROGER);
default:
break;
}
return(RADIO_STATIC);
}
/***********************************************************************************************
* ObjectClass::Take_Damage -- Applies damage to the object. *
* *
* This routine applies damage to the object according to the damage parameters. It handles *
* reducing the strength of the object and also returns the result of that damage. The *
* result value can be examined to determine if the object was destroyed, greatly damaged, *
* or other results. *
* *
* INPUT: damage -- Reference to the damage number to apply. This number will be adjusted *
* according to defensive armor and distance. Examine this value after *
* the call to determine the actual amount of damage applied. *
* *
* distance -- The distance (in leptons) from the center of the damage causing *
* explosion to the object itself. *
* *
* warhead -- The warhead type that is causing the damage. *
* *
* source -- The perpetrator of this damage. *
* *
* forced -- Is the damage forced upon the object regardless of whether it *
* is normally immune? *
* *
* OUTPUT: Returns the ResultType that indicates what the affect of the damage was. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/29/1994 JLB : Created. *
* 12/27/1994 JLB : Trigger event processing for attacked or destroyed. *
* 01/01/1995 JLB : Reduces damage greatly depending on range. *
*=============================================================================================*/
ResultType ObjectClass::Take_Damage(int & damage, int distance, WarheadType warhead, TechnoClass * source, bool forced)
{
assert(this != 0);
assert(IsActive);
ResultType result = RESULT_NONE;
int oldstrength = Strength;
if (oldstrength && damage != 0 && (forced || !Class_Of().IsImmune)) {
int maxstrength = Class_Of().MaxStrength;
/*
** Modify damage based on the warhead type and the armor of the object. This results
** in a reduced damage value, but never below 1 damage point. Unless
** it's forced damage, in which case we want full damage.
*/
if (!forced /*&& damage > 0*/) {
damage = Modify_Damage(damage, warhead, Class_Of().Armor, distance);
/*
** Special hack to ensure that dogs only do damage to intended victim and no
** damage to others.
*/
if (source && source->What_Am_I() == RTTI_INFANTRY && ((InfantryClass *)source)->Class->IsDog) {
if (source->TarCom == As_Target()) {
damage = Strength;
} else {
damage = 0;
}
}
}
if (damage == 0) return(RESULT_NONE);
/*
** Are we healing/repairing? If so, add strength, but in
** any case, return that no damage was done.
*/
if (damage < 0) {
#ifdef FIXIT_CSII // checked - ajw 9/28/98
if (What_Am_I() == RTTI_INFANTRY || What_Am_I() == RTTI_UNIT || What_Am_I() == RTTI_AIRCRAFT) {
#else
if (What_Am_I() == RTTI_INFANTRY) {
#endif
Clicked_As_Target(PlayerPtr->Class->House, 7); // 2019/09/20 JAS - Added record of who clicked on the object
Strength -= damage;
if (Strength > maxstrength) {
Strength = maxstrength;
}
}
return(RESULT_NONE);
}
/*
** At this point, we KNOW that at least light damage has occurred.
*/
result = RESULT_LIGHT;
/*
** A non-fatal blow has occurred. Check to see if the object transitioned to below
** half strength or if it is now down to one hit point.
*/
if (oldstrength > damage) {
if (oldstrength >= (maxstrength >> 1) && (oldstrength-damage) < (maxstrength >> 1)) {
result = RESULT_HALF;
}
} else {
/*
** When an object is damaged to destruction, it will instead stop at one
** damage point. This will prolong the damage state as well as
** give greater satisfaction when it is finally destroyed.
*/
damage = oldstrength;
}
/*
** Apply the damage to the object.
*/
Strength = oldstrength - damage;
/*
** Check to see if the object is majorly damaged or destroyed.
*/
switch (Strength) {
case 0:
Record_The_Kill(source);
result = RESULT_DESTROYED;
if (this->Is_Techno()) {
if (this == ::As_Object(((TechnoClass *)this)->House->UnitToTeleport)) ((TechnoClass *)this)->House->UnitToTeleport = 0;
}
Detach_All();
break;
case 1:
result = RESULT_MAJOR;
break;
default:
break;
}
/*
** Handle any trigger event associated with this object.
*/
if (source && Trigger.Is_Valid() && result != RESULT_DESTROYED) {
Trigger->Spring(TEVENT_ATTACKED, this);
}
/*
** If any damage was assessed and this object is selected, then flag
** the object to be redrawn so that the health bar will be updated.
*/
//if (result != RESULT_NONE && IsSelected) {
// Updated to function for multiplayer - 6/26/2019 JAS
if (result != RESULT_NONE && Is_Selected_By_Player()) {
Mark(MARK_CHANGE);
}
}
/*
** Return with the result of the damage taken.
*/
return(result);
}
/***********************************************************************************************
* ObjectClass::Mark -- Handles basic marking logic. *
* *
* This routine handles the base logic for marking an object up or down on the map. It *
* manages the IsDown flag as well as flagging the object to be redrawn if necessary. *
* Whenever an object is to be marked, it should call this base class function first. If *
* this function returns true, then the higher level function should proceed with its own *
* logic. *
* *
* INPUT: mark -- The marking method to use for this object. It can be either MARK_DOWN, *
* MARK_UP, or MARK_CHANGE. *
* *
* OUTPUT: bool; Was the object marked successfully? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/23/1995 JLB : Created. *
*=============================================================================================*/
bool ObjectClass::Mark(MarkType mark)
{
assert(this != 0);
assert(IsActive);
if (!IsInLimbo && IsActive) {
/*
** A mark for change is always successful UNLESS the object
** is not placed down or has already been flagged as changed
** this game frame.
*/
if (mark == MARK_CHANGE || mark == MARK_CHANGE_REDRAW) {
if (IsToDisplay && mark != MARK_CHANGE_REDRAW) return(false);
if (IsDown) {
Mark_For_Redraw();
return(true);
}
return(false);
}
/*
** Handle adding or removing the object in the cells' overlap lists
*/
if (mark == MARK_OVERLAP_UP) {
if (IsDown == true) {
if (Class_Of().IsFootprint) {
Map.Overlap_Up(Coord_Cell(Coord), this);
}
Mark_For_Redraw();
return(true);
}
}
if (mark == MARK_OVERLAP_DOWN) {
if (IsDown == true) {
if (Class_Of().IsFootprint) {
Map.Overlap_Down(Coord_Cell(Coord), this);
}
Mark_For_Redraw();
return(true);
}
}
/*
** It is important to know whether the object is a techno class
** or not to see if we have to adjust the regional threat ratings
*/
int threat = 0;
HousesType house = HOUSE_NONE;
CELL cell = 0;
TechnoClass * tech;
if (Is_Techno()) {
tech = (TechnoClass *)this;
threat = tech->Risk();
house = tech->Owner();
cell = Coord_Cell(Coord);
} else {
tech = NULL;
}
/*
** Marking down is only successful if the object isn't already
** placed down.
*/
if (mark == MARK_DOWN && !IsDown) {
if (tech && Session.Type == GAME_NORMAL && In_Which_Layer() == LAYER_GROUND) {
Map[cell].Adjust_Threat(house, threat);
}
IsDown = true;
Mark_For_Redraw();
return(true);
}
/*
** Lifting up is only successful if the object isn't already
** lifted up from the map.
*/
if (mark == MARK_UP && IsDown) {
if (tech && Session.Type == GAME_NORMAL && In_Which_Layer() == LAYER_GROUND) {
Map[cell].Adjust_Threat(house, -threat);
}
if (Class_Of().IsFootprint) {
Map.Overlap_Up(Coord_Cell(Coord), this);
}
IsDown = false;
return(true);
}
}
return(false);
}
/***********************************************************************************************
* ObjectClass::Init -- Initializes the basic object system. *
* *
* This routine should be called when the basic object system needs to be initialized. This *
* occurs when the scenario is about to be loaded. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/23/1995 JLB : Created. *
*=============================================================================================*/
void ObjectClass::Init(void)
{
CurrentObject.Clear_All();
}
/***********************************************************************************************
* ObjectClass::Revealed -- Reveals this object to the house specified. *
* *
* This routine is called when this object gets revealed to the house specified. *
* *
* INPUT: house -- Pointer to the house that this object is being revealed to. *
* *
* OUTPUT: Was this object revealed for the first time to this house? Generic objects always *
* return true unless an invalid house pointer was specified. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/19/1995 JLB : Created. *
*=============================================================================================*/
bool ObjectClass::Revealed(HouseClass * house)
{
assert(this != 0);
assert(IsActive);
return(house != NULL);
}
/***********************************************************************************************
* ObjectClass::Set_Selected_By_Player -- Set this object as selected by the given player or *
* the default player. *
* *
* INPUT: Player pointer *
* *
* OUTPUT: *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 6/25/2019 - JAS *
*=============================================================================================*/
void ObjectClass::Set_Selected_By_Player(HouseClass *player)
{
if (!player || !player->Class) {
player = PlayerPtr;
}
HousesType house = player->Class->House;
if (((TechnoTypeClass const &)Class_Of()).IsLeader) {
CurrentObject.Add_Head(house, this);
}
else {
CurrentObject.Add(house, this);
}
int shift = (int)house;
IsSelectedMask |= (1 << shift);
if (Session.Type == GAME_NORMAL && player == PlayerPtr) {
IsSelected = true;
}
}
/***********************************************************************************************
* ObjectClass::Set_Unselected_By_Player -- Set this object as unselected by the given player *
* orthe default player. *
* *
* INPUT: Player pointer *
* *
* OUTPUT: *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 6/25/2019 - JAS *
*=============================================================================================*/
void ObjectClass::Set_Unselected_By_Player(HouseClass *player)
{
if (!player || !player->Class) {
player = PlayerPtr;
}
HousesType house = player->Class->House;
CurrentObject.Delete(house, this);
int shift = (int)house;
IsSelectedMask &= ~(1 << shift);
if (Session.Type == GAME_NORMAL && player == PlayerPtr) {
IsSelected = false;
}
}
/***********************************************************************************************
* ObjectClass::Is_Selected_By_Player -- Has this object been selected by the given player *
* *
* INPUT: Player pointer *
* *
* OUTPUT: True if selected by that player *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 6/25/2019 - JAS *
*=============================================================================================*/
bool ObjectClass::Is_Selected_By_Player(HouseClass *player) const
{
if (player && player->Class) {
int shift = (int)player->Class->House;
return (IsSelectedMask & (1 << shift)) ? true : false;
}
else {
int shift = (int)PlayerPtr->Class->House;
return (IsSelectedMask & (1 << shift)) ? true : false;
}
return false;
}
/***********************************************************************************************
* ObjectClass::Paradrop -- Unlimbos object in paradrop mode. *
* *
* Call this routine as a replacement for Unlimbo() if the object is to be paradropped onto *
* the playing field. *
* *
* INPUT: coord -- The desired landing coordinate to give the dropping unit. *
* *
* OUTPUT: bool; Was the object successfully unlimboed and has begun paradropping? *
* *
* WARNINGS: The unit may not be successful in paradropping if the desired destination *
* location cannot be occupied by the object. *
* *
* HISTORY: *
* 02/07/1996 JLB : Created. *
*=============================================================================================*/
bool ObjectClass::Paradrop(COORDINATE coord)
{
assert(this != 0);
assert(IsActive);
Height = FLIGHT_LEVEL;
IsFalling = true;
if (Unlimbo(coord, DIR_S)) {
AnimClass * anim = NULL;
if (What_Am_I() == RTTI_BULLET) {
anim = new AnimClass(ANIM_PARA_BOMB, Coord_Move(Center_Coord(), DIR_N, 0x0030 + Height));
} else {
anim = new AnimClass(ANIM_PARACHUTE, Coord_Move(Center_Coord(), DIR_N, 0x0030 + Height));
}
/*
** If the animation was created, then attach it to this object.
*/
if (anim != NULL) {
anim->Attach_To(this);
}
return(true);
}
return(false);
}
/***********************************************************************************************
* ObjectClass::Attach_Trigger -- Attach specified trigger to object. *
* *
* This routine is used to attach the specified trigger to the object. *
* *
* INPUT: trigger -- Pointer to the trigger to attach. If any existing trigger is desired *
* to be detached, then pass NULL to this routine. *
* *
* OUTPUT: bool; Was the trigger attached? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/06/1996 JLB : Created. *
*=============================================================================================*/
bool ObjectClass::Attach_Trigger(TriggerClass * trigger)
{
if (Trigger.Is_Valid()) {
TriggerClass * tptr = Trigger;
tptr->AttachCount--;
Trigger = NULL;
}
if (trigger) {
Trigger = trigger;
trigger->AttachCount++;
return(true);
}
return(false);
}
// These can't be made inline (for various reasons).
short const * ObjectClass::Occupy_List(bool placement) const {return(Class_Of().Occupy_List(placement));};
short const * ObjectClass::Overlap_List(bool ) const {return(Class_Of().Overlap_List());};
BuildingClass * ObjectClass::Who_Can_Build_Me(bool intheory, bool legal) const {return(Class_Of().Who_Can_Build_Me(intheory, legal, Owner()));};
fixed ObjectClass::Health_Ratio(void) const {return(fixed(Strength, Class_Of().MaxStrength));};
int ObjectClass::Full_Name(void) const {return Class_Of().Full_Name();};
//**********************************************************************************************
// MODULE SEPARATION -- ObjectTypeClass member functions follow.
//**********************************************************************************************
/***********************************************************************************************
* ObjectTypeClass::ObjectTypeClass -- Normal constructor for object type class objects. *
* *
* This is the base constructor that is used when constructing the object type classes. *
* Every tangible game piece type calls this constructor for the ObjectTypeClass. This *
* class holds static information that is common to objects in general. *
* *
* INPUT: see below... *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 03/23/1995 JLB : Created. *
*=============================================================================================*/
ObjectTypeClass::ObjectTypeClass(
RTTIType rtti,
int id,
bool is_sentient,
bool is_stealthy,
bool is_selectable,
bool is_legal_target,
bool is_insignificant,
bool is_immune,
bool is_footprint,
int name,
char const * ini) :
AbstractTypeClass(rtti, id, name, ini),
IsCrushable(false),
IsStealthy(is_stealthy),
IsSelectable(is_selectable),
IsLegalTarget(is_legal_target),
IsInsignificant(is_insignificant),
IsImmune(is_immune),
IsSentient(is_sentient),
IsFootprint(is_footprint),
Armor(ARMOR_NONE),
MaxStrength(0),
ImageData(0),
RadarIcon(0)
{
/*
** Init the DimensionData rect. Not sure how this was ever working before without being allocated. It was just trashing
** memory later on when the pointer was being dereferenced and written to without being initialized. ST - 8/14/2019 3:15PM
*/
DimensionData = NULL;
}
/***********************************************************************************************
* ObjectTypeClass::Max_Pips -- Fetches the maximum pips allowed for this object. *
* *
* This routine will return the maximum number of pips that can be displayed for this *
* object. When dealing with generic objects, this value is always zero. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the number of pip boxes (empty or otherwise) to display. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/19/1995 JLB : Created. *
*=============================================================================================*/
int ObjectTypeClass::Max_Pips(void) const
{
return(0);
}
/***********************************************************************************************
* ObjectTypeClass::Dimensions -- Gets the dimensions of the object in pixels. *
* *
* This routine will fetch the dimensions of this object expressed as pixels width and *
* pixels height. This information can be used to intelligently update the clipping *
* rectangles. *
* *
* INPUT: width -- Reference to the width variable that will be filled in. *
* *
* height -- Reference to the height variable that will be filled in. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/19/1995 JLB : Created. *
*=============================================================================================*/
void ObjectTypeClass::Dimensions(int &width, int &height) const
{
width = 10;
height = 10;
}
/***********************************************************************************************
* ObjectTypeClass::Cost_Of -- Returns the cost to buy this unit. *
* *
* This routine will return the cost to purchase this unit. This routine is expected to be *
* overridden by the objects that can actually be purchased. All other object types can *
* simply return zero since this value won't be used. *
* *
* INPUT: none *
* *
* OUTPUT: Returns the cost of the object. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/19/1995 JLB : Created. *
*=============================================================================================*/
int ObjectTypeClass::Cost_Of(void) const
{
return(0);
}
/***********************************************************************************************
* ObjectTypeClass::Time_To_Build -- Fetches the time to construct this object. *
* *
* This routine will fetch the time in takes to construct this object. Objects that can *
* be constructed will override this routine in order to return a useful value. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the time units (arbitrary) that it takes to construct this object. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/19/1995 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 ObjectTypeClass::Time_To_Build(HousesType ) const
{
return(0);
}
/***********************************************************************************************
* ObjectTypeClass::Get_Cameo_Data -- Fetches pointer to cameo data for this object type. *
* *
* This routine will return with the cameo data pointer for this object type. It is *
* expected that objects that can appear on the sidebar will override this routine in order *
* to provide proper cameo data pointer. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with a pointer to the cameo shape data. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/19/1995 JLB : Created. *
*=============================================================================================*/
void const * ObjectTypeClass::Get_Cameo_Data(void) const
{
return(NULL);
}
/***********************************************************************************************
* ObjectTypeClass::Occupy_List -- Returns with simple occupation list for object. *
* *
* This routine returns a pointer to a simple occupation list for this object. Since at *
* this tier of the object class chain, the exact shape of the object is indeterminate, *
* this function merely returns a single cell occupation list. This actually works for *
* most vehicles. *
* *
* INPUT: none *
* *
* OUTPUT: Returns a pointer to a simple occupation list. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/28/1994 JLB : Created. *
*=============================================================================================*/
short const * ObjectTypeClass::Occupy_List(bool) const
{
static short const _list[] = {0, REFRESH_EOL};
return(_list);
}
/***********************************************************************************************
* ObjectTypeClass::Overlap_List -- Returns a pointer to a simple overlap list. *
* *
* This function returns a pointer to an overlap list for the object. An overlap list is *
* the offsets from the object's cell to get the cells the imagery overlaps, but is object *
* is not considered to occupy. Since at this stage, the overlap information is not *
* available, this function merely returns a pointer to an empty list. *
* *
* INPUT: none *
* *
* OUTPUT: Returns a pointer to the generic overlap list. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/28/1994 JLB : Created. *
*=============================================================================================*/
short const * ObjectTypeClass::Overlap_List(void) const
{
static short const _list[] = {REFRESH_EOL};
return(_list);
}
/***********************************************************************************************
* ObjectTypeClass::One_Time -- Handles one time processing for object types. *
* *
* This routine is used to handle the once per game processing required for object types. *
* This consists of loading any data and initializing any data tables the game requires. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: This routine goes to disk. *
* *
* HISTORY: *
* 11/01/1994 JLB : Created. *
*=============================================================================================*/
void ObjectTypeClass::One_Time(void)
{
SelectShapes = MFCD::Retrieve("SELECT.SHP");
#ifndef NDEBUG
RawFileClass file("PIPS.SHP");
if (file.Is_Available()) {
PipShapes = Load_Alloc_Data(file);
} else {
PipShapes = MFCD::Retrieve("PIPS.SHP");
}
#else
PipShapes = MFCD::Retrieve("PIPS.SHP");
#endif
}
/***********************************************************************************************
* ObjectTypeClass::Who_Can_Build_Me -- Determine what building can build this object type. *
* *
* This routine will scan through all available factory buildings and determine which *
* is capable of building this object type. The scan can be controlled to scan for only *
* factory buildings that are free to produce now or those that could produce this *
* object type if conditions permit. *
* *
* INPUT: intheory -- Should the general (when conditions permit) case be examined to see *
* if a building could build this object type "in theory" even though it *
* might currently be otherwise occupied? *
* *
* legal -- Check for building prerequisite and technology level rules? Usually *
* this would be 'true' for human controlled requests and 'false' for *
* the computer. This is because the computer is usually not under *
* the normal restrictions that the player is under. *
* *
* OUTPUT: Returns with a pointer to the building that can produce the object of this *
* type. If no suitable factory building could be found, then NULL is returned. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/29/1996 JLB : Created. *
*=============================================================================================*/
BuildingClass * ObjectTypeClass::Who_Can_Build_Me(bool intheory, bool legal, HousesType house) const
{
BuildingClass * anybuilding = NULL;
if (!intheory && What_Am_I() == RTTI_AIRCRAFTTYPE && ((AircraftTypeClass*)this)->IsFixedWing) {
int num_builders = 0, num_fixed_wings = 0;
for (int index = 0; index < Buildings.Count(); index++) {
BuildingClass * building = Buildings.Ptr(index);
assert(building != NULL);
if ( !building->IsInLimbo &&
building->House->Class->House == house &&
building->Class->ToBuild == RTTI &&
building->Mission != MISSION_DECONSTRUCTION && building->MissionQueue != MISSION_DECONSTRUCTION &&
((1L << building->ActLike) & Get_Ownable()) &&
(!legal || building->House->Can_Build(this, building->ActLike))) {
num_builders++;
}
}
for (int index = 0; index < Aircraft.Count(); index++) {
AircraftClass * aircraft = Aircraft.Ptr(index);
assert(aircraft != NULL);
if ( !aircraft->IsInLimbo &&
aircraft->House->Class->House == house &&
aircraft->Class->IsFixedWing) {
num_fixed_wings++;
}
}
if (num_fixed_wings >= num_builders) {
return NULL;
}
}
for (int index = 0; index < Buildings.Count(); index++) {
BuildingClass * building = Buildings.Ptr(index);
assert(building != NULL);
if ( !building->IsInLimbo &&
building->House->Class->House == house &&
building->Class->ToBuild == RTTI &&
building->Mission != MISSION_DECONSTRUCTION && building->MissionQueue != MISSION_DECONSTRUCTION &&
((1L << building->ActLike) & Get_Ownable()) &&
(!legal || building->House->Can_Build(this, building->ActLike)) &&
(intheory || !building->In_Radio_Contact())) {
// BG: Hack so only kennels can build dogs, and no other, and barracks can
// only build humans and no other.
if (What_Am_I() == RTTI_INFANTRYTYPE) {
InfantryTypeClass * me = (InfantryTypeClass *)this;
if (me->IsDog) {
if (*building == STRUCT_KENNEL) {
if (building->IsLeader) return(building);
anybuilding = building;
}
} else {
if (*building != STRUCT_KENNEL) {
if (building->IsLeader) return(building);
anybuilding = building;
}
}
} else {
/*
** HACK ALERT: Helipads can build aircraft and airstrips can build
** fixed wing craft only.
*/
if (What_Am_I() == RTTI_AIRCRAFTTYPE) {
AircraftTypeClass * air = (AircraftTypeClass *)this;
if ((*building == STRUCT_HELIPAD && !air->IsFixedWing) || (*building == STRUCT_AIRSTRIP && air->IsFixedWing)) {
if (building->IsLeader) return(building);
anybuilding = building;
}
} else {
if (building->IsLeader) return(building);
anybuilding = building;
}
}
}
}
return(anybuilding);
}