Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
da1c97b86d
71 changed files with 1354 additions and 573 deletions
|
@ -2112,6 +2112,31 @@ static AnimTypeClass const MineExp1(
|
|||
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, // Theater specific art imagery?
|
||||
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?
|
||||
0, // 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
|
||||
);
|
||||
|
||||
#ifdef FIXIT_ANTS
|
||||
static AnimTypeClass const Ant1Death(
|
||||
ANIM_ANT1_DEATH, // Animation number.
|
||||
|
@ -2424,6 +2449,7 @@ void AnimTypeClass::Init_Heap(void)
|
|||
new AnimTypeClass(CrateTQuake);
|
||||
new AnimTypeClass(ParaBomb);
|
||||
new AnimTypeClass(MineExp1);
|
||||
new AnimTypeClass(Flag);
|
||||
#ifdef FIXIT_ANTS
|
||||
new AnimTypeClass(Ant1Death);
|
||||
new AnimTypeClass(Ant2Death);
|
||||
|
|
|
@ -1621,9 +1621,13 @@ 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());
|
||||
COORDINATE coord = Target_Coord();
|
||||
if (!(coord & HIGH_COORD_MASK)) {
|
||||
new AnimClass(ANIM_FBALL1, coord);
|
||||
}
|
||||
|
||||
/*
|
||||
** Parachute a survivor if possible.
|
||||
|
@ -1638,6 +1642,7 @@ ResultType AircraftClass::Take_Damage(int & damage, int distance, WarheadType wa
|
|||
}
|
||||
|
||||
delete this;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -260,6 +260,24 @@ void AnimClass::Draw_It(int x, int y, WindowNumberType window) const
|
|||
void const * transtable = NULL;
|
||||
int shapenum = Class->Start + Fetch_Stage();
|
||||
void const * remap = NULL;
|
||||
ShapeFlags_Type flags = SHAPE_CENTER|SHAPE_WIN_REL;
|
||||
bool alt = false;
|
||||
|
||||
/*
|
||||
** Some animations require special fixups.
|
||||
*/
|
||||
switch (Class->Type) {
|
||||
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;
|
||||
alt = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** If the translucent table hasn't been determined yet, then check to see if it
|
||||
|
@ -267,13 +285,19 @@ void AnimClass::Draw_It(int x, int y, WindowNumberType window) const
|
|||
*/
|
||||
if (transtable == NULL && Class->IsWhiteTrans) transtable = DisplayClass::WhiteTranslucentTable;
|
||||
if (transtable == NULL && Class->IsTranslucent) transtable = DisplayClass::TranslucentTable;
|
||||
if (Class->Type == ANIM_ATOM_BLAST) transtable = Map.UnitShadow;
|
||||
|
||||
/*
|
||||
** Set the shape flags to properly take into account any fading or ghosting
|
||||
** table necessary.
|
||||
*/
|
||||
ShapeFlags_Type flags = SHAPE_CENTER|SHAPE_WIN_REL;
|
||||
if (alt) {
|
||||
flags = flags | SHAPE_FADING;
|
||||
if (OwnerHouse != HOUSE_NONE) {
|
||||
remap = HouseClass::As_Pointer(OwnerHouse)->Remap_Table(false);
|
||||
} else {
|
||||
remap = ColorRemaps[PCOLOR_GOLD].RemapTable;
|
||||
}
|
||||
}
|
||||
if (transtable != NULL) flags = flags | SHAPE_GHOST;
|
||||
|
||||
/*
|
||||
|
@ -357,6 +381,7 @@ short const * AnimClass::Overlap_List(void) const
|
|||
( MAP_CELL_W * 2) - 1, ( MAP_CELL_W * 2), ( MAP_CELL_W * 2) + 1,
|
||||
REFRESH_EOL
|
||||
};
|
||||
static short const OverlapFlag[] = { 0, 1, -MAP_CELL_W, -(MAP_CELL_W-1), MAP_CELL_W, MAP_CELL_W+1, REFRESH_EOL };
|
||||
|
||||
if (IsToDelete) {
|
||||
static short const _list[] = {REFRESH_EOL};
|
||||
|
@ -367,6 +392,10 @@ short const * AnimClass::Overlap_List(void) const
|
|||
return(OverlapAtom);
|
||||
}
|
||||
|
||||
if (Class->Type == ANIM_FLAG) {
|
||||
return(OverlapFlag);
|
||||
}
|
||||
|
||||
#ifdef PARTIAL
|
||||
IsTheaterShape = Class->IsTheater;
|
||||
if (Class->Get_Image_Data() != NULL) {
|
||||
|
@ -512,7 +541,7 @@ 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) :
|
||||
AnimClass::AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay, char loop) :
|
||||
ObjectClass(RTTI_ANIM, Anims.ID(this)),
|
||||
Class(AnimTypes.Ptr((int)animnum)),
|
||||
xObject(TARGET_NONE),
|
||||
|
@ -559,8 +588,12 @@ IsTheaterShape = false;
|
|||
Map.Sight_From(Coord_Cell(coord), Rule.DropZoneRadius / CELL_LEPTON_W, PlayerPtr, false);
|
||||
}
|
||||
|
||||
Loops = (unsigned char)(max(loop, 1) * Class->Loops);
|
||||
Loops = (unsigned char)max(Loops, 1);
|
||||
if (Class->Loops >= 0) {
|
||||
Loops = (char)(max(loop, 1) * Class->Loops);
|
||||
Loops = (char)max(Loops, 1);
|
||||
} else {
|
||||
Loops = Class->Loops;
|
||||
}
|
||||
|
||||
/*
|
||||
** If the animation starts immediately, then play the associated sound effect now.
|
||||
|
@ -812,8 +845,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 {
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ class AnimClass : public ObjectClass, public StageClass {
|
|||
|
||||
public:
|
||||
|
||||
AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay=0, unsigned char loop=1);
|
||||
AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay=0, char loop=1);
|
||||
AnimClass(NoInitClass const & x) : ObjectClass(x), Class(x), StageClass(x) {};
|
||||
virtual ~AnimClass(void);
|
||||
|
||||
|
@ -79,6 +79,7 @@ class AnimClass : public ObjectClass, public StageClass {
|
|||
void Set_Visible_Flags(unsigned flags) { VisibleFlags = flags; }
|
||||
unsigned Get_Visible_Flags() const { return (Delay == 0) ? VisibleFlags : 0; }
|
||||
|
||||
virtual HousesType Owner(void) const {return OwnerHouse;};
|
||||
virtual bool Can_Place_Here(COORDINATE ) const {return true;}
|
||||
virtual bool Mark(MarkType mark=MARK_CHANGE);
|
||||
virtual bool Render(bool forced) const;
|
||||
|
@ -121,7 +122,7 @@ class AnimClass : public ObjectClass, public StageClass {
|
|||
** This counter tells how many more times the animation should loop before it
|
||||
** terminates.
|
||||
*/
|
||||
unsigned char Loops;
|
||||
char Loops;
|
||||
|
||||
protected:
|
||||
void Middle(void);
|
||||
|
|
|
@ -358,6 +358,9 @@ RadioMessageType BuildingClass::Receive_Message(RadioClass * from, RadioMessageT
|
|||
*/
|
||||
case RADIO_OVER_OUT:
|
||||
Begin_Mode(BSTATE_IDLE);
|
||||
if (*this == STRUCT_REPAIR) {
|
||||
Assign_Mission(MISSION_GUARD);
|
||||
}
|
||||
TechnoClass::Receive_Message(from, message, param);
|
||||
return(RADIO_ROGER);
|
||||
|
||||
|
@ -4811,8 +4814,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);
|
||||
if (cptr->Cell_Building() == NULL) {
|
||||
CellClass * cptr = cellptr->Adjacent_Cell(f);
|
||||
if (cptr && cptr->Cell_Building() == NULL) {
|
||||
cptr->Incoming(coord, true, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,7 +125,8 @@ CellClass::CellClass(void) :
|
|||
Land(LAND_CLEAR),
|
||||
OverrideLand(LAND_NONE),
|
||||
IsMappedByPlayerMask(0),
|
||||
IsVisibleByPlayerMask(0)
|
||||
IsVisibleByPlayerMask(0),
|
||||
CTFFlag(NULL)
|
||||
{
|
||||
for (int zone = MZONE_FIRST; zone < MZONE_COUNT; zone++) {
|
||||
Zones[zone] = 0;
|
||||
|
@ -212,7 +213,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 = Coord_Fraction(object->Center_Coord());
|
||||
long dist = Distance(coord, click);
|
||||
|
@ -248,7 +249,7 @@ ObjectClass * CellClass::Cell_Find_Object(RTTIType rtti) const
|
|||
|
||||
ObjectClass * object = Cell_Occupier();
|
||||
|
||||
while (object != NULL) {
|
||||
while (object != NULL && object->IsActive) {
|
||||
if (object->What_Am_I() == rtti) {
|
||||
return(object);
|
||||
}
|
||||
|
@ -1236,14 +1237,6 @@ void CellClass::Draw_It(int x, int y, bool objects) const
|
|||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Draw the flag if there is one located at this cell.
|
||||
*/
|
||||
if (IsFlagged) {
|
||||
void const * flag_remap = HouseClass::As_Pointer(Owner)->Remap_Table(false, REMAP_NORMAL);
|
||||
CC_Draw_Shape(MFCD::Retrieve("FLAGFLY.SHP"), Frame % 14, x+(ICON_PIXEL_W/2), y+(ICON_PIXEL_H/2), WINDOW_TACTICAL, SHAPE_CENTER|SHAPE_GHOST|SHAPE_FADING, flag_remap, DisplayClass::UnitShadow);
|
||||
}
|
||||
|
||||
#ifdef CHEAT_KEYS
|
||||
}
|
||||
#endif
|
||||
|
@ -1263,22 +1256,20 @@ void CellClass::Draw_It(int x, int y, bool objects) const
|
|||
** hack overpass after the cells are redrawn so that subs can be
|
||||
** redrawn separately.
|
||||
*/
|
||||
ObjectClass * optr[20 + ARRAY_SIZE(Overlapper)];
|
||||
int count = 0;
|
||||
static DynamicVectorClass<ObjectClass*> optr(20 + ARRAY_SIZE(Overlapper));
|
||||
optr.Delete_All();
|
||||
ObjectClass * object = Cell_Occupier();
|
||||
while (object != NULL) {
|
||||
if (!object->IsActive) break;
|
||||
optr[count] = object;
|
||||
optr.Add(object);
|
||||
object->IsToDisplay = true;
|
||||
object = object->Next;
|
||||
count++;
|
||||
}
|
||||
for (int index = 0; index < ARRAY_SIZE(Overlapper); index++) {
|
||||
object = Overlapper[index];
|
||||
if (object != NULL && object->IsActive) {
|
||||
object->IsToDisplay = true;
|
||||
optr[count] = object;
|
||||
count++;
|
||||
optr.Add(object);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1286,7 +1277,7 @@ void CellClass::Draw_It(int x, int y, bool objects) const
|
|||
** Sort the object list so that objects will be drawn from
|
||||
** back to front.
|
||||
*/
|
||||
switch (count) {
|
||||
switch (optr.Count()) {
|
||||
|
||||
/*
|
||||
** If there are zero or one object, then sorting is
|
||||
|
@ -1325,14 +1316,14 @@ void CellClass::Draw_It(int x, int y, bool objects) const
|
|||
** a quicksort.
|
||||
*/
|
||||
default:
|
||||
qsort(optr, count, sizeof(optr[0]), _ocompare);
|
||||
qsort(&optr[0], optr.Count(), sizeof(ObjectClass*), _ocompare);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** Draw any objects that happen to be in or overlapping this cell.
|
||||
*/
|
||||
for (int index = 0; index < count; index++) {
|
||||
for (int index = 0; index < optr.Count(); index++) {
|
||||
object = optr[index];
|
||||
int xx,yy;
|
||||
if (object->IsToDisplay && (!object->Is_Techno() || ((TechnoClass *)object)->Visual_Character() == VISUAL_NORMAL) && Map.Coord_To_Pixel(object->Render_Coord(), xx, yy)) {
|
||||
|
@ -1608,9 +1599,9 @@ void CellClass::Wall_Update(void)
|
|||
static FacingType _offsets[5] = {FACING_N, FACING_E, FACING_S, FACING_W, FACING_NONE};
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
|
@ -1618,45 +1609,46 @@ 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 = (newcell->OverlayData & 0xFFF0) | 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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
Detach_This_From_All(::As_Target(newcell->Cell_Number()), true);
|
||||
}
|
||||
if (newcell.Overlay == OVERLAY_FENCE && (newcell.OverlayData == 16 || newcell.OverlayData == 32)) {
|
||||
newcell.Overlay = OVERLAY_NONE;
|
||||
newcell.OverlayData = 0;
|
||||
Detach_This_From_All(::As_Target(newcell.Cell_Number()), true);
|
||||
if (newcell->Overlay == OVERLAY_FENCE && (newcell->OverlayData == 16 || newcell->OverlayData == 32)) {
|
||||
newcell->Overlay = OVERLAY_NONE;
|
||||
newcell->OverlayData = 0;
|
||||
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;
|
||||
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;
|
||||
Detach_This_From_All(::As_Target(newcell->Cell_Number()), true);
|
||||
}
|
||||
|
||||
newcell.Recalc_Attributes();
|
||||
newcell.Redraw_Objects();
|
||||
newcell->Recalc_Attributes();
|
||||
newcell->Redraw_Objects();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1773,10 +1765,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();
|
||||
Detach_This_From_All(As_Target());
|
||||
|
||||
/*
|
||||
|
@ -2022,27 +2018,24 @@ 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
|
||||
{
|
||||
assert((unsigned)Cell_Number() <= MAP_CELL_TOTAL);
|
||||
|
||||
if (face == FACING_NONE) {
|
||||
return(this);
|
||||
}
|
||||
|
||||
if ((unsigned)face >= FACING_COUNT) {
|
||||
return(*this);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
//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 ((unsigned)ptr->Cell_Number() > MAP_CELL_TOTAL) return(*this);
|
||||
return(*ptr);
|
||||
return &Map[newcell];
|
||||
}
|
||||
|
||||
|
||||
|
@ -2144,10 +2137,10 @@ long CellClass::Tiberium_Adjust(bool pregame)
|
|||
*/
|
||||
for (FacingType face = FACING_FIRST; face < FACING_COUNT; face++) {
|
||||
if ((unsigned)::Adjacent_Cell(Cell_Number(), face) >= 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++;
|
||||
}
|
||||
}
|
||||
|
@ -2763,6 +2756,7 @@ bool CellClass::Flag_Place(HousesType house)
|
|||
if (!IsFlagged && Is_Clear_To_Move(SPEED_TRACK, false, false)) {
|
||||
IsFlagged = true;
|
||||
Owner = house;
|
||||
Flag_Update();
|
||||
Redraw_Objects();
|
||||
return(true);
|
||||
}
|
||||
|
@ -2791,6 +2785,7 @@ bool CellClass::Flag_Remove(void)
|
|||
if (IsFlagged) {
|
||||
IsFlagged = false;
|
||||
Owner = HOUSE_NONE;
|
||||
Flag_Update();
|
||||
Redraw_Objects();
|
||||
return(true);
|
||||
}
|
||||
|
@ -2798,6 +2793,34 @@ 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());
|
||||
if (CTFFlag) {
|
||||
CTFFlag->OwnerHouse = Owner;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CellClass::Flag_Destroy(void)
|
||||
{
|
||||
delete CTFFlag;
|
||||
CTFFlag = NULL;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CellClass::Shimmer -- Causes all objects in the cell to shimmer. *
|
||||
* *
|
||||
|
@ -3088,7 +3111,7 @@ bool CellClass::Spread_Tiberium(bool forced)
|
|||
}
|
||||
FacingType offset = Random_Pick(FACING_N, FACING_NW);
|
||||
for (FacingType index = FACING_N; index < FACING_COUNT; index++) {
|
||||
CellClass * newcell = &Adjacent_Cell(index+offset);
|
||||
CellClass * newcell = Adjacent_Cell(index+offset);
|
||||
|
||||
if (newcell != NULL && newcell->Can_Tiberium_Germinate()) {
|
||||
new OverlayClass(Random_Pick(OVERLAY_GOLD1, OVERLAY_GOLD4), newcell->Cell_Number());
|
||||
|
|
|
@ -231,8 +231,8 @@ class CellClass
|
|||
COORDINATE Cell_Coord(void) const;
|
||||
COORDINATE Closest_Free_Spot(COORDINATE coord, bool any=false) const;
|
||||
COORDINATE Free_Spot(void) const {return Closest_Free_Spot(Cell_Coord());}
|
||||
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));}
|
||||
CellClass const * Adjacent_Cell(FacingType face) const;
|
||||
InfantryClass * Cell_Infantry(void) const;
|
||||
LandType Land_Type(void) const {return((OverrideLand != LAND_NONE) ? OverrideLand : Land);}
|
||||
ObjectClass * Cell_Find_Object(RTTIType rtti) const;
|
||||
|
@ -263,6 +263,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.
|
||||
|
@ -323,10 +326,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
|
|
@ -190,7 +190,8 @@ void Explosion_Damage(COORDINATE coord, int strength, TechnoClass * source, Warh
|
|||
** further than one cell away.
|
||||
*/
|
||||
if (i != FACING_NONE) {
|
||||
cellptr = &Map[cell].Adjacent_Cell(i);
|
||||
cellptr = Map[cell].Adjacent_Cell(i);
|
||||
if (!cellptr) continue;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -3921,6 +3921,8 @@ void Handle_Team(int team, int action)
|
|||
TeamEvent = (char)action + 1;
|
||||
}
|
||||
|
||||
TeamFormDataStruct& team_form_data = TeamFormData[PlayerPtr->Class->House];
|
||||
|
||||
AllowVoice = true;
|
||||
switch (action) {
|
||||
|
||||
|
@ -3935,9 +3937,11 @@ 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()) {
|
||||
if (CurrentObject[0]->Is_Foot() && ((FootClass *)CurrentObject[0])->Group != team) {
|
||||
for (index = 0; index < CurrentObject.Count(); index++) {
|
||||
ObjectClass * obj = CurrentObject[index];
|
||||
if (obj->Is_Foot() && ((FootClass *)obj)->Group != team) {
|
||||
Unselect_All();
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (index = 0; index < Vessels.Count(); index++) {
|
||||
|
@ -4036,8 +4040,8 @@ void Handle_Team(int team, int action)
|
|||
case 2: {
|
||||
long minx = 0x7FFFFFFFL, miny = 0x7FFFFFFFL;
|
||||
long maxx = 0, maxy = 0;
|
||||
TeamSpeed[team] = SPEED_WHEEL;
|
||||
TeamMaxSpeed[team] = MPH_LIGHT_SPEED;
|
||||
team_form_data.TeamSpeed[team] = SPEED_WHEEL;
|
||||
team_form_data.TeamMaxSpeed[team] = MPH_LIGHT_SPEED;
|
||||
for (index = 0; index < Units.Count(); index++) {
|
||||
UnitClass * obj = Units.Ptr(index);
|
||||
if (obj && !obj->IsInLimbo && obj->House->IsPlayerControl) {
|
||||
|
@ -4051,9 +4055,9 @@ void Handle_Team(int team, int action)
|
|||
if (xc > maxx) maxx = xc;
|
||||
if (yc < miny) miny = yc;
|
||||
if (yc > maxy) maxy = yc;
|
||||
if (obj->Class->MaxSpeed < TeamMaxSpeed[team]) {
|
||||
TeamMaxSpeed[team] = obj->Class->MaxSpeed;
|
||||
TeamSpeed[team] = obj->Class->Speed;
|
||||
if (obj->Class->MaxSpeed < team_form_data.TeamMaxSpeed[team]) {
|
||||
team_form_data.TeamMaxSpeed[team] = obj->Class->MaxSpeed;
|
||||
team_form_data.TeamSpeed[team] = obj->Class->Speed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4072,9 +4076,9 @@ void Handle_Team(int team, int action)
|
|||
if (xc > maxx) maxx = xc;
|
||||
if (yc < miny) miny = yc;
|
||||
if (yc > maxy) maxy = yc;
|
||||
if (obj->Class->MaxSpeed < TeamMaxSpeed[team]) {
|
||||
TeamMaxSpeed[team] = obj->Class->MaxSpeed;
|
||||
TeamSpeed[team] = obj->Class->Speed;
|
||||
if (obj->Class->MaxSpeed < team_form_data.TeamMaxSpeed[team]) {
|
||||
team_form_data.TeamMaxSpeed[team] = obj->Class->MaxSpeed;
|
||||
team_form_data.TeamSpeed[team] = obj->Class->Speed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4093,8 +4097,8 @@ void Handle_Team(int team, int action)
|
|||
if (xc > maxx) maxx = xc;
|
||||
if (yc < miny) miny = yc;
|
||||
if (yc > maxy) maxy = yc;
|
||||
if (obj->Class->MaxSpeed < TeamMaxSpeed[team]) {
|
||||
TeamMaxSpeed[team] = obj->Class->MaxSpeed;
|
||||
if (obj->Class->MaxSpeed < team_form_data.TeamMaxSpeed[team]) {
|
||||
team_form_data.TeamMaxSpeed[team] = obj->Class->MaxSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5300,8 +5304,7 @@ static void Do_Record_Playback(void)
|
|||
Session.RecordFile.Write (&TeamEvent, sizeof(TeamEvent));
|
||||
Session.RecordFile.Write (&TeamNumber, sizeof(TeamNumber));
|
||||
Session.RecordFile.Write (&FormationEvent, sizeof(FormationEvent));
|
||||
Session.RecordFile.Write (TeamMaxSpeed, sizeof(TeamMaxSpeed));
|
||||
Session.RecordFile.Write (TeamSpeed, sizeof(TeamSpeed));
|
||||
Session.RecordFile.Write (TeamFormData, sizeof(TeamFormData));
|
||||
Session.RecordFile.Write (&FormMove, sizeof(FormMove));
|
||||
Session.RecordFile.Write (&FormSpeed, sizeof(FormSpeed));
|
||||
Session.RecordFile.Write (&FormMaxSpeed, sizeof(FormMaxSpeed));
|
||||
|
@ -5372,11 +5375,11 @@ static void Do_Record_Playback(void)
|
|||
Toggle_Formation();
|
||||
}
|
||||
|
||||
Session.RecordFile.Read (TeamMaxSpeed, sizeof(TeamMaxSpeed));
|
||||
Session.RecordFile.Read (TeamSpeed, sizeof(TeamSpeed));
|
||||
Session.RecordFile.Read (&FormMove, sizeof(FormMove));
|
||||
Session.RecordFile.Read (&FormSpeed, sizeof(FormSpeed));
|
||||
Session.RecordFile.Read (&FormMaxSpeed, sizeof(FormMaxSpeed));
|
||||
Session.RecordFile.Read (TeamFormData, sizeof(TeamFormData));
|
||||
Session.RecordFile.Read (&FormMove, sizeof(FormMove));
|
||||
Session.RecordFile.Read (&FormSpeed, sizeof(FormSpeed));
|
||||
Session.RecordFile.Read (&FormMaxSpeed, sizeof(FormMaxSpeed));
|
||||
|
||||
/*
|
||||
** The map isn't drawn in playback mode, so draw it here.
|
||||
*/
|
||||
|
|
|
@ -2323,6 +2323,7 @@ typedef enum AnimType : char {
|
|||
ANIM_CRATE_TQUAKE,
|
||||
ANIM_PARA_BOMB,
|
||||
ANIM_MINE_EXP1,
|
||||
ANIM_FLAG,
|
||||
|
||||
#ifdef FIXIT_ANTS
|
||||
ANIM_ANT1_DEATH,
|
||||
|
|
|
@ -4024,7 +4024,7 @@ void DisplayClass::Mouse_Left_Release(CELL cell, int x, int y, ObjectClass * obj
|
|||
/*
|
||||
** Only consider objects that are owned by the player.
|
||||
*/
|
||||
if (!foot->IsOwnedByPlayer) continue;
|
||||
if (!foot->Is_Owned_By_Player()) continue;
|
||||
|
||||
/*
|
||||
** If another member of this team has been discovered and
|
||||
|
|
|
@ -107,6 +107,7 @@ typedef enum {
|
|||
|
||||
#define RANDOM_START_POSITION 0x7f
|
||||
|
||||
#define KILL_PLAYER_ON_DISCONNECT 1
|
||||
|
||||
|
||||
|
||||
|
@ -1999,18 +2000,34 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Player_Switch_To_AI(uin
|
|||
return;
|
||||
}
|
||||
|
||||
HousesType house;
|
||||
HouseClass *ptr;
|
||||
|
||||
GlyphX_Debug_Print("CNC_Handle_Player_Switch_To_AI");
|
||||
|
||||
if (GAME_TO_PLAY == GAME_NORMAL) {
|
||||
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;
|
||||
|
@ -2055,6 +2072,9 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Player_Switch_To_AI(uin
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif //KILL_PLAYER_ON_DISCONNECT
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -2898,12 +2918,24 @@ 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<player_count; i++) {
|
||||
// Trigger an event for each human player, winner first (even if it's an AI)
|
||||
for (int i = 0; i < player_count; i++) {
|
||||
HouseClass *player_ptr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
|
||||
if (player_ptr->IsHuman) {
|
||||
if (!player_ptr->IsDefeated) {
|
||||
event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
|
||||
event.GameOver.PlayerWins = !player_ptr->IsDefeated;
|
||||
event.GameOver.IsHuman = player_ptr->IsHuman;
|
||||
event.GameOver.PlayerWins = true;
|
||||
event.GameOver.RemainingCredits = player_ptr->Available_Money();
|
||||
EventCallback(event);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < player_count; i++) {
|
||||
HouseClass *player_ptr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
|
||||
if (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);
|
||||
}
|
||||
|
@ -4135,6 +4167,10 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Sidebar_Request(Sidebar
|
|||
|
||||
switch (request_type) {
|
||||
|
||||
// MBL 06.02.2020 - 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;
|
||||
|
@ -4372,7 +4408,7 @@ bool DLLExportClass::Get_Sidebar_State(uint64 player_id, unsigned char *buffer_i
|
|||
if (tech) {
|
||||
sidebar_entry.Cost = tech->Cost * PlayerPtr->CostBias;
|
||||
sidebar_entry.PowerProvided = 0;
|
||||
sidebar_entry.BuildTime = tech->Time_To_Build(); // sidebar_entry.BuildTime = tech->Time_To_Build() / 60;
|
||||
sidebar_entry.BuildTime = tech->Time_To_Build(PlayerPtr->Class->House); // sidebar_entry.BuildTime = tech->Time_To_Build() / 60;
|
||||
strncpy(sidebar_entry.AssetName, tech->IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
|
||||
} else {
|
||||
sidebar_entry.Cost = 0;
|
||||
|
@ -4527,7 +4563,7 @@ bool DLLExportClass::Get_Sidebar_State(uint64 player_id, unsigned char *buffer_i
|
|||
if (tech) {
|
||||
sidebar_entry.Cost = tech->Cost;
|
||||
sidebar_entry.PowerProvided = 0;
|
||||
sidebar_entry.BuildTime = tech->Time_To_Build(); // sidebar_entry.BuildTime = tech->Time_To_Build() / 60;
|
||||
sidebar_entry.BuildTime = tech->Time_To_Build(PlayerPtr->Class->House); // sidebar_entry.BuildTime = tech->Time_To_Build() / 60;
|
||||
strncpy(sidebar_entry.AssetName, tech->IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
|
||||
} else {
|
||||
sidebar_entry.Cost = 0;
|
||||
|
@ -7376,8 +7412,12 @@ void DLLExportClass::Selected_Guard_Mode(uint64 player_id)
|
|||
for (int index = 0; index < CurrentObject.Count(); index++) {
|
||||
ObjectClass const * tech = CurrentObject[index];
|
||||
|
||||
if (tech != NULL && tech->Can_Player_Move() && tech->Can_Player_Fire()) {
|
||||
if (tech != NULL && tech->Can_Player_Fire()) {
|
||||
if (tech->Can_Player_Move()) {
|
||||
OutList.Add(EventClass(TargetClass(tech), MISSION_GUARD_AREA));
|
||||
} else {
|
||||
OutList.Add(EventClass(TargetClass(tech), MISSION_GUARD));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7458,6 +7498,8 @@ void DLLExportClass::Team_Units_Formation_Toggle_On(uint64 player_id)
|
|||
int index;
|
||||
bool setform = 0;
|
||||
|
||||
TeamFormDataStruct& team_form_data = TeamFormData[PlayerPtr->Class->House];
|
||||
|
||||
//
|
||||
// Recording support
|
||||
//
|
||||
|
@ -7481,8 +7523,8 @@ void DLLExportClass::Team_Units_Formation_Toggle_On(uint64 player_id)
|
|||
team = obj->Group;
|
||||
if (team < MAX_TEAMS) {
|
||||
setform = obj->XFormOffset == (int)0x80000000;
|
||||
TeamSpeed[team] = SPEED_WHEEL;
|
||||
TeamMaxSpeed[team] = MPH_LIGHT_SPEED;
|
||||
team_form_data.TeamSpeed[team] = SPEED_WHEEL;
|
||||
team_form_data.TeamMaxSpeed[team] = MPH_LIGHT_SPEED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -7500,8 +7542,8 @@ void DLLExportClass::Team_Units_Formation_Toggle_On(uint64 player_id)
|
|||
team = obj->Group;
|
||||
if (team < MAX_TEAMS) {
|
||||
setform = obj->XFormOffset == (int)0x80000000;
|
||||
TeamSpeed[team] = SPEED_WHEEL;
|
||||
TeamMaxSpeed[team] = MPH_LIGHT_SPEED;
|
||||
team_form_data.TeamSpeed[team] = SPEED_WHEEL;
|
||||
team_form_data.TeamMaxSpeed[team] = MPH_LIGHT_SPEED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -7521,8 +7563,8 @@ void DLLExportClass::Team_Units_Formation_Toggle_On(uint64 player_id)
|
|||
team = obj->Group;
|
||||
if (team < MAX_TEAMS) {
|
||||
setform = obj->XFormOffset == 0x80000000UL;
|
||||
TeamSpeed[team] = SPEED_WHEEL;
|
||||
TeamMaxSpeed[team] = MPH_LIGHT_SPEED;
|
||||
team_form_data.TeamSpeed[team] = SPEED_WHEEL;
|
||||
team_form_data.TeamMaxSpeed[team] = MPH_LIGHT_SPEED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -7547,9 +7589,9 @@ void DLLExportClass::Team_Units_Formation_Toggle_On(uint64 player_id)
|
|||
if (xc > maxx) maxx = xc;
|
||||
if (yc < miny) miny = yc;
|
||||
if (yc > maxy) maxy = yc;
|
||||
if (obj->Class->MaxSpeed < TeamMaxSpeed[team]) {
|
||||
TeamMaxSpeed[team] = obj->Class->MaxSpeed;
|
||||
TeamSpeed[team] = obj->Class->Speed;
|
||||
if (obj->Class->MaxSpeed < team_form_data.TeamMaxSpeed[team]) {
|
||||
team_form_data.TeamMaxSpeed[team] = obj->Class->MaxSpeed;
|
||||
team_form_data.TeamSpeed[team] = obj->Class->Speed;
|
||||
}
|
||||
} else {
|
||||
obj->XFormOffset = obj->YFormOffset = (int)0x80000000;
|
||||
|
@ -7568,8 +7610,8 @@ void DLLExportClass::Team_Units_Formation_Toggle_On(uint64 player_id)
|
|||
if (xc > maxx) maxx = xc;
|
||||
if (yc < miny) miny = yc;
|
||||
if (yc > maxy) maxy = yc;
|
||||
if (obj->Class->MaxSpeed < TeamMaxSpeed[team]) {
|
||||
TeamMaxSpeed[team] = obj->Class->MaxSpeed;
|
||||
if (obj->Class->MaxSpeed < team_form_data.TeamMaxSpeed[team]) {
|
||||
team_form_data.TeamMaxSpeed[team] = obj->Class->MaxSpeed;
|
||||
}
|
||||
} else {
|
||||
obj->XFormOffset = obj->YFormOffset = (int)0x80000000;
|
||||
|
@ -7588,8 +7630,8 @@ void DLLExportClass::Team_Units_Formation_Toggle_On(uint64 player_id)
|
|||
if (xc > maxx) maxx = xc;
|
||||
if (yc < miny) miny = yc;
|
||||
if (yc > maxy) maxy = yc;
|
||||
if (obj->Class->MaxSpeed < TeamMaxSpeed[team]) {
|
||||
TeamMaxSpeed[team] = obj->Class->MaxSpeed;
|
||||
if (obj->Class->MaxSpeed < team_form_data.TeamMaxSpeed[team]) {
|
||||
team_form_data.TeamMaxSpeed[team] = obj->Class->MaxSpeed;
|
||||
}
|
||||
} else {
|
||||
obj->XFormOffset = obj->YFormOffset = 0x80000000UL;
|
||||
|
@ -8158,7 +8200,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++) {
|
||||
|
|
|
@ -29,7 +29,7 @@ struct CarryoverObjectStruct;
|
|||
**
|
||||
**
|
||||
*/
|
||||
#define CNC_DLL_API_VERSION 0x100
|
||||
#define CNC_DLL_API_VERSION 0x101
|
||||
|
||||
|
||||
|
||||
|
@ -627,6 +627,7 @@ struct EventCallbackStruct {
|
|||
//
|
||||
// Single-player data
|
||||
//
|
||||
bool IsHuman;
|
||||
bool PlayerWins; //This should specify player id
|
||||
const char* MovieName;
|
||||
const char* MovieName2;
|
||||
|
|
|
@ -1372,7 +1372,7 @@ void DriveClass::AI(void)
|
|||
land = Map[Center_Coord()].Land_Type();
|
||||
}
|
||||
if (IsLocked && Mission != MISSION_ENTER && Target_Legal(NavCom) && !Is_In_Same_Zone(As_Cell(NavCom)) &&
|
||||
land != LAND_ROCK && land != LAND_WATER && land != LAND_RIVER) {
|
||||
land != LAND_ROCK && land != LAND_WATER && land != LAND_RIVER && !Team) {
|
||||
Stop_Driver();
|
||||
Assign_Destination(TARGET_NONE);
|
||||
} else {
|
||||
|
|
|
@ -255,8 +255,7 @@ extern DynamicVectorClass<TriggerClass *> HouseTriggers[HOUSE_COUNT];
|
|||
extern BaseClass Base;
|
||||
|
||||
/* These variables are used to keep track of the slowest speed of a team */
|
||||
extern MPHType TeamMaxSpeed[MAX_TEAMS];
|
||||
extern SpeedType TeamSpeed[MAX_TEAMS];
|
||||
extern TeamFormDataStruct TeamFormData[HOUSE_COUNT];
|
||||
extern bool FormMove;
|
||||
extern SpeedType FormSpeed;
|
||||
extern MPHType FormMaxSpeed;
|
||||
|
|
|
@ -445,29 +445,13 @@ bool FactoryClass::Start(void)
|
|||
int time;
|
||||
|
||||
if (Object) {
|
||||
time = Object->Time_To_Build();
|
||||
// } else {
|
||||
// time = TICKS_PER_MINUTE * 5;
|
||||
time = Object->Class_Of().Time_To_Build(House->Class->House);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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 = time * Inverse(fixed(House->IQ+Rule.MaxIQ, Rule.MaxIQ*2));
|
||||
}
|
||||
time /= STEP_COUNT;
|
||||
time = Bound(time, 1, 255);
|
||||
|
||||
int rate = time / Bound(House->Power_Fraction(), fixed(1, 16), fixed(1));
|
||||
// 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);
|
||||
}
|
||||
|
|
|
@ -629,7 +629,7 @@ top_of_list:
|
|||
|
||||
// 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; This code does not exist in Tiberian Dawn.
|
||||
// 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)/sizeof(moves_left[0]), threshhold);
|
||||
// left = Follow_Edge(startcell, next, &pleft, COUNTERCLOCK, direction, threat, threat_stage, follow_len, threshhold);
|
||||
|
@ -649,7 +649,7 @@ top_of_list:
|
|||
|
||||
// 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; This code does not exist in Tiberian Dawn.
|
||||
// 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)/sizeof(moves_right[0]), threshhold);
|
||||
// right = Follow_Edge(startcell, next, &pright, CLOCK, direction, threat, threat_stage, follow_len, threshhold);
|
||||
|
|
|
@ -130,8 +130,7 @@ template<> FixedIHeapClass * CCPtr<SmudgeTypeClass>::Heap = &SmudgeTypes;
|
|||
#endif
|
||||
|
||||
/* These variables are used to keep track of the slowest speed of a team */
|
||||
MPHType TeamMaxSpeed[MAX_TEAMS];
|
||||
SpeedType TeamSpeed[MAX_TEAMS];
|
||||
TeamFormDataStruct TeamFormData[HOUSE_COUNT];
|
||||
bool FormMove;
|
||||
SpeedType FormSpeed;
|
||||
MPHType FormMaxSpeed;
|
||||
|
|
|
@ -1125,6 +1125,7 @@ void HouseClass::AI(void)
|
|||
unit->Mark(MARK_CHANGE);
|
||||
} else {
|
||||
CELL cell = As_Cell(FlagLocation);
|
||||
Map[cell].Flag_Update();
|
||||
Map[cell].Redraw_Objects();
|
||||
}
|
||||
}
|
||||
|
@ -1823,7 +1824,11 @@ void HouseClass::Attacked(BuildingClass* source)
|
|||
if (SpeakAttackDelay == 0 && PlayerPtr->Class->House == Class->House) {
|
||||
#endif
|
||||
Speak(VOX_BASE_UNDER_ATTACK, NULL, source ? source->Center_Coord() : 0);
|
||||
SpeakAttackDelay = Options.Normalize_Delay(TICKS_PER_MINUTE * Rule.SpeakDelay);
|
||||
|
||||
// MBL 06.13.2020 - Timing change from 2 minute cooldown, per https://jaas.ea.com/browse/TDRA-6784
|
||||
// SpeakAttackDelay = Options.Normalize_Delay(TICKS_PER_MINUTE * Rule.SpeakDelay); // 2 minutes
|
||||
// SpeakAttackDelay = Options.Normalize_Delay(TICKS_PER_MINUTE/2); // 30 seconds as requested
|
||||
SpeakAttackDelay = 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
|
||||
|
@ -3762,7 +3767,6 @@ void HouseClass::MPlayer_Defeated(void)
|
|||
*/
|
||||
if (PlayerPtr == this) {
|
||||
Session.ObiWan = 1;
|
||||
Debug_Unshroud = true;
|
||||
HidPage.Clear();
|
||||
Map.Flag_To_Redraw(true);
|
||||
|
||||
|
@ -3919,11 +3923,6 @@ void HouseClass::MPlayer_Defeated(void)
|
|||
#endif // MPATH
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
** Be sure our messages get displayed, even if we're about to exit.
|
||||
*/
|
||||
Map.Render();
|
||||
}
|
||||
|
||||
|
||||
|
@ -4411,10 +4410,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();
|
||||
Map.Radar_Pixel(cell);
|
||||
|
@ -8016,7 +8019,7 @@ void HouseClass::Check_Pertinent_Structures(void)
|
|||
BuildingClass *b = Buildings.Ptr(index);
|
||||
|
||||
if (b && b->IsActive && b->House == this) {
|
||||
if (!b->Class->IsWall) {
|
||||
if (!b->Class->IsWall && *b != STRUCT_APMINE && *b != STRUCT_AVMINE) {
|
||||
if (!b->IsInLimbo && b->Strength > 0) {
|
||||
any_good_buildings = true;
|
||||
break;
|
||||
|
|
|
@ -142,6 +142,8 @@ void CellClass::Code_Pointers(void)
|
|||
Overlapper[index] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
assert(CTFFlag == NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -177,6 +179,8 @@ void CellClass::Decode_Pointers(void)
|
|||
assert(Overlapper[index] != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
CTFFlag = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -480,8 +484,14 @@ void DisplayClass::Decode_Pointers(void)
|
|||
*=============================================================================================*/
|
||||
void MapClass::Code_Pointers(void)
|
||||
{
|
||||
CELL cell;
|
||||
|
||||
for (cell = 0; cell < MAP_CELL_TOTAL; cell++) {
|
||||
(*this)[cell].Flag_Destroy();
|
||||
}
|
||||
|
||||
CellClass * cellptr = &(*this)[(CELL)0];
|
||||
for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
|
||||
for (cell = 0; cell < MAP_CELL_TOTAL; cell++) {
|
||||
cellptr->Code_Pointers();
|
||||
cellptr++;
|
||||
}
|
||||
|
|
|
@ -428,7 +428,7 @@ dxisbig:
|
|||
#if (0)
|
||||
|
||||
/*
|
||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/REDALERT/MiscAsm.cpp#33 $
|
||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/REDALERT/MiscAsm.cpp#57 $
|
||||
;***************************************************************************
|
||||
;** 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 **
|
||||
;***************************************************************************
|
||||
|
|
|
@ -2270,7 +2270,7 @@ int ObjectTypeClass::Cost_Of(void) const
|
|||
* HISTORY: *
|
||||
* 07/19/1995 JLB : Created. *
|
||||
*=============================================================================================*/
|
||||
int ObjectTypeClass::Time_To_Build(void) const
|
||||
int ObjectTypeClass::Time_To_Build(HousesType ) const
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
|
|
@ -329,7 +329,8 @@ static TechnoClass * _Who_Can_Pop_Out_Of(CELL origin)
|
|||
for (int f = -1; f < 8; f++) {
|
||||
CellClass * ptr = cellptr;
|
||||
if (f != -1) {
|
||||
ptr = &ptr->Adjacent_Cell(FacingType(f));
|
||||
ptr = ptr->Adjacent_Cell(FacingType(f));
|
||||
if (!ptr) continue;
|
||||
}
|
||||
|
||||
BuildingClass * building = ptr->Cell_Building();
|
||||
|
|
|
@ -2470,7 +2470,10 @@ bool Read_Scenario_INI(char * fname, bool )
|
|||
/*
|
||||
** Special cases:
|
||||
** Gold Rush multiplayer map cell 9033 - LAND_ROCK
|
||||
** The Lake District multiplayer map cell 8482 - LAND_ROCK
|
||||
** Blue Lakes multiplayer map cell 11937 - LAND_RIVER
|
||||
** USSR mission 13 - fixup trigger action
|
||||
** Allied mission 5B - fail mission if spy re-boards the transport at mission start
|
||||
** Allied mission 9A - fail mission if tech center is destroyed before being spied
|
||||
** Aftermath: Brother in Arms - have transports move to separate waypoints
|
||||
** Aftermath: Let's Make a Steal - Make the pillboxes un-capturable
|
||||
|
@ -2480,11 +2483,45 @@ bool Read_Scenario_INI(char * fname, bool )
|
|||
Map[(CELL)9033].Override_Land_Type(LAND_ROCK);
|
||||
}
|
||||
|
||||
if (_stricmp(Scen.ScenarioName, "scm93ea.ini") == 0) {
|
||||
Map[(CELL)8482].Override_Land_Type(LAND_ROCK);
|
||||
}
|
||||
|
||||
if (_stricmp(Scen.ScenarioName, "scmh4ea.ini") == 0) {
|
||||
Map[(CELL)11937].Override_Land_Type(LAND_RIVER);
|
||||
}
|
||||
|
||||
if (_stricmp(Scen.ScenarioName, "scu13ea.ini") == 0) {
|
||||
TriggerTypeClass* trigger = TriggerTypes.Ptr(11);
|
||||
trigger->Action1.Trigger.Set_Raw(39);
|
||||
}
|
||||
|
||||
if (_stricmp(Scen.ScenarioName, "scg05eb.ini") == 0) {
|
||||
TeamTypeClass* spy1_team = TeamTypeClass::From_Name("spy1");
|
||||
assert(spy1_team != NULL);
|
||||
spy1_team->MissionList[spy1_team->MissionCount].Mission = TMISSION_SET_GLOBAL;
|
||||
spy1_team->MissionList[spy1_team->MissionCount].Data.Value = 16;
|
||||
spy1_team->MissionCount++;
|
||||
|
||||
TriggerTypeClass* los3_trigger = new TriggerTypeClass();
|
||||
los3_trigger->IsPersistant = TriggerTypeClass::VOLATILE;
|
||||
los3_trigger->House = HOUSE_GREECE;
|
||||
los3_trigger->EventControl = MULTI_AND;
|
||||
los3_trigger->ActionControl = MULTI_AND;
|
||||
los3_trigger->Event1.Event = TEVENT_GLOBAL_SET;
|
||||
los3_trigger->Event1.Data.Value = 16;
|
||||
los3_trigger->Event2.Event = TEVENT_ALL_DESTROYED;
|
||||
los3_trigger->Event2.Data.House = HOUSE_GREECE;
|
||||
los3_trigger->Action1.Action = TACTION_LOSE;
|
||||
los3_trigger->Action1.Data.Value = -255;
|
||||
los3_trigger->Action2.Action = TACTION_NONE;
|
||||
los3_trigger->Action2.Data.Value = -1;
|
||||
|
||||
TriggerTypeClass* frc1_trigger = TriggerTypeClass::From_Name("frc1");
|
||||
assert(frc1_trigger != NULL);
|
||||
frc1_trigger->Action1.Trigger = los3_trigger;
|
||||
}
|
||||
|
||||
if (_stricmp(Scen.ScenarioName, "scg09ea.ini") == 0) {
|
||||
TriggerTypeClass* spyd_trigger = TriggerTypeClass::From_Name("Spyd");
|
||||
assert(spyd_trigger != NULL);
|
||||
|
|
|
@ -2485,6 +2485,7 @@ int TeamClass::TMission_Formation(void)
|
|||
int xdir = 0;
|
||||
int ydir = 0;
|
||||
bool evenodd = 1;
|
||||
HousesType house = (member != NULL) ? member->Owner() : HOUSE_NONE;
|
||||
|
||||
/*
|
||||
** Assign appropriate formation offsets for each of the members
|
||||
|
@ -2606,9 +2607,10 @@ int TeamClass::TMission_Formation(void)
|
|||
/*
|
||||
** Now calculate the group's movement type and speed
|
||||
*/
|
||||
if (Formation != FORMATION_NONE) {
|
||||
TeamSpeed[group] = SPEED_WHEEL;
|
||||
TeamMaxSpeed[group] = MPH_LIGHT_SPEED;
|
||||
if (Formation != FORMATION_NONE && house != HOUSE_NONE) {
|
||||
TeamFormDataStruct& team_form_data = TeamFormData[house];
|
||||
team_form_data.TeamSpeed[group] = SPEED_WHEEL;
|
||||
team_form_data.TeamMaxSpeed[group] = MPH_LIGHT_SPEED;
|
||||
member = Member;
|
||||
while (member != NULL) {
|
||||
RTTIType mytype = member->What_Am_I();
|
||||
|
@ -2634,9 +2636,9 @@ int TeamClass::TMission_Formation(void)
|
|||
}
|
||||
|
||||
if (speedcheck) {
|
||||
if (memmax < TeamMaxSpeed[group]) {
|
||||
TeamMaxSpeed[group] = memmax;
|
||||
TeamSpeed[group] = memspeed;
|
||||
if (memmax < team_form_data.TeamMaxSpeed[group]) {
|
||||
team_form_data.TeamMaxSpeed[group] = memmax;
|
||||
team_form_data.TeamSpeed[group] = memspeed;
|
||||
}
|
||||
}
|
||||
member = member->Member;
|
||||
|
@ -2648,8 +2650,8 @@ int TeamClass::TMission_Formation(void)
|
|||
*/
|
||||
member = Member;
|
||||
while (member != NULL) {
|
||||
member->FormationSpeed = TeamSpeed[group];
|
||||
member->FormationMaxSpeed = TeamMaxSpeed[group];
|
||||
member->FormationSpeed = team_form_data.TeamSpeed[group];
|
||||
member->FormationMaxSpeed = team_form_data.TeamMaxSpeed[group];
|
||||
if (member->What_Am_I() == RTTI_INFANTRY) {
|
||||
member->FormationSpeed = SPEED_FOOT;
|
||||
member->FormationMaxSpeed = MPH_SLOW_ISH;
|
||||
|
|
|
@ -47,6 +47,12 @@
|
|||
*/
|
||||
#define STRAY_DISTANCE 2
|
||||
|
||||
struct TeamFormDataStruct
|
||||
{
|
||||
MPHType TeamMaxSpeed[MAX_TEAMS];
|
||||
SpeedType TeamSpeed[MAX_TEAMS];
|
||||
};
|
||||
|
||||
class TeamClass : public AbstractClass
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -637,80 +637,6 @@ TechnoClass::TechnoClass(RTTIType rtti, int id, HousesType house) :
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* TechnoClass::Time_To_Build -- Determines the time it would take to build this. *
|
||||
* *
|
||||
* Use this routine to determine the amount of time it would take to build an object of *
|
||||
* this type. *
|
||||
* *
|
||||
* INPUT: none *
|
||||
* *
|
||||
* OUTPUT: Returns with the time it should take (unmodified by outside factors) to build *
|
||||
* this object. The time is expressed in game frames. *
|
||||
* *
|
||||
* WARNINGS: The time will usually be modified by power status and handicap rating for the *
|
||||
* owning house. The value returned is merely the raw unmodified time to build. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 07/29/1996 JLB : Created. *
|
||||
* 09/27/1996 JLB : Takes into account the power availability. *
|
||||
*=============================================================================================*/
|
||||
//#define UNIT_BUILD_BIAS fixed(5,4)
|
||||
//#define UNIT_BUILD_BIAS fixed(6,4)
|
||||
#define UNIT_BUILD_BIAS fixed(1,1)
|
||||
//#define UNIT_BUILD_BIAS fixed(5,1)
|
||||
|
||||
extern int UnitBuildPenalty;
|
||||
|
||||
int TechnoClass::Time_To_Build(void) const
|
||||
{
|
||||
int val = Class_Of().Time_To_Build();
|
||||
|
||||
#ifdef FIXIT_VERSION_3
|
||||
if (Session.Type == GAME_NORMAL ) {
|
||||
#else
|
||||
if (Session.Type == GAME_NORMAL ||
|
||||
PlayingAgainstVersion == VERSION_RED_ALERT_104 ||
|
||||
PlayingAgainstVersion == VERSION_RED_ALERT_107){
|
||||
#endif
|
||||
val *= House->BuildSpeedBias;
|
||||
}else{
|
||||
if (What_Am_I() == RTTI_BUILDING || What_Am_I() == RTTI_INFANTRY) {
|
||||
val *= House->BuildSpeedBias;
|
||||
} else {
|
||||
val *= House->BuildSpeedBias * fixed (UnitBuildPenalty, 100); //UNIT_BUILD_BIAS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Adjust the time to build based on the power output of the owning house.
|
||||
*/
|
||||
fixed power = House->Power_Fraction();
|
||||
if (power > 1) power = 1;
|
||||
if (power < 1 && power > fixed::_3_4) power = fixed::_3_4;
|
||||
if (power < fixed::_1_2) power = fixed::_1_2;
|
||||
power.Inverse();
|
||||
val *= power;
|
||||
|
||||
int divisor = House->Factory_Count(What_Am_I());
|
||||
if (divisor != 0) {
|
||||
#ifdef FIXIT_CSII // checked - ajw 9/28/98
|
||||
// Hack: allow the multiple-factory bonus, but only up to two factories if
|
||||
// this is an AM<->AM game.
|
||||
if(NewUnitsEnabled) {
|
||||
val /= min(divisor,2);
|
||||
} else {
|
||||
val /= divisor;
|
||||
}
|
||||
#else
|
||||
val /= divisor;
|
||||
#endif
|
||||
}
|
||||
return(val);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* TechnoClass::Is_Visible_On_Radar -- Is this object visible on player's radar screen? *
|
||||
* *
|
||||
|
@ -3458,8 +3384,9 @@ void TechnoClass::Player_Assign_Mission(MissionType mission, TARGET target, TARG
|
|||
if (Is_Foot()) {
|
||||
const FootClass* foot = (const FootClass*)this;
|
||||
if (foot->Group < MAX_TEAMS) {
|
||||
speed = TeamSpeed[foot->Group];
|
||||
maxspeed = TeamMaxSpeed[foot->Group];
|
||||
TeamFormDataStruct& team_form_data = TeamFormData[foot->Owner()];
|
||||
speed = team_form_data.TeamSpeed[foot->Group];
|
||||
maxspeed = team_form_data.TeamMaxSpeed[foot->Group];
|
||||
}
|
||||
}
|
||||
Queue_Mission(TargetClass(this), mission, target, destination, speed, maxspeed);
|
||||
|
@ -6494,9 +6421,82 @@ int TechnoTypeClass::Get_Ownable(void) const
|
|||
* HISTORY: *
|
||||
* 07/29/1995 JLB : Created. *
|
||||
*=============================================================================================*/
|
||||
int TechnoTypeClass::Time_To_Build(void) const
|
||||
//#define UNIT_BUILD_BIAS fixed(5,4)
|
||||
//#define UNIT_BUILD_BIAS fixed(6,4)
|
||||
#define UNIT_BUILD_BIAS fixed(1,1)
|
||||
//#define UNIT_BUILD_BIAS fixed(5,1)
|
||||
|
||||
extern int UnitBuildPenalty;
|
||||
|
||||
int TechnoTypeClass::Time_To_Build(HousesType house) const
|
||||
{
|
||||
return(Cost * Rule.BuildSpeedBias * fixed(TICKS_PER_MINUTE, 1000));
|
||||
int time = Cost * Rule.BuildSpeedBias * fixed(TICKS_PER_MINUTE, 1000);
|
||||
|
||||
HouseClass* hptr = HouseClass::As_Pointer(house);
|
||||
if (!hptr || !hptr->IsActive) {
|
||||
return time;
|
||||
}
|
||||
|
||||
#ifdef FIXIT_VERSION_3
|
||||
if (Session.Type == GAME_NORMAL) {
|
||||
#else
|
||||
if (Session.Type == GAME_NORMAL ||
|
||||
PlayingAgainstVersion == VERSION_RED_ALERT_104 ||
|
||||
PlayingAgainstVersion == VERSION_RED_ALERT_107) {
|
||||
#endif
|
||||
time *= hptr->BuildSpeedBias;
|
||||
}
|
||||
else {
|
||||
if (What_Am_I() == RTTI_BUILDINGTYPE || What_Am_I() == RTTI_INFANTRYTYPE) {
|
||||
time *= hptr->BuildSpeedBias;
|
||||
}
|
||||
else {
|
||||
time *= hptr->BuildSpeedBias * fixed(UnitBuildPenalty, 100); //UNIT_BUILD_BIAS;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** 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 = time * Inverse(fixed(hptr->IQ + Rule.MaxIQ, Rule.MaxIQ * 2));
|
||||
}
|
||||
|
||||
/*
|
||||
** Adjust the time to build based on the power output of the owning house.
|
||||
*/
|
||||
fixed power = hptr->Power_Fraction();
|
||||
fixed scale(1);
|
||||
if (power == 0) {
|
||||
scale = fixed(4, 1);
|
||||
}
|
||||
else if (power < fixed::_1_2) {
|
||||
scale = fixed(5, 2);
|
||||
}
|
||||
else if (power < 1) {
|
||||
scale = fixed(3, 2);
|
||||
}
|
||||
time *= scale;
|
||||
|
||||
int divisor = hptr->Factory_Count(What_Am_I());
|
||||
if (divisor != 0) {
|
||||
#ifdef FIXIT_CSII // checked - ajw 9/28/98
|
||||
// Hack: allow the multiple-factory bonus, but only up to two factories if
|
||||
// this is an AM<->AM game.
|
||||
if (NewUnitsEnabled) {
|
||||
time /= min(divisor, 2);
|
||||
}
|
||||
else {
|
||||
time /= divisor;
|
||||
}
|
||||
#else
|
||||
time /= divisor;
|
||||
#endif
|
||||
}
|
||||
|
||||
return(time);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -277,7 +277,6 @@ class TechnoClass : public RadioClass,
|
|||
int Anti_Air(void) const;
|
||||
int Anti_Armor(void) const;
|
||||
int Anti_Infantry(void) const;
|
||||
int Time_To_Build(void) const;
|
||||
int What_Weapon_Should_I_Use(TARGET target) const;
|
||||
virtual ActionType What_Action(CELL cell) const;
|
||||
virtual ActionType What_Action(ObjectClass const * target) const;
|
||||
|
|
|
@ -292,7 +292,7 @@ class ObjectTypeClass : public AbstractTypeClass
|
|||
virtual void Dimensions(int &width, int &height) const;
|
||||
virtual bool Create_And_Place(CELL , HousesType =HOUSE_NONE) const = 0;
|
||||
virtual int Cost_Of(void) const;
|
||||
virtual int Time_To_Build(void) const;
|
||||
virtual int Time_To_Build(HousesType house) const;
|
||||
virtual ObjectClass * Create_One_Of(HouseClass *) const = 0;
|
||||
virtual short const * Occupy_List(bool placement=false) const;
|
||||
virtual short const * Overlap_List(void) const;
|
||||
|
@ -572,7 +572,7 @@ class TechnoTypeClass : public ObjectTypeClass
|
|||
virtual int Repair_Step(void) const;
|
||||
virtual void const * Get_Cameo_Data(void) const;
|
||||
virtual int Cost_Of(void) const;
|
||||
virtual int Time_To_Build(void) const;
|
||||
virtual int Time_To_Build(HousesType house) const;
|
||||
virtual int Get_Ownable(void) const;
|
||||
virtual bool Read_INI(CCINIClass & ini);
|
||||
|
||||
|
@ -1789,7 +1789,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 Loops;
|
||||
int Loops;
|
||||
|
||||
/*
|
||||
** This is the sound effect to play when this animation starts. Usually, this
|
||||
|
|
|
@ -1276,6 +1276,18 @@ void UnitClass::Active_Click_With(ActionType action, CELL cell)
|
|||
}
|
||||
|
||||
|
||||
void UnitClass::Player_Assign_Mission(MissionType mission, TARGET target, TARGET destination)
|
||||
{
|
||||
assert(Units.ID(this) == ID);
|
||||
assert(IsActive);
|
||||
|
||||
if (mission == MISSION_HARVEST) {
|
||||
ArchiveTarget = TARGET_NONE;
|
||||
}
|
||||
DriveClass::Player_Assign_Mission(mission, target, destination);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* UnitClass::Enter_Idle_Mode -- Unit enters idle mode state. *
|
||||
* *
|
||||
|
@ -2144,7 +2156,10 @@ void UnitClass::Draw_It(int x, int y, WindowNumberType window) const
|
|||
** If this unit is carrying the flag, then draw that on top of everything else.
|
||||
*/
|
||||
if (Flagged != HOUSE_NONE) {
|
||||
CC_Draw_Shape(this, "FLAGFLY", MFCD::Retrieve("FLAGFLY.SHP"), Frame % 14, x, y, window, SHAPE_CENTER|SHAPE_FADING|SHAPE_GHOST, HouseClass::As_Pointer(Flagged)->Remap_Table(false, Class->Remap), Map.UnitShadow, DIR_N, 0x0100, Flagged);
|
||||
shapefile = MFCD::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, Class->Remap), Map.UnitShadow, DIR_N, 0x0100, Flagged);
|
||||
}
|
||||
|
||||
DriveClass::Draw_It(x, y, window);
|
||||
|
@ -2163,14 +2178,14 @@ void UnitClass::Draw_It(int x, int y, WindowNumberType window) const
|
|||
* *
|
||||
* x,y -- Relative offset from the center cell to perform the check upon. *
|
||||
* *
|
||||
* 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 & center, int x, int y)
|
||||
int UnitClass::Tiberium_Check(CELL & center, int x, int y)
|
||||
{
|
||||
assert(Units.ID(this) == ID);
|
||||
assert(IsActive);
|
||||
|
@ -2179,20 +2194,20 @@ bool UnitClass::Tiberium_Check(CELL & center, int x, int y)
|
|||
** 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);
|
||||
|
||||
if ((Session.Type != GAME_NORMAL || (!IsOwnedByPlayer || Map[center].IsMapped))) {
|
||||
if (Map[Coord].Zones[Class->MZone] != Map[center].Zones[Class->MZone]) return(false);
|
||||
if (Map[Coord].Zones[Class->MZone] != Map[center].Zones[Class->MZone]) return(0);
|
||||
if (!Map[center].Cell_Techno() && Map[center].Land_Type() == LAND_TIBERIUM) {
|
||||
return(true);
|
||||
return(Map[center].OverlayData);
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2228,31 +2243,42 @@ bool UnitClass::Goto_Tiberium(int rad)
|
|||
** Perform a ring search outward from the center.
|
||||
*/
|
||||
for (int radius = 1; radius < rad; radius++) {
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
CELL cell = center;
|
||||
if (Tiberium_Check(cell, x, -radius)) {
|
||||
Assign_Destination(::As_Target(cell));
|
||||
return(false);
|
||||
CELL bestcell = 0;
|
||||
int tiberium = 0;
|
||||
int besttiberium = 0;
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
tiberium = Tiberium_Check(cell, x, -radius);
|
||||
if (tiberium > besttiberium) {
|
||||
bestcell = cell;
|
||||
besttiberium = tiberium;
|
||||
}
|
||||
|
||||
cell = center;
|
||||
if (Tiberium_Check(cell, x, +radius)) {
|
||||
Assign_Destination(::As_Target(cell));
|
||||
return(false);
|
||||
tiberium = Tiberium_Check(cell, x, +radius);
|
||||
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, -radius, x);
|
||||
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, +radius, x);
|
||||
if (tiberium > besttiberium) {
|
||||
bestcell = cell;
|
||||
besttiberium = tiberium;
|
||||
}
|
||||
}
|
||||
if (bestcell) {
|
||||
Assign_Destination(::As_Target(bestcell));
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2827,6 +2853,7 @@ int UnitClass::Mission_Harvest(void)
|
|||
Set_Rate(2);
|
||||
Set_Stage(0);
|
||||
Status = HARVESTING;
|
||||
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
|
||||
return(1);
|
||||
} else {
|
||||
|
||||
|
@ -2874,7 +2901,6 @@ int UnitClass::Mission_Harvest(void)
|
|||
IsHarvesting = false;
|
||||
if (Tiberium_Load() == 1) {
|
||||
Status = FINDHOME;
|
||||
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
|
||||
} else {
|
||||
if (!Goto_Tiberium(Rule.TiberiumShortScan / CELL_LEPTON_W) && !Target_Legal(NavCom)) {
|
||||
ArchiveTarget = TARGET_NONE;
|
||||
|
@ -2885,6 +2911,8 @@ int UnitClass::Mission_Harvest(void)
|
|||
}
|
||||
}
|
||||
return(1);
|
||||
} else if (!Target_Legal(NavCom) && ArchiveTarget == TARGET_NONE) {
|
||||
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
|
||||
}
|
||||
return(1);
|
||||
// return(TICKS_PER_SECOND*Rule.OreDumpRate);
|
||||
|
@ -3502,16 +3530,14 @@ ActionType UnitClass::What_Action(ObjectClass const * object) const
|
|||
/*
|
||||
** Special return to friendly refinery action.
|
||||
*/
|
||||
if (House->IsPlayerControl && 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) {
|
||||
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 (House->IsPlayerControl && 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 && ((UnitClass *)this)->Transmit_Message(RADIO_CAN_LOAD, building) == RADIO_ROGER && !building->In_Radio_Contact() && !building->Is_Something_Attached()) {
|
||||
action = ACTION_MOVE;
|
||||
|
|
|
@ -137,7 +137,7 @@ class UnitClass : public DriveClass
|
|||
bool Try_To_Deploy(void);
|
||||
virtual void Scatter(COORDINATE threat, bool forced=false, bool nokidding=false);
|
||||
|
||||
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);
|
||||
bool Goto_Tiberium(int radius);
|
||||
|
@ -185,6 +185,7 @@ class UnitClass : public DriveClass
|
|||
virtual ActionType What_Action(ObjectClass const * 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 destination);
|
||||
|
||||
/*
|
||||
** Combat related.
|
||||
|
|
|
@ -1824,8 +1824,8 @@ int VesselClass::Mission_Unload(void)
|
|||
** Tell everyone around the transport to scatter.
|
||||
*/
|
||||
for (FacingType face = FACING_N; face < FACING_COUNT; face++) {
|
||||
CellClass * cellptr = &Map[Coord].Adjacent_Cell(face);
|
||||
if (cellptr->Is_Clear_To_Move(SPEED_TRACK, true, true)) {
|
||||
CellClass * cellptr = Map[Coord].Adjacent_Cell(face);
|
||||
if (cellptr && cellptr->Is_Clear_To_Move(SPEED_TRACK, true, true)) {
|
||||
cellptr->Incoming(0, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4842,7 +4842,7 @@ extern "C" int __cdecl Confine_Rect ( int * x , int * y , int w , int h , int wi
|
|||
|
||||
|
||||
/*
|
||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/REDALERT/WIN32LIB/DrawMisc.cpp#33 $
|
||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/REDALERT/WIN32LIB/DrawMisc.cpp#57 $
|
||||
;***************************************************************************
|
||||
;** 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 **
|
||||
;***************************************************************************
|
||||
|
|
163
SCRIPTS/tgautil.py
Normal file
163
SCRIPTS/tgautil.py
Normal file
|
@ -0,0 +1,163 @@
|
|||
'''
|
||||
Copyright 2020 Electronic Arts Inc.
|
||||
|
||||
This program is 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.
|
||||
|
||||
This program is 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
|
||||
'''
|
||||
import argparse
|
||||
import io
|
||||
import json
|
||||
from PIL import Image
|
||||
import os
|
||||
import StringIO
|
||||
import sys
|
||||
import zipfile
|
||||
|
||||
def overwrite_prompt(question, default=False):
|
||||
prompt = " [Y/n] " if default else " [y/N] "
|
||||
while True:
|
||||
sys.stdout.write(question + prompt)
|
||||
choice = raw_input().lower()
|
||||
if choice == '':
|
||||
return default
|
||||
elif choice == 'y':
|
||||
return True
|
||||
elif choice == 'n':
|
||||
return False
|
||||
else:
|
||||
sys.stdout.write("\n")
|
||||
|
||||
def crop(tga_file):
|
||||
with Image.open(tga_file) as image:
|
||||
image = image.convert('RGBA')
|
||||
alpha = image.split()[-1]
|
||||
left, top, right, bottom = 0, 0, image.width, image.height
|
||||
found_left, found_top, found_right, found_bottom = False, False, False, False
|
||||
for y in range(0, image.height):
|
||||
if found_top and found_bottom:
|
||||
break
|
||||
for x in range(0, image.width):
|
||||
if found_top and found_bottom:
|
||||
break
|
||||
if not found_top and alpha.getpixel((x, y)) != 0:
|
||||
top = y
|
||||
found_top = True
|
||||
if not found_bottom and alpha.getpixel((x, image.height - y - 1)) != 0:
|
||||
bottom = image.height - y
|
||||
found_bottom = True
|
||||
for x in range(0, image.width):
|
||||
if found_left and found_right:
|
||||
break
|
||||
for y in range(top, bottom):
|
||||
if found_left and found_right:
|
||||
break
|
||||
if not found_left and alpha.getpixel((x, y)) != 0:
|
||||
left = x
|
||||
found_left = True
|
||||
if not found_right and alpha.getpixel((image.width - x - 1, y)) != 0:
|
||||
right = image.width - x
|
||||
found_right = True
|
||||
tga_data = StringIO.StringIO()
|
||||
meta = None
|
||||
if left == 0 and top == 0 and right == image.width and bottom == image.height:
|
||||
image.save(tga_data, 'TGA')
|
||||
else:
|
||||
image.crop((left, top, right, bottom)).save(tga_data, 'TGA')
|
||||
meta = json.dumps({
|
||||
'size': [image.width, image.height],
|
||||
'crop': [left, top, right, bottom]
|
||||
}, separators=(',',':'))
|
||||
return (tga_data.getvalue(), meta)
|
||||
|
||||
def expand(tga_data, meta, tga_file):
|
||||
with Image.open(io.BytesIO(tga_data)) as image:
|
||||
if meta:
|
||||
crop = meta['crop']
|
||||
image_size = (crop[2] - crop[0], crop[3] - crop[1])
|
||||
image = image.resize(image_size)
|
||||
expanded_crop = (crop[0], crop[1], crop[2], crop[3])
|
||||
expanded_size = (meta['size'][0], meta['size'][1])
|
||||
with Image.new('RGBA', expanded_size, (0, 0, 0, 0)) as expanded:
|
||||
expanded.paste(image, expanded_crop)
|
||||
expanded.save(tga_file)
|
||||
else:
|
||||
image.save(tga_file)
|
||||
|
||||
def zip(args):
|
||||
if not os.path.isdir(args.directory):
|
||||
print >> sys.stderr, '\'{}\' does not exist or is not a directory\n'.format(args.directory)
|
||||
sys.exit(1)
|
||||
tga_files = [f for f in os.listdir(args.directory) if os.path.isfile(os.path.join(args.directory, f)) and os.path.splitext(f)[1].lower() == '.tga']
|
||||
if not tga_files:
|
||||
print >> sys.stderr, '\'{}\' does not contain any TGA files\n'.format(args.directory)
|
||||
sys.exit(1)
|
||||
out_file = os.path.basename(os.path.normpath(args.directory)).upper() + '.ZIP'
|
||||
if os.path.exists(out_file):
|
||||
if not os.path.isfile(out_file):
|
||||
print >> sys.stderr, '\'{}\' already exists and is not a file\n'.format(out_file)
|
||||
sys.exit(1)
|
||||
if not args.yes and not overwrite_prompt('\'{}\' already exists, overwrite?'.format(out_file)):
|
||||
sys.exit(0)
|
||||
with zipfile.ZipFile(out_file, 'w', zipfile.ZIP_DEFLATED) as zip:
|
||||
for tga_file in tga_files:
|
||||
tga_data, meta = crop(os.path.join(args.directory, tga_file))
|
||||
zip.writestr(tga_file, tga_data)
|
||||
if meta:
|
||||
zip.writestr(os.path.splitext(tga_file)[0] + '.meta', meta)
|
||||
print 'Wrote ZIP archive \'{}\''.format(out_file)
|
||||
|
||||
def unzip(args):
|
||||
if not os.path.isfile(args.archive):
|
||||
print >> sys.stderr, '\'{}\' does not exist or is not a file\n'.format(args.archive)
|
||||
sys.exit(1)
|
||||
out_dir = os.path.normpath(os.path.splitext(args.archive)[0])
|
||||
if os.path.exists(out_dir):
|
||||
if not os.path.isdir(out_dir):
|
||||
print >> sys.stderr, '\'{}\' already exists and is not a directory\n'.format(out_dir)
|
||||
sys.exit(1)
|
||||
if len(os.listdir(out_dir)) > 0:
|
||||
if not args.yes and not overwrite_prompt('\'{}\' is not empty, overwrite?'.format(out_dir)):
|
||||
sys.exit(0)
|
||||
else:
|
||||
os.mkdir(out_dir)
|
||||
files = {}
|
||||
with zipfile.ZipFile(args.archive, 'r', zipfile.ZIP_DEFLATED) as zip:
|
||||
for filename in zip.namelist():
|
||||
fileparts = os.path.splitext(filename)
|
||||
name, ext = fileparts[0].lower(), fileparts[1].lower()
|
||||
data = files.setdefault(name, {'tga': None, 'meta': None})
|
||||
if data['tga'] is None and ext == '.tga':
|
||||
data['tga'] = zip.read(filename)
|
||||
elif data['meta'] is None and ext == '.meta':
|
||||
data['meta'] = json.loads(zip.read(filename).decode('ascii'))
|
||||
if data['tga'] is not None and data['meta'] is not None:
|
||||
expand(data['tga'], data['meta'], os.path.join(out_dir, name) + '.tga')
|
||||
del files[name]
|
||||
for name, data in files.items():
|
||||
expand(data['tga'], None, os.path.join(out_dir, name) + '.tga')
|
||||
print 'Extracted files to \'{}\''.format(out_dir)
|
||||
|
||||
parser = argparse.ArgumentParser(description='TGA archive utility.')
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
parser_zip = subparsers.add_parser('z', help='Build a ZIP archive from a directory of TGA files.')
|
||||
parser_zip.add_argument('directory', help='Directory of TGA files.')
|
||||
parser_zip.add_argument('-o', '--out', nargs='?', help='Output archive path (defaults to input directory name with ZIP extension in the current path).')
|
||||
parser_zip.add_argument('-y', '--yes', action='store_true', help='Confirm overwrite of existing ZIP archives.')
|
||||
parser_zip.set_defaults(func=zip)
|
||||
|
||||
parser_unzip = subparsers.add_parser('u', help='Extract a ZIP archive of TGA files to a directory.')
|
||||
parser_unzip.add_argument('archive', help='ZIP archive of TGA files.')
|
||||
parser_unzip.add_argument('-o', '--out', nargs='?', help='Output directory (defaults to directory with name of the ZIP archive in the current path).')
|
||||
parser_unzip.add_argument('-y', '--yes', action='store_true', help='Confirm overwrite of files in output directory.')
|
||||
parser_unzip.set_defaults(func=unzip)
|
||||
|
||||
args = parser.parse_args()
|
||||
args.func(args)
|
|
@ -2360,6 +2360,30 @@ 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
|
||||
);
|
||||
|
||||
|
||||
|
||||
AnimTypeClass const * const AnimTypeClass::Pointers[ANIM_COUNT] = {
|
||||
|
@ -2459,6 +2483,7 @@ AnimTypeClass const * const AnimTypeClass::Pointers[ANIM_COUNT] = {
|
|||
&StegDie,
|
||||
&RaptDie,
|
||||
&ChemBall,
|
||||
&Flag,
|
||||
&Fire3Virtual,
|
||||
&Fire2Virtual,
|
||||
&Fire1Virtual,
|
||||
|
@ -2502,7 +2527,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;
|
||||
|
|
|
@ -607,6 +607,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,
|
||||
|
@ -1600,10 +1604,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());
|
||||
COORDINATE coord = Target_Coord();
|
||||
if (!(coord & 0xC000C000L)) {
|
||||
new AnimClass(ANIM_FBALL1, coord);
|
||||
}
|
||||
Delete_This();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -270,6 +270,12 @@ 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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -285,8 +291,12 @@ void AnimClass::Draw_It(int x, int y, WindowNumberType window)
|
|||
*/
|
||||
if (IsAlternate) {
|
||||
flags = flags | SHAPE_FADING;
|
||||
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;
|
||||
|
||||
/*
|
||||
|
@ -380,6 +390,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 +431,9 @@ short const * AnimClass::Overlap_List(void) const
|
|||
case ANIM_ATOM_BLAST:
|
||||
return(OverlapAtom);
|
||||
|
||||
case ANIM_FLAG:
|
||||
return(OverlapFlag);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -550,12 +565,12 @@ 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;
|
||||
|
||||
if (Class->Stages == -1) {
|
||||
((int&)Class->Stages) = Get_Build_Frame_Count(Class->Get_Image_Data());
|
||||
|
@ -590,8 +605,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;
|
||||
|
@ -798,8 +817,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 +1011,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 +1127,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;
|
||||
|
|
|
@ -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.
|
||||
|
@ -114,13 +115,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 +147,9 @@ class AnimClass : public ObjectClass, private StageClass {
|
|||
*/
|
||||
unsigned IsBrandNew:1;
|
||||
|
||||
// Use alternate color when drawing?
|
||||
/*
|
||||
** Use alternate color when drawing
|
||||
*/
|
||||
unsigned IsAlternate:1;
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
@ -1899,7 +1924,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 +1932,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 +1940,7 @@ void BuildingClass::Drop_Debris(TARGET source)
|
|||
i->Assign_Mission(MISSION_GUARD_AREA);
|
||||
} else {
|
||||
delete i;
|
||||
PlayerPtr->Flag_To_Win();
|
||||
}
|
||||
ScenarioInit--;
|
||||
}
|
||||
|
@ -3523,7 +3549,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 +3829,21 @@ bool BuildingClass::Can_Demolish_Unit(void) const
|
|||
}
|
||||
|
||||
|
||||
bool BuildingClass::Can_Capture(void) const
|
||||
{
|
||||
bool can_capture = Class->IsCaptureable;
|
||||
if (*this == STRUCT_EYE) {
|
||||
// Don't allow the Advanced Comm Center to be capturable in skirmish, MP, or beyond scenario 13 in SP
|
||||
if (GameToPlay == GAME_NORMAL) {
|
||||
can_capture &= Scenario < 13;
|
||||
} else {
|
||||
can_capture = false;
|
||||
}
|
||||
}
|
||||
return(can_capture);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* BuildingClass::Mission_Guard -- Handles guard mission for combat buildings. *
|
||||
* *
|
||||
|
@ -5020,7 +5061,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;
|
||||
|
|
|
@ -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->OwnerHouse = Payback->House->Class->House;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -1132,14 +1132,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 +1194,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 +1391,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 +1401,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 +1543,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 +1810,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 +1903,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++;
|
||||
}
|
||||
}
|
||||
|
@ -2386,6 +2378,7 @@ bool CellClass::Flag_Place(HousesType house)
|
|||
if (!IsFlagged && Is_Generally_Clear()) {
|
||||
IsFlagged = true;
|
||||
Owner = house;
|
||||
Flag_Update();
|
||||
Redraw_Objects();
|
||||
return(true);
|
||||
}
|
||||
|
@ -2413,6 +2406,7 @@ bool CellClass::Flag_Remove(void)
|
|||
if (IsFlagged) {
|
||||
IsFlagged = false;
|
||||
Owner = HOUSE_NONE;
|
||||
Flag_Update();
|
||||
Redraw_Objects();
|
||||
return(true);
|
||||
}
|
||||
|
@ -2420,6 +2414,34 @@ 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) {
|
||||
CTFFlag->OwnerHouse = 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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -3140,17 +3140,15 @@ 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) {
|
||||
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++) {
|
||||
UnitClass * obj = Units.Ptr(index);
|
||||
if (obj && !obj->IsInLimbo && obj->Group == team && obj->House == PlayerPtr) {
|
||||
|
|
|
@ -1509,6 +1509,7 @@ typedef enum AnimType : char {
|
|||
ANIM_STEG_DIE,
|
||||
ANIM_RAPT_DIE,
|
||||
ANIM_CHEM_BALL, // Chemical warrior explosion.
|
||||
ANIM_FLAG, // CTF flag.
|
||||
|
||||
ANIM_FIRE_SMALL_VIRTUAL, // Small flame animation (virtual).
|
||||
ANIM_FIRE_MED_VIRTUAL, // Medium flame animation (virtual).
|
||||
|
@ -1630,6 +1631,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;
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ typedef enum {
|
|||
*/
|
||||
#define RANDOM_START_POSITION 0x7f
|
||||
|
||||
|
||||
#define KILL_PLAYER_ON_DISCONNECT 1
|
||||
|
||||
|
||||
|
||||
|
@ -1748,18 +1748,34 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Player_Switch_To_AI(uin
|
|||
return;
|
||||
}
|
||||
|
||||
HousesType house;
|
||||
HouseClass *ptr;
|
||||
|
||||
GlyphX_Debug_Print("CNC_Handle_Player_Switch_To_AI");
|
||||
|
||||
if (GameToPlay == GAME_NORMAL) {
|
||||
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 +1819,9 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Player_Switch_To_AI(uin
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif //KILL_PLAYER_ON_DISCONNECT
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -2489,19 +2508,27 @@ 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 )
|
||||
{
|
||||
if (player_ptr != NULL && !player_ptr->IsDefeated) {
|
||||
event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
|
||||
event.GameOver.PlayerWins = !player_ptr->IsDefeated;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3761,6 +3788,10 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Sidebar_Request(Sidebar
|
|||
|
||||
switch (request_type) {
|
||||
|
||||
// MBL 06.02.2020 - 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;
|
||||
|
@ -6627,8 +6658,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()) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7158,7 +7193,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++) {
|
||||
|
|
|
@ -28,7 +28,7 @@ struct CarryoverObjectStruct;
|
|||
**
|
||||
**
|
||||
*/
|
||||
#define CNC_DLL_API_VERSION 0x100
|
||||
#define CNC_DLL_API_VERSION 0x101
|
||||
|
||||
|
||||
|
||||
|
@ -623,6 +623,7 @@ struct EventCallbackStruct {
|
|||
//
|
||||
// Single-player data
|
||||
//
|
||||
bool IsHuman;
|
||||
bool PlayerWins;
|
||||
const char* MovieName;
|
||||
const char* MovieName2;
|
||||
|
|
|
@ -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 {
|
||||
|
||||
/*
|
||||
|
@ -1598,12 +1598,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1006,6 +1006,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 +1259,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;
|
||||
|
@ -1498,6 +1499,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 +1537,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,36 +1603,40 @@ 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) {
|
||||
|
||||
/*
|
||||
** 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);
|
||||
TechnoClass * contact = Contact_With_Whom();
|
||||
if (contact == NULL) {
|
||||
contact = As_Techno(ArchiveTarget);
|
||||
}
|
||||
} else {
|
||||
ArchiveTarget = TARGET_NONE;
|
||||
Enter_Idle_Mode();
|
||||
if (contact == NULL) {
|
||||
contact = As_Techno(NavCom);
|
||||
}
|
||||
|
||||
} else {
|
||||
/*
|
||||
** If in contact, then let the transporter handle the movement coordination.
|
||||
*/
|
||||
if (contact != NULL) {
|
||||
|
||||
/*
|
||||
** Since radio contact exists with the transport, maintain a dialogue so that
|
||||
** the transport can give proper instructions to the passenger.
|
||||
** 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) != RADIO_ROGER) {
|
||||
if (Transmit_Message(RADIO_DOCKING, contact) != RADIO_ROGER && !IsTethered) {
|
||||
Transmit_Message(RADIO_OVER_OUT);
|
||||
Enter_Idle_Mode();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/*
|
||||
** Since there is no potential object to enter, then abort this
|
||||
** mission with some default standby mission.
|
||||
*/
|
||||
ArchiveTarget = TARGET_NONE;
|
||||
Enter_Idle_Mode();
|
||||
}
|
||||
return(TICKS_PER_SECOND/2);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1221,6 +1221,7 @@ void HouseClass::AI(void)
|
|||
unit->Mark(MARK_CHANGE);
|
||||
} else {
|
||||
CELL cell = As_Cell(FlagLocation);
|
||||
Map[cell].Flag_Update();
|
||||
Map[cell].Redraw_Objects();
|
||||
}
|
||||
}
|
||||
|
@ -1665,7 +1666,11 @@ 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));
|
||||
|
||||
// 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
|
||||
|
@ -2655,7 +2660,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->OwnerHouse = Class->House;
|
||||
if (this == PlayerPtr) {
|
||||
Map.IsTargettingMode = false;
|
||||
}
|
||||
|
@ -4055,7 +4060,6 @@ void HouseClass::MPlayer_Defeated(void)
|
|||
------------------------------------------------------------------------*/
|
||||
if (PlayerPtr == this) {
|
||||
MPlayerObiWan = 1;
|
||||
Debug_Unshroud = true;
|
||||
HiddenPage.Clear();
|
||||
Map.Flag_To_Redraw(true);
|
||||
|
||||
|
@ -4313,11 +4317,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 +4737,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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1000,7 +1000,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);
|
||||
}
|
||||
}
|
||||
|
@ -2086,11 +2086,15 @@ 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) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -2909,7 +2913,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 +2982,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 +3020,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 +3197,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 +3229,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
|
||||
*/
|
||||
|
|
|
@ -554,6 +554,11 @@ bool Read_Scenario_Ini(char *root, bool fresh)
|
|||
Map[(CELL)2015].Override_Land_Type(LAND_ROCK);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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 -------------------------
|
||||
*/
|
||||
|
|
|
@ -980,7 +980,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;
|
||||
|
|
|
@ -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#57 $
|
||||
;***************************************************************************
|
||||
;** 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? *
|
||||
* *
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
@ -787,3 +777,26 @@ bool Restate_Mission(char const * name, int button1, int button2)
|
|||
}
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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) && ((Cloak != CLOAKED) || Is_Owned_By_Player()) &&
|
||||
(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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1968,8 +2000,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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2249,6 +2286,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);
|
||||
|
||||
|
@ -2558,11 +2598,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -583,6 +583,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 +630,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);
|
||||
|
||||
|
@ -1215,6 +1254,16 @@ 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;
|
||||
}
|
||||
TarComClass::Player_Assign_Mission(mission, target, destination);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* UnitClass::Enter_Idle_Mode -- Unit enters idle mode state. *
|
||||
* *
|
||||
|
@ -1744,7 +1793,7 @@ void UnitClass::Per_Cell_Process(bool center)
|
|||
return;
|
||||
|
||||
default:
|
||||
Scatter(true);
|
||||
Scatter(0, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1755,7 +1804,17 @@ 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))) {
|
||||
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 {
|
||||
TechnoClass * contact = Contact_With_Whom();
|
||||
if (Transmit_Message(RADIO_UNLOADED) == RADIO_RUN_AWAY) {
|
||||
if (*this == UNIT_HARVESTER && contact && contact->What_Am_I() == RTTI_BUILDING) {
|
||||
|
@ -1782,6 +1841,7 @@ void UnitClass::Per_Cell_Process(bool center)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef OBSOLETE
|
||||
/*
|
||||
|
@ -2204,7 +2264,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 +2284,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);
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2265,32 +2328,42 @@ bool UnitClass::Goto_Tiberium(void)
|
|||
** Perform a ring search outward from the center.
|
||||
*/
|
||||
for (int radius = 1; radius < 64; radius++) {
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
CELL cell = center;
|
||||
if (Tiberium_Check(cell, x, -radius)) {
|
||||
Assign_Destination(::As_Target(cell));
|
||||
return(false);
|
||||
CELL bestcell = 0;
|
||||
int tiberium = 0;
|
||||
int besttiberium = 0;
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
tiberium = Tiberium_Check(cell, x, -radius);
|
||||
if (tiberium > besttiberium) {
|
||||
bestcell = cell;
|
||||
besttiberium = tiberium;
|
||||
}
|
||||
|
||||
cell = center;
|
||||
if (Tiberium_Check(cell, x, +radius)) {
|
||||
Assign_Destination(::As_Target(cell));
|
||||
return(false);
|
||||
tiberium = Tiberium_Check(cell, x, +radius);
|
||||
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, -radius, x);
|
||||
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, +radius, x);
|
||||
if (tiberium > besttiberium) {
|
||||
bestcell = cell;
|
||||
besttiberium = tiberium;
|
||||
}
|
||||
}
|
||||
if (bestcell) {
|
||||
Assign_Destination(::As_Target(bestcell));
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2589,6 +2662,7 @@ int UnitClass::Mission_Harvest(void)
|
|||
Set_Rate(2);
|
||||
Set_Stage(0);
|
||||
Status = HARVESTING;
|
||||
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
|
||||
return(1);
|
||||
} else {
|
||||
|
||||
|
@ -2623,7 +2697,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 +2707,8 @@ int UnitClass::Mission_Harvest(void)
|
|||
}
|
||||
}
|
||||
return(1);
|
||||
} else if (!Target_Legal(NavCom) && ArchiveTarget == TARGET_NONE) {
|
||||
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -2823,7 +2898,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 +3320,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 +3454,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 +3628,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) {
|
||||
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);
|
||||
|
@ -125,6 +125,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);
|
||||
|
|
|
@ -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#57 $
|
||||
;***************************************************************************
|
||||
;** 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#57 $
|
||||
;***************************************************************************
|
||||
;** 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