August 6th Patch Update

Accumulated DLL source code changes since June 22nd patch
This commit is contained in:
PG-SteveT 2020-08-06 09:44:54 -07:00
parent 93a1af2eff
commit ae72fce5dd
76 changed files with 1071 additions and 210 deletions

View file

@ -337,7 +337,7 @@ static AnimTypeClass const LZSmoke(
72, // Loop start frame number.
91, // Ending frame of loop back.
-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.
ANIM_NONE
);
@ -1427,7 +1427,7 @@ static AnimTypeClass const OilFieldBurn(
33, // Loop start frame number.
99, // Ending frame of loop back.
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.
ANIM_NONE
);

View file

@ -245,6 +245,7 @@ AircraftClass::AircraftClass(AircraftType classid, HousesType house) :
NavCom = TARGET_NONE;
SecondaryFacing = PrimaryFacing;
Jitter = 0;
ReinforcementStart = -1;
/*
** 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 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.
@ -743,7 +752,17 @@ void AircraftClass::AI(void)
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();
}
@ -1399,9 +1418,13 @@ int AircraftClass::Mission_Retreat(void)
{
Validate();
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++;
return(3);
return(1);
}
return(TICKS_PER_SECOND*10);
}
@ -2175,7 +2198,7 @@ ActionType AircraftClass::What_Action(CELL cell) const
ActionType action = FootClass::What_Action(cell);
//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;
}
@ -2438,7 +2461,7 @@ int AircraftClass::Mission_Attack(void)
* HISTORY: *
* 06/19/1995 JLB : Created. *
*=============================================================================================*/
TARGET AircraftClass::New_LZ(TARGET oldlz) const
TARGET AircraftClass::New_LZ(TARGET oldlz, bool stable) const
{
Validate();
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.
*/
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;
/*
@ -2838,8 +2861,9 @@ TARGET AircraftClass::Good_Fire_Location(TARGET target) const
for (int face = 0; face < 255; face += 16) {
COORDINATE newcoord = Coord_Move(tcoord, (DirType)face, r);
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);
if (bestval == -1 || dist < bestval) {
best2val = bestval;
@ -3545,4 +3569,9 @@ void AircraftClass::Response_Select(void)
if (AllowVoice) {
Sound_Effect(response, 0, -(Aircraft.ID(this)+1));
}
}
void AircraftClass::Set_Reinforcement_Delay(long delay)
{
ReinforcementStart = Frame + delay;
}

View file

@ -98,7 +98,7 @@ class AircraftClass : public FootClass, public FlyClass
** Landing zone support functionality.
*/
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
@ -148,6 +148,7 @@ class AircraftClass : public FootClass, public FlyClass
virtual void Enter_Idle_Mode(bool initial = false);
virtual RadioMessageType Receive_Message(RadioClass * from, RadioMessageType message, long & param);
virtual void Scatter(COORDINATE threat, bool forced=false, bool nokidding=false);
void Set_Reinforcement_Delay(long delay);
/*
** Scenario and debug support.
@ -242,10 +243,15 @@ class AircraftClass : public FootClass, public FlyClass
*/
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
*/
unsigned char SaveLoadPadding[32];
unsigned char SaveLoadPadding[28];
/*
** This contains the value of the Virtual Function Table Pointer

View file

@ -589,7 +589,7 @@ AnimClass::AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay
coord = Adjust_Coord(coord);
Unlimbo(coord);
VisibleFlags = 0xffff;
VisibleFlags = static_cast<unsigned int>(-1);
/*
** Drop zone smoke always reveals the map around itself.
@ -751,6 +751,16 @@ void AnimClass::AI(void)
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) {
Delay--;
if (!Delay) {
@ -788,10 +798,10 @@ void AnimClass::AI(void)
int damage = accum >> 8;
if (Object->Take_Damage(damage, 0, WARHEAD_FIRE) == RESULT_DESTROYED) {
//Object = 0;
Delete_This();
if (VirtualAnim != NULL) {
VirtualAnim->Delete_This();
}
Delete_This();
return;
}
}
@ -1272,6 +1282,9 @@ void AnimClass::Detach(TARGET target, bool all)
if (all) {
if (VirtualAnim && VirtualAnim->As_Target() == target) {
VirtualAnim = NULL;
if (IsInvisible) {
IsToDelete = true;
}
}
if (Object && Object->As_Target() == target) {
Map.Remove(this, In_Which_Layer());

View file

@ -234,7 +234,7 @@ static BuildingTypeClass const ClassEye(
false, // Always use the given name for the building?
false, // Is this a wall type structure?
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, // Simple (one frame) damage imagery?
false, // Is it invisible to radar?

View file

@ -213,7 +213,7 @@ RadioMessageType BuildingClass::Receive_Message(RadioClass * from, RadioMessageT
case RADIO_CAN_LOAD:
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) {
case STRUCT_AIRSTRIP:
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 &&
(ScenarioInit || !Is_Something_Attached())) {
return(RADIO_ROGER);
return((Contact_With_Whom() != from) ? RADIO_ROGER : RADIO_NEGATIVE);
}
break;
@ -1166,7 +1166,9 @@ void BuildingClass::AI(void)
Repair(1);
} else {
if (IsTickedOff && (int)Scenario > 2 && Random_Pick(0, 50) < (int)Scenario && !Trigger) {
Sell_Back(1);
if (GameToPlay != GAME_NORMAL || Scenario != 15 || PlayerPtr->ActLike != HOUSE_GOOD || *this != STRUCT_TEMPLE) {
Sell_Back(1);
}
}
}
}
@ -2734,6 +2736,39 @@ bool BuildingClass::Limbo(void)
* HISTORY: *
* 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
{
Validate();
@ -3519,8 +3554,14 @@ bool BuildingClass::Toggle_Primary(void)
}
}
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);
@ -3832,14 +3873,14 @@ bool BuildingClass::Can_Demolish_Unit(void) const
bool BuildingClass::Can_Capture(void) const
{
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
if (GameToPlay == GAME_NORMAL) {
can_capture &= Scenario < 13;
} else {
can_capture = false;
// Override capturable state if this building has a capture win trigger
if (GameToPlay == GAME_NORMAL) {
if (Trigger != NULL && Trigger->Action == TriggerClass::ACTION_WINLOSE) {
can_capture = true;
}
}
return(can_capture);
}
@ -4093,11 +4134,18 @@ int BuildingClass::Mission_Deconstruction(void)
}
}
//Changed for multiplayer ST - 3/13/2019 5:31PM
if (Is_Owned_By_Player()) {
//if (IsOwnedByPlayer) {
// 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
if (Is_Owned_By_Player()) {
//if (IsOwnedByPlayer) {
Sound_Effect(VOC_CASHTURN, Coord);
}
#else
Sound_Effect(VOC_CASHTURN, Coord);
}
#endif
/*
** 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 (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;
Begin_Mode(BSTATE_ACTIVE);
IsReadyToCommence = false;

View file

@ -196,6 +196,7 @@ class BuildingClass : public TechnoClass
** combat purposes.
*/
virtual COORDINATE Docking_Coord(void) const;
virtual FireDataType Fire_Data(int which) const;
virtual COORDINATE Fire_Coord(int which) const;
virtual COORDINATE Center_Coord(void) const;
virtual COORDINATE Sort_Y(void) const;

View file

@ -1824,7 +1824,7 @@ static TemplateTypeClass const Patch15(
"P15",
TXT_PATCH,
LAND_CLEAR,
1,1,
4,2,
LAND_CLEAR,
NULL
);

View file

@ -1936,7 +1936,7 @@ long CellClass::Tiberium_Adjust(bool pregame)
* 05/22/1995 JLB : Created. *
* 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();
enum {
@ -1990,21 +1990,30 @@ bool CellClass::Goodie_Check(FootClass * object)
bool steel = (Overlay == OVERLAY_STEEL_CRATE);
COORDINATE coord; // Temporary working coordinate value.
/*
** A triggered crate is automatically destroyed regardless of who or how
** it was triggered.
*/
Redraw_Objects();
Overlay = OVERLAY_NONE;
OverlayData = 0;
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;
if (steel) {
if (object->Owner() == HOUSE_BAD) {
object->House->Add_Nuke_Piece();
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;
UnitClass * unit = 0;
@ -2428,9 +2437,18 @@ void CellClass::Flag_Create(void)
{
if (!CTFFlag) {
CTFFlag = new AnimClass(ANIM_FLAG, Cell_Coord(), 0, 1, true);
if (CTFFlag) {
CTFFlag->OwnerHouse = Owner;
if (CTFFlag == NULL) {
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;
}
}

View file

@ -208,7 +208,7 @@ class CellClass
InfantryClass * Cell_Infantry(void) const;
TriggerClass * Get_Trigger(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;
bool Get_Template_Info(char *template_name, int &icon, void *&image_data);

View file

@ -2847,6 +2847,15 @@ typedef enum OptionControlType : char {
} OptionControlType;
/****************************************************************************
** Used to store firing data for a unit.
*/
typedef struct {
COORDINATE Center;
int Distance;
} FireDataType;
#define TOTAL_CRATE_TYPES 15
#define size_of(typ,id) sizeof(((typ*)0)->id)

View file

@ -1810,8 +1810,9 @@ bool DisplayClass::Map_Cell(CELL cell, HouseClass * house, bool and_for_allies)
/*
** Maybe also recurse to map for allies
*/
if (ShareAllyVisibility && and_for_allies && GameToPlay == GAME_GLYPHX_MULTIPLAYER) {
for (HousesType house_type = HOUSE_MULTI1; house_type < HOUSE_COUNT; house_type++) {
if (ShareAllyVisibility && and_for_allies) {
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);
if (hptr && hptr->IsActive) {
if (hptr != house && house->Is_Ally(hptr)) {
@ -3870,12 +3871,17 @@ void DisplayClass::Mouse_Left_Release(CELL cell, int x, int y, ObjectClass * obj
AllowVoice = true;
for (int index = 0; index < CurrentObject.Count(); index++) {
ObjectClass * tobject = CurrentObject[index];
ActionType action = ACTION_NONE;
if (object) {
tobject->Active_Click_With(tobject->What_Action(object), object);
action = tobject->What_Action(object);
tobject->Active_Click_With(action, object);
} 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;

View file

@ -672,6 +672,7 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Set_Multiplayer_Data(int scena
Special.IsVisceroids = game_options.SpawnVisceroids;
Special.IsCaptureTheFlag = game_options.CaptureTheFlag;
Special.IsEarlyWin = game_options.DestroyStructures;
Special.ModernBalance = game_options.ModernBalance;
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();
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();
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);
// MBL 07.21.2020
if (result == false)
{
return false;
}
DLLExportClass::Set_Player_Context(DLLExportClass::GlyphxPlayerIDs[0], true);
Set_Logic_Page(SeenBuff);
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)
{
CNCObjectStruct& new_object = ObjectList->Objects[TotalObjectCount + CurrentDrawCount];
memset(&new_object, 0, sizeof(new_object));
Convert_Type(object, new_object);
if (new_object.Type == UNKNOWN) {
return;
@ -4012,6 +4022,8 @@ bool DLLExportClass::Get_Sidebar_State(uint64 player_id, unsigned char *buffer_i
if ((entry_index + 1) * sizeof(CNCSidebarEntryStruct) + memory_needed > buffer_size) {
return false;
}
memset(&sidebar_entry, 0, sizeof(sidebar_entry));
sidebar_entry.AssetName[0] = 0;
sidebar_entry.Type = UNKNOWN;
@ -4191,6 +4203,8 @@ bool DLLExportClass::Get_Sidebar_State(uint64 player_id, unsigned char *buffer_i
return false;
}
memset(&sidebar_entry, 0, sizeof(sidebar_entry));
sidebar_entry.AssetName[0] = 0;
sidebar_entry.Type = UNKNOWN;
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)
{
int map_cell_x = Map.MapCellX;
@ -4380,7 +4396,7 @@ void DLLExportClass::Calculate_Placement_Distances(BuildingTypeClass* placement_
memset(placement_distance, 255U, MAP_CELL_TOTAL);
for (int y = 0; y < map_cell_height; y++) {
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);
if ((base && base->House->Class->House == PlayerPtr->Class->House) || (Map[cell].Owner == PlayerPtr->Class->House)) {
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 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]);
@ -5132,7 +5148,7 @@ Map.Passes_Proximity_Check
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.
@ -7503,10 +7519,18 @@ bool DLLExportClass::Save(FileClass & file)
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(&not_allow_super_weapons, sizeof(not_allow_super_weapons)) != sizeof(not_allow_super_weapons)) {
return false;
}
/*
** Room for save game expansion
*/
unsigned char padding[4096];
unsigned char padding[4095];
memset(padding, 0, sizeof(padding));
if (file.Write(padding, sizeof(padding)) != sizeof(padding)) {
@ -7621,7 +7645,16 @@ bool DLLExportClass::Load(FileClass & file)
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(&not_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)) {
return false;

View file

@ -728,7 +728,7 @@ struct CNCMultiplayerOptionsStruct {
int MPlayerCount; // # of human players in this game
int MPlayerBases; // 1 = bases are on for this scenario
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 MPlayerGhosts; // 1 = houses with no players will still play
int MPlayerSolo; // 1 = allows a single-player net game
@ -740,6 +740,7 @@ struct CNCMultiplayerOptionsStruct {
bool MPlayerAftermathUnits;
bool CaptureTheFlag;
bool DestroyStructures; // New early win condition via destroying all a player's structures
bool ModernBalance;
};

View file

@ -962,9 +962,17 @@ bool DriveClass::Start_Of_Move(void)
/*
** If a basic path could be found, but the immediate move destination is
** 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 (Can_Enter_Cell(cell) == MOVE_TEMP) {
CellClass * cellptr = &Map[cell];

View file

@ -509,7 +509,7 @@ CCDebugString ("C&C95 - Sell packet received\n");
//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)
{
anim->Set_Visible_Flags(0xffff);
anim->Set_Visible_Flags(static_cast<unsigned int>(-1));
}
else
{
@ -626,6 +626,12 @@ CCDebugString ("C&C95 - Primary building packet received\n");
techno->ArchiveTarget = Data.MegaMission.Target;
techno->Assign_Target(TARGET_NONE);
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 {
techno->Assign_Target(Data.MegaMission.Target);
techno->Assign_Destination(Data.MegaMission.Destination);

View file

@ -1423,6 +1423,8 @@ void FootClass::Per_Cell_Process(bool center)
}
// }
Map[Coord_Cell(Coord)].Goodie_Check(this, true);
TechnoClass::Per_Cell_Process(center);
}
@ -1635,8 +1637,20 @@ int FootClass::Mission_Enter(void)
** Since there is no potential object to enter, then abort this
** mission with some default standby mission.
*/
ArchiveTarget = TARGET_NONE;
Enter_Idle_Mode();
if (MissionQueue == MISSION_NONE) {
/*
** If this is a harvester, then return to harvesting.
** Set a hacky target so we know to skip to the proper state.
*/
if (What_Am_I() == RTTI_UNIT && ((UnitClass*)this)->Class->IsToHarvest) {
Assign_Mission(MISSION_HARVEST);
Assign_Target(As_Target());
Assign_Destination(TARGET_NONE);
} else {
ArchiveTarget = TARGET_NONE;
Enter_Idle_Mode();
}
}
}
return(TICKS_PER_SECOND/2);
}

View file

@ -569,16 +569,18 @@ bool HouseClass::Can_Build(TechnoTypeClass const * type, HousesType house) const
*/
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
** sidebar to keep track of this information.
** AI players update flags using building quantity tracker.
** Ensures consistent logic when determining building choices.
*/
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;
if (flags & STRUCTF_ADVANCED_POWER) flags |= STRUCTF_POWER;
@ -972,6 +974,12 @@ void HouseClass::AI(void)
if (IsToDie && BorrowedTime.Expired()) {
IsToDie = false;
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
if (GameToPlay != GAME_NORMAL) {
if (GameToPlay != GAME_NORMAL && Class->House != HOUSE_JP) {
Check_Pertinent_Structures();
}
@ -1664,8 +1672,15 @@ void HouseClass::AI(void)
void HouseClass::Attacked(BuildingClass* source)
{
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);
spoke = true;
// 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
@ -1680,6 +1695,23 @@ void HouseClass::Attacked(BuildingClass* source)
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:
- Set MPlayerObiWan, so I can only send messages to all players, and
@ -4784,6 +4823,13 @@ void HouseClass::Check_Pertinent_Structures(void)
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;
for (int index = 0; index < Buildings.Count(); index++) {

View file

@ -430,7 +430,7 @@ static InfantryTypeClass const E5(
70, // Strength of infantry (in damage points).
1, // Sight range.
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.
HOUSEF_MULTI1|
HOUSEF_MULTI2|

View file

@ -882,7 +882,7 @@ void InfantryClass::Look(bool incremental)
if (!IsInLimbo) {
//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;
if (sight) {
@ -1098,7 +1098,14 @@ void InfantryClass::AI(void)
** run in circles, scream, and shout.
*/
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()
** 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
@ -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
** 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;
}

View file

@ -321,6 +321,9 @@ bool Read_Scenario_Ini(char *root, bool fresh)
#ifdef NEWMENU
if (Scenario <= 15) {
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 {
BuildLevel = WWGetPrivateProfileInt("Basic", "BuildLevel", Scenario, buffer);
}
@ -444,6 +447,9 @@ bool Read_Scenario_Ini(char *root, bool fresh)
UnitClass::Read_INI(buffer);
Call_Back();
AircraftClass::Read_INI(buffer);
Call_Back();
/*
** 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
** NOD09A - delete airstrike trigger when radar destroyed
** 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) {
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) {
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)
@ -844,6 +876,9 @@ bool Read_Scenario_Ini_File(char *scenario_file_name, char* bin_file_name, const
UnitClass::Read_INI(buffer);
Call_Back();
AircraftClass::Read_INI(buffer);
Call_Back();
/*
** 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();
Call_Back();
/*
** Scenario fix-up (applied on loaded games as well)
*/
Fixup_Scenario();
/*
** Multi-player last-minute fixups:
** - If computer players are disabled, remove all computer-owned houses

View file

@ -190,6 +190,7 @@ void LogicClass::AI(void)
*/
for (index = 0; index < Count(); index++) {
ObjectClass * obj = (*this)[index];
int count = Count();
obj->AI();
@ -197,9 +198,9 @@ void LogicClass::AI(void)
** If the object was destroyed in the process of performing its AI, then
** adjust the index so that no object gets skipped.
*/
if (obj != (*this)[index]) {
// if (!obj->IsActive) {
index--;
int count_diff = Count() - count;
if (count_diff < 0) {
index += count_diff;
}
}

View file

@ -362,11 +362,9 @@ void MapClass::Sight_From(HouseClass *house, CELL cell, int sightrange, bool inc
** adjacent cells as well. For full scans, just update
** 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
//Map.Map_Cell(newcell, PlayerPtr);
Map.Map_Cell(newcell, house, true);
}
// 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, house, true);
}
}
@ -950,6 +948,15 @@ void MapClass::Logic(void)
if (TiberiumScan >= MAP_CELL_TOTAL) {
int tries = 1;
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;
IsForwardScan = (IsForwardScan == false);
@ -958,11 +965,17 @@ void MapClass::Logic(void)
*/
if (TiberiumGrowthCount) {
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];
if (newcell->Land_Type() == LAND_TIBERIUM && newcell->OverlayData < 12-1) {
newcell->OverlayData++;
}
TiberiumGrowth[pick] = TiberiumGrowth[TiberiumGrowthCount - 1];
TiberiumGrowthCount--;
if (TiberiumGrowthCount <= 0) {
break;
}
}
}
TiberiumGrowthCount = 0;
@ -972,7 +985,8 @@ void MapClass::Logic(void)
*/
if (TiberiumSpreadCount) {
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.
@ -1003,6 +1017,11 @@ void MapClass::Logic(void)
}
}
}
TiberiumSpread[pick] = TiberiumSpread[TiberiumSpreadCount - 1];
TiberiumSpreadCount--;
if (TiberiumSpreadCount <= 0) {
break;
}
}
}
TiberiumSpreadCount = 0;
@ -1400,10 +1419,10 @@ ObjectClass * MapClass::Close_Object(COORDINATE coord) const
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
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) {
int d=-1;
if (o->What_Am_I() == RTTI_BUILDING) {
@ -1429,7 +1448,7 @@ ObjectClass * MapClass::Close_Object(COORDINATE coord) const
AircraftClass * aircraft = Aircraft.Ptr(index);
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))));
if (d >= 0 && (!object || d < distance)) {
distance = d;

View file

@ -428,7 +428,7 @@ dxisbig:
#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 **
;***************************************************************************

View file

@ -564,6 +564,7 @@ COORDINATE ObjectClass::Center_Coord(void) const {return Coord;};
COORDINATE ObjectClass::Render_Coord(void) const {return(Center_Coord());}
COORDINATE ObjectClass::Docking_Coord(void) const {return(Center_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;};
void ObjectClass::Record_The_Kill(TechnoClass * ) {};
void ObjectClass::Do_Shimmer(void) {};

View file

@ -172,6 +172,7 @@ class ObjectClass : public AbstractClass
virtual COORDINATE Center_Coord(void) const;
virtual COORDINATE Render_Coord(void) const;
virtual COORDINATE Sort_Y(void) const;
virtual FireDataType Fire_Data(int) const;
virtual COORDINATE Fire_Coord(int ) const;
/*

View file

@ -235,7 +235,7 @@ bool RadarClass::Radar_Activate(int control)
case 0:
if (Map.IsSidebarActive) {
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;
IsRadarActive = false;
if (IsRadarActivating == true) {
@ -252,7 +252,7 @@ bool RadarClass::Radar_Activate(int control)
case 1:
if (Map.IsSidebarActive) {
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;
if (IsRadarDeactivating == true) {
IsRadarDeactivating = false;

View file

@ -338,6 +338,7 @@ bool Do_Reinforcements(TeamTypeClass *teamtype)
*/
case SOURCE_AIR: {
AircraftClass * thisone = (AircraftClass *)object;
TARGET target = TARGET_NONE;
while (thisone) {
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
** exactly lines up with the airfield they will unload at.
*/
CELL newcell;
COORDINATE newcoord;
long reinforcement_delay = -1;
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--;
if (*thisone == AIRCRAFT_CARGO) {
BuildingClass const * building = thisone->Find_Docking_Bay(STRUCT_AIRSTRIP, false);
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;
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--;
if (placed) {
if (!team) {
if (thisone->Class->IsFixedWing) {
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 {
if (thisone->Class->IsTransporter && thisone->Is_Something_Attached()) {
thisone->Assign_Mission(MISSION_UNLOAD);

View file

@ -799,4 +799,22 @@ void Fixup_Scenario(void)
} else {
((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;
}
}

View file

@ -70,6 +70,7 @@ class SpecialClass
IsEarlyWin = false;
HealthBarDisplayMode = HB_SELECTED;
ResourceBarDisplayMode = RB_SELECTED;
ModernBalance = false;
}
/*
@ -254,11 +255,21 @@ class SpecialClass
RB_ALWAYS,
} 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
*/
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];
};

View file

@ -1266,7 +1266,14 @@ void TeamClass::Coordinate_Move(void)
unit->Assign_Mission(MISSION_MOVE);
}
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;
} else {

View file

@ -1021,7 +1021,7 @@ void TechnoClass::Draw_It(int x, int y, WindowNumberType window)
Clear_Redraw_Flag();
const bool show_health_bar =
(Strength > 0) && ((Cloak != CLOAKED) || Is_Owned_By_Player()) &&
(Strength > 0) && !Is_Cloaked(PlayerPtr) &&
(Is_Selected_By_Player() ||
((Special.HealthBarDisplayMode == SpecialClass::HB_DAMAGED) && (Strength < Techno_Type_Class()->MaxStrength)) ||
(Special.HealthBarDisplayMode == SpecialClass::HB_ALWAYS));
@ -1191,7 +1191,8 @@ bool TechnoClass::In_Range(TARGET target, int which, bool reciprocal_check) cons
if (building) {
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);
}
@ -1244,8 +1245,8 @@ bool TechnoClass::In_Range(ObjectClass const * target, int which, bool reciproca
BuildingClass const * building = (BuildingClass const *)target;
range += ((building->Class->Width() + building->Class->Height()) * (ICON_LEPTON_W / 4));
}
if (::Distance(Fire_Coord(which), target->Center_Coord()) <= range) {
FireDataType data = Fire_Data(which);
if (MAX(0, ::Distance(data.Center, target->Center_Coord()) - data.Distance) <= range) {
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 (object->Cloak == CLOAKED) return(false);
if (object->Is_Cloaked(this)) return(false);
/*
** 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("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();
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);
}
@ -2425,7 +2426,7 @@ BulletClass * TechnoClass::Fire_At(TARGET target, int which)
}
#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);
@ -2433,7 +2434,7 @@ BulletClass * TechnoClass::Fire_At(TARGET target, int which)
HousesType tgt_owner = obj->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)) {
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) {
best = 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);
}

View file

@ -280,8 +280,11 @@ class TechnoClass : public RadioClass,
virtual int Weapon_Range(int which) const;
virtual bool Captured(HouseClass * newowner);
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_Object(ThreatType method, int mask, 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 Is_Cloaked(HousesType house) const;
bool Is_Cloaked(HouseClass const * house) const;
bool Is_Cloaked(ObjectClass const * object) const;
/*
** AI.

View file

@ -361,6 +361,64 @@ FireErrorType TurretClass::Can_Fire(TARGET target, int which) const
* HISTORY: *
* 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 coord = Center_Coord();

View file

@ -75,6 +75,7 @@ class TurretClass : public DriveClass
virtual FireErrorType Can_Fire(TARGET target, int which) const;
virtual bool Ok_To_Move(DirType facing);
virtual void AI(void);
virtual FireDataType Fire_Data(int which) const;
virtual COORDINATE Fire_Coord(int which) const;
};

View file

@ -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">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">

View file

@ -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">
<ItemGroup>
<Filter Include="Source Files">

View file

@ -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
** 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();
Delete_This();
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.
*/
@ -1259,6 +1266,11 @@ void UnitClass::Player_Assign_Mission(MissionType mission, TARGET target, TARGET
Validate();
if (mission == MISSION_HARVEST) {
ArchiveTarget = TARGET_NONE;
} else if (mission == MISSION_ENTER) {
BuildingClass* building = As_Building(destination);
if (building != NULL && *building == STRUCT_REFINERY && building->In_Radio_Contact()) {
building->Transmit_Message(RADIO_OVER_OUT);
}
}
TarComClass::Player_Assign_Mission(mission, target, destination);
}
@ -1817,7 +1829,7 @@ void UnitClass::Per_Cell_Process(bool center)
} else {
TechnoClass * contact = Contact_With_Whom();
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);
} else if (!Target_Legal(NavCom)) {
Scatter(0, true);
@ -2308,7 +2320,7 @@ int UnitClass::Tiberium_Check(CELL &center, int x, int y)
//using function for IsVisible so we have different results for different players - JAS 2019/09/30
if ((GameToPlay != GAME_NORMAL || (!IsOwnedByPlayer || Map[center].Is_Visible(PlayerPtr)))) {
if (!Map[center].Cell_Techno() && Map[center].Land_Type() == LAND_TIBERIUM) {
return(Map[center].OverlayData);
return(Map[center].OverlayData+1);
}
}
return(0);
@ -2333,6 +2345,7 @@ bool UnitClass::Goto_Tiberium(void)
int tiberium = 0;
int besttiberium = 0;
for (int x = -radius; x <= radius; x++) {
cell = center;
tiberium = Tiberium_Check(cell, x, -radius);
if (tiberium > besttiberium) {
bestcell = cell;
@ -2657,7 +2670,14 @@ int UnitClass::Mission_Harvest(void)
*/
case LOOKING:
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;
Set_Rate(2);
Set_Stage(0);
@ -2853,7 +2873,7 @@ void UnitClass::Look(bool incremental)
{
Validate();
//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;
if (sight) {

View file

@ -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 **
;***************************************************************************

View file

@ -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 **
;***************************************************************************