August 6th Patch Update
Accumulated DLL source code changes since June 22nd patch
This commit is contained in:
parent
93a1af2eff
commit
ae72fce5dd
|
@ -1,4 +1,4 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.28307.1022
|
VisualStudioVersion = 15.0.28307.1022
|
||||||
|
|
|
@ -359,7 +359,7 @@ static AnimTypeClass const LZSmoke(
|
||||||
72, // Loop start frame number.
|
72, // Loop start frame number.
|
||||||
91, // Ending frame of loop back.
|
91, // Ending frame of loop back.
|
||||||
-1, // Number of animation stages.
|
-1, // Number of animation stages.
|
||||||
255, // Number of times the animation loops.
|
127, // Number of times the animation loops.
|
||||||
VOC_NONE, // Sound effect to play.
|
VOC_NONE, // Sound effect to play.
|
||||||
ANIM_NONE
|
ANIM_NONE
|
||||||
);
|
);
|
||||||
|
@ -1127,7 +1127,7 @@ static AnimTypeClass const OilFieldBurn(
|
||||||
33, // Loop start frame number.
|
33, // Loop start frame number.
|
||||||
99, // Ending frame of loop back.
|
99, // Ending frame of loop back.
|
||||||
66, // Number of animation stages.
|
66, // Number of animation stages.
|
||||||
65535, // Number of times the animation loops.
|
127, // Number of times the animation loops.
|
||||||
VOC_NONE, // Sound effect to play.
|
VOC_NONE, // Sound effect to play.
|
||||||
ANIM_NONE
|
ANIM_NONE
|
||||||
);
|
);
|
||||||
|
|
|
@ -1948,9 +1948,17 @@ void AircraftClass::Enter_Idle_Mode(bool )
|
||||||
/*
|
/*
|
||||||
** Normal aircraft try to find a good landing spot to rest.
|
** Normal aircraft try to find a good landing spot to rest.
|
||||||
*/
|
*/
|
||||||
BuildingClass * building = Find_Docking_Bay(Class->Building, false);
|
BuildingClass * building = NULL;
|
||||||
|
if (In_Radio_Contact() && Contact_With_Whom()->What_Am_I() == RTTI_BUILDING) {
|
||||||
|
building = (BuildingClass *)Contact_With_Whom();
|
||||||
|
} else {
|
||||||
|
building = Find_Docking_Bay(Class->Building, false);
|
||||||
|
if (Transmit_Message(RADIO_HELLO, building) != RADIO_ROGER) {
|
||||||
|
building = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
Assign_Destination(TARGET_NONE);
|
Assign_Destination(TARGET_NONE);
|
||||||
if (building != NULL && Transmit_Message(RADIO_HELLO, building) == RADIO_ROGER) {
|
if (building != NULL) {
|
||||||
if (Class->IsFixedWing) {
|
if (Class->IsFixedWing) {
|
||||||
Status = 0; //BG - reset the mission status to avoid landing on the ground next to the airstrip
|
Status = 0; //BG - reset the mission status to avoid landing on the ground next to the airstrip
|
||||||
if (IsLanding) {
|
if (IsLanding) {
|
||||||
|
@ -2367,7 +2375,7 @@ ActionType AircraftClass::What_Action(CELL cell) const
|
||||||
ActionType action = FootClass::What_Action(cell);
|
ActionType action = FootClass::What_Action(cell);
|
||||||
|
|
||||||
//using function for IsVisible so we have different results for different players - JAS 2019/09/30
|
//using function for IsVisible so we have different results for different players - JAS 2019/09/30
|
||||||
if (action == ACTION_MOVE && !Map[cell].Is_Visible(PlayerPtr)) {
|
if ((action == ACTION_MOVE || action == ACTION_ATTACK) && !Map[cell].Is_Visible(PlayerPtr)) {
|
||||||
action = ACTION_NOMOVE;
|
action = ACTION_NOMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3068,7 +3076,7 @@ MoveType AircraftClass::Can_Enter_Cell(CELL cell, FacingType ) const
|
||||||
if (occupier == NULL ||
|
if (occupier == NULL ||
|
||||||
!occupier->Is_Techno() ||
|
!occupier->Is_Techno() ||
|
||||||
((TechnoClass *)occupier)->House->Is_Ally(House) ||
|
((TechnoClass *)occupier)->House->Is_Ally(House) ||
|
||||||
(((TechnoClass *)occupier)->Cloak != CLOAKED &&
|
(!((TechnoClass *)occupier)->Is_Cloaked(this) &&
|
||||||
(ScenarioInit == 0 && (occupier->What_Am_I() != RTTI_BUILDING || !((BuildingClass*)occupier)->Class->IsInvisible)) )
|
(ScenarioInit == 0 && (occupier->What_Am_I() != RTTI_BUILDING || !((BuildingClass*)occupier)->Class->IsInvisible)) )
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -3128,9 +3136,10 @@ TARGET AircraftClass::Good_Fire_Location(TARGET target) const
|
||||||
for (int face = 0; face < 255; face += 16) {
|
for (int face = 0; face < 255; face += 16) {
|
||||||
COORDINATE newcoord = Coord_Move(tcoord, (DirType)face, r);
|
COORDINATE newcoord = Coord_Move(tcoord, (DirType)face, r);
|
||||||
CELL newcell = Coord_Cell(newcoord);
|
CELL newcell = Coord_Cell(newcoord);
|
||||||
|
CELL actualcell = Coord_Cell(Coord_Sub(newcoord, XY_Coord(0, FLIGHT_LEVEL)));
|
||||||
|
|
||||||
//using function for IsVisible so we have different results for different players - JAS 2019/09/30
|
//using function for IsVisible so we have different results for different players - JAS 2019/09/30
|
||||||
if (Map.In_Radar(newcell) && (Session.Type != GAME_NORMAL || Map[newcell].Is_Visible(PlayerPtr)) && Cell_Seems_Ok(newcell, true)) {
|
if (Map.In_Radar(actualcell) && (Session.Type != GAME_NORMAL || Map[newcell].Is_Visible(PlayerPtr)) && Cell_Seems_Ok(newcell, true)) {
|
||||||
int dist;
|
int dist;
|
||||||
if (altcoord != 0) {
|
if (altcoord != 0) {
|
||||||
dist = ::Distance(newcoord, altcoord);
|
dist = ::Distance(newcoord, altcoord);
|
||||||
|
|
|
@ -578,7 +578,7 @@ IsTheaterShape = false;
|
||||||
|
|
||||||
AnimClass::Unlimbo(coord);
|
AnimClass::Unlimbo(coord);
|
||||||
|
|
||||||
VisibleFlags = 0xffff;
|
VisibleFlags = static_cast<unsigned int>(-1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Drop zone smoke always reveals the map around itself.
|
** Drop zone smoke always reveals the map around itself.
|
||||||
|
@ -817,10 +817,10 @@ void AnimClass::AI(void)
|
||||||
int damage = Accum;
|
int damage = Accum;
|
||||||
Accum -= damage;
|
Accum -= damage;
|
||||||
if (As_Object(xObject)->Take_Damage(damage, 0, WARHEAD_FIRE) == RESULT_DESTROYED) {
|
if (As_Object(xObject)->Take_Damage(damage, 0, WARHEAD_FIRE) == RESULT_DESTROYED) {
|
||||||
delete this;
|
|
||||||
if (Target_Legal(VirtualAnimTarget)) {
|
if (Target_Legal(VirtualAnimTarget)) {
|
||||||
delete As_Animation(VirtualAnimTarget);
|
delete As_Animation(VirtualAnimTarget);
|
||||||
}
|
}
|
||||||
|
delete this;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1177,8 +1177,12 @@ void AnimClass::Detach(TARGET target, bool all)
|
||||||
assert(IsActive);
|
assert(IsActive);
|
||||||
|
|
||||||
if (all) {
|
if (all) {
|
||||||
if (VirtualAnimTarget && VirtualAnimTarget == target) {
|
if (Target_Legal(VirtualAnimTarget) && VirtualAnimTarget == target) {
|
||||||
VirtualAnimTarget = TARGET_NONE;
|
VirtualAnimTarget = TARGET_NONE;
|
||||||
|
if (IsInvisible) {
|
||||||
|
IsToDelete = true;
|
||||||
|
Mark(MARK_UP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (xObject == target) {
|
if (xObject == target) {
|
||||||
Map.Remove(this, In_Which_Layer());
|
Map.Remove(this, In_Which_Layer());
|
||||||
|
|
|
@ -173,7 +173,7 @@ RadioMessageType BuildingClass::Receive_Message(RadioClass * from, RadioMessageT
|
||||||
case RADIO_CAN_LOAD:
|
case RADIO_CAN_LOAD:
|
||||||
TechnoClass::Receive_Message(from, message, param);
|
TechnoClass::Receive_Message(from, message, param);
|
||||||
if (!House->Is_Ally(from)) return(RADIO_STATIC);
|
if (!House->Is_Ally(from)) return(RADIO_STATIC);
|
||||||
if (Mission == MISSION_CONSTRUCTION || Mission == MISSION_DECONSTRUCTION || BState == BSTATE_CONSTRUCTION || (!ScenarioInit && In_Radio_Contact() && Contact_With_Whom() != from)) return(RADIO_NEGATIVE);
|
if (Mission == MISSION_CONSTRUCTION || Mission == MISSION_DECONSTRUCTION || BState == BSTATE_CONSTRUCTION || (!ScenarioInit && Class->Type != STRUCT_REFINERY && In_Radio_Contact())) return(RADIO_NEGATIVE);
|
||||||
switch (Class->Type) {
|
switch (Class->Type) {
|
||||||
case STRUCT_AIRSTRIP:
|
case STRUCT_AIRSTRIP:
|
||||||
if (from->What_Am_I() == RTTI_AIRCRAFT && ((AircraftClass const *)from)->Class->IsFixedWing) {
|
if (from->What_Am_I() == RTTI_AIRCRAFT && ((AircraftClass const *)from)->Class->IsFixedWing) {
|
||||||
|
@ -200,7 +200,7 @@ RadioMessageType BuildingClass::Receive_Message(RadioClass * from, RadioMessageT
|
||||||
*((UnitClass *)from) == UNIT_HARVESTER &&
|
*((UnitClass *)from) == UNIT_HARVESTER &&
|
||||||
(ScenarioInit || !Is_Something_Attached())) {
|
(ScenarioInit || !Is_Something_Attached())) {
|
||||||
|
|
||||||
return(RADIO_ROGER);
|
return((Contact_With_Whom() != from) ? RADIO_ROGER : RADIO_NEGATIVE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2572,13 +2572,21 @@ void BuildingClass::Grand_Opening(bool captured)
|
||||||
** to place it in a nearby location.
|
** to place it in a nearby location.
|
||||||
*/
|
*/
|
||||||
if (!unit->Unlimbo(Cell_Coord(cell), DIR_W)) {
|
if (!unit->Unlimbo(Cell_Coord(cell), DIR_W)) {
|
||||||
cell = unit->Nearby_Location(this);
|
/*
|
||||||
|
** Check multiple times for clear locations.
|
||||||
|
*/
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
cell = unit->Nearby_Location(this, i);
|
||||||
|
if (unit->Unlimbo(Cell_Coord(cell), DIR_SW)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** If the harvester could still not be placed, then refund the money
|
** If the harvester could still not be placed, then refund the money
|
||||||
** to the owner and then bail.
|
** to the owner and then bail.
|
||||||
*/
|
*/
|
||||||
if (!unit->Unlimbo(Cell_Coord(cell), DIR_SW)) {
|
if (unit->IsInLimbo) {
|
||||||
House->Refund_Money(unit->Class->Cost_Of());
|
House->Refund_Money(unit->Class->Cost_Of());
|
||||||
delete unit;
|
delete unit;
|
||||||
}
|
}
|
||||||
|
@ -3726,9 +3734,16 @@ int BuildingClass::Mission_Deconstruction(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MBL 07.10.2020 - In 1v1, sometimes both players will hear this SFX, or neither player will hear it
|
||||||
|
// Making it so all players hear it positionally in the map; Per thread discussion in https://jaas.ea.com/browse/TDRA-7245
|
||||||
|
//
|
||||||
|
#if 0
|
||||||
if (House->IsPlayerControl) {
|
if (House->IsPlayerControl) {
|
||||||
Sound_Effect(VOC_CASHTURN, Coord);
|
Sound_Effect(VOC_CASHTURN, Coord);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
Sound_Effect(VOC_CASHTURN, Coord);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Destroy all attached objects. ST - 4/24/2020 9:38PM
|
** Destroy all attached objects. ST - 4/24/2020 9:38PM
|
||||||
|
|
|
@ -2807,10 +2807,19 @@ void CellClass::Flag_Create(void)
|
||||||
{
|
{
|
||||||
if (!CTFFlag) {
|
if (!CTFFlag) {
|
||||||
CTFFlag = new AnimClass(ANIM_FLAG, Cell_Coord());
|
CTFFlag = new AnimClass(ANIM_FLAG, Cell_Coord());
|
||||||
if (CTFFlag) {
|
if (CTFFlag == NULL) {
|
||||||
CTFFlag->OwnerHouse = Owner;
|
for (int i = 0; i < Anims.Count(); ++i) {
|
||||||
|
AnimClass* anim = Anims.Ptr(i);
|
||||||
|
if (*anim != ANIM_FLAG) {
|
||||||
|
delete anim;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CTFFlag = new AnimClass(ANIM_FLAG, Cell_Coord());
|
||||||
|
}
|
||||||
|
assert(CTFFlag != NULL);
|
||||||
|
CTFFlag->OwnerHouse = Owner;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3615,6 +3615,15 @@ typedef enum OptionControlType : char {
|
||||||
} OptionControlType;
|
} OptionControlType;
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
** Used to store firing data for a unit.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
COORDINATE Center;
|
||||||
|
int Distance;
|
||||||
|
} FireDataType;
|
||||||
|
|
||||||
|
|
||||||
#define size_of(typ,id) sizeof(((typ*)0)->id)
|
#define size_of(typ,id) sizeof(((typ*)0)->id)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3146,9 +3146,9 @@ int DisplayClass::TacticalClass::Action(unsigned flags, KeyNumType & key)
|
||||||
object = Map.Close_Object(coord);
|
object = Map.Close_Object(coord);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Special case check to ignore cloaked object if not owned by the player.
|
** Special case check to ignore cloaked object if not allied with the player.
|
||||||
*/
|
*/
|
||||||
if (object != NULL && object->Is_Techno() && !((TechnoClass *)object)->IsOwnedByPlayer && (((TechnoClass *)object)->Cloak == CLOAKED || ((TechnoClass *)object)->Techno_Type_Class()->IsInvisible)) {
|
if (object != NULL && object->Is_Techno() && ((TechnoClass *)object)->Is_Cloaked(PlayerPtr, true)) {
|
||||||
object = NULL;
|
object = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -384,6 +384,8 @@ bool MPSuperWeaponDisable = false;
|
||||||
bool ShareAllyVisibility = true;
|
bool ShareAllyVisibility = true;
|
||||||
bool UseGlyphXStartLocations = true;
|
bool UseGlyphXStartLocations = true;
|
||||||
|
|
||||||
|
SpecialClass* SpecialBackup = NULL;
|
||||||
|
|
||||||
|
|
||||||
int GetRandSeed()
|
int GetRandSeed()
|
||||||
{
|
{
|
||||||
|
@ -800,6 +802,8 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Set_Multiplayer_Data(int scena
|
||||||
|
|
||||||
Special.IsEarlyWin = game_options.DestroyStructures;
|
Special.IsEarlyWin = game_options.DestroyStructures;
|
||||||
|
|
||||||
|
Special.ModernBalance = game_options.ModernBalance;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Enable Counterstrike/Aftermath units
|
** Enable Counterstrike/Aftermath units
|
||||||
*/
|
*/
|
||||||
|
@ -844,6 +848,13 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Set_Multiplayer_Data(int scena
|
||||||
*/
|
*/
|
||||||
Rule.IsSmartDefense = true;
|
Rule.IsSmartDefense = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Backup special
|
||||||
|
*/
|
||||||
|
if (SpecialBackup != NULL) {
|
||||||
|
memcpy(SpecialBackup, &Special, sizeof(SpecialClass));
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1673,6 +1684,13 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Advance_Instance(uint64 player
|
||||||
DLLExportClass::Set_Player_Context(DLLExportClass::GlyphxPlayerIDs[0]);
|
DLLExportClass::Set_Player_Context(DLLExportClass::GlyphxPlayerIDs[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Restore special from backup
|
||||||
|
*/
|
||||||
|
if (SpecialBackup != NULL) {
|
||||||
|
memcpy(&Special, SpecialBackup, sizeof(SpecialClass));
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef FIXIT_CSII // checked - ajw 9/28/98
|
#ifdef FIXIT_CSII // checked - ajw 9/28/98
|
||||||
TimeQuake = PendingTimeQuake;
|
TimeQuake = PendingTimeQuake;
|
||||||
PendingTimeQuake = false;
|
PendingTimeQuake = false;
|
||||||
|
@ -1865,6 +1883,15 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Advance_Instance(uint64 player
|
||||||
//Sync_Delay();
|
//Sync_Delay();
|
||||||
//DLLExportClass::Set_Event_Callback(NULL);
|
//DLLExportClass::Set_Event_Callback(NULL);
|
||||||
Color_Cycle();
|
Color_Cycle();
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Don't respect GameActive. Game will end in multiplayer on win/loss
|
||||||
|
*/
|
||||||
|
if (GAME_TO_PLAY == GAME_GLYPHX_MULTIPLAYER) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return(GameActive);
|
return(GameActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1911,6 +1938,12 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Save_Load(bool save, const cha
|
||||||
|
|
||||||
result = Load_Game(file_path_and_name);
|
result = Load_Game(file_path_and_name);
|
||||||
|
|
||||||
|
// MBL 07.21.2020
|
||||||
|
if (result == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
DLLExportClass::Set_Player_Context(DLLExportClass::GlyphxPlayerIDs[0], true);
|
DLLExportClass::Set_Player_Context(DLLExportClass::GlyphxPlayerIDs[0], true);
|
||||||
Set_Logic_Page(SeenBuff);
|
Set_Logic_Page(SeenBuff);
|
||||||
VisiblePage.Clear();
|
VisiblePage.Clear();
|
||||||
|
@ -2130,6 +2163,11 @@ void DLLExportClass::Init(void)
|
||||||
CurrentLocalPlayerIndex = 0;
|
CurrentLocalPlayerIndex = 0;
|
||||||
|
|
||||||
MessagesSent.clear();
|
MessagesSent.clear();
|
||||||
|
|
||||||
|
if (SpecialBackup == NULL) {
|
||||||
|
SpecialBackup = new SpecialClass;
|
||||||
|
}
|
||||||
|
memcpy(SpecialBackup, &Special, sizeof(SpecialClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2146,6 +2184,9 @@ void DLLExportClass::Init(void)
|
||||||
**************************************************************************************************/
|
**************************************************************************************************/
|
||||||
void DLLExportClass::Shutdown(void)
|
void DLLExportClass::Shutdown(void)
|
||||||
{
|
{
|
||||||
|
delete SpecialBackup;
|
||||||
|
SpecialBackup = NULL;
|
||||||
|
|
||||||
for (int i=0 ; i<ModSearchPaths.Count() ; i++) {
|
for (int i=0 ; i<ModSearchPaths.Count() ; i++) {
|
||||||
delete [] ModSearchPaths[i];
|
delete [] ModSearchPaths[i];
|
||||||
}
|
}
|
||||||
|
@ -3252,6 +3293,7 @@ void DLL_Draw_Pip_Intercept(const ObjectClass* object, int pip)
|
||||||
void DLLExportClass::DLL_Draw_Intercept(int shape_number, int x, int y, int width, int height, int flags, const ObjectClass *object, DirType rotation, long scale, const char *shape_file_name, char override_owner)
|
void DLLExportClass::DLL_Draw_Intercept(int shape_number, int x, int y, int width, int height, int flags, const ObjectClass *object, DirType rotation, long scale, const char *shape_file_name, char override_owner)
|
||||||
{
|
{
|
||||||
CNCObjectStruct& new_object = ObjectList->Objects[TotalObjectCount + CurrentDrawCount];
|
CNCObjectStruct& new_object = ObjectList->Objects[TotalObjectCount + CurrentDrawCount];
|
||||||
|
memset(&new_object, 0, sizeof(new_object));
|
||||||
Convert_Type(object, new_object);
|
Convert_Type(object, new_object);
|
||||||
if (new_object.Type == UNKNOWN) {
|
if (new_object.Type == UNKNOWN) {
|
||||||
return;
|
return;
|
||||||
|
@ -4394,6 +4436,8 @@ bool DLLExportClass::Get_Sidebar_State(uint64 player_id, unsigned char *buffer_i
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(&sidebar_entry, 0, sizeof(sidebar_entry));
|
||||||
|
|
||||||
sidebar_entry.AssetName[0] = 0;
|
sidebar_entry.AssetName[0] = 0;
|
||||||
sidebar_entry.Type = UNKNOWN;
|
sidebar_entry.Type = UNKNOWN;
|
||||||
sidebar_entry.BuildableID = Map.Column[c].Buildables[b].BuildableID;
|
sidebar_entry.BuildableID = Map.Column[c].Buildables[b].BuildableID;
|
||||||
|
@ -4406,7 +4450,7 @@ bool DLLExportClass::Get_Sidebar_State(uint64 player_id, unsigned char *buffer_i
|
||||||
sidebar_entry.SuperWeaponType = SW_NONE;
|
sidebar_entry.SuperWeaponType = SW_NONE;
|
||||||
|
|
||||||
if (tech) {
|
if (tech) {
|
||||||
sidebar_entry.Cost = tech->Cost * PlayerPtr->CostBias;
|
sidebar_entry.Cost = tech->Cost * PlayerPtr->CostBias; // MBL: If this gets modified, also modify below for skirmish and multiplayer
|
||||||
sidebar_entry.PowerProvided = 0;
|
sidebar_entry.PowerProvided = 0;
|
||||||
sidebar_entry.BuildTime = tech->Time_To_Build(PlayerPtr->Class->House); // sidebar_entry.BuildTime = tech->Time_To_Build() / 60;
|
sidebar_entry.BuildTime = tech->Time_To_Build(PlayerPtr->Class->House); // sidebar_entry.BuildTime = tech->Time_To_Build() / 60;
|
||||||
strncpy(sidebar_entry.AssetName, tech->IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
|
strncpy(sidebar_entry.AssetName, tech->IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
|
||||||
|
@ -4549,6 +4593,8 @@ bool DLLExportClass::Get_Sidebar_State(uint64 player_id, unsigned char *buffer_i
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(&sidebar_entry, 0, sizeof(sidebar_entry));
|
||||||
|
|
||||||
sidebar_entry.AssetName[0] = 0;
|
sidebar_entry.AssetName[0] = 0;
|
||||||
sidebar_entry.Type = UNKNOWN;
|
sidebar_entry.Type = UNKNOWN;
|
||||||
sidebar_entry.BuildableID = context_sidebar->Column[c].Buildables[b].BuildableID;
|
sidebar_entry.BuildableID = context_sidebar->Column[c].Buildables[b].BuildableID;
|
||||||
|
@ -4561,7 +4607,13 @@ bool DLLExportClass::Get_Sidebar_State(uint64 player_id, unsigned char *buffer_i
|
||||||
sidebar_entry.SuperWeaponType = SW_NONE;
|
sidebar_entry.SuperWeaponType = SW_NONE;
|
||||||
|
|
||||||
if (tech) {
|
if (tech) {
|
||||||
sidebar_entry.Cost = tech->Cost;
|
|
||||||
|
// MBL 06.22.2020 - Updated to apply and difficulty abd/or faction price modifier; See https://jaas.ea.com/browse/TDRA-6864
|
||||||
|
// If this gets modified, also modify above for non-skirmish / non-multiplayer
|
||||||
|
//
|
||||||
|
// sidebar_entry.Cost = tech->Cost;
|
||||||
|
sidebar_entry.Cost = tech->Cost * PlayerPtr->CostBias;
|
||||||
|
|
||||||
sidebar_entry.PowerProvided = 0;
|
sidebar_entry.PowerProvided = 0;
|
||||||
sidebar_entry.BuildTime = tech->Time_To_Build(PlayerPtr->Class->House); // sidebar_entry.BuildTime = tech->Time_To_Build() / 60;
|
sidebar_entry.BuildTime = tech->Time_To_Build(PlayerPtr->Class->House); // sidebar_entry.BuildTime = tech->Time_To_Build() / 60;
|
||||||
strncpy(sidebar_entry.AssetName, tech->IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
|
strncpy(sidebar_entry.AssetName, tech->IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
|
||||||
|
@ -8480,10 +8532,16 @@ bool DLLExportClass::Save(Pipe & pipe)
|
||||||
|
|
||||||
pipe.Put(&Special, sizeof(Special));
|
pipe.Put(&Special, sizeof(Special));
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Special case for MPSuperWeaponDisable - store negated value so it defaults to enabled
|
||||||
|
*/
|
||||||
|
bool not_allow_super_weapons = !MPSuperWeaponDisable;
|
||||||
|
pipe.Put(¬_allow_super_weapons, sizeof(not_allow_super_weapons));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Room for save game expansion
|
** Room for save game expansion
|
||||||
*/
|
*/
|
||||||
unsigned char padding[4096];
|
unsigned char padding[4095];
|
||||||
memset(padding, 0, sizeof(padding));
|
memset(padding, 0, sizeof(padding));
|
||||||
|
|
||||||
pipe.Put(padding, sizeof(padding));
|
pipe.Put(padding, sizeof(padding));
|
||||||
|
@ -8566,7 +8624,23 @@ bool DLLExportClass::Load(Straw & file)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char padding[4096];
|
/*
|
||||||
|
** Restore backup
|
||||||
|
*/
|
||||||
|
if (SpecialBackup != NULL) {
|
||||||
|
memcpy(SpecialBackup, &Special, sizeof(SpecialClass));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Special case for MPSuperWeaponDisable - store negated value so it defaults to enabled
|
||||||
|
*/
|
||||||
|
bool not_allow_super_weapons = false;
|
||||||
|
if (file.Get(¬_allow_super_weapons, sizeof(not_allow_super_weapons)) != sizeof(not_allow_super_weapons)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MPSuperWeaponDisable = !not_allow_super_weapons;
|
||||||
|
|
||||||
|
unsigned char padding[4095];
|
||||||
|
|
||||||
if (file.Get(padding, sizeof(padding)) != sizeof(padding)) {
|
if (file.Get(padding, sizeof(padding)) != sizeof(padding)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -732,7 +732,7 @@ struct CNCMultiplayerOptionsStruct {
|
||||||
int MPlayerCount; // # of human players in this game
|
int MPlayerCount; // # of human players in this game
|
||||||
int MPlayerBases; // 1 = bases are on for this scenario
|
int MPlayerBases; // 1 = bases are on for this scenario
|
||||||
int MPlayerCredits; // # credits everyone gets
|
int MPlayerCredits; // # credits everyone gets
|
||||||
int MPlayerTiberium; // 1 = tiberium enabled for this scenario
|
int MPlayerTiberium; // >0 = tiberium enabled for this scenario
|
||||||
int MPlayerGoodies; // 1 = goodies enabled for this scenario
|
int MPlayerGoodies; // 1 = goodies enabled for this scenario
|
||||||
int MPlayerGhosts; // 1 = houses with no players will still play
|
int MPlayerGhosts; // 1 = houses with no players will still play
|
||||||
int MPlayerSolo; // 1 = allows a single-player net game
|
int MPlayerSolo; // 1 = allows a single-player net game
|
||||||
|
@ -744,6 +744,7 @@ struct CNCMultiplayerOptionsStruct {
|
||||||
bool MPlayerAftermathUnits;
|
bool MPlayerAftermathUnits;
|
||||||
bool CaptureTheFlag;
|
bool CaptureTheFlag;
|
||||||
bool DestroyStructures; // New early win condition via destroying all a player's structures
|
bool DestroyStructures; // New early win condition via destroying all a player's structures
|
||||||
|
bool ModernBalance;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -603,7 +603,7 @@ void EventClass::Execute(void)
|
||||||
//2019/09/19 JAS - Visibility needs to be determined per player
|
//2019/09/19 JAS - Visibility needs to be determined per player
|
||||||
if (Data.Anim.Owner == HOUSE_NONE || Data.Anim.What != ANIM_MOVE_FLASH)
|
if (Data.Anim.Owner == HOUSE_NONE || Data.Anim.What != ANIM_MOVE_FLASH)
|
||||||
{
|
{
|
||||||
anim->Set_Visible_Flags(0xffff);
|
anim->Set_Visible_Flags(static_cast<unsigned int>(-1));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -761,6 +761,12 @@ void EventClass::Execute(void)
|
||||||
techno->Assign_Target(TARGET_NONE);
|
techno->Assign_Target(TARGET_NONE);
|
||||||
techno->Assign_Destination(Data.MegaMission.Target.As_TARGET());
|
techno->Assign_Destination(Data.MegaMission.Target.As_TARGET());
|
||||||
techno->ArchiveTarget = Data.MegaMission.Target.As_TARGET();
|
techno->ArchiveTarget = Data.MegaMission.Target.As_TARGET();
|
||||||
|
} else if (Data.MegaMission.Mission == MISSION_ENTER &&
|
||||||
|
object != NULL &&
|
||||||
|
object->What_Am_I() == RTTI_BUILDING &&
|
||||||
|
*((BuildingClass*)object) == STRUCT_REFINERY) {
|
||||||
|
techno->Transmit_Message(RADIO_HELLO, (BuildingClass*)object);
|
||||||
|
techno->Assign_Destination(TARGET_NONE);
|
||||||
} else {
|
} else {
|
||||||
if (q && techno->Is_Foot()) {
|
if (q && techno->Is_Foot()) {
|
||||||
((FootClass *)techno)->Queue_Navigation_List(Data.MegaMission.Destination.As_TARGET());
|
((FootClass *)techno)->Queue_Navigation_List(Data.MegaMission.Destination.As_TARGET());
|
||||||
|
|
|
@ -1741,8 +1741,20 @@ int FootClass::Mission_Enter(void)
|
||||||
** Since there is no potential object to enter, then abort this
|
** Since there is no potential object to enter, then abort this
|
||||||
** mission with some default standby mission.
|
** mission with some default standby mission.
|
||||||
*/
|
*/
|
||||||
|
if (MissionQueue == MISSION_NONE) {
|
||||||
|
/*
|
||||||
|
** If this is a harvester, then return to harvesting.
|
||||||
|
** Set a hacky target so we know to skip to the proper state.
|
||||||
|
*/
|
||||||
|
if (What_Am_I() == RTTI_UNIT && ((UnitClass*)this)->Class->IsToHarvest) {
|
||||||
|
Assign_Mission(MISSION_HARVEST);
|
||||||
|
Assign_Target(As_Target());
|
||||||
|
Assign_Destination(TARGET_NONE);
|
||||||
|
} else {
|
||||||
Enter_Idle_Mode();
|
Enter_Idle_Mode();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
|
return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
|
||||||
}
|
}
|
||||||
|
|
|
@ -921,7 +921,7 @@ void HouseClass::AI(void)
|
||||||
** production and team creation as well. This is also true if the IQ is high enough to
|
** production and team creation as well. This is also true if the IQ is high enough to
|
||||||
** being base building.
|
** being base building.
|
||||||
*/
|
*/
|
||||||
if (IsBaseBuilding || IQ >= Rule.IQProduction) {
|
if (!IsHuman && (IsBaseBuilding || IQ >= Rule.IQProduction)) {
|
||||||
IsBaseBuilding = true;
|
IsBaseBuilding = true;
|
||||||
IsStarted = true;
|
IsStarted = true;
|
||||||
IsAlerted = true;
|
IsAlerted = true;
|
||||||
|
@ -957,6 +957,9 @@ void HouseClass::AI(void)
|
||||||
if (IsToDie && BorrowedTime == 0) {
|
if (IsToDie && BorrowedTime == 0) {
|
||||||
IsToDie = false;
|
IsToDie = false;
|
||||||
Blowup_All();
|
Blowup_All();
|
||||||
|
if (Session.Type == GAME_GLYPHX_MULTIPLAYER) {
|
||||||
|
MPlayer_Defeated();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1151,7 +1154,7 @@ void HouseClass::AI(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FIXIT_VERSION_3 // For endgame auto-sonar pulse.
|
#ifdef FIXIT_VERSION_3 // For endgame auto-sonar pulse.
|
||||||
if( Scen.AutoSonarTimer == 0 )
|
if( (Session.Type != GAME_NORMAL || !IsHuman) && Scen.AutoSonarTimer == 0 )
|
||||||
{
|
{
|
||||||
// If house has nothing but subs left, do an automatic sonar pulse to reveal them.
|
// If house has nothing but subs left, do an automatic sonar pulse to reveal them.
|
||||||
if( VQuantity[ VESSEL_SS ] > 0 ) // Includes count of VESSEL_MISSILESUBs. ajw
|
if( VQuantity[ VESSEL_SS ] > 0 ) // Includes count of VESSEL_MISSILESUBs. ajw
|
||||||
|
@ -1818,12 +1821,18 @@ void HouseClass::Attacked(BuildingClass* source)
|
||||||
{
|
{
|
||||||
assert(Houses.ID(this) == ID);
|
assert(Houses.ID(this) == ID);
|
||||||
|
|
||||||
|
bool expired = SpeakAttackDelay == 0;
|
||||||
|
bool spoke = false;
|
||||||
|
|
||||||
#ifdef FIXIT_BASE_ANNOUNCE
|
#ifdef FIXIT_BASE_ANNOUNCE
|
||||||
if (SpeakAttackDelay == 0 && ((Session.Type == GAME_NORMAL && IsPlayerControl) || PlayerPtr->Class->House == Class->House)) {
|
// if (SpeakAttackDelay == 0 && ((Session.Type == GAME_NORMAL && IsPlayerControl) || PlayerPtr->Class->House == Class->House)) {
|
||||||
|
if (expired && ((Session.Type == GAME_NORMAL && IsPlayerControl) || PlayerPtr->Class->House == Class->House)) {
|
||||||
#else
|
#else
|
||||||
if (SpeakAttackDelay == 0 && PlayerPtr->Class->House == Class->House) {
|
// if (SpeakAttackDelay == 0 && PlayerPtr->Class->House == Class->House) {
|
||||||
|
if (expired && PlayerPtr->Class->House == Class->House) {
|
||||||
#endif
|
#endif
|
||||||
Speak(VOX_BASE_UNDER_ATTACK, NULL, source ? source->Center_Coord() : 0);
|
Speak(VOX_BASE_UNDER_ATTACK, NULL, source ? source->Center_Coord() : 0);
|
||||||
|
spoke = true;
|
||||||
|
|
||||||
// MBL 06.13.2020 - Timing change from 2 minute cooldown, per https://jaas.ea.com/browse/TDRA-6784
|
// MBL 06.13.2020 - Timing change from 2 minute cooldown, per https://jaas.ea.com/browse/TDRA-6784
|
||||||
// SpeakAttackDelay = Options.Normalize_Delay(TICKS_PER_MINUTE * Rule.SpeakDelay); // 2 minutes
|
// SpeakAttackDelay = Options.Normalize_Delay(TICKS_PER_MINUTE * Rule.SpeakDelay); // 2 minutes
|
||||||
|
@ -1838,6 +1847,22 @@ void HouseClass::Attacked(BuildingClass* source)
|
||||||
HouseTriggers[Class->House][index]->Spring(TEVENT_ATTACKED);
|
HouseTriggers[Class->House][index]->Spring(TEVENT_ATTACKED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 (Session.Type != GAME_NORMAL) // Multiplayer
|
||||||
|
{
|
||||||
|
Speak(VOX_BASE_UNDER_ATTACK, this);
|
||||||
|
spoke = true;
|
||||||
|
|
||||||
|
// SpeakAttackDelay = Options.Normalize_Delay(TICKS_PER_MINUTE * Rule.SpeakDelay); // 2 minutes
|
||||||
|
// SpeakAttackDelay = Options.Normalize_Delay(TICKS_PER_MINUTE/2); // 30 seconds as requested
|
||||||
|
SpeakAttackDelay = Options.Normalize_Delay( (TICKS_PER_MINUTE/2)+(TICKS_PER_SECOND*5) ); // Tweaked for accuracy
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3758,6 +3783,13 @@ void HouseClass::MPlayer_Defeated(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Remove any one-time superweapons the player might have.
|
||||||
|
*/
|
||||||
|
for (i = SPC_FIRST; i < SPC_COUNT; i++) {
|
||||||
|
SuperWeapon[i].Remove(true);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** If this is me:
|
** If this is me:
|
||||||
** - Set MPlayerObiWan, so I can only send messages to all players, and
|
** - Set MPlayerObiWan, so I can only send messages to all players, and
|
||||||
|
@ -4099,7 +4131,14 @@ void HouseClass::Blowup_All(void)
|
||||||
*/
|
*/
|
||||||
count = 0;
|
count = 0;
|
||||||
while (::Units.Ptr(i)==uptr && uptr->Strength) {
|
while (::Units.Ptr(i)==uptr && uptr->Strength) {
|
||||||
damage = uptr->Strength;
|
|
||||||
|
// MBL 06.22.2020 RA: Not all aircraft die in this case; See https://jaas.ea.com/browse/TDRA-6840
|
||||||
|
// Likely due to damage biasing based on RA factions and/or difficulty settings
|
||||||
|
// Applying this to units (vehicles), ships, buildings, and infantry, too
|
||||||
|
//
|
||||||
|
// damage = uptr->Strength; // Original
|
||||||
|
damage = 0x7fff; // Copied from TD
|
||||||
|
|
||||||
uptr->Take_Damage(damage, 0, WARHEAD_HE, NULL, true);
|
uptr->Take_Damage(damage, 0, WARHEAD_HE, NULL, true);
|
||||||
count++;
|
count++;
|
||||||
if (count > 5 && uptr->IsActive) {
|
if (count > 5 && uptr->IsActive) {
|
||||||
|
@ -4118,7 +4157,13 @@ void HouseClass::Blowup_All(void)
|
||||||
if (::Aircraft.Ptr(i)->House == this && !::Aircraft.Ptr(i)->IsInLimbo) {
|
if (::Aircraft.Ptr(i)->House == this && !::Aircraft.Ptr(i)->IsInLimbo) {
|
||||||
AircraftClass * aptr = ::Aircraft.Ptr(i);
|
AircraftClass * aptr = ::Aircraft.Ptr(i);
|
||||||
|
|
||||||
damage = aptr->Strength;
|
// MBL 06.22.2020 RA: Not all aircraft die in this case; See https://jaas.ea.com/browse/TDRA-6840
|
||||||
|
// Likely due to damage biasing based on RA factions and/or difficulty settings
|
||||||
|
// Applying this to units (vehicles), ships, buildings, and infantry, too
|
||||||
|
//
|
||||||
|
// damage = aptr->Strength; // Original
|
||||||
|
damage = 0x7fff; // Copied from TD
|
||||||
|
|
||||||
aptr->Take_Damage(damage, 0, WARHEAD_HE, NULL, true);
|
aptr->Take_Damage(damage, 0, WARHEAD_HE, NULL, true);
|
||||||
if (!aptr->IsActive) {
|
if (!aptr->IsActive) {
|
||||||
i--;
|
i--;
|
||||||
|
@ -4133,7 +4178,13 @@ void HouseClass::Blowup_All(void)
|
||||||
if (::Vessels.Ptr(i)->House == this && !::Vessels.Ptr(i)->IsInLimbo) {
|
if (::Vessels.Ptr(i)->House == this && !::Vessels.Ptr(i)->IsInLimbo) {
|
||||||
VesselClass * vptr = ::Vessels.Ptr(i);
|
VesselClass * vptr = ::Vessels.Ptr(i);
|
||||||
|
|
||||||
damage = vptr->Strength;
|
// MBL 06.22.2020 RA: Not all aircraft die in this case; See https://jaas.ea.com/browse/TDRA-6840
|
||||||
|
// Likely due to damage biasing based on RA factions and/or difficulty settings
|
||||||
|
// Applying this to units (vehicles), ships, buildings, and infantry, too
|
||||||
|
//
|
||||||
|
// damage = vptr->Strength; // Original
|
||||||
|
damage = 0x7fff; // Copied from TD
|
||||||
|
|
||||||
vptr->Take_Damage(damage, 0, WARHEAD_HE, NULL, true);
|
vptr->Take_Damage(damage, 0, WARHEAD_HE, NULL, true);
|
||||||
if (!vptr->IsActive) {
|
if (!vptr->IsActive) {
|
||||||
i--;
|
i--;
|
||||||
|
@ -4151,7 +4202,14 @@ void HouseClass::Blowup_All(void)
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
while (Buildings.Ptr(i)==bptr && bptr->Strength) {
|
while (Buildings.Ptr(i)==bptr && bptr->Strength) {
|
||||||
damage = bptr->Strength;
|
|
||||||
|
// MBL 06.22.2020 RA: Not all aircraft die in this case; See https://jaas.ea.com/browse/TDRA-6840
|
||||||
|
// Likely due to damage biasing based on RA factions and/or difficulty settings
|
||||||
|
// Applying this to units (vehicles), ships, buildings, and infantry, too
|
||||||
|
//
|
||||||
|
// damage = bptr->Strength; // Original
|
||||||
|
damage = 0x7fff; // Copied from TD
|
||||||
|
|
||||||
bptr->Take_Damage(damage, 0, WARHEAD_HE, NULL, true);
|
bptr->Take_Damage(damage, 0, WARHEAD_HE, NULL, true);
|
||||||
count++;
|
count++;
|
||||||
if (count > 5) {
|
if (count > 5) {
|
||||||
|
@ -4174,7 +4232,14 @@ void HouseClass::Blowup_All(void)
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
while (Infantry.Ptr(i)==iptr && iptr->Strength) {
|
while (Infantry.Ptr(i)==iptr && iptr->Strength) {
|
||||||
damage = iptr->Strength;
|
|
||||||
|
// MBL 06.22.2020 RA: Not all aircraft die in this case; See https://jaas.ea.com/browse/TDRA-6840
|
||||||
|
// Likely due to damage biasing based on RA factions and/or difficulty settings
|
||||||
|
// Applying this to units (vehicles), ships, buildings, and infantry, too
|
||||||
|
//
|
||||||
|
// damage = iptr->Strength; // Original
|
||||||
|
damage = 0x7fff; // Copied from TD
|
||||||
|
|
||||||
warhead = Random_Pick(WARHEAD_SA, WARHEAD_FIRE);
|
warhead = Random_Pick(WARHEAD_SA, WARHEAD_FIRE);
|
||||||
iptr->Take_Damage(damage, 0, warhead, NULL, true);
|
iptr->Take_Damage(damage, 0, warhead, NULL, true);
|
||||||
|
|
||||||
|
@ -8013,6 +8078,13 @@ void HouseClass::Check_Pertinent_Structures(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
bool any_good_buildings = false;
|
bool any_good_buildings = false;
|
||||||
|
|
||||||
for (int index = 0; index < Buildings.Count(); index++) {
|
for (int index = 0; index < Buildings.Count(); index++) {
|
||||||
|
@ -8020,6 +8092,7 @@ void HouseClass::Check_Pertinent_Structures(void)
|
||||||
|
|
||||||
if (b && b->IsActive && b->House == this) {
|
if (b && b->IsActive && b->House == this) {
|
||||||
if (!b->Class->IsWall && *b != STRUCT_APMINE && *b != STRUCT_AVMINE) {
|
if (!b->Class->IsWall && *b != STRUCT_APMINE && *b != STRUCT_AVMINE) {
|
||||||
|
if (!Special.ModernBalance || (*b != STRUCT_SHIP_YARD && *b != STRUCT_FAKE_YARD && *b != STRUCT_SUB_PEN && *b != STRUCT_FAKE_PEN)) {
|
||||||
if (!b->IsInLimbo && b->Strength > 0) {
|
if (!b->IsInLimbo && b->Strength > 0) {
|
||||||
any_good_buildings = true;
|
any_good_buildings = true;
|
||||||
break;
|
break;
|
||||||
|
@ -8027,6 +8100,7 @@ void HouseClass::Check_Pertinent_Structures(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!any_good_buildings) {
|
if (!any_good_buildings) {
|
||||||
for (int index = 0; index < Units.Count(); index++) {
|
for (int index = 0; index < Units.Count(); index++) {
|
||||||
|
|
|
@ -511,6 +511,9 @@ int InfantryClass::Shape_Number(WindowNumberType window) const
|
||||||
** The animation frame numbers may be different when rendering in legacy mode vs. exporting for render in GlyphX. ST - 9/5/2019 12:34PM
|
** The animation frame numbers may be different when rendering in legacy mode vs. exporting for render in GlyphX. ST - 9/5/2019 12:34PM
|
||||||
*/
|
*/
|
||||||
const DoInfoStruct *do_controls = (window == WINDOW_VIRTUAL) ? Class->DoControlsVirtual : Class->DoControls;
|
const DoInfoStruct *do_controls = (window == WINDOW_VIRTUAL) ? Class->DoControlsVirtual : Class->DoControls;
|
||||||
|
if (window != WINDOW_VIRTUAL && !IsOwnedByPlayer && *this == INFANTRY_SPY) {
|
||||||
|
do_controls = InfantryTypeClass::As_Reference(INFANTRY_E1).DoControls;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The infantry shape is always modulo the number of animation frames
|
** The infantry shape is always modulo the number of animation frames
|
||||||
|
@ -692,7 +695,7 @@ void InfantryClass::Per_Cell_Process(PCPType why)
|
||||||
|
|
||||||
// If they're spying on a sub pen, give 'em a sonar pulse
|
// If they're spying on a sub pen, give 'em a sonar pulse
|
||||||
if (build == STRUCT_SUB_PEN) {
|
if (build == STRUCT_SUB_PEN) {
|
||||||
House->SuperWeapon[SPC_SONAR_PULSE].Enable(true, true, false);
|
House->SuperWeapon[SPC_SONAR_PULSE].Enable(false, true, false);
|
||||||
// Add to Glyphx multiplayer sidebar. ST - 8/7/2019 10:13AM
|
// Add to Glyphx multiplayer sidebar. ST - 8/7/2019 10:13AM
|
||||||
if (Session.Type == GAME_GLYPHX_MULTIPLAYER) {
|
if (Session.Type == GAME_GLYPHX_MULTIPLAYER) {
|
||||||
if (House->IsHuman) {
|
if (House->IsHuman) {
|
||||||
|
@ -1480,7 +1483,7 @@ MoveType InfantryClass::Can_Enter_Cell(CELL cell, FacingType ) const
|
||||||
** Cloaked enemy objects are not considered if this is a Find_Path()
|
** Cloaked enemy objects are not considered if this is a Find_Path()
|
||||||
** call.
|
** call.
|
||||||
*/
|
*/
|
||||||
if (!obj->Is_Techno() || ((TechnoClass *)obj)->Cloak != CLOAKED) {
|
if (!obj->Is_Techno() || !((TechnoClass *)obj)->Is_Cloaked(this)) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Any non-allied blockage is considered impassible if the infantry
|
** Any non-allied blockage is considered impassible if the infantry
|
||||||
|
@ -3958,6 +3961,13 @@ void InfantryClass::Movement_AI(void)
|
||||||
// if (IsTethered) Scatter(0, true);
|
// if (IsTethered) Scatter(0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Scatter infantry off buildings in guard modes.
|
||||||
|
*/
|
||||||
|
if (!IsTethered && (Mission == MISSION_GUARD || Mission == MISSION_GUARD_AREA) && MissionQueue == MISSION_NONE && Map[Coord].Cell_Building() != NULL) {
|
||||||
|
Scatter(0, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Double check to make sure it doesn't have a movement destination into a zone
|
** Double check to make sure it doesn't have a movement destination into a zone
|
||||||
** that it can't travel to. In such a case, abort the movement process by clearing
|
** that it can't travel to. In such a case, abort the movement process by clearing
|
||||||
|
|
|
@ -286,6 +286,9 @@ bool Read_Scenario_INI_Write_INB( char *root, bool fresh)
|
||||||
UnitClass::Read_INI(buffer);
|
UnitClass::Read_INI(buffer);
|
||||||
Call_Back();
|
Call_Back();
|
||||||
|
|
||||||
|
AircraftClass::Read_INI(buffer);
|
||||||
|
Call_Back();
|
||||||
|
|
||||||
VesselClass::Read_INI(buffer);
|
VesselClass::Read_INI(buffer);
|
||||||
Call_Back();
|
Call_Back();
|
||||||
|
|
||||||
|
|
|
@ -434,6 +434,16 @@ bool Init_Game(int , char * [])
|
||||||
ChronalVortex.Stop();
|
ChronalVortex.Stop();
|
||||||
ChronalVortex.Setup_Remap_Tables(Scen.Theater);
|
ChronalVortex.Setup_Remap_Tables(Scen.Theater);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Clear out name overrides array
|
||||||
|
*/
|
||||||
|
#ifdef FIXIT_NAME_OVERRIDE
|
||||||
|
for (int index = 0; index < ARRAY_SIZE(NameOverride); index++) {
|
||||||
|
NameOverride[index] = NULL;
|
||||||
|
NameIDOverride[index] = 0;
|
||||||
|
}
|
||||||
|
#endif //FIXIT_NAME_OVERRIDE
|
||||||
|
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -316,6 +316,7 @@ void LogicClass::AI(void)
|
||||||
*/
|
*/
|
||||||
for (index = 0; index < Count(); index++) {
|
for (index = 0; index < Count(); index++) {
|
||||||
ObjectClass * obj = (*this)[index];
|
ObjectClass * obj = (*this)[index];
|
||||||
|
int count = Count();
|
||||||
|
|
||||||
BStart(BENCH_AI);
|
BStart(BENCH_AI);
|
||||||
obj->AI();
|
obj->AI();
|
||||||
|
@ -354,8 +355,9 @@ void LogicClass::AI(void)
|
||||||
** If the object was destroyed in the process of performing its AI, then
|
** If the object was destroyed in the process of performing its AI, then
|
||||||
** adjust the index so that no object gets skipped.
|
** adjust the index so that no object gets skipped.
|
||||||
*/
|
*/
|
||||||
if (obj != (*this)[index]) {
|
int count_diff = Count() - count;
|
||||||
index--;
|
if (count_diff < 0) {
|
||||||
|
index += count_diff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HouseClass::Recalc_Attributes();
|
HouseClass::Recalc_Attributes();
|
||||||
|
|
|
@ -1026,6 +1026,16 @@ void MapClass::Logic(void)
|
||||||
** Tiberium cells that can grow or spread.
|
** Tiberium cells that can grow or spread.
|
||||||
*/
|
*/
|
||||||
int subcount = MAP_CELL_TOTAL / (Rule.GrowthRate * TICKS_PER_MINUTE);
|
int subcount = MAP_CELL_TOTAL / (Rule.GrowthRate * TICKS_PER_MINUTE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Use the Tiberium setting as a multiplier on growth rate. ST - 7/1/2020 3:05PM
|
||||||
|
*/
|
||||||
|
if (Session.Type == GAME_GLYPHX_MULTIPLAYER) {
|
||||||
|
if (Session.Options.Tiberium > 1) {
|
||||||
|
subcount *= Session.Options.Tiberium;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcount = max(subcount, 1);
|
subcount = max(subcount, 1);
|
||||||
int index;
|
int index;
|
||||||
for (index = TiberiumScan; index < MAP_CELL_TOTAL; index++) {
|
for (index = TiberiumScan; index < MAP_CELL_TOTAL; index++) {
|
||||||
|
@ -1416,11 +1426,11 @@ ObjectClass * MapClass::Close_Object(COORDINATE coord) const
|
||||||
while (o != NULL) {
|
while (o != NULL) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Special case check to ignore cloaked object if not owned by the player.
|
** Special case check to ignore cloaked object if not allied with the player.
|
||||||
*/
|
*/
|
||||||
// Change for client/server multiplayer. ST - 8/7/2019 10:35AM
|
// Change for client/server multiplayer. ST - 8/7/2019 10:35AM
|
||||||
//if (!o->Is_Techno() || ((TechnoClass *)o)->IsOwnedByPlayer || ((TechnoClass *)o)->Cloak != CLOAKED) {
|
//if (!o->Is_Techno() || ((TechnoClass *)o)->IsOwnedByPlayer || ((TechnoClass *)o)->Cloak != CLOAKED) {
|
||||||
if (!o->Is_Techno() || ((TechnoClass *)o)->Is_Owned_By_Player() || ((TechnoClass *)o)->Cloak != CLOAKED) {
|
if (!o->Is_Techno() || !((TechnoClass *)o)->Is_Cloaked(PlayerPtr)) {
|
||||||
int d=-1;
|
int d=-1;
|
||||||
if (o->What_Am_I() == RTTI_BUILDING) {
|
if (o->What_Am_I() == RTTI_BUILDING) {
|
||||||
d = Distance(coord, Cell_Coord(newcell));
|
d = Distance(coord, Cell_Coord(newcell));
|
||||||
|
@ -1445,7 +1455,7 @@ ObjectClass * MapClass::Close_Object(COORDINATE coord) const
|
||||||
AircraftClass * aircraft = Aircraft.Ptr(index);
|
AircraftClass * aircraft = Aircraft.Ptr(index);
|
||||||
|
|
||||||
if (aircraft->In_Which_Layer() != LAYER_GROUND) {
|
if (aircraft->In_Which_Layer() != LAYER_GROUND) {
|
||||||
if (aircraft->Is_Owned_By_Player() || (aircraft->Cloak != CLOAKED)) {
|
if (!aircraft->Is_Cloaked(PlayerPtr)) {
|
||||||
int d = Distance(coord, Coord_Add(aircraft->Center_Coord(), XY_Coord(0, -aircraft->Height)));
|
int d = Distance(coord, Coord_Add(aircraft->Center_Coord(), XY_Coord(0, -aircraft->Height)));
|
||||||
if (d >= 0 && (!object || d < distance)) {
|
if (d >= 0 && (!object || d < distance)) {
|
||||||
distance = d;
|
distance = d;
|
||||||
|
@ -1683,7 +1693,7 @@ int MapClass::Zone_Span(CELL cell, int zone, MZoneType check)
|
||||||
* HISTORY: *
|
* HISTORY: *
|
||||||
* 10/05/1995 JLB : Created. *
|
* 10/05/1995 JLB : Created. *
|
||||||
*=============================================================================================*/
|
*=============================================================================================*/
|
||||||
CELL MapClass::Nearby_Location(CELL cell, SpeedType speed, int zone, MZoneType check, bool checkflagged) const
|
CELL MapClass::Nearby_Location(CELL cell, SpeedType speed, int zone, MZoneType check, bool checkflagged, int locationmod) const
|
||||||
{
|
{
|
||||||
CELL topten[10];
|
CELL topten[10];
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -1767,7 +1777,7 @@ CELL MapClass::Nearby_Location(CELL cell, SpeedType speed, int zone, MZoneType c
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
return(topten[Frame % count]);
|
return(topten[(Frame+locationmod) % count]);
|
||||||
}
|
}
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ class MapClass: public GScreenClass
|
||||||
CELL Pick_Random_Location(void) const;
|
CELL Pick_Random_Location(void) const;
|
||||||
int Intact_Bridge_Count(void) const;
|
int Intact_Bridge_Count(void) const;
|
||||||
bool Base_Region(CELL cell, HousesType & house, ZoneType & zone) const;
|
bool Base_Region(CELL cell, HousesType & house, ZoneType & zone) const;
|
||||||
CELL Nearby_Location(CELL cell, SpeedType speed, int zone=-1, MZoneType check=MZONE_NORMAL, bool checkflagged=false) const;
|
CELL Nearby_Location(CELL cell, SpeedType speed, int zone=-1, MZoneType check=MZONE_NORMAL, bool checkflagged=false, int locationmod=0) const;
|
||||||
ObjectClass * Close_Object(COORDINATE coord) const;
|
ObjectClass * Close_Object(COORDINATE coord) const;
|
||||||
virtual void Detach(ObjectClass * ) {};
|
virtual void Detach(ObjectClass * ) {};
|
||||||
int Cell_Region(CELL cell);
|
int Cell_Region(CELL cell);
|
||||||
|
|
|
@ -428,7 +428,7 @@ dxisbig:
|
||||||
#if (0)
|
#if (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/REDALERT/MiscAsm.cpp#57 $
|
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/REDALERT/MiscAsm.cpp#95 $
|
||||||
;***************************************************************************
|
;***************************************************************************
|
||||||
;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
|
;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
|
||||||
;***************************************************************************
|
;***************************************************************************
|
||||||
|
|
|
@ -627,6 +627,14 @@ COORDINATE ObjectClass::Sort_Y(void) const
|
||||||
* HISTORY: *
|
* HISTORY: *
|
||||||
* 09/21/1995 JLB : Created. *
|
* 09/21/1995 JLB : Created. *
|
||||||
*=============================================================================================*/
|
*=============================================================================================*/
|
||||||
|
FireDataType ObjectClass::Fire_Data(int which) const
|
||||||
|
{
|
||||||
|
assert(this != 0);
|
||||||
|
assert(IsActive);
|
||||||
|
|
||||||
|
return{Fire_Coord(which),0};
|
||||||
|
}
|
||||||
|
|
||||||
COORDINATE ObjectClass::Fire_Coord(int ) const
|
COORDINATE ObjectClass::Fire_Coord(int ) const
|
||||||
{
|
{
|
||||||
assert(this != 0);
|
assert(this != 0);
|
||||||
|
|
|
@ -177,6 +177,7 @@ class ObjectClass : public AbstractClass
|
||||||
virtual COORDINATE Center_Coord(void) const;
|
virtual COORDINATE Center_Coord(void) const;
|
||||||
virtual COORDINATE Render_Coord(void) const;
|
virtual COORDINATE Render_Coord(void) const;
|
||||||
virtual COORDINATE Sort_Y(void) const;
|
virtual COORDINATE Sort_Y(void) const;
|
||||||
|
virtual FireDataType Fire_Data(int which) const;
|
||||||
virtual COORDINATE Fire_Coord(int which) const;
|
virtual COORDINATE Fire_Coord(int which) const;
|
||||||
virtual COORDINATE Exit_Coord(void) const;
|
virtual COORDINATE Exit_Coord(void) const;
|
||||||
|
|
||||||
|
|
|
@ -267,7 +267,7 @@ bool RadarClass::Radar_Activate(int control)
|
||||||
case 0:
|
case 0:
|
||||||
if (Map.IsSidebarActive) {
|
if (Map.IsSidebarActive) {
|
||||||
if (IsRadarActive && !IsRadarDeactivating) {
|
if (IsRadarActive && !IsRadarDeactivating) {
|
||||||
Sound_Effect(VOC_RADAR_OFF);
|
// Sound_Effect(VOC_RADAR_OFF); // MBL 07.20.2020: These are never being sent to the client, so handled there; Disabling here for good measure.
|
||||||
IsRadarDeactivating = true;
|
IsRadarDeactivating = true;
|
||||||
IsRadarActive = false;
|
IsRadarActive = false;
|
||||||
if (IsRadarActivating == true) {
|
if (IsRadarActivating == true) {
|
||||||
|
@ -284,7 +284,7 @@ bool RadarClass::Radar_Activate(int control)
|
||||||
case 1:
|
case 1:
|
||||||
if (Map.IsSidebarActive) {
|
if (Map.IsSidebarActive) {
|
||||||
if (!IsRadarActivating && !IsRadarActive) {
|
if (!IsRadarActivating && !IsRadarActive) {
|
||||||
Sound_Effect(VOC_RADAR_ON);
|
// Sound_Effect(VOC_RADAR_ON); // MBL 07.20.2020: These are never being sent to the client, so handled there; Disabling here for good measure.
|
||||||
IsRadarActivating = true;
|
IsRadarActivating = true;
|
||||||
if (IsRadarDeactivating == true) {
|
if (IsRadarDeactivating == true) {
|
||||||
IsRadarDeactivating = false;
|
IsRadarDeactivating = false;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="Source Files">
|
<Filter Include="Source Files">
|
||||||
|
|
|
@ -2411,6 +2411,9 @@ bool Read_Scenario_INI(char * fname, bool )
|
||||||
UnitClass::Read_INI(ini);
|
UnitClass::Read_INI(ini);
|
||||||
Call_Back();
|
Call_Back();
|
||||||
|
|
||||||
|
AircraftClass::Read_INI(ini);
|
||||||
|
Call_Back();
|
||||||
|
|
||||||
VesselClass::Read_INI(ini);
|
VesselClass::Read_INI(ini);
|
||||||
Call_Back();
|
Call_Back();
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,7 @@ void SpecialClass::Init(void)
|
||||||
UseMCVDeploy = false;
|
UseMCVDeploy = false;
|
||||||
IsMCVDeploy = false;
|
IsMCVDeploy = false;
|
||||||
IsEarlyWin = false;
|
IsEarlyWin = false;
|
||||||
|
ModernBalance = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -105,10 +105,22 @@ class SpecialClass
|
||||||
*/
|
*/
|
||||||
unsigned IsEarlyWin:1;
|
unsigned IsEarlyWin:1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** New modern balance setting.
|
||||||
|
*/
|
||||||
|
unsigned ModernBalance:1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Some additional padding in case we need to add data to the class and maintain backwards compatibility for save/load
|
** Some additional padding in case we need to add data to the class and maintain backwards compatibility for save/load
|
||||||
*/
|
*/
|
||||||
unsigned char SaveLoadPadding[128];
|
// MBL 07.21.2020 - https://jaas.ea.com/browse/TDRA-7537
|
||||||
|
// Loading save files from Live and July Patch 3 Beta versions results in a crash
|
||||||
|
// Fixes issue from Change 738397 2020/07/17 14:06:03
|
||||||
|
//
|
||||||
|
// unsigned char SaveLoadPadding[128]; // Note: Never changed to 127 like TD did
|
||||||
|
//
|
||||||
|
// unsigned char SaveLoadPadding[124]; // Trying 124 like we did with TD - Failed
|
||||||
|
unsigned char SaveLoadPadding[128]; // Works with With last weeks saves (7/16/2020) and newest saves; Skyler says go with this.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -977,6 +977,10 @@ void __cdecl Prog_End(const char *why, bool fatal)
|
||||||
*((int*)0) = 0;
|
*((int*)0) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Session.Type == GAME_GLYPHX_MULTIPLAYER) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Sound_End();
|
Sound_End();
|
||||||
if (WWMouse) {
|
if (WWMouse) {
|
||||||
delete WWMouse;
|
delete WWMouse;
|
||||||
|
|
|
@ -168,9 +168,9 @@ bool SuperClass::Enable(bool onetime, bool player, bool quiet)
|
||||||
* HISTORY: *
|
* HISTORY: *
|
||||||
* 07/28/1995 JLB : Created. *
|
* 07/28/1995 JLB : Created. *
|
||||||
*=============================================================================================*/
|
*=============================================================================================*/
|
||||||
bool SuperClass::Remove(void)
|
bool SuperClass::Remove(bool forced)
|
||||||
{
|
{
|
||||||
if (IsPresent && !IsOneTime) {
|
if (IsPresent && (!IsOneTime || forced)) {
|
||||||
IsReady = false;
|
IsReady = false;
|
||||||
IsPresent = false;
|
IsPresent = false;
|
||||||
return(true);
|
return(true);
|
||||||
|
|
|
@ -47,7 +47,7 @@ class SuperClass {
|
||||||
bool Enable(bool onetime = false, bool player=false, bool quiet=false);
|
bool Enable(bool onetime = false, bool player=false, bool quiet=false);
|
||||||
void Forced_Charge(bool player=false);
|
void Forced_Charge(bool player=false);
|
||||||
bool AI(bool player=false);
|
bool AI(bool player=false);
|
||||||
bool Remove(void);
|
bool Remove(bool forced=false);
|
||||||
void Impatient_Click(void) const;
|
void Impatient_Click(void) const;
|
||||||
int Anim_Stage(void) const;
|
int Anim_Stage(void) const;
|
||||||
bool Discharged(bool player);
|
bool Discharged(bool player);
|
||||||
|
|
|
@ -489,6 +489,25 @@ bool TechnoClass::Is_Allowed_To_Recloak(void) const
|
||||||
* HISTORY: *
|
* HISTORY: *
|
||||||
* 07/29/1996 JLB : Created. *
|
* 07/29/1996 JLB : Created. *
|
||||||
*=============================================================================================*/
|
*=============================================================================================*/
|
||||||
|
FireDataType TechnoClass::Fire_Data(int which) const
|
||||||
|
{
|
||||||
|
assert(IsActive);
|
||||||
|
|
||||||
|
TechnoTypeClass const * tclass = Techno_Type_Class();
|
||||||
|
|
||||||
|
int dist = 0;
|
||||||
|
if (which == 0) {
|
||||||
|
dist = tclass->PrimaryOffset;
|
||||||
|
} else {
|
||||||
|
dist = tclass->SecondaryOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
COORDINATE coord = Coord_Move(Center_Coord(), DIR_N, tclass->VerticalOffset + Height);
|
||||||
|
coord = Coord_Move(coord, DIR_E, tclass->HorizontalOffset);
|
||||||
|
|
||||||
|
return{coord,dist};
|
||||||
|
}
|
||||||
|
|
||||||
COORDINATE TechnoClass::Fire_Coord(int which) const
|
COORDINATE TechnoClass::Fire_Coord(int which) const
|
||||||
{
|
{
|
||||||
assert(IsActive);
|
assert(IsActive);
|
||||||
|
@ -667,7 +686,7 @@ bool TechnoClass::Is_Visible_On_Radar(void) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Techno_Type_Class()->IsInvisible && (Cloak != CLOAKED || House->Is_Ally(PlayerPtr))) {
|
if (!Is_Cloaked(PlayerPtr, true)) {
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
return(false);
|
return(false);
|
||||||
|
@ -973,9 +992,14 @@ RadioMessageType TechnoClass::Receive_Message(RadioClass * from, RadioMessageTyp
|
||||||
/*
|
/*
|
||||||
** If there is sufficient money to repair the unit one step, then do so.
|
** If there is sufficient money to repair the unit one step, then do so.
|
||||||
** Otherwise return with a "can't complete" radio response.
|
** Otherwise return with a "can't complete" radio response.
|
||||||
|
** Special case: in single-player campaigns, also try to use the repair pad house's money.
|
||||||
*/
|
*/
|
||||||
if (House->Available_Money() >= cost) {
|
HouseClass* house = House;
|
||||||
House->Spend_Money(cost);
|
if (Session.Type == GAME_NORMAL && house->Available_Money() < cost) {
|
||||||
|
house = HouseClass::As_Pointer(from->Owner());
|
||||||
|
}
|
||||||
|
if (house != NULL && house->Available_Money() >= cost) {
|
||||||
|
house->Spend_Money(cost);
|
||||||
Strength += step;
|
Strength += step;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1088,7 +1112,7 @@ void TechnoClass::Draw_It(int x, int y, WindowNumberType window) const
|
||||||
int width, height;
|
int width, height;
|
||||||
Class_Of().Dimensions(width, height);
|
Class_Of().Dimensions(width, height);
|
||||||
|
|
||||||
const bool show_health_bar = (Strength > 0) && (Is_Selected_By_Player() ||
|
const bool show_health_bar = (Strength > 0) && !Is_Cloaked(PlayerPtr) && (Is_Selected_By_Player() ||
|
||||||
((Rule.HealthBarDisplayMode == RulesClass::HB_DAMAGED) && (Strength < Techno_Type_Class()->MaxStrength)) ||
|
((Rule.HealthBarDisplayMode == RulesClass::HB_DAMAGED) && (Strength < Techno_Type_Class()->MaxStrength)) ||
|
||||||
(Rule.HealthBarDisplayMode == RulesClass::HB_ALWAYS));
|
(Rule.HealthBarDisplayMode == RulesClass::HB_ALWAYS));
|
||||||
|
|
||||||
|
@ -1253,8 +1277,8 @@ bool TechnoClass::In_Range(TARGET target, int which, bool reciprocal_check) cons
|
||||||
if (building != NULL) {
|
if (building != NULL) {
|
||||||
range += ((building->Class->Width() + building->Class->Height()) * (ICON_LEPTON_W / 4));
|
range += ((building->Class->Width() + building->Class->Height()) * (ICON_LEPTON_W / 4));
|
||||||
}
|
}
|
||||||
|
FireDataType data = Fire_Data(which);
|
||||||
if (::Distance(Fire_Coord(which), As_Coord(target)) <= range) {
|
if (MAX(0, ::Distance(data.Center, As_Coord(target)) - data.Distance) <= range) {
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1309,8 +1333,8 @@ bool TechnoClass::In_Range(ObjectClass const * target, int which, bool reciproca
|
||||||
BuildingClass const * building = (BuildingClass const *)target;
|
BuildingClass const * building = (BuildingClass const *)target;
|
||||||
range += ((building->Class->Width() + building->Class->Height()) * (ICON_LEPTON_W / 4));
|
range += ((building->Class->Width() + building->Class->Height()) * (ICON_LEPTON_W / 4));
|
||||||
}
|
}
|
||||||
|
FireDataType data = Fire_Data(which);
|
||||||
if (::Distance(Fire_Coord(which), target->Center_Coord()) <= range) {
|
if (MAX(0, ::Distance(data.Center, target->Center_Coord()) - data.Distance) <= range) {
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1506,7 +1530,7 @@ bool TechnoClass::Evaluate_Object(ThreatType method, int mask, int range, Techno
|
||||||
/*
|
/*
|
||||||
** If the object is cloaked, then it isn't a legal target.
|
** If the object is cloaked, then it isn't a legal target.
|
||||||
*/
|
*/
|
||||||
if (object->Cloak == CLOAKED) {
|
if (object->Is_Cloaked(this)) {
|
||||||
BEnd(BENCH_EVAL_OBJECT);
|
BEnd(BENCH_EVAL_OBJECT);
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
@ -1535,17 +1559,13 @@ bool TechnoClass::Evaluate_Object(ThreatType method, int mask, int range, Techno
|
||||||
** object is a friend. Unless we're a medic, of course. But then,
|
** object is a friend. Unless we're a medic, of course. But then,
|
||||||
** only consider it a target if it's injured.
|
** only consider it a target if it's injured.
|
||||||
*/
|
*/
|
||||||
if (House->Is_Ally(object)) {
|
bool is_ally = House->Is_Ally(object);
|
||||||
if (Combat_Damage() < 0) {
|
bool is_medic = Combat_Damage() < 0;
|
||||||
if (object->Health_Ratio() == Rule.ConditionGreen) {
|
bool green_health = object->Health_Ratio() == Rule.ConditionGreen;
|
||||||
|
if ((is_ally && (!is_medic || green_health)) || (!is_ally && is_medic)) {
|
||||||
BEnd(BENCH_EVAL_OBJECT);
|
BEnd(BENCH_EVAL_OBJECT);
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
BEnd(BENCH_EVAL_OBJECT);
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** If the object is further away than allowed, bail.
|
** If the object is further away than allowed, bail.
|
||||||
|
@ -2016,6 +2036,27 @@ int TechnoClass::Evaluate_Just_Cell(CELL cell) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool TechnoClass::Is_Cloaked(HousesType house, bool check_invisible) const
|
||||||
|
{
|
||||||
|
const bool is_invisible = check_invisible && Techno_Type_Class()->IsInvisible;
|
||||||
|
return !House->Is_Ally(house) && ((Cloak == CLOAKED) || is_invisible);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool TechnoClass::Is_Cloaked(HouseClass const * house, bool check_invisible) const
|
||||||
|
{
|
||||||
|
const bool is_invisible = check_invisible && Techno_Type_Class()->IsInvisible;
|
||||||
|
return !House->Is_Ally(house) && ((Cloak == CLOAKED) || is_invisible);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool TechnoClass::Is_Cloaked(ObjectClass const * object, bool check_invisible) const
|
||||||
|
{
|
||||||
|
const bool is_invisible = check_invisible && Techno_Type_Class()->IsInvisible;
|
||||||
|
return !House->Is_Ally(object) && ((Cloak == CLOAKED) || is_invisible);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************************************
|
/***********************************************************************************************
|
||||||
* TechnoClass::Greatest_Threat -- Determines best target given search criteria. *
|
* TechnoClass::Greatest_Threat -- Determines best target given search criteria. *
|
||||||
* *
|
* *
|
||||||
|
@ -2448,7 +2489,7 @@ void TechnoClass::AI(void)
|
||||||
** If for some strange reason, the computer is firing upon itself, then
|
** If for some strange reason, the computer is firing upon itself, then
|
||||||
** tell it not to.
|
** tell it not to.
|
||||||
*/
|
*/
|
||||||
if (!House->IsHuman && As_Techno(TarCom) && As_Techno(TarCom)->House->Is_Ally(this)) {
|
if (!House->IsHuman && As_Techno(TarCom) && As_Techno(TarCom)->House->Is_Ally(this) && Combat_Damage() >= 0) {
|
||||||
//#ifdef FIXIT_CSII // checked - ajw 9/28/98 (commented out)
|
//#ifdef FIXIT_CSII // checked - ajw 9/28/98 (commented out)
|
||||||
//if(What_Am_I() == RTTI_INFANTRY && *(InfantryClass *)this==INFANTRY_GENERAL && Session.Type==GAME_NORMAL && House->Class->House==HOUSE_UKRAINE) {
|
//if(What_Am_I() == RTTI_INFANTRY && *(InfantryClass *)this==INFANTRY_GENERAL && Session.Type==GAME_NORMAL && House->Class->House==HOUSE_UKRAINE) {
|
||||||
//} else
|
//} else
|
||||||
|
@ -2773,9 +2814,9 @@ FireErrorType TechnoClass::Can_Fire(TARGET target, int which) const
|
||||||
ObjectClass * object = As_Object(target);
|
ObjectClass * object = As_Object(target);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** If the object is completely cloaked, then you can't fire on it.
|
** If an enemy object is completely cloaked, then you can't fire on it.
|
||||||
*/
|
*/
|
||||||
if (object != NULL && object->Is_Techno() && ((TechnoClass *)object)->Cloak == CLOAKED) {
|
if (object != NULL && object->Is_Techno() && ((TechnoClass *)object)->Is_Cloaked(this)) {
|
||||||
return(FIRE_CANT);
|
return(FIRE_CANT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4187,7 +4228,7 @@ void TechnoClass::Record_The_Kill(TechnoClass * source)
|
||||||
* 07/06/1995 JLB : Created. *
|
* 07/06/1995 JLB : Created. *
|
||||||
* 09/28/1995 JLB : Uses map scan function. *
|
* 09/28/1995 JLB : Uses map scan function. *
|
||||||
*=============================================================================================*/
|
*=============================================================================================*/
|
||||||
CELL TechnoClass::Nearby_Location(TechnoClass const * techno) const
|
CELL TechnoClass::Nearby_Location(TechnoClass const * techno, int locationmod) const
|
||||||
{
|
{
|
||||||
assert(IsActive);
|
assert(IsActive);
|
||||||
|
|
||||||
|
@ -4203,7 +4244,7 @@ CELL TechnoClass::Nearby_Location(TechnoClass const * techno) const
|
||||||
cell = Coord_Cell(Center_Coord());
|
cell = Coord_Cell(Center_Coord());
|
||||||
}
|
}
|
||||||
|
|
||||||
return(Map.Nearby_Location(cell, speed, Map[cell].Zones[Techno_Type_Class()->MZone], Techno_Type_Class()->MZone));
|
return(Map.Nearby_Location(cell, speed, Map[cell].Zones[Techno_Type_Class()->MZone], Techno_Type_Class()->MZone, false, locationmod));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -271,7 +271,7 @@ class TechnoClass : public RadioClass,
|
||||||
bool Is_Ready_To_Cloak(void) const;
|
bool Is_Ready_To_Cloak(void) const;
|
||||||
virtual int How_Many_Survivors(void) const;
|
virtual int How_Many_Survivors(void) const;
|
||||||
virtual DirType Turret_Facing(void) const {return(PrimaryFacing.Current());}
|
virtual DirType Turret_Facing(void) const {return(PrimaryFacing.Current());}
|
||||||
CELL Nearby_Location(TechnoClass const * from=NULL) const;
|
CELL Nearby_Location(TechnoClass const * from=NULL, int locationmod=0) const;
|
||||||
TechnoTypeClass * Techno_Type_Class(void) const {return((TechnoTypeClass *)&Class_Of());};
|
TechnoTypeClass * Techno_Type_Class(void) const {return((TechnoTypeClass *)&Class_Of());};
|
||||||
bool Is_Visible_On_Radar(void) const;
|
bool Is_Visible_On_Radar(void) const;
|
||||||
int Anti_Air(void) const;
|
int Anti_Air(void) const;
|
||||||
|
@ -282,6 +282,7 @@ class TechnoClass : public RadioClass,
|
||||||
virtual ActionType What_Action(ObjectClass const * target) const;
|
virtual ActionType What_Action(ObjectClass const * target) const;
|
||||||
virtual BuildingClass * Find_Docking_Bay(StructType b, bool friendly) const;
|
virtual BuildingClass * Find_Docking_Bay(StructType b, bool friendly) const;
|
||||||
virtual CELL Find_Exit_Cell(TechnoClass const * techno) const;
|
virtual CELL Find_Exit_Cell(TechnoClass const * techno) const;
|
||||||
|
virtual FireDataType Fire_Data(int) const;
|
||||||
virtual COORDINATE Fire_Coord(int which) const;
|
virtual COORDINATE Fire_Coord(int which) const;
|
||||||
virtual DirType Desired_Load_Dir(ObjectClass * , CELL & moveto) const;
|
virtual DirType Desired_Load_Dir(ObjectClass * , CELL & moveto) const;
|
||||||
virtual DirType Fire_Direction(void) const;
|
virtual DirType Fire_Direction(void) const;
|
||||||
|
@ -338,6 +339,9 @@ class TechnoClass : public RadioClass,
|
||||||
bool Evaluate_Object(ThreatType method, int mask, int range, TechnoClass const * object, int & value, int zone=-1) const;
|
bool Evaluate_Object(ThreatType method, int mask, int range, TechnoClass const * object, int & value, int zone=-1) const;
|
||||||
int Evaluate_Just_Cell(CELL cell) const;
|
int Evaluate_Just_Cell(CELL cell) const;
|
||||||
virtual bool Electric_Zap (COORDINATE target_coord, int which, WindowNumberType window, COORDINATE source_coord=0L, unsigned char * remap=NULL) const;
|
virtual bool Electric_Zap (COORDINATE target_coord, int which, WindowNumberType window, COORDINATE source_coord=0L, unsigned char * remap=NULL) const;
|
||||||
|
bool Is_Cloaked(HousesType house, bool check_invisible=false) const;
|
||||||
|
bool Is_Cloaked(HouseClass const * house, bool check_invisible=false) const;
|
||||||
|
bool Is_Cloaked(ObjectClass const * object, bool check_invisible=false) const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** AI.
|
** AI.
|
||||||
|
|
|
@ -433,6 +433,13 @@ void UnitClass::AI(void)
|
||||||
*/
|
*/
|
||||||
Rotation_AI();
|
Rotation_AI();
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Scatter units off buildings in guard modes.
|
||||||
|
*/
|
||||||
|
if (!IsTethered && !IsFiring && !IsDriving && !IsRotating && (Mission == MISSION_GUARD || Mission == MISSION_GUARD_AREA) && MissionQueue == MISSION_NONE && Map[Coord].Cell_Building() != NULL) {
|
||||||
|
Scatter(0, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Delete this unit if it finds itself off the edge of the map and it is in
|
** Delete this unit if it finds itself off the edge of the map and it is in
|
||||||
** guard or other static mission mode.
|
** guard or other static mission mode.
|
||||||
|
@ -1283,6 +1290,11 @@ void UnitClass::Player_Assign_Mission(MissionType mission, TARGET target, TARGET
|
||||||
|
|
||||||
if (mission == MISSION_HARVEST) {
|
if (mission == MISSION_HARVEST) {
|
||||||
ArchiveTarget = TARGET_NONE;
|
ArchiveTarget = TARGET_NONE;
|
||||||
|
} else if (mission == MISSION_ENTER) {
|
||||||
|
BuildingClass* building = As_Building(destination);
|
||||||
|
if (building != NULL && *building == STRUCT_REFINERY && building->In_Radio_Contact()) {
|
||||||
|
building->Transmit_Message(RADIO_OVER_OUT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DriveClass::Player_Assign_Mission(mission, target, destination);
|
DriveClass::Player_Assign_Mission(mission, target, destination);
|
||||||
}
|
}
|
||||||
|
@ -1704,7 +1716,7 @@ void UnitClass::Per_Cell_Process(PCPType why)
|
||||||
} else {
|
} else {
|
||||||
TechnoClass * contact = Contact_With_Whom();
|
TechnoClass * contact = Contact_With_Whom();
|
||||||
if (Transmit_Message(RADIO_UNLOADED) == RADIO_RUN_AWAY) {
|
if (Transmit_Message(RADIO_UNLOADED) == RADIO_RUN_AWAY) {
|
||||||
if (*this == UNIT_HARVESTER && contact && contact->What_Am_I() == RTTI_BUILDING) {
|
if (*this == UNIT_HARVESTER && contact && contact->What_Am_I() == RTTI_BUILDING && *((BuildingClass*)contact) != STRUCT_REPAIR) {
|
||||||
Assign_Mission(MISSION_HARVEST);
|
Assign_Mission(MISSION_HARVEST);
|
||||||
} else if (!Target_Legal(NavCom)) {
|
} else if (!Target_Legal(NavCom)) {
|
||||||
Scatter(0, true);
|
Scatter(0, true);
|
||||||
|
@ -2201,10 +2213,25 @@ int UnitClass::Tiberium_Check(CELL & center, int x, int y)
|
||||||
|
|
||||||
center = XY_Cell(Cell_X(center)+x, Cell_Y(center)+y);
|
center = XY_Cell(Cell_X(center)+x, Cell_Y(center)+y);
|
||||||
|
|
||||||
if ((Session.Type != GAME_NORMAL || (!IsOwnedByPlayer || Map[center].IsMapped))) {
|
if ((Session.Type != GAME_NORMAL || (!IsOwnedByPlayer || Map[center].Is_Mapped(PlayerPtr)))) {
|
||||||
if (Map[Coord].Zones[Class->MZone] != Map[center].Zones[Class->MZone]) return(0);
|
if (Map[Coord].Zones[Class->MZone] != Map[center].Zones[Class->MZone]) return(0);
|
||||||
if (!Map[center].Cell_Techno() && Map[center].Land_Type() == LAND_TIBERIUM) {
|
if (!Map[center].Cell_Techno() && Map[center].Land_Type() == LAND_TIBERIUM) {
|
||||||
return(Map[center].OverlayData);
|
int value = 0;
|
||||||
|
switch (Map[center].Overlay) {
|
||||||
|
case OVERLAY_GOLD1:
|
||||||
|
case OVERLAY_GOLD2:
|
||||||
|
case OVERLAY_GOLD3:
|
||||||
|
case OVERLAY_GOLD4:
|
||||||
|
value = Rule.GoldValue;
|
||||||
|
break;
|
||||||
|
case OVERLAY_GEMS1:
|
||||||
|
case OVERLAY_GEMS2:
|
||||||
|
case OVERLAY_GEMS3:
|
||||||
|
case OVERLAY_GEMS4:
|
||||||
|
value = Rule.GemValue*4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return((Map[center].OverlayData+1)*value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(0);
|
return(0);
|
||||||
|
@ -2248,6 +2275,7 @@ bool UnitClass::Goto_Tiberium(int rad)
|
||||||
int tiberium = 0;
|
int tiberium = 0;
|
||||||
int besttiberium = 0;
|
int besttiberium = 0;
|
||||||
for (int x = -radius; x <= radius; x++) {
|
for (int x = -radius; x <= radius; x++) {
|
||||||
|
cell = center;
|
||||||
tiberium = Tiberium_Check(cell, x, -radius);
|
tiberium = Tiberium_Check(cell, x, -radius);
|
||||||
if (tiberium > besttiberium) {
|
if (tiberium > besttiberium) {
|
||||||
bestcell = cell;
|
bestcell = cell;
|
||||||
|
@ -2832,10 +2860,10 @@ int UnitClass::Mission_Harvest(void)
|
||||||
*/
|
*/
|
||||||
case LOOKING:
|
case LOOKING:
|
||||||
/*
|
/*
|
||||||
** When full of tiberium, just skip to finding a free refinery
|
** Slightly hacky; if TarCom is set then skip to finding home state.
|
||||||
** to unload at.
|
|
||||||
*/
|
*/
|
||||||
if (Tiberium_Load() == 1) {
|
if (Target_Legal(TarCom)) {
|
||||||
|
Assign_Target(TARGET_NONE);
|
||||||
Status = FINDHOME;
|
Status = FINDHOME;
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
@ -3252,7 +3280,7 @@ MoveType UnitClass::Can_Enter_Cell(CELL cell, FacingType ) const
|
||||||
** Cloaked enemy objects are not considered if this is a Find_Path()
|
** Cloaked enemy objects are not considered if this is a Find_Path()
|
||||||
** call.
|
** call.
|
||||||
*/
|
*/
|
||||||
if (!obj->Is_Techno() || ((TechnoClass *)obj)->Cloak != CLOAKED) {
|
if (!obj->Is_Techno() || !((TechnoClass *)obj)->Is_Cloaked(this)) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** If this unit can crush infantry, and there is an enemy infantry in the
|
** If this unit can crush infantry, and there is an enemy infantry in the
|
||||||
|
@ -3530,14 +3558,17 @@ ActionType UnitClass::What_Action(ObjectClass const * object) const
|
||||||
/*
|
/*
|
||||||
** Special return to friendly refinery action.
|
** Special return to friendly refinery action.
|
||||||
*/
|
*/
|
||||||
if (Is_Owned_By_Player() && House->Class->House == object->Owner() && object->What_Am_I() == RTTI_BUILDING && ((UnitClass *)this)->Transmit_Message(RADIO_CAN_LOAD, (TechnoClass*)object) == RADIO_ROGER) {
|
bool is_player_controlled = (Session.Type == GAME_NORMAL)
|
||||||
|
? (House->IsPlayerControl && object->Owner() != HOUSE_NONE && HouseClass::As_Pointer(object->Owner())->IsPlayerControl)
|
||||||
|
: (Is_Owned_By_Player() && House->Class->House == object->Owner());
|
||||||
|
if (is_player_controlled && object->What_Am_I() == RTTI_BUILDING && ((UnitClass *)this)->Transmit_Message(RADIO_CAN_LOAD, (TechnoClass*)object) == RADIO_ROGER) {
|
||||||
action = ACTION_ENTER;
|
action = ACTION_ENTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Special return to friendly repair factory action.
|
** Special return to friendly repair factory action.
|
||||||
*/
|
*/
|
||||||
if (Is_Owned_By_Player() && House->Class->House == object->Owner() && action == ACTION_SELECT && object->What_Am_I() == RTTI_BUILDING) {
|
if (is_player_controlled && action == ACTION_SELECT && object->What_Am_I() == RTTI_BUILDING) {
|
||||||
BuildingClass * building = (BuildingClass *)object;
|
BuildingClass * building = (BuildingClass *)object;
|
||||||
if (building->Class->Type == STRUCT_REPAIR && ((UnitClass *)this)->Transmit_Message(RADIO_CAN_LOAD, building) == RADIO_ROGER && !building->In_Radio_Contact() && !building->Is_Something_Attached()) {
|
if (building->Class->Type == STRUCT_REPAIR && ((UnitClass *)this)->Transmit_Message(RADIO_CAN_LOAD, building) == RADIO_ROGER && !building->In_Radio_Contact() && !building->Is_Something_Attached()) {
|
||||||
action = ACTION_MOVE;
|
action = ACTION_MOVE;
|
||||||
|
|
|
@ -299,7 +299,7 @@ MoveType VesselClass::Can_Enter_Cell(CELL cell, FacingType ) const
|
||||||
}
|
}
|
||||||
|
|
||||||
TechnoClass * techno = cellptr->Cell_Techno();
|
TechnoClass * techno = cellptr->Cell_Techno();
|
||||||
if (techno != NULL && techno->Cloak == CLOAKED && !House->Is_Ally(techno)) {
|
if (techno != NULL && techno->Is_Cloaked(this)) {
|
||||||
return(MOVE_CLOAK);
|
return(MOVE_CLOAK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1183,6 +1183,32 @@ Mono_Set_Cursor(0,0);
|
||||||
* HISTORY: *
|
* HISTORY: *
|
||||||
* 05/13/1996 JLB : Created. *
|
* 05/13/1996 JLB : Created. *
|
||||||
*=============================================================================================*/
|
*=============================================================================================*/
|
||||||
|
FireDataType VesselClass::Fire_Data(int which) const
|
||||||
|
{
|
||||||
|
assert(Vessels.ID(this) == ID);
|
||||||
|
assert(IsActive);
|
||||||
|
|
||||||
|
COORDINATE coord = Center_Coord();
|
||||||
|
|
||||||
|
if (*this == VESSEL_CA) {
|
||||||
|
if (IsSecondShot) {
|
||||||
|
coord = Coord_Move(coord, PrimaryFacing + DIR_S, 0x0100);
|
||||||
|
} else {
|
||||||
|
coord = Coord_Move(coord, PrimaryFacing, 0x0100);
|
||||||
|
}
|
||||||
|
coord = Coord_Move(coord, DIR_N, 0x0030);
|
||||||
|
return{coord,0x0040};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*this == VESSEL_PT) {
|
||||||
|
coord = Coord_Move(coord, PrimaryFacing, 0x0080);
|
||||||
|
coord = Coord_Move(coord, DIR_N, 0x0020);
|
||||||
|
return{coord,0x0010};
|
||||||
|
}
|
||||||
|
|
||||||
|
return(DriveClass::Fire_Data(which));
|
||||||
|
}
|
||||||
|
|
||||||
COORDINATE VesselClass::Fire_Coord(int which) const
|
COORDINATE VesselClass::Fire_Coord(int which) const
|
||||||
{
|
{
|
||||||
assert(Vessels.ID(this) == ID);
|
assert(Vessels.ID(this) == ID);
|
||||||
|
|
|
@ -97,6 +97,7 @@ class VesselClass : public DriveClass
|
||||||
virtual int Mission_Unload(void);
|
virtual int Mission_Unload(void);
|
||||||
void LST_Open_Door(void);
|
void LST_Open_Door(void);
|
||||||
void LST_Close_Door(void);
|
void LST_Close_Door(void);
|
||||||
|
virtual FireDataType Fire_Data(int) const;
|
||||||
virtual COORDINATE Fire_Coord(int which) const;
|
virtual COORDINATE Fire_Coord(int which) const;
|
||||||
virtual MoveType Can_Enter_Cell(CELL cell, FacingType from=FACING_NONE) const;
|
virtual MoveType Can_Enter_Cell(CELL cell, FacingType from=FACING_NONE) const;
|
||||||
virtual void Draw_It(int x, int y, WindowNumberType window) const;
|
virtual void Draw_It(int x, int y, WindowNumberType window) const;
|
||||||
|
|
|
@ -4842,7 +4842,7 @@ extern "C" int __cdecl Confine_Rect ( int * x , int * y , int w , int h , int wi
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/REDALERT/WIN32LIB/DrawMisc.cpp#57 $
|
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/REDALERT/WIN32LIB/DrawMisc.cpp#95 $
|
||||||
;***************************************************************************
|
;***************************************************************************
|
||||||
;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
|
;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
|
||||||
;***************************************************************************
|
;***************************************************************************
|
||||||
|
|
|
@ -337,7 +337,7 @@ static AnimTypeClass const LZSmoke(
|
||||||
72, // Loop start frame number.
|
72, // Loop start frame number.
|
||||||
91, // Ending frame of loop back.
|
91, // Ending frame of loop back.
|
||||||
-1, // Number of animation stages.
|
-1, // Number of animation stages.
|
||||||
255, // Number of times the animation loops.
|
127, // Number of times the animation loops.
|
||||||
VOC_NONE, // Sound effect to play.
|
VOC_NONE, // Sound effect to play.
|
||||||
ANIM_NONE
|
ANIM_NONE
|
||||||
);
|
);
|
||||||
|
@ -1427,7 +1427,7 @@ static AnimTypeClass const OilFieldBurn(
|
||||||
33, // Loop start frame number.
|
33, // Loop start frame number.
|
||||||
99, // Ending frame of loop back.
|
99, // Ending frame of loop back.
|
||||||
66, // Number of animation stages.
|
66, // Number of animation stages.
|
||||||
65535, // Number of times the animation loops.
|
127, // Number of times the animation loops.
|
||||||
VOC_NONE, // Sound effect to play.
|
VOC_NONE, // Sound effect to play.
|
||||||
ANIM_NONE
|
ANIM_NONE
|
||||||
);
|
);
|
||||||
|
|
|
@ -245,6 +245,7 @@ AircraftClass::AircraftClass(AircraftType classid, HousesType house) :
|
||||||
NavCom = TARGET_NONE;
|
NavCom = TARGET_NONE;
|
||||||
SecondaryFacing = PrimaryFacing;
|
SecondaryFacing = PrimaryFacing;
|
||||||
Jitter = 0;
|
Jitter = 0;
|
||||||
|
ReinforcementStart = -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Keep count of the number of units created. Dont track cargo planes as they are created
|
** Keep count of the number of units created. Dont track cargo planes as they are created
|
||||||
|
@ -346,6 +347,14 @@ void AircraftClass::Draw_It(int x, int y, WindowNumberType window)
|
||||||
int shapenum = 0;
|
int shapenum = 0;
|
||||||
int facing = Facing_To_32(SecondaryFacing);
|
int facing = Facing_To_32(SecondaryFacing);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Don't draw Cargo aircraft that are delayed.
|
||||||
|
*/
|
||||||
|
if (Special.ModernBalance) {
|
||||||
|
if (*this == AIRCRAFT_CARGO && !Map.In_Radar(Coord_Cell(Coord)) && ReinforcementStart > Frame) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Verify the legality of the unit class.
|
** Verify the legality of the unit class.
|
||||||
|
@ -743,7 +752,17 @@ void AircraftClass::AI(void)
|
||||||
Mark();
|
Mark();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Physics(Coord, PrimaryFacing) != RESULT_NONE) {
|
|
||||||
|
/*
|
||||||
|
** Handle reinforcement delay.
|
||||||
|
*/
|
||||||
|
bool do_physics = true;
|
||||||
|
if (Special.ModernBalance) {
|
||||||
|
if (*this == AIRCRAFT_CARGO && !Map.In_Radar(Coord_Cell(Coord)) && ReinforcementStart > Frame) {
|
||||||
|
do_physics = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (do_physics && Physics(Coord, PrimaryFacing) != RESULT_NONE) {
|
||||||
Mark();
|
Mark();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1399,9 +1418,13 @@ int AircraftClass::Mission_Retreat(void)
|
||||||
{
|
{
|
||||||
Validate();
|
Validate();
|
||||||
if (Class->IsFixedWing) {
|
if (Class->IsFixedWing) {
|
||||||
if (Class->IsFixedWing && Altitude < FLIGHT_LEVEL) {
|
if (*this == AIRCRAFT_CARGO) {
|
||||||
|
PrimaryFacing.Set_Desired(DIR_W);
|
||||||
|
SecondaryFacing.Set_Desired(PrimaryFacing.Desired());
|
||||||
|
}
|
||||||
|
if (Altitude < FLIGHT_LEVEL) {
|
||||||
Altitude++;
|
Altitude++;
|
||||||
return(3);
|
return(1);
|
||||||
}
|
}
|
||||||
return(TICKS_PER_SECOND*10);
|
return(TICKS_PER_SECOND*10);
|
||||||
}
|
}
|
||||||
|
@ -2175,7 +2198,7 @@ ActionType AircraftClass::What_Action(CELL cell) const
|
||||||
ActionType action = FootClass::What_Action(cell);
|
ActionType action = FootClass::What_Action(cell);
|
||||||
|
|
||||||
//using function for IsVisible so we have different results for different players - JAS 2019/09/30
|
//using function for IsVisible so we have different results for different players - JAS 2019/09/30
|
||||||
if (action == ACTION_MOVE && !Map[cell].Is_Visible(PlayerPtr)) {
|
if ((action == ACTION_MOVE || action == ACTION_ATTACK) && !Map[cell].Is_Visible(PlayerPtr)) {
|
||||||
action = ACTION_NOMOVE;
|
action = ACTION_NOMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2438,7 +2461,7 @@ int AircraftClass::Mission_Attack(void)
|
||||||
* HISTORY: *
|
* HISTORY: *
|
||||||
* 06/19/1995 JLB : Created. *
|
* 06/19/1995 JLB : Created. *
|
||||||
*=============================================================================================*/
|
*=============================================================================================*/
|
||||||
TARGET AircraftClass::New_LZ(TARGET oldlz) const
|
TARGET AircraftClass::New_LZ(TARGET oldlz, bool stable) const
|
||||||
{
|
{
|
||||||
Validate();
|
Validate();
|
||||||
if (Target_Legal(oldlz) && (!Is_LZ_Clear(oldlz) || !Cell_Seems_Ok(As_Cell(oldlz)))) {
|
if (Target_Legal(oldlz) && (!Is_LZ_Clear(oldlz) || !Cell_Seems_Ok(As_Cell(oldlz)))) {
|
||||||
|
@ -2449,7 +2472,7 @@ TARGET AircraftClass::New_LZ(TARGET oldlz) const
|
||||||
** in cells.
|
** in cells.
|
||||||
*/
|
*/
|
||||||
for (int radius = 0; radius < 16; radius++) {
|
for (int radius = 0; radius < 16; radius++) {
|
||||||
FacingType modifier = Random_Pick(FACING_N, FACING_NW);
|
FacingType modifier = stable ? FACING_N : Random_Pick(FACING_N, FACING_NW);
|
||||||
CELL lastcell = -1;
|
CELL lastcell = -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2838,8 +2861,9 @@ TARGET AircraftClass::Good_Fire_Location(TARGET target) const
|
||||||
for (int face = 0; face < 255; face += 16) {
|
for (int face = 0; face < 255; face += 16) {
|
||||||
COORDINATE newcoord = Coord_Move(tcoord, (DirType)face, r);
|
COORDINATE newcoord = Coord_Move(tcoord, (DirType)face, r);
|
||||||
CELL newcell = Coord_Cell(newcoord);
|
CELL newcell = Coord_Cell(newcoord);
|
||||||
|
CELL actualcell = Coord_Cell(Coord_Sub(newcoord, XYPixel_Coord(0, FLIGHT_LEVEL)));
|
||||||
|
|
||||||
if (Map.In_Radar(newcell) && (GameToPlay != GAME_NORMAL || Map[newcell].Is_Visible(PlayerPtr)) && Cell_Seems_Ok(newcell, true)) {
|
if (Map.In_Radar(actualcell) && (GameToPlay != GAME_NORMAL || Map[newcell].Is_Visible(PlayerPtr)) && Cell_Seems_Ok(newcell, true)) {
|
||||||
int dist = Distance(newcoord);
|
int dist = Distance(newcoord);
|
||||||
if (bestval == -1 || dist < bestval) {
|
if (bestval == -1 || dist < bestval) {
|
||||||
best2val = bestval;
|
best2val = bestval;
|
||||||
|
@ -3546,3 +3570,8 @@ void AircraftClass::Response_Select(void)
|
||||||
Sound_Effect(response, 0, -(Aircraft.ID(this)+1));
|
Sound_Effect(response, 0, -(Aircraft.ID(this)+1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AircraftClass::Set_Reinforcement_Delay(long delay)
|
||||||
|
{
|
||||||
|
ReinforcementStart = Frame + delay;
|
||||||
|
}
|
|
@ -98,7 +98,7 @@ class AircraftClass : public FootClass, public FlyClass
|
||||||
** Landing zone support functionality.
|
** Landing zone support functionality.
|
||||||
*/
|
*/
|
||||||
bool Is_LZ_Clear(TARGET target) const;
|
bool Is_LZ_Clear(TARGET target) const;
|
||||||
TARGET New_LZ(TARGET oldlz) const;
|
TARGET New_LZ(TARGET oldlz, bool stable = false) const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Coordinate inquiry functions. These are used for both display and
|
** Coordinate inquiry functions. These are used for both display and
|
||||||
|
@ -148,6 +148,7 @@ class AircraftClass : public FootClass, public FlyClass
|
||||||
virtual void Enter_Idle_Mode(bool initial = false);
|
virtual void Enter_Idle_Mode(bool initial = false);
|
||||||
virtual RadioMessageType Receive_Message(RadioClass * from, RadioMessageType message, long & param);
|
virtual RadioMessageType Receive_Message(RadioClass * from, RadioMessageType message, long & param);
|
||||||
virtual void Scatter(COORDINATE threat, bool forced=false, bool nokidding=false);
|
virtual void Scatter(COORDINATE threat, bool forced=false, bool nokidding=false);
|
||||||
|
void Set_Reinforcement_Delay(long delay);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Scenario and debug support.
|
** Scenario and debug support.
|
||||||
|
@ -242,10 +243,15 @@ class AircraftClass : public FootClass, public FlyClass
|
||||||
*/
|
*/
|
||||||
char AttacksRemaining;
|
char AttacksRemaining;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Cargo planes will wait a certain number of ticks before flying in.
|
||||||
|
*/
|
||||||
|
long ReinforcementStart;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Some additional padding in case we need to add data to the class and maintain backwards compatibility for save/load
|
** Some additional padding in case we need to add data to the class and maintain backwards compatibility for save/load
|
||||||
*/
|
*/
|
||||||
unsigned char SaveLoadPadding[32];
|
unsigned char SaveLoadPadding[28];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This contains the value of the Virtual Function Table Pointer
|
** This contains the value of the Virtual Function Table Pointer
|
||||||
|
|
|
@ -589,7 +589,7 @@ AnimClass::AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay
|
||||||
coord = Adjust_Coord(coord);
|
coord = Adjust_Coord(coord);
|
||||||
Unlimbo(coord);
|
Unlimbo(coord);
|
||||||
|
|
||||||
VisibleFlags = 0xffff;
|
VisibleFlags = static_cast<unsigned int>(-1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Drop zone smoke always reveals the map around itself.
|
** Drop zone smoke always reveals the map around itself.
|
||||||
|
@ -751,6 +751,16 @@ void AnimClass::AI(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Lazy-initialize animation data (for loaded saves).
|
||||||
|
*/
|
||||||
|
if (Class->Stages == -1) {
|
||||||
|
((int&)Class->Stages) = Get_Build_Frame_Count(Class->Get_Image_Data());
|
||||||
|
}
|
||||||
|
if (Class->LoopEnd == -1) {
|
||||||
|
((int&)Class->LoopEnd) = Class->Stages;
|
||||||
|
}
|
||||||
|
|
||||||
if (Delay) {
|
if (Delay) {
|
||||||
Delay--;
|
Delay--;
|
||||||
if (!Delay) {
|
if (!Delay) {
|
||||||
|
@ -788,10 +798,10 @@ void AnimClass::AI(void)
|
||||||
int damage = accum >> 8;
|
int damage = accum >> 8;
|
||||||
if (Object->Take_Damage(damage, 0, WARHEAD_FIRE) == RESULT_DESTROYED) {
|
if (Object->Take_Damage(damage, 0, WARHEAD_FIRE) == RESULT_DESTROYED) {
|
||||||
//Object = 0;
|
//Object = 0;
|
||||||
Delete_This();
|
|
||||||
if (VirtualAnim != NULL) {
|
if (VirtualAnim != NULL) {
|
||||||
VirtualAnim->Delete_This();
|
VirtualAnim->Delete_This();
|
||||||
}
|
}
|
||||||
|
Delete_This();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1272,6 +1282,9 @@ void AnimClass::Detach(TARGET target, bool all)
|
||||||
if (all) {
|
if (all) {
|
||||||
if (VirtualAnim && VirtualAnim->As_Target() == target) {
|
if (VirtualAnim && VirtualAnim->As_Target() == target) {
|
||||||
VirtualAnim = NULL;
|
VirtualAnim = NULL;
|
||||||
|
if (IsInvisible) {
|
||||||
|
IsToDelete = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (Object && Object->As_Target() == target) {
|
if (Object && Object->As_Target() == target) {
|
||||||
Map.Remove(this, In_Which_Layer());
|
Map.Remove(this, In_Which_Layer());
|
||||||
|
|
|
@ -234,7 +234,7 @@ static BuildingTypeClass const ClassEye(
|
||||||
false, // Always use the given name for the building?
|
false, // Always use the given name for the building?
|
||||||
false, // Is this a wall type structure?
|
false, // Is this a wall type structure?
|
||||||
false, // Is it a factory type building?
|
false, // Is it a factory type building?
|
||||||
true, // Can this building be captured?
|
false, // Can this building be captured?
|
||||||
false, // Does it catch fire?
|
false, // Does it catch fire?
|
||||||
false, // Simple (one frame) damage imagery?
|
false, // Simple (one frame) damage imagery?
|
||||||
false, // Is it invisible to radar?
|
false, // Is it invisible to radar?
|
||||||
|
|
|
@ -213,7 +213,7 @@ RadioMessageType BuildingClass::Receive_Message(RadioClass * from, RadioMessageT
|
||||||
|
|
||||||
case RADIO_CAN_LOAD:
|
case RADIO_CAN_LOAD:
|
||||||
TechnoClass::Receive_Message(from, message, param);
|
TechnoClass::Receive_Message(from, message, param);
|
||||||
if (BState == BSTATE_CONSTRUCTION || (!ScenarioInit && In_Radio_Contact())) return(RADIO_NEGATIVE);
|
if (BState == BSTATE_CONSTRUCTION || (!ScenarioInit && Class->Type != STRUCT_REFINERY && In_Radio_Contact())) return(RADIO_NEGATIVE);
|
||||||
switch (Class->Type) {
|
switch (Class->Type) {
|
||||||
case STRUCT_AIRSTRIP:
|
case STRUCT_AIRSTRIP:
|
||||||
if (from->What_Am_I() == RTTI_AIRCRAFT && *((AircraftClass const *)from) == AIRCRAFT_CARGO) {
|
if (from->What_Am_I() == RTTI_AIRCRAFT && *((AircraftClass const *)from) == AIRCRAFT_CARGO) {
|
||||||
|
@ -238,7 +238,7 @@ RadioMessageType BuildingClass::Receive_Message(RadioClass * from, RadioMessageT
|
||||||
*((UnitClass *)from) == UNIT_HARVESTER &&
|
*((UnitClass *)from) == UNIT_HARVESTER &&
|
||||||
(ScenarioInit || !Is_Something_Attached())) {
|
(ScenarioInit || !Is_Something_Attached())) {
|
||||||
|
|
||||||
return(RADIO_ROGER);
|
return((Contact_With_Whom() != from) ? RADIO_ROGER : RADIO_NEGATIVE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1166,10 +1166,12 @@ void BuildingClass::AI(void)
|
||||||
Repair(1);
|
Repair(1);
|
||||||
} else {
|
} else {
|
||||||
if (IsTickedOff && (int)Scenario > 2 && Random_Pick(0, 50) < (int)Scenario && !Trigger) {
|
if (IsTickedOff && (int)Scenario > 2 && Random_Pick(0, 50) < (int)Scenario && !Trigger) {
|
||||||
|
if (GameToPlay != GAME_NORMAL || Scenario != 15 || PlayerPtr->ActLike != HOUSE_GOOD || *this != STRUCT_TEMPLE) {
|
||||||
Sell_Back(1);
|
Sell_Back(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Buildings that produce other objects have special factory logic handled here.
|
** Buildings that produce other objects have special factory logic handled here.
|
||||||
|
@ -2734,6 +2736,39 @@ bool BuildingClass::Limbo(void)
|
||||||
* HISTORY: *
|
* HISTORY: *
|
||||||
* 12/24/1994 JLB : Created. *
|
* 12/24/1994 JLB : Created. *
|
||||||
*=============================================================================================*/
|
*=============================================================================================*/
|
||||||
|
FireDataType BuildingClass::Fire_Data(int ) const
|
||||||
|
{
|
||||||
|
Validate();
|
||||||
|
COORDINATE coord = Center_Coord();
|
||||||
|
int dist = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Make adjustments to the firing coordinate to account for turret
|
||||||
|
** position. This depends on building type and turret facing.
|
||||||
|
*/
|
||||||
|
switch (Class->Type) {
|
||||||
|
default:
|
||||||
|
case STRUCT_GTOWER:
|
||||||
|
case STRUCT_ATOWER:
|
||||||
|
coord = Coord_Move(coord, DIR_N, 0x0030);
|
||||||
|
dist = 0x0040;
|
||||||
|
break;
|
||||||
|
case STRUCT_OBELISK:
|
||||||
|
coord = Coord_Move(coord, DIR_N, 0x00A8);
|
||||||
|
coord = Coord_Move(coord, DIR_W, 0x0018);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STRUCT_SAM:
|
||||||
|
case STRUCT_TURRET:
|
||||||
|
coord = Coord_Move(coord, DIR_N, 0x0030);
|
||||||
|
dist = 0x0080;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return{coord,dist};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
COORDINATE BuildingClass::Fire_Coord(int ) const
|
COORDINATE BuildingClass::Fire_Coord(int ) const
|
||||||
{
|
{
|
||||||
Validate();
|
Validate();
|
||||||
|
@ -3519,8 +3554,14 @@ bool BuildingClass::Toggle_Primary(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IsLeader = true;
|
IsLeader = true;
|
||||||
if (House == PlayerPtr) {
|
//
|
||||||
Speak(VOX_PRIMARY_SELECTED);
|
// MBL 07.22.2020 - Update so that each player in multiplayer will properly hear this when it applies to them
|
||||||
|
//
|
||||||
|
// if (House == PlayerPtr) {
|
||||||
|
// Speak(VOX_PRIMARY_SELECTED);
|
||||||
|
// }
|
||||||
|
if ((HouseClass *)House->IsHuman) {
|
||||||
|
Speak(VOX_PRIMARY_SELECTED, House);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Mark(MARK_CHANGE);
|
Mark(MARK_CHANGE);
|
||||||
|
@ -3832,14 +3873,14 @@ bool BuildingClass::Can_Demolish_Unit(void) const
|
||||||
bool BuildingClass::Can_Capture(void) const
|
bool BuildingClass::Can_Capture(void) const
|
||||||
{
|
{
|
||||||
bool can_capture = Class->IsCaptureable;
|
bool can_capture = Class->IsCaptureable;
|
||||||
if (*this == STRUCT_EYE) {
|
|
||||||
// Don't allow the Advanced Comm Center to be capturable in skirmish, MP, or beyond scenario 13 in SP
|
// Override capturable state if this building has a capture win trigger
|
||||||
if (GameToPlay == GAME_NORMAL) {
|
if (GameToPlay == GAME_NORMAL) {
|
||||||
can_capture &= Scenario < 13;
|
if (Trigger != NULL && Trigger->Action == TriggerClass::ACTION_WINLOSE) {
|
||||||
} else {
|
can_capture = true;
|
||||||
can_capture = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return(can_capture);
|
return(can_capture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4093,11 +4134,18 @@ int BuildingClass::Mission_Deconstruction(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MBL 07.10.2020 - In 1v1, sometimes both players will hear this SFX, or neither player will hear it
|
||||||
|
// Making it so all players hear it positionally in the map; Per thread discussion in https://jaas.ea.com/browse/TDRA-7245
|
||||||
|
//
|
||||||
|
#if 0
|
||||||
//Changed for multiplayer ST - 3/13/2019 5:31PM
|
//Changed for multiplayer ST - 3/13/2019 5:31PM
|
||||||
if (Is_Owned_By_Player()) {
|
if (Is_Owned_By_Player()) {
|
||||||
//if (IsOwnedByPlayer) {
|
//if (IsOwnedByPlayer) {
|
||||||
Sound_Effect(VOC_CASHTURN, Coord);
|
Sound_Effect(VOC_CASHTURN, Coord);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
Sound_Effect(VOC_CASHTURN, Coord);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Destroy all attached objects. ST - 4/24/2020 9:38PM
|
** Destroy all attached objects. ST - 4/24/2020 9:38PM
|
||||||
|
@ -4557,6 +4605,11 @@ int BuildingClass::Mission_Repair(void)
|
||||||
|
|
||||||
if (Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER) {
|
if (Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER) {
|
||||||
if (Contact_With_Whom()->Health_Ratio() < 0x0100 && Transmit_Message(RADIO_REPAIR) == RADIO_ROGER) {
|
if (Contact_With_Whom()->Health_Ratio() < 0x0100 && Transmit_Message(RADIO_REPAIR) == RADIO_ROGER) {
|
||||||
|
|
||||||
|
// MBL 07.06.2020 - Patch 3: Change to TD Legacy: Adding "Repairing" VO for units on repair bay
|
||||||
|
// Per https://jaas.ea.com/browse/TDRA-7271
|
||||||
|
if (IsOwnedByPlayer && House) Speak(VOX_REPAIRING, House);
|
||||||
|
|
||||||
Status = DURING;
|
Status = DURING;
|
||||||
Begin_Mode(BSTATE_ACTIVE);
|
Begin_Mode(BSTATE_ACTIVE);
|
||||||
IsReadyToCommence = false;
|
IsReadyToCommence = false;
|
||||||
|
|
|
@ -196,6 +196,7 @@ class BuildingClass : public TechnoClass
|
||||||
** combat purposes.
|
** combat purposes.
|
||||||
*/
|
*/
|
||||||
virtual COORDINATE Docking_Coord(void) const;
|
virtual COORDINATE Docking_Coord(void) const;
|
||||||
|
virtual FireDataType Fire_Data(int which) const;
|
||||||
virtual COORDINATE Fire_Coord(int which) const;
|
virtual COORDINATE Fire_Coord(int which) const;
|
||||||
virtual COORDINATE Center_Coord(void) const;
|
virtual COORDINATE Center_Coord(void) const;
|
||||||
virtual COORDINATE Sort_Y(void) const;
|
virtual COORDINATE Sort_Y(void) const;
|
||||||
|
|
|
@ -1824,7 +1824,7 @@ static TemplateTypeClass const Patch15(
|
||||||
"P15",
|
"P15",
|
||||||
TXT_PATCH,
|
TXT_PATCH,
|
||||||
LAND_CLEAR,
|
LAND_CLEAR,
|
||||||
1,1,
|
4,2,
|
||||||
LAND_CLEAR,
|
LAND_CLEAR,
|
||||||
NULL
|
NULL
|
||||||
);
|
);
|
||||||
|
|
|
@ -1936,7 +1936,7 @@ long CellClass::Tiberium_Adjust(bool pregame)
|
||||||
* 05/22/1995 JLB : Created. *
|
* 05/22/1995 JLB : Created. *
|
||||||
* 07/08/1995 JLB : Added a bunch of goodies to the crates. *
|
* 07/08/1995 JLB : Added a bunch of goodies to the crates. *
|
||||||
*=============================================================================================*/
|
*=============================================================================================*/
|
||||||
bool CellClass::Goodie_Check(FootClass * object)
|
bool CellClass::Goodie_Check(FootClass * object, bool check_steel)
|
||||||
{
|
{
|
||||||
Validate();
|
Validate();
|
||||||
enum {
|
enum {
|
||||||
|
@ -1990,6 +1990,8 @@ bool CellClass::Goodie_Check(FootClass * object)
|
||||||
bool steel = (Overlay == OVERLAY_STEEL_CRATE);
|
bool steel = (Overlay == OVERLAY_STEEL_CRATE);
|
||||||
COORDINATE coord; // Temporary working coordinate value.
|
COORDINATE coord; // Temporary working coordinate value.
|
||||||
|
|
||||||
|
if (check_steel && steel) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A triggered crate is automatically destroyed regardless of who or how
|
** A triggered crate is automatically destroyed regardless of who or how
|
||||||
** it was triggered.
|
** it was triggered.
|
||||||
|
@ -1998,13 +2000,20 @@ bool CellClass::Goodie_Check(FootClass * object)
|
||||||
Overlay = OVERLAY_NONE;
|
Overlay = OVERLAY_NONE;
|
||||||
OverlayData = 0;
|
OverlayData = 0;
|
||||||
|
|
||||||
if (steel) {
|
|
||||||
if (object->Owner() == HOUSE_BAD) {
|
if (object->Owner() == HOUSE_BAD) {
|
||||||
object->House->Add_Nuke_Piece();
|
object->House->Add_Nuke_Piece();
|
||||||
new AnimClass(ANIM_CRATE_EMPULSE, Cell_Coord());
|
new AnimClass(ANIM_CRATE_EMPULSE, Cell_Coord());
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else if(!check_steel && !steel) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
** A triggered crate is automatically destroyed regardless of who or how
|
||||||
|
** it was triggered.
|
||||||
|
*/
|
||||||
|
Redraw_Objects();
|
||||||
|
Overlay = OVERLAY_NONE;
|
||||||
|
OverlayData = 0;
|
||||||
|
|
||||||
int index;
|
int index;
|
||||||
UnitClass * unit = 0;
|
UnitClass * unit = 0;
|
||||||
|
@ -2428,10 +2437,19 @@ void CellClass::Flag_Create(void)
|
||||||
{
|
{
|
||||||
if (!CTFFlag) {
|
if (!CTFFlag) {
|
||||||
CTFFlag = new AnimClass(ANIM_FLAG, Cell_Coord(), 0, 1, true);
|
CTFFlag = new AnimClass(ANIM_FLAG, Cell_Coord(), 0, 1, true);
|
||||||
if (CTFFlag) {
|
if (CTFFlag == NULL) {
|
||||||
CTFFlag->OwnerHouse = Owner;
|
for (int i = 0; i < Anims.Count(); ++i) {
|
||||||
|
AnimClass* anim = Anims.Ptr(i);
|
||||||
|
if (*anim != ANIM_FLAG) {
|
||||||
|
anim->Delete_This();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CTFFlag = new AnimClass(ANIM_FLAG, Cell_Coord(), 0, 1, true);
|
||||||
|
}
|
||||||
|
assert(CTFFlag != NULL);
|
||||||
|
CTFFlag->OwnerHouse = Owner;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -208,7 +208,7 @@ class CellClass
|
||||||
InfantryClass * Cell_Infantry(void) const;
|
InfantryClass * Cell_Infantry(void) const;
|
||||||
TriggerClass * Get_Trigger(void) const;
|
TriggerClass * Get_Trigger(void) const;
|
||||||
int Clear_Icon(void) const;
|
int Clear_Icon(void) const;
|
||||||
bool Goodie_Check(FootClass * object);
|
bool Goodie_Check(FootClass * object, bool check_steel = false);
|
||||||
ObjectClass * Fetch_Occupier(void) const;
|
ObjectClass * Fetch_Occupier(void) const;
|
||||||
bool Get_Template_Info(char *template_name, int &icon, void *&image_data);
|
bool Get_Template_Info(char *template_name, int &icon, void *&image_data);
|
||||||
|
|
||||||
|
|
|
@ -2847,6 +2847,15 @@ typedef enum OptionControlType : char {
|
||||||
} OptionControlType;
|
} OptionControlType;
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
** Used to store firing data for a unit.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
COORDINATE Center;
|
||||||
|
int Distance;
|
||||||
|
} FireDataType;
|
||||||
|
|
||||||
|
|
||||||
#define TOTAL_CRATE_TYPES 15
|
#define TOTAL_CRATE_TYPES 15
|
||||||
|
|
||||||
#define size_of(typ,id) sizeof(((typ*)0)->id)
|
#define size_of(typ,id) sizeof(((typ*)0)->id)
|
||||||
|
|
|
@ -1810,8 +1810,9 @@ bool DisplayClass::Map_Cell(CELL cell, HouseClass * house, bool and_for_allies)
|
||||||
/*
|
/*
|
||||||
** Maybe also recurse to map for allies
|
** Maybe also recurse to map for allies
|
||||||
*/
|
*/
|
||||||
if (ShareAllyVisibility && and_for_allies && GameToPlay == GAME_GLYPHX_MULTIPLAYER) {
|
if (ShareAllyVisibility && and_for_allies) {
|
||||||
for (HousesType house_type = HOUSE_MULTI1; house_type < HOUSE_COUNT; house_type++) {
|
HousesType first_house = (GameToPlay == GAME_NORMAL) ? HOUSE_FIRST : HOUSE_MULTI1;
|
||||||
|
for (HousesType house_type = first_house; house_type < HOUSE_COUNT; house_type++) {
|
||||||
HouseClass *hptr = HouseClass::As_Pointer(house_type);
|
HouseClass *hptr = HouseClass::As_Pointer(house_type);
|
||||||
if (hptr && hptr->IsActive) {
|
if (hptr && hptr->IsActive) {
|
||||||
if (hptr != house && house->Is_Ally(hptr)) {
|
if (hptr != house && house->Is_Ally(hptr)) {
|
||||||
|
@ -3870,13 +3871,18 @@ void DisplayClass::Mouse_Left_Release(CELL cell, int x, int y, ObjectClass * obj
|
||||||
AllowVoice = true;
|
AllowVoice = true;
|
||||||
for (int index = 0; index < CurrentObject.Count(); index++) {
|
for (int index = 0; index < CurrentObject.Count(); index++) {
|
||||||
ObjectClass * tobject = CurrentObject[index];
|
ObjectClass * tobject = CurrentObject[index];
|
||||||
|
ActionType action = ACTION_NONE;
|
||||||
if (object) {
|
if (object) {
|
||||||
tobject->Active_Click_With(tobject->What_Action(object), object);
|
action = tobject->What_Action(object);
|
||||||
|
tobject->Active_Click_With(action, object);
|
||||||
} else {
|
} else {
|
||||||
tobject->Active_Click_With(tobject->What_Action(cell), cell);
|
action = tobject->What_Action(cell);
|
||||||
|
tobject->Active_Click_With(action, cell);
|
||||||
}
|
}
|
||||||
|
if (action != ACTION_NONE) {
|
||||||
AllowVoice = false;
|
AllowVoice = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
AllowVoice = true;
|
AllowVoice = true;
|
||||||
|
|
||||||
if (action == ACTION_REPAIR && object->What_Am_I() == RTTI_BUILDING) {
|
if (action == ACTION_REPAIR && object->What_Am_I() == RTTI_BUILDING) {
|
||||||
|
|
|
@ -672,6 +672,7 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Set_Multiplayer_Data(int scena
|
||||||
Special.IsVisceroids = game_options.SpawnVisceroids;
|
Special.IsVisceroids = game_options.SpawnVisceroids;
|
||||||
Special.IsCaptureTheFlag = game_options.CaptureTheFlag;
|
Special.IsCaptureTheFlag = game_options.CaptureTheFlag;
|
||||||
Special.IsEarlyWin = game_options.DestroyStructures;
|
Special.IsEarlyWin = game_options.DestroyStructures;
|
||||||
|
Special.ModernBalance = game_options.ModernBalance;
|
||||||
|
|
||||||
Rule.AllowSuperWeapons = game_options.EnableSuperweapons; // Are superweapons available
|
Rule.AllowSuperWeapons = game_options.EnableSuperweapons; // Are superweapons available
|
||||||
|
|
||||||
|
@ -1314,7 +1315,9 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Start_Custom_Instance(const ch
|
||||||
|
|
||||||
Clear_Scenario();
|
Clear_Scenario();
|
||||||
|
|
||||||
Read_Scenario_Ini_File(scenario_file_name, bin_file_name, scenario_name, true);
|
if (!Read_Scenario_Ini_File(scenario_file_name, bin_file_name, scenario_name, true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
HiddenPage.Clear();
|
HiddenPage.Clear();
|
||||||
VisiblePage.Clear();
|
VisiblePage.Clear();
|
||||||
|
@ -1696,6 +1699,12 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Save_Load(bool save, const cha
|
||||||
|
|
||||||
result = Load_Game(file_path_and_name);
|
result = Load_Game(file_path_and_name);
|
||||||
|
|
||||||
|
// MBL 07.21.2020
|
||||||
|
if (result == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
DLLExportClass::Set_Player_Context(DLLExportClass::GlyphxPlayerIDs[0], true);
|
DLLExportClass::Set_Player_Context(DLLExportClass::GlyphxPlayerIDs[0], true);
|
||||||
Set_Logic_Page(SeenBuff);
|
Set_Logic_Page(SeenBuff);
|
||||||
VisiblePage.Clear();
|
VisiblePage.Clear();
|
||||||
|
@ -2938,6 +2947,7 @@ void DLL_Draw_Line_Intercept(int x, int y, int x1, int y1, unsigned char color,
|
||||||
void DLLExportClass::DLL_Draw_Intercept(int shape_number, int x, int y, int width, int height, int flags, ObjectClass *object, const char *shape_file_name, char override_owner, int scale)
|
void DLLExportClass::DLL_Draw_Intercept(int shape_number, int x, int y, int width, int height, int flags, ObjectClass *object, const char *shape_file_name, char override_owner, int scale)
|
||||||
{
|
{
|
||||||
CNCObjectStruct& new_object = ObjectList->Objects[TotalObjectCount + CurrentDrawCount];
|
CNCObjectStruct& new_object = ObjectList->Objects[TotalObjectCount + CurrentDrawCount];
|
||||||
|
memset(&new_object, 0, sizeof(new_object));
|
||||||
Convert_Type(object, new_object);
|
Convert_Type(object, new_object);
|
||||||
if (new_object.Type == UNKNOWN) {
|
if (new_object.Type == UNKNOWN) {
|
||||||
return;
|
return;
|
||||||
|
@ -4013,6 +4023,8 @@ bool DLLExportClass::Get_Sidebar_State(uint64 player_id, unsigned char *buffer_i
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(&sidebar_entry, 0, sizeof(sidebar_entry));
|
||||||
|
|
||||||
sidebar_entry.AssetName[0] = 0;
|
sidebar_entry.AssetName[0] = 0;
|
||||||
sidebar_entry.Type = UNKNOWN;
|
sidebar_entry.Type = UNKNOWN;
|
||||||
sidebar_entry.BuildableID = Map.Column[c].Buildables[b].BuildableID;
|
sidebar_entry.BuildableID = Map.Column[c].Buildables[b].BuildableID;
|
||||||
|
@ -4191,6 +4203,8 @@ bool DLLExportClass::Get_Sidebar_State(uint64 player_id, unsigned char *buffer_i
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(&sidebar_entry, 0, sizeof(sidebar_entry));
|
||||||
|
|
||||||
sidebar_entry.AssetName[0] = 0;
|
sidebar_entry.AssetName[0] = 0;
|
||||||
sidebar_entry.Type = UNKNOWN;
|
sidebar_entry.Type = UNKNOWN;
|
||||||
sidebar_entry.BuildableID = context_sidebar->Column[c].Buildables[b].BuildableID;
|
sidebar_entry.BuildableID = context_sidebar->Column[c].Buildables[b].BuildableID;
|
||||||
|
@ -4352,6 +4366,8 @@ bool DLLExportClass::Get_Sidebar_State(uint64 player_id, unsigned char *buffer_i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const int _map_width_shift_bits = 6;
|
||||||
|
|
||||||
void DLLExportClass::Calculate_Placement_Distances(BuildingTypeClass* placement_type, unsigned char* placement_distance)
|
void DLLExportClass::Calculate_Placement_Distances(BuildingTypeClass* placement_type, unsigned char* placement_distance)
|
||||||
{
|
{
|
||||||
int map_cell_x = Map.MapCellX;
|
int map_cell_x = Map.MapCellX;
|
||||||
|
@ -4380,7 +4396,7 @@ void DLLExportClass::Calculate_Placement_Distances(BuildingTypeClass* placement_
|
||||||
memset(placement_distance, 255U, MAP_CELL_TOTAL);
|
memset(placement_distance, 255U, MAP_CELL_TOTAL);
|
||||||
for (int y = 0; y < map_cell_height; y++) {
|
for (int y = 0; y < map_cell_height; y++) {
|
||||||
for (int x = 0; x < map_cell_width; x++) {
|
for (int x = 0; x < map_cell_width; x++) {
|
||||||
CELL cell = (CELL)map_cell_x + x + ((map_cell_y + y) << 6);
|
CELL cell = (CELL)map_cell_x + x + ((map_cell_y + y) << _map_width_shift_bits);
|
||||||
BuildingClass* base = (BuildingClass*)Map[cell].Cell_Find_Object(RTTI_BUILDING);
|
BuildingClass* base = (BuildingClass*)Map[cell].Cell_Find_Object(RTTI_BUILDING);
|
||||||
if ((base && base->House->Class->House == PlayerPtr->Class->House) || (Map[cell].Owner == PlayerPtr->Class->House)) {
|
if ((base && base->House->Class->House == PlayerPtr->Class->House) || (Map[cell].Owner == PlayerPtr->Class->House)) {
|
||||||
placement_distance[cell] = 0U;
|
placement_distance[cell] = 0U;
|
||||||
|
@ -4471,7 +4487,7 @@ bool DLLExportClass::Get_Placement_State(uint64 player_id, unsigned char *buffer
|
||||||
for (int y=0 ; y < map_cell_height ; y++) {
|
for (int y=0 ; y < map_cell_height ; y++) {
|
||||||
for (int x=0 ; x < map_cell_width ; x++) {
|
for (int x=0 ; x < map_cell_width ; x++) {
|
||||||
|
|
||||||
CELL cell = (CELL) map_cell_x + x + ((map_cell_y + y) << 6);
|
CELL cell = (CELL) map_cell_x + x + ((map_cell_y + y) << _map_width_shift_bits);
|
||||||
|
|
||||||
bool pass = Passes_Proximity_Check(cell, PlacementType[CurrentLocalPlayerIndex], PlacementDistance[CurrentLocalPlayerIndex]);
|
bool pass = Passes_Proximity_Check(cell, PlacementType[CurrentLocalPlayerIndex], PlacementDistance[CurrentLocalPlayerIndex]);
|
||||||
|
|
||||||
|
@ -5132,7 +5148,7 @@ Map.Passes_Proximity_Check
|
||||||
map_cell_height++;
|
map_cell_height++;
|
||||||
}
|
}
|
||||||
|
|
||||||
CELL cell = (CELL) (map_cell_x + cell_x) + ( (map_cell_y + cell_y) << 6 );
|
CELL cell = (CELL) (map_cell_x + cell_x) + ( (map_cell_y + cell_y) << _map_width_shift_bits );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Call the place directly instead of queueing it, so we can evaluate the return code.
|
** Call the place directly instead of queueing it, so we can evaluate the return code.
|
||||||
|
@ -7503,10 +7519,18 @@ bool DLLExportClass::Save(FileClass & file)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Special case for Rule.AllowSuperWeapons - store negated value so it defaults to enabled
|
||||||
|
*/
|
||||||
|
bool not_allow_super_weapons = !Rule.AllowSuperWeapons;
|
||||||
|
if (file.Write(¬_allow_super_weapons, sizeof(not_allow_super_weapons)) != sizeof(not_allow_super_weapons)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Room for save game expansion
|
** Room for save game expansion
|
||||||
*/
|
*/
|
||||||
unsigned char padding[4096];
|
unsigned char padding[4095];
|
||||||
memset(padding, 0, sizeof(padding));
|
memset(padding, 0, sizeof(padding));
|
||||||
|
|
||||||
if (file.Write(padding, sizeof(padding)) != sizeof(padding)) {
|
if (file.Write(padding, sizeof(padding)) != sizeof(padding)) {
|
||||||
|
@ -7621,7 +7645,16 @@ bool DLLExportClass::Load(FileClass & file)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char padding[4096];
|
/*
|
||||||
|
** Special case for Rule.AllowSuperWeapons - store negated value so it defaults to enabled
|
||||||
|
*/
|
||||||
|
bool not_allow_super_weapons = false;
|
||||||
|
if (file.Read(¬_allow_super_weapons, sizeof(not_allow_super_weapons)) != sizeof(not_allow_super_weapons)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Rule.AllowSuperWeapons = !not_allow_super_weapons;
|
||||||
|
|
||||||
|
unsigned char padding[4095];
|
||||||
|
|
||||||
if (file.Read(padding, sizeof(padding)) != sizeof(padding)) {
|
if (file.Read(padding, sizeof(padding)) != sizeof(padding)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -728,7 +728,7 @@ struct CNCMultiplayerOptionsStruct {
|
||||||
int MPlayerCount; // # of human players in this game
|
int MPlayerCount; // # of human players in this game
|
||||||
int MPlayerBases; // 1 = bases are on for this scenario
|
int MPlayerBases; // 1 = bases are on for this scenario
|
||||||
int MPlayerCredits; // # credits everyone gets
|
int MPlayerCredits; // # credits everyone gets
|
||||||
int MPlayerTiberium; // 1 = tiberium enabled for this scenario
|
int MPlayerTiberium; // >0 = tiberium enabled for this scenario
|
||||||
int MPlayerGoodies; // 1 = goodies enabled for this scenario
|
int MPlayerGoodies; // 1 = goodies enabled for this scenario
|
||||||
int MPlayerGhosts; // 1 = houses with no players will still play
|
int MPlayerGhosts; // 1 = houses with no players will still play
|
||||||
int MPlayerSolo; // 1 = allows a single-player net game
|
int MPlayerSolo; // 1 = allows a single-player net game
|
||||||
|
@ -740,6 +740,7 @@ struct CNCMultiplayerOptionsStruct {
|
||||||
bool MPlayerAftermathUnits;
|
bool MPlayerAftermathUnits;
|
||||||
bool CaptureTheFlag;
|
bool CaptureTheFlag;
|
||||||
bool DestroyStructures; // New early win condition via destroying all a player's structures
|
bool DestroyStructures; // New early win condition via destroying all a player's structures
|
||||||
|
bool ModernBalance;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -962,9 +962,17 @@ bool DriveClass::Start_Of_Move(void)
|
||||||
/*
|
/*
|
||||||
** If a basic path could be found, but the immediate move destination is
|
** If a basic path could be found, but the immediate move destination is
|
||||||
** blocked by a friendly temporary blockage, then cause that blockage
|
** blocked by a friendly temporary blockage, then cause that blockage
|
||||||
** to scatter.
|
** to scatter. If the destination is also one cell away, then scatter
|
||||||
|
** regardless of direction.
|
||||||
*/
|
*/
|
||||||
CELL cell = Adjacent_Cell(Coord_Cell(Center_Coord()), PrimaryFacing.Current());
|
CELL ourcell = Coord_Cell(Center_Coord());
|
||||||
|
CELL navcell = As_Cell(NavCom);
|
||||||
|
CELL cell = -1;
|
||||||
|
if (::Distance(ourcell, navcell) < 2) {
|
||||||
|
cell = navcell;
|
||||||
|
} else {
|
||||||
|
cell = Adjacent_Cell(ourcell, PrimaryFacing.Current());
|
||||||
|
}
|
||||||
if (Map.In_Radar(cell)) {
|
if (Map.In_Radar(cell)) {
|
||||||
if (Can_Enter_Cell(cell) == MOVE_TEMP) {
|
if (Can_Enter_Cell(cell) == MOVE_TEMP) {
|
||||||
CellClass * cellptr = &Map[cell];
|
CellClass * cellptr = &Map[cell];
|
||||||
|
|
|
@ -509,7 +509,7 @@ CCDebugString ("C&C95 - Sell packet received\n");
|
||||||
//2019/09/19 JAS - Visibility needs to be determined per player
|
//2019/09/19 JAS - Visibility needs to be determined per player
|
||||||
if (Data.Anim.What != ANIM_MOVE_FLASH || Data.Anim.Owner == HOUSE_NONE || Special.IsVisibleTarget)
|
if (Data.Anim.What != ANIM_MOVE_FLASH || Data.Anim.Owner == HOUSE_NONE || Special.IsVisibleTarget)
|
||||||
{
|
{
|
||||||
anim->Set_Visible_Flags(0xffff);
|
anim->Set_Visible_Flags(static_cast<unsigned int>(-1));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -626,6 +626,12 @@ CCDebugString ("C&C95 - Primary building packet received\n");
|
||||||
techno->ArchiveTarget = Data.MegaMission.Target;
|
techno->ArchiveTarget = Data.MegaMission.Target;
|
||||||
techno->Assign_Target(TARGET_NONE);
|
techno->Assign_Target(TARGET_NONE);
|
||||||
techno->Assign_Destination(Data.MegaMission.Target);
|
techno->Assign_Destination(Data.MegaMission.Target);
|
||||||
|
} else if (Data.MegaMission.Mission == MISSION_ENTER &&
|
||||||
|
object != NULL &&
|
||||||
|
object->What_Am_I() == RTTI_BUILDING &&
|
||||||
|
*((BuildingClass*)object) == STRUCT_REFINERY) {
|
||||||
|
techno->Transmit_Message(RADIO_HELLO, (BuildingClass*)object);
|
||||||
|
techno->Assign_Destination(TARGET_NONE);
|
||||||
} else {
|
} else {
|
||||||
techno->Assign_Target(Data.MegaMission.Target);
|
techno->Assign_Target(Data.MegaMission.Target);
|
||||||
techno->Assign_Destination(Data.MegaMission.Destination);
|
techno->Assign_Destination(Data.MegaMission.Destination);
|
||||||
|
|
|
@ -1423,6 +1423,8 @@ void FootClass::Per_Cell_Process(bool center)
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
Map[Coord_Cell(Coord)].Goodie_Check(this, true);
|
||||||
|
|
||||||
TechnoClass::Per_Cell_Process(center);
|
TechnoClass::Per_Cell_Process(center);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1635,9 +1637,21 @@ int FootClass::Mission_Enter(void)
|
||||||
** Since there is no potential object to enter, then abort this
|
** Since there is no potential object to enter, then abort this
|
||||||
** mission with some default standby mission.
|
** mission with some default standby mission.
|
||||||
*/
|
*/
|
||||||
|
if (MissionQueue == MISSION_NONE) {
|
||||||
|
/*
|
||||||
|
** If this is a harvester, then return to harvesting.
|
||||||
|
** Set a hacky target so we know to skip to the proper state.
|
||||||
|
*/
|
||||||
|
if (What_Am_I() == RTTI_UNIT && ((UnitClass*)this)->Class->IsToHarvest) {
|
||||||
|
Assign_Mission(MISSION_HARVEST);
|
||||||
|
Assign_Target(As_Target());
|
||||||
|
Assign_Destination(TARGET_NONE);
|
||||||
|
} else {
|
||||||
ArchiveTarget = TARGET_NONE;
|
ArchiveTarget = TARGET_NONE;
|
||||||
Enter_Idle_Mode();
|
Enter_Idle_Mode();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return(TICKS_PER_SECOND/2);
|
return(TICKS_PER_SECOND/2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -569,16 +569,18 @@ bool HouseClass::Can_Build(TechnoTypeClass const * type, HousesType house) const
|
||||||
*/
|
*/
|
||||||
long flags = ActiveBScan;
|
long flags = ActiveBScan;
|
||||||
|
|
||||||
#ifdef USE_RA_AI
|
|
||||||
// OldBScan Copied from RA for AI. ST - 7/25/2019 3:27PM
|
|
||||||
/*
|
/*
|
||||||
** The computer records prerequisite buildings because it can't relay on the
|
** AI players update flags using building quantity tracker.
|
||||||
** sidebar to keep track of this information.
|
** Ensures consistent logic when determining building choices.
|
||||||
*/
|
*/
|
||||||
if (!IsHuman) {
|
if (!IsHuman) {
|
||||||
flags = OldBScan;
|
flags = 0;
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
if (BQuantity[i] > 0) {
|
||||||
|
flags |= (1 << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
int pre = type->Pre;
|
int pre = type->Pre;
|
||||||
if (flags & STRUCTF_ADVANCED_POWER) flags |= STRUCTF_POWER;
|
if (flags & STRUCTF_ADVANCED_POWER) flags |= STRUCTF_POWER;
|
||||||
|
@ -972,6 +974,12 @@ void HouseClass::AI(void)
|
||||||
if (IsToDie && BorrowedTime.Expired()) {
|
if (IsToDie && BorrowedTime.Expired()) {
|
||||||
IsToDie = false;
|
IsToDie = false;
|
||||||
Blowup_All();
|
Blowup_All();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1424,7 +1432,7 @@ void HouseClass::AI(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (GameToPlay != GAME_NORMAL) {
|
if (GameToPlay != GAME_NORMAL && Class->House != HOUSE_JP) {
|
||||||
Check_Pertinent_Structures();
|
Check_Pertinent_Structures();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1664,8 +1672,15 @@ void HouseClass::AI(void)
|
||||||
void HouseClass::Attacked(BuildingClass* source)
|
void HouseClass::Attacked(BuildingClass* source)
|
||||||
{
|
{
|
||||||
Validate();
|
Validate();
|
||||||
if (SpeakAttackDelay.Expired() && PlayerPtr->Class->House == Class->House) {
|
|
||||||
|
bool expired = SpeakAttackDelay.Expired();
|
||||||
|
bool spoke = false;
|
||||||
|
|
||||||
|
// if (SpeakAttackDelay.Expired() && PlayerPtr->Class->House == Class->House) {
|
||||||
|
if (expired && PlayerPtr->Class->House == Class->House) {
|
||||||
|
|
||||||
Speak(VOX_BASE_UNDER_ATTACK, NULL, source ? source->Center_Coord() : 0);
|
Speak(VOX_BASE_UNDER_ATTACK, NULL, source ? source->Center_Coord() : 0);
|
||||||
|
spoke = true;
|
||||||
|
|
||||||
// MBL 06.13.2020 - Timing change from 2 minute cooldown, per https://jaas.ea.com/browse/TDRA-6784
|
// 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(SPEAK_DELAY)); // 2 minutes
|
||||||
|
@ -1680,6 +1695,23 @@ void HouseClass::Attacked(BuildingClass* source)
|
||||||
HouseTriggers[Class->House][index]->Spring(EVENT_ATTACKED, Class->House);
|
HouseTriggers[Class->House][index]->Spring(EVENT_ATTACKED, Class->House);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4051,6 +4083,13 @@ void HouseClass::MPlayer_Defeated(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Remove any one-time superweapons the player might have.
|
||||||
|
*/
|
||||||
|
IonCannon.Remove(true);
|
||||||
|
AirStrike.Remove(true);
|
||||||
|
NukeStrike.Remove(true);
|
||||||
|
|
||||||
/*------------------------------------------------------------------------
|
/*------------------------------------------------------------------------
|
||||||
If this is me:
|
If this is me:
|
||||||
- Set MPlayerObiWan, so I can only send messages to all players, and
|
- Set MPlayerObiWan, so I can only send messages to all players, and
|
||||||
|
@ -4784,6 +4823,13 @@ void HouseClass::Check_Pertinent_Structures(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
bool any_good_buildings = false;
|
bool any_good_buildings = false;
|
||||||
|
|
||||||
for (int index = 0; index < Buildings.Count(); index++) {
|
for (int index = 0; index < Buildings.Count(); index++) {
|
||||||
|
|
|
@ -430,7 +430,7 @@ static InfantryTypeClass const E5(
|
||||||
70, // Strength of infantry (in damage points).
|
70, // Strength of infantry (in damage points).
|
||||||
1, // Sight range.
|
1, // Sight range.
|
||||||
300, // Cost of infantry (in credits).
|
300, // Cost of infantry (in credits).
|
||||||
99, // Scenario when they first appear.
|
98, // Scenario when they first appear.
|
||||||
80,10, // Risk/Reward of this infantry unit.
|
80,10, // Risk/Reward of this infantry unit.
|
||||||
HOUSEF_MULTI1|
|
HOUSEF_MULTI1|
|
||||||
HOUSEF_MULTI2|
|
HOUSEF_MULTI2|
|
||||||
|
|
|
@ -882,7 +882,7 @@ void InfantryClass::Look(bool incremental)
|
||||||
|
|
||||||
if (!IsInLimbo) {
|
if (!IsInLimbo) {
|
||||||
//if (IsOwnedByPlayer) { // Changed for multiple player mapping. ST - 3/6/2019 1:27PM
|
//if (IsOwnedByPlayer) { // Changed for multiple player mapping. ST - 3/6/2019 1:27PM
|
||||||
if (House->IsHuman) {
|
if (House->IsHuman || GameToPlay != GAME_NORMAL) {
|
||||||
sight = Class->SightRange;
|
sight = Class->SightRange;
|
||||||
|
|
||||||
if (sight) {
|
if (sight) {
|
||||||
|
@ -1098,7 +1098,14 @@ void InfantryClass::AI(void)
|
||||||
** run in circles, scream, and shout.
|
** run in circles, scream, and shout.
|
||||||
*/
|
*/
|
||||||
if (Class->IsFraidyCat && Fear > FEAR_ANXIOUS && !IsDriving && !Target_Legal(NavCom)) {
|
if (Class->IsFraidyCat && Fear > FEAR_ANXIOUS && !IsDriving && !Target_Legal(NavCom)) {
|
||||||
Scatter(true);
|
Scatter(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Scatter infantry off buildings in guard modes.
|
||||||
|
*/
|
||||||
|
if (!IsTethered && !IsFiring && !IsDriving && !IsRotating && (Mission == MISSION_GUARD || Mission == MISSION_GUARD_AREA) && MissionQueue == MISSION_NONE && Map[Coord_Cell(Coord)].Cell_Building() != NULL) {
|
||||||
|
Scatter(0, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1659,7 +1666,7 @@ MoveType InfantryClass::Can_Enter_Cell(CELL cell, FacingType ) const
|
||||||
** Cloaked enemy objects are not considered if this is a Find_Path()
|
** Cloaked enemy objects are not considered if this is a Find_Path()
|
||||||
** call.
|
** call.
|
||||||
*/
|
*/
|
||||||
if (!obj->Is_Techno() || ((TechnoClass *)obj)->Cloak != CLOAKED) {
|
if (!obj->Is_Techno() || !((TechnoClass *)obj)->Is_Cloaked(this)) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Any non-allied blockage is considered impassible if the infantry
|
** Any non-allied blockage is considered impassible if the infantry
|
||||||
|
@ -2447,7 +2454,8 @@ bool InfantryClass::Unlimbo(COORDINATE coord, DirType facing)
|
||||||
** If there is no sight range, then this object isn't discovered by the player unless
|
** If there is no sight range, then this object isn't discovered by the player unless
|
||||||
** it actually appears in a cell mapped by the player.
|
** it actually appears in a cell mapped by the player.
|
||||||
*/
|
*/
|
||||||
if (Class->SightRange == 0) {
|
if (Class->SightRange == 0 && GameToPlay == GAME_NORMAL && !House->IsHuman && !Map[Coord_Cell(coord)].Is_Visible(PlayerPtr)) {
|
||||||
|
IsDiscoveredByPlayerMask &= ~(1 << (int)PlayerPtr->Class->House);
|
||||||
IsDiscoveredByPlayer = false;
|
IsDiscoveredByPlayer = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -321,6 +321,9 @@ bool Read_Scenario_Ini(char *root, bool fresh)
|
||||||
#ifdef NEWMENU
|
#ifdef NEWMENU
|
||||||
if (Scenario <= 15) {
|
if (Scenario <= 15) {
|
||||||
BuildLevel = Scenario;
|
BuildLevel = Scenario;
|
||||||
|
} else if (_stricmp(ScenarioName, "scg30ea") == 0 || _stricmp(ScenarioName, "scg90ea") == 0 || _stricmp(ScenarioName, "scb22ea") == 0) {
|
||||||
|
// N64 missions require build level 15
|
||||||
|
BuildLevel = 15;
|
||||||
} else {
|
} else {
|
||||||
BuildLevel = WWGetPrivateProfileInt("Basic", "BuildLevel", Scenario, buffer);
|
BuildLevel = WWGetPrivateProfileInt("Basic", "BuildLevel", Scenario, buffer);
|
||||||
}
|
}
|
||||||
|
@ -444,6 +447,9 @@ bool Read_Scenario_Ini(char *root, bool fresh)
|
||||||
UnitClass::Read_INI(buffer);
|
UnitClass::Read_INI(buffer);
|
||||||
Call_Back();
|
Call_Back();
|
||||||
|
|
||||||
|
AircraftClass::Read_INI(buffer);
|
||||||
|
Call_Back();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Read in and place the infantry units (all sides).
|
** Read in and place the infantry units (all sides).
|
||||||
*/
|
*/
|
||||||
|
@ -534,6 +540,8 @@ bool Read_Scenario_Ini(char *root, bool fresh)
|
||||||
** NOD7A cell 2795 - LAND_ROCK
|
** NOD7A cell 2795 - LAND_ROCK
|
||||||
** NOD09A - delete airstrike trigger when radar destroyed
|
** NOD09A - delete airstrike trigger when radar destroyed
|
||||||
** NOD10B cell 2015 - LAND_ROCK
|
** NOD10B cell 2015 - LAND_ROCK
|
||||||
|
** NOD13B - trigger AI production when the player reaches the transports
|
||||||
|
** NOD13C - delete airstrike trigger when radar destroyed
|
||||||
*/
|
*/
|
||||||
if (_stricmp(ScenarioName, "scb07ea") == 0) {
|
if (_stricmp(ScenarioName, "scb07ea") == 0) {
|
||||||
Map[(CELL)2795].Override_Land_Type(LAND_ROCK);
|
Map[(CELL)2795].Override_Land_Type(LAND_ROCK);
|
||||||
|
@ -553,6 +561,30 @@ bool Read_Scenario_Ini(char *root, bool fresh)
|
||||||
if (_stricmp(ScenarioName, "scb10eb") == 0) {
|
if (_stricmp(ScenarioName, "scb10eb") == 0) {
|
||||||
Map[(CELL)2015].Override_Land_Type(LAND_ROCK);
|
Map[(CELL)2015].Override_Land_Type(LAND_ROCK);
|
||||||
}
|
}
|
||||||
|
if (_stricmp(ScenarioName, "scb13eb") == 0) {
|
||||||
|
TriggerClass* prod = new TriggerClass();
|
||||||
|
prod->Set_Name("prod");
|
||||||
|
prod->Event = EVENT_PLAYER_ENTERED;
|
||||||
|
prod->Action = TriggerClass::ACTION_BEGIN_PRODUCTION;
|
||||||
|
prod->House = HOUSE_BAD;
|
||||||
|
|
||||||
|
CellTriggers[276] = prod; prod->AttachCount++;
|
||||||
|
CellTriggers[340] = prod; prod->AttachCount++;
|
||||||
|
CellTriggers[404] = prod; prod->AttachCount++;
|
||||||
|
CellTriggers[468] = prod; prod->AttachCount++;
|
||||||
|
}
|
||||||
|
if (_stricmp(ScenarioName, "scb13ec") == 0) {
|
||||||
|
for (int index = 0; index < Buildings.Count(); ++index) {
|
||||||
|
BuildingClass* building = Buildings.Ptr(index);
|
||||||
|
if (building != NULL && building->Owner() == HOUSE_GOOD && *building == STRUCT_RADAR && building->Trigger == NULL) {
|
||||||
|
building->Trigger = TriggerClass::As_Pointer("delx");
|
||||||
|
if (building->Trigger) {
|
||||||
|
building->Trigger->AttachCount++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Scenario fix-up (applied on loaded games as well)
|
** Scenario fix-up (applied on loaded games as well)
|
||||||
|
@ -844,6 +876,9 @@ bool Read_Scenario_Ini_File(char *scenario_file_name, char* bin_file_name, const
|
||||||
UnitClass::Read_INI(buffer);
|
UnitClass::Read_INI(buffer);
|
||||||
Call_Back();
|
Call_Back();
|
||||||
|
|
||||||
|
AircraftClass::Read_INI(buffer);
|
||||||
|
Call_Back();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Read in and place the infantry units (all sides).
|
** Read in and place the infantry units (all sides).
|
||||||
*/
|
*/
|
||||||
|
@ -929,6 +964,11 @@ bool Read_Scenario_Ini_File(char *scenario_file_name, char* bin_file_name, const
|
||||||
Map.Overpass();
|
Map.Overpass();
|
||||||
Call_Back();
|
Call_Back();
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Scenario fix-up (applied on loaded games as well)
|
||||||
|
*/
|
||||||
|
Fixup_Scenario();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Multi-player last-minute fixups:
|
** Multi-player last-minute fixups:
|
||||||
** - If computer players are disabled, remove all computer-owned houses
|
** - If computer players are disabled, remove all computer-owned houses
|
||||||
|
|
|
@ -190,6 +190,7 @@ void LogicClass::AI(void)
|
||||||
*/
|
*/
|
||||||
for (index = 0; index < Count(); index++) {
|
for (index = 0; index < Count(); index++) {
|
||||||
ObjectClass * obj = (*this)[index];
|
ObjectClass * obj = (*this)[index];
|
||||||
|
int count = Count();
|
||||||
|
|
||||||
obj->AI();
|
obj->AI();
|
||||||
|
|
||||||
|
@ -197,9 +198,9 @@ void LogicClass::AI(void)
|
||||||
** If the object was destroyed in the process of performing its AI, then
|
** If the object was destroyed in the process of performing its AI, then
|
||||||
** adjust the index so that no object gets skipped.
|
** adjust the index so that no object gets skipped.
|
||||||
*/
|
*/
|
||||||
if (obj != (*this)[index]) {
|
int count_diff = Count() - count;
|
||||||
// if (!obj->IsActive) {
|
if (count_diff < 0) {
|
||||||
index--;
|
index += count_diff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -362,12 +362,10 @@ void MapClass::Sight_From(HouseClass *house, CELL cell, int sightrange, bool inc
|
||||||
** adjacent cells as well. For full scans, just update
|
** adjacent cells as well. For full scans, just update
|
||||||
** the cell itself.
|
** the cell itself.
|
||||||
*/
|
*/
|
||||||
if (!(*this)[newcell].Is_Mapped(house)) {
|
|
||||||
// Pass the house through, instead of assuming it's the local player. ST - 3/6/2019 10:26AM
|
// Pass the house through, instead of assuming it's the local player. ST - 3/6/2019 10:26AM
|
||||||
//Map.Map_Cell(newcell, PlayerPtr);
|
//Map.Map_Cell(newcell, PlayerPtr);
|
||||||
Map.Map_Cell(newcell, house, true);
|
Map.Map_Cell(newcell, house, true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -950,6 +948,15 @@ void MapClass::Logic(void)
|
||||||
if (TiberiumScan >= MAP_CELL_TOTAL) {
|
if (TiberiumScan >= MAP_CELL_TOTAL) {
|
||||||
int tries = 1;
|
int tries = 1;
|
||||||
if (Special.IsTFast || GameToPlay != GAME_NORMAL) tries = 2;
|
if (Special.IsTFast || GameToPlay != GAME_NORMAL) tries = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Use the Tiberium setting as a multiplier on growth rate. ST - 7/1/2020 3:05PM
|
||||||
|
*/
|
||||||
|
if (GameToPlay == GAME_GLYPHX_MULTIPLAYER) {
|
||||||
|
if (MPlayerTiberium > 1) {
|
||||||
|
tries += (MPlayerTiberium - 1) << 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
TiberiumScan = 0;
|
TiberiumScan = 0;
|
||||||
IsForwardScan = (IsForwardScan == false);
|
IsForwardScan = (IsForwardScan == false);
|
||||||
|
|
||||||
|
@ -958,11 +965,17 @@ void MapClass::Logic(void)
|
||||||
*/
|
*/
|
||||||
if (TiberiumGrowthCount) {
|
if (TiberiumGrowthCount) {
|
||||||
for (int i = 0; i < tries; i++) {
|
for (int i = 0; i < tries; i++) {
|
||||||
CELL cell = TiberiumGrowth[Random_Pick(0, TiberiumGrowthCount-1)];
|
int pick = Random_Pick(0, TiberiumGrowthCount-1);
|
||||||
|
CELL cell = TiberiumGrowth[pick];
|
||||||
CellClass * newcell = &(*this)[cell];
|
CellClass * newcell = &(*this)[cell];
|
||||||
if (newcell->Land_Type() == LAND_TIBERIUM && newcell->OverlayData < 12-1) {
|
if (newcell->Land_Type() == LAND_TIBERIUM && newcell->OverlayData < 12-1) {
|
||||||
newcell->OverlayData++;
|
newcell->OverlayData++;
|
||||||
}
|
}
|
||||||
|
TiberiumGrowth[pick] = TiberiumGrowth[TiberiumGrowthCount - 1];
|
||||||
|
TiberiumGrowthCount--;
|
||||||
|
if (TiberiumGrowthCount <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TiberiumGrowthCount = 0;
|
TiberiumGrowthCount = 0;
|
||||||
|
@ -972,7 +985,8 @@ void MapClass::Logic(void)
|
||||||
*/
|
*/
|
||||||
if (TiberiumSpreadCount) {
|
if (TiberiumSpreadCount) {
|
||||||
for (int i = 0; i < tries; i++) {
|
for (int i = 0; i < tries; i++) {
|
||||||
CELL cell = TiberiumSpread[Random_Pick(0, TiberiumSpreadCount-1)];
|
int pick = Random_Pick(0, TiberiumSpreadCount-1);
|
||||||
|
CELL cell = TiberiumSpread[pick];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Find a pseudo-random adjacent cell that doesn't contain any tiberium.
|
** Find a pseudo-random adjacent cell that doesn't contain any tiberium.
|
||||||
|
@ -1003,6 +1017,11 @@ void MapClass::Logic(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TiberiumSpread[pick] = TiberiumSpread[TiberiumSpreadCount - 1];
|
||||||
|
TiberiumSpreadCount--;
|
||||||
|
if (TiberiumSpreadCount <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TiberiumSpreadCount = 0;
|
TiberiumSpreadCount = 0;
|
||||||
|
@ -1400,10 +1419,10 @@ ObjectClass * MapClass::Close_Object(COORDINATE coord) const
|
||||||
while (o) {
|
while (o) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Special case check to ignore cloaked object if not owned by the player.
|
** Special case check to ignore cloaked object if not allied with the player.
|
||||||
*/
|
*/
|
||||||
// Changed for multiplayer. ST - 3/13/2019 5:38PM
|
// Changed for multiplayer. ST - 3/13/2019 5:38PM
|
||||||
if (!o->Is_Techno() || ((TechnoClass *)o)->Is_Owned_By_Player() || ((TechnoClass *)o)->Cloak != CLOAKED) {
|
if (!o->Is_Techno() || !((TechnoClass *)o)->Is_Cloaked(PlayerPtr)) {
|
||||||
//if (!o->Is_Techno() || ((TechnoClass *)o)->IsOwnedByPlayer || ((TechnoClass *)o)->Cloak != CLOAKED) {
|
//if (!o->Is_Techno() || ((TechnoClass *)o)->IsOwnedByPlayer || ((TechnoClass *)o)->Cloak != CLOAKED) {
|
||||||
int d=-1;
|
int d=-1;
|
||||||
if (o->What_Am_I() == RTTI_BUILDING) {
|
if (o->What_Am_I() == RTTI_BUILDING) {
|
||||||
|
@ -1429,7 +1448,7 @@ ObjectClass * MapClass::Close_Object(COORDINATE coord) const
|
||||||
AircraftClass * aircraft = Aircraft.Ptr(index);
|
AircraftClass * aircraft = Aircraft.Ptr(index);
|
||||||
|
|
||||||
if (aircraft->In_Which_Layer() != LAYER_GROUND) {
|
if (aircraft->In_Which_Layer() != LAYER_GROUND) {
|
||||||
if (aircraft->Is_Owned_By_Player() || (aircraft->Cloak != CLOAKED)) {
|
if (!aircraft->Is_Cloaked(PlayerPtr)) {
|
||||||
int d = Distance(coord, Coord_Add(aircraft->Center_Coord(), XY_Coord(0, -Pixel_To_Lepton(aircraft->Altitude))));
|
int d = Distance(coord, Coord_Add(aircraft->Center_Coord(), XY_Coord(0, -Pixel_To_Lepton(aircraft->Altitude))));
|
||||||
if (d >= 0 && (!object || d < distance)) {
|
if (d >= 0 && (!object || d < distance)) {
|
||||||
distance = d;
|
distance = d;
|
||||||
|
|
|
@ -428,7 +428,7 @@ dxisbig:
|
||||||
#if (0)
|
#if (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/MiscAsm.cpp#57 $
|
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/MiscAsm.cpp#95 $
|
||||||
;***************************************************************************
|
;***************************************************************************
|
||||||
;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
|
;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
|
||||||
;***************************************************************************
|
;***************************************************************************
|
||||||
|
|
|
@ -564,6 +564,7 @@ COORDINATE ObjectClass::Center_Coord(void) const {return Coord;};
|
||||||
COORDINATE ObjectClass::Render_Coord(void) const {return(Center_Coord());}
|
COORDINATE ObjectClass::Render_Coord(void) const {return(Center_Coord());}
|
||||||
COORDINATE ObjectClass::Docking_Coord(void) const {return(Center_Coord());}
|
COORDINATE ObjectClass::Docking_Coord(void) const {return(Center_Coord());}
|
||||||
COORDINATE ObjectClass::Sort_Y(void) const {return Coord;};
|
COORDINATE ObjectClass::Sort_Y(void) const {return Coord;};
|
||||||
|
FireDataType ObjectClass::Fire_Data(int which) const {return{Fire_Coord(which),0};}
|
||||||
COORDINATE ObjectClass::Fire_Coord(int ) const {return Coord;};
|
COORDINATE ObjectClass::Fire_Coord(int ) const {return Coord;};
|
||||||
void ObjectClass::Record_The_Kill(TechnoClass * ) {};
|
void ObjectClass::Record_The_Kill(TechnoClass * ) {};
|
||||||
void ObjectClass::Do_Shimmer(void) {};
|
void ObjectClass::Do_Shimmer(void) {};
|
||||||
|
|
|
@ -172,6 +172,7 @@ class ObjectClass : public AbstractClass
|
||||||
virtual COORDINATE Center_Coord(void) const;
|
virtual COORDINATE Center_Coord(void) const;
|
||||||
virtual COORDINATE Render_Coord(void) const;
|
virtual COORDINATE Render_Coord(void) const;
|
||||||
virtual COORDINATE Sort_Y(void) const;
|
virtual COORDINATE Sort_Y(void) const;
|
||||||
|
virtual FireDataType Fire_Data(int) const;
|
||||||
virtual COORDINATE Fire_Coord(int ) const;
|
virtual COORDINATE Fire_Coord(int ) const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -235,7 +235,7 @@ bool RadarClass::Radar_Activate(int control)
|
||||||
case 0:
|
case 0:
|
||||||
if (Map.IsSidebarActive) {
|
if (Map.IsSidebarActive) {
|
||||||
if (IsRadarActive && !IsRadarDeactivating) {
|
if (IsRadarActive && !IsRadarDeactivating) {
|
||||||
Sound_Effect(VOC_RADAR_OFF);
|
// Sound_Effect(VOC_RADAR_OFF); // MBL 07.20.2020: These are never being sent to the client, so handled there; Disabling here for good measure.
|
||||||
IsRadarDeactivating = true;
|
IsRadarDeactivating = true;
|
||||||
IsRadarActive = false;
|
IsRadarActive = false;
|
||||||
if (IsRadarActivating == true) {
|
if (IsRadarActivating == true) {
|
||||||
|
@ -252,7 +252,7 @@ bool RadarClass::Radar_Activate(int control)
|
||||||
case 1:
|
case 1:
|
||||||
if (Map.IsSidebarActive) {
|
if (Map.IsSidebarActive) {
|
||||||
if (!IsRadarActivating && !IsRadarActive) {
|
if (!IsRadarActivating && !IsRadarActive) {
|
||||||
Sound_Effect(VOC_RADAR_ON);
|
// Sound_Effect(VOC_RADAR_ON); // MBL 07.20.2020: These are never being sent to the client, so handled there; Disabling here for good measure.
|
||||||
IsRadarActivating = true;
|
IsRadarActivating = true;
|
||||||
if (IsRadarDeactivating == true) {
|
if (IsRadarDeactivating == true) {
|
||||||
IsRadarDeactivating = false;
|
IsRadarDeactivating = false;
|
||||||
|
|
|
@ -338,6 +338,7 @@ bool Do_Reinforcements(TeamTypeClass *teamtype)
|
||||||
*/
|
*/
|
||||||
case SOURCE_AIR: {
|
case SOURCE_AIR: {
|
||||||
AircraftClass * thisone = (AircraftClass *)object;
|
AircraftClass * thisone = (AircraftClass *)object;
|
||||||
|
TARGET target = TARGET_NONE;
|
||||||
while (thisone) {
|
while (thisone) {
|
||||||
AircraftClass * next = (AircraftClass *)thisone->Next;
|
AircraftClass * next = (AircraftClass *)thisone->Next;
|
||||||
|
|
||||||
|
@ -345,25 +346,57 @@ bool Do_Reinforcements(TeamTypeClass *teamtype)
|
||||||
** Find a suitable map entry location. Cargo planes will try to find a cell that
|
** Find a suitable map entry location. Cargo planes will try to find a cell that
|
||||||
** exactly lines up with the airfield they will unload at.
|
** exactly lines up with the airfield they will unload at.
|
||||||
*/
|
*/
|
||||||
CELL newcell;
|
COORDINATE newcoord;
|
||||||
|
long reinforcement_delay = -1;
|
||||||
ScenarioInit++;
|
ScenarioInit++;
|
||||||
newcell = Map.Calculated_Cell(HouseClass::As_Pointer(teamtype->House)->Edge, teamtype->House);
|
newcoord = Cell_Coord(Map.Calculated_Cell(HouseClass::As_Pointer(teamtype->House)->Edge, teamtype->House));
|
||||||
ScenarioInit--;
|
ScenarioInit--;
|
||||||
if (*thisone == AIRCRAFT_CARGO) {
|
if (*thisone == AIRCRAFT_CARGO) {
|
||||||
BuildingClass const * building = thisone->Find_Docking_Bay(STRUCT_AIRSTRIP, false);
|
BuildingClass const * building = thisone->Find_Docking_Bay(STRUCT_AIRSTRIP, false);
|
||||||
if (building) {
|
if (building) {
|
||||||
newcell = XY_Cell(Map.MapCellX+Map.MapCellWidth, Coord_YCell(building->Docking_Coord()+2));
|
COORDINATE docking_coord = building->Docking_Coord();
|
||||||
|
const int border_x = Cell_To_Lepton(Map.MapCellX + Map.MapCellWidth) | 0x80;
|
||||||
|
if (Special.ModernBalance) {
|
||||||
|
/*
|
||||||
|
** Cargo plane takes 5 seconds to reach the airstrip on Normal (1.5x legacy), or (75 / 10) seconds at speed.
|
||||||
|
** Assumes a 45ms (1000 / 45 ticks per second) service rate.
|
||||||
|
*/
|
||||||
|
const int speed = AircraftTypeClass::As_Reference(AIRCRAFT_CARGO).MaxSpeed;
|
||||||
|
int spawn_x = Coord_X(docking_coord) + ((speed * 1000 * 75) / (45 * 10));
|
||||||
|
if (spawn_x > border_x) {
|
||||||
|
reinforcement_delay = (spawn_x - border_x) / speed;
|
||||||
|
spawn_x = border_x;
|
||||||
|
}
|
||||||
|
newcoord = XY_Coord(spawn_x, Coord_Y(docking_coord));
|
||||||
|
} else {
|
||||||
|
newcoord = XY_Coord(border_x, Coord_Y(docking_coord));
|
||||||
|
}
|
||||||
|
if (teamtype->MissionCount) {
|
||||||
|
teamtype->MissionList[0].Argument = building->As_Target();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thisone->Next = 0;
|
thisone->Next = 0;
|
||||||
|
|
||||||
ScenarioInit++;
|
ScenarioInit++;
|
||||||
placed = thisone->Unlimbo(Cell_Coord(newcell), DIR_W);
|
placed = thisone->Unlimbo(newcoord, DIR_W);
|
||||||
|
if (Special.ModernBalance && reinforcement_delay >= 0) {
|
||||||
|
thisone->Set_Reinforcement_Delay(reinforcement_delay);
|
||||||
|
}
|
||||||
ScenarioInit--;
|
ScenarioInit--;
|
||||||
if (placed) {
|
if (placed) {
|
||||||
if (!team) {
|
if (!team) {
|
||||||
if (thisone->Class->IsFixedWing) {
|
if (thisone->Class->IsFixedWing) {
|
||||||
thisone->Assign_Mission(MISSION_HUNT);
|
thisone->Assign_Mission(MISSION_HUNT);
|
||||||
|
if (*thisone == AIRCRAFT_A10) {
|
||||||
|
/*
|
||||||
|
** Groups of A10s always go after the same target initally.
|
||||||
|
*/
|
||||||
|
if (target == TARGET_NONE) {
|
||||||
|
target = thisone->Greatest_Threat(THREAT_NORMAL);
|
||||||
|
}
|
||||||
|
thisone->Assign_Target(target);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (thisone->Class->IsTransporter && thisone->Is_Something_Attached()) {
|
if (thisone->Class->IsTransporter && thisone->Is_Something_Attached()) {
|
||||||
thisone->Assign_Mission(MISSION_UNLOAD);
|
thisone->Assign_Mission(MISSION_UNLOAD);
|
||||||
|
|
|
@ -799,4 +799,22 @@ void Fixup_Scenario(void)
|
||||||
} else {
|
} else {
|
||||||
((AircraftTypeClass&)AircraftTypeClass::As_Reference(AIRCRAFT_ORCA)).Primary = WEAPON_DRAGON;
|
((AircraftTypeClass&)AircraftTypeClass::As_Reference(AIRCRAFT_ORCA)).Primary = WEAPON_DRAGON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Modern Balance
|
||||||
|
*/
|
||||||
|
if (Special.ModernBalance) {
|
||||||
|
/*
|
||||||
|
** GDI Weapons Factory has 30% more health.
|
||||||
|
*/
|
||||||
|
((BuildingTypeClass&)BuildingTypeClass::As_Reference(STRUCT_WEAP)).MaxStrength = 520;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Repair Pad is a pre-requisite for the APC.
|
||||||
|
*/
|
||||||
|
((UnitTypeClass&)UnitTypeClass::As_Reference(UNIT_APC)).Pre |= STRUCTF_REPAIR;
|
||||||
|
} else {
|
||||||
|
((BuildingTypeClass&)BuildingTypeClass::As_Reference(STRUCT_WEAP)).MaxStrength = 400;
|
||||||
|
((UnitTypeClass&)UnitTypeClass::As_Reference(UNIT_APC)).Pre &= ~STRUCTF_REPAIR;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -70,6 +70,7 @@ class SpecialClass
|
||||||
IsEarlyWin = false;
|
IsEarlyWin = false;
|
||||||
HealthBarDisplayMode = HB_SELECTED;
|
HealthBarDisplayMode = HB_SELECTED;
|
||||||
ResourceBarDisplayMode = RB_SELECTED;
|
ResourceBarDisplayMode = RB_SELECTED;
|
||||||
|
ModernBalance = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -254,11 +255,21 @@ class SpecialClass
|
||||||
RB_ALWAYS,
|
RB_ALWAYS,
|
||||||
} ResourceBarDisplayMode;
|
} ResourceBarDisplayMode;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** New modern balance setting.
|
||||||
|
*/
|
||||||
|
unsigned ModernBalance:1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Some additional padding in case we need to add data to the class and maintain backwards compatibility for save/load
|
** Some additional padding in case we need to add data to the class and maintain backwards compatibility for save/load
|
||||||
*/
|
*/
|
||||||
unsigned char SaveLoadPadding[128];
|
// MBL 07.21.2020 - https://jaas.ea.com/browse/TDRA-7537
|
||||||
|
// Loading save files from Live and July Patch 3 Beta versions results in a crash
|
||||||
|
// Fixes issue from Change 738397 2020/07/17 14:06:03
|
||||||
|
//
|
||||||
|
// unsigned char SaveLoadPadding[127];
|
||||||
|
//
|
||||||
|
unsigned char SaveLoadPadding[124];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1266,7 +1266,14 @@ void TeamClass::Coordinate_Move(void)
|
||||||
unit->Assign_Mission(MISSION_MOVE);
|
unit->Assign_Mission(MISSION_MOVE);
|
||||||
}
|
}
|
||||||
if (unit->NavCom != Target) {
|
if (unit->NavCom != Target) {
|
||||||
unit->Assign_Destination(Target);
|
TARGET target = Target;
|
||||||
|
if (unit->What_Am_I() == RTTI_AIRCRAFT) {
|
||||||
|
AircraftClass* aircraft = (AircraftClass *)unit;
|
||||||
|
if (!aircraft->Class->IsFixedWing && !aircraft->Is_LZ_Clear(target)) {
|
||||||
|
target = aircraft->New_LZ(target, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unit->Assign_Destination(target);
|
||||||
}
|
}
|
||||||
finished = false;
|
finished = false;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1021,7 +1021,7 @@ void TechnoClass::Draw_It(int x, int y, WindowNumberType window)
|
||||||
Clear_Redraw_Flag();
|
Clear_Redraw_Flag();
|
||||||
|
|
||||||
const bool show_health_bar =
|
const bool show_health_bar =
|
||||||
(Strength > 0) && ((Cloak != CLOAKED) || Is_Owned_By_Player()) &&
|
(Strength > 0) && !Is_Cloaked(PlayerPtr) &&
|
||||||
(Is_Selected_By_Player() ||
|
(Is_Selected_By_Player() ||
|
||||||
((Special.HealthBarDisplayMode == SpecialClass::HB_DAMAGED) && (Strength < Techno_Type_Class()->MaxStrength)) ||
|
((Special.HealthBarDisplayMode == SpecialClass::HB_DAMAGED) && (Strength < Techno_Type_Class()->MaxStrength)) ||
|
||||||
(Special.HealthBarDisplayMode == SpecialClass::HB_ALWAYS));
|
(Special.HealthBarDisplayMode == SpecialClass::HB_ALWAYS));
|
||||||
|
@ -1191,7 +1191,8 @@ bool TechnoClass::In_Range(TARGET target, int which, bool reciprocal_check) cons
|
||||||
if (building) {
|
if (building) {
|
||||||
range += ((building->Class->Width() + building->Class->Height()) * (ICON_LEPTON_W / 4));
|
range += ((building->Class->Width() + building->Class->Height()) * (ICON_LEPTON_W / 4));
|
||||||
}
|
}
|
||||||
if (::Distance(Fire_Coord(which), As_Coord(target)) <= range) {
|
FireDataType data = Fire_Data(which);
|
||||||
|
if (MAX(0, ::Distance(data.Center, As_Coord(target)) - data.Distance) <= range) {
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1244,8 +1245,8 @@ bool TechnoClass::In_Range(ObjectClass const * target, int which, bool reciproca
|
||||||
BuildingClass const * building = (BuildingClass const *)target;
|
BuildingClass const * building = (BuildingClass const *)target;
|
||||||
range += ((building->Class->Width() + building->Class->Height()) * (ICON_LEPTON_W / 4));
|
range += ((building->Class->Width() + building->Class->Height()) * (ICON_LEPTON_W / 4));
|
||||||
}
|
}
|
||||||
|
FireDataType data = Fire_Data(which);
|
||||||
if (::Distance(Fire_Coord(which), target->Center_Coord()) <= range) {
|
if (MAX(0, ::Distance(data.Center, target->Center_Coord()) - data.Distance) <= range) {
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1367,7 +1368,7 @@ bool TechnoClass::Evaluate_Object(ThreatType method, int mask, int range, Techno
|
||||||
/*
|
/*
|
||||||
** If the object is cloaked, then it isn't a legal target.
|
** If the object is cloaked, then it isn't a legal target.
|
||||||
*/
|
*/
|
||||||
if (object->Cloak == CLOAKED) return(false);
|
if (object->Is_Cloaked(this)) return(false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Determine if the target is theoretically allowed to be a target. If
|
** Determine if the target is theoretically allowed to be a target. If
|
||||||
|
@ -2103,7 +2104,7 @@ FireErrorType TechnoClass::Can_Fire(TARGET target, int which) const
|
||||||
//Mono_Printf("Buildings[0]=%p.\n", Buildings.Raw_Ptr(0));
|
//Mono_Printf("Buildings[0]=%p.\n", Buildings.Raw_Ptr(0));
|
||||||
//Mono_Printf("Aircraft[0]=%p.\n", Aircraft.Raw_Ptr(0));
|
//Mono_Printf("Aircraft[0]=%p.\n", Aircraft.Raw_Ptr(0));
|
||||||
//Mono_Printf("object=%p, Strength=%d, IsActive=%d, IsInLimbo=%d.\n", object, (long)object->Strength, object->IsActive, object->IsInLimbo);Get_Key();
|
//Mono_Printf("object=%p, Strength=%d, IsActive=%d, IsInLimbo=%d.\n", object, (long)object->Strength, object->IsActive, object->IsInLimbo);Get_Key();
|
||||||
if (object && /*(object->IsActive || GameToPlay != GAME_NORMAL) &&*/ object->Is_Techno() && ((TechnoClass *)object)->Cloak == CLOAKED) {
|
if (object && /*(object->IsActive || GameToPlay != GAME_NORMAL) &&*/ object->Is_Techno() && ((TechnoClass *)object)->Is_Cloaked(this)) {
|
||||||
return(FIRE_CANT);
|
return(FIRE_CANT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2425,7 +2426,7 @@ BulletClass * TechnoClass::Fire_At(TARGET target, int which)
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
** Now need to reveal for any human player that is the target. ST - 3/13/2019 5:43PM
|
** Now need to reveal for any player that is the target. ST - 3/13/2019 5:43PM
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ObjectClass *obj = As_Object(target);
|
ObjectClass *obj = As_Object(target);
|
||||||
|
@ -2433,7 +2434,7 @@ BulletClass * TechnoClass::Fire_At(TARGET target, int which)
|
||||||
HousesType tgt_owner = obj->Owner();
|
HousesType tgt_owner = obj->Owner();
|
||||||
|
|
||||||
HouseClass *player = HouseClass::As_Pointer(tgt_owner);
|
HouseClass *player = HouseClass::As_Pointer(tgt_owner);
|
||||||
if (player != nullptr && player->IsHuman) {
|
if (player != nullptr) {
|
||||||
if ((!Is_Owned_By_Player(player) && !Is_Discovered_By_Player(player)) || !Map[Coord_Cell(Center_Coord())].Is_Mapped(House)) {
|
if ((!Is_Owned_By_Player(player) && !Is_Discovered_By_Player(player)) || !Map[Coord_Cell(Center_Coord())].Is_Mapped(House)) {
|
||||||
Map.Sight_From(player, Coord_Cell(Center_Coord()), 1, false);
|
Map.Sight_From(player, Coord_Cell(Center_Coord()), 1, false);
|
||||||
}
|
}
|
||||||
|
@ -4442,6 +4443,7 @@ BuildingClass * TechnoClass::Find_Docking_Bay(StructType b, bool friendly) const
|
||||||
if (bestval == -1 || Distance(building) < bestval || building->IsLeader) {
|
if (bestval == -1 || Distance(building) < bestval || building->IsLeader) {
|
||||||
best = building;
|
best = building;
|
||||||
bestval = Distance(building);
|
bestval = Distance(building);
|
||||||
|
if (building->IsLeader) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4616,8 +4618,23 @@ bool TechnoClass::Is_Owned_By_Player(HouseClass *player) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool TechnoClass::Is_Cloaked(HousesType house) const
|
||||||
|
{
|
||||||
|
return !House->Is_Ally(house) && (Cloak == CLOAKED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool TechnoClass::Is_Cloaked(HouseClass const * house) const
|
||||||
|
{
|
||||||
|
return !House->Is_Ally(house) && (Cloak == CLOAKED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool TechnoClass::Is_Cloaked(ObjectClass const * object) const
|
||||||
|
{
|
||||||
|
return !House->Is_Ally(object) && (Cloak == CLOAKED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -282,6 +282,9 @@ class TechnoClass : public RadioClass,
|
||||||
virtual ResultType Take_Damage(int & damage, int distance, WarheadType warhead, TechnoClass * source);
|
virtual ResultType Take_Damage(int & damage, int distance, WarheadType warhead, TechnoClass * source);
|
||||||
bool Evaluate_Cell(ThreatType method, int mask, CELL cell, int range, TechnoClass const ** object, int & value) const;
|
bool Evaluate_Cell(ThreatType method, int mask, CELL cell, int range, TechnoClass const ** object, int & value) const;
|
||||||
bool Evaluate_Object(ThreatType method, int mask, int range, TechnoClass const * object, int & value) const;
|
bool Evaluate_Object(ThreatType method, int mask, int range, TechnoClass const * object, int & value) const;
|
||||||
|
bool Is_Cloaked(HousesType house) const;
|
||||||
|
bool Is_Cloaked(HouseClass const * house) const;
|
||||||
|
bool Is_Cloaked(ObjectClass const * object) const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** AI.
|
** AI.
|
||||||
|
|
|
@ -361,6 +361,64 @@ FireErrorType TurretClass::Can_Fire(TARGET target, int which) const
|
||||||
* HISTORY: *
|
* HISTORY: *
|
||||||
* 12/28/1994 JLB : Created. *
|
* 12/28/1994 JLB : Created. *
|
||||||
*=============================================================================================*/
|
*=============================================================================================*/
|
||||||
|
FireDataType TurretClass::Fire_Data(int which) const
|
||||||
|
{
|
||||||
|
COORDINATE coord = Center_Coord();
|
||||||
|
int dist = 0;
|
||||||
|
|
||||||
|
switch (Class->Type) {
|
||||||
|
case UNIT_GUNBOAT:
|
||||||
|
coord = Coord_Move(coord, PrimaryFacing.Current(), Pixel2Lepton[Class->TurretOffset]);
|
||||||
|
dist = 0x0060;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UNIT_ARTY:
|
||||||
|
coord = Coord_Move(coord, DIR_N, 0x0040);
|
||||||
|
dist = 0x0060;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UNIT_FTANK:
|
||||||
|
dist = 0x30;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UNIT_HTANK:
|
||||||
|
coord = Coord_Move(coord, DIR_N, 0x0040);
|
||||||
|
if (which == 0) {
|
||||||
|
dist = 0x00C0;
|
||||||
|
} else {
|
||||||
|
dist = 0x0008;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UNIT_LTANK:
|
||||||
|
coord = Coord_Move(coord, DIR_N, 0x0020);
|
||||||
|
dist = 0x00C0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UNIT_MTANK:
|
||||||
|
coord = Coord_Move(coord, DIR_N, 0x0030);
|
||||||
|
dist = 0x00C0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UNIT_APC:
|
||||||
|
case UNIT_JEEP:
|
||||||
|
case UNIT_BUGGY:
|
||||||
|
coord = Coord_Move(coord, DIR_N, 0x0030);
|
||||||
|
dist = 0x0030;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef PETROGLYPH_EXAMPLE_MOD
|
||||||
|
case UNIT_NUKE_TANK:
|
||||||
|
coord = Coord_Move(coord, DIR_N, 0x00A0);
|
||||||
|
dist = 0x00A0;
|
||||||
|
break;
|
||||||
|
#endif //PETROGLYPH_EXAMPLE_MOD
|
||||||
|
}
|
||||||
|
|
||||||
|
return {coord,dist};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
COORDINATE TurretClass::Fire_Coord(int which) const
|
COORDINATE TurretClass::Fire_Coord(int which) const
|
||||||
{
|
{
|
||||||
COORDINATE coord = Center_Coord();
|
COORDINATE coord = Center_Coord();
|
||||||
|
|
|
@ -75,6 +75,7 @@ class TurretClass : public DriveClass
|
||||||
virtual FireErrorType Can_Fire(TARGET target, int which) const;
|
virtual FireErrorType Can_Fire(TARGET target, int which) const;
|
||||||
virtual bool Ok_To_Move(DirType facing);
|
virtual bool Ok_To_Move(DirType facing);
|
||||||
virtual void AI(void);
|
virtual void AI(void);
|
||||||
|
virtual FireDataType Fire_Data(int which) const;
|
||||||
virtual COORDINATE Fire_Coord(int which) const;
|
virtual COORDINATE Fire_Coord(int which) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
<ProjectConfiguration Include="Debug|Win32">
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="Source Files">
|
<Filter Include="Source Files">
|
||||||
|
|
|
@ -390,7 +390,7 @@ void UnitClass::AI(void)
|
||||||
** Delete this unit if it finds itself off the edge of the map and it is in
|
** Delete this unit if it finds itself off the edge of the map and it is in
|
||||||
** guard or other static mission mode.
|
** guard or other static mission mode.
|
||||||
*/
|
*/
|
||||||
if (!Team && Mission == MISSION_GUARD && !Map.In_Radar(Coord_Cell(Coord))) {
|
if (!Team && Mission == MISSION_GUARD && MissionQueue == MISSION_NONE && !Map.In_Radar(Coord_Cell(Coord))) {
|
||||||
Stun();
|
Stun();
|
||||||
Delete_This();
|
Delete_This();
|
||||||
return;
|
return;
|
||||||
|
@ -501,6 +501,13 @@ void UnitClass::AI(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Scatter units off buildings in guard modes.
|
||||||
|
*/
|
||||||
|
if (!IsTethered && !IsFiring && !IsDriving && !IsRotating && (Mission == MISSION_GUARD || Mission == MISSION_GUARD_AREA) && MissionQueue == MISSION_NONE && Map[Coord_Cell(Coord)].Cell_Building() != NULL) {
|
||||||
|
Scatter(0, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A cloaked object that is carrying the flag will always shimmer.
|
** A cloaked object that is carrying the flag will always shimmer.
|
||||||
*/
|
*/
|
||||||
|
@ -1259,6 +1266,11 @@ void UnitClass::Player_Assign_Mission(MissionType mission, TARGET target, TARGET
|
||||||
Validate();
|
Validate();
|
||||||
if (mission == MISSION_HARVEST) {
|
if (mission == MISSION_HARVEST) {
|
||||||
ArchiveTarget = TARGET_NONE;
|
ArchiveTarget = TARGET_NONE;
|
||||||
|
} else if (mission == MISSION_ENTER) {
|
||||||
|
BuildingClass* building = As_Building(destination);
|
||||||
|
if (building != NULL && *building == STRUCT_REFINERY && building->In_Radio_Contact()) {
|
||||||
|
building->Transmit_Message(RADIO_OVER_OUT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TarComClass::Player_Assign_Mission(mission, target, destination);
|
TarComClass::Player_Assign_Mission(mission, target, destination);
|
||||||
}
|
}
|
||||||
|
@ -1817,7 +1829,7 @@ void UnitClass::Per_Cell_Process(bool center)
|
||||||
} else {
|
} else {
|
||||||
TechnoClass * contact = Contact_With_Whom();
|
TechnoClass * contact = Contact_With_Whom();
|
||||||
if (Transmit_Message(RADIO_UNLOADED) == RADIO_RUN_AWAY) {
|
if (Transmit_Message(RADIO_UNLOADED) == RADIO_RUN_AWAY) {
|
||||||
if (*this == UNIT_HARVESTER && contact && contact->What_Am_I() == RTTI_BUILDING) {
|
if (*this == UNIT_HARVESTER && contact && contact->What_Am_I() == RTTI_BUILDING && *((BuildingClass*)contact) != STRUCT_REPAIR) {
|
||||||
Assign_Mission(MISSION_HARVEST);
|
Assign_Mission(MISSION_HARVEST);
|
||||||
} else if (!Target_Legal(NavCom)) {
|
} else if (!Target_Legal(NavCom)) {
|
||||||
Scatter(0, true);
|
Scatter(0, true);
|
||||||
|
@ -2308,7 +2320,7 @@ int UnitClass::Tiberium_Check(CELL ¢er, int x, int y)
|
||||||
//using function for IsVisible so we have different results for different players - JAS 2019/09/30
|
//using function for IsVisible so we have different results for different players - JAS 2019/09/30
|
||||||
if ((GameToPlay != GAME_NORMAL || (!IsOwnedByPlayer || Map[center].Is_Visible(PlayerPtr)))) {
|
if ((GameToPlay != GAME_NORMAL || (!IsOwnedByPlayer || Map[center].Is_Visible(PlayerPtr)))) {
|
||||||
if (!Map[center].Cell_Techno() && Map[center].Land_Type() == LAND_TIBERIUM) {
|
if (!Map[center].Cell_Techno() && Map[center].Land_Type() == LAND_TIBERIUM) {
|
||||||
return(Map[center].OverlayData);
|
return(Map[center].OverlayData+1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(0);
|
return(0);
|
||||||
|
@ -2333,6 +2345,7 @@ bool UnitClass::Goto_Tiberium(void)
|
||||||
int tiberium = 0;
|
int tiberium = 0;
|
||||||
int besttiberium = 0;
|
int besttiberium = 0;
|
||||||
for (int x = -radius; x <= radius; x++) {
|
for (int x = -radius; x <= radius; x++) {
|
||||||
|
cell = center;
|
||||||
tiberium = Tiberium_Check(cell, x, -radius);
|
tiberium = Tiberium_Check(cell, x, -radius);
|
||||||
if (tiberium > besttiberium) {
|
if (tiberium > besttiberium) {
|
||||||
bestcell = cell;
|
bestcell = cell;
|
||||||
|
@ -2657,7 +2670,14 @@ int UnitClass::Mission_Harvest(void)
|
||||||
*/
|
*/
|
||||||
case LOOKING:
|
case LOOKING:
|
||||||
IsHarvesting = false;
|
IsHarvesting = false;
|
||||||
if (Goto_Tiberium()) {
|
/*
|
||||||
|
** Slightly hacky; if TarCom is set then skip to finding home state.
|
||||||
|
*/
|
||||||
|
if (Target_Legal(TarCom)) {
|
||||||
|
Assign_Target(TARGET_NONE);
|
||||||
|
Status = FINDHOME;
|
||||||
|
return(1);
|
||||||
|
} else if (Goto_Tiberium()) {
|
||||||
IsHarvesting = true;
|
IsHarvesting = true;
|
||||||
Set_Rate(2);
|
Set_Rate(2);
|
||||||
Set_Stage(0);
|
Set_Stage(0);
|
||||||
|
@ -2853,7 +2873,7 @@ void UnitClass::Look(bool incremental)
|
||||||
{
|
{
|
||||||
Validate();
|
Validate();
|
||||||
//if (!IsInLimbo && IsOwnedByPlayer) { // Changed for mapping of multiple players
|
//if (!IsInLimbo && IsOwnedByPlayer) { // Changed for mapping of multiple players
|
||||||
if (!IsInLimbo && House && House->IsHuman) {
|
if (!IsInLimbo && House && (House->IsHuman || GameToPlay != GAME_NORMAL)) {
|
||||||
int sight = Class->SightRange;
|
int sight = Class->SightRange;
|
||||||
|
|
||||||
if (sight) {
|
if (sight) {
|
||||||
|
|
|
@ -4841,7 +4841,7 @@ extern "C" int __cdecl Confine_Rect ( int * x , int * y , int w , int h , int wi
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/DrawMisc.cpp#57 $
|
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/DrawMisc.cpp#95 $
|
||||||
;***************************************************************************
|
;***************************************************************************
|
||||||
;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
|
;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
|
||||||
;***************************************************************************
|
;***************************************************************************
|
||||||
|
|
|
@ -321,7 +321,7 @@ int __cdecl Desired_Facing8(long x1, long y1, long x2, long y2);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/FACINGFF.h#57 $
|
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/FACINGFF.h#95 $
|
||||||
;***************************************************************************
|
;***************************************************************************
|
||||||
;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
|
;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
|
||||||
;***************************************************************************
|
;***************************************************************************
|
||||||
|
|
Loading…
Reference in New Issue