commit
7dd96e38b7
407 changed files with 84520 additions and 927 deletions
|
@ -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
|
||||
);
|
||||
|
@ -2360,6 +2360,81 @@ static AnimTypeClass const ChemBall(
|
|||
ANIM_NONE
|
||||
);
|
||||
|
||||
static AnimTypeClass const Flag(
|
||||
ANIM_FLAG, // Animation number.
|
||||
"FLAGFLY", // Data name of animation.
|
||||
21, // Maximum dimension of animation.
|
||||
0, // Biggest animation stage.
|
||||
false, // Normalized animation rate?
|
||||
false, // Uses white translucent table?
|
||||
false, // Scorches the ground?
|
||||
false, // Forms a crater?
|
||||
false, // Sticks to unit in square?
|
||||
false, // Ground level animation?
|
||||
false, // Translucent colors in this animation?
|
||||
false, // Is this a flame thrower animation?
|
||||
0x0000, // Damage to apply per tick (fixed point).
|
||||
1, // Delay between frames.
|
||||
0, // Starting frame number.
|
||||
0, // Loop start frame number.
|
||||
-1, // Ending frame of loop back.
|
||||
-1, // Number of animation stages.
|
||||
-1, // Number of times the animation loops.
|
||||
VOC_NONE, // Sound effect to play.
|
||||
ANIM_NONE
|
||||
);
|
||||
|
||||
static AnimTypeClass const Beacon(
|
||||
ANIM_BEACON, // Animation number.
|
||||
"MOVEFLSH", // Data name of animation.
|
||||
21, // Maximum dimension of animation.
|
||||
0, // Biggest animation stage.
|
||||
false, // Normalized animation rate?
|
||||
false, // Uses white translucent table?
|
||||
false, // Scorches the ground?
|
||||
false, // Forms a crater?
|
||||
false, // Sticks to unit in square?
|
||||
false, // Ground level animation?
|
||||
false, // Translucent colors in this animation?
|
||||
false, // Is this a flame thrower animation?
|
||||
0x0000, // Damage to apply per tick (fixed point).
|
||||
1, // Delay between frames.
|
||||
0, // Starting frame number.
|
||||
0, // Loop start frame number.
|
||||
-1, // Ending frame of loop back.
|
||||
1, // Number of animation stages.
|
||||
-1, // Number of times the animation loops.
|
||||
VOC_NONE, // Sound effect to play.
|
||||
ANIM_NONE,
|
||||
-1, // Virtual stages
|
||||
0x100, // Virtual scale
|
||||
ANIM_BEACON_VIRTUAL // Virtual anim
|
||||
);
|
||||
|
||||
static AnimTypeClass const BeaconVirtual(
|
||||
ANIM_BEACON_VIRTUAL, // Animation number.
|
||||
"BEACON", // Data name of animation.
|
||||
21, // Maximum dimension of animation.
|
||||
0, // Biggest animation stage.
|
||||
false, // Normalized animation rate?
|
||||
false, // Uses white translucent table?
|
||||
false, // Scorches the ground?
|
||||
false, // Forms a crater?
|
||||
false, // Sticks to unit in square?
|
||||
false, // Ground level animation?
|
||||
false, // Translucent colors in this animation?
|
||||
false, // Is this a flame thrower animation?
|
||||
0x0000, // Damage to apply per tick (fixed point).
|
||||
1, // Delay between frames.
|
||||
0, // Starting frame number.
|
||||
0, // Loop start frame number.
|
||||
-1, // Ending frame of loop back.
|
||||
1, // Number of animation stages.
|
||||
-1, // Number of times the animation loops.
|
||||
VOC_NONE, // Sound effect to play.
|
||||
ANIM_NONE
|
||||
);
|
||||
|
||||
|
||||
|
||||
AnimTypeClass const * const AnimTypeClass::Pointers[ANIM_COUNT] = {
|
||||
|
@ -2459,10 +2534,13 @@ AnimTypeClass const * const AnimTypeClass::Pointers[ANIM_COUNT] = {
|
|||
&StegDie,
|
||||
&RaptDie,
|
||||
&ChemBall,
|
||||
&Flag,
|
||||
&Beacon,
|
||||
&Fire3Virtual,
|
||||
&Fire2Virtual,
|
||||
&Fire1Virtual,
|
||||
&Fire4Virtual
|
||||
&Fire4Virtual,
|
||||
&BeaconVirtual
|
||||
};
|
||||
|
||||
|
||||
|
@ -2502,7 +2580,7 @@ AnimTypeClass::AnimTypeClass(AnimType anim, char const *name, int size, int bigg
|
|||
IsWhiteTrans = iswhitetrans;
|
||||
LoopEnd = loopend;
|
||||
LoopStart = loopstart;
|
||||
Loops = (unsigned char)loops;
|
||||
Loops = (char)loops;
|
||||
Size = size;
|
||||
Sound = sound;
|
||||
Stages = stages;
|
||||
|
@ -2545,6 +2623,9 @@ void AnimTypeClass::One_Time(void)
|
|||
((void const *&)As_Reference(index).ImageData) = MixFileClass::Retrieve(fullname);
|
||||
}
|
||||
}
|
||||
|
||||
// Set up beacon image data manually since they're new animations only available in the virtual renderer
|
||||
((void const *&)As_Reference(ANIM_BEACON_VIRTUAL).ImageData) = As_Reference(ANIM_BEACON).ImageData;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -607,6 +616,10 @@ int AircraftClass::Mission_Hunt(void)
|
|||
{
|
||||
Validate();
|
||||
if (Class->IsFixedWing) {
|
||||
if (Class->Primary == WEAPON_NONE && Class->Secondary == WEAPON_NONE) {
|
||||
Assign_Mission(MISSION_RETREAT);
|
||||
return(1);
|
||||
}
|
||||
enum {
|
||||
LOOK_FOR_TARGET,
|
||||
FLY_TO_TARGET,
|
||||
|
@ -739,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();
|
||||
}
|
||||
|
||||
|
@ -1395,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);
|
||||
}
|
||||
|
@ -1600,10 +1627,15 @@ ResultType AircraftClass::Take_Damage(int & damage, int distance, WarheadType wa
|
|||
|
||||
switch (res) {
|
||||
case RESULT_DESTROYED:
|
||||
Kill_Cargo(source);
|
||||
Death_Announcement();
|
||||
new AnimClass(ANIM_FBALL1, Target_Coord());
|
||||
Delete_This();
|
||||
{
|
||||
Kill_Cargo(source);
|
||||
Death_Announcement();
|
||||
COORDINATE coord = Target_Coord();
|
||||
if (!(coord & 0xC000C000L)) {
|
||||
new AnimClass(ANIM_FBALL1, coord);
|
||||
}
|
||||
Delete_This();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1867,15 +1899,24 @@ void AircraftClass::Enter_Idle_Mode(bool )
|
|||
} else {
|
||||
|
||||
/*
|
||||
** Normal aircraft try to find a good landing spot to rest.
|
||||
** Continue with the current helipad if there is one.
|
||||
*/
|
||||
BuildingClass * building = Find_Docking_Bay(STRUCT_HELIPAD, false);
|
||||
Assign_Destination(TARGET_NONE);
|
||||
if (building && Transmit_Message(RADIO_HELLO, building) == RADIO_ROGER) {
|
||||
mission = MISSION_ENTER;
|
||||
if (!In_Radio_Contact() ||
|
||||
Contact_With_Whom()->What_Am_I() != RTTI_BUILDING ||
|
||||
*((BuildingClass*)Contact_With_Whom()) != STRUCT_HELIPAD) {
|
||||
/*
|
||||
** Normal aircraft try to find a good landing spot to rest.
|
||||
*/
|
||||
BuildingClass * building = Find_Docking_Bay(STRUCT_HELIPAD, false);
|
||||
Assign_Destination(TARGET_NONE);
|
||||
if (building && Transmit_Message(RADIO_HELLO, building) == RADIO_ROGER) {
|
||||
mission = MISSION_ENTER;
|
||||
} else {
|
||||
Assign_Destination(Good_LZ());
|
||||
mission = MISSION_MOVE;
|
||||
}
|
||||
} else {
|
||||
Assign_Destination(Good_LZ());
|
||||
mission = MISSION_MOVE;
|
||||
mission = MISSION_ENTER;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2166,7 +2207,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;
|
||||
}
|
||||
|
||||
|
@ -2336,6 +2377,11 @@ int AircraftClass::Mission_Attack(void)
|
|||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear second shot flag so fire burst works correctly.
|
||||
*/
|
||||
IsSecondShot = false;
|
||||
|
||||
PrimaryFacing.Set_Desired(Direction(TarCom));
|
||||
SecondaryFacing.Set_Desired(Direction(TarCom));
|
||||
switch (Can_Fire(TarCom, 0)) {
|
||||
|
@ -2429,7 +2475,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)))) {
|
||||
|
@ -2440,7 +2486,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;
|
||||
|
||||
/*
|
||||
|
@ -2829,8 +2875,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;
|
||||
|
@ -3536,4 +3583,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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -249,6 +249,8 @@ void AnimClass::Draw_It(int x, int y, WindowNumberType window)
|
|||
int shapenum = Class->Start + Fetch_Stage();
|
||||
void const * remap = NULL;
|
||||
ShapeFlags_Type flags = SHAPE_CENTER|SHAPE_WIN_REL;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
/*
|
||||
** Some animations require special fixups.
|
||||
|
@ -270,6 +272,18 @@ void AnimClass::Draw_It(int x, int y, WindowNumberType window)
|
|||
case ANIM_ATOM_BLAST:
|
||||
transtable = Map.UnitShadow;
|
||||
break;
|
||||
|
||||
case ANIM_FLAG:
|
||||
x += (ICON_PIXEL_W / 2) - 2;
|
||||
y += (3 * ICON_PIXEL_H / 4) - Get_Build_Frame_Height(shapefile);
|
||||
transtable = Map.UnitShadow;
|
||||
break;
|
||||
|
||||
case ANIM_BEACON_VIRTUAL:
|
||||
width = 29;
|
||||
height = 39;
|
||||
flags = flags | SHAPE_BOTTOM | SHAPE_COMPACT;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -285,7 +299,11 @@ void AnimClass::Draw_It(int x, int y, WindowNumberType window)
|
|||
*/
|
||||
if (IsAlternate) {
|
||||
flags = flags | SHAPE_FADING;
|
||||
remap = Map.RemapTables[HOUSE_GOOD][0];
|
||||
if (OwnerHouse != HOUSE_NONE) {
|
||||
remap = HouseClass::As_Pointer(OwnerHouse)->Remap_Table(false, false);
|
||||
} else {
|
||||
remap = Map.RemapTables[HOUSE_GOOD][0];
|
||||
}
|
||||
}
|
||||
if (transtable) flags = flags | SHAPE_GHOST;
|
||||
|
||||
|
@ -293,7 +311,7 @@ void AnimClass::Draw_It(int x, int y, WindowNumberType window)
|
|||
** Draw the animation shape, but ignore legacy if beyond normal stage count.
|
||||
*/
|
||||
if ((window == WINDOW_VIRTUAL) || (Fetch_Stage() < Class->Stages)) {
|
||||
CC_Draw_Shape(this, shapefile, shapenum, x, y, window, flags, remap, transtable, Class->VirtualScale);
|
||||
CC_Draw_Shape(this, shapefile, shapenum, x, y, window, flags, remap, transtable, Class->VirtualScale, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -380,6 +398,8 @@ short const * AnimClass::Overlap_List(void) const
|
|||
REFRESH_EOL
|
||||
};
|
||||
|
||||
static short const OverlapFlag[] = { 0, 1, -MAP_CELL_W, -(MAP_CELL_W-1), MAP_CELL_W, MAP_CELL_W+1, REFRESH_EOL };
|
||||
|
||||
switch (Class->Type) {
|
||||
case ANIM_CHEM_N:
|
||||
case ANIM_FLAME_N:
|
||||
|
@ -419,6 +439,9 @@ short const * AnimClass::Overlap_List(void) const
|
|||
case ANIM_ATOM_BLAST:
|
||||
return(OverlapAtom);
|
||||
|
||||
case ANIM_FLAG:
|
||||
return(OverlapFlag);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -550,12 +573,13 @@ void AnimClass::operator delete(void *ptr)
|
|||
* 05/31/1994 JLB : Created. *
|
||||
* 08/03/1994 JLB : Added a delayed affect parameter. *
|
||||
*=============================================================================================*/
|
||||
AnimClass::AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay, unsigned char loop, bool alt) :
|
||||
AnimClass::AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay, char loop, bool alt) :
|
||||
Class(&AnimTypeClass::As_Reference(animnum))
|
||||
{
|
||||
Object = 0;
|
||||
SortTarget = TARGET_NONE;
|
||||
Owner = HOUSE_NONE;
|
||||
OwnerHouse = HOUSE_NONE;
|
||||
KillTime = 0ULL;
|
||||
|
||||
if (Class->Stages == -1) {
|
||||
((int&)Class->Stages) = Get_Build_Frame_Count(Class->Get_Image_Data());
|
||||
|
@ -574,7 +598,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.
|
||||
|
@ -590,8 +614,12 @@ AnimClass::AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay
|
|||
*/
|
||||
Delay = timedelay;
|
||||
|
||||
Loops = (unsigned char)(MAX(loop, (unsigned char)1) * Class->Loops);
|
||||
Loops = (unsigned char)MAX(Loops, (unsigned char)1);
|
||||
if (Class->Loops >= 0) {
|
||||
Loops = (char)(MAX(loop, (char)1) * Class->Loops);
|
||||
Loops = (char)MAX(Loops, (char)1);
|
||||
} else {
|
||||
Loops = Class->Loops;
|
||||
}
|
||||
|
||||
IsToDelete = false;
|
||||
IsBrandNew = true;
|
||||
|
@ -609,7 +637,7 @@ AnimClass::AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay
|
|||
** Check for a virtual animation
|
||||
*/
|
||||
if (Class->VirtualAnim != ANIM_NONE) {
|
||||
VirtualAnim = new AnimClass(Class->VirtualAnim, 0, timedelay, loop, alt);
|
||||
VirtualAnim = new AnimClass(Class->VirtualAnim, Coord, timedelay, loop, alt);
|
||||
if (VirtualAnim != NULL) {
|
||||
VirtualAnim->Make_Invisible();
|
||||
}
|
||||
|
@ -713,6 +741,19 @@ void AnimClass::AI(void)
|
|||
IsToDelete = true;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check the kill time.
|
||||
*/
|
||||
if (KillTime > 0ULL) {
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
|
||||
unsigned long long now = (unsigned long long)ft.dwLowDateTime + ((unsigned long long)ft.dwHighDateTime << 32ULL);
|
||||
if (now >= KillTime) {
|
||||
IsToDelete = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete this animation and bail early if the animation is flagged to be deleted
|
||||
** immediately.
|
||||
|
@ -732,6 +773,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) {
|
||||
|
@ -769,10 +820,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;
|
||||
}
|
||||
}
|
||||
|
@ -798,8 +849,8 @@ void AnimClass::AI(void)
|
|||
** Determine if this animation should loop another time. If so, then start the loop
|
||||
** but if not, then proceed into the animation termination handler.
|
||||
*/
|
||||
if (Loops) Loops--;
|
||||
if (Loops) {
|
||||
if (Loops > 0) Loops--;
|
||||
if (Loops != 0) {
|
||||
Set_Stage(Class->LoopStart);
|
||||
} else {
|
||||
if (Class->VirtualAnim != ANIM_NONE) {
|
||||
|
@ -992,11 +1043,11 @@ void AnimClass::Middle(void)
|
|||
*/
|
||||
BuildingClass * building = NULL;
|
||||
TechnoClass * backup = NULL;
|
||||
if (Owner != HOUSE_NONE) {
|
||||
if (OwnerHouse != HOUSE_NONE) {
|
||||
for (int index = 0; index < Logic.Count(); index++) {
|
||||
ObjectClass * obj = Logic[index];
|
||||
|
||||
if (obj && obj->Is_Techno() && obj->Owner() == Owner) {
|
||||
if (obj && obj->Is_Techno() && obj->Owner() == OwnerHouse) {
|
||||
backup = (TechnoClass *)obj;
|
||||
if (obj->What_Am_I() == RTTI_BUILDING && *((BuildingClass *)obj) == STRUCT_TEMPLE) {
|
||||
building = (BuildingClass *)obj;
|
||||
|
@ -1108,11 +1159,11 @@ void AnimClass::Middle(void)
|
|||
case ANIM_ION_CANNON: {
|
||||
BuildingClass * building = NULL;
|
||||
TechnoClass * backup = NULL;
|
||||
if (Owner != HOUSE_NONE) {
|
||||
if (OwnerHouse != HOUSE_NONE) {
|
||||
for (int index = 0; index < Logic.Count(); index++) {
|
||||
ObjectClass * obj = Logic[index];
|
||||
|
||||
if (obj && obj->Is_Techno() && obj->Owner() == Owner && !obj->IsInLimbo) {
|
||||
if (obj && obj->Is_Techno() && obj->Owner() == OwnerHouse && !obj->IsInLimbo) {
|
||||
backup = (TechnoClass *)obj;
|
||||
if (obj->What_Am_I() == RTTI_BUILDING && *((BuildingClass *)obj) == STRUCT_EYE) {
|
||||
building = (BuildingClass *)obj;
|
||||
|
@ -1253,6 +1304,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());
|
||||
|
@ -1260,4 +1314,20 @@ void AnimClass::Detach(TARGET target, bool all)
|
|||
IsToDelete = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimClass::Set_Owner(HousesType owner)
|
||||
{
|
||||
OwnerHouse = owner;
|
||||
if (VirtualAnim != NULL) {
|
||||
VirtualAnim->Set_Owner(owner);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimClass::Set_Visible_Flags(unsigned flags)
|
||||
{
|
||||
VisibleFlags = flags;
|
||||
if (VirtualAnim != NULL) {
|
||||
VirtualAnim->Set_Visible_Flags(flags);
|
||||
}
|
||||
}
|
|
@ -47,11 +47,12 @@ class AnimClass : public ObjectClass, private StageClass {
|
|||
|
||||
static void * AnimClass::operator new(size_t size);
|
||||
static void AnimClass::operator delete(void *ptr);
|
||||
AnimClass(void) : Class(0) {Owner=HOUSE_NONE;Object=0;}; // Default constructor does nothing.
|
||||
AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay=0, unsigned char loop=1, bool alt=false);
|
||||
AnimClass(void) : Class(0) {OwnerHouse=HOUSE_NONE;Object=0;}; // Default constructor does nothing.
|
||||
AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay=0, char loop=1, bool alt=false);
|
||||
virtual ~AnimClass(void);
|
||||
operator AnimType(void) const {return Class->Type;};
|
||||
virtual RTTIType What_Am_I(void) const {return RTTI_ANIM;};
|
||||
virtual HousesType Owner(void) const {return OwnerHouse;};
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
** Member function prototypes.
|
||||
|
@ -62,14 +63,16 @@ class AnimClass : public ObjectClass, private StageClass {
|
|||
void Sort_Above(TARGET target);
|
||||
void Make_Invisible(void) {IsInvisible = true;};
|
||||
void Make_Visible(void) {IsInvisible = false;};
|
||||
void Kill_At(unsigned long long kill_time) {KillTime = kill_time;}
|
||||
|
||||
/*
|
||||
** 2019/09/19 JAS
|
||||
** Added functions for accessing which players can see this anim
|
||||
*/
|
||||
void Set_Visible_Flags(unsigned flags) { VisibleFlags = flags; }
|
||||
void Set_Visible_Flags(unsigned flags);
|
||||
unsigned Get_Visible_Flags() const { return (Delay == 0) ? VisibleFlags : 0; }
|
||||
|
||||
virtual void Set_Owner(HousesType owner);
|
||||
virtual bool Can_Place_Here(COORDINATE ) const {return true;}
|
||||
virtual bool Mark(MarkType mark=MARK_CHANGE);
|
||||
virtual bool Render(bool forced);
|
||||
|
@ -114,13 +117,13 @@ class AnimClass : public ObjectClass, private StageClass {
|
|||
** is used when damage is caused by this animation during the middle of its
|
||||
** animation.
|
||||
*/
|
||||
HousesType Owner;
|
||||
HousesType OwnerHouse;
|
||||
|
||||
/*
|
||||
** This counter tells how many more times the animation should loop before it
|
||||
** terminates.
|
||||
*/
|
||||
unsigned char Loops;
|
||||
char Loops;
|
||||
|
||||
protected:
|
||||
void Middle(void);
|
||||
|
@ -146,7 +149,9 @@ class AnimClass : public ObjectClass, private StageClass {
|
|||
*/
|
||||
unsigned IsBrandNew:1;
|
||||
|
||||
// Use alternate color when drawing?
|
||||
/*
|
||||
** Use alternate color when drawing
|
||||
*/
|
||||
unsigned IsAlternate:1;
|
||||
|
||||
/*
|
||||
|
@ -191,10 +196,15 @@ class AnimClass : public ObjectClass, private StageClass {
|
|||
*/
|
||||
AnimClass * VirtualAnim;
|
||||
|
||||
/*
|
||||
** Real-time point to kill this animation.
|
||||
*/
|
||||
unsigned long long KillTime;
|
||||
|
||||
/*
|
||||
** 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[24];
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -254,6 +254,7 @@ struct SoundEffectNameStruct {
|
|||
{"DINOYES", 10, IN_NOVAR}, // VOC_DINOYES Yes Sir in dino-speak.
|
||||
{"DINOATK1", 10, IN_NOVAR}, // VOC_DINOATK1 Dino attack sound.
|
||||
{"DINODIE1", 10, IN_NOVAR}, // VOC_DINODIE1 Dino die sound.
|
||||
{"BEACON", 10, IN_NOVAR }, // VOC_BEACON Beacon sound.
|
||||
|
||||
#ifdef PETROGLYPH_EXAMPLE_MOD
|
||||
{"NUKE_LOB", 10, IN_NOVAR} // VOC_NUKE_LOB Mod expansion unit firing sound
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -293,7 +293,32 @@ RadioMessageType BuildingClass::Receive_Message(RadioClass * from, RadioMessageT
|
|||
Begin_Mode(BSTATE_FULL);
|
||||
}
|
||||
|
||||
if (Transmit_Message(RADIO_NEED_TO_MOVE, from) == RADIO_ROGER) {
|
||||
/*
|
||||
** If this building is already in radio contact, then it might
|
||||
** be able to satisfy the request to load by bumping off any
|
||||
** preoccupying task.
|
||||
*/
|
||||
if (*this == STRUCT_REPAIR) {
|
||||
if (Contact_With_Whom() != from) {
|
||||
if (Transmit_Message(RADIO_ON_DEPOT) == RADIO_ROGER) {
|
||||
if (Transmit_Message(RADIO_NEED_REPAIR) == RADIO_NEGATIVE) {
|
||||
Transmit_Message(RADIO_RUN_AWAY);
|
||||
Transmit_Message(RADIO_OVER_OUT);
|
||||
return(RADIO_ROGER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Establish contact with the object if this building isn't already in contact
|
||||
** with another.
|
||||
*/
|
||||
if (!In_Radio_Contact()) {
|
||||
Transmit_Message(RADIO_HELLO, from);
|
||||
}
|
||||
|
||||
if (Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER) {
|
||||
if (*this == STRUCT_HELIPAD) {
|
||||
param = As_Target();
|
||||
} else {
|
||||
|
@ -308,7 +333,7 @@ RadioMessageType BuildingClass::Receive_Message(RadioClass * from, RadioMessageT
|
|||
/*
|
||||
** Tell the harvester to move to the docking pad of the refinery.
|
||||
*/
|
||||
if (Transmit_Message(RADIO_MOVE_HERE, param, from) == RADIO_YEA_NOW_WHAT) {
|
||||
if (Transmit_Message(RADIO_MOVE_HERE, param) == RADIO_YEA_NOW_WHAT) {
|
||||
|
||||
/*
|
||||
** Since the harvester is already there, tell it to begin the backup
|
||||
|
@ -1141,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1899,7 +1926,7 @@ void BuildingClass::Drop_Debris(TARGET source)
|
|||
CELL cell;
|
||||
|
||||
/*
|
||||
** Special case for Moebius to run from destroyed technology
|
||||
** Special case for Chan to run from destroyed technology
|
||||
** building.
|
||||
*/
|
||||
if (GameToPlay == GAME_NORMAL && *this == STRUCT_MISSION && PlayerPtr->ActLike == HOUSE_BAD && Scenario == 10) {
|
||||
|
@ -1907,7 +1934,7 @@ void BuildingClass::Drop_Debris(TARGET source)
|
|||
|
||||
ScenarioInit++;
|
||||
if (i->Unlimbo(Center_Coord(), DIR_N)) {
|
||||
i->Trigger = TriggerClass::As_Pointer("CHAN");
|
||||
i->Trigger = TriggerClass::As_Pointer("win");
|
||||
i->Strength = Random_Pick(5, (int)i->Class->MaxStrength);
|
||||
ScenarioInit--;
|
||||
i->Scatter(0, true);
|
||||
|
@ -1915,6 +1942,7 @@ void BuildingClass::Drop_Debris(TARGET source)
|
|||
i->Assign_Mission(MISSION_GUARD_AREA);
|
||||
} else {
|
||||
delete i;
|
||||
PlayerPtr->Flag_To_Win();
|
||||
}
|
||||
ScenarioInit--;
|
||||
}
|
||||
|
@ -2049,7 +2077,7 @@ void BuildingClass::Active_Click_With(ActionType action, CELL cell)
|
|||
OutList.Add(EventClass(EventClass::SELL, As_Target()));
|
||||
|
||||
COORDINATE coord = Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y());
|
||||
OutList.Add(EventClass(ANIM_MOVE_FLASH, PlayerPtr->Class->House, coord));
|
||||
OutList.Add(EventClass(ANIM_MOVE_FLASH, PlayerPtr->Class->House, coord, 1 << PlayerPtr->Class->House));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2708,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();
|
||||
|
@ -3493,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);
|
||||
|
@ -3523,7 +3590,7 @@ bool BuildingClass::Toggle_Primary(void)
|
|||
bool BuildingClass::Captured(HouseClass * newowner)
|
||||
{
|
||||
Validate();
|
||||
if (Class->IsCaptureable && newowner != House) {
|
||||
if (Can_Capture() && newowner != House) {
|
||||
switch (Owner()) {
|
||||
case HOUSE_GOOD:
|
||||
Speak(VOX_GDI_CAPTURED);
|
||||
|
@ -3803,6 +3870,21 @@ bool BuildingClass::Can_Demolish_Unit(void) const
|
|||
}
|
||||
|
||||
|
||||
bool BuildingClass::Can_Capture(void) const
|
||||
{
|
||||
bool can_capture = Class->IsCaptureable && Mission != MISSION_DECONSTRUCTION;
|
||||
|
||||
// Override capturable state if this building has a capture win trigger
|
||||
if (GameToPlay == GAME_NORMAL) {
|
||||
if (!House->IsHuman && Trigger != NULL && Trigger->Action == TriggerClass::ACTION_WINLOSE) {
|
||||
can_capture = true;
|
||||
}
|
||||
}
|
||||
|
||||
return(can_capture);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* BuildingClass::Mission_Guard -- Handles guard mission for combat buildings. *
|
||||
* *
|
||||
|
@ -4052,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
|
||||
|
@ -4072,6 +4161,7 @@ int BuildingClass::Mission_Deconstruction(void)
|
|||
Status = DURING;
|
||||
Begin_Mode(BSTATE_CONSTRUCTION);
|
||||
IsReadyToCommence = false;
|
||||
IsSurvivorless = true;
|
||||
break;
|
||||
}
|
||||
Transmit_Message(RADIO_RUN_AWAY);
|
||||
|
@ -4516,6 +4606,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;
|
||||
|
@ -5020,7 +5115,8 @@ int BuildingClass::Mission_Unload(void)
|
|||
** Scatter everything around the weapon's factory door.
|
||||
*/
|
||||
for (FacingType f = FACING_FIRST; f < FACING_COUNT; f++) {
|
||||
CellClass * cptr = &cellptr->Adjacent_Cell(f);
|
||||
CellClass * cptr = cellptr->Adjacent_Cell(f);
|
||||
if (!cptr) continue;
|
||||
UnitClass * cellunit = cptr->Cell_Unit();
|
||||
if ((cellunit && cellunit != unit) || cptr->Cell_Infantry()) {
|
||||
cptr->Incoming(coord, true, true);
|
||||
|
|
|
@ -185,6 +185,7 @@ class BuildingClass : public TechnoClass
|
|||
virtual ActionType What_Action(CELL cell) const;
|
||||
virtual bool Can_Demolish(void) const;
|
||||
virtual bool Can_Demolish_Unit(void) const;
|
||||
virtual bool Can_Capture(void) const;
|
||||
virtual ObjectTypeClass const & Class_Of(void) const {return *Class;};
|
||||
virtual int Refund_Amount(void) const;
|
||||
virtual DirType Fire_Direction(void) const;
|
||||
|
@ -195,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;
|
||||
|
|
|
@ -471,9 +471,9 @@ void BulletClass::AI(void)
|
|||
// Fix for Nuke or Atom Bomb killing structures and units during animation sequence and not getting kills tracked
|
||||
// Per https://jaas.ea.com/browse/TDRA-6610
|
||||
//
|
||||
if (newanim && Class->Explosion == ANIM_ATOM_BLAST && newanim->Owner == HOUSE_NONE) {
|
||||
if (newanim && Class->Explosion == ANIM_ATOM_BLAST && newanim->OwnerHouse == HOUSE_NONE) {
|
||||
if (Payback && Payback->House && Payback->House->Class) {
|
||||
newanim->Owner = Payback->House->Class->House;
|
||||
newanim->Set_Owner(Payback->House->Class->House);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1824,7 +1824,7 @@ static TemplateTypeClass const Patch15(
|
|||
"P15",
|
||||
TXT_PATCH,
|
||||
LAND_CLEAR,
|
||||
1,1,
|
||||
4,2,
|
||||
LAND_CLEAR,
|
||||
NULL
|
||||
);
|
||||
|
|
|
@ -211,7 +211,7 @@ TechnoClass * CellClass::Cell_Techno(int x, int y) const
|
|||
|
||||
if (Cell_Occupier()) {
|
||||
object = Cell_Occupier();
|
||||
while (object) {
|
||||
while (object && object->IsActive) {
|
||||
if (object->Is_Techno()) {
|
||||
COORDINATE coord; // Coordinate relative to cell corner.
|
||||
long dist;
|
||||
|
@ -248,7 +248,7 @@ ObjectClass * CellClass::Cell_Find_Object(RTTIType rtti) const
|
|||
Validate();
|
||||
ObjectClass * object = Cell_Occupier();
|
||||
|
||||
while (object) {
|
||||
while (object && object->IsActive) {
|
||||
if (object->What_Am_I() == rtti) {
|
||||
return(object);
|
||||
}
|
||||
|
@ -389,7 +389,9 @@ void CellClass::Redraw_Objects(bool forced)
|
|||
if (Cell_Occupier()) {
|
||||
ObjectClass * optr = Cell_Occupier();
|
||||
while (optr) {
|
||||
optr->Mark(MARK_CHANGE);
|
||||
if (optr->IsActive) {
|
||||
optr->Mark(MARK_CHANGE);
|
||||
}
|
||||
optr = optr->Next;
|
||||
}
|
||||
}
|
||||
|
@ -1132,14 +1134,6 @@ void CellClass::Draw_It(int x, int y, int draw_type) const
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Draw the flag if there is one located at this cell.
|
||||
*/
|
||||
if (IsFlagged) {
|
||||
void const * remap = HouseClass::As_Pointer(Owner)->Remap_Table(false, false);
|
||||
CC_Draw_Shape(MixFileClass::Retrieve("FLAGFLY.SHP"), Frame % 14, x+(ICON_PIXEL_W/2), y+(ICON_PIXEL_H/2), WINDOW_TACTICAL, SHAPE_CENTER|SHAPE_GHOST|SHAPE_FADING, remap, Map.UnitShadow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1202,13 +1196,13 @@ void CellClass::Concrete_Calc(void)
|
|||
*/
|
||||
index = 0;
|
||||
for (int i = 0; i < (sizeof(_even)/sizeof(_even[0])); i++) {
|
||||
CellClass & cellptr = Adjacent_Cell(*ptr++);
|
||||
CellClass * cellptr = Adjacent_Cell(*ptr++);
|
||||
|
||||
// if ((cellptr->IsConcrete) ||
|
||||
// cellptr->Concrete == C_UPDOWN_RIGHT ||
|
||||
// cellptr->Concrete == C_UPDOWN_LEFT) {
|
||||
|
||||
if (cellptr.Overlay == OVERLAY_CONCRETE) {
|
||||
if (cellptr && cellptr->Overlay == OVERLAY_CONCRETE) {
|
||||
index |= (1<<i);
|
||||
}
|
||||
}
|
||||
|
@ -1399,9 +1393,9 @@ void CellClass::Wall_Update(void)
|
|||
}
|
||||
|
||||
for (unsigned index = 0; index < (sizeof(_offsets)/sizeof(_offsets[0])); index++) {
|
||||
CellClass & newcell = Adjacent_Cell(_offsets[index]);
|
||||
CellClass * newcell = Adjacent_Cell(_offsets[index]);
|
||||
|
||||
if (newcell.Overlay != OVERLAY_NONE && OverlayTypeClass::As_Reference(newcell.Overlay).IsWall) {
|
||||
if (newcell && newcell->Overlay != OVERLAY_NONE && OverlayTypeClass::As_Reference(newcell->Overlay).IsWall) {
|
||||
int icon = 0;
|
||||
|
||||
/*
|
||||
|
@ -1409,41 +1403,42 @@ void CellClass::Wall_Update(void)
|
|||
** cells.
|
||||
*/
|
||||
for (unsigned i = 0; i < 4; i++) {
|
||||
if (newcell.Adjacent_Cell(_offsets[i]).Overlay == newcell.Overlay) {
|
||||
CellClass * adjcell = newcell->Adjacent_Cell(_offsets[i]);
|
||||
if (adjcell && adjcell->Overlay == newcell->Overlay) {
|
||||
icon |= 1 << i;
|
||||
}
|
||||
}
|
||||
newcell.OverlayData = (newcell.OverlayData & 0xFFF0) | icon;
|
||||
// newcell.OverlayData = icon;
|
||||
newcell->OverlayData = (newcell->OverlayData & 0xFFF0) | icon;
|
||||
// newcell->OverlayData = icon;
|
||||
|
||||
/*
|
||||
** Handle special cases for the incomplete damaged wall sets. If a damage stage
|
||||
** is calculated, but there is no artwork for it, then consider the wall to be
|
||||
** completely destroyed.
|
||||
*/
|
||||
if (newcell.Overlay == OVERLAY_BRICK_WALL && newcell.OverlayData == 48) {
|
||||
newcell.Overlay = OVERLAY_NONE;
|
||||
newcell.OverlayData = 0;
|
||||
ObjectClass::Detach_This_From_All(::As_Target(newcell.Cell_Number()), true);
|
||||
if (newcell->Overlay == OVERLAY_BRICK_WALL && newcell->OverlayData == 48) {
|
||||
newcell->Overlay = OVERLAY_NONE;
|
||||
newcell->OverlayData = 0;
|
||||
ObjectClass::Detach_This_From_All(::As_Target(newcell->Cell_Number()), true);
|
||||
}
|
||||
if (newcell.Overlay == OVERLAY_SANDBAG_WALL && newcell.OverlayData == 16) {
|
||||
newcell.Overlay = OVERLAY_NONE;
|
||||
newcell.OverlayData = 0;
|
||||
ObjectClass::Detach_This_From_All(::As_Target(newcell.Cell_Number()), true);
|
||||
if (newcell->Overlay == OVERLAY_SANDBAG_WALL && newcell->OverlayData == 16) {
|
||||
newcell->Overlay = OVERLAY_NONE;
|
||||
newcell->OverlayData = 0;
|
||||
ObjectClass::Detach_This_From_All(::As_Target(newcell->Cell_Number()), true);
|
||||
}
|
||||
if (newcell.Overlay == OVERLAY_CYCLONE_WALL && newcell.OverlayData == 32) {
|
||||
newcell.Overlay = OVERLAY_NONE;
|
||||
newcell.OverlayData = 0;
|
||||
ObjectClass::Detach_This_From_All(::As_Target(newcell.Cell_Number()), true);
|
||||
if (newcell->Overlay == OVERLAY_CYCLONE_WALL && newcell->OverlayData == 32) {
|
||||
newcell->Overlay = OVERLAY_NONE;
|
||||
newcell->OverlayData = 0;
|
||||
ObjectClass::Detach_This_From_All(::As_Target(newcell->Cell_Number()), true);
|
||||
}
|
||||
if (newcell.Overlay == OVERLAY_BARBWIRE_WALL && newcell.OverlayData == 16) {
|
||||
newcell.Overlay = OVERLAY_NONE;
|
||||
newcell.OverlayData = 0;
|
||||
ObjectClass::Detach_This_From_All(::As_Target(newcell.Cell_Number()), true);
|
||||
if (newcell->Overlay == OVERLAY_BARBWIRE_WALL && newcell->OverlayData == 16) {
|
||||
newcell->Overlay = OVERLAY_NONE;
|
||||
newcell->OverlayData = 0;
|
||||
ObjectClass::Detach_This_From_All(::As_Target(newcell->Cell_Number()), true);
|
||||
}
|
||||
|
||||
newcell.Recalc_Attributes();
|
||||
newcell.Redraw_Objects();
|
||||
newcell->Recalc_Attributes();
|
||||
newcell->Redraw_Objects();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1550,10 +1545,14 @@ int CellClass::Reduce_Wall(int damage)
|
|||
OverlayData = 0;
|
||||
Recalc_Attributes();
|
||||
Redraw_Objects();
|
||||
Adjacent_Cell(FACING_N).Wall_Update();
|
||||
Adjacent_Cell(FACING_W).Wall_Update();
|
||||
Adjacent_Cell(FACING_S).Wall_Update();
|
||||
Adjacent_Cell(FACING_E).Wall_Update();
|
||||
CellClass * ncell = Adjacent_Cell(FACING_N);
|
||||
if (ncell) ncell->Wall_Update();
|
||||
CellClass * wcell = Adjacent_Cell(FACING_W);
|
||||
if (wcell) wcell->Wall_Update();
|
||||
CellClass * scell = Adjacent_Cell(FACING_S);
|
||||
if (scell) scell->Wall_Update();
|
||||
CellClass * ecell = Adjacent_Cell(FACING_E);
|
||||
if (ecell) ecell->Wall_Update();
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
|
@ -1813,28 +1812,23 @@ void CellClass::Incoming(COORDINATE threat, bool forced, bool nokidding)
|
|||
* HISTORY: *
|
||||
* 03/19/1995 JLB : Created. *
|
||||
*=============================================================================================*/
|
||||
CellClass const & CellClass::Adjacent_Cell(FacingType face) const
|
||||
CellClass const * CellClass::Adjacent_Cell(FacingType face) const
|
||||
{
|
||||
Validate();
|
||||
if (face == FACING_NONE) {
|
||||
return(this);
|
||||
}
|
||||
|
||||
if ((unsigned)face >= FACING_COUNT) {
|
||||
return(*this);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
CELL id = Cell_Number();
|
||||
//The top row doesn't have any adjacent cells to the north. - LLL
|
||||
if (id < MAP_CELL_W && (face == FACING_N || face == FACING_NE || face == FACING_NW)) {
|
||||
return (*this);
|
||||
CELL newcell = ::Adjacent_Cell(Cell_Number(), face);
|
||||
if ((unsigned)newcell >= MAP_CELL_TOTAL) {
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
//The bottom row doesn't have any adjacent cells to the south. - LLL
|
||||
if ((id > MAP_CELL_TOTAL - MAP_CELL_W) && (face == FACING_S || face == FACING_SE || face == FACING_SW)) {
|
||||
return (*this);
|
||||
}
|
||||
|
||||
CellClass const * ptr = this + AdjacentCell[face];
|
||||
if (ptr->Cell_Number() & 0xF000) return(*this);
|
||||
return(*ptr);
|
||||
// return(*(this + AdjacentCell[face]));
|
||||
return &Map[newcell];
|
||||
}
|
||||
|
||||
|
||||
|
@ -1911,10 +1905,10 @@ long CellClass::Tiberium_Adjust(bool pregame)
|
|||
CELL cell = Cell_Number() + AdjacentCell[face];
|
||||
if ((unsigned)cell >= MAP_CELL_TOTAL) continue;
|
||||
|
||||
CellClass & adj = Adjacent_Cell(face);
|
||||
CellClass * adj = Adjacent_Cell(face);
|
||||
|
||||
if (adj.Overlay != OVERLAY_NONE &&
|
||||
OverlayTypeClass::As_Reference(adj.Overlay).Land == LAND_TIBERIUM) {
|
||||
if (adj && adj->Overlay != OVERLAY_NONE &&
|
||||
OverlayTypeClass::As_Reference(adj->Overlay).Land == LAND_TIBERIUM) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
@ -1944,7 +1938,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 {
|
||||
|
@ -1998,21 +1992,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;
|
||||
|
@ -2386,6 +2389,7 @@ bool CellClass::Flag_Place(HousesType house)
|
|||
if (!IsFlagged && Is_Generally_Clear()) {
|
||||
IsFlagged = true;
|
||||
Owner = house;
|
||||
Flag_Update();
|
||||
Redraw_Objects();
|
||||
return(true);
|
||||
}
|
||||
|
@ -2413,6 +2417,7 @@ bool CellClass::Flag_Remove(void)
|
|||
if (IsFlagged) {
|
||||
IsFlagged = false;
|
||||
Owner = HOUSE_NONE;
|
||||
Flag_Update();
|
||||
Redraw_Objects();
|
||||
return(true);
|
||||
}
|
||||
|
@ -2420,6 +2425,43 @@ bool CellClass::Flag_Remove(void)
|
|||
}
|
||||
|
||||
|
||||
void CellClass::Flag_Update(void)
|
||||
{
|
||||
if (IsFlagged && !CTFFlag) {
|
||||
Flag_Create();
|
||||
} else if (!IsFlagged && CTFFlag) {
|
||||
Flag_Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CellClass::Flag_Create(void)
|
||||
{
|
||||
if (!CTFFlag) {
|
||||
CTFFlag = new AnimClass(ANIM_FLAG, Cell_Coord(), 0, 1, true);
|
||||
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->Set_Owner(Owner);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CellClass::Flag_Destroy(void)
|
||||
{
|
||||
delete CTFFlag;
|
||||
CTFFlag = NULL;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CellClass::Shimmer -- Causes all objects in the cell to shimmer. *
|
||||
* *
|
||||
|
|
|
@ -194,8 +194,8 @@ class CellClass
|
|||
bool Is_Generally_Clear(bool ignore_cloaked = false) const;
|
||||
TARGET As_Target(void) const {return ::As_Target(Cell_Number());};
|
||||
BuildingClass * Cell_Building(void) const;
|
||||
CellClass const & Adjacent_Cell(FacingType face) const;
|
||||
CellClass & Adjacent_Cell(FacingType face) {return (CellClass &)((*((CellClass const *)this)).Adjacent_Cell(face));};
|
||||
CellClass const * Adjacent_Cell(FacingType face) const;
|
||||
CellClass * Adjacent_Cell(FacingType face) {return (CellClass *)((*((CellClass const *)this)).Adjacent_Cell(face));};
|
||||
COORDINATE Cell_Coord(void) const;
|
||||
int Cell_Color(bool override=false) const;
|
||||
CELL Cell_Number(void) const;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -221,6 +221,9 @@ class CellClass
|
|||
void Overlap_Up(ObjectClass * object);
|
||||
bool Flag_Place(HousesType house);
|
||||
bool Flag_Remove(void);
|
||||
void Flag_Update(void);
|
||||
void Flag_Create(void);
|
||||
void Flag_Destroy(void);
|
||||
|
||||
/*
|
||||
** File I/O.
|
||||
|
@ -286,10 +289,15 @@ class CellClass
|
|||
|
||||
LandType OverrideLand; // The overriden land type of this cell.
|
||||
|
||||
/*
|
||||
** Points to the flag animation on this cell in CTF games.
|
||||
*/
|
||||
AnimClass* CTFFlag;
|
||||
|
||||
/*
|
||||
** 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];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -160,7 +160,8 @@ void Explosion_Damage(COORDINATE coord, unsigned strength, TechnoClass * source,
|
|||
** further than one cell away.
|
||||
*/
|
||||
if (i != FACING_NONE) {
|
||||
cellptr = &Map[cell].Adjacent_Cell(i);
|
||||
cellptr = Map[cell].Adjacent_Cell(i);
|
||||
if (!cellptr) continue;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -2730,11 +2730,11 @@ extern void DLL_Draw_Intercept(int shape_number, int x, int y, int width, int he
|
|||
extern void DLL_Draw_Pip_Intercept(const ObjectClass* object, int pip);
|
||||
extern void DLL_Draw_Line_Intercept(int x, int y, int x1, int y1, unsigned char color, int frame);
|
||||
|
||||
void CC_Draw_Shape(ObjectClass *object, void const * shapefile, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const * fadingdata, void const * ghostdata, int scale)
|
||||
void CC_Draw_Shape(ObjectClass *object, void const * shapefile, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const * fadingdata, void const * ghostdata, int scale, int width, int height)
|
||||
{
|
||||
if (window == WINDOW_VIRTUAL) {
|
||||
int width = Get_Build_Frame_Width(shapefile);
|
||||
int height = Get_Build_Frame_Height(shapefile);
|
||||
if (width == 0) width = Get_Build_Frame_Width(shapefile);
|
||||
if (height == 0) height = Get_Build_Frame_Height(shapefile);
|
||||
DLL_Draw_Intercept(shapenum, x, y, width, height, (int)flags, object, NULL, -1, scale);
|
||||
return;
|
||||
}
|
||||
|
@ -3140,15 +3140,13 @@ void Handle_Team(int team, int action)
|
|||
** If a non team member is currently selected, then deselect all objects
|
||||
** before selecting this team.
|
||||
*/
|
||||
if (CurrentObject.Count()) {
|
||||
switch (CurrentObject[0]->What_Am_I()) {
|
||||
case RTTI_UNIT:
|
||||
case RTTI_INFANTRY:
|
||||
case RTTI_AIRCRAFT:
|
||||
if (((FootClass *)CurrentObject[0])->Group != team) {
|
||||
Unselect_All();
|
||||
}
|
||||
for (index = 0; index < CurrentObject.Count(); index++) {
|
||||
ObjectClass * obj = CurrentObject[index];
|
||||
if (obj->What_Am_I() == RTTI_UNIT || obj->What_Am_I() == RTTI_INFANTRY || obj->What_Am_I() == RTTI_AIRCRAFT) {
|
||||
if (((FootClass *)obj)->Group != team) {
|
||||
Unselect_All();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (index = 0; index < Units.Count(); index++) {
|
||||
|
|
|
@ -1509,11 +1509,14 @@ typedef enum AnimType : char {
|
|||
ANIM_STEG_DIE,
|
||||
ANIM_RAPT_DIE,
|
||||
ANIM_CHEM_BALL, // Chemical warrior explosion.
|
||||
ANIM_FLAG, // CTF flag.
|
||||
ANIM_BEACON, // Beacon.
|
||||
|
||||
ANIM_FIRE_SMALL_VIRTUAL, // Small flame animation (virtual).
|
||||
ANIM_FIRE_MED_VIRTUAL, // Medium flame animation (virtual).
|
||||
ANIM_FIRE_MED2_VIRTUAL, // Medium flame animation (oranger) (virtual).
|
||||
ANIM_FIRE_TINY_VIRTUAL, // Very tiny flames (virtual).
|
||||
ANIM_FIRE_SMALL_VIRTUAL, // Small flame animation (virtual).
|
||||
ANIM_FIRE_MED_VIRTUAL, // Medium flame animation (virtual).
|
||||
ANIM_FIRE_MED2_VIRTUAL, // Medium flame animation (oranger) (virtual).
|
||||
ANIM_FIRE_TINY_VIRTUAL, // Very tiny flames (virtual).
|
||||
ANIM_BEACON_VIRTUAL, // Beacon (virtual).
|
||||
|
||||
ANIM_COUNT,
|
||||
ANIM_FIRST=0
|
||||
|
@ -1630,6 +1633,9 @@ typedef enum RadioMessageType : unsigned char {
|
|||
RADIO_PUNCH, // "Take this punch, you.. you.."
|
||||
RADIO_PREPARE_TO_BOX,// "Fancy a little fisticuffs, eh?"
|
||||
|
||||
RADIO_NEED_REPAIR, // "Are you in need of service depot work?"
|
||||
RADIO_ON_DEPOT, // "Are you sitting on a service depot?"
|
||||
|
||||
RADIO_COUNT
|
||||
} RadioMessageType;
|
||||
|
||||
|
@ -2305,6 +2311,8 @@ typedef enum VocType : char{
|
|||
VOC_DINOATK1, // Dino attack sound.
|
||||
VOC_DINODIE1, // Dino die sound.
|
||||
|
||||
VOC_BEACON, // Beacon sound.
|
||||
|
||||
#ifdef PETROGLYPH_EXAMPLE_MOD
|
||||
VOC_NUKE_LOB, // Modded unit firing sound
|
||||
#endif
|
||||
|
@ -2843,6 +2851,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)
|
||||
|
|
|
@ -1107,7 +1107,7 @@ void DisplayClass::Cursor_Mark(CELL pos, bool on)
|
|||
CELL const *ptr;
|
||||
CellClass *cellptr;
|
||||
|
||||
if (pos == -1) return;
|
||||
if ((unsigned)pos >= MAP_CELL_TOTAL) return;
|
||||
|
||||
/*
|
||||
** For every cell in the CursorSize list, invoke its Redraw_Objects and
|
||||
|
@ -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)) {
|
||||
|
@ -2964,6 +2965,7 @@ void DisplayClass::Select_These(COORDINATE coord1, COORDINATE coord2, bool addit
|
|||
*/
|
||||
if ( obj->Class_Of().IsSelectable &&
|
||||
obj->What_Am_I() != RTTI_BUILDING &&
|
||||
(!obj->Is_Techno() || !((TechnoClass*)obj)->Is_Cloaked(PlayerPtr)) &&
|
||||
x >= x1 && x <= x2 && y >= y1 && y <= y2) {
|
||||
bool old_allow_voice = AllowVoice;
|
||||
bool is_player_controlled = obj->Owner() == PlayerPtr->Class->House;
|
||||
|
@ -2991,6 +2993,7 @@ void DisplayClass::Select_These(COORDINATE coord1, COORDINATE coord2, bool addit
|
|||
** selected, and are within the bounding box.
|
||||
*/
|
||||
if ( aircraft->Class_Of().IsSelectable &&
|
||||
!aircraft->Is_Cloaked(PlayerPtr) &&
|
||||
!aircraft->Is_Selected_By_Player() &&
|
||||
x >= x1 && x <= x2 && y >= y1 && y <= y2) {
|
||||
bool old_allow_voice = AllowVoice;
|
||||
|
@ -3870,12 +3873,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;
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ typedef enum {
|
|||
*/
|
||||
#define RANDOM_START_POSITION 0x7f
|
||||
|
||||
|
||||
#define KILL_PLAYER_ON_DISCONNECT 1
|
||||
|
||||
|
||||
|
||||
|
@ -140,6 +140,7 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Sidebar_Request(Sidebar
|
|||
extern "C" __declspec(dllexport) void __cdecl CNC_Handle_SuperWeapon_Request(SuperWeaponRequestEnum request_type, uint64 player_id, int buildable_type, int buildable_id, int x1, int y1);
|
||||
extern "C" __declspec(dllexport) void __cdecl CNC_Handle_ControlGroup_Request(ControlGroupRequestEnum request_type, uint64 player_id, unsigned char control_group_index);
|
||||
extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Debug_Request(DebugRequestEnum debug_request_type, uint64 player_id, const char *object_name, int x, int y, bool unshroud, bool enemy);
|
||||
extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Beacon_Request(BeaconRequestEnum beacon_request_type, uint64 player_id, int pixel_x, int pixel_y);
|
||||
extern "C" __declspec(dllexport) bool __cdecl CNC_Set_Multiplayer_Data(int scenario_index, CNCMultiplayerOptionsStruct &game_options, int num_players, CNCPlayerInfoStruct *player_list, int max_players);
|
||||
extern "C" __declspec(dllexport) bool __cdecl CNC_Clear_Object_Selection(uint64 player_id);
|
||||
extern "C" __declspec(dllexport) bool __cdecl CNC_Select_Object(uint64 player_id, int object_type_id, int object_to_select_id);
|
||||
|
@ -148,7 +149,7 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Set_Difficulty(int difficulty)
|
|||
extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Player_Switch_To_AI(uint64 player_id);
|
||||
extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Human_Team_Wins(uint64 player_id);
|
||||
extern "C" __declspec(dllexport) void __cdecl CNC_Start_Mission_Timer(int time);
|
||||
|
||||
extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Start_Game_Info(uint64 player_id, int &start_location_waypoint_index);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -296,6 +297,7 @@ class DLLExportClass {
|
|||
static int CurrentDrawCount;
|
||||
static int TotalObjectCount;
|
||||
static int SortOrder;
|
||||
static int ExportLayer;
|
||||
static CNCObjectListStruct *ObjectList;
|
||||
|
||||
static CNC_Event_Callback_Type EventCallback;
|
||||
|
@ -337,6 +339,7 @@ class DLLExportClass {
|
|||
int DLLExportClass::CurrentDrawCount = 0;
|
||||
int DLLExportClass::TotalObjectCount = 0;
|
||||
int DLLExportClass::SortOrder = 0;
|
||||
int DLLExportClass::ExportLayer = 0;
|
||||
CNCObjectListStruct *DLLExportClass::ObjectList = NULL;
|
||||
SidebarGlyphxClass DLLExportClass::MultiplayerSidebars [MAX_PLAYERS];
|
||||
uint64 DLLExportClass::GlyphxPlayerIDs[MAX_PLAYERS] = {0xffffffffl};
|
||||
|
@ -388,14 +391,13 @@ void Play_Movie_GlyphX(const char * movie_name, ThemeType theme)
|
|||
|
||||
void On_Sound_Effect(int sound_index, int variation, COORDINATE coord)
|
||||
{
|
||||
// MBL 02.26.2019
|
||||
int voc = sound_index;
|
||||
if (voc == VOC_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// MBL 02.26.2019 - Borrowed from AUDIO.CPP Sound_Effect()
|
||||
// Borrowed from AUDIO.CPP Sound_Effect()
|
||||
//
|
||||
#if 1
|
||||
char const * ext = ""; // ".AUD";
|
||||
|
@ -423,16 +425,12 @@ void On_Sound_Effect(int sound_index, int variation, COORDINATE coord)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
// END MBL
|
||||
|
||||
DLLExportClass::On_Sound_Effect(PlayerPtr, sound_index, ext, variation, coord);
|
||||
}
|
||||
|
||||
// MBL 02.06.2020
|
||||
// void On_Speech(int speech_index)
|
||||
void On_Speech(int speech_index, HouseClass *house)
|
||||
{
|
||||
// DLLExportClass::On_Speech(PlayerPtr, speech_index); // MBL 02.06.2020
|
||||
if (house == NULL) {
|
||||
DLLExportClass::On_Speech(PlayerPtr, speech_index);
|
||||
}
|
||||
|
@ -502,7 +500,6 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Init(const char *command_line,
|
|||
|
||||
DLL_Startup(command_line);
|
||||
|
||||
// MBL
|
||||
DLLExportClass::Set_Event_Callback( event_callback );
|
||||
|
||||
DLLExportClass::Init();
|
||||
|
@ -672,6 +669,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
|
||||
|
||||
|
@ -876,7 +874,7 @@ void GlyphX_Assign_Houses(void)
|
|||
preassigned = true;
|
||||
}
|
||||
}
|
||||
if (!preassigned) {
|
||||
if (!preassigned && i < MAX_PLAYERS) {
|
||||
random_start_locations[num_random_start_locations] = num_start_locations;
|
||||
num_random_start_locations++;
|
||||
}
|
||||
|
@ -1314,7 +1312,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();
|
||||
|
@ -1329,6 +1329,10 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Start_Custom_Instance(const ch
|
|||
|
||||
GlyphXClientSidebarWidthInLeptons = 0;
|
||||
|
||||
Play_Movie(IntroMovie);
|
||||
Play_Movie(BriefMovie);
|
||||
Play_Movie(ActionMovie, TransitTheme);
|
||||
|
||||
/*
|
||||
if (!Start_Scenario(ScenarioName)) {
|
||||
return(false);
|
||||
|
@ -1695,8 +1699,14 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Save_Load(bool save, const cha
|
|||
}
|
||||
|
||||
result = Load_Game(file_path_and_name);
|
||||
|
||||
|
||||
if (result == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DLLExportClass::Set_Player_Context(DLLExportClass::GlyphxPlayerIDs[0], true);
|
||||
DLLExportClass::Cancel_Placement(DLLExportClass::GlyphxPlayerIDs[0], -1, -1);
|
||||
Set_Logic_Page(SeenBuff);
|
||||
VisiblePage.Clear();
|
||||
Map.Flag_To_Redraw(true);
|
||||
|
@ -1747,9 +1757,6 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Player_Switch_To_AI(uin
|
|||
if (PlayerWins || PlayerLoses || DLLExportClass::Get_Game_Over()) {
|
||||
return;
|
||||
}
|
||||
|
||||
HousesType house;
|
||||
HouseClass *ptr;
|
||||
|
||||
GlyphX_Debug_Print("CNC_Handle_Player_Switch_To_AI");
|
||||
|
||||
|
@ -1757,9 +1764,28 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Player_Switch_To_AI(uin
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef KILL_PLAYER_ON_DISCONNECT
|
||||
|
||||
/*
|
||||
** Kill player's units on disconnect.
|
||||
*/
|
||||
if (player_id != 0) {
|
||||
DLLExportClass::Set_Player_Context(player_id);
|
||||
|
||||
if (PlayerPtr) {
|
||||
PlayerPtr->Flag_To_Die();
|
||||
}
|
||||
}
|
||||
|
||||
#else //KILL_PLAYER_ON_DISCONNECT
|
||||
|
||||
if (player_id != 0) {
|
||||
|
||||
HousesType house;
|
||||
HouseClass *ptr;
|
||||
|
||||
DLLExportClass::Set_Player_Context(player_id);
|
||||
|
||||
if (PlayerPtr) {
|
||||
PlayerPtr->WasHuman = true;
|
||||
PlayerPtr->IsHuman = false;
|
||||
|
@ -1803,6 +1829,9 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Player_Switch_To_AI(uin
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif //KILL_PLAYER_ON_DISCONNECT
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1830,6 +1859,24 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Start_Mission_Timer(int time)
|
|||
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
* CNC_Get_Start_Game_Info
|
||||
*
|
||||
* History: 8/31/2020 11:37AM - ST
|
||||
**************************************************************************************************/
|
||||
extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Start_Game_Info(uint64 player_id, int &start_location_waypoint_index)
|
||||
{
|
||||
start_location_waypoint_index = 0;
|
||||
if (!DLLExportClass::Set_Player_Context(player_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
start_location_waypoint_index = PlayerPtr->StartLocationOverride;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
* DLLExportClass::Init -- Init the class
|
||||
*
|
||||
|
@ -2489,18 +2536,26 @@ void DLLExportClass::On_Multiplayer_Game_Over(void)
|
|||
event.GameOver.SabotagedStructureType = 0;
|
||||
event.GameOver.TimerRemaining = -1;
|
||||
|
||||
// Trigger an event for each human player
|
||||
for (int i=0 ; i<MPlayerCount ; i++) {
|
||||
// Trigger an event for each human player, winner first (even if it's an AI)
|
||||
for (int i = 0; i < MPlayerCount; i++) {
|
||||
HouseClass* player_ptr = HouseClass::As_Pointer(MPlayerHouses[i]); //HouseClass::As_Pointer(HOUSE_MULTI2);
|
||||
if ( player_ptr != NULL )
|
||||
{
|
||||
if ( player_ptr->IsHuman == true )
|
||||
{
|
||||
event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
|
||||
event.GameOver.PlayerWins = !player_ptr->IsDefeated;
|
||||
event.GameOver.RemainingCredits = player_ptr->Available_Money();
|
||||
EventCallback(event);
|
||||
}
|
||||
if (player_ptr != NULL && !player_ptr->IsDefeated) {
|
||||
event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
|
||||
event.GameOver.IsHuman = player_ptr->IsHuman;
|
||||
event.GameOver.PlayerWins = true;
|
||||
event.GameOver.RemainingCredits = player_ptr->Available_Money();
|
||||
EventCallback(event);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MPlayerCount; i++) {
|
||||
HouseClass* player_ptr = HouseClass::As_Pointer(MPlayerHouses[i]); //HouseClass::As_Pointer(HOUSE_MULTI2);
|
||||
if (player_ptr != NULL && player_ptr->IsHuman && player_ptr->IsDefeated) {
|
||||
event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
|
||||
event.GameOver.IsHuman = true;
|
||||
event.GameOver.PlayerWins = false;
|
||||
event.GameOver.RemainingCredits = player_ptr->Available_Money();
|
||||
EventCallback(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2911,6 +2966,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;
|
||||
|
@ -2927,7 +2983,11 @@ void DLLExportClass::DLL_Draw_Intercept(int shape_number, int x, int y, int widt
|
|||
|
||||
new_object.CNCInternalObjectPointer = (void*)object;
|
||||
new_object.OccupyListLength = 0;
|
||||
new_object.SortOrder = SortOrder++;
|
||||
if (CurrentDrawCount == 0) {
|
||||
new_object.SortOrder = (ExportLayer << 29) + (object->Sort_Y() >> 3);
|
||||
} else {
|
||||
new_object.SortOrder = ObjectList->Objects[TotalObjectCount].SortOrder + CurrentDrawCount;
|
||||
}
|
||||
|
||||
strncpy(new_object.TypeName, object->Class_Of().IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
|
||||
|
||||
|
@ -3295,6 +3355,8 @@ bool DLLExportClass::Get_Layer_State(uint64 player_id, unsigned char *buffer_in,
|
|||
*/
|
||||
for (int layer = 0; layer < DLL_LAYER_COUNT; layer++) {
|
||||
|
||||
ExportLayer = layer;
|
||||
|
||||
for (int index = 0; index < Map.Layer[layer].Count(); index++) {
|
||||
|
||||
ObjectClass *object = Map.Layer[layer][index];
|
||||
|
@ -3637,6 +3699,31 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Input(InputRequestEnum
|
|||
break;
|
||||
}
|
||||
|
||||
// MBL 09.08.2020 - Mod Support
|
||||
case INPUT_REQUEST_MOD_GAME_COMMAND_1_AT_POSITION:
|
||||
case INPUT_REQUEST_MOD_GAME_COMMAND_2_AT_POSITION:
|
||||
case INPUT_REQUEST_MOD_GAME_COMMAND_3_AT_POSITION:
|
||||
case INPUT_REQUEST_MOD_GAME_COMMAND_4_AT_POSITION:
|
||||
{
|
||||
DLLExportClass::Adjust_Internal_View();
|
||||
DLLForceMouseX = x1;
|
||||
DLLForceMouseY = y1;
|
||||
_Kbd->MouseQX = x1;
|
||||
_Kbd->MouseQY = y1;
|
||||
|
||||
COORDINATE coord = Map.Pixel_To_Coord(x1, y1);
|
||||
CELL cell = Coord_Cell(coord);
|
||||
|
||||
if (Map.Pixel_To_Coord(x1, y1))
|
||||
{
|
||||
// TBD: For our ever-awesome Community Modders!
|
||||
//
|
||||
// PlayerPtr->Handle_Mod_Game_Command(cell, input_event - INPUT_REQUEST_MOD_GAME_COMMAND_1_AT_POSITION);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -3761,6 +3848,10 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Sidebar_Request(Sidebar
|
|||
|
||||
switch (request_type) {
|
||||
|
||||
// Changing right-click support for first put building on hold, and then subsequenct right-clicks to decrement that queue count for 1x or 5x; Then, 1x or 5x Left click will resume from hold
|
||||
// Handle and fall through to start construction (from hold state) below
|
||||
case SIDEBAR_REQUEST_START_CONSTRUCTION_MULTI:
|
||||
|
||||
case SIDEBAR_REQUEST_START_CONSTRUCTION:
|
||||
DLLExportClass::Start_Construction(player_id, buildable_type, buildable_id);
|
||||
break;
|
||||
|
@ -3981,6 +4072,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;
|
||||
|
@ -4160,6 +4253,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;
|
||||
|
@ -4321,6 +4416,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;
|
||||
|
@ -4349,7 +4446,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;
|
||||
|
@ -4440,7 +4537,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]);
|
||||
|
||||
|
@ -5101,7 +5198,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.
|
||||
|
@ -6627,8 +6724,12 @@ void DLLExportClass::Selected_Guard_Mode(uint64 player_id)
|
|||
for (int index = 0; index < CurrentObject.Count(); index++) {
|
||||
ObjectClass const * tech = CurrentObject[index];
|
||||
|
||||
if (tech && tech->Can_Player_Move() && tech->Can_Player_Fire()) {
|
||||
OutList.Add(EventClass(tech->As_Target(), MISSION_GUARD_AREA));
|
||||
if (tech && tech->Can_Player_Fire()) {
|
||||
if (tech->Can_Player_Move()) {
|
||||
OutList.Add(EventClass(tech->As_Target(), MISSION_GUARD_AREA));
|
||||
} else {
|
||||
OutList.Add(EventClass(tech->As_Target(), MISSION_GUARD));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6792,6 +6893,39 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Debug_Request(DebugRequ
|
|||
}
|
||||
|
||||
|
||||
extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Beacon_Request(BeaconRequestEnum beacon_request_type, uint64 player_id, int pixel_x, int pixel_y)
|
||||
{
|
||||
if (!DLLExportClass::Set_Player_Context(player_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Beacons are only available if legacy rendering is disabled
|
||||
if (DLLExportClass::Legacy_Render_Enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only allow one beacon per player
|
||||
for (int index = 0; index < Anims.Count(); ++index) {
|
||||
AnimClass* anim = Anims.Ptr(index);
|
||||
if (anim != NULL &&
|
||||
(*anim == ANIM_BEACON || *anim == ANIM_BEACON_VIRTUAL) &&
|
||||
anim->OwnerHouse == PlayerPtr->Class->House) {
|
||||
delete anim;
|
||||
}
|
||||
}
|
||||
|
||||
OutList.Add(EventClass(ANIM_BEACON, PlayerPtr->Class->House, Map.Pixel_To_Coord(pixel_x, pixel_y), PlayerPtr->Get_Allies()));
|
||||
|
||||
// Send sound effect to allies
|
||||
for (int index = 0; index < Houses.Count(); ++index) {
|
||||
HouseClass* hptr = Houses.Ptr(index);
|
||||
if (hptr != NULL && hptr->IsActive && hptr->IsHuman && PlayerPtr->Is_Ally(hptr)) {
|
||||
DLLExportClass::On_Sound_Effect(hptr, VOC_BEACON, "", 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
* DLLExportClass::Debug_Spawn_All -- Debug spawn all buildable units and structures
|
||||
*
|
||||
|
@ -7158,7 +7292,7 @@ void DLLExportClass::Debug_Heal_Unit(int x, int y)
|
|||
CellClass* cells[cellcount];
|
||||
cells[0] = cellptr;
|
||||
for (FacingType index = FACING_N; index < FACING_COUNT; index++) {
|
||||
cells[(int)index + 1] = &cellptr->Adjacent_Cell(index);
|
||||
cells[(int)index + 1] = cellptr->Adjacent_Cell(index);
|
||||
}
|
||||
|
||||
for (int index = 0; index < cellcount; index++) {
|
||||
|
@ -7468,10 +7602,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(¬_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)) {
|
||||
|
@ -7586,7 +7728,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(¬_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;
|
||||
|
|
|
@ -28,7 +28,7 @@ struct CarryoverObjectStruct;
|
|||
**
|
||||
**
|
||||
*/
|
||||
#define CNC_DLL_API_VERSION 0x100
|
||||
#include "DLLInterfaceVersion.h"
|
||||
|
||||
|
||||
|
||||
|
@ -421,7 +421,11 @@ enum InputRequestEnum {
|
|||
INPUT_REQUEST_SELL_AT_POSITION,
|
||||
INPUT_REQUEST_SELECT_AT_POSITION,
|
||||
INPUT_REQUEST_COMMAND_AT_POSITION,
|
||||
INPUT_REQUEST_SPECIAL_KEYS
|
||||
INPUT_REQUEST_SPECIAL_KEYS,
|
||||
INPUT_REQUEST_MOD_GAME_COMMAND_1_AT_POSITION,
|
||||
INPUT_REQUEST_MOD_GAME_COMMAND_2_AT_POSITION,
|
||||
INPUT_REQUEST_MOD_GAME_COMMAND_3_AT_POSITION,
|
||||
INPUT_REQUEST_MOD_GAME_COMMAND_4_AT_POSITION,
|
||||
};
|
||||
|
||||
|
||||
|
@ -472,6 +476,18 @@ enum GameRequestEnum {
|
|||
};
|
||||
|
||||
|
||||
/**************************************************************************************
|
||||
**
|
||||
** Beacon Requests
|
||||
**
|
||||
**
|
||||
*/
|
||||
enum BeaconRequestEnum {
|
||||
INPUT_BEACON_NONE,
|
||||
INPUT_BEACON_PLACE,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**************************************************************************************
|
||||
**
|
||||
|
@ -623,6 +639,7 @@ struct EventCallbackStruct {
|
|||
//
|
||||
// Single-player data
|
||||
//
|
||||
bool IsHuman;
|
||||
bool PlayerWins;
|
||||
const char* MovieName;
|
||||
const char* MovieName2;
|
||||
|
@ -727,7 +744,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
|
||||
|
@ -739,6 +756,7 @@ struct CNCMultiplayerOptionsStruct {
|
|||
bool MPlayerAftermathUnits;
|
||||
bool CaptureTheFlag;
|
||||
bool DestroyStructures; // New early win condition via destroying all a player's structures
|
||||
bool ModernBalance;
|
||||
};
|
||||
|
||||
|
||||
|
|
33
TIBERIANDAWN/DLLInterfaceVersion.h
Normal file
33
TIBERIANDAWN/DLLInterfaceVersion.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// Copyright 2020 Electronic Arts Inc.
|
||||
//
|
||||
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
|
||||
// software: you can redistribute it and/or modify it under the terms of
|
||||
// the GNU General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
|
||||
// in the hope that it will be useful, but with permitted additional restrictions
|
||||
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
|
||||
// distributed with this program. You should have received a copy of the
|
||||
// GNU General Public License along with permitted additional restrictions
|
||||
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef DLL_INTERFACE_VERSION_H
|
||||
#define DLL_INTERFACE_VERSION_H
|
||||
|
||||
|
||||
/*
|
||||
** DLL Interface version
|
||||
**
|
||||
**
|
||||
**
|
||||
*/
|
||||
#define CNC_DLL_API_VERSION 0x102
|
||||
|
||||
|
||||
|
||||
#endif //DLL_INTERFACE_VERSION_H
|
|
@ -521,8 +521,8 @@ void DriveClass::Assign_Destination(TARGET target)
|
|||
** facility is currently not involved with some other unit (radio or unloading).
|
||||
*/
|
||||
if (b && *b == STRUCT_REPAIR) {
|
||||
if (b->In_Radio_Contact()) {
|
||||
target = 0;
|
||||
if (b->In_Radio_Contact() && (b->Contact_With_Whom() != this)) {
|
||||
ArchiveTarget = target;
|
||||
} else {
|
||||
|
||||
/*
|
||||
|
@ -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];
|
||||
|
@ -1598,12 +1606,18 @@ void DriveClass::Mark_Track(COORDINATE headto, MarkType type)
|
|||
|
||||
if (TrackIndex < cellidx && cellidx != -1) {
|
||||
COORDINATE offset = Smooth_Turn(ptr[cellidx].Offset, &dir);
|
||||
Map[Coord_Cell(offset)].Flag.Occupy.Vehicle = value;
|
||||
CELL cell = Coord_Cell(offset);
|
||||
if ((unsigned)cell < MAP_CELL_TOTAL) {
|
||||
Map[cell].Flag.Occupy.Vehicle = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Map[Coord_Cell(headto)].Flag.Occupy.Vehicle = value;
|
||||
CELL cell = Coord_Cell(headto);
|
||||
if ((unsigned)cell < MAP_CELL_TOTAL) {
|
||||
Map[cell].Flag.Occupy.Vehicle = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -250,7 +250,7 @@ EventClass::EventClass(EventType type, TARGET src, TARGET dest)
|
|||
* HISTORY: *
|
||||
* 05/19/1995 JLB : Created. *
|
||||
*=============================================================================================*/
|
||||
EventClass::EventClass(AnimType anim, HousesType owner, COORDINATE coord)
|
||||
EventClass::EventClass(AnimType anim, HousesType owner, COORDINATE coord, int visible)
|
||||
{
|
||||
ID = Houses.ID(PlayerPtr);
|
||||
Type = ANIMATION;
|
||||
|
@ -258,6 +258,7 @@ EventClass::EventClass(AnimType anim, HousesType owner, COORDINATE coord)
|
|||
Data.Anim.What = anim;
|
||||
Data.Anim.Owner = owner;
|
||||
Data.Anim.Where = coord;
|
||||
Data.Anim.Visible = visible;
|
||||
}
|
||||
|
||||
|
||||
|
@ -506,14 +507,26 @@ CCDebugString ("C&C95 - Sell packet received\n");
|
|||
case ANIMATION:
|
||||
anim = new AnimClass(Data.Anim.What, Data.Anim.Where);
|
||||
if (anim) {
|
||||
//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_Owner(Data.Anim.Owner);
|
||||
|
||||
if (Special.IsVisibleTarget)
|
||||
{
|
||||
anim->Set_Visible_Flags(0xffff);
|
||||
anim->Set_Visible_Flags(static_cast<unsigned int>(-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
anim->Set_Visible_Flags(1 << Data.Anim.Owner);
|
||||
anim->Set_Visible_Flags(static_cast<unsigned int>(Data.Anim.Visible));
|
||||
}
|
||||
|
||||
/*
|
||||
** Beacons have a 30-second kill time.
|
||||
*/
|
||||
if (Data.Anim.What == ANIM_BEACON) {
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
|
||||
unsigned long long kill_time = ((unsigned long long)ft.dwLowDateTime + ((unsigned long long)ft.dwHighDateTime << 32ULL)) + 300000000ULL;
|
||||
anim->Kill_At(kill_time);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -626,6 +639,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);
|
||||
|
|
|
@ -127,6 +127,7 @@ class EventClass
|
|||
AnimType What; // The animation to create.
|
||||
HousesType Owner; // The owner of the animation (when it matters).
|
||||
COORDINATE Where; // The location to place the animation.
|
||||
int Visible; // Who this animation is visible to.
|
||||
} Anim;
|
||||
struct {
|
||||
int Value; // general-purpose data
|
||||
|
@ -208,7 +209,7 @@ class EventClass
|
|||
EventClass(EventType type, RTTIType object, int id);
|
||||
EventClass(EventType type, RTTIType object, CELL cell);
|
||||
EventClass(EventType type, int id, CELL cell);
|
||||
EventClass(AnimType anim, HousesType owner, COORDINATE coord);
|
||||
EventClass(AnimType anim, HousesType owner, COORDINATE coord, int visible = -1);
|
||||
|
||||
// Process the event.
|
||||
void Execute(void);
|
||||
|
|
|
@ -546,23 +546,10 @@ bool FactoryClass::Start(void)
|
|||
time = TICKS_PER_MINUTE * 5;
|
||||
}
|
||||
|
||||
/*
|
||||
** Adjust time according to IQ setting of computer controlled house. The
|
||||
** build time will range from double normal time at the slowest to
|
||||
** just normal time at the fastest.
|
||||
*/
|
||||
if (!House->IsHuman && Rule.Diff[House->Difficulty].IsBuildSlowdown) {
|
||||
time = (int)((time*Rule.MaxIQ*2.0f) / (House->IQ+Rule.MaxIQ));
|
||||
}
|
||||
time /= STEP_COUNT;
|
||||
time = Bound(time, 1, 255);
|
||||
|
||||
int frac = House->Power_Fraction();
|
||||
frac = Bound(frac, 0x0010, 0x0100);
|
||||
int rate = (time*256) / frac;
|
||||
|
||||
rate /= STEP_COUNT;
|
||||
rate = Bound(rate, 1, 255);
|
||||
|
||||
Set_Rate(rate);
|
||||
Set_Rate(time);
|
||||
IsSuspended = false;
|
||||
return(true);
|
||||
}
|
||||
|
|
|
@ -98,6 +98,8 @@
|
|||
#define MAX_MLIST_SIZE 300
|
||||
#define THREAT_THRESHOLD 5
|
||||
|
||||
#define MAX_PATH_EDGE_FOLLOW 400
|
||||
|
||||
#ifdef NEVER
|
||||
typedef enum {
|
||||
FACING_N, // North
|
||||
|
@ -734,8 +736,14 @@ top_of_list:
|
|||
pleft.Overlap = LeftOverlap;
|
||||
Mem_Copy(path.Command, pleft.Command, path.Length);
|
||||
Mem_Copy(path.Overlap, pleft.Overlap, sizeof(LeftOverlap));
|
||||
// MBL 09.30.2019: We hit a runtime bounds crash where END (-1 / 0xFF) was being poked into +1 just past the end of the moves_right[] array;
|
||||
// The FacingType moves_left[] and moves_right[] arrays already have MAX_MLIST_SIZE+2 as their size, which may have been a previous attempted fix;
|
||||
// We are now passing MAX_MLIST_SIZE, since the sizeof calculations included the +2 buffering;
|
||||
#if 0
|
||||
left = Follow_Edge(startcell, next, &pleft, COUNTERCLOCK, direction, threat, threat_stage, sizeof(moves_left), threshhold);
|
||||
// left = Follow_Edge(startcell, next, &pleft, COUNTERCLOCK, direction, threat, threat_stage, follow_len, threshhold);
|
||||
#endif
|
||||
left = Follow_Edge(startcell, next, &pleft, COUNTERCLOCK, direction, threat, threat_stage, MAX_MLIST_SIZE, threshhold);
|
||||
|
||||
if (left) {
|
||||
follow_len = MIN(maxlen, pleft.Length + (pleft.Length >> 1));
|
||||
|
@ -761,8 +769,14 @@ top_of_list:
|
|||
pright.Overlap = RightOverlap;
|
||||
Mem_Copy(path.Command, pright.Command, path.Length);
|
||||
Mem_Copy(path.Overlap, pright.Overlap, sizeof(RightOverlap));
|
||||
// MBL 09.30.2019: We hit a runtime bounds crash where END (-1 / 0xFF) was being poked into +1 just past the end of the moves_right[] array;
|
||||
// The FacingType moves_left[] and moves_right[] arrays already have MAX_MLIST_SIZE+2 as their size, which may have been a previous attempted fix;
|
||||
// We are now passing MAX_MLIST_SIZE, since the sizeof calculations included the +2 buffering;
|
||||
#if 0
|
||||
right = Follow_Edge(startcell, next, &pright, CLOCK, direction, threat, threat_stage, sizeof(moves_right), threshhold);
|
||||
// right = Follow_Edge(startcell, next, &pright, CLOCK, direction, threat, threat_stage, follow_len, threshhold);
|
||||
#endif
|
||||
right = Follow_Edge(startcell, next, &pright, CLOCK, direction, threat, threat_stage, MAX_MLIST_SIZE, threshhold);
|
||||
|
||||
/*
|
||||
** If we are in debug mode then let us know how well our right path
|
||||
|
@ -1119,7 +1133,7 @@ bool FootClass::Follow_Edge(CELL start, CELL target, PathType *path, FacingType
|
|||
online = true;
|
||||
}
|
||||
cellcount++;
|
||||
if (cellcount==100) {
|
||||
if (cellcount==MAX_PATH_EDGE_FOLLOW) {
|
||||
// DrawPath = true;
|
||||
// Debug_Find_Path = true;
|
||||
// Debug_Draw_Map("Loop failure", start, target, false);
|
||||
|
|
|
@ -305,14 +305,20 @@ bool FootClass::Mark(MarkType mark)
|
|||
/*
|
||||
** Inform the map of the refresh, occupation, and overlap
|
||||
** request.
|
||||
** Special case is fixed-wing aircraft, which are never placed
|
||||
** or picked up since they can never land.
|
||||
*/
|
||||
switch (mark) {
|
||||
case MARK_UP:
|
||||
Map.Pick_Up(cell, this);
|
||||
if (What_Am_I() != RTTI_AIRCRAFT || !((AircraftClass*)this)->Class->IsFixedWing) {
|
||||
Map.Pick_Up(cell, this);
|
||||
}
|
||||
break;
|
||||
|
||||
case MARK_DOWN:
|
||||
Map.Place_Down(cell, this);
|
||||
if (What_Am_I() != RTTI_AIRCRAFT || !((AircraftClass*)this)->Class->IsFixedWing) {
|
||||
Map.Place_Down(cell, this);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -947,8 +953,10 @@ void FootClass::Approach_Target(void)
|
|||
/*
|
||||
** If a suitable intermediate location was found, then head toward it.
|
||||
** Otherwise, head toward the enemy unit directly.
|
||||
** Infantry always head towards the target since they can enter a cell
|
||||
** in range, but still not be able to hit the target if the spot is out of range.
|
||||
*/
|
||||
if (found) {
|
||||
if (found && What_Am_I() != RTTI_INFANTRY) {
|
||||
Assign_Destination(::As_Target(trycell));
|
||||
} else {
|
||||
Assign_Destination(TarCom);
|
||||
|
@ -990,6 +998,20 @@ int FootClass::Mission_Guard_Area(void)
|
|||
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
|
||||
}
|
||||
|
||||
/*
|
||||
** Ensure units aren't trying to guard cells off the map.
|
||||
*/
|
||||
if (Target_Legal(NavCom) && Is_Target_Cell(NavCom)) {
|
||||
CELL cell = As_Cell(NavCom);
|
||||
int x = Cell_X(cell);
|
||||
int y = Cell_Y(cell);
|
||||
if (x < Map.MapCellX || y < Map.MapCellY || x >= (Map.MapCellX + Map.MapCellWidth) || y >= (Map.MapCellY + Map.MapCellHeight)) {
|
||||
Assign_Target(TARGET_NONE);
|
||||
Assign_Destination(TARGET_NONE);
|
||||
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Make sure that the unit has not strayed too far from the home position.
|
||||
** If it has, then race back to it.
|
||||
|
@ -1006,6 +1028,7 @@ int FootClass::Mission_Guard_Area(void)
|
|||
Target_Something_Nearby(THREAT_AREA);
|
||||
Coord = old;
|
||||
if (Target_Legal(TarCom)) return(1);
|
||||
Random_Animate();
|
||||
} else {
|
||||
Approach_Target();
|
||||
}
|
||||
|
@ -1258,7 +1281,7 @@ void FootClass::Active_Click_With(ActionType action, ObjectClass * object)
|
|||
break;
|
||||
|
||||
case ACTION_ENTER:
|
||||
if (Can_Player_Move() && object && object->Is_Techno() && !((RadioClass *)object)->In_Radio_Contact()) {
|
||||
if (Can_Player_Move() && object && object->Is_Techno() /*&& !((RadioClass *)object)->In_Radio_Contact()*/) {
|
||||
Player_Assign_Mission(MISSION_ENTER, TARGET_NONE, object->As_Target());
|
||||
}
|
||||
break;
|
||||
|
@ -1319,7 +1342,7 @@ void FootClass::Active_Click_With(ActionType action, CELL cell)
|
|||
case ACTION_MOVE:
|
||||
if (AllowVoice) {
|
||||
COORDINATE coord = Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y());
|
||||
OutList.Add(EventClass(ANIM_MOVE_FLASH, PlayerPtr->Class->House, coord));
|
||||
OutList.Add(EventClass(ANIM_MOVE_FLASH, PlayerPtr->Class->House, coord, 1 << PlayerPtr->Class->House));
|
||||
}
|
||||
// Fall into next case.
|
||||
|
||||
|
@ -1422,6 +1445,8 @@ void FootClass::Per_Cell_Process(bool center)
|
|||
}
|
||||
// }
|
||||
|
||||
Map[Coord_Cell(Coord)].Goodie_Check(this, true);
|
||||
|
||||
TechnoClass::Per_Cell_Process(center);
|
||||
}
|
||||
|
||||
|
@ -1498,6 +1523,18 @@ RadioMessageType FootClass::Receive_Message(RadioClass * from, RadioMessageType
|
|||
{
|
||||
switch (message) {
|
||||
|
||||
/*
|
||||
** Answers if this object is located on top of a service depot.
|
||||
*/
|
||||
case RADIO_ON_DEPOT:
|
||||
if (Map[Coord_Cell(Center_Coord())].Cell_Building() != NULL) {
|
||||
BuildingClass const * building = Map[Coord_Cell(Center_Coord())].Cell_Building();
|
||||
if (*building == STRUCT_REPAIR) {
|
||||
return(RADIO_ROGER);
|
||||
}
|
||||
}
|
||||
return(RADIO_NEGATIVE);
|
||||
|
||||
/*
|
||||
** Intercept the repair request and if this object is moving, then no repair
|
||||
** is possible.
|
||||
|
@ -1524,7 +1561,7 @@ RadioMessageType FootClass::Receive_Message(RadioClass * from, RadioMessageType
|
|||
Assign_Mission(MISSION_GUARD);
|
||||
}
|
||||
if (!IsRotating && !Target_Legal(NavCom)) {
|
||||
Scatter(0, true);
|
||||
Scatter(0, true, true);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1590,35 +1627,51 @@ RadioMessageType FootClass::Receive_Message(RadioClass * from, RadioMessageType
|
|||
int FootClass::Mission_Enter(void)
|
||||
{
|
||||
/*
|
||||
** If radio contact has not yet been established with the transport, try to
|
||||
** establish contact now.
|
||||
** Find out who to coordinate with. If in radio contact, then this the transporter is
|
||||
** defined. If not in radio contact, then try the archive target value to see if that
|
||||
** is suitable.
|
||||
*/
|
||||
if (!In_Radio_Contact()) {
|
||||
TechnoClass * techno = As_Techno(ArchiveTarget);
|
||||
if (!techno) techno = As_Techno(NavCom);
|
||||
if (techno) {
|
||||
TechnoClass * contact = Contact_With_Whom();
|
||||
if (contact == NULL) {
|
||||
contact = As_Techno(ArchiveTarget);
|
||||
}
|
||||
if (contact == NULL) {
|
||||
contact = As_Techno(NavCom);
|
||||
}
|
||||
|
||||
/*
|
||||
** If the transport is already in radio contact, do nothing. Try to
|
||||
** establish radio contact later.
|
||||
*/
|
||||
if (Transmit_Message(RADIO_HELLO, techno) == RADIO_ROGER) {
|
||||
Assign_Destination(TARGET_NONE);
|
||||
}
|
||||
} else {
|
||||
ArchiveTarget = TARGET_NONE;
|
||||
/*
|
||||
** If in contact, then let the transporter handle the movement coordination.
|
||||
*/
|
||||
if (contact != NULL) {
|
||||
|
||||
/*
|
||||
** If the transport says to "bug off", then abort the enter mission. The transport may
|
||||
** likely say all is 'ok' with the "RADIO ROGER", then try again later.
|
||||
*/
|
||||
if (Transmit_Message(RADIO_DOCKING, contact) != RADIO_ROGER && !IsTethered) {
|
||||
Transmit_Message(RADIO_OVER_OUT);
|
||||
Enter_Idle_Mode();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/*
|
||||
** Since radio contact exists with the transport, maintain a dialogue so that
|
||||
** the transport can give proper instructions to the passenger.
|
||||
** Since there is no potential object to enter, then abort this
|
||||
** mission with some default standby mission.
|
||||
*/
|
||||
if (Transmit_Message(RADIO_DOCKING) != RADIO_ROGER) {
|
||||
Transmit_Message(RADIO_OVER_OUT);
|
||||
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);
|
||||
|
|
|
@ -360,7 +360,7 @@ void const *Get_Radar_Icon(void const *shapefile, int shapenum, int frames, int
|
|||
void CC_Draw_Shape(void const * shapefile, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const * fadingdata=0, void const * ghostdata=0);
|
||||
|
||||
// Added for draw intercept. ST - 1/17/2019 12:31PM
|
||||
void CC_Draw_Shape(ObjectClass *object, void const * shapefile, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const * fadingdata=0, void const * ghostdata=0, int scale=0x100);
|
||||
void CC_Draw_Shape(ObjectClass *object, void const * shapefile, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const * fadingdata=0, void const * ghostdata=0, int scale=0x100, int width=0, int height=0);
|
||||
void CC_Draw_Shape(ObjectClass *object, const char *shape_file_name, void const * shapefile, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const * fadingdata = 0, void const * ghostdata = 0, char override_owner = HOUSE_NONE);
|
||||
|
||||
// Added for pip draw intercept - SKY
|
||||
|
@ -669,6 +669,7 @@ void Do_Win(void);
|
|||
void Do_Restart(void);
|
||||
void Fill_In_Data(void);
|
||||
bool Restate_Mission(char const * name, int button1, int button2);
|
||||
void Fixup_Scenario(void);
|
||||
|
||||
/*
|
||||
** SCORE.CPP
|
||||
|
|
|
@ -560,7 +560,7 @@ DynamicVectorClass <int> MPlayerFilenum;
|
|||
/***************************************************************************
|
||||
** This value determines the max allowable # of players.
|
||||
*/
|
||||
int MPlayerMax = 4;
|
||||
int MPlayerMax = 6;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1221,6 +1229,7 @@ void HouseClass::AI(void)
|
|||
unit->Mark(MARK_CHANGE);
|
||||
} else {
|
||||
CELL cell = As_Cell(FlagLocation);
|
||||
Map[cell].Flag_Update();
|
||||
Map[cell].Redraw_Objects();
|
||||
}
|
||||
}
|
||||
|
@ -1423,7 +1432,7 @@ void HouseClass::AI(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (GameToPlay != GAME_NORMAL) {
|
||||
if (GameToPlay != GAME_NORMAL && Class->House != HOUSE_JP) {
|
||||
Check_Pertinent_Structures();
|
||||
}
|
||||
|
||||
|
@ -1663,9 +1672,19 @@ void HouseClass::AI(void)
|
|||
void HouseClass::Attacked(BuildingClass* source)
|
||||
{
|
||||
Validate();
|
||||
|
||||
if (SpeakAttackDelay.Expired() && PlayerPtr->Class->House == Class->House) {
|
||||
Speak(VOX_BASE_UNDER_ATTACK, NULL, source ? source->Center_Coord() : 0);
|
||||
SpeakAttackDelay.Set(Options.Normalize_Delay(SPEAK_DELAY));
|
||||
|
||||
if (GameToPlay == GAME_NORMAL) {
|
||||
Speak(VOX_BASE_UNDER_ATTACK, NULL, source ? source->Center_Coord() : 0);
|
||||
} else {
|
||||
Speak(VOX_BASE_UNDER_ATTACK, this);
|
||||
}
|
||||
|
||||
// MBL 06.13.2020 - Timing change from 2 minute cooldown, per https://jaas.ea.com/browse/TDRA-6784
|
||||
// SpeakAttackDelay.Set(Options.Normalize_Delay(SPEAK_DELAY)); // 2 minutes
|
||||
// SpeakAttackDelay.Set(Options.Normalize_Delay(TICKS_PER_MINUTE/2)); // 30 seconds as requested
|
||||
SpeakAttackDelay.Set(Options.Normalize_Delay( (TICKS_PER_MINUTE/2)+(TICKS_PER_SECOND*5) )); // Tweaked for accuracy
|
||||
|
||||
/*
|
||||
** If there is a trigger event associated with being attacked, process it
|
||||
|
@ -2547,7 +2566,15 @@ ProdFailType HouseClass::Abandon_Production(RTTIType type)
|
|||
if (GameToPlay == GAME_GLYPHX_MULTIPLAYER) {
|
||||
if (IsHuman) {
|
||||
Sidebar_Glyphx_Abandon_Production(type, *factory, this);
|
||||
// Need to clear pending object here?
|
||||
|
||||
// Need to clear pending object here if legacy renderer enabled
|
||||
|
||||
if (type == RTTI_BUILDINGTYPE || type == RTTI_BUILDING && Map.PendingObjectPtr) {
|
||||
Map.PendingObjectPtr = 0;
|
||||
Map.PendingObject = 0;
|
||||
Map.PendingHouse = HOUSE_NONE;
|
||||
Map.Set_Cursor_Shape(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
|
@ -2655,7 +2682,7 @@ bool HouseClass::Place_Special_Blast(SpecialWeaponType id, CELL cell)
|
|||
case SPC_ION_CANNON:
|
||||
if (IonCannon.Is_Ready()) {
|
||||
anim = new AnimClass(ANIM_ION_CANNON, Cell_Coord(cell));
|
||||
if (anim) anim->Owner = Class->House;
|
||||
if (anim) anim->Set_Owner(Class->House);
|
||||
if (this == PlayerPtr) {
|
||||
Map.IsTargettingMode = false;
|
||||
}
|
||||
|
@ -4046,6 +4073,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
|
||||
|
@ -4055,7 +4089,6 @@ void HouseClass::MPlayer_Defeated(void)
|
|||
------------------------------------------------------------------------*/
|
||||
if (PlayerPtr == this) {
|
||||
MPlayerObiWan = 1;
|
||||
Debug_Unshroud = true;
|
||||
HiddenPage.Clear();
|
||||
Map.Flag_To_Redraw(true);
|
||||
|
||||
|
@ -4313,11 +4346,6 @@ void HouseClass::MPlayer_Defeated(void)
|
|||
MPlayerCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
Be sure our messages get displayed, even if we're about to exit.
|
||||
------------------------------------------------------------------------*/
|
||||
Map.Render();
|
||||
}
|
||||
|
||||
|
||||
|
@ -4738,10 +4766,14 @@ void HouseClass::Sell_Wall(CELL cell)
|
|||
Map[cell].OverlayData = 0;
|
||||
Map[cell].Owner = HOUSE_NONE;
|
||||
Map[cell].Wall_Update();
|
||||
Map[cell].Adjacent_Cell(FACING_N).Wall_Update();
|
||||
Map[cell].Adjacent_Cell(FACING_W).Wall_Update();
|
||||
Map[cell].Adjacent_Cell(FACING_S).Wall_Update();
|
||||
Map[cell].Adjacent_Cell(FACING_E).Wall_Update();
|
||||
CellClass * ncell = Map[cell].Adjacent_Cell(FACING_N);
|
||||
if (ncell) ncell->Wall_Update();
|
||||
CellClass * wcell = Map[cell].Adjacent_Cell(FACING_W);
|
||||
if (wcell) wcell->Wall_Update();
|
||||
CellClass * scell = Map[cell].Adjacent_Cell(FACING_S);
|
||||
if (scell) scell->Wall_Update();
|
||||
CellClass * ecell = Map[cell].Adjacent_Cell(FACING_E);
|
||||
if (ecell) ecell->Wall_Update();
|
||||
Map[cell].Recalc_Attributes();
|
||||
Map[cell].Redraw_Objects();
|
||||
ObjectClass::Detach_This_From_All(::As_Target(cell), true);
|
||||
|
@ -4781,6 +4813,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++) {
|
||||
|
|
|
@ -444,6 +444,7 @@ class HouseClass {
|
|||
bool Is_Ally(HousesType house) const;
|
||||
bool Is_Ally(HouseClass const * house) const;
|
||||
bool Is_Ally(ObjectClass const * object) const;
|
||||
unsigned int Get_Allies(void) const {return Allies;}
|
||||
#ifdef CHEAT_KEYS
|
||||
void Debug_Dump(MonoClass *mono) const;
|
||||
#endif
|
||||
|
@ -517,6 +518,9 @@ class HouseClass {
|
|||
void Init_Unit_Trackers(void);
|
||||
void Free_Unit_Trackers(void);
|
||||
|
||||
// MBL 09.08.2020 Mod support stub
|
||||
void Handle_Mod_Game_Command(CELL cell, int mod_command_index); // mod_command_index = 0-3
|
||||
|
||||
#ifdef USE_RA_AI
|
||||
/*
|
||||
** AI Functions imported from RA
|
||||
|
|
|
@ -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|
|
||||
|
@ -572,7 +572,7 @@ static InfantryTypeClass const Commando(
|
|||
false, // Is this a civlian?
|
||||
false, // Always use the given name for the infantry?
|
||||
false, // Is this a "fraidycat" run-away type infantry?
|
||||
true, // Can this infantry type capture a building?
|
||||
false, // Can this infantry type capture a building?
|
||||
false, // Theater specific graphic image?
|
||||
-1, // Number of shots it has (default).
|
||||
&CommandoDos[0][0], // ptr to DO table
|
||||
|
@ -1648,6 +1648,7 @@ InfantryTypeClass::InfantryTypeClass (
|
|||
IsCapture = is_capture;
|
||||
IsFraidyCat = is_fraidycat;
|
||||
IsCivilian = is_civilian;
|
||||
IsAvoidingTiberium = false;
|
||||
Type = type;
|
||||
FireLaunch = firelaunch;
|
||||
ProneLaunch = pronelaunch;
|
||||
|
|
|
@ -677,6 +677,10 @@ void InfantryClass::Per_Cell_Process(bool center)
|
|||
*/
|
||||
if (center && Mission == MISSION_CAPTURE) {
|
||||
TechnoClass * tech = cellptr->Cell_Techno();
|
||||
if (tech && tech->As_Target() == NavCom && tech->What_Am_I() == RTTI_BUILDING && !tech->Can_Capture()) {
|
||||
tech = NULL;
|
||||
Assign_Destination(TARGET_NONE);
|
||||
}
|
||||
if (tech && tech->As_Target() == NavCom) {
|
||||
tech->Captured(House);
|
||||
Delete_This();
|
||||
|
@ -882,7 +886,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) {
|
||||
|
@ -1000,7 +1004,7 @@ void InfantryClass::Assign_Target(TARGET target)
|
|||
*/
|
||||
if (!Target_Legal(NavCom) && Class->IsCapture && Class->Primary == WEAPON_NONE) {
|
||||
BuildingClass const * building = As_Building(target);
|
||||
if (building && building->Class->IsCaptureable && (GameToPlay != GAME_NORMAL || *building != STRUCT_EYE && Scenario < 13)) {
|
||||
if (building && building->Can_Capture()) {
|
||||
Assign_Destination(target);
|
||||
}
|
||||
}
|
||||
|
@ -1098,7 +1102,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 +1670,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
|
||||
|
@ -2086,8 +2097,12 @@ void InfantryClass::Scatter(COORDINATE threat, bool forced, bool nokidding)
|
|||
newcell = Adjacent_Cell(Coord_Cell(Coord), newface);
|
||||
|
||||
if (Map.In_Radar(newcell) && Can_Enter_Cell(newcell) == MOVE_OK) {
|
||||
Assign_Mission(MISSION_MOVE);
|
||||
Assign_Destination(::As_Target(newcell));
|
||||
if (!Class->IsAvoidingTiberium ||
|
||||
Map[newcell].Overlay == OVERLAY_NONE ||
|
||||
OverlayTypeClass::As_Reference(Map[newcell].Overlay).Land != LAND_TIBERIUM) {
|
||||
Assign_Mission(MISSION_MOVE);
|
||||
Assign_Destination(::As_Target(newcell));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2443,7 +2458,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;
|
||||
}
|
||||
|
||||
|
@ -2909,7 +2925,7 @@ ActionType InfantryClass::What_Action(ObjectClass * object) const
|
|||
if (object->Owner() != Owner() &&
|
||||
((object->What_Am_I() == RTTI_AIRCRAFT && ((AircraftClass *)object)->Pip_Count() == 0 && *((AircraftClass *)object) == AIRCRAFT_TRANSPORT) ||
|
||||
(object->What_Am_I() == RTTI_BUILDING &&
|
||||
((BuildingClass *)object)->Class->IsCaptureable && (GameToPlay != GAME_NORMAL || *((BuildingClass *)object) != STRUCT_EYE || Scenario < 13) ))
|
||||
((BuildingClass *)object)->Can_Capture()))
|
||||
) {
|
||||
|
||||
action = ACTION_CAPTURE;
|
||||
|
@ -2978,6 +2994,13 @@ void InfantryClass::Read_INI(char *buffer)
|
|||
*/
|
||||
classid = InfantryTypeClass::From_Name(strtok(NULL, ",\n\r"));
|
||||
|
||||
/*
|
||||
** Special case: replace C7 with C5 on scg08eb
|
||||
*/
|
||||
if (GameToPlay == GAME_NORMAL && PlayerPtr->ActLike == HOUSE_GOOD && Scenario == 8 && ScenVar == SCEN_VAR_B && classid == INFANTRY_C7) {
|
||||
classid = INFANTRY_C5;
|
||||
}
|
||||
|
||||
if (classid != INFANTRY_NONE) {
|
||||
|
||||
if (HouseClass::As_Pointer(inhouse) != NULL) {
|
||||
|
@ -3009,7 +3032,12 @@ void InfantryClass::Read_INI(char *buffer)
|
|||
infantry->Trigger->AttachCount++;
|
||||
}
|
||||
|
||||
if (infantry->Unlimbo(coord, dir)) {
|
||||
/*
|
||||
** Special case: delete pre-placed Chan on scb10ea; he will spawn from the Tech Center.
|
||||
*/
|
||||
bool is_scb10ea_chan = GameToPlay == GAME_NORMAL && PlayerPtr->ActLike == HOUSE_BAD && Scenario == 10 && ScenVar == SCEN_VAR_A && *infantry == INFANTRY_CHAN;
|
||||
|
||||
if (!is_scb10ea_chan && infantry->Unlimbo(coord, dir)) {
|
||||
infantry->Strength = Fixed_To_Cardinal(infantry->Class_Of().MaxStrength, strength);
|
||||
if (GameToPlay == GAME_NORMAL || infantry->House->IsHuman) {
|
||||
infantry->Assign_Mission(mission);
|
||||
|
@ -3181,6 +3209,11 @@ int InfantryClass::Made_A_Kill(void)
|
|||
void InfantryClass::Set_Occupy_Bit(CELL cell, int spot_index)
|
||||
{
|
||||
Validate();
|
||||
|
||||
if ((unsigned)cell >= MAP_CELL_TOTAL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the occupy postion for the spot that we passed in
|
||||
*/
|
||||
|
@ -3208,6 +3241,11 @@ void InfantryClass::Set_Occupy_Bit(CELL cell, int spot_index)
|
|||
void InfantryClass::Clear_Occupy_Bit(CELL cell, int spot_index)
|
||||
{
|
||||
Validate();
|
||||
|
||||
if ((unsigned)cell >= MAP_CELL_TOTAL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear the occupy bit for the infantry in that cell
|
||||
*/
|
||||
|
|
|
@ -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).
|
||||
*/
|
||||
|
@ -485,11 +491,15 @@ bool Read_Scenario_Ini(char *root, bool fresh)
|
|||
** Build the full text of the mission objective.
|
||||
*/
|
||||
for (;;) {
|
||||
char buff[16];
|
||||
int len = (sizeof(BriefingText)-strlen(BriefingText))-1;
|
||||
if (len <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
char buff[16];
|
||||
sprintf(buff, "%d", index++);
|
||||
*stage = '\0';
|
||||
WWGetPrivateProfileString("Briefing", buff, "", stage, (sizeof(BriefingText)-strlen(BriefingText))-1, buffer);
|
||||
WWGetPrivateProfileString("Briefing", buff, "", stage, len, buffer);
|
||||
if (strlen(stage) == 0) break;
|
||||
strcat(stage, " ");
|
||||
stage += strlen(stage);
|
||||
|
@ -534,6 +544,9 @@ 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
|
||||
- fix repeating airstrike trigger
|
||||
** NOD13C - delete airstrike trigger when radar destroyed
|
||||
*/
|
||||
if (_stricmp(ScenarioName, "scb07ea") == 0) {
|
||||
Map[(CELL)2795].Override_Land_Type(LAND_ROCK);
|
||||
|
@ -553,6 +566,39 @@ 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++;
|
||||
|
||||
TriggerClass* xxxx = TriggerClass::As_Pointer("xxxx");
|
||||
assert(xxxx != NULL);
|
||||
xxxx->IsPersistant = TriggerClass::PERSISTANT;
|
||||
}
|
||||
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)
|
||||
*/
|
||||
Fixup_Scenario();
|
||||
|
||||
/*
|
||||
** Multi-player last-minute fixups:
|
||||
|
@ -839,6 +885,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).
|
||||
*/
|
||||
|
@ -880,11 +929,15 @@ bool Read_Scenario_Ini_File(char *scenario_file_name, char* bin_file_name, const
|
|||
** Build the full text of the mission objective.
|
||||
*/
|
||||
for (;;) {
|
||||
char buff[16];
|
||||
int len = (sizeof(BriefingText) - strlen(BriefingText)) - 1;
|
||||
if (len <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
char buff[16];
|
||||
sprintf(buff, "%d", index++);
|
||||
*stage = '\0';
|
||||
WWGetPrivateProfileString("Briefing", buff, "", stage, (sizeof(BriefingText) - strlen(BriefingText)) - 1, buffer);
|
||||
WWGetPrivateProfileString("Briefing", buff, "", stage, len, buffer);
|
||||
if (strlen(stage) == 0) break;
|
||||
strcat(stage, " ");
|
||||
stage += strlen(stage);
|
||||
|
@ -924,6 +977,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
|
||||
|
|
|
@ -218,6 +218,11 @@ void CellClass::Code_Pointers(void)
|
|||
if (IsTrigger) {
|
||||
CellTriggers[Cell_Number()] = (TriggerClass *)CellTriggers[Cell_Number()]->As_Target();
|
||||
}
|
||||
|
||||
/*
|
||||
------------------------ Convert flag pointer -------------------------
|
||||
*/
|
||||
assert(CTFFlag == NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -299,6 +304,11 @@ void CellClass::Decode_Pointers(void)
|
|||
CellTriggers[Cell_Number()] = As_Trigger( (TARGET)CellTriggers[Cell_Number()], false );
|
||||
Check_Ptr((void *)CellTriggers[Cell_Number()],__FILE__,__LINE__);
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert flag pointer.
|
||||
*/
|
||||
CTFFlag = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1012,6 +1022,13 @@ void MapClass::Code_Pointers(void)
|
|||
{
|
||||
CELL cell;
|
||||
|
||||
/*
|
||||
------------------------- Destroy all flag animations --------------------
|
||||
*/
|
||||
for (cell = 0; cell < MAP_CELL_TOTAL; cell++) {
|
||||
(*this)[cell].Flag_Destroy();
|
||||
}
|
||||
|
||||
/*
|
||||
------------------------- Code the cell pointers -------------------------
|
||||
*/
|
||||
|
|
|
@ -1560,6 +1560,10 @@ bool UnitClass::Save(FileClass & file)
|
|||
*=============================================================================================*/
|
||||
void UnitClass::Code_Pointers(void)
|
||||
{
|
||||
if (TiberiumUnloadRefinery) {
|
||||
TiberiumUnloadRefinery = (BuildingClass *)TiberiumUnloadRefinery->As_Target();
|
||||
}
|
||||
|
||||
TarComClass::Code_Pointers();
|
||||
}
|
||||
|
||||
|
@ -1584,6 +1588,11 @@ void UnitClass::Code_Pointers(void)
|
|||
*=============================================================================================*/
|
||||
void UnitClass::Decode_Pointers(void)
|
||||
{
|
||||
if (TiberiumUnloadRefinery) {
|
||||
TiberiumUnloadRefinery = As_Building((TARGET)TiberiumUnloadRefinery, false);
|
||||
Check_Ptr((void *)TiberiumUnloadRefinery, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
TarComClass::Decode_Pointers();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -980,7 +994,7 @@ void MapClass::Logic(void)
|
|||
if (Map.In_Radar(cell)) {
|
||||
FacingType offset = Random_Pick(FACING_N, FACING_NW);
|
||||
for (FacingType index = FACING_N; index < FACING_COUNT; index++) {
|
||||
CellClass *newcell = &(*this)[cell].Adjacent_Cell(index+offset);
|
||||
CellClass *newcell = (*this)[cell].Adjacent_Cell(index+offset);
|
||||
|
||||
if (newcell && newcell->Cell_Object() == NULL && newcell->Land_Type() == LAND_CLEAR && newcell->Overlay == OVERLAY_NONE) {
|
||||
bool found = false;
|
||||
|
@ -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;
|
||||
|
|
|
@ -428,7 +428,7 @@ dxisbig:
|
|||
#if (0)
|
||||
|
||||
/*
|
||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/MiscAsm.cpp#33 $
|
||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/MiscAsm.cpp#138 $
|
||||
;***************************************************************************
|
||||
;** 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 **
|
||||
;***************************************************************************
|
||||
|
|
|
@ -489,6 +489,12 @@ bool ObjectClass::Can_Demolish_Unit(void) const
|
|||
}
|
||||
|
||||
|
||||
bool ObjectClass::Can_Capture(void) const
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* ObjectClass::Can_Player_Fire -- Can the player give this object an attack mission? *
|
||||
* *
|
||||
|
@ -558,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) {};
|
||||
|
|
|
@ -159,6 +159,7 @@ class ObjectClass : public AbstractClass
|
|||
virtual bool Can_Repair(void) const;
|
||||
virtual bool Can_Demolish(void) const;
|
||||
virtual bool Can_Demolish_Unit(void) const;
|
||||
virtual bool Can_Capture(void) const;
|
||||
virtual bool Can_Player_Fire(void) const;
|
||||
virtual bool Can_Player_Move(void) const;
|
||||
|
||||
|
@ -171,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;
|
||||
|
||||
/*
|
||||
|
|
|
@ -309,7 +309,8 @@ bool OverlayClass::Mark(MarkType mark)
|
|||
static FacingType _face[4] = {FACING_N, FACING_E, FACING_S, FACING_W};
|
||||
|
||||
for (int index = 0; index < (sizeof(_face)/sizeof(_face[0])); index++) {
|
||||
cellptr->Adjacent_Cell(_face[index]).Concrete_Calc();
|
||||
CellClass * adjcell = cellptr->Adjacent_Cell(_face[index]);
|
||||
if (adjcell) adjcell->Concrete_Calc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -539,12 +539,14 @@ bool Load_Game(const char *file_name)
|
|||
Map.Init_IO();
|
||||
Map.Flag_To_Redraw(true);
|
||||
|
||||
Fixup_Scenario();
|
||||
|
||||
ScenarioInit = 0;
|
||||
|
||||
/*
|
||||
** Fixup remap tables. ST - 2/28/2020 1:50PM
|
||||
*/
|
||||
for (HousesType house = HOUSE_MULTI1; house < HOUSE_COUNT; house++) {
|
||||
for (HousesType house = HOUSE_FIRST; house < HOUSE_COUNT; house++) {
|
||||
HouseClass * hptr = HouseClass::As_Pointer(house);
|
||||
if (hptr && hptr->IsActive) {
|
||||
hptr->Init_Data(hptr->RemapColor, hptr->ActLike, hptr->Credits);
|
||||
|
|
|
@ -138,16 +138,6 @@ bool Start_Scenario(char *root, bool briefing)
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Hack for laser-firing Orcas in the PATSUX secret mission
|
||||
*/
|
||||
if (GameToPlay == GAME_NORMAL && Scenario == 72) {
|
||||
((AircraftTypeClass&)AircraftTypeClass::As_Reference(AIRCRAFT_ORCA)).Primary = WEAPON_OBELISK_LASER;
|
||||
}
|
||||
else {
|
||||
((AircraftTypeClass&)AircraftTypeClass::As_Reference(AIRCRAFT_ORCA)).Primary = WEAPON_DRAGON;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the options values, since the palette has been initialized by Read_Scenario
|
||||
*/
|
||||
|
@ -786,4 +776,45 @@ bool Restate_Mission(char const * name, int button1, int button2)
|
|||
#endif
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
void Fixup_Scenario(void)
|
||||
{
|
||||
/*
|
||||
** "Fraidycat" civilians avoid wandering into Tiberium for SCG08EB, since they're mission-critical.
|
||||
*/
|
||||
bool is_scg08ea = GameToPlay == GAME_NORMAL && PlayerPtr->ActLike == HOUSE_GOOD && Scenario == 8 && ScenVar == SCEN_VAR_B;
|
||||
for (InfantryType index = INFANTRY_FIRST; index < INFANTRY_COUNT; index++) {
|
||||
InfantryTypeClass& infantry_type = (InfantryTypeClass&)InfantryTypeClass::As_Reference(index);
|
||||
if (infantry_type.IsFraidyCat) {
|
||||
infantry_type.IsAvoidingTiberium = is_scg08ea;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Laser-firing Orcas in the PATSUX secret mission
|
||||
*/
|
||||
if (GameToPlay == GAME_NORMAL && Scenario == 72) {
|
||||
((AircraftTypeClass&)AircraftTypeClass::As_Reference(AIRCRAFT_ORCA)).Primary = WEAPON_OBELISK_LASER;
|
||||
} 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;
|
||||
}
|
||||
}
|
|
@ -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];
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -317,7 +317,7 @@ int DLL_Startup(const char * command_line_in)
|
|||
if (Parse_Command_Line(argc, argv)) {
|
||||
|
||||
WindowsTimer = new WinTimerClass(60,FALSE);
|
||||
|
||||
#if (0)
|
||||
int time_test = WindowsTimer->Get_System_Tick_Count();
|
||||
Sleep (1000);
|
||||
if (WindowsTimer->Get_System_Tick_Count() == time_test){
|
||||
|
@ -332,6 +332,7 @@ int DLL_Startup(const char * command_line_in)
|
|||
#endif //FRENCH
|
||||
return(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
RawFileClass cfile("CONQUER.INI");
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -290,7 +290,15 @@ unsigned short TechnoTypeClass::Get_Ownable(void) const
|
|||
*=============================================================================================*/
|
||||
int TechnoTypeClass::Time_To_Build(HousesType house) const
|
||||
{
|
||||
int cost = Raw_Cost();
|
||||
/*
|
||||
** Base time is the raw cost.
|
||||
*/
|
||||
int time = Raw_Cost();
|
||||
|
||||
HouseClass* hptr = HouseClass::As_Pointer(house);
|
||||
if (!hptr || !hptr->IsActive) {
|
||||
return time;
|
||||
}
|
||||
|
||||
/*
|
||||
** For computer controlled buildings, slow down production on
|
||||
|
@ -299,9 +307,8 @@ int TechnoTypeClass::Time_To_Build(HousesType house) const
|
|||
if (PlayerPtr->Difficulty != DIFF_HARD &&
|
||||
GameToPlay == GAME_NORMAL &&
|
||||
What_Am_I() == RTTI_BUILDINGTYPE &&
|
||||
PlayerPtr->Class->House != house) {
|
||||
|
||||
cost = (cost + (PlayerPtr->Difficulty == DIFF_EASY ? 4000 : 2000)) / 2;
|
||||
PlayerPtr->Class->House != hptr->Class->House) {
|
||||
time = (time + (PlayerPtr->Difficulty == DIFF_EASY ? 4000 : 2000)) / 2;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -309,10 +316,35 @@ int TechnoTypeClass::Time_To_Build(HousesType house) const
|
|||
** an airfield.
|
||||
*/
|
||||
if (What_Am_I() == RTTI_UNITTYPE && !(Ownable & HOUSEF_GOOD)) {
|
||||
return (cost - (cost/4));
|
||||
time -= (time / 4);
|
||||
}
|
||||
|
||||
return(cost);
|
||||
/*
|
||||
** Adjust time according to IQ setting of computer controlled house. The
|
||||
** build time will range from double normal time at the slowest to
|
||||
** just normal time at the fastest.
|
||||
*/
|
||||
if (!hptr->IsHuman && Rule.Diff[hptr->Difficulty].IsBuildSlowdown) {
|
||||
time = (int)((time * Rule.MaxIQ * 2.0f) / (hptr->IQ + Rule.MaxIQ));
|
||||
}
|
||||
|
||||
/*
|
||||
** Adjust the time to build based on the power output of the owning house.
|
||||
*/
|
||||
int power = hptr->Power_Fraction();
|
||||
int inv_scale(256);
|
||||
if (power == 0x000) {
|
||||
inv_scale = 64;
|
||||
}
|
||||
else if (power < 0x080) {
|
||||
inv_scale = 103;
|
||||
}
|
||||
else if (power < 0x0100) {
|
||||
inv_scale = 171;
|
||||
}
|
||||
time = (time * 256) / inv_scale;
|
||||
|
||||
return(time);
|
||||
}
|
||||
|
||||
|
||||
|
@ -988,7 +1020,9 @@ void TechnoClass::Draw_It(int x, int y, WindowNumberType window)
|
|||
{
|
||||
Clear_Redraw_Flag();
|
||||
|
||||
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() ||
|
||||
((Special.HealthBarDisplayMode == SpecialClass::HB_DAMAGED) && (Strength < Techno_Type_Class()->MaxStrength)) ||
|
||||
(Special.HealthBarDisplayMode == SpecialClass::HB_ALWAYS));
|
||||
|
||||
|
@ -1013,10 +1047,8 @@ void TechnoClass::Draw_It(int x, int y, WindowNumberType window)
|
|||
for (int i = start_line; i < LineCount; i++) {
|
||||
CC_Draw_Line(Lines[i][0], Lines[i][1], Lines[i][2], Lines[i][3], (unsigned char)Lines[i][4], LineFrame, window);
|
||||
}
|
||||
if ((window == WINDOW_VIRTUAL) && (++LineFrame >= LineMaxFrames)) {
|
||||
LineCount = 0;
|
||||
LineFrame = 0;
|
||||
LineMaxFrames = 0;
|
||||
if (window == WINDOW_VIRTUAL) {
|
||||
LineFrame++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1159,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);
|
||||
}
|
||||
|
||||
|
@ -1212,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);
|
||||
}
|
||||
|
||||
|
@ -1335,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
|
||||
|
@ -1369,7 +1402,7 @@ bool TechnoClass::Evaluate_Object(ThreatType method, int mask, int range, Techno
|
|||
** If the scan is limited to capturable buildings only, then bail if the examined
|
||||
** object isn't a capturable building.
|
||||
*/
|
||||
if ((method & THREAT_CAPTURE) && (otype != RTTI_BUILDING || !((BuildingTypeClass const *)tclass)->IsCaptureable)) {
|
||||
if ((method & THREAT_CAPTURE) && (otype != RTTI_BUILDING || !object->Can_Capture())) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
@ -1968,8 +2001,13 @@ void TechnoClass::AI(void)
|
|||
/*
|
||||
** Handle line delay logic.
|
||||
*/
|
||||
if ((LineMaxFrames > 0) && (LineCount > 0)) {
|
||||
if (LineMaxFrames > 0) {
|
||||
Map.Flag_To_Redraw(true);
|
||||
if (LineFrame >= LineMaxFrames) {
|
||||
LineCount = 0;
|
||||
LineFrame = 0;
|
||||
LineMaxFrames = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2066,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);
|
||||
}
|
||||
|
||||
|
@ -2249,6 +2287,9 @@ BulletClass * TechnoClass::Fire_At(TARGET target, int which)
|
|||
COORDINATE fire_coord; // Coordinate of firing position.
|
||||
TechnoTypeClass const & tclass = *Techno_Type_Class();
|
||||
ObjectClass *object;
|
||||
if ((which == 0 && tclass.Primary == WEAPON_NONE) || (which != 0 && tclass.Secondary == WEAPON_NONE)) {
|
||||
return(NULL);
|
||||
}
|
||||
WeaponTypeClass const *weapon = (which == 0) ? &Weapons[tclass.Primary] : &Weapons[tclass.Secondary];
|
||||
BulletTypeClass const &btype = BulletTypeClass::As_Reference(weapon->Fires);
|
||||
|
||||
|
@ -2385,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 (only humans in normal node) that is the target. ST - 3/13/2019 5:43PM
|
||||
*/
|
||||
|
||||
ObjectClass *obj = As_Object(target);
|
||||
|
@ -2393,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 && (player->IsHuman || GameToPlay != GAME_NORMAL)) {
|
||||
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);
|
||||
}
|
||||
|
@ -2558,11 +2599,17 @@ ActionType TechnoClass::What_Action(ObjectClass * object) const
|
|||
//if (IsOwnedByPlayer && (ctrldown || !House->Is_Ally(object)) && (ctrldown || object->Class_Of().IsLegalTarget || (Special.IsTreeTarget && object->What_Am_I() == RTTI_TERRAIN))) {
|
||||
if (Can_Player_Move() || In_Range(object, 0)) {
|
||||
// Check for anti-air capability
|
||||
if ((object->What_Am_I() != RTTI_AIRCRAFT) ||
|
||||
((Techno_Type_Class()->Primary != WEAPON_NONE) && BulletTypeClass::As_Reference(Weapons[Techno_Type_Class()->Primary].Fires).IsAntiAircraft) ||
|
||||
((Techno_Type_Class()->Secondary != WEAPON_NONE) && BulletTypeClass::As_Reference(Weapons[Techno_Type_Class()->Secondary].Fires).IsAntiAircraft) ||
|
||||
(((AircraftClass *)object)->Altitude == 0)) {
|
||||
if (object->What_Am_I() != RTTI_AIRCRAFT) {
|
||||
return(ACTION_ATTACK);
|
||||
} else {
|
||||
AircraftClass* aircraft = (AircraftClass*)object;
|
||||
if (*aircraft != AIRCRAFT_CARGO) {
|
||||
if (((Techno_Type_Class()->Primary != WEAPON_NONE) && BulletTypeClass::As_Reference(Weapons[Techno_Type_Class()->Primary].Fires).IsAntiAircraft) ||
|
||||
((Techno_Type_Class()->Secondary != WEAPON_NONE) && BulletTypeClass::As_Reference(Weapons[Techno_Type_Class()->Secondary].Fires).IsAntiAircraft) ||
|
||||
(aircraft->Altitude == 0)) {
|
||||
return(ACTION_ATTACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4396,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4570,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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -1111,6 +1111,12 @@ class InfantryTypeClass : public TechnoTypeClass
|
|||
*/
|
||||
unsigned IsCivilian:1;
|
||||
|
||||
/*
|
||||
** For "fraidycat" infantry types that will run away from any damage causing
|
||||
** events, this controls whether they avoid wandering into Tiberium.
|
||||
*/
|
||||
unsigned IsAvoidingTiberium:1;
|
||||
|
||||
/*
|
||||
** This value represents the unit class. It can serve as a unique
|
||||
** identification number for this unit class.
|
||||
|
@ -1642,7 +1648,7 @@ class AnimTypeClass : public ObjectTypeClass
|
|||
** This is the normal loop count for this animation. Usually this is one, but
|
||||
** for some animations, it may be larger.
|
||||
*/
|
||||
unsigned char Loops;
|
||||
char Loops;
|
||||
|
||||
/*
|
||||
** This is the sound effect to play when this animation starts. Usually, this
|
||||
|
|
|
@ -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">
|
||||
|
@ -210,6 +210,7 @@
|
|||
<ClInclude Include="DIAL8.H" />
|
||||
<ClInclude Include="DISPLAY.H" />
|
||||
<ClInclude Include="DLLInterface.h" />
|
||||
<ClInclude Include="DLLInterfaceVersion.h" />
|
||||
<ClInclude Include="DOOR.H" />
|
||||
<ClInclude Include="DPMI.H" />
|
||||
<ClInclude Include="DRIVE.H" />
|
||||
|
|
|
@ -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">
|
||||
|
@ -627,6 +627,9 @@
|
|||
<ClInclude Include="RULES.H">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DLLInterfaceVersion.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AADATA.CPP">
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
@ -583,6 +590,13 @@ RadioMessageType UnitClass::Receive_Message(RadioClass * from, RadioMessageType
|
|||
Validate();
|
||||
switch (message) {
|
||||
|
||||
/*
|
||||
** Checks to see if this object is in need of service depot processing.
|
||||
*/
|
||||
case RADIO_NEED_REPAIR:
|
||||
if (!IsDriving && !Target_Legal(NavCom) && Health_Ratio() >= 0x100) return(RADIO_NEGATIVE);
|
||||
break;
|
||||
|
||||
/*
|
||||
** Asks if the passenger can load on this transport.
|
||||
*/
|
||||
|
@ -623,6 +637,38 @@ RadioMessageType UnitClass::Receive_Message(RadioClass * from, RadioMessageType
|
|||
** to the impatient unit.
|
||||
*/
|
||||
case RADIO_DOCKING:
|
||||
|
||||
/*
|
||||
** Check for the case of a docking message arriving from a unit that does not
|
||||
** have formal radio contact established. This might be a unit that is standing
|
||||
** by. If this transport is free to proceed with normal docking operation, then
|
||||
** establish formal contact now. If the transport is completely full, then break
|
||||
** off contact. In all other cases, just tell the pending unit to stand by.
|
||||
*/
|
||||
if (Contact_With_Whom() != from) {
|
||||
|
||||
/*
|
||||
** Can't ever load up so tell the passenger to bug off.
|
||||
*/
|
||||
if (How_Many() >= Class->Max_Passengers()) {
|
||||
return(RADIO_NEGATIVE);
|
||||
}
|
||||
|
||||
/*
|
||||
** Establish contact and let the loading process proceed normally.
|
||||
*/
|
||||
if (!In_Radio_Contact()) {
|
||||
Transmit_Message(RADIO_HELLO, from);
|
||||
} else {
|
||||
|
||||
/*
|
||||
** This causes the potential passenger to think that all is ok and to
|
||||
** hold on for a bit.
|
||||
*/
|
||||
return(RADIO_ROGER);
|
||||
}
|
||||
}
|
||||
|
||||
if (Class->IsTransporter && *this == UNIT_APC && How_Many() < Class->Max_Passengers()) {
|
||||
TarComClass::Receive_Message(from, message, param);
|
||||
|
||||
|
@ -703,6 +749,22 @@ RadioMessageType UnitClass::Receive_Message(RadioClass * from, RadioMessageType
|
|||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
** Something bad has happened to the object in contact with. Abort any coordinated
|
||||
** activity with this object. Basically, ... run away! Run away!
|
||||
*/
|
||||
case RADIO_RUN_AWAY:
|
||||
if (Class->IsToHarvest && In_Radio_Contact() && Mission == MISSION_ENTER) {
|
||||
TechnoClass * contact = Contact_With_Whom();
|
||||
if (contact->What_Am_I() == RTTI_BUILDING && *((BuildingClass*)contact) == STRUCT_REFINERY) {
|
||||
// Slight hack; set a target so the harvest mission knows to skip to finding home state
|
||||
Assign_Mission(MISSION_HARVEST);
|
||||
TarCom = As_Target();
|
||||
return(RADIO_ROGER);
|
||||
}
|
||||
}
|
||||
return(DriveClass::Receive_Message(from, message, param));
|
||||
|
||||
/*
|
||||
** When this message is received, it means that the other object
|
||||
** has already turned its radio off. Turn this radio off as well.
|
||||
|
@ -1152,6 +1214,7 @@ UnitClass::UnitClass(UnitType classid, HousesType house) :
|
|||
Reload = 0;
|
||||
Ammo = Class->MaxAmmo;
|
||||
IsCloakable = Class->IsCloakable;
|
||||
TiberiumUnloadRefinery = NULL;
|
||||
if (Class->IsAnimating) Set_Rate(Options.Normalize_Delay(3));
|
||||
|
||||
/*
|
||||
|
@ -1215,6 +1278,21 @@ void UnitClass::Active_Click_With(ActionType action, ObjectClass * object)
|
|||
void UnitClass::Active_Click_With(ActionType action, CELL cell) {TarComClass::Active_Click_With(action, cell);};
|
||||
|
||||
|
||||
void UnitClass::Player_Assign_Mission(MissionType mission, TARGET target, TARGET destination)
|
||||
{
|
||||
Validate();
|
||||
if (mission == MISSION_HARVEST) {
|
||||
ArchiveTarget = TARGET_NONE;
|
||||
} else if (mission == MISSION_ENTER) {
|
||||
BuildingClass* building = As_Building(destination);
|
||||
if (building != NULL && *building == STRUCT_REFINERY && building->In_Radio_Contact()) {
|
||||
building->Transmit_Message(RADIO_OVER_OUT);
|
||||
}
|
||||
}
|
||||
TarComClass::Player_Assign_Mission(mission, target, destination);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* UnitClass::Enter_Idle_Mode -- Unit enters idle mode state. *
|
||||
* *
|
||||
|
@ -1744,7 +1822,7 @@ void UnitClass::Per_Cell_Process(bool center)
|
|||
return;
|
||||
|
||||
default:
|
||||
Scatter(true);
|
||||
Scatter(0, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1755,28 +1833,39 @@ void UnitClass::Per_Cell_Process(bool center)
|
|||
** When breaking away from a transport object or building, possibly
|
||||
** scatter or otherwise begin normal unit operations.
|
||||
*/
|
||||
if (IsTethered && center && Mission != MISSION_ENTER && (*this != UNIT_APC || IsDriving || !Target_Legal(TarCom))) {
|
||||
TechnoClass * contact = Contact_With_Whom();
|
||||
if (Transmit_Message(RADIO_UNLOADED) == RADIO_RUN_AWAY) {
|
||||
if (*this == UNIT_HARVESTER && contact && contact->What_Am_I() == RTTI_BUILDING) {
|
||||
Assign_Mission(MISSION_HARVEST);
|
||||
} else if (!Target_Legal(NavCom)) {
|
||||
Scatter(0, true);
|
||||
}
|
||||
if (IsTethered && center &&
|
||||
(Mission != MISSION_ENTER || (As_Techno(NavCom) != NULL && Contact_With_Whom() != As_Techno(NavCom))) &&
|
||||
Mission != MISSION_UNLOAD) {
|
||||
/*
|
||||
** Special hack check to make sure that even though it has moved one
|
||||
** cell, if it is still on the building (e.g., service depot), have
|
||||
** it scatter again.
|
||||
*/
|
||||
if (Map[cell].Cell_Building() != NULL && !Target_Legal(NavCom)) {
|
||||
Scatter(0, true, true);
|
||||
} else {
|
||||
if (*this == UNIT_HARVESTER) {
|
||||
if (Target_Legal(ArchiveTarget)) {
|
||||
TechnoClass * contact = Contact_With_Whom();
|
||||
if (Transmit_Message(RADIO_UNLOADED) == RADIO_RUN_AWAY) {
|
||||
if (*this == UNIT_HARVESTER && contact && contact->What_Am_I() == RTTI_BUILDING && *((BuildingClass*)contact) != STRUCT_REPAIR) {
|
||||
Assign_Mission(MISSION_HARVEST);
|
||||
Assign_Destination(ArchiveTarget);
|
||||
ArchiveTarget = TARGET_NONE;
|
||||
} else {
|
||||
} else if (!Target_Legal(NavCom)) {
|
||||
Scatter(0, true);
|
||||
}
|
||||
} else {
|
||||
if (*this == UNIT_HARVESTER) {
|
||||
if (Target_Legal(ArchiveTarget)) {
|
||||
Assign_Mission(MISSION_HARVEST);
|
||||
Assign_Destination(ArchiveTarget);
|
||||
ArchiveTarget = TARGET_NONE;
|
||||
} else {
|
||||
|
||||
/*
|
||||
** Since there is no place to go, move away to clear
|
||||
** the pad for another harvester.
|
||||
*/
|
||||
if (!Target_Legal(NavCom)) {
|
||||
Scatter(0, true);
|
||||
/*
|
||||
** Since there is no place to go, move away to clear
|
||||
** the pad for another harvester.
|
||||
*/
|
||||
if (!Target_Legal(NavCom)) {
|
||||
Scatter(0, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2204,7 +2293,10 @@ void UnitClass::Draw_It(int x, int y, WindowNumberType window)
|
|||
** If this unit is carrying the flag, then draw that on top of everything else.
|
||||
*/
|
||||
if (Flagged != HOUSE_NONE) {
|
||||
CC_Draw_Shape(this, "FLAGFLY", MixFileClass::Retrieve("FLAGFLY.SHP"), Frame % 14, x, y, window, SHAPE_CENTER|SHAPE_FADING|SHAPE_GHOST, HouseClass::As_Pointer(Flagged)->Remap_Table(false, false), Map.UnitShadow, Flagged);
|
||||
shapefile = MixFileClass::Retrieve("FLAGFLY.SHP");
|
||||
int flag_x = x + (ICON_PIXEL_W / 2) - 2;
|
||||
int flag_y = y + (3 * ICON_PIXEL_H / 4) - Get_Build_Frame_Height(shapefile);
|
||||
CC_Draw_Shape(this, "FLAGFLY", shapefile, Frame % 14, flag_x, flag_y, window, SHAPE_CENTER|SHAPE_FADING|SHAPE_GHOST, HouseClass::As_Pointer(Flagged)->Remap_Table(false, false), Map.UnitShadow, Flagged);
|
||||
}
|
||||
|
||||
TarComClass::Draw_It(x, y, window);
|
||||
|
@ -2221,34 +2313,34 @@ void UnitClass::Draw_It(int x, int y, WindowNumberType window)
|
|||
* *
|
||||
* INPUT: none *
|
||||
* *
|
||||
* OUTPUT: bool; Is it located directly over a Tiberium patch? *
|
||||
* OUTPUT: int; Amount of Tiberium at this location. *
|
||||
* *
|
||||
* WARNINGS: none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 07/18/1994 JLB : Created. *
|
||||
*=============================================================================================*/
|
||||
bool UnitClass::Tiberium_Check(CELL ¢er, int x, int y)
|
||||
int UnitClass::Tiberium_Check(CELL ¢er, int x, int y)
|
||||
{
|
||||
Validate();
|
||||
/*
|
||||
** If the specified offset from the origin will cause it
|
||||
** to spill past the map edge, then abort this cell check.
|
||||
*/
|
||||
if (Cell_X(center)+x < Map.MapCellX) return(false);
|
||||
if (Cell_X(center)+x >= Map.MapCellX+Map.MapCellWidth) return(false);
|
||||
if (Cell_Y(center)+y < Map.MapCellY) return(false);
|
||||
if (Cell_Y(center)+y >= Map.MapCellY+Map.MapCellHeight) return(false);
|
||||
if (Cell_X(center)+x < Map.MapCellX) return(0);
|
||||
if (Cell_X(center)+x >= Map.MapCellX+Map.MapCellWidth) return(0);
|
||||
if (Cell_Y(center)+y < Map.MapCellY) return(0);
|
||||
if (Cell_Y(center)+y >= Map.MapCellY+Map.MapCellHeight) return(0);
|
||||
|
||||
center = XY_Cell(Cell_X(center)+x, Cell_Y(center)+y);
|
||||
|
||||
//using function for IsVisible so we have different results for different players - JAS 2019/09/30
|
||||
if ((GameToPlay != GAME_NORMAL || (!IsOwnedByPlayer || Map[center].Is_Visible(PlayerPtr)))) {
|
||||
if (!Map[center].Cell_Techno() && Map[center].Land_Type() == LAND_TIBERIUM) {
|
||||
return(true);
|
||||
return(Map[center].OverlayData+1);
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2265,31 +2357,60 @@ bool UnitClass::Goto_Tiberium(void)
|
|||
** Perform a ring search outward from the center.
|
||||
*/
|
||||
for (int radius = 1; radius < 64; radius++) {
|
||||
CELL cell = center;
|
||||
CELL bestcell = 0;
|
||||
int tiberium = 0;
|
||||
int besttiberium = 0;
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
CELL cell = center;
|
||||
if (Tiberium_Check(cell, x, -radius)) {
|
||||
Assign_Destination(::As_Target(cell));
|
||||
return(false);
|
||||
|
||||
/*
|
||||
** Randomize the corners.
|
||||
*/
|
||||
int corner[2];
|
||||
int corners[4][2] = {
|
||||
{x, -radius},
|
||||
{x, +radius},
|
||||
{-radius, x},
|
||||
{+radius, x}
|
||||
};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int j = i + rand() / (RAND_MAX / (4 - i) + 1);
|
||||
memcpy(&corner, &corners[j], sizeof(corner));
|
||||
memcpy(&corners[j], &corners[i], sizeof(corner));
|
||||
memcpy(&corners[i], corner, sizeof(corner));
|
||||
}
|
||||
|
||||
cell = center;
|
||||
if (Tiberium_Check(cell, x, +radius)) {
|
||||
Assign_Destination(::As_Target(cell));
|
||||
return(false);
|
||||
tiberium = Tiberium_Check(cell, corners[0][0], corners[0][1]);
|
||||
if (tiberium > besttiberium) {
|
||||
bestcell = cell;
|
||||
besttiberium = tiberium;
|
||||
}
|
||||
|
||||
cell = center;
|
||||
if (Tiberium_Check(cell, -radius, x)) {
|
||||
Assign_Destination(::As_Target(cell));
|
||||
return(false);
|
||||
tiberium = Tiberium_Check(cell, corners[1][0], corners[1][1]);
|
||||
if (tiberium > besttiberium) {
|
||||
bestcell = cell;
|
||||
besttiberium = tiberium;
|
||||
}
|
||||
|
||||
|
||||
cell = center;
|
||||
if (Tiberium_Check(cell, +radius, x)) {
|
||||
Assign_Destination(::As_Target(cell));
|
||||
return(false);
|
||||
tiberium = Tiberium_Check(cell, corners[2][0], corners[2][1]);
|
||||
if (tiberium > besttiberium) {
|
||||
bestcell = cell;
|
||||
besttiberium = tiberium;
|
||||
}
|
||||
|
||||
cell = center;
|
||||
tiberium = Tiberium_Check(cell, corners[3][0], corners[3][1]);
|
||||
if (tiberium > besttiberium) {
|
||||
bestcell = cell;
|
||||
besttiberium = tiberium;
|
||||
}
|
||||
}
|
||||
if (bestcell) {
|
||||
Assign_Destination(::As_Target(bestcell));
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2299,6 +2420,29 @@ bool UnitClass::Goto_Tiberium(void)
|
|||
}
|
||||
|
||||
|
||||
BuildingClass* UnitClass::Find_Best_Refinery(void) const
|
||||
{
|
||||
/*
|
||||
** Remember our last refinery and prefer that one, if still available and valid.
|
||||
*/
|
||||
if (TiberiumUnloadRefinery != NULL) {
|
||||
if (TiberiumUnloadRefinery->House == House &&
|
||||
!TiberiumUnloadRefinery->IsInLimbo &&
|
||||
TiberiumUnloadRefinery->Mission != MISSION_DECONSTRUCTION &&
|
||||
*TiberiumUnloadRefinery == STRUCT_REFINERY) {
|
||||
return TiberiumUnloadRefinery;
|
||||
} else {
|
||||
TiberiumUnloadRefinery = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Find nearby refinery and head to it?
|
||||
*/
|
||||
return Find_Docking_Bay(STRUCT_REFINERY, false);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* UnitClass::Harvesting -- Harvests tiberium at the current location. *
|
||||
* *
|
||||
|
@ -2584,11 +2728,19 @@ 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);
|
||||
Status = HARVESTING;
|
||||
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
|
||||
return(1);
|
||||
} else {
|
||||
|
||||
|
@ -2623,7 +2775,6 @@ int UnitClass::Mission_Harvest(void)
|
|||
IsHarvesting = false;
|
||||
if (Tiberium_Load() == 0x0100) {
|
||||
Status = FINDHOME;
|
||||
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
|
||||
} else {
|
||||
if (!Goto_Tiberium() && !Target_Legal(NavCom)) {
|
||||
ArchiveTarget = TARGET_NONE;
|
||||
|
@ -2634,6 +2785,8 @@ int UnitClass::Mission_Harvest(void)
|
|||
}
|
||||
}
|
||||
return(1);
|
||||
} else if (!Target_Legal(NavCom) && ArchiveTarget == TARGET_NONE) {
|
||||
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -2644,9 +2797,9 @@ int UnitClass::Mission_Harvest(void)
|
|||
if (!Target_Legal(NavCom)) {
|
||||
|
||||
/*
|
||||
** Find nearby refinery and head to it?
|
||||
** Find best refinery.
|
||||
*/
|
||||
BuildingClass * nearest = Find_Docking_Bay(STRUCT_REFINERY, false);
|
||||
BuildingClass * nearest = Find_Best_Refinery();
|
||||
|
||||
/*
|
||||
** Since the refinery said it was ok to load, establish radio
|
||||
|
@ -2656,7 +2809,7 @@ int UnitClass::Mission_Harvest(void)
|
|||
Status = HEADINGHOME;
|
||||
} else {
|
||||
ScenarioInit++;
|
||||
nearest = Find_Docking_Bay(STRUCT_REFINERY, false);
|
||||
nearest = Find_Best_Refinery();
|
||||
ScenarioInit--;
|
||||
if (nearest) {
|
||||
Assign_Destination(::As_Target(nearest->Nearby_Location(this)));
|
||||
|
@ -2753,6 +2906,28 @@ int UnitClass::Mission_Hunt(void)
|
|||
}
|
||||
|
||||
|
||||
int UnitClass::Mission_Enter(void)
|
||||
{
|
||||
Validate();
|
||||
if (Class->IsToHarvest) {
|
||||
TechnoClass * contact = Contact_With_Whom();
|
||||
if (contact == NULL) {
|
||||
contact = As_Techno(ArchiveTarget);
|
||||
}
|
||||
if (contact == NULL) {
|
||||
contact = As_Techno(NavCom);
|
||||
}
|
||||
if (contact != NULL &&
|
||||
contact->What_Am_I() == RTTI_BUILDING &&
|
||||
*((BuildingClass*)contact) == STRUCT_REFINERY) {
|
||||
TiberiumUnloadRefinery = (BuildingClass*)contact;
|
||||
}
|
||||
}
|
||||
|
||||
return(TarComClass::Mission_Enter());
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* UnitClass::Look -- Perform map revelation from a unit's position. *
|
||||
* *
|
||||
|
@ -2778,7 +2953,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) {
|
||||
|
@ -2823,7 +2998,7 @@ short const * UnitClass::Overlap_List(void) const
|
|||
if (Is_Selected_By_Player() || IsFiring) {
|
||||
size += 24;
|
||||
}
|
||||
if (Is_Selected_By_Player() || Class->IsGigundo || IsAnimAttached) {
|
||||
if (Is_Selected_By_Player() || Class->IsGigundo || IsAnimAttached || Flagged != HOUSE_NONE) {
|
||||
size = ICON_PIXEL_W*2;
|
||||
}
|
||||
return(Coord_Spillage_List(Coord, size)+1);
|
||||
|
@ -3245,7 +3420,11 @@ void UnitClass::Scatter(COORDINATE threat, bool forced, bool nokidding)
|
|||
{
|
||||
Validate();
|
||||
if (*this != UNIT_GUNBOAT && *this != UNIT_HOVER) {
|
||||
if (!PrimaryFacing.Is_Rotating() && ((!Target_Legal(TarCom) && !Target_Legal(NavCom)) || forced || nokidding || Random_Pick(1, 4) == 1)) {
|
||||
if (PrimaryFacing.Is_Rotating()) return;
|
||||
if (Target_Legal(NavCom) && !nokidding) return;
|
||||
if (threat == 0) {
|
||||
Assign_Destination(::As_Target(Map.Nearby_Location(Coord_Cell(Coord))));
|
||||
} else if (((!Target_Legal(TarCom) && !Target_Legal(NavCom)) || forced || nokidding || Random_Pick(1, 4) == 1)) {
|
||||
FacingType toface;
|
||||
FacingType newface;
|
||||
CELL newcell;
|
||||
|
@ -3375,7 +3554,13 @@ bool UnitClass::Limbo(void)
|
|||
if (!IsInLimbo) {
|
||||
Stop_Driver();
|
||||
}
|
||||
return(TarComClass::Limbo());
|
||||
if (TarComClass::Limbo()) {
|
||||
if (Flagged != HOUSE_NONE) {
|
||||
HouseClass::As_Pointer(Flagged)->Flag_Attach(Coord_Cell(Coord));
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3543,16 +3728,14 @@ ActionType UnitClass::What_Action(ObjectClass * object) const
|
|||
/*
|
||||
** Special return to friendly refinery action.
|
||||
*/
|
||||
if (IsOwnedByPlayer && object->Is_Techno() && ((TechnoClass const *)object)->House->Is_Ally(this)) {
|
||||
if (object->What_Am_I() == RTTI_BUILDING && ((UnitClass *)this)->Transmit_Message(RADIO_CAN_LOAD, (TechnoClass*)object) == RADIO_ROGER) {
|
||||
action = ACTION_ENTER;
|
||||
}
|
||||
if (Is_Owned_By_Player() && House->Class->House == object->Owner() && object->What_Am_I() == RTTI_BUILDING && ((UnitClass *)this)->Transmit_Message(RADIO_CAN_LOAD, (TechnoClass*)object) == RADIO_ROGER) {
|
||||
action = ACTION_ENTER;
|
||||
}
|
||||
|
||||
/*
|
||||
** Special return to friendly repair factory action.
|
||||
*/
|
||||
if (IsOwnedByPlayer && action == ACTION_SELECT && object->What_Am_I() == RTTI_BUILDING) {
|
||||
if (Is_Owned_By_Player() && House->Class->House == object->Owner() && action == ACTION_SELECT && object->What_Am_I() == RTTI_BUILDING) {
|
||||
BuildingClass * building = (BuildingClass *)object;
|
||||
if (building->Class->Type == STRUCT_REPAIR && !building->In_Radio_Contact() && !building->Is_Something_Attached()) {
|
||||
action = ACTION_MOVE;
|
||||
|
|
|
@ -75,7 +75,7 @@ class UnitClass : public TarComClass
|
|||
bool Goto_Clear_Spot(void);
|
||||
bool Try_To_Deploy(void);
|
||||
|
||||
bool Tiberium_Check(CELL ¢er, int x, int y);
|
||||
int Tiberium_Check(CELL ¢er, int x, int y);
|
||||
bool Flag_Attach(HousesType house);
|
||||
bool Flag_Remove(void);
|
||||
void Find_LZ(void);
|
||||
|
@ -84,6 +84,7 @@ class UnitClass : public TarComClass
|
|||
bool Harvesting(void);
|
||||
void APC_Close_Door(void);
|
||||
void APC_Open_Door(void);
|
||||
virtual BuildingClass* Find_Best_Refinery(void) const;
|
||||
|
||||
/*
|
||||
** Query functions.
|
||||
|
@ -125,6 +126,7 @@ class UnitClass : public TarComClass
|
|||
virtual ActionType What_Action(ObjectClass * object) const;
|
||||
virtual void Active_Click_With(ActionType action, ObjectClass * object);
|
||||
virtual void Active_Click_With(ActionType action, CELL cell);
|
||||
virtual void Player_Assign_Mission(MissionType mission, TARGET target=TARGET_NONE, TARGET destination=TARGET_NONE);
|
||||
virtual void Response_Select(void);
|
||||
virtual void Response_Move(void);
|
||||
virtual void Response_Attack(void);
|
||||
|
@ -155,6 +157,7 @@ class UnitClass : public TarComClass
|
|||
virtual int Mission_Guard(void);
|
||||
virtual int Mission_Harvest(void);
|
||||
virtual int Mission_Hunt(void);
|
||||
virtual int Mission_Enter(void);
|
||||
virtual int UnitClass::Mission_Move(void);
|
||||
virtual FireErrorType Can_Fire(TARGET, int which) const;
|
||||
|
||||
|
@ -198,10 +201,15 @@ class UnitClass : public TarComClass
|
|||
*/
|
||||
TCountDownTimerClass HarvestTimer;
|
||||
|
||||
/*
|
||||
** This is the refinery a harvester is interested in unloading at.
|
||||
*/
|
||||
mutable BuildingClass* TiberiumUnloadRefinery;
|
||||
|
||||
/*
|
||||
** 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
|
||||
|
|
|
@ -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#33 $
|
||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/DrawMisc.cpp#138 $
|
||||
;***************************************************************************
|
||||
;** 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#33 $
|
||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/FACINGFF.h#138 $
|
||||
;***************************************************************************
|
||||
;** 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 **
|
||||
;***************************************************************************
|
||||
|
|
Reference in a new issue