2020-05-27 20:16:20 +01:00
//
// 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\house.cpv 2.13 02 Aug 1995 17:03:50 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 : HOUSE . CPP *
* *
* Programmer : Joe L . Bostic *
* *
* Start Date : May 21 , 1994 *
* *
* Last Update : August 12 , 1995 [ JLB ] *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *
* Functions : *
* HouseClass : : AI - - Process house logic . *
* HouseClass : : Abandon_Production - - Abandons production of item type specified . *
* HouseClass : : Add_Nuke_Piece - - Add a nuclear piece to the collection . *
* HouseClass : : Adjust_Capacity - - Adjusts the house Tiberium storage capacity . *
* HouseClass : : Adjust_Threat - - Adjust threat for the region specified . *
* HouseClass : : As_Pointer - - Converts a house number into a house object pointer . *
* HouseClass : : Assign_Handicap - - Assigns the specified handicap rating to the house . *
* HouseClass : : Attacked - - Lets player know if base is under attack . *
* HouseClass : : Available_Money - - Fetches the total credit worth of the house . *
* HouseClass : : Begin_Production - - Starts production of the specified object type . *
* HouseClass : : Blowup_All - - blows up everything *
* HouseClass : : Can_Build - - Determines if the aircraft type can be built . *
* HouseClass : : Can_Build - - Determines if the building type can be built . *
* HouseClass : : Can_Build - - Determines if the infantry unit can be built by this house . *
* HouseClass : : Can_Build - - Determines if the unit can be built by this house . *
* HouseClass : : Can_Build - - General purpose build legality checker . *
* HouseClass : : Clobber_All - - removes house & all its objects *
* HouseClass : : Debug_Dump - - Dumps the house status data to the mono screen . *
* HouseClass : : Detach - - Removes specified object from house tracking systems . *
* HouseClass : : Does_Enemy_Building_Exist - - Checks for enemy building of specified type . *
* HouseClass : : Flag_Attach - - Attach flag to specified cell ( or thereabouts ) . *
* HouseClass : : Flag_Attach - - Attaches the house flag the specified unit . *
* HouseClass : : Flag_Remove - - Removes the flag from the specified target . *
* HouseClass : : Flag_To_Die - - Flags the house to blow up soon . *
* HouseClass : : Flag_To_Lose - - Flags the house to die soon . *
* HouseClass : : Flag_To_Win - - Flags the house to win soon . *
* HouseClass : : Harvested - - Adds Tiberium to the harvest storage . *
* HouseClass : : Has_Nuke_Device - - Deteremines if the house has a nuclear device . *
* HouseClass : : HouseClass - - Constructor for a house object . *
* HouseClass : : Init - - init ' s in preparation for new scenario *
* HouseClass : : Init_Air_Strike - - Add ( or reset ) the air strike sidebar button . *
* HouseClass : : Init_Data - - Initializes the multiplayer color data . *
* HouseClass : : Init_Ion_Cannon - - Initialize the ion cannon countdown . *
* HouseClass : : Init_Nuke_Bomb - - Adds ( if necessary ) the atom bomb to the sidebar . *
* HouseClass : : Is_Ally - - Checks to see if the object is an ally . *
* HouseClass : : Is_Ally - - Determines if the specified house is an ally . *
* HouseClass : : Is_Ally - - Determines if the specified house is an ally . *
* HouseClass : : MPlayer_Defeated - - multiplayer ; house is defeated *
* HouseClass : : Make_Air_Strike_Available - - Make the airstrike available . *
* HouseClass : : Make_Ally - - Make the specified house an ally . *
* HouseClass : : Make_Enemy - - Make an enemy of the house specified . *
* HouseClass : : Manual_Place - - Inform display system of building placement mode . *
* HouseClass : : One_Time - - Handles one time initialization of the house array . *
* HouseClass : : Place_Object - - Places the object ( building ) at location specified . *
* HouseClass : : Place_Special_Blast - - Place a special blast effect at location specified . *
* HouseClass : : Power_Fraction - - Fetches the current power output rating . *
* HouseClass : : Read_INI - - Reads house specific data from INI . *
* HouseClass : : Refund_Money - - Refunds money to back to the house . *
* HouseClass : : Remap_Table - - Fetches the remap table for this house object . *
* HouseClass : : Remove_Air_Strike - - Removes the air strike button from the sidebar . *
* HouseClass : : Remove_Ion_Cannon - - Disables the ion cannon . *
* HouseClass : : Remove_Nuke_Bomb - - Removes the nuclear bomb from the sidebar . *
* HouseClass : : Sell_Wall - - Tries to sell the wall at the specified location . *
* HouseClass : : Silo_Redraw_Check - - Flags silos to be redrawn if necessary . *
* HouseClass : : Special_Weapon_AI - - Fires special weapon . *
* HouseClass : : Spend_Money - - Removes money from the house . *
* HouseClass : : Suggest_New_Object - - Determine what would the next buildable object be . *
* HouseClass : : Suggested_New_Team - - Determine what team should be created . *
* HouseClass : : Suspend_Production - - Temporarily puts production on hold . *
* HouseClass : : Validate - - validates house pointer *
* HouseClass : : Write_INI - - Writes house specific data into INI file . *
* HouseClass : : delete - - Deallocator function for a house object . *
* HouseClass : : new - - Allocator for a house class . *
* HouseClass : : operator HousesType - - Conversion to HousesType operator . *
* HouseClass : : ~ HouseClass - - Default destructor for a house object . *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
# include "function.h"
/*
* * New sidebar for GlyphX multiplayer . ST - 3 / 26 / 2019 12 : 24 PM
*/
# include "SidebarGlyphx.h"
# include "defines.h"
/***********************************************************************************************
* HouseClass : : Validate - - validates house pointer *
* *
* INPUT : *
* none . *
* *
* OUTPUT : *
* 1 = ok , 0 = error *
* *
* WARNINGS : *
* none . *
* *
* HISTORY : *
* 08 / 09 / 1995 BRR : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# ifdef CHEAT_KEYS
int HouseClass : : Validate ( void ) const
{
int num ;
num = Houses . ID ( this ) ;
if ( num < 0 | | num > = HOUSE_MAX ) {
Validate_Error ( " HOUSE " ) ;
return ( 0 ) ;
}
else
return ( 1 ) ;
}
# else
# define Validate()
# endif
/***********************************************************************************************
* HouseClass : : operator HousesType - - Conversion to HousesType operator . *
* *
* This operator will automatically convert from a houses class object into the HousesType *
* enumerated value . *
* *
* INPUT : none *
* *
* OUTPUT : Returns with the object ' s HousesType value . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 01 / 23 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
HouseClass : : operator HousesType ( void ) const
{
Validate ( ) ;
return ( Class - > House ) ;
}
/***********************************************************************************************
* HouseClass : : As_Pointer - - Converts a house number into a house object pointer . *
* *
* Use this routine to convert a house number into the house pointer that it represents . *
* A simple index into the Houses template array is not sufficient , since the array order *
* is arbitrary . An actual scan through the house object is required in order to find the *
* house object desired . *
* *
* INPUT : house - - The house type number to look up . *
* *
* OUTPUT : Returns with a pointer to the house object that the house number represents . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 01 / 23 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
HouseClass * HouseClass : : As_Pointer ( HousesType house )
{
for ( int index = 0 ; index < Houses . Count ( ) ; index + + ) {
if ( Houses . Ptr ( index ) - > Class - > House = = house ) {
return ( Houses . Ptr ( index ) ) ;
}
}
return ( 0 ) ;
}
/***********************************************************************************************
* HouseClass : : One_Time - - Handles one time initialization of the house array . *
* *
* This basically calls the constructor for each of the houses in the game . All other *
* data specific to the house is initialized when the scenario is loaded . *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : Only call this ONCE at the beginning of the game . *
* *
* HISTORY : *
* 12 / 09 / 1994 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : One_Time ( void )
{
// for (HousesType index = HOUSE_FIRST; index < HOUSE_COUNT; index++) {
// new(index) HouseClass;
// }
# ifdef USE_RA_AI
/*
* * Required for Red Alert AI . ST - 7 / 23 / 2019 3 : 21 PM
*/
BuildChoice . Set_Heap ( STRUCT_COUNT ) ;
# endif
}
/***********************************************************************************************
* HouseClass : : Assign_Handicap - - Assigns the specified handicap rating to the house . *
* *
* The handicap rating will affect combat , movement , and production for the house . It can *
* either make it more or less difficult for the house ( controlled by the handicap value ) . *
* *
* INPUT : handicap - - The handicap value to assign to this house . The default value for *
* a house is DIFF_NORMAL . *
* *
* OUTPUT : Returns with the old handicap value . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 07 / 09 / 1996 JLB : Created . *
* 10 / 22 / 1996 JLB : Uses act like value for multiplay only . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
DiffType HouseClass : : Assign_Handicap ( DiffType handicap )
{
DiffType old = Difficulty ;
Difficulty = handicap ;
if ( GameToPlay ! = GAME_NORMAL ) {
HouseTypeClass const * hptr = & HouseTypeClass : : As_Reference ( ActLike ) ;
FirepowerBias = hptr - > FirepowerBias * Rule . Diff [ handicap ] . FirepowerBias ;
GroundspeedBias = hptr - > GroundspeedBias * Rule . Diff [ handicap ] . GroundspeedBias ;
AirspeedBias = hptr - > AirspeedBias * Rule . Diff [ handicap ] . AirspeedBias ;
ArmorBias = hptr - > ArmorBias * Rule . Diff [ handicap ] . ArmorBias ;
ROFBias = hptr - > ROFBias * Rule . Diff [ handicap ] . ROFBias ;
CostBias = hptr - > CostBias * Rule . Diff [ handicap ] . CostBias ;
RepairDelay = Rule . Diff [ handicap ] . RepairDelay ;
BuildDelay = Rule . Diff [ handicap ] . BuildDelay ;
BuildSpeedBias = hptr - > BuildSpeedBias * Rule . Diff [ handicap ] . BuildSpeedBias ;
} else {
FirepowerBias = Rule . Diff [ handicap ] . FirepowerBias ;
GroundspeedBias = Rule . Diff [ handicap ] . GroundspeedBias ;
AirspeedBias = Rule . Diff [ handicap ] . AirspeedBias ;
ArmorBias = Rule . Diff [ handicap ] . ArmorBias ;
ROFBias = Rule . Diff [ handicap ] . ROFBias ;
CostBias = Rule . Diff [ handicap ] . CostBias ;
RepairDelay = Rule . Diff [ handicap ] . RepairDelay ;
BuildDelay = Rule . Diff [ handicap ] . BuildDelay ;
BuildSpeedBias = Rule . Diff [ handicap ] . BuildSpeedBias ;
}
return ( old ) ;
}
# ifdef CHEAT_KEYS
/***********************************************************************************************
* HouseClass : : Debug_Dump - - Dumps the house status data to the mono screen . *
* *
* This utility function will output the current status of the house class to the mono *
* screen . Through this information bugs may be fixed or detected . *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 31 / 1994 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Debug_Dump ( MonoClass * ) const
{
Validate ( ) ;
}
# endif
/***********************************************************************************************
* HouseClass : : new - - Allocator for a house class . *
* *
* This is the allocator for a house class . Since there can be only *
* one of each type of house , this is allocator has restricted *
* functionality . Any attempt to allocate a house structure for a *
* house that already exists , just returns a pointer to the previously *
* allocated house . *
* *
* INPUT : house - - The house to allocate a class object for . *
* *
* OUTPUT : Returns with a pointer to the allocated class object . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 22 / 1994 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void * HouseClass : : operator new ( size_t )
{
void * ptr = Houses . Allocate ( ) ;
if ( ptr ) {
( ( HouseClass * ) ptr ) - > IsActive = true ;
}
return ( ptr ) ;
}
/***********************************************************************************************
* HouseClass : : delete - - Deallocator function for a house object . *
* *
* This function marks the house object as " deallocated " . Such a *
* house object is available for reallocation later . *
* *
* INPUT : ptr - - Pointer to the house object to deallocate . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 22 / 1994 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : operator delete ( void * ptr )
{
if ( ptr ) {
( ( HouseClass * ) ptr ) - > IsActive = false ;
}
Houses . Free ( ( HouseClass * ) ptr ) ;
}
/***********************************************************************************************
* HouseClass : : HouseClass - - Constructor for a house object . *
* *
* This function is the constructor and it marks the house object *
* as being allocated . *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 22 / 1994 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
HouseClass : : HouseClass ( HousesType house ) :
Class ( & HouseTypeClass : : As_Reference ( house ) ) ,
IonCannon ( ION_CANNON_GONE_TIME , VOX_ION_READY , VOX_ION_CHARGING , VOX_ION_CHARGING , VOX_NO_POWER ) ,
AirStrike ( AIR_CANNON_GONE_TIME , VOX_AIRSTRIKE_READY , VOX_NONE , VOX_NOT_READY , VOX_NOT_READY ) ,
NukeStrike ( NUKE_GONE_TIME , VOX_NUKE_AVAILABLE , VOX_NONE , VOX_NOT_READY , VOX_NO_POWER )
{
for ( HousesType i = HOUSE_FIRST ; i < HOUSE_COUNT ; i + + ) {
UnitsKilled [ i ] = 0 ;
BuildingsKilled [ i ] = 0 ;
}
WhoLastHurtMe = house ; // init this to myself
IsVisionary = false ;
IsFreeHarvester = false ;
Blockage = 0 ;
UnitsLost = 0 ;
BuildingsLost = 0 ;
NewActiveBScan = 0 ;
ActiveBScan = 0 ;
NewActiveUScan = 0 ;
ActiveUScan = 0 ;
NewActiveIScan = 0 ;
ActiveIScan = 0 ;
NewActiveAScan = 0 ;
ActiveAScan = 0 ;
strcpy ( ( char * ) Name , " Computer " ) ; // Default computer name.
JustBuilt = STRUCT_NONE ;
AlertTime = 0 ;
IsAlerted = false ;
IsAirstrikePending = false ;
AircraftFactory = - 1 ;
AircraftFactories = 0 ;
ActLike = Class - > House ;
Allies = 0 ;
AScan = 0 ;
NukeDest = 0 ;
BlitzTime . Clear ( ) ;
ScreenShakeTime . Clear ( ) ;
BScan = 0 ;
BuildingFactories = 0 ;
BuildingFactory = - 1 ;
Capacity = 0 ;
Credits = 0 ;
CreditsSpent = 0 ;
CurBuildings = 0 ;
CurUnits = 0 ;
DamageTime = DAMAGE_DELAY ;
Drain = 0 ;
Edge = SOURCE_NORTH ;
FlagHome = 0 ;
FlagLocation = TARGET_NONE ;
HarvestedCredits = 0 ;
HouseTriggers [ house ] . Clear ( ) ;
IGaveUp = false ;
InfantryFactories = 0 ;
InfantryFactory = - 1 ;
InitialCredits = 0 ;
InitialCredits = 0 ;
IScan = 0 ;
IsRecalcNeeded = true ;
IsCivEvacuated = false ;
IsDefeated = false ;
IsDiscovered = false ;
IsHuman = false ;
WasHuman = false ;
IsMaxedOut = false ;
IsStarted = false ;
IsToDie = false ;
IsToLose = false ;
IsToWin = false ;
Make_Ally ( house ) ;
MaxBuilding = 0 ;
MaxUnit = 0 ;
NewAScan = 0 ;
NewBScan = 0 ;
NewIScan = 0 ;
NewUScan = 0 ;
NukePieces = 0x07 ;
Power = 0 ;
Radar = RADAR_NONE ;
RemapTable = Class - > RemapTable ;
RemapColor = Class - > RemapColor ;
Resigned = false ;
SpeakAttackDelay = 1 ;
SpeakMaxedDelay = 1 ;
SpeakMoneyDelay = 1 ;
SpeakMoneyDelay . Set ( Options . Normalize_Delay ( SPEAK_DELAY ) ) ; // 2 minutes
SpeakPowerDelay = 1 ;
SpecialFactories = 0 ;
SpecialFactory = - 1 ;
TeamTime = TEAM_DELAY ;
Tiberium = 0 ;
TriggerTime = 0 ;
UnitFactories = 0 ;
UnitFactory = - 1 ;
UScan = 0 ;
memset ( ( void * ) & Regions [ 0 ] , 0x00 , sizeof ( Regions ) ) ;
Init_Unit_Trackers ( ) ;
DebugUnlockBuildables = false ;
StartLocationOverride = - 1 ;
/*
* * New AI variables from RA . Need to add to save / load ?
*/
# ifdef USE_RA_AI
IsBaseBuilding = true ;
Center = 0 ;
Radius = 0 ;
for ( ZoneType zone = ZONE_FIRST ; zone < ZONE_COUNT ; zone + + ) {
ZoneInfo [ zone ] . AirDefense = 0 ;
ZoneInfo [ zone ] . ArmorDefense = 0 ;
ZoneInfo [ zone ] . InfantryDefense = 0 ;
}
LATime = 0 ;
LAType = RTTI_NONE ;
LAZone = ZONE_NONE ;
LAEnemy = HOUSE_NONE ;
ToCapture = TARGET_NONE ;
RadarSpied = 0 ;
PointTotal = 0 ;
memset ( BQuantity , ' \0 ' , sizeof ( BQuantity ) ) ;
memset ( UQuantity , ' \0 ' , sizeof ( UQuantity ) ) ;
memset ( IQuantity , ' \0 ' , sizeof ( IQuantity ) ) ;
memset ( AQuantity , ' \0 ' , sizeof ( AQuantity ) ) ;
Attack = 0 ;
Enemy = HOUSE_NONE ;
AITimer = 0 ;
BuildStructure = STRUCT_NONE ;
BuildUnit = UNIT_NONE ;
BuildInfantry = INFANTRY_NONE ;
BuildAircraft = AIRCRAFT_NONE ;
State = STATE_BUILDUP ;
IsTiberiumShort = false ;
IQ = Rule . MaxIQ ;
IsParanoid = false ;
OldBScan = 0 ;
Assign_Handicap ( DIFF_NORMAL ) ;
# endif
}
HouseClass : : ~ HouseClass ( void )
{
Free_Unit_Trackers ( ) ;
}
/***********************************************************************************************
* HouseClass : : Can_Build - - General purpose build legality checker . *
* *
* This routine is called when it needs to be determined if the specified object type can *
* be built by this house . Production and sidebar maintenance use this routine heavily . *
* *
* INPUT : type - - Pointer to the type of object that legality is to be checked for . *
* *
* house - - This is the house to check for legality against . Note that this might *
* not be ' this ' house since the check could be from a captured factory . *
* Captured factories build what the original owner of them could build . *
* *
* OUTPUT : Can the specified object be built ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 07 / 04 / 1995 JLB : Created . *
* 08 / 12 / 1995 JLB : Updated for GDI building sandbag walls in # 9. *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Can_Build ( TechnoTypeClass const * type , HousesType house ) const
{
Validate ( ) ;
if ( ! type | | ! type - > IsBuildable | | ! ( ( 1L < < house ) & type - > Ownable ) ) return ( false ) ;
/*
* * The computer can always build everthing .
*/
# ifdef USE_RA_AI
if ( ! IsHuman & & GameToPlay = = GAME_NORMAL ) return ( true ) ; // Added game type check for AI from RA. ST - 7/25/2019 3:25PM
# else
if ( ! IsHuman ) return ( true ) ;
# endif
/*
* * Perform some equivalency fixups for the building existance flags .
*/
long flags = ActiveBScan ;
/*
2020-08-06 17:44:54 +01:00
* * AI players update flags using building quantity tracker .
* * Ensures consistent logic when determining building choices .
2020-05-27 20:16:20 +01:00
*/
if ( ! IsHuman ) {
2020-08-06 17:44:54 +01:00
flags = 0 ;
for ( int i = 0 ; i < 32 ; i + + ) {
if ( BQuantity [ i ] > 0 ) {
flags | = ( 1 < < i ) ;
}
}
2020-05-27 20:16:20 +01:00
}
int pre = type - > Pre ;
if ( flags & STRUCTF_ADVANCED_POWER ) flags | = STRUCTF_POWER ;
if ( flags & STRUCTF_HAND ) flags | = STRUCTF_BARRACKS ;
if ( flags & STRUCTF_OBELISK ) flags | = STRUCTF_ATOWER ;
if ( flags & STRUCTF_TEMPLE ) flags | = STRUCTF_EYE ;
if ( flags & STRUCTF_AIRSTRIP ) flags | = STRUCTF_WEAP ;
if ( flags & STRUCTF_SAM ) flags | = STRUCTF_HELIPAD ;
/*
* * Multiplayer game uses a different legality check for building .
*/
if ( GameToPlay ! = GAME_NORMAL | | ( Special . IsJurassic & & AreThingiesEnabled ) ) {
if ( DebugUnlockBuildables ) {
return true ;
}
return ( ( pre & flags ) = = pre & & type - > Level < = BuildLevel ) ;
}
# ifdef NEWMENU
int level = BuildLevel ;
# else
int level = Scenario ;
# endif
/*
* * Special check to make the mission objective buildings the prerequisite
* * for the stealth tank in mission # 11 only .
*/
if ( house = = HOUSE_BAD & &
type - > What_Am_I ( ) = = RTTI_UNITTYPE & &
( ( UnitTypeClass const * ) type ) - > Type = = UNIT_STANK & &
level = = 11 ) {
pre = STRUCTF_MISSION ;
level = type - > Scenario ;
}
/*
* * Special case check to ensure that GDI doesn ' t get the bazooka guy
* * until mission # 8.
*/
if ( house = = HOUSE_GOOD & &
type - > What_Am_I ( ) = = RTTI_INFANTRYTYPE & &
( ( InfantryTypeClass const * ) type ) - > Type = = INFANTRY_E3 & &
level < 7 ) {
return ( false ) ;
}
/*
* * Special check to allow GDI to build the MSAM by mission # 9
* * and no sooner .
*/
if ( house = = HOUSE_GOOD & &
type - > What_Am_I ( ) = = RTTI_UNITTYPE & &
( ( UnitTypeClass const * ) type ) - > Type = = UNIT_MLRS & &
level < 9 ) {
return ( false ) ;
}
/*
* * Special case to disable the APC from the Nod player .
*/
if ( house = = HOUSE_BAD & &
type - > What_Am_I ( ) = = RTTI_UNITTYPE & &
( ( UnitTypeClass const * ) type ) - > Type = = UNIT_APC ) {
return ( false ) ;
}
/*
* * Ensure that the Temple of Nod cannot be built by GDI even
* * if GDI has captured the Nod construction yard .
*/
if ( type - > What_Am_I ( ) = = RTTI_BUILDINGTYPE & &
( ( ( BuildingTypeClass const * ) type ) - > Type = = STRUCT_TEMPLE | | ( ( BuildingTypeClass const * ) type ) - > Type = = STRUCT_OBELISK ) & &
Class - > House = = HOUSE_GOOD ) {
return ( false ) ;
}
/*
* * Ensure that the rocket launcher tank cannot be built by Nod .
*/
if ( type - > What_Am_I ( ) = = RTTI_UNITTYPE & &
( ( UnitTypeClass const * ) type ) - > Type = = UNIT_MLRS & &
Class - > House = = HOUSE_BAD ) {
return ( false ) ;
}
/*
* * Ensure that the ion cannon cannot be built if
* * Nod has captured the GDI construction yard .
*/
if ( type - > What_Am_I ( ) = = RTTI_BUILDINGTYPE & &
( ( ( BuildingTypeClass const * ) type ) - > Type = = STRUCT_EYE ) & &
Class - > House = = HOUSE_BAD ) {
return ( false ) ;
}
/*
* * Nod can build the advanced power plant at scenario # 12.
*/
if ( house = = HOUSE_BAD & &
level > = 12 & &
type - > What_Am_I ( ) = = RTTI_BUILDINGTYPE & &
( ( BuildingTypeClass const * ) type ) - > Type = = STRUCT_ADVANCED_POWER ) {
level = type - > Scenario ;
}
/*
* * Nod cannot build a helipad in the normal game .
*/
if ( house = = HOUSE_BAD & &
type - > What_Am_I ( ) = = RTTI_BUILDINGTYPE & &
( ( BuildingTypeClass const * ) type ) - > Type = = STRUCT_HELIPAD ) {
return ( false ) ;
}
/*
* * GDI can build the sandbag wall only from scenario # 9 onwards .
*/
if ( house = = HOUSE_GOOD & &
level < 8 & &
type - > What_Am_I ( ) = = RTTI_BUILDINGTYPE & &
( ( BuildingTypeClass const * ) type ) - > Type = = STRUCT_SANDBAG_WALL ) {
return ( false ) ;
}
/*
* * GDI has a special second training mission . Adjust the scenario level so that
* * scenario two will still feel like scenario # 1.
*/
if ( house = = HOUSE_GOOD & & level = = 2 ) {
level = 1 ;
}
// ST - 8/23/2019 4:53PM
if ( DebugUnlockBuildables ) {
level = 98 ;
pre = 0 ;
}
if ( Debug_Cheat ) level = 98 ;
return ( ( pre & flags ) = = pre & & type - > Scenario < = level ) ;
}
/***********************************************************************************************
* HouseClass : : Can_Build - - Determines if the building type can be built . *
* *
* This routine is used by the construction preparation code to building a list of building *
* types that can be built . It determines if a building can be built by checking if the *
* prerequisite buildings have been built ( and still exist ) as well as checking to see if *
* the house can build the specified structure . *
* *
* INPUT : s - - The structure type number that is being checked . *
* *
* house - - The house number to use when determining if the object can be built . *
* This is necessary because the current owner of the factory doesn ' t *
* control what the factory can produce . Rather , the original builder of *
* the factory controls this . *
* *
* OUTPUT : bool ; Can this structure type be built at this time ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 06 / 08 / 1994 JLB : Created . *
* 05 / 31 / 1995 JLB : Handles specified ownership override . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Can_Build ( StructType s , HousesType house ) const
{
Validate ( ) ;
return ( Can_Build ( & BuildingTypeClass : : As_Reference ( s ) , house ) ) ;
}
/***********************************************************************************************
* HouseClass : : Can_Build - - Determines if the infantry unit can be built by this house . *
* *
* Use this routine to determine if the infantry type specified can be built by this *
* house . It determines this by checking the ownership allowed bits in the infantry *
* type class . *
* *
* INPUT : infantry - - The infantry type to check against this house . *
* *
* house - - The house number to use when determining if the object can be built . *
* This is necessary because the current owner of the factory doesn ' t *
* control what the factory can produce . Rather , the original builder of *
* the factory controls this . *
* *
* OUTPUT : bool ; Can the infantry be produced by this house ? *
* *
* WARNINGS : It does not check to see if there is a functional barracks available , but *
* merely checks to see if it is legal for this house to build that infantry *
* type . *
* *
* HISTORY : *
* 12 / 09 / 1994 JLB : Created . *
* 05 / 31 / 1995 JLB : Handles specified ownership override . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Can_Build ( InfantryType infantry , HousesType house ) const
{
Validate ( ) ;
return ( Can_Build ( & InfantryTypeClass : : As_Reference ( infantry ) , house ) ) ;
}
/***********************************************************************************************
* HouseClass : : Can_Build - - Determines if the unit can be built by this house . *
* *
* This routine is used to determine if the unit type specified can in fact be built by *
* this house . It checks the ownable bits in the unit ' s type to determine this . *
* *
* INPUT : unit - - The unit type to check against this house . *
* *
* house - - The house number to use when determining if the object can be built . *
* This is necessary because the current owner of the factory doesn ' t *
* control what the factory can produce . Rather , the original builder of *
* the factory controls this . *
* *
* OUTPUT : bool ; Can the unit be built by this house ? *
* *
* WARNINGS : This doesn ' t check to see if there is a functional factory that can build *
* this unit , but merely if the unit can be built according to ownership rules . *
* *
* HISTORY : *
* 12 / 09 / 1994 JLB : Created . *
* 05 / 31 / 1995 JLB : Handles specified ownership override . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Can_Build ( UnitType unit , HousesType house ) const
{
Validate ( ) ;
return ( Can_Build ( & UnitTypeClass : : As_Reference ( unit ) , house ) ) ;
}
/***********************************************************************************************
* HouseClass : : Can_Build - - Determines if the aircraft type can be built . *
* *
* Use this routine to determine if the specified aircraft type can be built . This routine *
* is used by the sidebar and factory to determine what can be built . *
* *
* INPUT : aircraft - - The aircraft type to check for build legality . *
* *
* house - - The house that is performing the check . This is typically the house *
* of the original building of the factory rather than the current *
* owner . *
* *
* OUTPUT : Can this aircraft type be built by the house specified ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 06 / 24 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Can_Build ( AircraftType aircraft , HousesType house ) const
{
Validate ( ) ;
return ( Can_Build ( & AircraftTypeClass : : As_Reference ( aircraft ) , house ) ) ;
}
/***************************************************************************
* HouseClass : : Init - - init ' s in preparation for new scenario *
* *
* INPUT : *
* none . *
* *
* OUTPUT : *
* none . *
* *
* WARNINGS : *
* none . *
* *
* HISTORY : *
* 12 / 07 / 1994 BR : Created . *
* 12 / 17 / 1994 JLB : Resets tracker bits . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Init ( void )
{
Houses . Free_All ( ) ;
for ( HousesType index = HOUSE_FIRST ; index < HOUSE_COUNT ; index + + ) {
HouseTriggers [ index ] . Clear ( ) ;
}
}
// Object selection list is switched with player context for GlyphX. ST - 4/17/2019 9:42AM
extern void Logic_Switch_Player_Context ( HouseClass * house ) ;
/***********************************************************************************************
* HouseClass : : AI - - Process house logic . *
* *
* This handles the AI for the house object . It should be called once per house per game *
* tick . It processes all house global tasks such as low power damage accumulation and *
* house specific trigger events . *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 12 / 27 / 1994 JLB : Created . *
* 07 / 17 / 1995 JLB : Limits EVA speaking unless the player can do something . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
extern void Recalculate_Placement_Distances ( ) ;
extern void On_Message ( const char * message , float timeout_seconds , long long message_id ) ;
void HouseClass : : AI ( void )
{
Validate ( ) ;
// Set PlayerPtr to be this house. Not really keen on this solution but it means I have to make fewer code changes to the original code. ST - 4/17/2019 4:32PM
Logic_Switch_Player_Context ( this ) ;
/*
* * Reset the scan accumulation bits for the next logic pass .
*/
IScan = NewIScan ;
BScan = NewBScan ;
UScan = NewUScan ;
AScan = NewAScan ;
ActiveIScan = NewActiveIScan ;
ActiveBScan = NewActiveBScan ;
ActiveUScan = NewActiveUScan ;
ActiveAScan = NewActiveAScan ;
NewIScan = 0 ;
NewBScan = 0 ;
NewUScan = 0 ;
NewAScan = 0 ;
NewActiveIScan = 0 ;
NewActiveBScan = 0 ;
NewActiveUScan = 0 ;
NewActiveAScan = 0 ;
# ifdef USE_RA_AI
//
// Copied from RA for AI. ST - 7/25/2019 3:58PM
//
/*
* * If base building has been turned on by a trigger , then force the house to begin
* * production and team creation as well . This is also true if the IQ is high enough to
* * being base building .
*/
if ( ! IsHuman & & GameToPlay ! = GAME_NORMAL & & ( IsBaseBuilding | | IQ > = Rule . IQProduction ) ) {
IsBaseBuilding = true ;
IsStarted = true ;
IsAlerted = true ;
}
# endif
/*
* * Check to see if the house wins .
*/
if ( GameToPlay = = GAME_NORMAL & & IsToWin & & BorrowedTime . Expired ( ) & & Blockage < = 0 ) {
IsToWin = false ;
if ( this = = PlayerPtr ) {
PlayerWins = true ;
} else {
PlayerLoses = true ;
}
}
/*
* * Check to see if the house loses .
*/
if ( GameToPlay = = GAME_NORMAL & & IsToLose & & BorrowedTime . Expired ( ) ) {
IsToLose = false ;
if ( this = = PlayerPtr ) {
PlayerLoses = true ;
} else {
PlayerWins = true ;
}
}
/*
* * Check to see if all objects of this house should be blown up .
*/
if ( IsToDie & & BorrowedTime . Expired ( ) ) {
IsToDie = false ;
Blowup_All ( ) ;
2020-08-06 17:44:54 +01:00
// MBL 07.15.2020 - Steve made this change for RA, so also applying here to TD
// See Change 737595 by Steve_Tall@STEVET3-VICTORY-H on 2020/07/10 13:40:02
if ( GameToPlay = = GAME_GLYPHX_MULTIPLAYER ) {
MPlayer_Defeated ( ) ;
}
2020-05-27 20:16:20 +01:00
}
/*
* * Double check power values to correct illegal conditions . It is possible to
* * get a power output of negative ( one usually ) as a result of damage sustained
* * and the fixed point fractional math involved with power adjustements . If the
* * power rating drops below zero , then make it zero .
*/
if ( GameToPlay = = GAME_NORMAL ) {
Power = MAX ( Power , 0 ) ;
Drain = MAX ( Drain , 0 ) ;
}
/*
* * If the base has been alerted to the enemy and should be attacking , then
* * see if the attack timer has expired . If it has , then create the attack
* * teams .
*/
if ( IsAlerted & & AlertTime . Expired ( ) ) {
/*
* * Adjusted to reduce maximum number of teams created .
*/
int maxteams = Random_Pick ( 2 , ( int ) ( ( ( BuildLevel - 1 ) / 3 ) + 1 ) ) ;
for ( int index = 0 ; index < maxteams ; index + + ) {
TeamTypeClass const * ttype = Suggested_New_Team ( true ) ;
if ( ttype ) {
ScenarioInit + + ;
ttype - > Create_One_Of ( ) ;
ScenarioInit - - ;
}
}
if ( GameToPlay = = GAME_NORMAL & & PlayerPtr - > Difficulty = = DIFF_HARD ) {
AlertTime = ( TICKS_PER_MINUTE * Random_Pick ( 4 , 10 ) ) ;
} else {
if ( GameToPlay = = GAME_NORMAL & & PlayerPtr - > Difficulty = = DIFF_EASY ) {
AlertTime = ( TICKS_PER_MINUTE * Random_Pick ( 16 , 40 ) ) ;
} else {
AlertTime = ( TICKS_PER_MINUTE * Random_Pick ( 5 , 20 ) ) ;
}
}
}
/*
* * Create teams for this house if necessary .
* * ( Use the same timer for some extra capture - the - flag logic . )
*/
if ( TeamTime . Expired ( ) ) {
TeamTypeClass const * ttype = Suggested_New_Team ( false ) ;
if ( ttype ) {
ttype - > Create_One_Of ( ) ;
}
/*
* * Also use this timer to detect if someone is sitting on my flag cell .
*/
if ( Special . IsCaptureTheFlag & & GameToPlay ! = GAME_NORMAL ) {
TechnoClass * techno ;
int moving ;
/*
* * If this house ' s flag waypoint is a valid cell , see if there ' s
* * someone sitting on it . If so , make the scatter .
*/
if ( FlagHome ) {
techno = Map [ FlagHome ] . Cell_Techno ( ) ;
if ( techno ) {
moving = false ;
if ( techno - > What_Am_I ( ) = = RTTI_INFANTRY | |
techno - > What_Am_I ( ) = = RTTI_UNIT ) {
if ( Target_Legal ( ( ( FootClass * ) techno ) - > NavCom ) ) {
moving = true ;
}
}
if ( ! moving ) {
techno - > Scatter ( 0 , true , true ) ;
}
}
}
}
/*
* * Randomly create a Visceroid or other disastrous multiplayer object .
* * Create the object , and use Scan_Place_Object to place the object near
* * the center of the map .
*/
if ( GameToPlay ! = GAME_NORMAL & & Class - > House = = HOUSE_JP ) {
int rlimit ;
if ( Special . IsJurassic & & AreThingiesEnabled ) {
rlimit = 450 ;
} else {
rlimit = 1000 ;
}
//if (IRandom(0, rlimit) == 0) {
if ( IRandom ( 0 , rlimit ) < = 5 ) { // More visceroids! ST - 3/3/2020 4:34PM
UnitClass * obj = NULL ;
CELL cell ;
if ( Special . IsJurassic & & AreThingiesEnabled ) {
obj = new UnitClass ( Random_Pick ( UNIT_TRIC , UNIT_STEG ) , HOUSE_JP ) ;
} else if ( Special . IsVisceroids ) {
if ( BuildLevel > = 7 ) {
if ( ! ( UScan & UNITF_VICE ) ) {
obj = new UnitClass ( UNIT_VICE , HOUSE_JP ) ;
}
}
}
if ( obj ) {
cell = XY_Cell ( Map . MapCellX + Random_Pick ( 0 , Map . MapCellWidth - 1 ) ,
Map . MapCellY + Random_Pick ( 0 , Map . MapCellHeight - 1 ) ) ;
if ( ! Scan_Place_Object ( obj , cell ) ) {
delete obj ;
}
}
}
}
TeamTime . Set ( TEAM_DELAY ) ;
}
/*
* * If there is insufficient power , then all buildings that are above
* * half strength take a little bit of damage .
*/
if ( DamageTime . Expired ( ) ) {
/*
* * No free harvesters for computer or player . - 8 / 16 / 95
*/
# ifdef OBSOLETE
/*
* * Replace the last harvester if there is a refinery present .
*/
if ( GameToPlay = = GAME_NORMAL & &
Frame > 5 & &
( ! IsHuman & & BuildLevel < = 6 ) & &
( ActiveBScan & STRUCTF_REFINERY ) ! = 0 & &
( UScan & UNITF_HARVESTER ) = = 0 & &
! IsFreeHarvester ) {
IsFreeHarvester = true ;
FreeHarvester = TICKS_PER_MINUTE * 2 ;
}
# endif
/*
* * If a free harvester is to be created and the time is right , then create
* * the harvester and clear the free harvester pending flag .
*/
if ( IsFreeHarvester & & FreeHarvester . Expired ( ) ) {
IsFreeHarvester = false ;
Create_Special_Reinforcement ( this , ( TechnoTypeClass * ) & UnitTypeClass : : As_Reference ( UNIT_HARVESTER ) , NULL ) ;
}
/*
* * When the power is below required , then the buildings will take damage over
* * time .
*/
if ( Power_Fraction ( ) < 0x100 ) {
for ( int index = 0 ; index < Buildings . Count ( ) ; index + + ) {
BuildingClass & b = * Buildings . Ptr ( index ) ;
if ( b . House = = this & & b . Health_Ratio ( ) > 0x080 ) {
if ( b . Class - > Drain ) {
int damage = 1 ;
b . Take_Damage ( damage , 0 , WARHEAD_AP , 0 ) ;
}
}
}
}
DamageTime . Set ( DAMAGE_DELAY ) ;
}
/*
* * If there are no more buildings to sell , then automatically cancel the
* * sell mode .
*/
if ( PlayerPtr = = this & & ! BScan & & Map . IsSellMode ) {
Map . Sell_Mode_Control ( 0 ) ;
}
/*
* * Various base conditions may be announced to the player .
*/
if ( PlayerPtr = = this ) {
if ( SpeakMoneyDelay . Expired ( ) & & Available_Money ( ) < 100 & & UnitFactories + BuildingFactories + InfantryFactories > 0 ) {
// MBL 03.23.2020 - Change "Need more funds" to "Insufficient funds" per https://jaas.ea.com/browse/TDRA-5370
// Speak(VOX_NEED_MO_MONEY);
Speak ( VOX_NO_CASH ) ;
//
// !!! MBL 03.18.2020:
// !!! Changing "Insufficient Funds" speak delay for this case to 1 minute instead of 2.
// !!! Note that all other speak delays are 2 minutes in TD (SPEAK_DELAY) and RA (Rule.SpeakDelay)
// !!! This is per https://jaas.ea.com/browse/TDRA-4659 (Ted and Jim)
// !!! I Checked with Joe mostly okay with this change, but want to note that we are changing original behavior
// !!! All other speak delays in TD and RA (max capacity and low power) remain at 2 minutes.
// !!! Also, in Red Alert, this is still 2 minutes from Rules.ini (SpeakDelay variable)
//
// SpeakMoneyDelay.Set(Options.Normalize_Delay(SPEAK_DELAY)); // 2 minutes
//
// MBL 05.18.2020: Setting back to 2 minutes as requested per https://jaas.ea.com/browse/TDRA-5834
//
// SpeakMoneyDelay.Set(Options.Normalize_Delay(SPEAK_DELAY / 2)); // 1 minute (new)
SpeakMoneyDelay . Set ( Options . Normalize_Delay ( SPEAK_DELAY ) ) ; // 2 minutes (original)
int text_id = TXT_INSUFFICIENT_FUNDS ;
char const * text = Text_String ( TXT_INSUFFICIENT_FUNDS ) ;
if ( text ! = NULL ) {
On_Message ( text , 35.0f , text_id ) ;
}
}
if ( SpeakMaxedDelay . Expired ( ) & & IsMaxedOut ) {
IsMaxedOut = false ;
if ( ( Capacity - Tiberium ) < 300 & & Capacity > 500 & & ( BScan & ( STRUCTF_REFINERY | STRUCTF_CONST ) ) ) {
Speak ( VOX_NEED_MO_CAPACITY ) ;
SpeakMaxedDelay . Set ( Options . Normalize_Delay ( SPEAK_DELAY ) ) ;
}
}
if ( SpeakPowerDelay . Expired ( ) & & Power_Fraction ( ) < 0x0100 ) {
if ( BScan & STRUCTF_CONST ) {
Speak ( VOX_LOW_POWER ) ;
SpeakPowerDelay . Set ( Options . Normalize_Delay ( SPEAK_DELAY ) ) ;
int text_id = TXT_LOW_POWER ;
char const * text = Text_String ( TXT_LOW_POWER ) ;
if ( text ! = NULL ) {
On_Message ( text , 35.0f , text_id ) ;
}
}
}
}
/*
* * If there is a flag associated with this house , then mark it to be
* * redrawn .
*/
if ( Target_Legal ( FlagLocation ) ) {
UnitClass * unit = As_Unit ( FlagLocation ) ;
if ( unit ) {
unit - > Mark ( MARK_CHANGE ) ;
} else {
CELL cell = As_Cell ( FlagLocation ) ;
2020-06-22 17:43:21 +01:00
Map [ cell ] . Flag_Update ( ) ;
2020-05-27 20:16:20 +01:00
Map [ cell ] . Redraw_Objects ( ) ;
}
}
bool is_time = false ;
/*
* * Triggers are only checked every so often . If the trigger timer has expired ,
* * then set the trigger processing flag .
*/
if ( TriggerTime . Expired ( ) ) {
is_time = true ;
TriggerTime = TICKS_PER_MINUTE / 10 ;
}
/*
* * Check to see if the ion cannon should be removed from the sidebar
* * because of outside circumstances . The advanced communications facility
* * being destroyed is a good example of this .
*/
if ( IonCannon . Is_Present ( ) ) {
if ( ! ( ActiveBScan & STRUCTF_EYE ) & & ! IonCannon . Is_One_Time ( ) ) {
/*
* * Remove the ion cannon when there is no advanced communication facility .
* * Note that this will not remove the one time created ion cannon .
*/
if ( IonCannon . Remove ( ) ) {
if ( this = = PlayerPtr ) Map . Column [ 1 ] . Flag_To_Redraw ( ) ;
IsRecalcNeeded = true ;
}
} else {
/*
* * Turn the ion cannon suspension on or off depending on the available
* * power . Note that one time ion cannon will not be affected by this .
*/
IonCannon . Suspend ( Power_Fraction ( ) < 0x0100 ) ;
/*
* * Process the ion cannon AI and if something changed that would affect
* * the sidebar , then flag the sidebar to be redrawn .
*/
if ( IonCannon . AI ( this = = PlayerPtr ) ) {
if ( this = = PlayerPtr ) Map . Column [ 1 ] . Flag_To_Redraw ( ) ;
}
}
/*
* * The computer may decide to fire the ion cannon if it is ready .
*/
if ( IonCannon . Is_Ready ( ) & & ! IsHuman ) {
Special_Weapon_AI ( SPC_ION_CANNON ) ;
}
} else {
/*
* * If there is no ion cannon present , but there is an advanced communcation
* * center available , then make the ion cannon available as well .
*/
if ( ( GameToPlay = = GAME_NORMAL | | Rule . AllowSuperWeapons ) & &
( ActiveBScan & STRUCTF_EYE ) & &
( ActLike = = HOUSE_GOOD | | GameToPlay ! = GAME_NORMAL ) & &
( IsHuman | | GameToPlay ! = GAME_NORMAL ) ) {
IonCannon . Enable ( false , this = = PlayerPtr , Power_Fraction ( ) < 0x0100 ) ;
/*
* * Flag the sidebar to be redrawn if necessary .
*/
// Add to Glyphx multiplayer sidebar. ST - 3/22/2019 1:50PM
if ( GameToPlay = = GAME_GLYPHX_MULTIPLAYER ) {
if ( IsHuman ) {
Sidebar_Glyphx_Add ( RTTI_SPECIAL , SPC_ION_CANNON , this ) ;
}
} else {
if ( this = = PlayerPtr ) {
Map . Add ( RTTI_SPECIAL , SPC_ION_CANNON ) ;
Map . Column [ 1 ] . Flag_To_Redraw ( ) ;
}
}
}
}
/*
* * Check to see if the nuke strike should be removed from the sidebar
* * because of outside circumstances . The Temple of Nod
* * being destroyed is a good example of this .
*/
if ( NukeStrike . Is_Present ( ) ) {
if ( ! ( ActiveBScan & STRUCTF_TEMPLE ) & & ( ! NukeStrike . Is_One_Time ( ) | | GameToPlay = = GAME_NORMAL ) ) {
/*
* * Remove the nuke strike when there is no Temple of Nod .
* * Note that this will not remove the one time created nuke strike .
*/
if ( NukeStrike . Remove ( true ) ) {
IsRecalcNeeded = true ;
if ( this = = PlayerPtr ) Map . Column [ 1 ] . Flag_To_Redraw ( ) ;
}
} else {
/*
* * Turn the nuke strike suspension on or off depending on the available
* * power . Note that one time nuke strike will not be affected by this .
*/
NukeStrike . Suspend ( Power_Fraction ( ) < 0x0100 ) ;
/*
* * Process the nuke strike AI and if something changed that would affect
* * the sidebar , then flag the sidebar to be redrawn .
*/
if ( NukeStrike . AI ( this = = PlayerPtr ) ) {
if ( this = = PlayerPtr ) Map . Column [ 1 ] . Flag_To_Redraw ( ) ;
}
}
/*
* * The computer may decide to fire the nuclear missile if it is ready .
*/
if ( NukeStrike . Is_Ready ( ) & & ! IsHuman ) {
Special_Weapon_AI ( SPC_NUCLEAR_BOMB ) ;
}
} else {
/*
* * If there is no nuke strike present , but there is a Temple of Nod
* * available , then make the nuke strike strike available .
*/
if ( ( GameToPlay = = GAME_NORMAL | | Rule . AllowSuperWeapons ) & & ( ActiveBScan & STRUCTF_TEMPLE ) & & Has_Nuke_Device ( ) & & IsHuman ) {
NukeStrike . Enable ( ( GameToPlay = = GAME_NORMAL ) , this = = PlayerPtr ) ;
/*
* * Flag the sidebar to be redrawn if necessary .
*/
// Add to Glyphx multiplayer sidebar. ST - 3/22/2019 1:50PM
if ( GameToPlay = = GAME_GLYPHX_MULTIPLAYER ) {
if ( IsHuman ) {
Sidebar_Glyphx_Add ( RTTI_SPECIAL , SPC_NUCLEAR_BOMB , this ) ;
}
} else {
if ( this = = PlayerPtr ) {
Map . Add ( RTTI_SPECIAL , SPC_NUCLEAR_BOMB ) ;
Map . Column [ 1 ] . Flag_To_Redraw ( ) ;
}
}
}
}
/*
* * Process the airstrike AI and if something changed that would affect
* * the sidebar , then flag the sidebar to be redrawn .
*/
if ( AirStrike . Is_Present ( ) ) {
if ( AirStrike . AI ( this = = PlayerPtr ) ) {
if ( this = = PlayerPtr ) Map . Column [ 1 ] . Flag_To_Redraw ( ) ;
}
/*
* * The computer may decide to call in the airstrike if it is ready .
*/
if ( AirStrike . Is_Ready ( ) & & ! IsHuman ) {
Special_Weapon_AI ( SPC_AIR_STRIKE ) ;
}
}
/*
* * Add the airstrike option if it is pending .
*/
if ( IsAirstrikePending ) {
IsAirstrikePending = false ;
if ( AirStrike . Enable ( false , this = = PlayerPtr ) ) {
AirStrike . Forced_Charge ( this = = PlayerPtr ) ;
// Add to Glyphx multiplayer sidebar. ST - 3/22/2019 1:50PM
if ( GameToPlay = = GAME_GLYPHX_MULTIPLAYER ) {
if ( IsHuman ) {
Sidebar_Glyphx_Add ( RTTI_SPECIAL , SPC_AIR_STRIKE , this ) ;
}
} else {
if ( this = = PlayerPtr ) {
Map . Add ( RTTI_SPECIAL , SPC_AIR_STRIKE ) ;
Map . Column [ 1 ] . Flag_To_Redraw ( ) ;
}
}
}
}
# ifdef NEVER
/*
* * The following logic deals with the nuclear warhead state machine . It
* * handles all the different stages of the temple firing and the rocket
* * travelling up and down . The rocket explosion is handled by the anim
* * which is attached to the bullet .
*/
if ( ! IsHuman & & NukePresent ) {
Special_Weapon_AI ( SPC_NUCLEAR_BOMB ) ;
}
# endif
2020-08-06 17:44:54 +01:00
if ( GameToPlay ! = GAME_NORMAL & & Class - > House ! = HOUSE_JP ) {
2020-05-27 20:16:20 +01:00
Check_Pertinent_Structures ( ) ;
}
/*
* * Special win / lose check for multiplayer games ; by - passes the
* * trigger system . We must wait for non - zero frame , because init
* * may not properly set IScan etc for each house ; you have to go
* * through each object ' s AI before it will be properly set .
*/
if ( GameToPlay ! = GAME_NORMAL & & ! IsDefeated & &
! ActiveBScan & & ! ActiveAScan & & ! UScan & & ! ActiveIScan & & Frame > 0 ) {
MPlayer_Defeated ( ) ;
}
for ( int index = 0 ; index < HouseTriggers [ Class - > House ] . Count ( ) ; index + + ) {
TriggerClass * t = HouseTriggers [ Class - > House ] [ index ] ;
/*
* * Check for just built the building trigger event .
*/
if ( JustBuilt ! = STRUCT_NONE ) {
if ( t - > Spring ( EVENT_BUILD , Class - > House , JustBuilt ) ) {
JustBuilt = STRUCT_NONE ;
continue ;
}
}
/*
* * Check for civilian evacuation trigger event .
*/
if ( IsCivEvacuated & & t - > Spring ( EVENT_EVAC_CIVILIAN , Class - > House ) ) {
continue ;
}
/*
* * Number of buildings destroyed checker .
*/
if ( t - > Spring ( EVENT_NBUILDINGS_DESTROYED , Class - > House , BuildingsLost ) ) {
continue ;
}
/*
* * Number of units destroyed checker .
*/
if ( t - > Spring ( EVENT_NUNITS_DESTROYED , Class - > House , UnitsLost ) ) {
continue ;
}
/*
* * House has been revealed trigger event .
*/
if ( IsDiscovered & & t - > Spring ( EVENT_HOUSE_DISCOVERED , Class - > House ) ) {
IsDiscovered = false ;
continue ;
}
/*
* * The " all destroyed " triggers are only processed after a certain
* * amount of safety time has expired .
*/
if ( ! EndCountDown ) {
/*
* * All buildings destroyed checker .
*/
if ( ! ActiveBScan ) {
if ( t - > Spring ( EVENT_BUILDINGS_DESTROYED , Class - > House ) ) {
continue ;
}
}
/*
* * All units destroyed checker .
*/
if ( ! ( ( ActiveUScan & ~ ( UNITF_GUNBOAT ) ) | IScan | ( ActiveAScan & ~ ( AIRCRAFTF_TRANSPORT | AIRCRAFTF_CARGO | AIRCRAFTF_A10 ) ) ) ) {
if ( t - > Spring ( EVENT_UNITS_DESTROYED , Class - > House ) ) {
continue ;
}
}
/*
* * All buildings AND units destroyed checker .
*/
if ( ! ( ActiveBScan | ( ActiveUScan & ~ ( UNITF_GUNBOAT ) ) | IScan | ( ActiveAScan & ~ ( AIRCRAFTF_TRANSPORT | AIRCRAFTF_CARGO | AIRCRAFTF_A10 ) ) ) ) {
if ( t - > Spring ( EVENT_ALL_DESTROYED , Class - > House ) ) {
continue ;
}
}
}
/*
* * Credit check .
*/
if ( t - > Spring ( EVENT_CREDITS , Class - > House , Credits ) ) {
continue ;
}
/*
* * Timeout check .
*/
if ( is_time & & t - > Spring ( EVENT_TIME , Class - > House ) ) {
continue ;
}
/*
* * All factories destroyed check .
*/
if ( ! ( BScan & ( STRUCTF_AIRSTRIP | STRUCTF_HAND | STRUCTF_WEAP | STRUCTF_BARRACKS ) ) & & t - > Spring ( EVENT_NOFACTORIES , Class - > House ) ) {
continue ;
}
}
/*
* * If a radar facility is not present , but the radar is active , then turn the radar off .
* * The radar also is turned off when the power gets below 100 % capacity .
*/
if ( PlayerPtr = = this ) {
if ( Map . Is_Radar_Active ( ) ) {
if ( BScan & ( STRUCTF_RADAR | STRUCTF_EYE ) ) {
if ( Power_Fraction ( ) < 0x0100 ) {
Map . Radar_Activate ( 0 ) ;
}
} else {
Map . Radar_Activate ( 0 ) ;
}
} else {
if ( BScan & ( STRUCTF_RADAR | STRUCTF_EYE ) ) {
if ( Power_Fraction ( ) > = 0x0100 ) {
Map . Radar_Activate ( 1 ) ;
}
} else {
if ( Map . Is_Radar_Existing ( ) ) {
Map . Radar_Activate ( 4 ) ;
}
}
}
if ( ! ( BScan & ( STRUCTF_RADAR | STRUCTF_EYE ) ) ) {
Radar = RADAR_NONE ;
} else {
Radar = ( Map . Is_Radar_Active ( ) | | Map . Is_Radar_Activating ( ) ) ? RADAR_ON : RADAR_OFF ;
}
}
VisibleCredits . AI ( false , this , true ) ;
/*
* * Copied from Red Alert for multiplayer AI . ST - 7 / 23 / 2019 3 : 02 PM
* *
* *
* *
*/
# ifdef USE_RA_AI
if ( GameToPlay = = GAME_GLYPHX_MULTIPLAYER & & IsHuman = = false ) {
/*
* * Perform any expert system AI processing .
*/
if ( IsBaseBuilding & & AITimer = = 0 ) {
AITimer = Expert_AI ( ) ;
}
if ( ! IsBaseBuilding & & State = = STATE_ENDGAME ) {
Fire_Sale ( ) ;
Do_All_To_Hunt ( ) ;
}
AI_Building ( ) ;
AI_Unit ( ) ;
AI_Vessel ( ) ;
AI_Infantry ( ) ;
AI_Aircraft ( ) ;
}
# endif
/*
* * If the production possibilities need to be recalculated , then do so now . This must
* * occur after the scan bits have been properly updated .
*/
if ( PlayerPtr = = this & & IsRecalcNeeded ) {
IsRecalcNeeded = false ;
Map . Recalc ( ) ;
# ifdef NEVER
/*
* * Remove the ion cannon if necessary .
*/
if ( IonCannon . Is_Present ( ) & & ! ( BScan & STRUCTF_EYE ) ) {
IonCannon . Remove ( ) ;
}
/*
* * Remove the nuclear bomb if necessary .
*/
if ( NukeStrike . Is_Present ( ) & & ! ( BScan & STRUCTF_TEMPLE ) ) {
NukeStrike . Remove ( ) ;
}
# endif
/*
* * This placement might affect any prerequisite requirements for construction
* * lists . Update the buildable options accordingly .
*/
for ( int index = 0 ; index < Buildings . Count ( ) ; index + + ) {
BuildingClass * building = Buildings . Ptr ( index ) ;
if ( building & & building - > Owner ( ) = = Class - > House ) {
building - > Update_Specials ( ) ;
if ( PlayerPtr = = building - > House ) {
building - > Update_Buildables ( ) ;
}
}
}
Recalculate_Placement_Distances ( ) ;
}
}
/***********************************************************************************************
* HouseClass : : Attacked - - Lets player know if base is under attack . *
* *
* Call this function whenever a building is attacked ( with malice ) . This function will *
* then announce to the player that his base is under attack . It checks to make sure that *
* this is referring to the player ' s house rather than the enemy ' s . *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 12 / 27 / 1994 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Attacked ( BuildingClass * source )
{
Validate ( ) ;
2020-08-06 17:44:54 +01:00
bool expired = SpeakAttackDelay . Expired ( ) ;
bool spoke = false ;
// if (SpeakAttackDelay.Expired() && PlayerPtr->Class->House == Class->House) {
if ( expired & & PlayerPtr - > Class - > House = = Class - > House ) {
2020-05-27 20:16:20 +01:00
Speak ( VOX_BASE_UNDER_ATTACK , NULL , source ? source - > Center_Coord ( ) : 0 ) ;
2020-08-06 17:44:54 +01:00
spoke = true ;
2020-06-22 17:43:21 +01:00
// MBL 06.13.2020 - Timing change from 2 minute cooldown, per https://jaas.ea.com/browse/TDRA-6784
// SpeakAttackDelay.Set(Options.Normalize_Delay(SPEAK_DELAY)); // 2 minutes
// SpeakAttackDelay.Set(Options.Normalize_Delay(TICKS_PER_MINUTE/2)); // 30 seconds as requested
SpeakAttackDelay . Set ( Options . Normalize_Delay ( ( TICKS_PER_MINUTE / 2 ) + ( TICKS_PER_SECOND * 5 ) ) ) ; // Tweaked for accuracy
2020-05-27 20:16:20 +01:00
/*
* * If there is a trigger event associated with being attacked , process it
* * now .
*/
for ( int index = 0 ; index < HouseTriggers [ Class - > House ] . Count ( ) ; index + + ) {
HouseTriggers [ Class - > House ] [ index ] - > Spring ( EVENT_ATTACKED , Class - > House ) ;
}
}
2020-08-06 17:44:54 +01:00
// MBL 07.07.2020 - CNC Patch 3, fix for not working for all players in MP, per https://jaas.ea.com/browse/TDRA-7249
// Separated to here as did not want to change any logic around the HouseTriggers[] Spring events
//
if ( expired = = true & & spoke = = false )
{
if ( GameToPlay ! = GAME_NORMAL ) // Multiplayer
{
Speak ( VOX_BASE_UNDER_ATTACK , this ) ;
spoke = true ;
// SpeakAttackDelay.Set(Options.Normalize_Delay(SPEAK_DELAY)); // 2 minutes
// SpeakAttackDelay.Set(Options.Normalize_Delay(TICKS_PER_MINUTE/2)); // 30 seconds as requested
SpeakAttackDelay . Set ( Options . Normalize_Delay ( ( TICKS_PER_MINUTE / 2 ) + ( TICKS_PER_SECOND * 5 ) ) ) ; // Tweaked for accuracy
}
}
// END MBL 07.07.2020
2020-05-27 20:16:20 +01:00
}
/***********************************************************************************************
* HouseClass : : Harvested - - Adds Tiberium to the harvest storage . *
* *
* Use this routine whenever Tiberium is harvested . The Tiberium is stored equally between *
* all storage capable buildings for the house . Harvested Tiberium adds to the credit *
* value of the house , but only up to the maximum storage capacity that the house can *
* currently maintain . *
* *
* INPUT : tiberium - - The number of Tiberium credits to add to the House ' s total . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 01 / 25 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Harvested ( unsigned tiberium )
{
Validate ( ) ;
long oldtib = Tiberium ;
Tiberium + = tiberium ;
if ( Tiberium > Capacity ) {
Tiberium = Capacity ;
IsMaxedOut = true ;
}
HarvestedCredits + = tiberium ;
Silo_Redraw_Check ( oldtib , Capacity ) ;
}
/***********************************************************************************************
* HouseClass : : Available_Money - - Fetches the total credit worth of the house . *
* *
* Use this routine to determine the total credit value of the house . This is the sum of *
* the harvested Tiberium in storage and the initial unspent cash reserves . *
* *
* INPUT : none *
* *
* OUTPUT : Returns with the total credit value of the house . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 01 / 25 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
long HouseClass : : Available_Money ( void ) const
{
Validate ( ) ;
return ( Tiberium + Credits ) ;
}
/***********************************************************************************************
* HouseClass : : Spend_Money - - Removes money from the house . *
* *
* Use this routine to extract money from the house . Typically , this is a result of *
* production spending . The money is extracted from available cash reserves first . When *
* cash reserves are exhausted , then Tiberium is consumed . *
* *
* INPUT : money - - The amount of money to spend . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 01 / 25 / 1995 JLB : Created . *
* 06 / 20 / 1995 JLB : Spends Tiberium before spending cash . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Spend_Money ( unsigned money )
{
Validate ( ) ;
long oldtib = Tiberium ;
if ( ( int ) money > Tiberium ) {
money - = ( unsigned ) Tiberium ;
Tiberium = 0 ;
Credits - = money ;
} else {
Tiberium - = money ;
}
Silo_Redraw_Check ( oldtib , Capacity ) ;
CreditsSpent + = money ;
}
/***********************************************************************************************
* HouseClass : : Refund_Money - - Refunds money to back to the house . *
* *
* Use this routine when money needs to be refunded back to the house . This can occur when *
* construction is aborted . At this point , the exact breakdown of Tiberium or initial *
* credits used for the orignal purchase is lost . Presume as much of the money is in the *
* form of Tiberium as storage capacity will allow . *
* *
* INPUT : money - - The number of credits to refund back to the house . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 01 / 25 / 1995 JLB : Created . *
* 06 / 01 / 1995 JLB : Refunded money is never lost *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Refund_Money ( unsigned money )
{
Validate ( ) ;
Credits + = money ;
}
/***********************************************************************************************
* HouseClass : : Adjust_Capacity - - Adjusts the house Tiberium storage capacity . *
* *
* Use this routine to adjust the maximum storage capacity for the house . This storage *
* capacity will limit the number of Tiberium credits that can be stored at any one time . *
* *
* INPUT : adjust - - The adjustment to the Tiberium storage capacity . *
* *
* inanger - - Is this a forced adjustment to capacity due to some hostile event ? *
* *
* OUTPUT : Returns with the number of Tiberium credits lost . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 01 / 25 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
int HouseClass : : Adjust_Capacity ( int adjust , bool inanger )
{
Validate ( ) ;
long oldcap = Capacity ;
int retval = 0 ;
Capacity + = adjust ;
Capacity = MAX ( Capacity , 0L ) ;
if ( Tiberium > Capacity ) {
retval = Tiberium - Capacity ;
Tiberium = Capacity ;
if ( ! inanger ) {
Refund_Money ( retval ) ;
retval = 0 ;
} else {
IsMaxedOut = true ;
}
}
Silo_Redraw_Check ( Tiberium , oldcap ) ;
return ( retval ) ;
}
/***********************************************************************************************
* HouseClass : : Silo_Redraw_Check - - Flags silos to be redrawn if necessary . *
* *
* Call this routine when either the capacity or tiberium levels change for a house . This *
* routine will determine if the aggregate tiberium storage level will result in the *
* silos changing their imagery . If this is detected , then all the silos for this house *
* are flagged to be redrawn . *
* *
* INPUT : oldtib - - Pre - change tiberium level . *
* *
* oldcap - - Pre - change tiberium storage capacity . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 02 / 02 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Silo_Redraw_Check ( long oldtib , long oldcap )
{
Validate ( ) ;
int oldratio = 0 ;
if ( oldcap ) oldratio = ( oldtib * 5 ) / oldcap ;
int newratio = 0 ;
if ( Capacity ) newratio = ( Tiberium * 5 ) / Capacity ;
if ( oldratio ! = newratio ) {
for ( int index = 0 ; index < Buildings . Count ( ) ; index + + ) {
BuildingClass * b = Buildings . Ptr ( index ) ;
if ( b & & ! b - > IsInLimbo & & b - > House = = this & & * b = = STRUCT_STORAGE ) {
b - > Mark ( MARK_CHANGE ) ;
}
}
}
}
/***********************************************************************************************
* HouseClass : : Read_INI - - Reads house specific data from INI . *
* *
* This routine reads the house specific data for a particular *
* scenario from the scenario INI file . Typical data includes starting *
* credits , maximum unit count , etc . *
* *
* INPUT : buffer - - Pointer to loaded scenario INI file . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 24 / 1994 JLB : Created . *
* 05 / 18 / 1995 JLB : Creates all houses . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Read_INI ( char * buffer )
{
HouseClass * p ; // Pointer to current player data.
char const * hname ; // Pointer to house name.
char buf [ 128 ] ;
for ( HousesType index = HOUSE_FIRST ; index < HOUSE_COUNT ; index + + ) {
hname = HouseTypeClass : : As_Reference ( index ) . IniName ;
int maxunit = WWGetPrivateProfileInt ( hname , " MaxUnit " , EACH_UNIT_MAX , buffer ) ;
maxunit = MAX ( maxunit , 150 ) ;
int maxbuilding = WWGetPrivateProfileInt ( hname , " MaxBuilding " , EACH_BUILDING_MAX , buffer ) ;
maxbuilding = MAX ( maxbuilding , 150 ) ;
int credits = WWGetPrivateProfileInt ( hname , " Credits " , 0 , buffer ) ;
p = new HouseClass ( index ) ;
p - > MaxBuilding = maxbuilding ;
p - > MaxUnit = maxunit ;
p - > Credits = ( long ) credits * 100 ;
p - > InitialCredits = p - > Credits ;
WWGetPrivateProfileString ( hname , " Edge " , " " , buf , sizeof ( buf ) - 1 , buffer ) ;
p - > Edge = Source_From_Name ( buf ) ;
if ( p - > Edge = = SOURCE_NONE ) {
p - > Edge = SOURCE_NORTH ;
}
if ( GameToPlay = = GAME_NORMAL ) {
WWGetPrivateProfileString ( hname , " Allies " , " " , buf , sizeof ( buf ) - 1 , buffer ) ;
if ( strlen ( buf ) ) {
char * tok = strtok ( buf , " , \t " ) ;
while ( tok ) {
HousesType h = HouseTypeClass : : From_Name ( tok ) ;
p - > Make_Ally ( h ) ;
tok = strtok ( NULL , " , \t " ) ;
}
} else {
/*
* * Special case for when no allies are specified in the INI file .
* * The GDI side defaults to considering the neutral side to be
* * friendly .
*/
if ( p - > Class - > House = = HOUSE_GOOD ) {
p - > Make_Ally ( HOUSE_NEUTRAL ) ;
}
}
}
}
}
/***********************************************************************************************
* HouseClass : : Write_INI - - Writes house specific data into INI file . *
* *
* Use this routine to write the house specific data ( for all houses ) into the INI file . *
* It is used by the scenario editor when saving the scenario . *
* *
* INPUT : buffer - - INI file staging buffer . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 28 / 1994 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Write_INI ( char * buffer )
{
for ( HousesType i = HOUSE_FIRST ; i < HOUSE_COUNT ; i + + ) {
HouseClass * p = As_Pointer ( i ) ;
if ( p ) {
WWWritePrivateProfileInt ( p - > Class - > IniName , " Credits " , ( int ) ( p - > Credits / 100 ) , buffer ) ;
WWWritePrivateProfileString ( p - > Class - > IniName , " Edge " , Name_From_Source ( p - > Edge ) , buffer ) ;
WWWritePrivateProfileInt ( p - > Class - > IniName , " MaxUnit " , p - > MaxUnit , buffer ) ;
WWWritePrivateProfileInt ( p - > Class - > IniName , " MaxBuilding " , p - > MaxBuilding , buffer ) ;
bool first = true ;
char sbuffer [ 100 ] = " " ;
for ( HousesType house = HOUSE_FIRST ; house < HOUSE_COUNT ; house + + ) {
if ( p - > Is_Ally ( house ) ) {
if ( ! first ) strcat ( sbuffer , " , " ) ;
strcat ( sbuffer , As_Pointer ( house ) - > Class - > IniName ) ;
first = false ;
}
}
WWWritePrivateProfileString ( p - > Class - > IniName , " Allies " , sbuffer , buffer ) ;
}
}
}
/***********************************************************************************************
* HouseClass : : Is_Ally - - Determines if the specified house is an ally . *
* *
* This routine will determine if the house number specified is a ally to this house . *
* *
* INPUT : house - - The house number to check to see if it is an ally . *
* *
* OUTPUT : Is the house an ally ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 08 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Is_Ally ( HousesType house ) const
{
Validate ( ) ;
if ( house ! = HOUSE_NONE ) {
return ( ( ( 1 < < house ) & Allies ) ! = 0 ) ;
}
return ( false ) ;
}
/***********************************************************************************************
* HouseClass : : Is_Ally - - Determines if the specified house is an ally . *
* *
* This routine will examine the specified house and determine if it is an ally . *
* *
* INPUT : house - - Pointer to the house object to check for ally relationship . *
* *
* OUTPUT : Is the specified house an ally ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 08 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Is_Ally ( HouseClass const * house ) const
{
Validate ( ) ;
if ( house ) {
return ( Is_Ally ( house - > Class - > House ) ) ;
}
return ( false ) ;
}
/***********************************************************************************************
* HouseClass : : Is_Ally - - Checks to see if the object is an ally . *
* *
* This routine will examine the specified object and return whether it is an ally or not . *
* *
* INPUT : object - - The object to examine to see if it is an ally . *
* *
* OUTPUT : Is the specified object an ally ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 08 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Is_Ally ( ObjectClass const * object ) const
{
Validate ( ) ;
if ( object ) {
return ( Is_Ally ( object - > Owner ( ) ) ) ;
}
return ( false ) ;
}
/***********************************************************************************************
* HouseClass : : Make_Ally - - Make the specified house an ally . *
* *
* This routine will make the specified house an ally to this house . An allied house will *
* not be considered a threat or potential target . *
* *
* INPUT : house - - The house to make an ally of this house . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 08 / 1995 JLB : Created . *
* 08 / 08 / 1995 JLB : Breaks off combat when ally commences . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Make_Ally ( HousesType house )
{
Validate ( ) ;
if ( house ! = HOUSE_NONE & & ! Is_Ally ( house ) ) {
/*
* * If in normal game play but the house is defeated , then don ' t allow the ally
* * key to work .
*/
if ( ! ScenarioInit & & ( IsDefeated | | house = = HOUSE_JP ) ) return ;
Allies | = ( 1 < < house ) ;
# ifdef CHEAT_KEYS
if ( Debug_Flag ) {
HouseClass * enemy = HouseClass : : As_Pointer ( house ) ;
if ( enemy & & ! enemy - > Is_Ally ( this ) ) {
enemy - > Make_Ally ( Class - > House ) ;
}
}
# endif
if ( ( Debug_Flag | | GameToPlay ! = GAME_NORMAL ) & & ! ScenarioInit ) {
char buffer [ 80 ] ;
/*
* * Sweep through all techno objects and perform a cheeseball tarcom clear to ensure
* * that fighting will most likely stop when the cease fire begins .
*/
for ( int index = 0 ; index < Logic . Count ( ) ; index + + ) {
ObjectClass * object = Logic [ index ] ;
if ( object & & ! object - > IsInLimbo & & object - > Owner ( ) = = Class - > House ) {
TARGET target = ( ( TechnoClass * ) object ) - > TarCom ;
if ( Target_Legal ( target ) & & As_Techno ( target ) ) {
if ( Is_Ally ( As_Techno ( target ) ) ) {
( ( TechnoClass * ) object ) - > TarCom = TARGET_NONE ;
}
}
}
}
sprintf ( buffer , Text_String ( TXT_HAS_ALLIED ) , Name , HouseClass : : As_Pointer ( house ) - > Name ) ;
Messages . Add_Message ( buffer , MPlayerTColors [ RemapColor ] , TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW , 1200 , 0 , 0 ) ;
Map . Flag_To_Redraw ( false ) ;
}
}
}
/***********************************************************************************************
* HouseClass : : Make_Enemy - - Make an enemy of the house specified . *
* *
* This routine will flag the house specified so that it will be an enemy to this house . *
* Enemy houses are legal targets for attack . *
* *
* INPUT : house - - The house to make an enemy of this house . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 08 / 1995 JLB : Created . *
* 07 / 27 / 1995 JLB : Making war is a bilateral aaction . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Make_Enemy ( HousesType house )
{
Validate ( ) ;
if ( house ! = HOUSE_NONE & & Is_Ally ( house ) ) {
HouseClass * enemy = HouseClass : : As_Pointer ( house ) ;
Allies & = ~ ( 1 < < house ) ;
if ( enemy & & enemy - > Is_Ally ( this ) ) {
enemy - > Allies & = ~ ( 1 < < Class - > House ) ;
}
if ( ( Debug_Flag | | GameToPlay ! = GAME_NORMAL ) & & ! ScenarioInit ) {
char buffer [ 80 ] ;
sprintf ( buffer , Text_String ( TXT_AT_WAR ) , Name , enemy - > Name ) ;
Messages . Add_Message ( buffer , MPlayerTColors [ RemapColor ] , TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW , 600 , 0 , 0 ) ;
Map . Flag_To_Redraw ( false ) ;
}
}
}
/***********************************************************************************************
* HouseClass : : Remap_Table - - Fetches the remap table for this house object . *
* *
* This routine will return with the remap table to use when displaying an object owned *
* by this house . If the object is blushing ( flashing ) , then the lightening remap table is *
* always used . The " unit " parameter allows proper remap selection for those houses that *
* have a different remap table for buildings or units . *
* *
* INPUT : blushing - - Is the object blushing ( flashing ) ? *
* *
* unit - - Is the object a vehicle or infantry ? *
* *
* OUTPUT : Returns with a pointer to the remap table to use when drawing this object . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 08 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
unsigned char const * HouseClass : : Remap_Table ( bool blushing , bool unit ) const
{
Validate ( ) ;
if ( blushing ) return ( & Map . FadingLight [ 0 ] ) ;
/*
* * For normal game play , return the TypeClass ' s remap table for this
* * house type
*/
if ( GameToPlay = = GAME_NORMAL ) {
/*
* * Special case exception for Nod and single player only . Remap
* * buildings to red as opposed to the default color of bluegrey .
*/
if ( ! unit & & Class - > House = = HOUSE_BAD ) {
return ( RemapRed ) ;
}
/*
* * Special case Jurassic missions to use the bluegrey remapping
*/
if ( Special . IsJurassic & & Class - > House = = HOUSE_MULTI4 ) {
return ( RemapLtBlue ) ;
}
return ( Class - > RemapTable ) ;
} else {
/*
* * For multiplayer games , return the remap table for this exact house instance .
*/
return ( RemapTable ) ;
}
}
/***********************************************************************************************
* HouseClass : : Suggested_New_Team - - Determine what team should be created . *
* *
* This routine examines the house condition and returns with the team that it thinks *
* should be created . The units that are not currently a member of a team are examined *
* to determine the team needed . *
* *
* INPUT : none *
* *
* OUTPUT : Returns with a pointer to the team type that should be created . If no team should *
* be created , then NULL is returned . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 08 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
TeamTypeClass const * HouseClass : : Suggested_New_Team ( bool alertcheck )
{
Validate ( ) ;
return ( TeamTypeClass : : Suggested_New_Team ( this , UScan , IScan , IsAlerted & & alertcheck ) ) ;
}
/***********************************************************************************************
* HouseClass : : Adjust_Threat - - Adjust threat for the region specified . *
* *
* This routine is called when the threat rating for a region needs to change . The region *
* and threat adjustment are provided . *
* *
* INPUT : region - - The region that adjustment is to occur on . *
* *
* threat - - The threat adjustment to perform . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 08 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Adjust_Threat ( int region , int threat )
{
Validate ( ) ;
static int _val [ ] = {
- MAP_REGION_WIDTH - 1 , - MAP_REGION_WIDTH , - MAP_REGION_WIDTH + 1 ,
- 1 , 0 , 1 ,
MAP_REGION_WIDTH - 1 , MAP_REGION_WIDTH , MAP_REGION_WIDTH + 1
} ;
static int _thr [ ] = {
2 , 1 , 2 ,
1 , 0 , 1 ,
2 , 1 , 2
} ;
int neg ;
int * val = & _val [ 0 ] ;
int * thr = & _thr [ 0 ] ;
if ( threat < 0 ) {
threat = - threat ;
neg = true ;
} else {
neg = false ;
}
for ( int lp = 0 ; lp < 9 ; lp + + ) {
Regions [ region + * val ] . Adjust_Threat ( threat > > * thr , neg ) ;
val + + ;
thr + + ;
}
}
/***********************************************************************************************
* HouseClass : : Begin_Production - - Starts production of the specified object type . *
* *
* This routine is called from the event system . It will start production for the object *
* type specified . This will be reflected in the sidebar as well as the house factory *
* tracking variables . *
* *
* INPUT : type - - The type of object to begin production on . *
* *
* id - - The subtype of object . *
* *
* OUTPUT : Returns with the reason why , or why not , production was started . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 08 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
ProdFailType HouseClass : : Begin_Production ( RTTIType type , int id )
{
Validate ( ) ;
int * factory = 0 ;
int result = true ;
bool initial_start = false ;
FactoryClass * fptr ;
TechnoTypeClass const * tech = Fetch_Techno_Type ( type , id ) ;
switch ( type ) {
case RTTI_AIRCRAFT :
case RTTI_AIRCRAFTTYPE :
factory = & AircraftFactory ;
break ;
case RTTI_UNIT :
case RTTI_UNITTYPE :
factory = & UnitFactory ;
break ;
case RTTI_BUILDING :
case RTTI_BUILDINGTYPE :
factory = & BuildingFactory ;
break ;
case RTTI_INFANTRY :
case RTTI_INFANTRYTYPE :
factory = & InfantryFactory ;
break ;
case RTTI_SPECIAL :
factory = & SpecialFactory ;
break ;
}
/*
* * Check for legality of the production object type suggested .
*/
if ( ! factory ) return ( PROD_ILLEGAL ) ;
/*
* * If the house is already busy producing the requested object , then
* * return with this failure code , unless we are restarting production .
*/
if ( * factory ! = - 1 ) {
fptr = Factories . Raw_Ptr ( * factory ) ;
if ( fptr - > Is_Building ( ) )
return ( PROD_CANT ) ;
} else {
fptr = new FactoryClass ( ) ;
if ( ! fptr ) return ( PROD_CANT ) ;
* factory = Factories . ID ( fptr ) ;
result = ( tech ) ? fptr - > Set ( * tech , * this ) : fptr - > Set ( id , * this ) ;
initial_start = true ;
/*
* * If set failed , we probably reached the production cap . Don ' t let the factory linger , preventing further production attempts .
* * ST - 3 / 17 / 2020 2 : 03 PM
*/
if ( ! result ) {
delete fptr ;
fptr = NULL ;
* factory = - 1 ;
}
}
if ( result ) {
fptr - > Start ( ) ;
/*
* * Link this factory to the sidebar so that proper graphic feedback
* * can take place .
*/
// Handle Glyphx multiplayer sidebar. ST - 3/26/2019 1:27PM
if ( GameToPlay = = GAME_GLYPHX_MULTIPLAYER ) {
if ( IsHuman ) {
Sidebar_Glyphx_Factory_Link ( * factory , type , id , this ) ;
}
} else {
if ( PlayerPtr = = this ) {
Map . Factory_Link ( * factory , type , id ) ;
}
}
return ( PROD_OK ) ;
}
return ( PROD_CANT ) ;
}
/***********************************************************************************************
* HouseClass : : Suspend_Production - - Temporarily puts production on hold . *
* *
* This routine is called from the event system whenever the production of the specified *
* type needs to be suspended . The suspended production will be reflected in the sidebar *
* as well as in the house control structure . *
* *
* INPUT : type - - The type of object that production is being suspended for . *
* *
* OUTPUT : Returns why , or why not , production was suspended . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 08 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
ProdFailType HouseClass : : Suspend_Production ( RTTIType type )
{
Validate ( ) ;
int * factory = 0 ;
switch ( type ) {
case RTTI_AIRCRAFT :
case RTTI_AIRCRAFTTYPE :
factory = & AircraftFactory ;
break ;
case RTTI_UNIT :
case RTTI_UNITTYPE :
factory = & UnitFactory ;
break ;
case RTTI_BUILDING :
case RTTI_BUILDINGTYPE :
factory = & BuildingFactory ;
break ;
case RTTI_INFANTRY :
case RTTI_INFANTRYTYPE :
factory = & InfantryFactory ;
break ;
case RTTI_SPECIAL :
factory = & SpecialFactory ;
break ;
}
/*
* * Check for legality of the production object type suggested .
*/
if ( ! factory ) return ( PROD_ILLEGAL ) ;
/*
* * If the house is already busy producing the requested object , then
* * return with this failure code .
*/
if ( * factory = = - 1 ) return ( PROD_CANT ) ;
/*
* * Create the factory pointer object .
* * If the factory could not be created , then report this error condition .
*/
FactoryClass * fptr = Factories . Raw_Ptr ( * factory ) ;
if ( ! fptr ) return ( PROD_CANT ) ;
/*
* * Actually suspend the production .
*/
fptr - > Suspend ( ) ;
/*
* * Tell the sidebar that it needs to be redrawn because of this .
*/
if ( PlayerPtr = = this ) {
Map . SidebarClass : : IsToRedraw = true ;
Map . SidebarClass : : Column [ 0 ] . IsToRedraw = true ;
Map . SidebarClass : : Column [ 1 ] . IsToRedraw = true ;
Map . Flag_To_Redraw ( false ) ;
}
return ( PROD_OK ) ;
}
/***********************************************************************************************
* HouseClass : : Abandon_Production - - Abandons production of item type specified . *
* *
* This routine is called from the event system whenever production must be abandoned for *
* the type specified . This will remove the factory and pending object from the sidebar as *
* well as from the house factory record . *
* *
* INPUT : type - - The object type that production is being suspended for . *
* *
* OUTPUT : Returns the reason why or why not , production was suspended . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 08 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
ProdFailType HouseClass : : Abandon_Production ( RTTIType type )
{
Validate ( ) ;
int * factory = 0 ;
switch ( type ) {
case RTTI_AIRCRAFT :
case RTTI_AIRCRAFTTYPE :
factory = & AircraftFactory ;
break ;
case RTTI_UNIT :
case RTTI_UNITTYPE :
factory = & UnitFactory ;
break ;
case RTTI_BUILDING :
case RTTI_BUILDINGTYPE :
factory = & BuildingFactory ;
break ;
case RTTI_INFANTRY :
case RTTI_INFANTRYTYPE :
factory = & InfantryFactory ;
break ;
case RTTI_SPECIAL :
factory = & SpecialFactory ;
break ;
}
/*
* * Check for legality of the production object type suggested .
*/
if ( ! factory ) return ( PROD_ILLEGAL ) ;
/*
* * If there is no factory to abandon , then return with a failure code .
*/
if ( * factory = = - 1 ) return ( PROD_CANT ) ;
/*
* * Fetch the factory pointer object .
*/
FactoryClass * fptr = Factories . Raw_Ptr ( * factory ) ;
if ( ! fptr ) return ( PROD_CANT ) ;
/*
* * Tell the sidebar that it needs to be redrawn because of this .
*/
// Handle Glyphx multiplayer sidebar. ST - 3/22/2019 2:01PM
if ( GameToPlay = = GAME_GLYPHX_MULTIPLAYER ) {
if ( IsHuman ) {
Sidebar_Glyphx_Abandon_Production ( type , * factory , this ) ;
// Need to clear pending object here?
}
} else {
if ( PlayerPtr = = this ) {
Map . Abandon_Production ( type , * factory ) ;
if ( type = = RTTI_BUILDINGTYPE | | type = = RTTI_BUILDING ) {
Map . PendingObjectPtr = 0 ;
Map . PendingObject = 0 ;
Map . PendingHouse = HOUSE_NONE ;
Map . Set_Cursor_Shape ( 0 ) ;
}
}
}
/*
* * Abandon production of the object .
*/
fptr - > Abandon ( ) ;
delete fptr ;
* factory = - 1 ;
return ( PROD_OK ) ;
}
/***********************************************************************************************
* HouseClass : : Special_Weapon_AI - - Fires special weapon . *
* *
* This routine will pick a good target to fire the special weapon specified . *
* *
* INPUT : id - - The special weapon id to fire . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 06 / 24 / 1995 PWG : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Special_Weapon_AI ( SpecialWeaponType id )
{
Validate ( ) ;
/*
* * Loop through all of the building objects on the map
* * and see which ones are available .
*/
BuildingClass * bestptr = NULL ;
int best = - 1 ;
for ( int index = 0 ; index < Buildings . Count ( ) ; index + + ) {
BuildingClass * b = Buildings . Ptr ( index ) ;
/*
* * If the building is valid , not in limbo , not in the process of
* * being destroyed and not our ally , then we can consider it .
*/
if ( b & & ! b - > IsInLimbo & & b - > Strength & & ! Is_Ally ( b ) ) {
if ( b - > Value ( ) > best | | best = = - 1 ) {
best = b - > Value ( ) ;
bestptr = b ;
}
}
}
if ( bestptr ) {
CELL cell = Coord_Cell ( bestptr - > Center_Coord ( ) ) ;
Place_Special_Blast ( id , cell ) ;
}
}
/***********************************************************************************************
* HouseClass : : Place_Special_Blast - - Place a special blast effect at location specified . *
* *
* This routine will create a blast effect at the cell specified . This is the result of *
* the special weapons . *
* *
* INPUT : id - - The special weapon id number . *
* *
* cell - - The location where the special weapon attack is to occur . *
* *
* OUTPUT : Was the special weapon successfully fired at the location specified ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 18 / 1995 JLB : commented . *
* 07 / 25 / 1995 JLB : Added scatter effect for nuclear bomb . *
* 07 / 28 / 1995 JLB : Revamped to use super weapon class controller . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Place_Special_Blast ( SpecialWeaponType id , CELL cell )
{
Validate ( ) ;
BuildingClass * launchsite = 0 ;
AnimClass * anim = 0 ;
// Added. ST - 12/2/2019 11:26AM
bool fired = false ;
const char * what = NULL ;
int index ;
switch ( id ) {
case SPC_ION_CANNON :
if ( IonCannon . Is_Ready ( ) ) {
anim = new AnimClass ( ANIM_ION_CANNON , Cell_Coord ( cell ) ) ;
2020-06-22 17:43:21 +01:00
if ( anim ) anim - > OwnerHouse = Class - > House ;
2020-05-27 20:16:20 +01:00
if ( this = = PlayerPtr ) {
Map . IsTargettingMode = false ;
}
IonCannon . Discharged ( PlayerPtr = = this ) ;
IsRecalcNeeded = true ;
fired = true ;
what = " ION " ;
}
break ;
case SPC_NUCLEAR_BOMB :
if ( NukeStrike . Is_Ready ( ) ) {
# ifdef NEVER
/*
* * Scatter the nuclear bomb impact point into an adjacent cell .
*/
for ( ; ; ) {
CELL newcell = Adjacent_Cell ( cell , Random_Pick ( FACING_N , FACING_COUNT ) ) ;
if ( Map . In_Radar ( newcell ) ) {
cell = newcell ;
break ;
}
}
# endif
/*
* * Search for a suitable launch site for this missile .
*/
for ( index = 0 ; index < Buildings . Count ( ) ; index + + ) {
BuildingClass * b = Buildings . Ptr ( index ) ;
if ( b & & ! b - > IsInLimbo & & b - > House = = this & & * b = = STRUCT_TEMPLE ) {
launchsite = b ;
break ;
}
}
/*
* * If a launch site was found , then proceed with the normal launch
* * sequence .
*/
if ( launchsite ) {
launchsite - > Assign_Mission ( MISSION_MISSILE ) ;
launchsite - > Commence ( ) ;
NukeDest = cell ;
NukePieces = 0 ;
} else {
/*
* * Only in the multiplayer version can the nuclear bomb be
* * sent from some off screen source .
*/
if ( GameToPlay = = GAME_NORMAL ) return ( false ) ;
/*
* * Since no launch site was found , just bring the missile in
* * directly from the North map edge .
*/
BulletClass * bullet = new BulletClass ( BULLET_NUKE_DOWN ) ;
if ( bullet ) {
COORDINATE start = Cell_Coord ( XY_Cell ( Cell_X ( cell ) , 0 ) ) ;
bullet - > Assign_Target ( : : As_Target ( cell ) ) ;
bullet - > Payback = NULL ;
bullet - > Strength = 1 ;
if ( ! bullet - > Unlimbo ( start , DIR_S ) ) {
delete bullet ;
} else {
bullet - > PrimaryFacing . Set_Current ( DIR_S ) ;
}
Speak ( VOX_INCOMING_NUKE ) ; // "Nuclear Warhead Approaching" - "NUKE1"
Sound_Effect ( VOC_NUKE_FIRE , start ) ;
}
}
if ( this = = PlayerPtr ) {
Map . IsTargettingMode = false ;
}
NukeStrike . Discharged ( this = = PlayerPtr ) ;
IsRecalcNeeded = true ;
fired = true ;
what = " NUKE " ;
}
break ;
case SPC_AIR_STRIKE :
if ( AirStrike . Is_Ready ( ) ) {
int strike = 1 ;
if ( GameToPlay = = GAME_NORMAL ) {
strike = Bound ( BuildLevel / 3 , 1 , 3 ) ;
} else {
strike = Bound ( MPlayerUnitCount / 5 , 1 , 3 ) ;
}
Create_Air_Reinforcement ( this , AIRCRAFT_A10 , strike , MISSION_HUNT , : : As_Target ( cell ) , TARGET_NONE ) ;
if ( this = = PlayerPtr ) {
Map . IsTargettingMode = false ;
}
AirStrike . Discharged ( this = = PlayerPtr ) ;
IsRecalcNeeded = true ;
fired = true ;
what = " AIR " ;
}
break ;
}
/*
* * Maybe trigger an achivement . ST - 12 / 2 / 2019 11 : 25 AM
*/
if ( IsHuman & & fired & & what ) {
On_Achievement_Event ( this , " SUPERWEAPON_FIRED " , what ) ;
}
return ( true ) ;
}
/***********************************************************************************************
* HouseClass : : Place_Object - - Places the object ( building ) at location specified . *
* *
* This routine is called when a building has been produced and now must be placed on *
* the map . When the player clicks on the map , this routine is ultimately called when the *
* event passes through the event queue system . *
* *
* INPUT : type - - The object type to place . The actual object is lifted from the sidebar . *
* *
* *
* cell - - The location to place the object on the map . *
* *
* OUTPUT : Was the placement successful ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 18 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
extern void On_Ping ( const HouseClass * player_ptr , COORDINATE coord ) ;
bool HouseClass : : Place_Object ( RTTIType type , CELL cell )
{
Validate ( ) ;
TechnoClass * tech = 0 ;
FactoryClass * factory = 0 ;
switch ( type ) {
case RTTI_AIRCRAFT :
case RTTI_AIRCRAFTTYPE :
if ( AircraftFactory ! = - 1 ) {
factory = Factories . Raw_Ptr ( AircraftFactory ) ;
}
break ;
case RTTI_INFANTRY :
case RTTI_INFANTRYTYPE :
if ( InfantryFactory ! = - 1 ) {
factory = Factories . Raw_Ptr ( InfantryFactory ) ;
}
break ;
case RTTI_UNIT :
case RTTI_UNITTYPE :
if ( UnitFactory ! = - 1 ) {
factory = Factories . Raw_Ptr ( UnitFactory ) ;
}
break ;
case RTTI_BUILDING :
case RTTI_BUILDINGTYPE :
if ( BuildingFactory ! = - 1 ) {
factory = Factories . Raw_Ptr ( BuildingFactory ) ;
}
break ;
}
/*
* * Only if there is a factory active for this type , can it be " placed " .
* * In the case of a missing factory , then this request is completely bogus - -
* * ignore it . This might occur if , between two events to exit the same
* * object , the mouse was clicked on the sidebar to start building again .
* * The second placement event should NOT try to place the object that is
* * just starting construction .
*/
if ( factory & & factory - > Has_Completed ( ) ) {
tech = factory - > Get_Object ( ) ;
if ( cell = = - 1 ) {
TechnoClass * pending = factory - > Get_Object ( ) ;
if ( pending ) {
TechnoClass * builder = pending - > Who_Can_Build_Me ( false , false ) ;
TechnoTypeClass const * object_type = pending - > Techno_Type_Class ( ) ;
if ( builder & & builder - > Exit_Object ( pending ) ) {
/*
* * Since the object has left the factory under its own power , delete
* * the production manager tied to this slot in the sidebar . Its job
* * has been completed .
*/
factory - > Set_Is_Blocked ( false ) ;
factory - > Completed ( ) ;
Abandon_Production ( type ) ;
/*
* * Could be tied to an achievement . ST - 11 / 11 / 2019 11 : 56 AM
*/
if ( IsHuman ) {
if ( object_type ) {
On_Achievement_Event ( this , " UNIT_CONSTRUCTED " , object_type - > IniName ) ;
}
if ( pending - > IsActive ) {
On_Ping ( this , pending - > Center_Coord ( ) ) ;
}
}
} else {
/*
* * The object could not leave under it ' s own power . Just wait
* * until the player tries to place the object again .
*/
/*
* * Flag that it ' s blocked so we can re - try the exit later .
* * This would have been a bad idea under the old peer - peer code since it would have pumped events into
* * the queue too often . ST - 2 / 25 / 2020 11 : 56 AM
*/
factory - > Set_Is_Blocked ( true ) ;
return ( false ) ;
}
}
} else {
if ( tech ) {
TechnoClass * builder = tech - > Who_Can_Build_Me ( false , false ) ;
if ( builder ) {
/*
* * Ensures that the proximity check is performed even when the building is
* * placed by way of a remote event .
*/
if ( tech - > What_Am_I ( ) ! = RTTI_BUILDING | | ( ( BuildingClass * ) tech ) - > Passes_Proximity_Check ( cell ) ) {
builder - > Transmit_Message ( RADIO_HELLO , tech ) ;
if ( tech - > Unlimbo ( Cell_Coord ( cell ) ) ) {
factory - > Completed ( ) ;
Abandon_Production ( type ) ;
if ( PlayerPtr = = this ) {
Sound_Effect ( VOC_SLAM ) ;
Map . Set_Cursor_Shape ( 0 ) ;
Map . PendingObjectPtr = 0 ;
Map . PendingObject = 0 ;
Map . PendingHouse = HOUSE_NONE ;
}
return ( true ) ;
} else {
if ( this = = PlayerPtr ) {
Speak ( VOX_DEPLOY ) ;
}
}
builder - > Transmit_Message ( RADIO_OVER_OUT ) ;
}
}
return ( false ) ;
} else {
// Play a bad sound here?
return ( false ) ;
}
}
}
return ( true ) ;
}
/***********************************************************************************************
* HouseClass : : Manual_Place - - Inform display system of building placement mode . *
* *
* This routine will inform the display system that building placement mode has begun . *
* The cursor will be created that matches the layout of the building shape . *
* *
* INPUT : builder - - The factory that is building this object . *
* *
* object - - The building that is going to be placed down on the map . *
* *
* OUTPUT : Was the building placement mode successfully initiated ? *
* *
* WARNINGS : This merely adjusts the cursor shape . Nothing that affects networked games *
* is affected . *
* *
* HISTORY : *
* 05 / 04 / 1995 JLB : Created . *
* 05 / 30 / 1995 JLB : Uses the Bib_And_Offset ( ) function to determine bib size . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Manual_Place ( BuildingClass * builder , BuildingClass * object )
{
Validate ( ) ;
if ( this = = PlayerPtr & & ! Map . PendingObject & & builder & & object ) {
/*
* * Ensures that object selection doesn ' t remain when
* * building placement takes place .
*/
Unselect_All ( ) ;
Map . Repair_Mode_Control ( 0 ) ;
Map . Sell_Mode_Control ( 0 ) ;
Map . PendingObject = object - > Class ;
Map . PendingObjectPtr = object ;
Map . PendingHouse = Class - > House ;
Map . Set_Cursor_Shape ( object - > Occupy_List ( true ) ) ;
Map . Set_Cursor_Pos ( Coord_Cell ( builder - > Coord ) ) ;
builder - > Mark ( MARK_CHANGE ) ;
return ( true ) ;
}
return ( false ) ;
}
# ifdef OBSOLETE
/***********************************************************************************************
* HouseClass : : Init_Ion_Cannon - - Initialize the ion cannon countdown . *
* *
* This routine will initiate the ion cannon charging countdown . It will add the ion *
* cannon to the sidebar if it isn ' t there and it is specified to be added . *
* *
* INPUT : first_time - - Set to true if the ion cannon must be added to the sidebar . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 18 / 1995 JLB : commented *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Init_Ion_Cannon ( SpecialControlType control )
{
Validate ( ) ;
switch ( control ) {
case CONTROL_RESET :
if ( IonCannonPresent ) {
IonOldStage = - 1 ;
IonControl . Set ( ION_CANNON_GONE_TIME ) ;
if ( PlayerPtr = = this ) {
Map . Add ( RTTI_SPECIAL , SPC_ION_CANNON ) ;
if ( ! ScenarioInit ) {
Speak ( VOX_ION_CHARGING ) ;
}
}
}
break ;
/*
* * Adds the special no - prerequisite ion cannon option .
*/
case CONTROL_ONE_TIME :
if ( ! IonCannonPresent ) {
Init_Ion_Cannon ( CONTROL_ADD ) ;
IonOneTimeFlag = true ;
}
break ;
/*
* * Adds the normal legitimate ion cannon option . If there was
* * already a one - time ion cannon available , the charging state
* * is NOT interrupted .
*/
case CONTROL_ADD :
IonOneTimeFlag = false ;
if ( ! IconCannonPresent ) {
IonCannonPresent = true ;
IonReady = false ;
Init_Ion_Cannon ( CONTROL_RESET ) ;
}
break ;
case CONTROL_REMOVE :
break ;
}
if ( ! ( first_time & & IonCannonPresent ) ) {
if ( IonCannonPresent & & IonOneTimeFlag ) {
IonOneTimeFlag = false ;
if ( this = = PlayerPtr ) Map . Recalc ( ) ;
return ;
}
if ( first_time & & this = = PlayerPtr ) {
Map . Add ( RTTI_SPECIAL , SPC_ION_CANNON ) ;
}
if ( ! ScenarioInit ) {
if ( this = = PlayerPtr ) {
Speak ( VOX_ION_CHARGING ) ;
}
}
IonControl . Set ( ION_CANNON_GONE_TIME ) ;
IonCannonPresent = true ;
IonReady = false ;
IonOldStage = - 1 ;
IonOneTimeFlag = one_time_effect ;
} else {
if ( first_time & & IonCannonPresent & & ! one_time_effect & & IonOneTimeFlag ) {
IonOneTimeFlag = false ;
}
}
}
# ifdef NEVER
void HouseClass : : Init_Ion_Cannon ( bool first_time , bool one_time_effect )
{
Validate ( ) ;
if ( ! ( first_time & & IonCannonPresent ) ) {
if ( IonCannonPresent & & IonOneTimeFlag ) {
IonOneTimeFlag = false ;
if ( this = = PlayerPtr ) Map . Recalc ( ) ;
return ;
}
if ( first_time & & this = = PlayerPtr ) {
Map . Add ( RTTI_SPECIAL , SPC_ION_CANNON ) ;
}
if ( ! ScenarioInit ) {
if ( this = = PlayerPtr ) {
Speak ( VOX_ION_CHARGING ) ;
}
}
IonControl . Set ( ION_CANNON_GONE_TIME ) ;
IonCannonPresent = true ;
IonReady = false ;
IonOldStage = - 1 ;
IonOneTimeFlag = one_time_effect ;
} else {
if ( first_time & & IonCannonPresent & & ! one_time_effect & & IonOneTimeFlag ) {
IonOneTimeFlag = false ;
}
}
}
# endif
/***********************************************************************************************
* HouseClass : : Remove_Ion_Cannon - - Disables the ion cannon . *
* *
* This routine will disable the ion cannon . It is called when the ion cannon cannot *
* establish a command link to the ground ( usually when there is insufficient power ) . *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 18 / 1995 JLB : commented *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Remove_Ion_Cannon ( void )
{
Validate ( ) ;
if ( IonCannonPresent ) {
IonCannonPresent = false ;
IonOneTimeFlag = false ;
IonReady = false ;
IonControl . Clear ( ) ;
IonOldStage = - 1 ;
}
}
# endif
/***************************************************************************
* HouseClass : : Clobber_All - - removes house & all its objects *
* *
* INPUT : *
* none . *
* *
* OUTPUT : *
* none . *
* *
* WARNINGS : *
* none . *
* *
* HISTORY : *
* 05 / 16 / 1995 BRR : Created . *
* 06 / 09 / 1995 JLB : Handles aircraft . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Clobber_All ( void )
{
Validate ( ) ;
int i ;
for ( i = 0 ; i < : : Aircraft . Count ( ) ; i + + ) {
if ( : : Aircraft . Ptr ( i ) - > House = = this ) {
delete : : Aircraft . Ptr ( i ) ;
i - - ;
}
}
for ( i = 0 ; i < : : Units . Count ( ) ; i + + ) {
if ( : : Units . Ptr ( i ) - > House = = this ) {
delete : : Units . Ptr ( i ) ;
i - - ;
}
}
for ( i = 0 ; i < Infantry . Count ( ) ; i + + ) {
if ( Infantry . Ptr ( i ) - > House = = this ) {
delete Infantry . Ptr ( i ) ;
i - - ;
}
}
for ( i = 0 ; i < Buildings . Count ( ) ; i + + ) {
if ( Buildings . Ptr ( i ) - > House = = this ) {
delete Buildings . Ptr ( i ) ;
i - - ;
}
}
for ( i = 0 ; i < TeamTypes . Count ( ) ; i + + ) {
if ( TeamTypes . Ptr ( i ) - > House = = Class - > House ) {
delete TeamTypes . Ptr ( i ) ;
i - - ;
}
}
for ( i = 0 ; i < Triggers . Count ( ) ; i + + ) {
if ( Triggers . Ptr ( i ) - > House = = Class - > House ) {
delete Triggers . Ptr ( i ) ;
i - - ;
}
}
delete this ;
}
# ifdef NEVER
/***********************************************************************************************
* HouseClass : : Init_Nuke_Bomb - - Adds ( if necessary ) the atom bomb to the sidebar . *
* *
* Use this routine whenever a piece of atom bomb has been discovered ( also at scenario *
* start ) . It will add the nuclear bomb button to the sidebar if necessary . *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 18 / 1995 JLB : commented *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Init_Nuke_Bomb ( bool first_time , bool one_time_effect )
{
Validate ( ) ;
if ( ! first_time | | ! NukePresent ) {
if ( NukePresent & & NukeOneTimeFlag ) {
NukeOneTimeFlag = false ;
if ( this = = PlayerPtr ) Map . Recalc ( ) ;
return ;
}
if ( first_time & & this = = PlayerPtr ) {
Map . Add ( RTTI_SPECIAL , SPC_NUCLEAR_BOMB ) ;
}
NukeControl . Set ( NUKE_GONE_TIME ) ;
NukePresent = true ;
NukeReady = false ;
NukeOldStage = - 1 ;
NukeOneTimeFlag = one_time_effect ;
} else {
if ( ! one_time_effect & & NukeOneTimeFlag ) {
NukeOneTimeFlag = false ;
}
}
}
/***********************************************************************************************
* HouseClass : : Remove_Nuke_Bomb - - Removes the nuclear bomb from the sidebar . *
* *
* This routine will remove the nuclear bomb from the sidebar . It should be called when *
* the nuclear strike has been launched . *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 18 / 1995 JLB : commented *
* 07 / 25 / 1995 JLB : Handles recharge reset logic . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Remove_Nuke_Bomb ( void )
{
Validate ( ) ;
if ( NukePresent & & ! NukeOneTimeFlag ) {
NukePresent = false ;
NukeControl . Clear ( ) ;
NukeOldStage = - 1 ;
NukeReady = false ;
}
}
/***********************************************************************************************
* HouseClass : : Init_Air_Strike - - Add ( or reset ) the air strike sidebar button . *
* *
* This routine will activate ( add if so indicated ) the air strike button to the sidebar . *
* Call this routine when events indicate that a special air strike is available . *
* *
* INPUT : first_time - - If the air strike button is to be added , then this will be true . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 18 / 1995 JLB : commented *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Init_Air_Strike ( bool first_time , bool one_time_effect )
{
Validate ( ) ;
if ( ! ( first_time & & AirPresent ) ) {
if ( AirPresent & & AirOneTimeFlag ) {
AirOneTimeFlag = false ;
AirPresent = false ;
Map . Recalc ( ) ;
return ;
}
if ( first_time ) {
if ( PlayerPtr = = this ) {
Map . Add ( RTTI_SPECIAL , SPC_AIR_STRIKE ) ;
}
AirControl . Set ( 0 ) ;
} else {
AirControl . Set ( AIR_CANNON_GONE_TIME ) ;
}
AirReady = first_time ;
AirPresent = true ;
AirOldStage = - 1 ;
AirOneTimeFlag = one_time_effect ;
if ( AirReady & & ! IsHuman ) {
Special_Weapon_AI ( SPC_AIR_STRIKE ) ;
}
} else {
if ( first_time & & AirPresent & & ! one_time_effect & & AirOneTimeFlag ) {
AirOneTimeFlag = false ;
}
}
}
/***********************************************************************************************
* HouseClass : : Remove_Air_Strike - - Removes the air strike button from the sidebar . *
* *
* This routine will remove the air strike button from the sidebar . Call this routine when *
* the air strike has been launched . *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 18 / 1995 JLB : commented *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Remove_Air_Strike ( void )
{
Validate ( ) ;
AirPresent = false ;
AirReady = false ;
AirControl . Clear ( ) ;
AirOldStage = - 1 ;
}
/***********************************************************************************************
* HouseClass : : Make_Air_Strike_Available - - Make the airstrike available . *
* *
* This routine will make the airstrike available . Typically , this results in a new icon *
* added to the sidebar . *
* *
* INPUT : present - - The the airstrike being added ? *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 06 / 20 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Make_Air_Strike_Available ( bool present , bool one_time_effect )
{
Validate ( ) ;
Init_Air_Strike ( true , one_time_effect ) ;
AirPresent = present ;
}
# endif
/***********************************************************************************************
* HouseClass : : Add_Nuke_Piece - - Add a nuclear piece to the collection . *
* *
* This routine will a the specified nuclear piece to the house collection of parts . When *
* all the pieces have been added , a nuclear strike ability is made available . *
* *
* INPUT : piece - - The nuclear piece to add . If equal to " -1 " , then the next possible piece *
* is added . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 06 / 20 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Add_Nuke_Piece ( int piece )
{
Validate ( ) ;
if ( piece = = - 1 ) {
piece = 1 ;
if ( ! ( NukePieces & 0x01 ) ) {
piece = 1 ;
}
if ( ! ( NukePieces & 0x02 ) ) {
piece = 2 ;
}
if ( ! ( NukePieces & 0x04 ) ) {
piece = 3 ;
}
}
NukePieces | = 1 < < ( piece - 1 ) ;
// Init_Nuke_Bomb(false);
}
/***********************************************************************************************
* HouseClass : : Detach - - Removes specified object from house tracking systems . *
* *
* This routine is called when an object is to be removed from the game system . If the *
* specified object is part of the house tracking system , then it will be removed . *
* *
* INPUT : target - - The target value of the object that is to be removed from the game . *
* *
* all - - Is the target going away for good as opposed to just cloaking / hiding ? *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 18 / 1995 JLB : commented *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Detach ( TARGET , bool )
{
Validate ( ) ;
// if (LaunchSite == target) {
// LaunchSite = TARGET_NONE;
// }
}
/***********************************************************************************************
* HouseClass : : Does_Enemy_Building_Exist - - Checks for enemy building of specified type . *
* *
* This routine will examine the enemy houses and if there is a building owned by one *
* of those house , true will be returned . *
* *
* INPUT : btype - - The building type to check for . *
* *
* OUTPUT : Does a building of the specified type exist for one of the enemy houses ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 23 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Does_Enemy_Building_Exist ( StructType btype ) const
{
Validate ( ) ;
int bflag = 1L < < btype ;
for ( HousesType index = HOUSE_FIRST ; index < HOUSE_COUNT ; index + + ) {
HouseClass * house = HouseClass : : As_Pointer ( index ) ;
if ( house & & ! Is_Ally ( house ) & & ( house - > BScan & bflag ) ! = 0 ) {
return ( true ) ;
}
}
return ( false ) ;
}
/***********************************************************************************************
* HouseClass : : Suggest_New_Object - - Determine what would the next buildable object be . *
* *
* This routine will examine the house status and return with a techno type pointer to *
* the object type that it thinks should be created . The type is restricted to match the *
* type specified . Typical use of this routine is by computer controlled factories . *
* *
* INPUT : objecttype - - The type of object to restrict the scan for . *
* *
* OUTPUT : Returns with a pointer to a techno type for the object type that should be *
* created . If no object should be created , then NULL is returned . *
* *
* WARNINGS : This is a time consuming routine . Only call when necessary . *
* *
* HISTORY : *
* 05 / 23 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
TechnoTypeClass const * HouseClass : : Suggest_New_Object ( RTTIType objecttype ) const
{
Validate ( ) ;
TechnoTypeClass const * techno = NULL ;
# ifdef USE_RA_AI
//
// Copied from RA for AI. ST - 7/25/2019 3:58PM
//
if ( ! IsHuman & & GameToPlay ! = GAME_NORMAL ) {
switch ( objecttype ) {
case RTTI_AIRCRAFT :
case RTTI_AIRCRAFTTYPE :
if ( BuildAircraft ! = AIRCRAFT_NONE ) {
return ( & AircraftTypeClass : : As_Reference ( BuildAircraft ) ) ;
}
return ( NULL ) ;
/*
* * Unit construction is based on the rule that up to twice the number required
* * to fill all teams will be created .
*/
case RTTI_UNIT :
case RTTI_UNITTYPE :
if ( BuildUnit ! = UNIT_NONE ) {
return ( & UnitTypeClass : : As_Reference ( BuildUnit ) ) ;
}
return ( NULL ) ;
/*
* * Infantry construction is based on the rule that up to twice the number required
* * to fill all teams will be created .
*/
case RTTI_INFANTRY :
case RTTI_INFANTRYTYPE :
if ( BuildInfantry ! = INFANTRY_NONE ) {
return ( & InfantryTypeClass : : As_Reference ( BuildInfantry ) ) ;
}
return ( NULL ) ;
/*
* * Building construction is based upon the preconstruction list .
*/
case RTTI_BUILDING :
case RTTI_BUILDINGTYPE :
if ( BuildStructure ! = STRUCT_NONE ) {
return ( & BuildingTypeClass : : As_Reference ( BuildStructure ) ) ;
}
return ( NULL ) ;
}
return NULL ;
}
# endif //USE_RA_AI
switch ( objecttype ) {
/*
* * Unit construction is based on the rule that up to twice the number required
* * to fill all teams will be created .
*/
case RTTI_UNIT :
case RTTI_UNITTYPE :
if ( CurUnits < MaxUnit ) {
/*
* * A computer controlled house will try to build a replacement
* * harvester if possible . Never replace harvesters if the game
* * is in easy mode .
*/
if ( ! ( GameToPlay = = GAME_NORMAL & & PlayerPtr - > Difficulty = = DIFF_EASY ) & & ! IsHuman & & ( ActiveBScan & STRUCTF_REFINERY ) & & ! ( UScan & UNITF_HARVESTER ) ) {
techno = & UnitTypeClass : : As_Reference ( UNIT_HARVESTER ) ;
if ( techno - > Scenario < = BuildLevel ) break ;
techno = 0 ;
}
int counter [ UNIT_COUNT ] ;
if ( GameToPlay = = GAME_NORMAL ) {
memset ( counter , 0x00 , sizeof ( counter ) ) ;
} else {
for ( UnitType index = UNIT_FIRST ; index < UNIT_COUNT ; index + + ) {
if ( Can_Build ( index , Class - > House ) & & UnitTypeClass : : As_Reference ( index ) . Level < = BuildLevel ) {
counter [ index ] = 16 ;
} else {
counter [ index ] = 0 ;
}
}
}
/*
* * Build a list of the maximum of each type we wish to produce . This will be
* * twice the number required to fill all teams .
*/
int index ;
for ( index = 0 ; index < Teams . Count ( ) ; index + + ) {
TeamClass * tptr = Teams . Ptr ( index ) ;
if ( tptr ) {
TeamTypeClass const * team = tptr - > Class ;
if ( ( /*team->IsReinforcable || */ ! tptr - > IsFullStrength ) & & team - > House = = Class - > House ) {
for ( int subindex = 0 ; subindex < team - > ClassCount ; subindex + + ) {
if ( team - > Class [ subindex ] - > What_Am_I ( ) = = RTTI_UNITTYPE ) {
counter [ ( ( UnitTypeClass const * ) ( team - > Class [ subindex ] ) ) - > Type ] = 1 ;
// counter[((UnitTypeClass const *)(team->Class[subindex]))->Type] += team->DesiredNum[subindex]*2;
}
}
}
}
}
/*
* * Team types that are flagged as prebuilt , will always try to produce enough
* * to fill one team of this type regardless of whether there is a team active
* * of that type .
*/
for ( index = 0 ; index < TeamTypes . Count ( ) ; index + + ) {
TeamTypeClass const * team = TeamTypes . Ptr ( index ) ;
if ( team ) {
if ( team - > House = = Class - > House & & team - > IsPrebuilt & & ( ! team - > IsAutocreate | | IsAlerted ) ) {
for ( int subindex = 0 ; subindex < team - > ClassCount ; subindex + + ) {
if ( team - > Class [ subindex ] - > What_Am_I ( ) = = RTTI_UNITTYPE ) {
int subtype = ( ( UnitTypeClass const * ) ( team - > Class [ subindex ] ) ) - > Type ;
counter [ subtype ] = MAX ( counter [ subtype ] , ( int ) team - > DesiredNum [ subindex ] ) ;
}
}
}
}
}
/*
* * Reduce the theoretical maximum by the actual number of objects currently
* * in play .
*/
for ( int uindex = 0 ; uindex < Units . Count ( ) ; uindex + + ) {
UnitClass * unit = Units . Ptr ( uindex ) ;
if ( unit & & ! unit - > Team & & unit - > House = = this & & ( unit - > Mission ! = MISSION_GUARD_AREA & & unit - > Mission ! = MISSION_HUNT & & unit - > Mission ! = MISSION_STICKY & & unit - > Mission ! = MISSION_SLEEP ) ) {
counter [ unit - > Class - > Type ] - - ;
}
}
/*
* * Pick to build the most needed object but don ' t consider those object that
* * can ' t be built because of scenario restrictions or insufficient cash .
*/
int bestval = - 1 ;
int bestcount = 0 ;
UnitType bestlist [ UNIT_COUNT ] ;
for ( UnitType utype = UNIT_FIRST ; utype < UNIT_COUNT ; utype + + ) {
if ( counter [ utype ] > 0 & & Can_Build ( utype , Class - > House ) & & UnitTypeClass : : As_Reference ( utype ) . Cost_Of ( ) < = Available_Money ( ) ) {
if ( bestval = = - 1 | | bestval < counter [ utype ] ) {
bestval = counter [ utype ] ;
bestcount = 0 ;
}
bestlist [ bestcount + + ] = utype ;
}
}
/*
* * The unit type to build is now known . Fetch a pointer to the techno type class .
*/
if ( bestcount ) {
techno = & UnitTypeClass : : As_Reference ( bestlist [ Random_Pick ( 0 , bestcount - 1 ) ] ) ;
}
}
break ;
/*
* * Infantry construction is based on the rule that up to twice the number required
* * to fill all teams will be created .
*/
case RTTI_INFANTRY :
case RTTI_INFANTRYTYPE :
if ( CurUnits < MaxUnit ) {
int counter [ INFANTRY_COUNT ] ;
if ( GameToPlay = = GAME_NORMAL ) {
memset ( counter , 0x00 , sizeof ( counter ) ) ;
} else {
for ( InfantryType index = INFANTRY_FIRST ; index < INFANTRY_COUNT ; index + + ) {
if ( Can_Build ( index , Class - > House ) & & InfantryTypeClass : : As_Reference ( index ) . Level < = BuildLevel ) {
counter [ index ] = 16 ;
} else {
counter [ index ] = 0 ;
}
}
}
/*
* * Build a list of the maximum of each type we wish to produce . This will be
* * twice the number required to fill all teams .
*/
int index ;
for ( index = 0 ; index < Teams . Count ( ) ; index + + ) {
TeamClass * tptr = Teams . Ptr ( index ) ;
if ( tptr ) {
TeamTypeClass const * team = tptr - > Class ;
if ( ( team - > IsReinforcable | | ! tptr - > IsFullStrength ) & & team - > House = = Class - > House ) {
for ( int subindex = 0 ; subindex < team - > ClassCount ; subindex + + ) {
if ( team - > Class [ subindex ] - > What_Am_I ( ) = = RTTI_INFANTRYTYPE ) {
counter [ ( ( InfantryTypeClass const * ) ( team - > Class [ subindex ] ) ) - > Type ] + = team - > DesiredNum [ subindex ] + 1 ;
}
}
}
}
}
/*
* * Team types that are flagged as prebuilt , will always try to produce enough
* * to fill one team of this type regardless of whether there is a team active
* * of that type .
*/
for ( index = 0 ; index < TeamTypes . Count ( ) ; index + + ) {
TeamTypeClass const * team = TeamTypes . Ptr ( index ) ;
if ( team ) {
if ( team - > House = = Class - > House & & team - > IsPrebuilt & & ( ! team - > IsAutocreate | | IsAlerted ) ) {
for ( int subindex = 0 ; subindex < team - > ClassCount ; subindex + + ) {
if ( team - > Class [ subindex ] - > What_Am_I ( ) = = RTTI_INFANTRYTYPE ) {
int subtype = ( ( InfantryTypeClass const * ) ( team - > Class [ subindex ] ) ) - > Type ;
// counter[subtype] = 1;
counter [ subtype ] = MAX ( counter [ subtype ] , ( int ) team - > DesiredNum [ subindex ] ) ;
counter [ subtype ] = MIN ( counter [ subtype ] , 5 ) ;
}
}
}
}
}
/*
* * Reduce the theoretical maximum by the actual number of objects currently
* * in play .
*/
for ( int uindex = 0 ; uindex < Infantry . Count ( ) ; uindex + + ) {
InfantryClass * infantry = Infantry . Ptr ( uindex ) ;
if ( infantry & & ! infantry - > Team & & infantry - > House = = this & & ( infantry - > Mission ! = MISSION_GUARD_AREA & & infantry - > Mission ! = MISSION_HUNT & & infantry - > Mission ! = MISSION_STICKY & & infantry - > Mission ! = MISSION_SLEEP ) ) {
counter [ infantry - > Class - > Type ] - - ;
}
}
/*
* * Pick to build the most needed object but don ' t consider those object that
* * can ' t be built because of scenario restrictions or insufficient cash .
*/
int bestval = - 1 ;
int bestcount = 0 ;
InfantryType bestlist [ INFANTRY_COUNT ] ;
for ( InfantryType utype = INFANTRY_FIRST ; utype < INFANTRY_COUNT ; utype + + ) {
if ( counter [ utype ] > 0 & & Can_Build ( utype , Class - > House ) & & InfantryTypeClass : : As_Reference ( utype ) . Cost_Of ( ) < = Available_Money ( ) ) {
if ( bestval = = - 1 | | bestval < counter [ utype ] ) {
bestval = counter [ utype ] ;
bestcount = 0 ;
}
bestlist [ bestcount + + ] = utype ;
}
}
/*
* * The infantry type to build is now known . Fetch a pointer to the techno type class .
*/
if ( bestcount ) {
techno = & InfantryTypeClass : : As_Reference ( bestlist [ Random_Pick ( 0 , bestcount - 1 ) ] ) ;
}
}
break ;
/*
* * Building construction is based upon the preconstruction list .
*/
case RTTI_BUILDING :
case RTTI_BUILDINGTYPE :
if ( CurBuildings < MaxBuilding ) {
BaseNodeClass * node = Base . Next_Buildable ( ) ;
if ( node ) {
techno = & BuildingTypeClass : : As_Reference ( node - > Type ) ;
}
}
break ;
}
return ( techno ) ;
}
/***********************************************************************************************
* HouseClass : : Flag_Remove - - Removes the flag from the specified target . *
* *
* This routine will remove the flag attached to the specified target object or cell . *
* Call this routine before placing the object down . This is called inherently by the *
* the Flag_Attach ( ) functions . *
* *
* INPUT : target - - The target that the flag was attached to but will be removed from . *
* *
* set_home - - if true , clears the flag ' s waypoint designation *
* *
* OUTPUT : Was the flag successfully removed from the specified target ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 23 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Flag_Remove ( TARGET target , bool set_home )
{
Validate ( ) ;
bool rc = false ;
if ( Target_Legal ( target ) ) {
/*
* * Remove the flag from a unit
*/
UnitClass * object = As_Unit ( target ) ;
if ( object ) {
rc = object - > Flag_Remove ( ) ;
if ( rc & & FlagLocation = = target ) {
FlagLocation = TARGET_NONE ;
}
} else {
/*
* * Remove the flag from a cell
*/
CELL cell = As_Cell ( target ) ;
if ( Map . In_Radar ( cell ) ) {
rc = Map [ cell ] . Flag_Remove ( ) ;
if ( rc & & FlagLocation = = target ) {
FlagLocation = TARGET_NONE ;
}
}
}
/*
* * Handle the flag home cell :
* * If ' set_home ' is set , clear the home value & the cell ' s overlay
*/
if ( set_home ) {
if ( FlagHome ) {
Map [ FlagHome ] . Overlay = OVERLAY_NONE ;
Map . Flag_Cell ( FlagHome ) ;
FlagHome = 0 ;
}
}
}
return ( rc ) ;
}
/***********************************************************************************************
* HouseClass : : Flag_Attach - - Attach flag to specified cell ( or thereabouts ) . *
* *
* This routine will attach the house flag to the location specified . If the location *
* cannot contain the flag , then a suitable nearby location will be selected . *
* *
* INPUT : cell - - The desired cell location to place the flag . *
* *
* set_home - - if true , resets the flag ' s waypoint designation *
* *
* OUTPUT : Was the flag successfully placed ? *
* *
* WARNINGS : The cell picked for the flag might very likely not be the cell requested . *
* Check the FlagLocation value to determine the final cell resting spot . *
* *
* HISTORY : *
* 05 / 23 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Flag_Attach ( CELL cell , bool set_home )
{
Validate ( ) ;
bool rc ;
bool clockwise ;
FacingType rot ;
FacingType fcounter ;
/*
* * Randomly decide if we ' re going to search cells clockwise or counter -
* * clockwise
*/
clockwise = IRandom ( 0 , 1 ) ;
/*
* * Only continue if this cell is a legal placement cell .
*/
if ( Map . In_Radar ( cell ) ) {
/*
* * If the flag already exists , then it must be removed from the object
* * it is attached to .
*/
Flag_Remove ( FlagLocation , set_home ) ;
/*
* * Attach the flag to the cell specified . If it can ' t be placed , then pick
* * a nearby cell where it can be placed .
*/
CELL newcell = cell ;
rc = Map [ newcell ] . Flag_Place ( Class - > House ) ;
if ( ! rc ) {
/*
* * Loop for increasing distance from the desired cell .
* * For each distance , randomly pick a starting direction . Between
* * this and the clockwise / counterclockwise random value , the flag
* * should appear to be placed fairly randomly .
*/
for ( int dist = 1 ; dist < 32 ; dist + + ) {
/*
* * Clockwise search .
*/
if ( clockwise ) {
rot = ( FacingType ) IRandom ( FACING_N , FACING_NW ) ;
for ( fcounter = FACING_N ; fcounter < = FACING_NW ; fcounter + + ) {
newcell = Coord_Cell ( Coord_Move ( Cell_Coord ( cell ) , Facing_Dir ( rot ) , dist * 256 ) ) ;
if ( Map . In_Radar ( newcell ) & & Map [ newcell ] . Flag_Place ( Class - > House ) ) {
dist = 32 ;
rc = true ;
break ;
}
rot + + ;
if ( rot > FACING_NW ) rot = FACING_N ;
}
} else {
/*
* * Counter - clockwise search
*/
rot = ( FacingType ) IRandom ( FACING_N , FACING_NW ) ;
for ( fcounter = FACING_NW ; fcounter > = FACING_N ; fcounter - - ) {
newcell = Coord_Cell ( Coord_Move ( Cell_Coord ( cell ) , Facing_Dir ( rot ) , dist * 256 ) ) ;
if ( Map . In_Radar ( newcell ) & & Map [ newcell ] . Flag_Place ( Class - > House ) ) {
dist = 32 ;
rc = true ;
break ;
}
rot - - ;
if ( rot < FACING_N )
rot = FACING_NW ;
}
}
}
}
/*
* * If we ' ve found a spot for the flag , place the flag at the new cell .
* * if ' set_home ' is set , OR this house has no current flag home cell ,
* * mark that cell as this house ' s flag home cell . Otherwise fall back
* * on returning the flag to its home .
*/
if ( rc ) {
FlagLocation = As_Target ( newcell ) ;
if ( set_home | | FlagHome = = 0 ) {
Map [ newcell ] . Overlay = OVERLAY_FLAG_SPOT ;
FlagHome = newcell ;
}
}
else if ( FlagHome ! = 0 ) {
rc = Map [ FlagHome ] . Flag_Place ( Class - > House ) ;
}
return ( rc ) ;
}
return ( false ) ;
}
/***********************************************************************************************
* HouseClass : : Flag_Attach - - Attaches the house flag the specified unit . *
* *
* This routine will attach the house flag to the specified unit . This routine is called *
* when a unit drives over a cell containing a flag . *
* *
* INPUT : object - - Pointer to the object that the house flag is to be attached to . *
* *
* set_home - - if true , clears the flag ' s waypoint designation *
* *
* OUTPUT : Was the flag attached successfully ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 23 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Flag_Attach ( UnitClass * object , bool set_home )
{
Validate ( ) ;
if ( object & & ! object - > IsInLimbo ) {
Flag_Remove ( FlagLocation , set_home ) ;
/*
* * Attach the flag to the object .
*/
object - > Flag_Attach ( Class - > House ) ;
FlagLocation = object - > As_Target ( ) ;
return ( true ) ;
}
return ( false ) ;
}
extern void On_Defeated_Message ( const char * message , float timeout_seconds ) ;
/***************************************************************************
* HouseClass : : MPlayer_Defeated - - multiplayer ; house is defeated *
* *
* INPUT : *
* none . *
* *
* OUTPUT : *
* none . *
* *
* WARNINGS : *
* none . *
* *
* HISTORY : *
* 05 / 25 / 1995 BRR : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : MPlayer_Defeated ( void )
{
Validate ( ) ;
char txt [ 80 ] ;
int i , j , k ;
unsigned char id ;
HousesType house ;
HouseClass * hptr ;
HouseClass * hptr2 ;
int num_alive ;
int num_humans ;
int all_allies ;
int max_index ;
int max_count ;
int count ;
int score_index [ MAX_PLAYERS ] ; // array of each multi-player's index into
// the score array
/*------------------------------------------------------------------------
Set the defeat flag for this house
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
IsDefeated = true ;
# ifdef USE_RA_AI
/*
* * Moved in from RA for AI . ST - 7 / 24 / 2019 4 : 02 PM
*/
/*
* * If this is a computer controlled house , then all computer controlled
* * houses become paranoid .
*/
if ( IQ = = Rule . MaxIQ & & ! IsHuman & & Rule . IsComputerParanoid ) {
Computer_Paranoid ( ) ;
}
# endif // USE_RA_AI
/*------------------------------------------------------------------------
Remove this house ' s flag & flag home cell
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if ( Special . IsCaptureTheFlag ) {
if ( FlagLocation ) {
Flag_Remove ( FlagLocation , true ) ;
} else {
if ( FlagHome ) {
Flag_Remove ( FlagHome , true ) ;
}
}
}
2020-08-06 17:44:54 +01:00
/*
* * Remove any one - time superweapons the player might have .
*/
IonCannon . Remove ( true ) ;
AirStrike . Remove ( true ) ;
NukeStrike . Remove ( true ) ;
2020-05-27 20:16:20 +01:00
/*------------------------------------------------------------------------
If this is me :
- Set MPlayerObiWan , so I can only send messages to all players , and
not just one ( so I can ' t be obnoxiously omnipotent )
- Reveal the map
- Add my defeat message
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if ( PlayerPtr = = this ) {
MPlayerObiWan = 1 ;
HiddenPage . Clear ( ) ;
Map . Flag_To_Redraw ( true ) ;
/*.....................................................................
Pop up a message showing that I was defeated
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
sprintf ( txt , Text_String ( TXT_PLAYER_DEFEATED ) , MPlayerName ) ;
//Messages.Add_Message(txt, MPlayerTColors[MPlayerColorIdx], TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_FULLSHADOW, 600, 0, 0);
Map . Flag_To_Redraw ( false ) ;
int timeout = 600 ;
On_Defeated_Message ( txt , timeout * 60.0f / TICKS_PER_MINUTE ) ;
//Sound_Effect(VOC_INCOMING_MESSAGE);
} else {
/*------------------------------------------------------------------------
If it wasn ' t me , find out who was defeated
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if ( IsHuman ) {
sprintf ( txt , Text_String ( TXT_PLAYER_DEFEATED ) , Text_String ( TXT_UNKNOWN ) ) ;
id = 0 ;
for ( i = 0 ; i < MPlayerCount ; i + + ) {
house = MPlayerHouses [ i ] ;
if ( HouseClass : : As_Pointer ( house ) = = this ) {
sprintf ( txt , Text_String ( TXT_PLAYER_DEFEATED ) , MPlayerNames [ i ] ) ;
id = MPlayerID [ i ] ;
}
}
Messages . Add_Message ( txt , MPlayerTColors [ MPlayerID_To_ColorIndex ( id ) ] ,
TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW , 600 , 0 , 0 ) ;
Map . Flag_To_Redraw ( false ) ;
}
}
/*------------------------------------------------------------------------
Find out how many players are left alive .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
num_alive = 0 ;
num_humans = 0 ;
for ( i = 0 ; i < MPlayerMax ; i + + ) {
hptr = HouseClass : : As_Pointer ( ( HousesType ) ( HOUSE_MULTI1 + i ) ) ;
if ( hptr & & hptr - > IsDefeated = = 0 ) {
if ( hptr - > IsHuman )
num_humans + + ;
num_alive + + ;
}
}
/*------------------------------------------------------------------------
If all the houses left alive are allied with each other , then in reality
there ' s only one player left :
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
all_allies = 1 ;
for ( i = 0 ; i < MPlayerMax ; i + + ) {
/*.....................................................................
Get a pointer to this house
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
hptr = HouseClass : : As_Pointer ( ( HousesType ) ( HOUSE_MULTI1 + i ) ) ;
if ( ! hptr | | hptr - > IsDefeated )
continue ;
/*.....................................................................
Loop through all houses ; if there ' s one left alive that this house
isn ' t allied with , then all_allies will be false
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
for ( j = 0 ; j < MPlayerMax ; j + + ) {
hptr2 = HouseClass : : As_Pointer ( ( HousesType ) ( HOUSE_MULTI1 + j ) ) ;
if ( ! hptr2 )
continue ;
if ( ! hptr2 - > IsDefeated & & ! hptr - > Is_Ally ( hptr2 ) ) {
all_allies = 0 ;
break ;
}
}
if ( ! all_allies )
break ;
}
/*........................................................................
If all houses left are allies , set ' num_alive ' to 1 ; game over .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
if ( all_allies )
num_alive = 1 ;
/*------------------------------------------------------------------------
If there ' s only one human player left or no humans left , the game is over :
- Determine whether this player wins or loses , based on the state of the
MPlayerObiWan flag
- Find all players ' indices in the MPlayerScore array
- Tally up scores for this game
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if ( num_alive = = 1 | | num_humans = = 0 ) {
if ( PlayerPtr - > IsDefeated ) {
PlayerLoses = true ;
} else {
PlayerWins = true ;
}
/*---------------------------------------------------------------------
Find each player ' s score index
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
for ( i = 0 ; i < MPlayerCount ; i + + ) {
score_index [ i ] = - 1 ;
/*..................................................................
Search for this player ' s name in the MPlayerScore array
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
for ( j = 0 ; j < MPlayerNumScores ; j + + ) {
if ( ! stricmp ( MPlayerNames [ i ] , MPlayerScore [ j ] . Name ) ) {
score_index [ i ] = j ;
break ;
}
}
/*..................................................................
If the index is still - 1 , the name wasn ' t found ; add a new entry .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
if ( score_index [ i ] = = - 1 ) {
if ( MPlayerNumScores < MAX_MULTI_NAMES ) {
score_index [ i ] = MPlayerNumScores ;
MPlayerNumScores + + ;
} else {
/*...............................................................
For each player in the scores array , count the # of ' - 1 ' entries
from this game backwards ; the one with the most is the one that
hasn ' t played the longest ; replace him with this new guy .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
max_index = 0 ;
max_count = 0 ;
for ( j = 0 ; j < MPlayerNumScores ; j + + ) {
count = 0 ;
for ( k = MPlayerNumScores - 1 ; k > = 0 ; k - - ) {
if ( MPlayerScore [ j ] . Kills [ k ] = = - 1 ) {
count + + ;
} else {
break ;
}
}
if ( count > max_count ) {
max_count = count ;
max_index = j ;
}
}
score_index [ i ] = max_index ;
}
/*...............................................................
Initialize this score entry
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
MPlayerScore [ score_index [ i ] ] . Wins = 0 ;
strcpy ( MPlayerScore [ score_index [ i ] ] . Name , MPlayerNames [ i ] ) ;
for ( j = 0 ; j < MAX_MULTI_GAMES ; j + + )
MPlayerScore [ score_index [ i ] ] . Kills [ j ] = - 1 ;
}
/*..................................................................
Init this player ' s Kills to 0 ( - 1 means he didn ' t play this round ;
0 means he played but got no kills ) .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
MPlayerScore [ score_index [ i ] ] . Kills [ MPlayerCurGame ] = 0 ;
/*..................................................................
Init this player ' s color to his last - used color index
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
MPlayerScore [ score_index [ i ] ] . Color = MPlayerID_To_ColorIndex ( MPlayerID [ i ] ) ;
}
#if 0 // (This is the old method of tallying scores:
/*---------------------------------------------------------------------
Tally up the scores for this game :
- For each house :
- If this house is human & wasn ' t defeated , its the winner
- If this house was defeated , find out who did it & increment their
Kills value .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
for ( house = HOUSE_MULTI1 ; house < ( HOUSE_MULTI1 + MPlayerMax ) ; house + + ) {
hptr = HouseClass : : As_Pointer ( house ) ;
if ( ! hptr ) continue ;
if ( ! hptr - > IsDefeated ) {
/*...............................................................
If this is the winning house , find which player it was & increment
their ' Wins ' value
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
if ( hptr - > IsHuman ) {
for ( i = 0 ; i < MPlayerCount ; i + + ) {
if ( house = = MPlayerHouses [ i ] ) {
MPlayerScore [ score_index [ i ] ] . Wins + + ;
MPlayerWinner = score_index [ i ] ;
}
}
}
} else {
/*..................................................................
This house was defeated ; find which player who defeated him & increment
his ' Kills ' value for this game
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
for ( i = 0 ; i < MPlayerCount ; i + + ) {
if ( hptr - > WhoLastHurtMe = = MPlayerHouses [ i ] ) {
MPlayerScore [ score_index [ i ] ] . Kills [ MPlayerCurGame ] + + ;
}
}
}
}
# else // This is the new method:
/*---------------------------------------------------------------------
Tally up the scores for this game :
- For each player :
- If this player is undefeated this round , he ' s the winner
- Each player ' s Kills value is the sum of the unit ' s they killed
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
for ( i = 0 ; i < MPlayerCount ; i + + ) {
hptr = HouseClass : : As_Pointer ( MPlayerHouses [ i ] ) ;
/*..................................................................
If this house was undefeated , it must have been the winner . ( If
no human houses are undefeated , the computer won . )
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
if ( ! hptr - > IsDefeated ) {
MPlayerScore [ score_index [ i ] ] . Wins + + ;
MPlayerWinner = score_index [ i ] ;
}
/*..................................................................
Tally up all kills for this player
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
for ( house = HOUSE_FIRST ; house < HOUSE_COUNT ; house + + ) {
MPlayerScore [ score_index [ i ] ] . Kills [ MPlayerCurGame ] + =
hptr - > UnitsKilled [ house ] ;
MPlayerScore [ score_index [ i ] ] . Kills [ MPlayerCurGame ] + =
hptr - > BuildingsKilled [ house ] ;
}
}
# endif
/*---------------------------------------------------------------------
Destroy all the IPX connections , since we have to go through the rest
of the Main_Loop ( ) before we detect that the game is over , and we ' ll
end up waiting for frame sync packets from the other machines .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if ( GameToPlay = = GAME_IPX | | GameToPlay = = GAME_INTERNET ) {
i = 0 ;
while ( Ipx . Num_Connections ( ) & & ( i + + < 1000 ) ) {
id = Ipx . Connection_ID ( 0 ) ;
Ipx . Delete_Connection ( id ) ;
}
MPlayerCount = 0 ;
}
}
}
/***************************************************************************
* HouseClass : : Blowup_All - - blows up everything *
* *
* INPUT : *
* none . *
* *
* OUTPUT : *
* none . *
* *
* WARNINGS : *
* none . *
* *
* HISTORY : *
* 05 / 16 / 1995 BRR : Created . *
* 06 / 09 / 1995 JLB : Handles aircraft . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Blowup_All ( void )
{
Validate ( ) ;
int i ;
int damage ;
UnitClass * uptr ;
InfantryClass * iptr ;
BuildingClass * bptr ;
int count ;
WarheadType warhead ;
/*
* * Find everything owned by this house & blast it with a huge amount of damage
* * at zero range . Do units before infantry , so the units ' drivers are killed
* * too . Using Explosion_Damage is like dropping a big bomb right on the
* * object ; it will also damage anything around it .
*/
for ( i = 0 ; i < : : Units . Count ( ) ; i + + ) {
if ( : : Units . Ptr ( i ) - > House = = this & & ! : : Units . Ptr ( i ) - > IsInLimbo ) {
uptr = : : Units . Ptr ( i ) ;
/*
* * Some units can ' t be killed with one shot , so keep damaging them until
* * they ' re gone . The unit will destroy itself , and put an infantry in
* * its place . When the unit destroys itself , decrement ' i ' since
* * its pointer will be removed from the active pointer list .
*/
count = 0 ;
while ( : : Units . Ptr ( i ) = = uptr & & uptr - > Strength ) {
damage = 0x7fff ;
Explosion_Damage ( uptr - > Center_Coord ( ) , damage , NULL , WARHEAD_HE ) ;
count + + ;
if ( count > 5 ) {
delete uptr ;
break ;
}
}
i - - ;
}
}
/*
* * Destroy all aircraft owned by this house .
*/
for ( i = 0 ; i < : : Aircraft . Count ( ) ; i + + ) {
if ( : : Aircraft . Ptr ( i ) - > House = = this & & ! : : Aircraft . Ptr ( i ) - > IsInLimbo ) {
AircraftClass * aptr = : : Aircraft . Ptr ( i ) ;
damage = 0x7fff ;
aptr - > Take_Damage ( damage , 0 , WARHEAD_HE , NULL ) ;
if ( ! aptr - > IsActive ) {
i - - ;
}
}
}
/*
* * Buildings don ' t delete themselves when they die ; they shake the screen
* * and begin a countdown , so don ' t decrement ' i ' when it ' s destroyed .
*/
for ( i = 0 ; i < Buildings . Count ( ) ; i + + ) {
if ( Buildings . Ptr ( i ) - > House = = this & & ! Buildings . Ptr ( i ) - > IsInLimbo ) {
bptr = Buildings . Ptr ( i ) ;
count = 0 ;
bptr - > IsSurvivorless = true ;
while ( Buildings . Ptr ( i ) = = bptr & & bptr - > Strength ) {
damage = 0x7fff ;
Explosion_Damage ( bptr - > Center_Coord ( ) , damage , NULL , WARHEAD_HE ) ;
count + + ;
if ( count > 5 ) {
delete bptr ;
break ;
}
}
}
}
/*
* * Infantry don ' t delete themselves when they die ; they go into a death -
* * animation sequence , so there ' s no need to decrement ' i ' when they die .
* * Infantry should die by different types of warheads , so their death
* * anims aren ' t all synchronized .
*/
for ( i = 0 ; i < Infantry . Count ( ) ; i + + ) {
if ( Infantry . Ptr ( i ) - > House = = this & & ! Infantry . Ptr ( i ) - > IsInLimbo ) {
iptr = Infantry . Ptr ( i ) ;
count = 0 ;
while ( Infantry . Ptr ( i ) = = iptr & & iptr - > Strength ) {
damage = 0x7fff ;
warhead = ( WarheadType ) IRandom ( WARHEAD_SA , WARHEAD_FIRE ) ;
Explosion_Damage ( iptr - > Center_Coord ( ) , damage , NULL , warhead ) ;
if ( iptr - > IsActive ) {
damage = 0x7fff ;
iptr - > Take_Damage ( damage , 0 , warhead ) ;
}
count + + ;
if ( count > 5 ) {
delete iptr ;
break ;
}
}
}
}
# ifdef NEVER
/*
* * Just delete the teams & triggers for this house .
*/
for ( i = 0 ; i < TeamTypes . Count ( ) ; i + + ) {
if ( TeamTypes . Ptr ( i ) - > House = = Class - > House ) {
delete TeamTypes . Ptr ( i ) ;
i - - ;
}
}
for ( i = 0 ; i < Triggers . Count ( ) ; i + + ) {
if ( Triggers . Ptr ( i ) - > House = = Class - > House ) {
delete Triggers . Ptr ( i ) ;
i - - ;
}
}
# endif
}
/***********************************************************************************************
* HouseClass : : Flag_To_Die - - Flags the house to blow up soon . *
* *
* When this routine is called , the house will blow up after a period of time . Typically *
* this is called when the flag is captured or the HQ destroyed . *
* *
* INPUT : none *
* *
* OUTPUT : Was the house flagged to blow up ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 06 / 20 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Flag_To_Die ( void )
{
Validate ( ) ;
if ( ! IsToWin & & ! IsToDie & & ! IsToLose ) {
IsToDie = true ;
if ( IsV107 ) {
BorrowedTime = TICKS_PER_SECOND * 3 ;
} else {
BorrowedTime = TICKS_PER_SECOND * 1 ;
}
}
return ( IsToDie ) ;
}
/***********************************************************************************************
* HouseClass : : Flag_To_Win - - Flags the house to win soon . *
* *
* When this routine is called , the house will be declared the winner after a period of *
* time . *
* *
* INPUT : none *
* *
* OUTPUT : Was the house flagged to win ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 06 / 20 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Flag_To_Win ( void )
{
Validate ( ) ;
if ( ! IsToWin & & ! IsToDie & & ! IsToLose ) {
IsToWin = true ;
if ( IsV107 ) {
BorrowedTime = TICKS_PER_SECOND * 3 ;
} else {
BorrowedTime = TICKS_PER_SECOND * 1 ;
}
}
return ( IsToWin ) ;
}
/***********************************************************************************************
* HouseClass : : Flag_To_Lose - - Flags the house to die soon . *
* *
* When this routine is called , it will spell the doom of this house . In a short while *
* all of the object owned by this house will explode . Typical use of this routine is when *
* the flag has been captured or the command vehicle has been destroyed . *
* *
* INPUT : none *
* *
* OUTPUT : Has the doom been initiated ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 06 / 12 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Flag_To_Lose ( void )
{
Validate ( ) ;
IsToWin = false ;
if ( ! IsToDie & & ! IsToLose ) {
IsToLose = true ;
if ( IsV107 ) {
BorrowedTime = TICKS_PER_SECOND * 3 ;
} else {
BorrowedTime = TICKS_PER_SECOND * 1 ;
}
}
return ( IsToLose ) ;
}
/***********************************************************************************************
* HouseClass : : Init_Data - - Initializes the multiplayer color data . *
* *
* This routine is called when initializing the color and remap data for this house . The *
* primary user of this routine is the multiplayer version of the game . *
* *
* INPUT : color - - The color of this house . *
* *
* house - - The house that this should act like . *
* *
* credits - - The initial credits to assign to this house . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 07 / 29 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Init_Data ( PlayerColorType color , HousesType house , int credits )
{
Validate ( ) ;
Credits = InitialCredits = credits ;
VisibleCredits . Current = Credits ;
ActLike = house ;
RemapColor = color ;
switch ( color ) {
case REMAP_GOLD :
RemapTable = RemapGold ;
( ( unsigned char & ) Class - > Color ) = 157 ;
( ( unsigned char & ) Class - > BrightColor ) = 5 ;
break ;
case REMAP_RED :
RemapTable = RemapRed ;
( ( unsigned char & ) Class - > Color ) = 123 ;
( ( unsigned char & ) Class - > BrightColor ) = 127 ;
break ;
case REMAP_LTBLUE :
RemapTable = RemapLtBlue ;
( ( unsigned char & ) Class - > Color ) = 135 ;
( ( unsigned char & ) Class - > BrightColor ) = 2 ;
break ;
case REMAP_ORANGE :
RemapTable = RemapOrange ;
( ( unsigned char & ) Class - > Color ) = 26 ;
( ( unsigned char & ) Class - > BrightColor ) = 24 ;
break ;
case REMAP_GREEN :
RemapTable = RemapGreen ;
( ( unsigned char & ) Class - > Color ) = 167 ;
( ( unsigned char & ) Class - > BrightColor ) = 159 ;
break ;
case REMAP_BLUE :
RemapTable = RemapBlue ;
( ( unsigned char & ) Class - > Color ) = 203 ;
( ( unsigned char & ) Class - > BrightColor ) = 201 ;
break ;
}
}
/***********************************************************************************************
* HouseClass : : Power_Fraction - - Fetches the current power output rating . *
* *
* Use this routine to fetch the current power output as a fixed point fraction . The *
* value 0x0100 is 100 % power . *
* *
* INPUT : none *
* *
* OUTPUT : Returns with power rating as a fixed pointer number . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 07 / 22 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
int HouseClass : : Power_Fraction ( void ) const
{
Validate ( ) ;
if ( Power ) {
if ( Drain ) {
return ( Cardinal_To_Fixed ( Drain , Power ) ) ;
} else {
return ( 0x0100 ) ;
}
}
return ( 0 ) ;
}
/***********************************************************************************************
* HouseClass : : Has_Nuke_Device - - Deteremines if the house has a nuclear device . *
* *
* This routine checks to see if the house has a nuclear device to launch . A nuclear *
* device is available when the necessary parts have been retrieved in earlier scenarios *
* or if this is the multiplayer version . *
* *
* INPUT : none *
* *
* OUTPUT : Does the house have a nuclear device ? *
* *
* WARNINGS : This does not check to see if there is a suitable launch facility ( i . e . , the *
* Temple of Nod ) , only that there is a nuclear device potential . *
* *
* HISTORY : *
* 07 / 24 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Has_Nuke_Device ( void )
{
Validate ( ) ;
if ( GameToPlay ! = GAME_NORMAL | | ! IsHuman ) return ( true ) ;
return ( ( NukePieces & 0x07 ) = = 0x07 ) ;
}
/***********************************************************************************************
* HouseClass : : Sell_Wall - - Tries to sell the wall at the specified location . *
* *
* This routine will try to sell the wall at the specified location . If there is a wall *
* present and it is owned by this house , then it can be sold . *
* *
* INPUT : cell - - The cell that wall selling is desired . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 08 / 05 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Sell_Wall ( CELL cell )
{
Validate ( ) ;
if ( ( unsigned ) cell > 0 ) {
OverlayType overlay = Map [ cell ] . Overlay ;
if ( overlay ! = OVERLAY_NONE & & Map [ cell ] . Owner = = Class - > House ) {
OverlayTypeClass const & optr = OverlayTypeClass : : As_Reference ( overlay ) ;
if ( optr . IsWall ) {
BuildingTypeClass const * btype = NULL ;
switch ( overlay ) {
case OVERLAY_SANDBAG_WALL :
btype = & BuildingTypeClass : : As_Reference ( STRUCT_SANDBAG_WALL ) ;
break ;
case OVERLAY_CYCLONE_WALL :
btype = & BuildingTypeClass : : As_Reference ( STRUCT_CYCLONE_WALL ) ;
break ;
case OVERLAY_BRICK_WALL :
btype = & BuildingTypeClass : : As_Reference ( STRUCT_BRICK_WALL ) ;
break ;
case OVERLAY_BARBWIRE_WALL :
btype = & BuildingTypeClass : : As_Reference ( STRUCT_BARBWIRE_WALL ) ;
break ;
case OVERLAY_WOOD_WALL :
btype = & BuildingTypeClass : : As_Reference ( STRUCT_WOOD_WALL ) ;
break ;
default :
break ;
}
if ( btype ! = NULL & & ! btype - > IsUnsellable ) {
if ( PlayerPtr = = this ) {
Sound_Effect ( VOC_CASHTURN ) ;
}
Refund_Money ( btype - > Cost_Of ( ) / 2 ) ;
Map [ cell ] . Overlay = OVERLAY_NONE ;
Map [ cell ] . OverlayData = 0 ;
Map [ cell ] . Owner = HOUSE_NONE ;
Map [ cell ] . Wall_Update ( ) ;
2020-06-22 17:43:21 +01:00
CellClass * ncell = Map [ cell ] . Adjacent_Cell ( FACING_N ) ;
if ( ncell ) ncell - > Wall_Update ( ) ;
CellClass * wcell = Map [ cell ] . Adjacent_Cell ( FACING_W ) ;
if ( wcell ) wcell - > Wall_Update ( ) ;
CellClass * scell = Map [ cell ] . Adjacent_Cell ( FACING_S ) ;
if ( scell ) scell - > Wall_Update ( ) ;
CellClass * ecell = Map [ cell ] . Adjacent_Cell ( FACING_E ) ;
if ( ecell ) ecell - > Wall_Update ( ) ;
2020-05-27 20:16:20 +01:00
Map [ cell ] . Recalc_Attributes ( ) ;
Map [ cell ] . Redraw_Objects ( ) ;
ObjectClass : : Detach_This_From_All ( : : As_Target ( cell ) , true ) ;
}
}
}
}
}
/***********************************************************************************************
* HouseClass : : Check_Pertinent_Structures - - See if any useful structures remain *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 1 / 31 / 2020 3 : 34 PM ST : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Check_Pertinent_Structures ( void )
{
/*
* * New default win mode to avoid griefing . ST - 1 / 31 / 2020 3 : 33 PM
* *
* * Game is over when no pertinent structures remain
*/
if ( ! Special . IsEarlyWin ) {
return ;
}
if ( IsToDie | | IsToWin | | IsToLose ) {
return ;
}
2020-08-06 17:44:54 +01:00
// MBL 07.15.2020 - Prevention of recent issue with constant "player defeated logic" and message to client spamming
// Per https://jaas.ea.com/browse/TDRA-7433
//
if ( IsDefeated ) {
return ;
}
2020-05-27 20:16:20 +01:00
bool any_good_buildings = false ;
for ( int index = 0 ; index < Buildings . Count ( ) ; index + + ) {
BuildingClass * b = Buildings . Ptr ( index ) ;
if ( b & & b - > IsActive & & b - > House = = this ) {
if ( ! b - > Class - > IsWall ) {
if ( ! b - > IsInLimbo & & b - > Strength > 0 ) {
any_good_buildings = true ;
break ;
}
}
}
}
if ( ! any_good_buildings ) {
for ( int index = 0 ; index < Units . Count ( ) ; index + + ) {
UnitClass * unit = Units . Ptr ( index ) ;
if ( unit & & unit - > IsActive & & * unit = = UNIT_MCV & & unit - > House = = this ) {
if ( ! unit - > IsInLimbo & & unit - > Strength > 0 ) {
any_good_buildings = true ;
break ;
}
}
}
}
if ( ! any_good_buildings ) {
Flag_To_Die ( ) ;
}
}
/***********************************************************************************************
* HouseClass : : Init_Unit_Trackers - - Allocate the unit trackers for the house *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 4 / 23 / 2020 11 : 06 PM ST : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Init_Unit_Trackers ( void )
{
AircraftTotals = new UnitTrackerClass ( ( int ) AIRCRAFT_COUNT ) ;
InfantryTotals = new UnitTrackerClass ( ( int ) INFANTRY_COUNT ) ;
UnitTotals = new UnitTrackerClass ( ( int ) UNIT_COUNT ) ;
BuildingTotals = new UnitTrackerClass ( ( int ) STRUCT_COUNT ) ;
DestroyedAircraft = new UnitTrackerClass ( ( int ) AIRCRAFT_COUNT ) ;
DestroyedInfantry = new UnitTrackerClass ( ( int ) INFANTRY_COUNT ) ;
DestroyedUnits = new UnitTrackerClass ( ( int ) UNIT_COUNT ) ;
DestroyedBuildings = new UnitTrackerClass ( ( int ) STRUCT_COUNT ) ;
CapturedBuildings = new UnitTrackerClass ( ( int ) STRUCT_COUNT ) ;
TotalCrates = new UnitTrackerClass ( TOTAL_CRATE_TYPES ) ; //15 crate types
}
/***********************************************************************************************
* HouseClass : : Free_Unit_Trackers - - Free the unit trackers for the house *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 4 / 23 / 2020 11 : 06 PM ST : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Free_Unit_Trackers ( void )
{
if ( AircraftTotals ) {
delete AircraftTotals ;
AircraftTotals = NULL ;
}
if ( InfantryTotals ) {
delete InfantryTotals ;
InfantryTotals = NULL ;
}
if ( UnitTotals ) {
delete UnitTotals ;
UnitTotals = NULL ;
}
if ( BuildingTotals ) {
delete BuildingTotals ;
BuildingTotals = NULL ;
}
if ( DestroyedAircraft ) {
delete DestroyedAircraft ;
DestroyedAircraft = NULL ;
}
if ( DestroyedInfantry ) {
delete DestroyedInfantry ;
DestroyedInfantry = NULL ;
}
if ( DestroyedUnits ) {
delete DestroyedUnits ;
DestroyedUnits = NULL ;
}
if ( DestroyedBuildings ) {
delete DestroyedBuildings ;
DestroyedBuildings = NULL ;
}
if ( CapturedBuildings ) {
delete CapturedBuildings ;
CapturedBuildings = NULL ;
}
if ( TotalCrates ) {
delete TotalCrates ;
TotalCrates = NULL ;
}
}
# ifdef USE_RA_AI
/***********************************************************************************************
Below AI code imported from RA
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifndef ARRAY_SIZE
# define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
# endif
/*
* * In RA , Control is a container for other variables . In TD , they are defined in the class
*/
# define Control (*this)
/*
* * Percent_Chance - implementation similar to Red Alert
*/
inline bool Percent_Chance ( int percent )
{
return ( Random_Pick ( 0 , 99 ) < percent ) ;
}
/*
* * Engineer was renamed to RENOVATOR for RA
*/
# define INFANTRY_RENOVATOR INFANTRY_E7
TFixedIHeapClass < HouseClass : : BuildChoiceClass > HouseClass : : BuildChoice ;
/*
* * This is a replacement for the RA ' fixed ' round up function . It takes the equivalent of a ' fixed ' value , but returns just the integer part
* * ST - 7 / 26 / 2019 11 : 13 AM
*/
unsigned short Round_Up ( unsigned short val )
{
if ( ( val & 0xff ) = = 0 ) {
return val ;
}
val & = 0xff00 ;
val + = 0x0100 ;
val > > = 8 ;
return val ;
}
unsigned short fixed ( int val ) { return ( unsigned short ) val ; }
/***********************************************************************************************
* HouseClass : : Suggest_New_Building - - Examines the situation and suggests a building . *
* *
* This routine is called when a construction yard needs to know what to build next . It *
* will either examine the prebuilt base list or try to figure out what to build next *
* based on the current game situation . *
* *
* INPUT : none *
* *
* OUTPUT : Returns with a pointer to the building type class to build . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 27 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
BuildingTypeClass const * HouseClass : : Suggest_New_Building ( void ) const
{
//assert(Houses.ID(this) == ID);
if ( BuildStructure ! = STRUCT_NONE ) {
return ( & BuildingTypeClass : : As_Reference ( BuildStructure ) ) ;
}
return ( NULL ) ;
}
/***********************************************************************************************
* HouseClass : : Find_Building - - Finds a building of specified type . *
* *
* This routine is used to find a building of the specified type . This is particularly *
* useful for when some event requires a specific building instance . The nuclear missile *
* launch is a good example . *
* *
* INPUT : type - - The building type to scan for . *
* *
* zone - - The zone that the building must be located in . If no zone specific search *
* is desired , then pass ZONE_NONE . *
* *
* OUTPUT : Returns with a pointer to the building type requested . If there is no building *
* of the type requested , then NULL is returned . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 27 / 1995 JLB : Created . *
* 10 / 02 / 1995 JLB : Allows for zone specifics . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
BuildingClass * HouseClass : : Find_Building ( StructType type , ZoneType zone ) const
{
//assert(Houses.ID(this) == ID);
/*
* * Only scan if we KNOW there is at least one building of the type
* * requested .
*/
if ( BQuantity [ type ] > 0 ) {
/*
* * Search for a suitable launch site for this missile .
*/
for ( int index = 0 ; index < Buildings . Count ( ) ; index + + ) {
BuildingClass * b = Buildings . Ptr ( index ) ;
if ( b & & ! b - > IsInLimbo & & b - > House = = this & & * b = = type ) {
if ( zone = = ZONE_NONE | | Which_Zone ( b ) = = zone ) {
return ( b ) ;
}
}
}
}
return ( NULL ) ;
}
/***********************************************************************************************
* HouseClass : : Find_Build_Location - - Finds a suitable building location . *
* *
* This routine is used to find a suitable building location for the building specified . *
* The auto base building logic uses this when building the base for the computer . *
* *
* INPUT : building - - Pointer to the building that needs to be placed down . *
* *
* OUTPUT : Returns with the coordinate to place the building at . If there are no suitable *
* locations , then NULL is returned . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 27 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
COORDINATE HouseClass : : Find_Build_Location ( BuildingClass * building ) const
{
//assert(Houses.ID(this) == ID);
int zonerating [ ZONE_COUNT ] ;
struct {
int AntiAir ; // Average air defense for the base.
int AntiArmor ; // Average armor defense for the base.
int AntiInfantry ; // Average infantry defense for the base.
} zoneinfo = { 0 , 0 , 0 } ;
int antiair = building - > Anti_Air ( ) ;
int antiarmor = building - > Anti_Armor ( ) ;
int antiinfantry = building - > Anti_Infantry ( ) ;
bool adj = true ;
/*
* * Never place combat buildings adjacent to each other . This is partly
* * because combat buildings don ' t have a bib and jamming will occur as well
* * as because spacing defensive buildings out will yield a better
* * defense .
*/
if ( antiair | | antiarmor | | antiinfantry ) {
adj = false ;
}
/*
* * Determine the average zone strengths for the base . This value is
* * used to determine what zones are considered under or over strength .
*/
ZoneType z ;
for ( z = ZONE_NORTH ; z < ZONE_COUNT ; z + + ) {
zoneinfo . AntiAir + = ZoneInfo [ z ] . AirDefense ;
zoneinfo . AntiArmor + = ZoneInfo [ z ] . ArmorDefense ;
zoneinfo . AntiInfantry + = ZoneInfo [ z ] . InfantryDefense ;
}
zoneinfo . AntiAir / = ZONE_COUNT - ZONE_NORTH ;
zoneinfo . AntiArmor / = ZONE_COUNT - ZONE_NORTH ;
zoneinfo . AntiInfantry / = ZONE_COUNT - ZONE_NORTH ;
/*
* * Give each zone a rating for value . The higher the value the more desirable
* * to place the specified building in that zone . Factor the average value of
* * zone defense such that more weight is given to zones that are very under
* * defended .
*/
memset ( & zonerating [ 0 ] , ' \0 ' , sizeof ( zonerating ) ) ;
for ( z = ZONE_FIRST ; z < ZONE_COUNT ; z + + ) {
int diff ;
diff = zoneinfo . AntiAir - ZoneInfo [ z ] . AirDefense ;
if ( z = = ZONE_CORE ) diff / = 2 ;
if ( diff > 0 ) {
zonerating [ z ] + = min ( antiair , diff ) ;
}
diff = zoneinfo . AntiArmor - ZoneInfo [ z ] . ArmorDefense ;
if ( z = = ZONE_CORE ) diff / = 2 ;
if ( diff > 0 ) {
zonerating [ z ] + = min ( antiarmor , diff ) ;
}
diff = zoneinfo . AntiInfantry - ZoneInfo [ z ] . InfantryDefense ;
if ( z = = ZONE_CORE ) diff / = 2 ;
if ( diff > 0 ) {
zonerating [ z ] + = min ( antiinfantry , diff ) ;
}
}
/*
* * Now that each zone has been given a desirability rating , find the zone
* * with the greatest value and try to place the building in that zone .
*/
ZoneType zone = Random_Pick ( ZONE_FIRST , ZONE_WEST ) ;
int largest = 0 ;
for ( z = ZONE_FIRST ; z < ZONE_COUNT ; z + + ) {
if ( zonerating [ z ] > largest ) {
zone = z ;
largest = zonerating [ z ] ;
}
}
CELL zcell = Find_Cell_In_Zone ( building , zone ) ;
if ( zcell ) {
return ( Cell_Coord ( zcell ) ) ;
}
/*
* * Could not build in preferred zone , so try building in any zone .
*/
static ZoneType _zones [ ] = { ZONE_CORE , ZONE_NORTH , ZONE_SOUTH , ZONE_EAST , ZONE_WEST } ;
int start = Random_Pick ( 0U , ARRAY_SIZE ( _zones ) - 1 ) ;
for ( int zz = 0 ; zz < ARRAY_SIZE ( _zones ) ; zz + + ) {
ZoneType tryzone = _zones [ ( zz + start ) % ARRAY_SIZE ( _zones ) ] ;
zcell = Find_Cell_In_Zone ( building , tryzone ) ;
if ( zcell ) return ( zcell ) ;
}
return ( NULL ) ;
}
/***********************************************************************************************
* HouseClass : : Recalc_Center - - Recalculates the center point of the base . *
* *
* This routine will average the location of the base and record the center point . The *
* recorded center point is used to determine such things as how far the base is spread *
* out and where to protect the most . This routine should be called whenever a building *
* is created or destroyed . *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 28 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Recalc_Center ( void )
{
//assert(Houses.ID(this) == ID);
/*
* * First presume that there is no base . If there is a base , then these values will be
* * properly filled in below .
*/
Center = 0 ;
Radius = 0 ;
for ( ZoneType zone = ZONE_FIRST ; zone < ZONE_COUNT ; zone + + ) {
ZoneInfo [ zone ] . AirDefense = 0 ;
ZoneInfo [ zone ] . ArmorDefense = 0 ;
ZoneInfo [ zone ] . InfantryDefense = 0 ;
}
/*
* * Only process the center base size / position calculation if there are buildings to
* * consider . When no buildings for this house are present , then no processing need
* * occur .
*/
if ( CurBuildings > 0 ) {
int x = 0 ;
int y = 0 ;
int count = 0 ;
int index ;
for ( index = 0 ; index < Buildings . Count ( ) ; index + + ) {
BuildingClass const * b = Buildings . Ptr ( index ) ;
if ( b ! = NULL & & ! b - > IsInLimbo & & ( HouseClass * ) b - > House = = this & & b - > Strength > 0 ) {
/*
* * Give more " weight " to buildings that cost more . The presumption is that cheap
* * buildings don ' t affect the base disposition as much as the more expensive
* * buildings do .
*/
int weight = ( b - > Class - > Cost_Of ( ) / 1000 ) + 1 ;
for ( int i = 0 ; i < weight ; i + + ) {
x + = Coord_X ( b - > Center_Coord ( ) ) ;
y + = Coord_Y ( b - > Center_Coord ( ) ) ;
count + + ;
}
}
}
/*
* * This second check for quantity of buildings is necessary because the first
* * check against CurBuildings doesn ' t take into account if the building is in
* * limbo , but for base calculation , the limbo state disqualifies a building
* * from being processed . Thus , CurBuildings may indicate a base , but count may
* * not match .
*/
if ( count > 0 ) {
x / = count ;
y / = count ;
# ifdef NEVER
/*
* * Bias the center of the base away from the edges of the map .
*/
LEPTON left = Cell_To_Lepton ( Map . MapCellX + 10 ) ;
LEPTON top = Cell_To_Lepton ( Map . MapCellY + 10 ) ;
LEPTON right = Cell_To_Lepton ( Map . MapCellX + Map . MapCellWidth - 10 ) ;
LEPTON bottom = Cell_To_Lepton ( Map . MapCellY + Map . MapCellHeight - 10 ) ;
if ( x < left ) x = left ;
if ( x > right ) x = right ;
if ( y < top ) y = top ;
if ( y > bottom ) y = bottom ;
# endif
Center = XY_Coord ( x , y ) ;
}
/*
* * If there were any buildings discovered as legal to consider as part of the base ,
* * then figure out the general average radius of the building disposition as it
* * relates to the center of the base .
*/
if ( count > 1 ) {
int radius = 0 ;
for ( index = 0 ; index < Buildings . Count ( ) ; index + + ) {
BuildingClass const * b = Buildings . Ptr ( index ) ;
if ( b ! = NULL & & ! b - > IsInLimbo & & ( HouseClass * ) b - > House = = this & & b - > Strength > 0 ) {
radius + = Distance ( Center , b - > Center_Coord ( ) ) ;
}
}
Radius = max ( radius / count , 2 * CELL_LEPTON_W ) ;
/*
* * Determine the relative strength of each base defense zone .
*/
for ( index = 0 ; index < Buildings . Count ( ) ; index + + ) {
BuildingClass const * b = Buildings . Ptr ( index ) ;
if ( b ! = NULL & & ! b - > IsInLimbo & & ( HouseClass * ) b - > House = = this & & b - > Strength > 0 ) {
ZoneType z = Which_Zone ( b ) ;
if ( z ! = ZONE_NONE ) {
ZoneInfo [ z ] . ArmorDefense + = b - > Anti_Armor ( ) ;
ZoneInfo [ z ] . AirDefense + = b - > Anti_Air ( ) ;
ZoneInfo [ z ] . InfantryDefense + = b - > Anti_Infantry ( ) ;
}
}
}
} else {
Radius = 0x0200 ;
}
}
}
/***********************************************************************************************
* HouseClass : : Expert_AI - - Handles expert AI processing . *
* *
* This routine is called when the computer should perform expert AI processing . This *
* method of AI is categorized as an " Expert System " process . *
* *
* INPUT : none *
* *
* OUTPUT : Returns the number of game frames to delay before calling this routine again . *
* *
* WARNINGS : This is relatively time consuming - - call periodically . *
* *
* HISTORY : *
* 09 / 29 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
int HouseClass : : Expert_AI ( void )
{
//assert(Houses.ID(this) == ID);
BuildingClass * b = 0 ;
bool stop = false ;
int time = TICKS_PER_SECOND * 10 ;
/*
* * If the current enemy no longer has a base or is defeated , then don ' t consider
* * that house a threat anymore . Clear out the enemy record and then try
* * to find a new enemy .
*/
if ( Enemy ! = HOUSE_NONE ) {
HouseClass * h = HouseClass : : As_Pointer ( Enemy ) ;
if ( h = = NULL | | ! h - > IsActive | | h - > IsDefeated | | Is_Ally ( h ) | | h - > BScan = = 0 ) {
Enemy = HOUSE_NONE ;
}
}
/*
* * If there is no enemy assigned to this house , then assign one now . The
* * enemy that is closest is picked . However , don ' t pick an enemy if the
* * base has not been established yet .
*/
if ( ActiveBScan & & Center & & Attack = = 0 ) {
int close = 0 ;
HousesType enemy = HOUSE_NONE ;
int maxunit = 0 ;
int maxinfantry = 0 ;
int maxvessel = 0 ;
int maxaircraft = 0 ;
int maxbuilding = 0 ;
int enemycount = 0 ;
for ( HousesType house = HOUSE_FIRST ; house < HOUSE_COUNT ; house + + ) {
HouseClass * h = HouseClass : : As_Pointer ( house ) ;
if ( h ! = NULL & & h - > IsActive & & ! h - > IsDefeated & & ! Is_Ally ( h ) ) {
/*
* * Perform a special restriction check to ensure that no enemy is chosen if
* * there is even one enemy that has not established a base yet . This will
* * ensure an accurate first pick for enemy since the distance to base
* * value can be determined .
*/
if ( ! h - > IsStarted ) {
enemy = HOUSE_NONE ;
break ;
}
/*
* * Keep track of the number of buildings and units owned by the
* * enemy . This is used to bring up the maximum allowed to match .
*/
maxunit + = h - > CurUnits ;
maxbuilding + = h - > CurBuildings ;
maxinfantry + = h - > CurInfantry ;
//maxvessel += h->CurVessels;
maxaircraft + = h - > CurAircraft ;
enemycount + + ;
/*
* * Determine a priority value based on distance to the center of the
* * candidate base . The higher the value , the better the candidate house
* * is to becoming the preferred enemy for this house .
*/
int value = ( ( MAP_CELL_W * 2 ) - Distance ( Center , h - > Center ) ) ;
value * = 2 ;
/*
* * In addition to distance , record the number of kills directed
* * against this house . The enemy that does more damage might be
* * considered a greater threat .
*/
value + = h - > BuildingsKilled [ Class - > House ] * 5 ;
value + = h - > UnitsKilled [ Class - > House ] ;
/*
* * Factor in the relative sizes of the bases . An enemy that has a
* * larger base will be considered a bigger threat . Conversely , a
* * smaller base is considered a lesser threat .
*/
value + = h - > CurUnits - CurUnits ;
value + = h - > CurBuildings - CurBuildings ;
value + = ( h - > CurInfantry - CurInfantry ) / 4 ;
/*
* * Whoever last attacked is given a little more priority as
* * a potential designated enemy .
*/
if ( house = = LAEnemy ) {
value + = 100 ;
}
# ifdef OBSOLETE
/*
* * Human players are a given preference as the target .
*/
if ( h - > IsHuman ) {
value * = 2 ;
}
# endif
/*
* * Compare the calculated value for this candidate house and if it is
* * greater than the previously recorded maximum , record this house as
* * the prime candidate for enemy .
*/
if ( value > close ) {
enemy = house ;
close = value ;
}
}
}
/*
* * Record this closest enemy base as the first enemy to attack .
*/
Enemy = enemy ;
/*
* * Up the maximum allowed units and buildings to match a rough average
* * of what the enemies are allowed .
*/
if ( enemycount ) {
maxunit / = enemycount ;
maxbuilding / = enemycount ;
maxinfantry / = enemycount ;
maxvessel / = enemycount ;
maxaircraft / = enemycount ;
}
if ( Control . MaxBuilding < ( unsigned ) maxbuilding + 10 ) {
Control . MaxBuilding = maxbuilding + 10 ;
}
if ( Control . MaxUnit < ( unsigned ) maxunit + 10 ) {
Control . MaxUnit = maxunit + 10 ;
}
if ( Control . MaxInfantry < ( unsigned ) maxinfantry + 10 ) {
Control . MaxInfantry = maxinfantry + 10 ;
}
//if (Control.MaxVessel < (unsigned)maxvessel + 10) {
// Control.MaxVessel = maxvessel + 10;
//}
if ( Control . MaxAircraft < ( unsigned ) maxaircraft + 10 ) {
Control . MaxAircraft = maxaircraft + 10 ;
}
}
/*
* * House state transition check occurs here . Transitions that occur here are ones
* * that relate to general base condition rather than specific combat events .
* * Typically , this is limited to transitions between normal buildup mode and
* * broke mode .
*/
if ( State = = STATE_ENDGAME ) {
Fire_Sale ( ) ;
Do_All_To_Hunt ( ) ;
} else {
if ( State = = STATE_BUILDUP ) {
if ( Available_Money ( ) < 25 ) {
State = STATE_BROKE ;
}
}
if ( State = = STATE_BROKE ) {
if ( Available_Money ( ) > = 25 ) {
State = STATE_BUILDUP ;
}
}
if ( State = = STATE_ATTACKED & & LATime + TICKS_PER_MINUTE < Frame ) {
State = STATE_BUILDUP ;
}
if ( State ! = STATE_ATTACKED & & LATime + TICKS_PER_MINUTE > Frame ) {
State = STATE_ATTACKED ;
}
}
/*
* * Records the urgency of all actions possible .
*/
UrgencyType urgency [ STRATEGY_COUNT ] ;
StrategyType strat ;
for ( strat = STRATEGY_FIRST ; strat < STRATEGY_COUNT ; strat + + ) {
urgency [ strat ] = URGENCY_NONE ;
switch ( strat ) {
case STRATEGY_BUILD_POWER :
urgency [ strat ] = Check_Build_Power ( ) ;
break ;
case STRATEGY_BUILD_DEFENSE :
urgency [ strat ] = Check_Build_Defense ( ) ;
break ;
case STRATEGY_BUILD_INCOME :
urgency [ strat ] = Check_Build_Income ( ) ;
break ;
case STRATEGY_FIRE_SALE :
urgency [ strat ] = Check_Fire_Sale ( ) ;
break ;
case STRATEGY_BUILD_ENGINEER :
urgency [ strat ] = Check_Build_Engineer ( ) ;
break ;
case STRATEGY_BUILD_OFFENSE :
urgency [ strat ] = Check_Build_Offense ( ) ;
break ;
case STRATEGY_RAISE_MONEY :
urgency [ strat ] = Check_Raise_Money ( ) ;
break ;
case STRATEGY_RAISE_POWER :
urgency [ strat ] = Check_Raise_Power ( ) ;
break ;
case STRATEGY_LOWER_POWER :
urgency [ strat ] = Check_Lower_Power ( ) ;
break ;
case STRATEGY_ATTACK :
urgency [ strat ] = Check_Attack ( ) ;
break ;
default :
urgency [ strat ] = URGENCY_NONE ;
break ;
}
}
/*
* * Performs the action required for each of the strategies that share
* * the most urgent category . Stop processing if any strategy at the
* * highest urgency performed any action . This is because higher urgency
* * actions tend to greatly affect the lower urgency actions .
*/
for ( UrgencyType u = URGENCY_CRITICAL ; u > = URGENCY_LOW ; u - - ) {
bool acted = false ;
for ( strat = STRATEGY_FIRST ; strat < STRATEGY_COUNT ; strat + + ) {
if ( urgency [ strat ] = = u ) {
switch ( strat ) {
case STRATEGY_BUILD_POWER :
acted | = AI_Build_Power ( u ) ;
break ;
case STRATEGY_BUILD_DEFENSE :
acted | = AI_Build_Defense ( u ) ;
break ;
case STRATEGY_BUILD_INCOME :
acted | = AI_Build_Income ( u ) ;
break ;
case STRATEGY_FIRE_SALE :
acted | = AI_Fire_Sale ( u ) ;
break ;
case STRATEGY_BUILD_ENGINEER :
acted | = AI_Build_Engineer ( u ) ;
break ;
case STRATEGY_BUILD_OFFENSE :
acted | = AI_Build_Offense ( u ) ;
break ;
case STRATEGY_RAISE_MONEY :
acted | = AI_Raise_Money ( u ) ;
break ;
case STRATEGY_RAISE_POWER :
acted | = AI_Raise_Power ( u ) ;
break ;
case STRATEGY_LOWER_POWER :
acted | = AI_Lower_Power ( u ) ;
break ;
case STRATEGY_ATTACK :
acted | = AI_Attack ( u ) ;
break ;
default :
break ;
}
}
}
}
return ( TICKS_PER_SECOND * 5 + Random_Pick ( 1 , TICKS_PER_SECOND / 2 ) ) ;
}
UrgencyType HouseClass : : Check_Build_Power ( void ) const
{
//assert(Houses.ID(this) == ID);
//fixed frac = Power_Fraction();
int frac = Power_Fraction ( ) ;
UrgencyType urgency = URGENCY_NONE ;
//if (frac < 1 && Can_Make_Money()) {
if ( frac < 0x0100 & & Can_Make_Money ( ) ) {
urgency = URGENCY_LOW ;
/*
* * Very low power condition is considered a higher priority .
*/
//if (frac < fixed::_3_4) urgency = URGENCY_MEDIUM;
if ( frac < 0x00C0 ) urgency = URGENCY_MEDIUM ;
/*
* * When under attack and there is a need for power in defense ,
* * then consider power building a higher priority .
*/
// No chronosphere in TD. ST - 7/19/2019 4:38PM
//if (State == STATE_THREATENED || State == STATE_ATTACKED) {
// if (BScan | (STRUCTF_CHRONOSPHERE)) {
// urgency = URGENCY_HIGH;
// }
//}
}
return ( urgency ) ;
}
UrgencyType HouseClass : : Check_Build_Defense ( void ) const
{
//assert(Houses.ID(this) == ID);
/*
* * This routine determines what urgency level that base defense
* * should be given . The more vulnerable the base is , the higher
* * the urgency this routine should return .
*/
return ( URGENCY_NONE ) ;
}
UrgencyType HouseClass : : Check_Build_Offense ( void ) const
{
//assert(Houses.ID(this) == ID);
/*
* * This routine determines what urgency level that offensive
* * weaponry should be given . Surplus money or a very strong
* * defense will cause the offensive urgency to increase .
*/
return ( URGENCY_NONE ) ;
}
/*
* * Determines what the attack state of the base is . The higher the state ,
* * the greater the immediate threat to base defense is .
*/
UrgencyType HouseClass : : Check_Attack ( void ) const
{
//assert(Houses.ID(this) == ID);
if ( Frame > TICKS_PER_MINUTE & & Attack = = 0 ) {
if ( State = = STATE_ATTACKED ) {
return ( URGENCY_LOW ) ;
}
return ( URGENCY_CRITICAL ) ;
}
return ( URGENCY_NONE ) ;
}
UrgencyType HouseClass : : Check_Build_Income ( void ) const
{
//assert(Houses.ID(this) == ID);
/*
* * This routine should determine if income processing buildings
* * should be constructed and at what urgency . The lower the money ,
* * the lower the refineries , or recent harvester losses should
* * cause a greater urgency to be returned .
*/
return ( URGENCY_NONE ) ;
}
UrgencyType HouseClass : : Check_Fire_Sale ( void ) const
{
//assert(Houses.ID(this) == ID);
/*
* * If there are no more factories at all , then sell everything off because the game
* * is basically over at this point .
*/
//if (State != STATE_ATTACKED && CurBuildings && !(ActiveBScan & (STRUCTF_TENT|STRUCTF_BARRACKS|STRUCTF_CONST|STRUCTF_AIRSTRIP|STRUCTF_WEAP|STRUCTF_HELIPAD))) {
if ( State ! = STATE_ATTACKED & & CurBuildings & & ! ( ActiveBScan & ( STRUCTF_BARRACKS | STRUCTF_CONST | STRUCTF_AIRSTRIP | STRUCTF_WEAP | STRUCTF_HELIPAD ) ) ) {
return ( URGENCY_CRITICAL ) ;
}
return ( URGENCY_NONE ) ;
}
UrgencyType HouseClass : : Check_Build_Engineer ( void ) const
{
//assert(Houses.ID(this) == ID);
/*
* * This routine should check to see what urgency that the production of
* * engineers should be . If a friendly building has been captured or the
* * enemy has weak defenses , then building an engineer would be a priority .
*/
return ( URGENCY_NONE ) ;
}
/*
* * Checks to see if money is critically low and something must be done
* * to immediately raise cash .
*/
UrgencyType HouseClass : : Check_Raise_Money ( void ) const
{
//assert(Houses.ID(this) == ID);
UrgencyType urgency = URGENCY_NONE ;
if ( Available_Money ( ) < 100 ) {
urgency = URGENCY_LOW ;
}
if ( Available_Money ( ) < 2000 & & ! Can_Make_Money ( ) ) {
urgency + + ;
}
return ( urgency ) ;
}
/*
* * Checks to see if power is very low and if so , a greater urgency to
* * build more power is returned .
*/
UrgencyType HouseClass : : Check_Lower_Power ( void ) const
{
//assert(Houses.ID(this) == ID);
if ( Power > Drain + 300 ) {
return ( URGENCY_LOW ) ;
}
return ( URGENCY_NONE ) ;
}
/*
* * This routine determines if there is a power emergency . Such an
* * emergency might require selling of structures in order to free
* * up power . This might occur if the base is being attacked and there
* * are defenses that require power , but are just short of having
* * enough .
*/
UrgencyType HouseClass : : Check_Raise_Power ( void ) const
{
//assert(Houses.ID(this) == ID);
UrgencyType urgency = URGENCY_NONE ;
if ( Power_Fraction ( ) < Rule . PowerEmergencyFraction & & Power < Drain - 400 ) {
// if (Power_Fraction() < Rule.PowerEmergencyFraction && (BQuantity[STRUCT_CONST] == 0 || Available_Money() < 200 || Power < Drain-400)) {
urgency = URGENCY_MEDIUM ;
if ( State = = STATE_ATTACKED ) {
urgency + + ;
}
}
return ( urgency ) ;
}
bool HouseClass : : AI_Attack ( UrgencyType )
{
//assert(Houses.ID(this) == ID);
bool shuffle = ! ( ( Frame > TICKS_PER_MINUTE & & ! CurBuildings ) | | Percent_Chance ( 33 ) ) ;
bool forced = ( CurBuildings = = 0 ) ;
int index ;
for ( index = 0 ; index < Aircraft . Count ( ) ; index + + ) {
AircraftClass * a = Aircraft . Ptr ( index ) ;
if ( a ! = NULL & & ! a - > IsInLimbo & & a - > House = = this & & a - > Strength > 0 ) {
if ( ! shuffle & & a - > Is_Weapon_Equipped ( ) & & ( forced | | Percent_Chance ( 75 ) ) ) {
a - > Assign_Mission ( MISSION_HUNT ) ;
}
}
}
for ( index = 0 ; index < Units . Count ( ) ; index + + ) {
UnitClass * u = Units . Ptr ( index ) ;
if ( u ! = NULL & & ! u - > IsInLimbo & & u - > House = = this & & u - > Strength > 0 ) {
if ( ! shuffle & & u - > Is_Weapon_Equipped ( ) & & ( forced | | Percent_Chance ( 75 ) ) ) {
u - > Assign_Mission ( MISSION_HUNT ) ;
} else {
/*
* * If this unit is guarding the base , then cause it to shuffle
* * location instead .
*/
if ( Percent_Chance ( 20 ) & & u - > Mission = = MISSION_GUARD_AREA & & Which_Zone ( u ) ! = ZONE_NONE ) {
u - > ArchiveTarget = : : As_Target ( Where_To_Go ( u ) ) ;
}
}
}
}
for ( index = 0 ; index < Infantry . Count ( ) ; index + + ) {
InfantryClass * i = Infantry . Ptr ( index ) ;
if ( i ! = NULL & & ! i - > IsInLimbo & & i - > House = = this & & i - > Strength > 0 ) {
if ( ! shuffle & & ( i - > Is_Weapon_Equipped ( ) | | * i = = INFANTRY_RENOVATOR ) & & ( forced | | Percent_Chance ( 75 ) ) ) {
i - > Assign_Mission ( MISSION_HUNT ) ;
} else {
/*
* * If this soldier is guarding the base , then cause it to shuffle
* * location instead .
*/
if ( Percent_Chance ( 20 ) & & i - > Mission = = MISSION_GUARD_AREA & & Which_Zone ( i ) ! = ZONE_NONE ) {
i - > ArchiveTarget = : : As_Target ( Where_To_Go ( i ) ) ;
}
}
}
}
Attack = Rule . AttackInterval * Random_Pick ( TICKS_PER_MINUTE / 2 , TICKS_PER_MINUTE * 2 ) ;
return ( true ) ;
}
/*
* * Given the specified urgency , build a power structure to meet
* * this need .
*/
bool HouseClass : : AI_Build_Power ( UrgencyType ) const
{
//assert(Houses.ID(this) == ID);
return ( false ) ;
}
/*
* * Given the specified urgency , build base defensive structures
* * according to need and according to existing base disposition .
*/
bool HouseClass : : AI_Build_Defense ( UrgencyType ) const
{
//assert(Houses.ID(this) == ID);
return ( false ) ;
}
/*
* * Given the specified urgency , build offensive units according
* * to need and according to the opponents base defenses .
*/
bool HouseClass : : AI_Build_Offense ( UrgencyType ) const
{
//assert(Houses.ID(this) == ID);
return ( false ) ;
}
/*
* * Given the specified urgency , build income producing
* * structures according to need .
*/
bool HouseClass : : AI_Build_Income ( UrgencyType ) const
{
//assert(Houses.ID(this) == ID);
return ( false ) ;
}
bool HouseClass : : AI_Fire_Sale ( UrgencyType urgency )
{
//assert(Houses.ID(this) == ID);
if ( CurBuildings & & urgency = = URGENCY_CRITICAL ) {
Fire_Sale ( ) ;
Do_All_To_Hunt ( ) ;
return ( true ) ;
}
return ( false ) ;
}
/*
* * Given the specified urgency , build an engineer .
*/
bool HouseClass : : AI_Build_Engineer ( UrgencyType ) const
{
//assert(Houses.ID(this) == ID);
return ( false ) ;
}
/*
* * Given the specified urgency , sell of some power since
* * there appears to be excess .
*/
bool HouseClass : : AI_Lower_Power ( UrgencyType ) const
{
//assert(Houses.ID(this) == ID);
BuildingClass * b = Find_Building ( STRUCT_POWER ) ;
if ( b ! = NULL ) {
b - > Sell_Back ( 1 ) ;
return ( true ) ;
}
b = Find_Building ( STRUCT_ADVANCED_POWER ) ;
if ( b ! = NULL ) {
b - > Sell_Back ( 1 ) ;
return ( true ) ;
}
return ( false ) ;
}
/***********************************************************************************************
* HouseClass : : AI_Raise_Power - - Try to raise power levels by selling off buildings . *
* *
* This routine is called when the computer needs to raise power by selling off buildings . *
* Usually this occurs because of some catastrophe that has lowered power levels to *
* the danger zone . *
* *
* INPUT : urgency - - The urgency that the power needs to be raised . This controls what *
* buildings will be sold . *
* *
* OUTPUT : bool ; Was a building sold to raise power ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 11 / 02 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : AI_Raise_Power ( UrgencyType urgency ) const
{
//assert(Houses.ID(this) == ID);
/*
* * Sell off structures in this order .
*/
# if (0)
static struct {
StructType Structure ;
UrgencyType Urgency ;
} _types [ ] = {
{ STRUCT_CHRONOSPHERE , URGENCY_LOW } ,
{ STRUCT_SHIP_YARD , URGENCY_LOW } ,
{ STRUCT_SUB_PEN , URGENCY_LOW } ,
{ STRUCT_ADVANCED_TECH , URGENCY_LOW } ,
{ STRUCT_FORWARD_COM , URGENCY_LOW } ,
{ STRUCT_SOVIET_TECH , URGENCY_LOW } ,
{ STRUCT_IRON_CURTAIN , URGENCY_MEDIUM } ,
{ STRUCT_RADAR , URGENCY_MEDIUM } ,
{ STRUCT_REPAIR , URGENCY_MEDIUM } ,
{ STRUCT_TESLA , URGENCY_HIGH }
} ;
# endif
static struct {
StructType Structure ;
UrgencyType Urgency ;
} _types [ ] = {
{ STRUCT_BIO_LAB , URGENCY_LOW } ,
{ STRUCT_EYE , URGENCY_MEDIUM } ,
{ STRUCT_RADAR , URGENCY_MEDIUM } ,
{ STRUCT_REPAIR , URGENCY_MEDIUM } ,
{ STRUCT_OBELISK , URGENCY_HIGH } ,
{ STRUCT_TURRET , URGENCY_HIGH } ,
{ STRUCT_ATOWER , URGENCY_HIGH } ,
{ STRUCT_GTOWER , URGENCY_HIGH }
} ;
/*
* * Find a structure to sell and then sell it . Bail from further scanning until
* * the next time .
*/
for ( int i = 0 ; i < ARRAY_SIZE ( _types ) ; i + + ) {
if ( urgency > = _types [ i ] . Urgency ) {
BuildingClass * b = Find_Building ( _types [ i ] . Structure ) ;
if ( b ! = NULL ) {
b - > Sell_Back ( 1 ) ;
return ( true ) ;
}
}
}
return ( false ) ;
}
/***********************************************************************************************
* HouseClass : : AI_Raise_Money - - Raise emergency cash by selling buildings . *
* *
* This routine handles the situation where the computer desperately needs cash but cannot *
* wait for normal harvesting to raise it . Buildings must be sold . *
* *
* INPUT : urgency - - The urgency level that cash must be raised . The greater the urgency , *
* the more important the buildings that can be sold become . *
* *
* OUTPUT : bool ; Was a building sold to raise cash ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 11 / 02 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : AI_Raise_Money ( UrgencyType urgency ) const
{
//assert(Houses.ID(this) == ID);
/*
* * Sell off structures in this order .
*/
# if (0)
static struct {
StructType Structure ;
UrgencyType Urgency ;
} _types [ ] = {
{ STRUCT_CHRONOSPHERE , URGENCY_LOW } ,
{ STRUCT_SHIP_YARD , URGENCY_LOW } ,
{ STRUCT_SUB_PEN , URGENCY_LOW } ,
{ STRUCT_ADVANCED_TECH , URGENCY_LOW } ,
{ STRUCT_FORWARD_COM , URGENCY_LOW } ,
{ STRUCT_SOVIET_TECH , URGENCY_LOW } ,
{ STRUCT_STORAGE , URGENCY_LOW } ,
{ STRUCT_REPAIR , URGENCY_LOW } ,
{ STRUCT_TESLA , URGENCY_MEDIUM } ,
{ STRUCT_HELIPAD , URGENCY_MEDIUM } ,
{ STRUCT_POWER , URGENCY_HIGH } ,
{ STRUCT_AIRSTRIP , URGENCY_HIGH } ,
// {STRUCT_WEAP,URGENCY_HIGH},
// {STRUCT_BARRACKS,URGENCY_HIGH},
// {STRUCT_TENT,URGENCY_HIGH},
{ STRUCT_CONST , URGENCY_CRITICAL }
} ;
# endif
static struct {
StructType Structure ;
UrgencyType Urgency ;
} _types [ ] = {
{ STRUCT_BIO_LAB , URGENCY_LOW } ,
{ STRUCT_EYE , URGENCY_MEDIUM } ,
{ STRUCT_RADAR , URGENCY_MEDIUM } ,
{ STRUCT_STORAGE , URGENCY_LOW } ,
{ STRUCT_REPAIR , URGENCY_MEDIUM } ,
{ STRUCT_OBELISK , URGENCY_HIGH } ,
{ STRUCT_TURRET , URGENCY_HIGH } ,
{ STRUCT_ATOWER , URGENCY_HIGH } ,
{ STRUCT_GTOWER , URGENCY_HIGH } ,
{ STRUCT_HELIPAD , URGENCY_MEDIUM } ,
{ STRUCT_POWER , URGENCY_HIGH } ,
{ STRUCT_AIRSTRIP , URGENCY_HIGH } ,
{ STRUCT_CONST , URGENCY_CRITICAL }
} ;
BuildingClass * b = 0 ;
/*
* * Find a structure to sell and then sell it . Bail from further scanning until
* * the next time .
*/
for ( int i = 0 ; i < ARRAY_SIZE ( _types ) ; i + + ) {
if ( urgency > = _types [ i ] . Urgency ) {
b = Find_Building ( _types [ i ] . Structure ) ;
if ( b ! = NULL ) {
b - > Sell_Back ( 1 ) ;
return ( true ) ;
}
}
}
return ( false ) ;
}
# ifdef NEVER
/***********************************************************************************************
* HouseClass : : AI_Base_Defense - - Handles maintaining a strong base defense . *
* *
* This logic is used to maintain a base defense . *
* *
* INPUT : none *
* *
* OUTPUT : Returns with the number of game frames to delay before calling this routine again . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 29 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
int HouseClass : : AI_Base_Defense ( void )
{
//assert(Houses.ID(this) == ID);
/*
* * Check to find if any zone of the base is over defended . Such zones should have
* * some of their defenses sold off to make better use of the money .
*/
/*
* * Make sure that the core defense is only about 1 / 2 of the perimeter defense average .
*/
int average = 0 ;
for ( ZoneType z = ZONE_NORTH ; z < ZONE_COUNT ; z + + ) {
average + = ZoneInfo [ z ] . AirDefense ;
average + = ZoneInfo [ z ] . ArmorDefense ;
average + = ZoneInfo [ z ] . InfantryDefense ;
}
average / = ( ZONE_COUNT - ZONE_NORTH ) ;
/*
* * If the core value is greater than the average , then sell off some of the
* * inner defensive structures .
*/
int core = ZoneInfo [ ZONE_CORE ] . AirDefense + ZoneInfo [ ZONE_CORE ] . ArmorDefense + ZoneInfo [ ZONE_CORE ] . InfantryDefense ;
if ( core > = average ) {
static StructType _stype [ ] = {
STRUCT_GTOWER ,
STRUCT_TURRET ,
STRUCT_ATOWER ,
STRUCT_OBELISK ,
STRUCT_TESLA ,
STRUCT_SAM
} ;
BuildingClass * b ;
for ( int index = 0 ; index < sizeof ( _stype ) / sizeof ( _stype [ 0 ] ) ; index + + ) {
b = Find_Building ( _stype [ index ] , ZONE_CORE ) ;
if ( b ) {
b - > Sell_Back ( 1 ) ;
break ;
}
}
}
/*
* * If the enemy doesn ' t have any offensive air capability , then sell off any
* * SAM sites . Only do this when money is moderately low .
*/
if ( Available_Money ( ) < 1000 & & ( ActiveBScan & STRUCTF_SAM ) ) {
/*
* * Scan to find if ANY human opponents have aircraft or a helipad . If one
* * is found then consider that opponent to have a valid air threat potential .
* * Don ' t sell off SAM sites in that case .
*/
bool nothreat = true ;
for ( HousesType h = HOUSE_FIRST ; h < HOUSE_COUNT ; h + + ) {
HouseClass * house = HouseClass : : As_Pointer ( h ) ;
if ( house & & house - > IsActive & & house - > IsHuman & & ! Is_Ally ( house ) ) {
if ( ( house - > ActiveAScan & ( AIRCRAFTF_ORCA | AIRCRAFTF_TRANSPORT | AIRCRAFTF_HELICOPTER ) ) | | ( house - > ActiveBScan & STRUCTF_HELIPAD ) ) {
nothreat = false ;
break ;
}
}
}
}
return ( TICKS_PER_SECOND * 5 ) ;
}
# endif
/***********************************************************************************************
* HouseClass : : AI_Building - - Determines what building to build . *
* *
* This routine handles the general case of determining what building to build next . *
* *
* INPUT : none *
* *
* OUTPUT : Returns with the number of game frames to delay before calling this routine again . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 29 / 1995 JLB : Created . *
* 11 / 03 / 1996 JLB : Tries to match aircraft of enemy *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
int HouseClass : : AI_Building ( void )
{
//assert(Houses.ID(this) == ID);
if ( BuildStructure ! = STRUCT_NONE ) return ( TICKS_PER_SECOND ) ;
# if (0) // Not used for GAME_NORMAL in C&C. ST - 7/23/2019 3:04PM
if ( Session . Type = = GAME_NORMAL & & Base . House = = Class - > House ) {
BaseNodeClass * node = Base . Next_Buildable ( ) ;
if ( node ) {
BuildStructure = node - > Type ;
}
}
# endif
if ( IsBaseBuilding ) {
/*
* * Don ' t suggest anything to build if the base is already big enough .
*/
unsigned int quant = 0 ;
for ( HousesType h = HOUSE_FIRST ; h < HOUSE_COUNT ; h + + ) {
HouseClass const * hptr = HouseClass : : As_Pointer ( h ) ;
if ( hptr ! = NULL & & hptr - > IsActive & & hptr - > IsHuman & & quant < hptr - > CurBuildings ) {
quant = hptr - > CurBuildings ;
}
}
quant + = Rule . BaseSizeAdd ;
// TCTC -- Should multiply largest player base by some rational number.
// if (CurBuildings >= quant) return(TICKS_PER_SECOND);
BuildChoice . Free_All ( ) ;
BuildChoiceClass * choiceptr ;
StructType stype = STRUCT_NONE ;
int money = Available_Money ( ) ;
//int level = Control.TechLevel;
bool hasincome = ( BQuantity [ STRUCT_REFINERY ] > 0 & & ! IsTiberiumShort & & UQuantity [ UNIT_HARVESTER ] > 0 ) ;
BuildingTypeClass const * b = NULL ;
HouseClass const * enemy = NULL ;
if ( Enemy ! = HOUSE_NONE ) {
enemy = HouseClass : : As_Pointer ( Enemy ) ;
}
//level = Control.TechLevel;
/*
* * Try to build a power plant if there is insufficient power and there is enough
* * money available .
*/
b = & BuildingTypeClass : : As_Reference ( STRUCT_ADVANCED_POWER ) ;
if ( Can_Build ( b , ActLike ) & & Power < = Drain + Rule . PowerSurplus & & b - > Cost_Of ( ) < money ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( BQuantity [ STRUCT_REFINERY ] = = 0 ? URGENCY_LOW : URGENCY_MEDIUM , b - > Type ) ;
}
} else {
b = & BuildingTypeClass : : As_Reference ( STRUCT_POWER ) ;
if ( Can_Build ( b , ActLike ) & & Power < = Drain + Rule . PowerSurplus & & b - > Cost_Of ( ) < money ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( BQuantity [ STRUCT_REFINERY ] = = 0 ? URGENCY_LOW : URGENCY_MEDIUM , b - > Type ) ;
}
}
}
/*
* * Build a refinery if there isn ' t one already available .
*/
unsigned int current = BQuantity [ STRUCT_REFINERY ] ;
if ( ! IsTiberiumShort & & current < Round_Up ( Rule . RefineryRatio * fixed ( CurBuildings ) ) & & current < ( unsigned ) Rule . RefineryLimit ) {
b = & BuildingTypeClass : : As_Reference ( STRUCT_REFINERY ) ;
if ( Can_Build ( b , ActLike ) & & ( money > b - > Cost_Of ( ) | | hasincome ) ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( BQuantity [ STRUCT_REFINERY ] = = 0 ? URGENCY_HIGH : URGENCY_MEDIUM , b - > Type ) ;
}
}
}
/*
* * Always make sure there is a barracks available , but only if there
* * will be sufficient money to train troopers .
*/
//current = BQuantity[STRUCT_BARRACKS] + BQuantity[STRUCT_TENT];
current = BQuantity [ STRUCT_BARRACKS ] + BQuantity [ STRUCT_HAND ] ;
if ( current < Round_Up ( Rule . BarracksRatio * fixed ( CurBuildings ) ) & & current < ( unsigned ) Rule . BarracksLimit & & ( money > 300 | | hasincome ) ) {
b = & BuildingTypeClass : : As_Reference ( STRUCT_BARRACKS ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( current > 0 ? URGENCY_LOW : URGENCY_MEDIUM , b - > Type ) ;
}
} else {
//b = &BuildingTypeClass::As_Reference(STRUCT_TENT);
b = & BuildingTypeClass : : As_Reference ( STRUCT_HAND ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( current > 0 ? URGENCY_LOW : URGENCY_MEDIUM , b - > Type ) ;
}
}
}
}
# if (0)
/*
* * Try to build one dog house .
*/
current = BQuantity [ STRUCT_KENNEL ] ;
if ( current < 1 & & ( money > 300 | | hasincome ) ) {
b = & BuildingTypeClass : : As_Reference ( STRUCT_KENNEL ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( URGENCY_MEDIUM , b - > Type ) ;
}
}
}
/*
* * Try to build one gap generator .
*/
current = BQuantity [ STRUCT_GAP ] ;
if ( current < 1 & & Power_Fraction ( ) > = 1 & & hasincome ) {
b = & BuildingTypeClass : : As_Reference ( STRUCT_GAP ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( URGENCY_MEDIUM , b - > Type ) ;
}
}
}
# endif
/*
* * A source of combat vehicles is always needed , but only if there will
* * be sufficient money to build vehicles .
*/
current = BQuantity [ STRUCT_WEAP ] ;
if ( current < Round_Up ( Rule . WarRatio * fixed ( CurBuildings ) ) & & current < ( unsigned ) Rule . WarLimit & & ( money > 2000 | | hasincome ) ) {
b = & BuildingTypeClass : : As_Reference ( STRUCT_WEAP ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( current > 0 ? URGENCY_LOW : URGENCY_MEDIUM , b - > Type ) ;
}
}
}
/*
* * Always build up some base defense .
*/
//current = BQuantity[STRUCT_PILLBOX] + BQuantity[STRUCT_CAMOPILLBOX] + BQuantity[STRUCT_TURRET] + BQuantity[STRUCT_FLAME_TURRET];
current = BQuantity [ STRUCT_TURRET ] + BQuantity [ STRUCT_OBELISK ] ;
if ( current < Round_Up ( Rule . DefenseRatio * fixed ( CurBuildings ) ) & & current < ( unsigned ) Rule . DefenseLimit ) {
//b = &BuildingTypeClass::As_Reference(STRUCT_FLAME_TURRET);
b = & BuildingTypeClass : : As_Reference ( STRUCT_OBELISK ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( URGENCY_MEDIUM , b - > Type ) ;
}
} else {
//if (Percent_Chance(50)) {
//b = &BuildingTypeClass::As_Reference(STRUCT_PILLBOX);
b = & BuildingTypeClass : : As_Reference ( STRUCT_TURRET ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( URGENCY_MEDIUM , b - > Type ) ;
}
}
# if (0)
} else {
b = & BuildingTypeClass : : As_Reference ( STRUCT_TURRET ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( URGENCY_MEDIUM , b - > Type ) ;
}
}
}
# endif
}
}
/*
* * Build some air defense .
*/
//current = BQuantity[STRUCT_SAM] + BQuantity[STRUCT_AAGUN];
current = BQuantity [ STRUCT_SAM ] ;
if ( current < Round_Up ( Rule . AARatio * fixed ( CurBuildings ) ) & & current < ( unsigned ) Rule . AALimit ) {
/*
* * Building air defense only makes sense if the opponent has aircraft
* * of some kind .
*/
bool airthreat = false ;
int threat_quantity = 0 ;
if ( enemy ! = NULL & & enemy - > AScan ! = 0 ) {
airthreat = true ;
threat_quantity = enemy - > CurAircraft ;
}
if ( ! airthreat ) {
for ( HousesType house = HOUSE_FIRST ; house < HOUSE_COUNT ; house + + ) {
HouseClass * h = HouseClass : : As_Pointer ( house ) ;
if ( h ! = NULL & & ! Is_Ally ( house ) & & h - > AScan ! = 0 ) {
airthreat = true ;
break ;
}
}
}
if ( airthreat ) {
if ( BQuantity [ STRUCT_RADAR ] = = 0 ) {
b = & BuildingTypeClass : : As_Reference ( STRUCT_RADAR ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( URGENCY_HIGH , b - > Type ) ;
}
}
}
b = & BuildingTypeClass : : As_Reference ( STRUCT_SAM ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( ( current < ( unsigned ) threat_quantity ) ? URGENCY_HIGH : URGENCY_MEDIUM , b - > Type ) ;
}
} else {
# if (0)
b = & BuildingTypeClass : : As_Reference ( STRUCT_AAGUN ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( ( current < ( unsigned ) threat_quantity ) ? URGENCY_HIGH : URGENCY_MEDIUM , b - > Type ) ;
}
}
# endif
}
}
}
# if (0)
/*
* * Advanced base defense would be good .
*/
current = BQuantity [ STRUCT_TESLA ] ;
if ( current < Round_Up ( Rule . TeslaRatio * fixed ( CurBuildings ) ) & & current < ( unsigned ) Rule . TeslaLimit ) {
b = & BuildingTypeClass : : As_Reference ( STRUCT_TESLA ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) & & Power_Fraction ( ) > = 1 ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( URGENCY_MEDIUM , b - > Type ) ;
}
}
}
/*
* * Build a tech center as soon as possible .
*/
current = BQuantity [ STRUCT_ADVANCED_TECH ] + BQuantity [ STRUCT_SOVIET_TECH ] ;
if ( current < 1 ) {
b = & BuildingTypeClass : : As_Reference ( STRUCT_ADVANCED_TECH ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) & & Power_Fraction ( ) > = 1 ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( URGENCY_MEDIUM , b - > Type ) ;
}
} else {
b = & BuildingTypeClass : : As_Reference ( STRUCT_SOVIET_TECH ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) & & Power_Fraction ( ) > = 1 ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
* choiceptr = BuildChoiceClass ( URGENCY_MEDIUM , b - > Type ) ;
}
}
}
}
# endif
/*
* * A helipad would be good .
*/
current = BQuantity [ STRUCT_HELIPAD ] ;
if ( current < Round_Up ( Rule . HelipadRatio * fixed ( CurBuildings ) ) & & current < ( unsigned ) Rule . HelipadLimit ) {
b = & BuildingTypeClass : : As_Reference ( STRUCT_HELIPAD ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
int threat_quantity = 0 ;
if ( enemy ! = NULL ) {
threat_quantity = enemy - > CurAircraft ;
}
* choiceptr = BuildChoiceClass ( ( CurAircraft < ( unsigned ) threat_quantity ) ? URGENCY_HIGH : URGENCY_MEDIUM , b - > Type ) ;
}
}
}
/*
* * An airstrip would be good .
*/
current = BQuantity [ STRUCT_AIRSTRIP ] ;
if ( current < Round_Up ( Rule . AirstripRatio * fixed ( CurBuildings ) ) & & current < ( unsigned ) Rule . AirstripLimit ) {
b = & BuildingTypeClass : : As_Reference ( STRUCT_AIRSTRIP ) ;
if ( Can_Build ( b , ActLike ) & & ( b - > Cost_Of ( ) < money | | hasincome ) ) {
choiceptr = BuildChoice . Alloc ( ) ;
if ( choiceptr ! = NULL ) {
int threat_quantity = 0 ;
if ( enemy ! = NULL ) {
threat_quantity = enemy - > CurAircraft ;
}
* choiceptr = BuildChoiceClass ( ( CurAircraft < ( unsigned ) threat_quantity ) ? URGENCY_HIGH : URGENCY_MEDIUM , b - > Type ) ;
}
}
}
/*
* * Pick the choice that is the most urgent .
*/
UrgencyType best = URGENCY_NONE ;
int bestindex ;
for ( int index = 0 ; index < BuildChoice . Count ( ) ; index + + ) {
if ( BuildChoice . Ptr ( index ) - > Urgency > best ) {
bestindex = index ;
best = BuildChoice . Ptr ( index ) - > Urgency ;
}
}
if ( best ! = URGENCY_NONE ) {
BuildStructure = BuildChoice . Ptr ( bestindex ) - > Structure ;
}
}
return ( TICKS_PER_SECOND ) ;
}
/***********************************************************************************************
* HouseClass : : AI_Unit - - Determines what unit to build next . *
* *
* This routine handles the general case of determining what units to build next . *
* *
* INPUT : none *
* *
* OUTPUT : Returns with the number of games frames to delay before calling this routine again . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 29 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
int HouseClass : : AI_Unit ( void )
{
//assert(Houses.ID(this) == ID);
if ( BuildUnit ! = UNIT_NONE ) return ( TICKS_PER_SECOND ) ;
if ( CurUnits > = Control . MaxUnit ) return ( TICKS_PER_SECOND ) ;
/*
* * A computer controlled house will try to build a replacement
* * harvester if possible .
*/
if ( IQ > = Rule . IQHarvester & & ! IsTiberiumShort & & ! IsHuman & & BQuantity [ STRUCT_REFINERY ] > UQuantity [ UNIT_HARVESTER ] & & Difficulty ! = DIFF_HARD ) {
//if (UnitTypeClass::As_Reference(UNIT_HARVESTER).Level <= (unsigned)Control.TechLevel) {
if ( UnitTypeClass : : As_Reference ( UNIT_HARVESTER ) . Level < = ( unsigned ) BuildLevel ) {
BuildUnit = UNIT_HARVESTER ;
return ( TICKS_PER_SECOND ) ;
}
}
//if (Session.Type == GAME_NORMAL) { // Why? ST - 7/24/2019 2:38PM
int counter [ UNIT_COUNT ] ;
memset ( counter , 0x00 , sizeof ( counter ) ) ;
/*
* * Build a list of the maximum of each type we wish to produce . This will be
* * twice the number required to fill all teams .
*/
int index ;
for ( index = 0 ; index < Teams . Count ( ) ; index + + ) {
TeamClass * tptr = Teams . Ptr ( index ) ;
if ( tptr ! = NULL ) {
TeamTypeClass const * team = tptr - > Class ;
//if (((team->IsReinforcable && !tptr->IsFullStrength) || (!tptr->IsForcedActive && !tptr->IsHasBeen && !tptr->JustAltered)) && team->House == Class->House) {
if ( ( ( team - > IsReinforcable & & ! tptr - > IsFullStrength ) | | ( ! tptr - > IsForcedActive & & ! tptr - > IsHasBeen & & ! tptr - > IsAltered ) ) & & team - > House = = Class - > House ) {
for ( int subindex = 0 ; subindex < team - > ClassCount ; subindex + + ) {
//TechnoTypeClass const * memtype = team->Members[subindex].Class;
TechnoTypeClass const * memtype = team - > Class [ subindex ] ;
if ( memtype - > What_Am_I ( ) = = RTTI_UNITTYPE ) {
counter [ ( ( UnitTypeClass const * ) memtype ) - > Type ] = 1 ;
}
}
}
}
}
/*
* * Team types that are flagged as prebuilt , will always try to produce enough
* * to fill one team of this type regardless of whether there is a team active
* * of that type .
*/
for ( index = 0 ; index < TeamTypes . Count ( ) ; index + + ) {
TeamTypeClass const * team = TeamTypes . Ptr ( index ) ;
if ( team ! = NULL & & team - > House = = Class - > House & & team - > IsPrebuilt & & ( ! team - > IsAutocreate | | IsAlerted ) ) {
for ( int subindex = 0 ; subindex < team - > ClassCount ; subindex + + ) {
//TechnoTypeClass const * memtype = team->Members[subindex].Class;
TechnoTypeClass const * memtype = team - > Class [ subindex ] ;
if ( memtype - > What_Am_I ( ) = = RTTI_UNITTYPE ) {
int subtype = ( ( UnitTypeClass const * ) memtype ) - > Type ;
//counter[subtype] = max(counter[subtype], team->Members[subindex].Quantity);
counter [ subtype ] = max ( counter [ subtype ] , 1 ) ;
}
}
}
}
/*
* * Reduce the theoretical maximum by the actual number of objects currently
* * in play .
*/
for ( int uindex = 0 ; uindex < Units . Count ( ) ; uindex + + ) {
UnitClass * unit = Units . Ptr ( uindex ) ;
//if (unit != NULL && unit->Is_Recruitable(this) && counter[unit->Class->Type] > 0) {
if ( unit ! = NULL & & counter [ unit - > Class - > Type ] > 0 ) {
counter [ unit - > Class - > Type ] - - ;
}
}
/*
* * Pick to build the most needed object but don ' t consider those objects that
* * can ' t be built because of scenario restrictions or insufficient cash .
*/
int bestval = - 1 ;
int bestcount = 0 ;
UnitType bestlist [ UNIT_COUNT ] ;
for ( UnitType utype = UNIT_FIRST ; utype < UNIT_COUNT ; utype + + ) {
if ( counter [ utype ] > 0 & & Can_Build ( & UnitTypeClass : : As_Reference ( utype ) , Class - > House ) & & UnitTypeClass : : As_Reference ( utype ) . Cost_Of ( ) < = Available_Money ( ) ) {
if ( bestval = = - 1 | | bestval < counter [ utype ] ) {
bestval = counter [ utype ] ;
bestcount = 0 ;
}
bestlist [ bestcount + + ] = utype ;
}
}
/*
* * The unit type to build is now known . Fetch a pointer to the techno type class .
*/
if ( bestcount ) {
BuildUnit = bestlist [ Random_Pick ( 0 , bestcount - 1 ) ] ;
}
//}
if ( IsBaseBuilding ) {
int counter [ UNIT_COUNT ] ;
int total = 0 ;
UnitType index ;
for ( index = UNIT_FIRST ; index < UNIT_COUNT ; index + + ) {
UnitTypeClass const * utype = & UnitTypeClass : : As_Reference ( index ) ;
if ( Can_Build ( utype , ActLike ) & & utype - > Type ! = UNIT_HARVESTER ) {
//if (utype->PrimaryWeapon != NULL) {
if ( utype - > Primary ! = WEAPON_NONE ) {
counter [ index ] = 20 ;
} else {
counter [ index ] = 1 ;
}
} else {
counter [ index ] = 0 ;
}
total + = counter [ index ] ;
}
if ( total > 0 ) {
int choice = Random_Pick ( 0 , total - 1 ) ;
for ( index = UNIT_FIRST ; index < UNIT_COUNT ; index + + ) {
if ( choice < counter [ index ] ) {
BuildUnit = index ;
break ;
}
choice - = counter [ index ] ;
}
}
}
return ( TICKS_PER_SECOND ) ;
}
int HouseClass : : AI_Vessel ( void )
{
# if (0)
//assert(Houses.ID(this) == ID);
if ( BuildVessel ! = VESSEL_NONE ) return ( TICKS_PER_SECOND ) ;
if ( CurVessels > = Control . MaxVessel ) {
return ( TICKS_PER_SECOND ) ;
}
if ( Session . Type = = GAME_NORMAL ) {
int counter [ VESSEL_COUNT ] ;
if ( Session . Type = = GAME_NORMAL ) {
memset ( counter , 0x00 , sizeof ( counter ) ) ;
} else {
for ( VesselType index = VESSEL_FIRST ; index < VESSEL_COUNT ; index + + ) {
//if (Can_Build(&VesselTypeClass::As_Reference(index), Class->House) && VesselTypeClass::As_Reference(index).Level <= (unsigned)Control.TechLevel) {
if ( Can_Build ( & VesselTypeClass : : As_Reference ( index ) , Class - > House ) & & VesselTypeClass : : As_Reference ( index ) . Level < = ( unsigned ) BuildLevel ) {
counter [ index ] = 16 ;
} else {
counter [ index ] = 0 ;
}
}
}
/*
* * Build a list of the maximum of each type we wish to produce . This will be
* * twice the number required to fill all teams .
*/
int index ;
for ( index = 0 ; index < Teams . Count ( ) ; index + + ) {
TeamClass * tptr = Teams . Ptr ( index ) ;
if ( tptr ) {
TeamTypeClass const * team = tptr - > Class ;
//if (((team->IsReinforcable && !tptr->IsFullStrength) || (!tptr->IsForcedActive && !tptr->IsHasBeen && !tptr->JustAltered)) && team->House == Class->House) {
if ( ( ( team - > IsReinforcable & & ! tptr - > IsFullStrength ) | | ( ! tptr - > IsForcedActive & & ! tptr - > IsHasBeen & & ! tptr - > IsAltered ) ) & & team - > House = = Class - > House ) {
for ( int subindex = 0 ; subindex < team - > ClassCount ; subindex + + ) {
if ( team - > Members [ subindex ] . Class - > What_Am_I ( ) = = RTTI_VESSELTYPE ) {
counter [ ( ( VesselTypeClass const * ) ( team - > Members [ subindex ] . Class ) ) - > Type ] = 1 ;
}
}
}
}
}
/*
* * Team types that are flagged as prebuilt , will always try to produce enough
* * to fill one team of this type regardless of whether there is a team active
* * of that type .
*/
for ( index = 0 ; index < TeamTypes . Count ( ) ; index + + ) {
TeamTypeClass const * team = TeamTypes . Ptr ( index ) ;
if ( team ) {
if ( team - > House = = Class - > House & & team - > IsPrebuilt & & ( ! team - > IsAutocreate | | IsAlerted ) ) {
for ( int subindex = 0 ; subindex < team - > ClassCount ; subindex + + ) {
if ( team - > Members [ subindex ] . Class - > What_Am_I ( ) = = RTTI_VESSELTYPE ) {
int subtype = ( ( VesselTypeClass const * ) ( team - > Members [ subindex ] . Class ) ) - > Type ;
//counter[subtype] = max(counter[subtype], team->Members[subindex].Quantity);
counter [ subtype ] = max ( counter [ subtype ] , 1 ) ;
}
}
}
}
}
/*
* * Reduce the theoretical maximum by the actual number of objects currently
* * in play .
*/
for ( int vindex = 0 ; vindex < Vessels . Count ( ) ; vindex + + ) {
VesselClass * unit = Vessels . Ptr ( vindex ) ;
//if (unit != NULL && unit->Is_Recruitable(this) && counter[unit->Class->Type] > 0) {
if ( unit ! = NULL & & counter [ unit - > Class - > Type ] > 0 ) {
counter [ unit - > Class - > Type ] - - ;
}
}
/*
* * Pick to build the most needed object but don ' t consider those object that
* * can ' t be built because of scenario restrictions or insufficient cash .
*/
int bestval = - 1 ;
int bestcount = 0 ;
VesselType bestlist [ VESSEL_COUNT ] ;
for ( VesselType utype = VESSEL_FIRST ; utype < VESSEL_COUNT ; utype + + ) {
if ( counter [ utype ] > 0 & & Can_Build ( & VesselTypeClass : : As_Reference ( utype ) , Class - > House ) & & VesselTypeClass : : As_Reference ( utype ) . Cost_Of ( ) < = Available_Money ( ) ) {
if ( bestval = = - 1 | | bestval < counter [ utype ] ) {
bestval = counter [ utype ] ;
bestcount = 0 ;
}
bestlist [ bestcount + + ] = utype ;
}
}
/*
* * The unit type to build is now known . Fetch a pointer to the techno type class .
*/
if ( bestcount ) {
BuildVessel = bestlist [ Random_Pick ( 0 , bestcount - 1 ) ] ;
}
}
if ( IsBaseBuilding ) {
BuildVessel = VESSEL_NONE ;
}
# endif
return ( TICKS_PER_SECOND ) ;
}
/***********************************************************************************************
* HouseClass : : AI_Infantry - - Determines the infantry unit to build . *
* *
* This routine handles the general case of determining what infantry unit to build *
* next . *
* *
* INPUT : none *
* *
* OUTPUT : Returns with the number of game frames to delay before being called again . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 29 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
int HouseClass : : AI_Infantry ( void )
{
//assert(Houses.ID(this) == ID);
if ( BuildInfantry ! = INFANTRY_NONE ) return ( TICKS_PER_SECOND ) ;
if ( CurInfantry > = Control . MaxInfantry ) return ( TICKS_PER_SECOND ) ;
//if (Session.Type == GAME_NORMAL) {
if ( GameToPlay = = GAME_NORMAL ) { // Not used for skirmish? ST - 7/24/2019 2:59PM
# if (0)
TechnoTypeClass const * techno = 0 ;
int counter [ INFANTRY_COUNT ] ;
memset ( counter , 0x00 , sizeof ( counter ) ) ;
/*
* * Build a list of the maximum of each type we wish to produce . This will be
* * twice the number required to fill all teams .
*/
int index ;
for ( index = 0 ; index < Teams . Count ( ) ; index + + ) {
TeamClass * tptr = Teams . Ptr ( index ) ;
if ( tptr ! = NULL ) {
TeamTypeClass const * team = tptr - > Class ;
//if (((team->IsReinforcable && !tptr->IsFullStrength) || (!tptr->IsForcedActive && !tptr->IsHasBeen && !tptr->JustAltered)) && team->House == Class->House) {
if ( ( ( team - > IsReinforcable & & ! tptr - > IsFullStrength ) | | ( ! tptr - > IsForcedActive & & ! tptr - > IsHasBeen & & ! tptr - > IsAltered ) ) & & team - > House = = Class - > House ) {
for ( int subindex = 0 ; subindex < team - > ClassCount ; subindex + + ) {
if ( team - > Members [ subindex ] . Class - > What_Am_I ( ) = = RTTI_INFANTRYTYPE ) {
//counter[((InfantryTypeClass const *)(team->Members[subindex].Class))->Type] += team->Members[subindex].Quantity + (team->IsReinforcable ? 1 : 0);
counter [ ( ( InfantryTypeClass const * ) ( team - > Members [ subindex ] . Class ) ) - > Type ] + = 1 + ( team - > IsReinforcable ? 1 : 0 ) ;
}
}
}
}
}
/*
* * Team types that are flagged as prebuilt , will always try to produce enough
* * to fill one team of this type regardless of whether there is a team active
* * of that type .
*/
for ( index = 0 ; index < TeamTypes . Count ( ) ; index + + ) {
TeamTypeClass const * team = TeamTypes . Ptr ( index ) ;
if ( team ! = NULL ) {
if ( team - > House = = Class - > House & & team - > IsPrebuilt & & ( ! team - > IsAutocreate | | IsAlerted ) ) {
for ( int subindex = 0 ; subindex < team - > ClassCount ; subindex + + ) {
if ( team - > Members [ subindex ] . Class - > What_Am_I ( ) = = RTTI_INFANTRYTYPE ) {
int subtype = ( ( InfantryTypeClass const * ) ( team - > Members [ subindex ] . Class ) ) - > Type ;
// counter[subtype] = 1;
//counter[subtype] = max(counter[subtype], team->Members[subindex].Quantity);
counter [ subtype ] = max ( counter [ subtype ] , 1 ) ;
counter [ subtype ] = min ( counter [ subtype ] , 5 ) ;
}
}
}
}
}
/*
* * Reduce the theoretical maximum by the actual number of objects currently
* * in play .
*/
for ( int uindex = 0 ; uindex < Infantry . Count ( ) ; uindex + + ) {
InfantryClass * infantry = Infantry . Ptr ( uindex ) ;
//if (infantry != NULL && infantry->Is_Recruitable(this) && counter[infantry->Class->Type] > 0) {
if ( infantry ! = NULL & & counter [ infantry - > Class - > Type ] > 0 ) {
counter [ infantry - > Class - > Type ] - - ;
}
}
/*
* * Pick to build the most needed object but don ' t consider those object that
* * can ' t be built because of scenario restrictions or insufficient cash .
*/
int bestval = - 1 ;
int bestcount = 0 ;
InfantryType bestlist [ INFANTRY_COUNT ] ;
for ( InfantryType utype = INFANTRY_FIRST ; utype < INFANTRY_COUNT ; utype + + ) {
if ( utype ! = INFANTRY_DOG | | ! ( IScan & INFANTRYF_DOG ) ) {
if ( counter [ utype ] > 0 & & Can_Build ( & InfantryTypeClass : : As_Reference ( utype ) , Class - > House ) & & InfantryTypeClass : : As_Reference ( utype ) . Cost_Of ( ) < = Available_Money ( ) ) {
if ( bestval = = - 1 | | bestval < counter [ utype ] ) {
bestval = counter [ utype ] ;
bestcount = 0 ;
}
bestlist [ bestcount + + ] = utype ;
}
}
}
/*
* * The infantry type to build is now known . Fetch a pointer to the techno type class .
*/
if ( bestcount ) {
int pick = Random_Pick ( 0 , bestcount - 1 ) ;
BuildInfantry = bestlist [ pick ] ;
}
# endif
}
if ( IsBaseBuilding ) {
HouseClass const * enemy = NULL ;
if ( Enemy ! = HOUSE_NONE ) {
enemy = HouseClass : : As_Pointer ( Enemy ) ;
}
/*
* * This structure is used to keep track of the list of infantry types that should be
* * built . The infantry type and the value assigned to it is recorded .
*/
struct {
InfantryType Type ; // Infantry type.
int Value ; // Relative value assigned.
} typetrack [ INFANTRY_COUNT ] ;
int count = 0 ;
int total = 0 ;
for ( InfantryType index = INFANTRY_FIRST ; index < INFANTRY_COUNT ; index + + ) {
//if (Can_Build(&InfantryTypeClass::As_Reference(index), ActLike) && InfantryTypeClass::As_Reference(index).Level <= (unsigned)Control.TechLevel) {
if ( Can_Build ( & InfantryTypeClass : : As_Reference ( index ) , ActLike ) & & InfantryTypeClass : : As_Reference ( index ) . Level < = ( unsigned ) BuildLevel ) {
typetrack [ count ] . Value = 0 ;
# ifdef FIXIT_CSII // checked - ajw 9/28/98 This looks like a potential bug. It is prob. for save game format compatibility.
int clipindex = index ;
if ( clipindex > = INFANTRY_RA_COUNT ) clipindex - = INFANTRY_RA_COUNT ;
if ( ( enemy ! = NULL & & enemy - > IQuantity [ clipindex ] > IQuantity [ clipindex ] ) | | Available_Money ( ) > Rule . InfantryReserve | | CurInfantry < CurBuildings * Rule . InfantryBaseMult ) {
# else
if ( ( enemy ! = NULL & & enemy - > IQuantity [ index ] > IQuantity [ index ] ) | | Available_Money ( ) > Rule . InfantryReserve | | CurInfantry < CurBuildings * Rule . InfantryBaseMult ) {
# endif
switch ( index ) {
case INFANTRY_E1 :
typetrack [ count ] . Value = 3 ;
break ;
case INFANTRY_E2 :
typetrack [ count ] . Value = 5 ;
break ;
case INFANTRY_E3 :
typetrack [ count ] . Value = 2 ;
break ;
case INFANTRY_E4 :
typetrack [ count ] . Value = 5 ;
break ;
//case INFANTRY_RENOVATOR:
case INFANTRY_E7 :
if ( CurInfantry > 5 ) {
typetrack [ count ] . Value = 1 - max ( IQuantity [ index ] , 0 ) ;
}
break ;
//case INFANTRY_TANYA:
// typetrack[count].Value = 1 - max(IQuantity[index], 0);
// break;
default :
typetrack [ count ] . Value = 0 ;
break ;
}
}
if ( typetrack [ count ] . Value > 0 ) {
typetrack [ count ] . Type = index ;
total + = typetrack [ count ] . Value ;
count + + ;
}
}
}
/*
* * If there is at least one choice , then pick it . The object picked
* * is influenced by the weight ( value ) assigned to it . This is accomplished
* * by picking a number between 0 and the total weight value . The appropriate
* * infantry object that matches the number picked is then selected to be built .
*/
if ( count > 0 ) {
int pick = Random_Pick ( 0 , total - 1 ) ;
for ( int index = 0 ; index < count ; index + + ) {
if ( pick < typetrack [ index ] . Value ) {
BuildInfantry = typetrack [ index ] . Type ;
break ;
}
pick - = typetrack [ index ] . Value ;
}
}
}
return ( TICKS_PER_SECOND ) ;
}
/***********************************************************************************************
* HouseClass : : AI_Aircraft - - Determines what aircraft to build next . *
* *
* This routine is used to determine the general case of what aircraft to build next . *
* *
* INPUT : none *
* *
* OUTPUT : Returns with the number of frame to delay before calling this routine again . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 29 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
int HouseClass : : AI_Aircraft ( void )
{
//assert(Houses.ID(this) == ID);
if ( ! IsHuman & & IQ > = Rule . IQAircraft ) {
if ( BuildAircraft ! = AIRCRAFT_NONE ) return ( TICKS_PER_SECOND ) ;
if ( CurAircraft > = Control . MaxAircraft ) return ( TICKS_PER_SECOND ) ;
if ( Can_Build ( & AircraftTypeClass : : As_Reference ( AIRCRAFT_HELICOPTER ) , ActLike ) & &
//AircraftTypeClass::As_Reference(AIRCRAFT_MIG).Level <= (unsigned)Control.TechLevel &&
AircraftTypeClass : : As_Reference ( AIRCRAFT_HELICOPTER ) . Level < = ( unsigned ) BuildLevel & &
BQuantity [ STRUCT_AIRSTRIP ] > AQuantity [ AIRCRAFT_HELICOPTER ] + AQuantity [ AIRCRAFT_ORCA ] ) {
BuildAircraft = AIRCRAFT_HELICOPTER ;
return ( TICKS_PER_SECOND ) ;
}
if ( Can_Build ( & AircraftTypeClass : : As_Reference ( AIRCRAFT_ORCA ) , ActLike ) & &
//AircraftTypeClass::As_Reference(AIRCRAFT_YAK).Level <= (unsigned)Control.TechLevel &&
AircraftTypeClass : : As_Reference ( AIRCRAFT_ORCA ) . Level < = ( unsigned ) BuildLevel & &
BQuantity [ STRUCT_AIRSTRIP ] > AQuantity [ AIRCRAFT_ORCA ] + AQuantity [ AIRCRAFT_HELICOPTER ] ) {
BuildAircraft = AIRCRAFT_ORCA ;
return ( TICKS_PER_SECOND ) ;
}
# if (0)
if ( Can_Build ( & AircraftTypeClass : : As_Reference ( AIRCRAFT_LONGBOW ) , ActLike ) & &
//AircraftTypeClass::As_Reference(AIRCRAFT_LONGBOW).Level <= (unsigned)Control.TechLevel &&
AircraftTypeClass : : As_Reference ( AIRCRAFT_LONGBOW ) . Level < = ( unsigned ) BuildLevel & &
BQuantity [ STRUCT_HELIPAD ] > AQuantity [ AIRCRAFT_LONGBOW ] + AQuantity [ AIRCRAFT_HIND ] ) {
BuildAircraft = AIRCRAFT_LONGBOW ;
return ( TICKS_PER_SECOND ) ;
}
if ( Can_Build ( & AircraftTypeClass : : As_Reference ( AIRCRAFT_HIND ) , ActLike ) & &
//AircraftTypeClass::As_Reference(AIRCRAFT_HIND).Level <= (unsigned)Control.TechLevel &&
AircraftTypeClass : : As_Reference ( AIRCRAFT_HIND ) . Level < = ( unsigned ) BuildLevel & &
BQuantity [ STRUCT_HELIPAD ] > AQuantity [ AIRCRAFT_LONGBOW ] + AQuantity [ AIRCRAFT_HIND ] ) {
BuildAircraft = AIRCRAFT_HIND ;
return ( TICKS_PER_SECOND ) ;
}
if ( Can_Build ( & AircraftTypeClass : : As_Reference ( AIRCRAFT_MIG ) , ActLike ) & &
//AircraftTypeClass::As_Reference(AIRCRAFT_MIG).Level <= (unsigned)Control.TechLevel &&
AircraftTypeClass : : As_Reference ( AIRCRAFT_MIG ) . Level < = ( unsigned ) BuildLevel & &
BQuantity [ STRUCT_AIRSTRIP ] > AQuantity [ AIRCRAFT_MIG ] + AQuantity [ AIRCRAFT_YAK ] ) {
BuildAircraft = AIRCRAFT_MIG ;
return ( TICKS_PER_SECOND ) ;
}
if ( Can_Build ( & AircraftTypeClass : : As_Reference ( AIRCRAFT_YAK ) , ActLike ) & &
//AircraftTypeClass::As_Reference(AIRCRAFT_YAK).Level <= (unsigned)Control.TechLevel &&
AircraftTypeClass : : As_Reference ( AIRCRAFT_YAK ) . Level < = ( unsigned ) BuildLevel & &
BQuantity [ STRUCT_AIRSTRIP ] > AQuantity [ AIRCRAFT_MIG ] + AQuantity [ AIRCRAFT_YAK ] ) {
BuildAircraft = AIRCRAFT_YAK ;
return ( TICKS_PER_SECOND ) ;
}
# endif
}
return ( TICKS_PER_SECOND ) ;
}
/***********************************************************************************************
* HouseClass : : Production_Begun - - Records that production has begun . *
* *
* This routine is used to inform the Expert System that production of the specified object *
* has begun . This allows the AI to proceed with picking another object to begin production *
* on . *
* *
* INPUT : product - - Pointer to the object that production has just begun on . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 29 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Production_Begun ( TechnoClass const * product )
{
//assert(Houses.ID(this) == ID);
if ( product ! = NULL ) {
switch ( product - > What_Am_I ( ) ) {
case RTTI_UNIT :
if ( * ( ( UnitClass * ) product ) = = BuildUnit ) {
BuildUnit = UNIT_NONE ;
}
break ;
# if (0)
case RTTI_VESSEL :
if ( * ( ( VesselClass * ) product ) = = BuildVessel ) {
BuildVessel = VESSEL_NONE ;
}
break ;
# endif
case RTTI_INFANTRY :
if ( * ( ( InfantryClass * ) product ) = = BuildInfantry ) {
BuildInfantry = INFANTRY_NONE ;
}
break ;
case RTTI_BUILDING :
if ( * ( ( BuildingClass * ) product ) = = BuildStructure ) {
BuildStructure = STRUCT_NONE ;
}
break ;
case RTTI_AIRCRAFT :
if ( * ( ( AircraftClass * ) product ) = = BuildAircraft ) {
BuildAircraft = AIRCRAFT_NONE ;
}
break ;
default :
break ;
}
}
}
/***********************************************************************************************
* HouseClass : : Tracking_Remove - - Remove object from house tracking system . *
* *
* This routine informs the Expert System that the specified object is no longer part of *
* this house ' s inventory . This occurs when the object is destroyed or captured . *
* *
* INPUT : techno - - Pointer to the object to remove from the tracking systems of this *
* house . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 29 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Tracking_Remove ( TechnoClass const * techno )
{
//assert(Houses.ID(this) == ID);
int type ;
switch ( techno - > What_Am_I ( ) ) {
case RTTI_BUILDING :
CurBuildings - - ;
BQuantity [ ( ( BuildingTypeClass const & ) techno - > Class_Of ( ) ) . Type ] - - ;
break ;
case RTTI_AIRCRAFT :
CurAircraft - - ;
AQuantity [ ( ( AircraftTypeClass const & ) techno - > Class_Of ( ) ) . Type ] - - ;
break ;
case RTTI_INFANTRY :
CurInfantry - - ;
if ( ! ( ( InfantryClass * ) techno ) - > IsTechnician ) {
type = ( ( InfantryTypeClass const & ) techno - > Class_Of ( ) ) . Type ;
# ifdef FIXIT_CSII // checked - ajw 9/28/98
if ( type > = INFANTRY_RA_COUNT ) type - = INFANTRY_RA_COUNT ;
# endif
IQuantity [ type ] - - ;
}
break ;
case RTTI_UNIT :
CurUnits - - ;
type = ( ( UnitTypeClass const & ) techno - > Class_Of ( ) ) . Type ;
# ifdef FIXIT_CSII // checked - ajw 9/28/98
if ( type > = UNIT_RA_COUNT ) type - = UNIT_RA_COUNT ;
# endif
UQuantity [ type ] - - ;
break ;
# if (0)
case RTTI_VESSEL :
CurVessels - - ;
type = ( ( VesselTypeClass const & ) techno - > Class_Of ( ) ) . Type ;
# ifdef FIXIT_CSII // checked - ajw 9/28/98
if ( type > = VESSEL_RA_COUNT ) type - = VESSEL_RA_COUNT ;
# endif
VQuantity [ type ] - - ;
break ;
# endif
default :
break ;
}
}
/***********************************************************************************************
* HouseClass : : Tracking_Add - - Informs house of new inventory item . *
* *
* This function is called when the specified object is now available as part of the house ' s *
* inventory . This occurs when the object is newly produced and also when it is captured *
* by this house . *
* *
* INPUT : techno - - Pointer to the object that is now part of the house inventory . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 29 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Tracking_Add ( TechnoClass const * techno )
{
//assert(Houses.ID(this) == ID);
StructType building ;
AircraftType aircraft ;
InfantryType infantry ;
UnitType unit ;
//VesselType vessel;
//int quant;
switch ( techno - > What_Am_I ( ) ) {
case RTTI_BUILDING :
CurBuildings + + ;
building = ( ( BuildingTypeClass const & ) techno - > Class_Of ( ) ) . Type ;
BQuantity [ building ] + + ;
BScan | = ( 1L < < building ) ;
# if (0) // This is a stats thing. ST - 7/24/2019 3:08PM
if ( Session . Type = = GAME_INTERNET ) {
BuildingTotals - > Increment_Unit_Total ( techno - > Class_Of ( ) . ID ) ;
}
# endif
break ;
case RTTI_AIRCRAFT :
CurAircraft + + ;
aircraft = ( ( AircraftTypeClass const & ) techno - > Class_Of ( ) ) . Type ;
AQuantity [ aircraft ] + + ;
AScan | = ( 1L < < aircraft ) ;
# if (0) // This is a stats thing. ST - 7/24/2019 3:08PM
if ( Session . Type = = GAME_INTERNET ) {
AircraftTotals - > Increment_Unit_Total ( techno - > Class_Of ( ) . ID ) ;
}
# endif
break ;
case RTTI_INFANTRY :
CurInfantry + + ;
infantry = ( ( InfantryTypeClass const & ) techno - > Class_Of ( ) ) . Type ;
if ( ! ( ( InfantryClass * ) techno ) - > IsTechnician ) {
# ifdef FIXIT_CSII // checked - ajw 9/28/98
quant = infantry ;
if ( quant > = INFANTRY_RA_COUNT ) quant - = INFANTRY_RA_COUNT ;
IQuantity [ quant ] + + ;
# else
IQuantity [ infantry ] + + ;
# endif
# if (0) // This is a stats thing. ST - 7/24/2019 3:08PM
if ( ! ( ( InfantryTypeClass const & ) techno - > Class_Of ( ) ) . IsCivilian & & Session . Type = = GAME_INTERNET ) {
InfantryTotals - > Increment_Unit_Total ( techno - > Class_Of ( ) . ID ) ;
}
# endif
IScan | = ( 1L < < infantry ) ;
}
break ;
case RTTI_UNIT :
CurUnits + + ;
unit = ( ( UnitTypeClass const & ) techno - > Class_Of ( ) ) . Type ;
# ifdef FIXIT_CSII // checked - ajw 9/28/98
quant = unit ;
if ( quant > = UNIT_RA_COUNT ) quant - = UNIT_RA_COUNT ;
UQuantity [ quant ] + + ;
# else
UQuantity [ unit ] + + ;
# endif
UScan | = ( 1L < < unit ) ;
# if (0) // This is a stats thing. ST - 7/24/2019 3:08PM
if ( Session . Type = = GAME_INTERNET ) {
UnitTotals - > Increment_Unit_Total ( techno - > Class_Of ( ) . ID ) ;
}
# endif
break ;
# if (0)
case RTTI_VESSEL :
CurVessels + + ;
vessel = ( ( VesselTypeClass const & ) techno - > Class_Of ( ) ) . Type ;
# ifdef FIXIT_CSII // checked - ajw 9/28/98
quant = vessel ;
if ( quant > = VESSEL_RA_COUNT ) quant - = VESSEL_RA_COUNT ;
VQuantity [ quant ] + + ;
# else
VQuantity [ vessel ] + + ;
# endif
VScan | = ( 1L < < vessel ) ;
if ( Session . Type = = GAME_INTERNET ) {
VesselTotals - > Increment_Unit_Total ( techno - > Class_Of ( ) . ID ) ;
}
break ;
# endif
default :
break ;
}
}
/***********************************************************************************************
* HouseClass : : Factory_Counter - - Fetches a pointer to the factory counter value . *
* *
* Use this routine to fetch a pointer to the variable that holds the number of factories *
* that can produce the specified object type . This is a helper routine used when *
* examining the number of factories as well as adjusting their number . *
* *
* INPUT : rtti - - The RTTI of the object that could be produced . *
* *
* OUTPUT : Returns with the number of factories owned by this house that could produce the *
* object of the type specified . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 07 / 30 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
int * HouseClass : : Factory_Counter ( RTTIType rtti )
{
switch ( rtti ) {
case RTTI_UNITTYPE :
case RTTI_UNIT :
return ( & UnitFactories ) ;
# if (0)
case RTTI_VESSELTYPE :
case RTTI_VESSEL :
return ( & VesselFactories ) ;
# endif
case RTTI_AIRCRAFTTYPE :
case RTTI_AIRCRAFT :
return ( & AircraftFactories ) ;
case RTTI_INFANTRYTYPE :
case RTTI_INFANTRY :
return ( & InfantryFactories ) ;
case RTTI_BUILDINGTYPE :
case RTTI_BUILDING :
return ( & BuildingFactories ) ;
default :
break ;
}
return ( NULL ) ;
}
/***********************************************************************************************
* HouseClass : : Active_Remove - - Remove this object from active duty for this house . *
* *
* This routine will recognize the specified object as having been removed from active *
* duty . *
* *
* INPUT : techno - - Pointer to the object to remove from active duty . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 07 / 16 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Active_Remove ( TechnoClass const * techno )
{
if ( techno = = NULL ) return ;
if ( techno - > What_Am_I ( ) = = RTTI_BUILDING ) {
int * fptr = Factory_Counter ( ( ( BuildingClass * ) techno ) - > Class - > ToBuild ) ;
if ( fptr ! = NULL ) {
* fptr = * fptr - 1 ;
}
}
}
/***********************************************************************************************
* HouseClass : : Active_Add - - Add an object to active duty for this house . *
* *
* This routine will recognize the specified object as having entered active duty . Any *
* abilities granted to the house by that object are now available . *
* *
* INPUT : techno - - Pointer to the object that is entering active duty . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 07 / 16 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Active_Add ( TechnoClass const * techno )
{
if ( techno = = NULL ) return ;
if ( techno - > What_Am_I ( ) = = RTTI_BUILDING ) {
int * fptr = Factory_Counter ( ( ( BuildingClass * ) techno ) - > Class - > ToBuild ) ;
if ( fptr ! = NULL ) {
* fptr = * fptr + 1 ;
}
}
}
/***********************************************************************************************
* HouseClass : : Which_Zone - - Determines what zone a coordinate lies in . *
* *
* This routine will determine what zone the specified coordinate lies in with respect to *
* this house ' s base . A location that is too distant from the base , even though it might *
* be a building , is not considered part of the base and returns ZONE_NONE . *
* *
* INPUT : coord - - The coordinate to examine . *
* *
* OUTPUT : Returns with the base zone that the specified coordinate lies in . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 10 / 02 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
ZoneType HouseClass : : Which_Zone ( COORDINATE coord ) const
{
//assert(Houses.ID(this) == ID);
if ( coord = = 0 ) return ( ZONE_NONE ) ;
int distance = Distance ( Center , coord ) ;
if ( distance < = Radius ) return ( ZONE_CORE ) ;
if ( distance > Radius * 4 ) return ( ZONE_NONE ) ;
DirType facing = Direction ( Center , coord ) ;
if ( facing < DIR_NE | | facing > DIR_NW ) return ( ZONE_NORTH ) ;
if ( facing > = DIR_NE & & facing < DIR_SE ) return ( ZONE_EAST ) ;
if ( facing > = DIR_SE & & facing < DIR_SW ) return ( ZONE_SOUTH ) ;
return ( ZONE_WEST ) ;
}
/***********************************************************************************************
* HouseClass : : Which_Zone - - Determines which base zone the specified object lies in . *
* *
* Use this routine to determine what zone the specified object lies in . *
* *
* INPUT : object - - Pointer to the object that will be checked for zone occupation . *
* *
* OUTPUT : Returns with the base zone that the object lies in . For objects that are too *
* distant from the center of the base , ZONE_NONE is returned . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 10 / 02 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
ZoneType HouseClass : : Which_Zone ( ObjectClass const * object ) const
{
//assert(Houses.ID(this) == ID);
if ( ! object ) return ( ZONE_NONE ) ;
return ( Which_Zone ( object - > Center_Coord ( ) ) ) ;
}
/***********************************************************************************************
* HouseClass : : Which_Zone - - Determines which base zone the specified cell lies in . *
* *
* This routine is used to determine what base zone the specified cell is in . *
* *
* INPUT : cell - - The cell to examine . *
* *
* OUTPUT : Returns the base zone that the cell lies in or ZONE_NONE if the cell is too far *
* away . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 10 / 02 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
ZoneType HouseClass : : Which_Zone ( CELL cell ) const
{
//assert(Houses.ID(this) == ID);
return ( Which_Zone ( Cell_Coord ( cell ) ) ) ;
}
/***********************************************************************************************
* HouseClass : : Recalc_Attributes - - Recalcs all houses existence bits . *
* *
* This routine will go through all game objects and reset the existence bits for the *
* owning house . This method ensures that if the object exists , then the corresponding *
* existence bit is also set . *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 10 / 02 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Recalc_Attributes ( void )
{
/*
* * Clear out all tracking values that will be filled in by this
* * routine . This allows the filling in process to not worry about
* * old existing values .
*/
int index ;
for ( index = 0 ; index < Houses . Count ( ) ; index + + ) {
HouseClass * house = Houses . Ptr ( index ) ;
if ( house ! = NULL ) {
house - > BScan = 0 ;
house - > ActiveBScan = 0 ;
house - > IScan = 0 ;
house - > ActiveIScan = 0 ;
house - > UScan = 0 ;
house - > ActiveUScan = 0 ;
house - > AScan = 0 ;
house - > ActiveAScan = 0 ;
# if (0)
house - > VScan = 0 ;
house - > ActiveVScan = 0 ;
# endif
}
}
/*
* * A second pass through the sentient objects is required so that the appropriate scan
* * bits will be set for the owner house .
*/
for ( index = 0 ; index < Units . Count ( ) ; index + + ) {
UnitClass const * unit = Units . Ptr ( index ) ;
unit - > House - > UScan | = ( 1L < < unit - > Class - > Type ) ;
//if (unit->IsLocked && (Session.Type != GAME_NORMAL || !unit->House->IsHuman || unit->IsDiscoveredByPlayer)) {
if ( unit - > IsLocked ) {
if ( ! unit - > IsInLimbo ) {
unit - > House - > ActiveUScan | = ( 1L < < unit - > Class - > Type ) ;
}
}
}
for ( index = 0 ; index < Infantry . Count ( ) ; index + + ) {
InfantryClass const * infantry = Infantry . Ptr ( index ) ;
infantry - > House - > IScan | = ( 1L < < infantry - > Class - > Type ) ;
//if (infantry->IsLocked && (Session.Type != GAME_NORMAL || !infantry->House->IsHuman || infantry->IsDiscoveredByPlayer)) {
if ( infantry - > IsLocked ) {
if ( ! infantry - > IsInLimbo ) {
infantry - > House - > ActiveIScan | = ( 1L < < infantry - > Class - > Type ) ;
//infantry->House->OldIScan |= (1L << infantry->Class->Type);
}
}
}
for ( index = 0 ; index < Aircraft . Count ( ) ; index + + ) {
AircraftClass const * aircraft = Aircraft . Ptr ( index ) ;
aircraft - > House - > AScan | = ( 1L < < aircraft - > Class - > Type ) ;
//if (aircraft->IsLocked && (Session.Type != GAME_NORMAL || !aircraft->House->IsHuman || aircraft->IsDiscoveredByPlayer)) {
if ( aircraft - > IsLocked ) {
if ( ! aircraft - > IsInLimbo ) {
aircraft - > House - > ActiveAScan | = ( 1L < < aircraft - > Class - > Type ) ;
//aircraft->House->OldAScan |= (1L << aircraft->Class->Type);
}
}
}
for ( index = 0 ; index < Buildings . Count ( ) ; index + + ) {
BuildingClass const * building = Buildings . Ptr ( index ) ;
if ( building - > Class - > Type < 32 ) {
building - > House - > BScan | = ( 1L < < building - > Class - > Type ) ;
//if (building->IsLocked && (Session.Type != GAME_NORMAL || !building->House->IsHuman || building->IsDiscoveredByPlayer)) {
if ( building - > IsLocked ) {
if ( ! building - > IsInLimbo ) {
building - > House - > ActiveBScan | = ( 1L < < building - > Class - > Type ) ;
building - > House - > OldBScan | = ( 1L < < building - > Class - > Type ) ;
}
}
}
}
# if (0)
for ( index = 0 ; index < Vessels . Count ( ) ; index + + ) {
VesselClass const * vessel = Vessels . Ptr ( index ) ;
vessel - > House - > VScan | = ( 1L < < vessel - > Class - > Type ) ;
if ( vessel - > IsLocked & & ( Session . Type ! = GAME_NORMAL | | ! vessel - > House - > IsHuman | | vessel - > IsDiscoveredByPlayer ) ) {
if ( ! vessel - > IsInLimbo ) {
vessel - > House - > ActiveVScan | = ( 1L < < vessel - > Class - > Type ) ;
vessel - > House - > OldVScan | = ( 1L < < vessel - > Class - > Type ) ;
}
}
}
# endif
}
/***********************************************************************************************
* HouseClass : : Zone_Cell - - Finds the cell closest to the center of the zone . *
* *
* This routine is used to find the cell that is closest to the center point of the *
* zone specified . Typical use of this routine is for building and unit placement so that *
* they can " cover " the specified zone . *
* *
* INPUT : zone - - The zone that the center point is to be returned . *
* *
* OUTPUT : Returns with the cell that is closest to the center point of the zone specified . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 10 / 02 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
CELL HouseClass : : Zone_Cell ( ZoneType zone ) const
{
//assert(Houses.ID(this) == ID);
switch ( zone ) {
case ZONE_CORE :
return ( Coord_Cell ( Center ) ) ;
case ZONE_NORTH :
return ( Coord_Cell ( Coord_Move ( Center , DIR_N , Radius * 3 ) ) ) ;
case ZONE_EAST :
return ( Coord_Cell ( Coord_Move ( Center , DIR_E , Radius * 3 ) ) ) ;
case ZONE_WEST :
return ( Coord_Cell ( Coord_Move ( Center , DIR_W , Radius * 3 ) ) ) ;
case ZONE_SOUTH :
return ( Coord_Cell ( Coord_Move ( Center , DIR_S , Radius * 3 ) ) ) ;
default :
break ;
}
return ( 0 ) ;
}
/***********************************************************************************************
* HouseClass : : Where_To_Go - - Determines where the object should go and wait . *
* *
* This function is called for every new unit produced or delivered in order to determine *
* where the unit should " hang out " to await further orders . The best area for the *
* unit to loiter is returned as a cell location . *
* *
* INPUT : object - - Pointer to the object that needs to know where to go . *
* *
* OUTPUT : Returns with the cell that the unit should move to . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 10 / 02 / 1995 JLB : Created . *
* 11 / 04 / 1996 JLB : Simplified to use helper functions *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
CELL HouseClass : : Where_To_Go ( FootClass const * object ) const
{
//assert(Houses.ID(this) == ID);
//assert(object != NULL);
ZoneType zone ; // The zone that the object should go to.
if ( object - > Anti_Air ( ) + object - > Anti_Armor ( ) + object - > Anti_Infantry ( ) = = 0 ) {
zone = ZONE_CORE ;
} else {
zone = Random_Pick ( ZONE_NORTH , ZONE_WEST ) ;
}
CELL cell = Random_Cell_In_Zone ( zone ) ;
//assert(cell != 0);
return ( Map . Nearby_Location ( cell ) ) ; //, SPEED_TRACK, Map[cell].Zones[MZONE_NORMAL], MZONE_NORMAL));
}
/***********************************************************************************************
* HouseClass : : Find_Juicy_Target - - Finds a suitable field target . *
* *
* This routine is used to find targets out in the field and away from base defense . *
* Typical of this would be the attack helicopters and the roving attack bands of *
* hunter killers . *
* *
* INPUT : coord - - The coordinate of the attacker . Closer targets are given preference . *
* *
* OUTPUT : Returns with a suitable target to attack . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 10 / 12 / 1995 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
TARGET HouseClass : : Find_Juicy_Target ( COORDINATE coord ) const
{
//assert(Houses.ID(this) == ID);
UnitClass * best = 0 ;
int value = 0 ;
for ( int index = 0 ; index < Units . Count ( ) ; index + + ) {
UnitClass * unit = Units . Ptr ( index ) ;
if ( unit & & ! unit - > IsInLimbo & & ! Is_Ally ( unit ) & & unit - > House - > Which_Zone ( unit ) = = ZONE_NONE ) {
int val = Distance ( coord , unit - > Center_Coord ( ) ) ;
if ( unit - > Anti_Air ( ) ) val * = 2 ;
if ( * unit = = UNIT_HARVESTER ) val / = 2 ;
if ( value = = 0 | | val < value ) {
value = val ;
best = unit ;
}
}
}
if ( best ) {
return ( best - > As_Target ( ) ) ;
}
return ( TARGET_NONE ) ;
}
/***********************************************************************************************
* HouseClass : : Get_Quantity - - Fetches the total number of aircraft of the specified type . *
* *
* Call this routine to fetch the total quantity of aircraft of the type specified that is *
* owned by this house . *
* *
* INPUT : aircraft - - The aircraft type to check the quantity of . *
* *
* OUTPUT : Returns with the total quantity of all aircraft of that type that is owned by this *
* house . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 07 / 09 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
int HouseClass : : Get_Quantity ( AircraftType aircraft )
{
return ( AQuantity [ aircraft ] ) ;
}
/***********************************************************************************************
* HouseClass : : Fetch_Factory - - Finds the factory associated with the object type specified . *
* *
* This is the counterpart to the Set_Factory function . It will return with a factory *
* pointer that is associated with the object type specified . *
* *
* INPUT : rtti - - The RTTI of the object type to find the factory for . *
* *
* OUTPUT : Returns with a pointer to the factory ( if present ) that can manufacture the *
* object type specified . *
* *
* WARNINGS : If this returns a non - NULL pointer , then the factory is probably already busy *
* producing another unit of that category . *
* *
* HISTORY : *
* 07 / 09 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
FactoryClass * HouseClass : : Fetch_Factory ( RTTIType rtti ) const
{
int factory_index = - 1 ;
switch ( rtti ) {
case RTTI_INFANTRY :
case RTTI_INFANTRYTYPE :
factory_index = InfantryFactory ;
break ;
case RTTI_UNIT :
case RTTI_UNITTYPE :
factory_index = UnitFactory ;
break ;
case RTTI_BUILDING :
case RTTI_BUILDINGTYPE :
factory_index = BuildingFactory ;
break ;
case RTTI_AIRCRAFT :
case RTTI_AIRCRAFTTYPE :
factory_index = AircraftFactory ;
break ;
# if (0)
case RTTI_VESSEL :
case RTTI_VESSELTYPE :
factory_index = VesselFactory ;
break ;
# endif
default :
factory_index = - 1 ;
break ;
}
/*
* * Fetch the actual pointer to the factory object . If there is
* * no object factory that matches the specified rtti type , then
* * null is returned .
*/
if ( factory_index ! = - 1 ) {
return ( Factories . Raw_Ptr ( factory_index ) ) ;
}
return ( NULL ) ;
}
/***********************************************************************************************
* HouseClass : : Set_Factory - - Assign specified factory to house tracking . *
* *
* Call this routine when a factory has been created and it now must be passed on to the *
* house for tracking purposes . The house maintains several factory pointers and this *
* routine will ensure that the factory pointer gets stored correctly . *
* *
* INPUT : rtti - - The RTTI of the object the factory it to manufacture . *
* *
* factory - - The factory object pointer . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 07 / 09 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Set_Factory ( RTTIType rtti , FactoryClass * factory )
{
int * factory_index = 0 ;
//assert(rtti != RTTI_NONE);
switch ( rtti ) {
case RTTI_UNIT :
case RTTI_UNITTYPE :
factory_index = & UnitFactory ;
break ;
case RTTI_INFANTRY :
case RTTI_INFANTRYTYPE :
factory_index = & InfantryFactory ;
break ;
# if (0)
case RTTI_VESSEL :
case RTTI_VESSELTYPE :
factory_index = & VesselFactory ;
break ;
# endif
case RTTI_BUILDING :
case RTTI_BUILDINGTYPE :
factory_index = & BuildingFactory ;
break ;
case RTTI_AIRCRAFT :
case RTTI_AIRCRAFTTYPE :
factory_index = & AircraftFactory ;
break ;
}
//assert(factory_index != NULL);
/*
* * Assign the factory to the appropriate slot . For the case of clearing
* * the factory out , then - 1 is assigned .
*/
if ( factory ! = NULL ) {
//*factory_index = factory->ID;
* factory_index = Factories . ID ( factory ) ;
} else {
* factory_index = - 1 ;
}
}
/***********************************************************************************************
* HouseClass : : Factory_Count - - Fetches the number of factories for specified type . *
* *
* This routine will count the number of factories owned by this house that can build *
* objects of the specified type . *
* *
* INPUT : rtti - - The type of object ( RTTI ) that the factories are to be counted for . *
* *
* OUTPUT : Returns with the number of factories that can build the object type specified . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 07 / 30 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
int HouseClass : : Factory_Count ( RTTIType rtti ) const
{
int const * ptr = ( ( HouseClass * ) this ) - > Factory_Counter ( rtti ) ;
if ( ptr ! = NULL ) {
return ( * ptr ) ;
}
return ( 0 ) ;
}
/***********************************************************************************************
* HouseClass : : Get_Quantity - - Gets the quantity of the building type specified . *
* *
* This will return the total number of buildings of that type owned by this house . *
* *
* INPUT : building - - The building type to check . *
* *
* OUTPUT : Returns with the number of buildings of that type owned by this house . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 07 / 09 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
int HouseClass : : Get_Quantity ( StructType building )
{
return ( BQuantity [ building ] ) ;
}
/***********************************************************************************************
* HouseClass : : Read_INI - - Reads house specific data from INI . *
* *
* This routine reads the house specific data for a particular *
* scenario from the scenario INI file . Typical data includes starting *
* credits , maximum unit count , etc . *
* *
* INPUT : buffer - - Pointer to loaded scenario INI file . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 05 / 24 / 1994 JLB : Created . *
* 05 / 18 / 1995 JLB : Creates all houses . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# if (0) // ST 7/17/2019
void HouseClass : : Read_INI ( CCINIClass & ini )
{
HouseClass * p ; // Pointer to current player data.
char const * hname ; // Pointer to house name.
for ( HousesType index = HOUSE_FIRST ; index < HOUSE_COUNT ; index + + ) {
hname = HouseTypeClass : : As_Reference ( index ) . IniName ;
p = new HouseClass ( index ) ;
p - > Control . TechLevel = ini . Get_Int ( hname , " TechLevel " , Scen . Scenario ) ;
p - > Control . MaxBuilding = ini . Get_Int ( hname , " MaxBuilding " , p - > Control . MaxBuilding ) ;
p - > Control . MaxUnit = ini . Get_Int ( hname , " MaxUnit " , p - > Control . MaxUnit ) ;
p - > Control . MaxInfantry = ini . Get_Int ( hname , " MaxInfantry " , p - > Control . MaxInfantry ) ;
p - > Control . MaxVessel = ini . Get_Int ( hname , " MaxVessel " , p - > Control . MaxVessel ) ;
if ( p - > Control . MaxVessel = = 0 ) p - > Control . MaxVessel = p - > Control . MaxUnit ;
p - > Control . InitialCredits = ini . Get_Int ( hname , " Credits " , 0 ) * 100 ;
p - > Credits = p - > Control . InitialCredits ;
int iq = ini . Get_Int ( hname , " IQ " , 0 ) ;
if ( iq > Rule . MaxIQ ) iq = 1 ;
p - > IQ = p - > Control . IQ = iq ;
p - > Control . Edge = ini . Get_SourceType ( hname , " Edge " , SOURCE_NORTH ) ;
p - > IsPlayerControl = ini . Get_Bool ( hname , " PlayerControl " , false ) ;
int owners = ini . Get_Owners ( hname , " Allies " , ( 1 < < HOUSE_NEUTRAL ) ) ;
p - > Make_Ally ( index ) ;
p - > Make_Ally ( HOUSE_NEUTRAL ) ;
for ( HousesType h = HOUSE_FIRST ; h < HOUSE_COUNT ; h + + ) {
if ( ( owners & ( 1 < < h ) ) ! = 0 ) {
p - > Make_Ally ( h ) ;
}
}
}
}
# endif
/***********************************************************************************************
* HouseClass : : Write_INI - - Writes the house data to the INI database . *
* *
* This routine will write out all data necessary to recreate it in anticipation of a *
* new scenario . All houses ( that are active ) will have their scenario type data written *
* out . *
* *
* INPUT : ini - - Reference to the INI database to write the data to . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 07 / 09 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# if (0) // ST 7/17/2019
void HouseClass : : Write_INI ( CCINIClass & ini )
{
/*
* * The identity house control object . Only if the house value differs from the
* * identity , will the data be written out .
*/
HouseStaticClass control ;
for ( HousesType i = HOUSE_FIRST ; i < HOUSE_COUNT ; i + + ) {
HouseClass * p = As_Pointer ( i ) ;
if ( p ! = NULL ) {
char const * name = p - > Class - > IniName ;
ini . Clear ( name ) ;
if ( i > = HOUSE_MULTI1 ) continue ;
if ( p - > Control . InitialCredits ! = control . InitialCredits ) {
ini . Put_Int ( name , " Credits " , ( int ) ( p - > Control . InitialCredits / 100 ) ) ;
}
if ( p - > Control . Edge ! = control . Edge ) {
ini . Put_SourceType ( name , " Edge " , p - > Control . Edge ) ;
}
if ( p - > Control . MaxUnit > 0 & & p - > Control . MaxUnit ! = control . MaxUnit ) {
ini . Put_Int ( name , " MaxUnit " , p - > Control . MaxUnit ) ;
}
if ( p - > Control . MaxInfantry > 0 & & p - > Control . MaxInfantry ! = control . MaxInfantry ) {
ini . Put_Int ( name , " MaxInfantry " , p - > Control . MaxInfantry ) ;
}
if ( p - > Control . MaxBuilding > 0 & & p - > Control . MaxBuilding ! = control . MaxBuilding ) {
ini . Put_Int ( name , " MaxBuilding " , p - > Control . MaxBuilding ) ;
}
if ( p - > Control . MaxVessel > 0 & & p - > Control . MaxVessel ! = control . MaxVessel ) {
ini . Put_Int ( name , " MaxVessel " , p - > Control . MaxVessel ) ;
}
if ( p - > Control . TechLevel ! = control . TechLevel ) {
ini . Put_Int ( name , " TechLevel " , p - > Control . TechLevel ) ;
}
if ( p - > Control . IQ ! = control . IQ ) {
ini . Put_Int ( name , " IQ " , p - > Control . IQ ) ;
}
if ( p - > IsPlayerControl ! = false & & p ! = PlayerPtr ) {
ini . Put_Bool ( name , " PlayerControl " , p - > IsPlayerControl ) ;
}
ini . Put_Owners ( name , " Allies " , p - > Control . Allies & ~ ( ( 1 < < p - > Class - > House ) | ( 1 < < HOUSE_NEUTRAL ) ) ) ;
}
}
}
# endif
# if (0)
/***********************************************************************************************
* HouseClass : : Is_No_YakMig - - Determines if no more yaks or migs should be allowed . *
* *
* This routine will examine the current yak and mig situation verses airfields . If there *
* are equal aircraft to airfields , then this routine will return TRUE . *
* *
* INPUT : none *
* *
* OUTPUT : bool ; Are all airfields full and thus no more yaks or migs are allowed ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 23 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Is_No_YakMig ( void ) const
{
int quantity = AQuantity [ AIRCRAFT_YAK ] + AQuantity [ AIRCRAFT_MIG ] ;
/*
* * Adjust the quantity down one if there is an aircraft in production . This will
* * allow production to resume after being held .
*/
FactoryClass const * factory = Fetch_Factory ( RTTI_AIRCRAFT ) ;
if ( factory ! = NULL & & factory - > Get_Object ( ) ! = NULL ) {
AircraftClass const * air = ( AircraftClass const * ) factory - > Get_Object ( ) ;
if ( * air = = AIRCRAFT_MIG | | * air = = AIRCRAFT_YAK ) {
quantity - = 1 ;
}
}
if ( quantity > = BQuantity [ STRUCT_AIRSTRIP ] ) {
return ( true ) ;
}
return ( false ) ;
}
/***********************************************************************************************
* HouseClass : : Is_Hack_Prevented - - Is production of the specified type and id prohibted ? *
* *
* This is a special hack check routine to see if the object type and id specified is *
* prevented from being produced . The Yak and the Mig are so prevented if there would be *
* insufficient airfields for them to land upon . *
* *
* INPUT : rtti - - The RTTI type of the value specified . *
* *
* value - - The type number ( according to the RTTI type specified ) . *
* *
* OUTPUT : bool ; Is production of this object prohibited ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 23 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Is_Hack_Prevented ( RTTIType rtti , int value ) const
{
if ( rtti = = RTTI_AIRCRAFTTYPE & & ( value = = AIRCRAFT_MIG | | value = = AIRCRAFT_YAK ) ) {
return ( Is_No_YakMig ( ) ) ;
}
return ( false ) ;
}
# endif
/***********************************************************************************************
* HouseClass : : Fire_Sale - - Cause all buildings to be sold . *
* *
* This routine will sell back all buildings owned by this house . *
* *
* INPUT : none *
* *
* OUTPUT : bool ; Was a fire sale performed ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 23 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Fire_Sale ( void )
{
if ( CurBuildings > 0 ) {
for ( int index = 0 ; index < Buildings . Count ( ) ; index + + ) {
BuildingClass * b = Buildings . Ptr ( index ) ;
if ( b ! = NULL & & ! b - > IsInLimbo & & b - > House = = this & & b - > Strength > 0 ) {
b - > Sell_Back ( 1 ) ;
}
}
return ( true ) ;
}
return ( false ) ;
}
/***********************************************************************************************
* HouseClass : : Do_All_To_Hunt - - Send all units to hunt . *
* *
* This routine will cause all combatants of this house to go into hunt mode . The effect of *
* this is to throw everything this house has to muster at the enemies of this house . *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 23 / 1996 JLB : Created . *
* 10 / 02 / 1996 JLB : Handles aircraft too . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Do_All_To_Hunt ( void ) const
{
int index ;
for ( index = 0 ; index < Units . Count ( ) ; index + + ) {
UnitClass * unit = Units . Ptr ( index ) ;
if ( unit - > House = = this & & unit - > IsDown & & ! unit - > IsInLimbo ) {
if ( unit - > Team ) unit - > Team - > Remove ( unit ) ;
unit - > Assign_Mission ( MISSION_HUNT ) ;
}
}
for ( index = 0 ; index < Infantry . Count ( ) ; index + + ) {
InfantryClass * infantry = Infantry . Ptr ( index ) ;
if ( infantry - > House = = this & & infantry - > IsDown & & ! infantry - > IsInLimbo ) {
if ( infantry - > Team ) infantry - > Team - > Remove ( infantry ) ;
infantry - > Assign_Mission ( MISSION_HUNT ) ;
}
}
# if (0)
for ( index = 0 ; index < Vessels . Count ( ) ; index + + ) {
VesselClass * vessel = Vessels . Ptr ( index ) ;
if ( vessel - > House = = this & & vessel - > IsDown & & ! vessel - > IsInLimbo ) {
if ( vessel - > Team ) vessel - > Team - > Remove ( vessel ) ;
vessel - > Assign_Mission ( MISSION_HUNT ) ;
}
}
# endif
for ( index = 0 ; index < Aircraft . Count ( ) ; index + + ) {
AircraftClass * aircraft = Aircraft . Ptr ( index ) ;
if ( aircraft - > House = = this & & aircraft - > IsDown & & ! aircraft - > IsInLimbo ) {
if ( aircraft - > Team ) aircraft - > Team - > Remove ( aircraft ) ;
aircraft - > Assign_Mission ( MISSION_HUNT ) ;
}
}
}
/***********************************************************************************************
* HouseClass : : Is_Allowed_To_Ally - - Determines if this house is allied to make allies . *
* *
* Use this routine to determine if this house is legally allowed to ally with the *
* house specified . There are many reason why an alliance is not allowed . Typically , this *
* is when there would be no more opponents left to fight or if this house has been *
* defeated . *
* *
* INPUT : house - - The house that alliance with is desired . *
* *
* OUTPUT : bool ; Is alliance with the house specified prohibited ? *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 23 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
bool HouseClass : : Is_Allowed_To_Ally ( HousesType house ) const
{
/*
* * Is not allowed to ally with a house that is patently invalid , such
* * as one that is illegally defined .
*/
if ( house = = HOUSE_NONE ) {
return ( false ) ;
}
/*
* * One cannot ally twice with the same house .
*/
if ( Is_Ally ( house ) ) {
return ( false ) ;
}
/*
* * If the scenario is being set up , then alliances are always
* * allowed . No further checking is required .
*/
if ( ScenarioInit ) {
return ( true ) ;
}
/*
* * Alliances ( outside of scneario init time ) are allowed only if
* * this is a multiplayer game . Otherwise , they are prohibited .
*/
//if (Session.Type == GAME_NORMAL) {
if ( GameToPlay = = GAME_NORMAL ) {
return ( false ) ;
}
/*
* * When the house is defeated , it can no longer make alliances .
*/
if ( IsDefeated ) {
return ( false ) ;
}
# ifdef FIXIT_VERSION_3
// Fix to prevent ally with computer.
if ( ! HouseClass : : As_Pointer ( house ) - > IsHuman ) {
return ( false ) ;
}
# else // FIXIT_VERSION_3
# ifdef FIXIT_NO_COMP_ALLY
// Fix to prevent ally with computer.
if ( PlayingAgainstVersion > VERSION_RED_ALERT_104 & & ! HouseClass : : As_Pointer ( house ) - > IsHuman ) {
return ( false ) ;
}
# endif
# endif // FIXIT_VERSION_3
/*
* * Count the number of active houses in the game as well as the
* * number of existing allies with this house .
*/
int housecount = 0 ;
int allycount = 0 ;
for ( HousesType house2 = HOUSE_MULTI1 ; house2 < HOUSE_COUNT ; house2 + + ) {
HouseClass * hptr = HouseClass : : As_Pointer ( house2 ) ;
if ( hptr ! = NULL & & hptr - > IsActive & & ! hptr - > IsDefeated ) {
housecount + + ;
if ( Is_Ally ( hptr ) ) {
allycount + + ;
}
}
}
/*
* * Alliance is not allowed if there wouldn ' t be any enemies left to
* * fight .
*/
if ( housecount = = allycount + 1 ) {
return ( false ) ;
}
return ( true ) ;
}
/***********************************************************************************************
* HouseClass : : Computer_Paranoid - - Cause the computer players to becom paranoid . *
* *
* This routine will cause the computer players to become suspicious of the human *
* players and thus the computer players will band together in order to defeat the *
* human players . *
* *
* INPUT : none *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 23 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Computer_Paranoid ( void )
{
if ( GameToPlay ! = GAME_GLYPHX_MULTIPLAYER ) { // Re-enable this for multiplayer if we support classic team/ally mode. ST - 10/29/2019
/*
* * Loop through every computer controlled house and make allies with all other computer
* * controlled houses and then make enemies with all other human controlled houses .
*/
for ( HousesType house = HOUSE_MULTI1 ; house < HOUSE_COUNT ; house + + ) {
HouseClass * hptr = HouseClass : : As_Pointer ( house ) ;
if ( hptr ! = NULL & & hptr - > IsActive & & ! hptr - > IsDefeated & & ! hptr - > IsHuman ) {
hptr - > IsParanoid = true ;
/*
* * Break alliance with every human it is allied with and make friends with
* * any other computer players .
*/
for ( HousesType house2 = HOUSE_MULTI1 ; house2 < HOUSE_COUNT ; house2 + + ) {
HouseClass * hptr2 = HouseClass : : As_Pointer ( house2 ) ;
if ( hptr2 ! = NULL & & hptr2 - > IsActive & & ! hptr2 - > IsDefeated ) {
if ( hptr2 - > IsHuman ) {
hptr - > Make_Enemy ( house2 ) ;
} else {
hptr - > Make_Ally ( house2 ) ;
}
}
}
}
}
}
}
/***********************************************************************************************
* HouseClass : : Adjust_Power - - Adjust the power value of the house . *
* *
* This routine will update the power output value of the house . It will cause any buildgins *
* that need to be redrawn to do so . *
* *
* INPUT : adjust - - The amount to adjust the power output value . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 11 / 01 / 1996 BWG : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Adjust_Power ( int adjust )
{
Power + = adjust ;
}
/***********************************************************************************************
* HouseClass : : Adjust_Drain - - Adjust the power drain value of the house . *
* *
* This routine will update the drain value of the house . It will cause any buildings that *
* need to be redraw to do so . *
* *
* INPUT : adjust - - The amount to adjust the drain ( positive means more drain ) . *
* *
* OUTPUT : none *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 11 / 01 / 1996 BWG : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
void HouseClass : : Adjust_Drain ( int adjust )
{
Drain + = adjust ;
}
/***********************************************************************************************
* HouseClass : : Find_Cell_In_Zone - - Finds a legal placement cell within the zone . *
* *
* Use this routine to determine where the specified object should go if it were to go *
* some random ( but legal ) location within the zone specified . *
* *
* INPUT : techno - - The object that is desirous of going into the zone specified . *
* *
* zone - - The zone to find a location within . *
* *
* OUTPUT : Returns with the cell that the specified object could be placed in the zone . If *
* no valid location could be found , then 0 is returned . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 11 / 01 / 1996 JLB : Created . *
* 11 / 04 / 1996 JLB : Not so strict on zone requirement . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
CELL HouseClass : : Find_Cell_In_Zone ( TechnoClass const * techno , ZoneType zone ) const
{
if ( techno = = NULL ) return ( 0 ) ;
int bestval = - 1 ;
int bestcell = 0 ;
TechnoTypeClass const * ttype = techno - > Techno_Type_Class ( ) ;
/*
* * Pick a random location within the zone specified .
*/
CELL trycell = Random_Cell_In_Zone ( zone ) ;
short const * list = NULL ;
if ( techno - > What_Am_I ( ) = = RTTI_BUILDING ) {
list = techno - > Occupy_List ( true ) ;
}
/*
* * Find a legal placement position as close as possible to the picked location while still
* * remaining within the zone .
*/
for ( CELL cell = 0 ; cell < MAP_CELL_TOTAL ; cell + + ) {
// if (Map.In_Radar(cell)) {
if ( Map . In_Radar ( cell ) & & Which_Zone ( cell ) ! = ZONE_NONE ) {
bool ok = ttype - > Legal_Placement ( cell ) ;
/*
* * Another ( adjacency ) check is required for buildings .
*/
if ( ok & & list ! = NULL & & ! Map . Passes_Proximity_Check ( ttype , techno - > House - > Class - > House , list , cell ) ) {
ok = false ;
}
if ( ok ) {
int dist = Distance ( Cell_Coord ( cell ) , Cell_Coord ( trycell ) ) ;
if ( bestval = = - 1 | | dist < bestval ) {
bestval = dist ;
bestcell = cell ;
}
}
}
}
/*
* * Return the best location to move to .
*/
return ( bestcell ) ;
}
/***********************************************************************************************
* HouseClass : : Random_Cell_In_Zone - - Find a ( technically ) legal cell in the zone specified . *
* *
* This routine will pick a random cell within the zone specified . The pick will be *
* clipped to the map edge when necessary . *
* *
* INPUT : zone - - The zone to pick a cell from . *
* *
* OUTPUT : Returns with a picked cell within the zone . If the entire zone lies outside of the *
* map , then a cell in the core zone is returned instead . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 11 / 04 / 1996 JLB : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
CELL HouseClass : : Random_Cell_In_Zone ( ZoneType zone ) const
{
COORDINATE coord = 0 ;
int maxdist = 0 ;
switch ( zone ) {
case ZONE_CORE :
coord = Coord_Scatter ( Center , Random_Pick ( 0 , Radius ) , true ) ;
break ;
case ZONE_NORTH :
maxdist = min ( Radius * 3 , ( Coord_Y ( Center ) - Cell_To_Lepton ( Map . MapCellY ) ) - CELL_LEPTON_H ) ;
if ( maxdist < 0 ) break ;
coord = Coord_Move ( Center , ( DirType ) ( Random_Pick ( DIR_N , DIR_E ) - ( ( DirType ) 32 ) ) , Random_Pick ( min ( Radius * 2 , maxdist ) , min ( Radius * 3 , maxdist ) ) ) ;
break ;
case ZONE_EAST :
maxdist = min ( Radius * 3 , ( Cell_To_Lepton ( Map . MapCellX + Map . MapCellWidth ) - Coord_X ( Center ) ) - CELL_LEPTON_W ) ;
if ( maxdist < 0 ) break ;
coord = Coord_Move ( Center , Random_Pick ( DIR_NE , DIR_SE ) , Random_Pick ( min ( Radius * 2 , maxdist ) , min ( Radius * 3 , maxdist ) ) ) ;
break ;
case ZONE_SOUTH :
maxdist = min ( Radius * 3 , ( Cell_To_Lepton ( Map . MapCellY + Map . MapCellHeight ) - Coord_Y ( Center ) ) - CELL_LEPTON_H ) ;
if ( maxdist < 0 ) break ;
coord = Coord_Move ( Center , Random_Pick ( DIR_SE , DIR_SW ) , Random_Pick ( min ( Radius * 2 , maxdist ) , min ( Radius * 3 , maxdist ) ) ) ;
break ;
case ZONE_WEST :
maxdist = min ( Radius * 3 , ( Coord_X ( Center ) - Cell_To_Lepton ( Map . MapCellX ) ) - CELL_LEPTON_W ) ;
if ( maxdist < 0 ) break ;
coord = Coord_Move ( Center , Random_Pick ( DIR_SW , DIR_NW ) , Random_Pick ( min ( Radius * 2 , maxdist ) , min ( Radius * 3 , maxdist ) ) ) ;
break ;
}
/*
* * Double check that the location is valid and if so , convert it into a cell
* * number .
*/
CELL cell ;
if ( coord = = 0 | | ! Map . In_Radar ( Coord_Cell ( coord ) ) ) {
if ( zone = = ZONE_CORE ) {
/*
* * Finding a cell within the core failed , so just pick the center
* * cell . This cell is guaranteed to be valid .
*/
cell = Coord_Cell ( Center ) ;
} else {
/*
* * If the edge fails , then try to find a cell within the core .
*/
cell = Random_Cell_In_Zone ( ZONE_CORE ) ;
}
} else {
cell = Coord_Cell ( coord ) ;
}
/*
* * If the randomly picked location is not in the legal map area , then clip it to
* * the legal map area .
*/
if ( ! Map . In_Radar ( cell ) ) {
int x = Cell_X ( cell ) ;
int y = Cell_Y ( cell ) ;
if ( x < Map . MapCellX ) x = Map . MapCellX ;
if ( y < Map . MapCellY ) y = Map . MapCellY ;
if ( x > = Map . MapCellX + Map . MapCellWidth ) x = Map . MapCellX + Map . MapCellWidth - 1 ;
if ( y > = Map . MapCellY + Map . MapCellHeight ) y = Map . MapCellY + Map . MapCellHeight - 1 ;
cell = XY_Cell ( x , y ) ;
}
return ( cell ) ;
}
/***********************************************************************************************
* HouseClass : : Get_Ally_Flags - - Get the bit flags denoting the allies this house has . *
* *
* INPUT : none *
* *
* OUTPUT : Returns the bit field storing which houses this house is allied with . *
* *
* WARNINGS : none *
* *
* HISTORY : *
* 09 / 12 / 2019 JAS : Created . *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
unsigned HouseClass : : Get_Ally_Flags ( )
{
return Allies ;
}
# endif