Merge pull request #1 from electronicarts/master

Update
This commit is contained in:
kapiosk 2020-06-23 12:37:48 +03:00 committed by GitHub
commit 7515901e25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
70 changed files with 1191 additions and 573 deletions

View file

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

View file

@ -1621,23 +1621,28 @@ 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());
{
Kill_Cargo(source);
Death_Announcement();
COORDINATE coord = Target_Coord();
if (!(coord & HIGH_COORD_MASK)) {
new AnimClass(ANIM_FBALL1, coord);
}
/*
** Parachute a survivor if possible.
*/
if (Class->IsCrew && Percent_Chance(90) && Map[Center_Coord()].Is_Clear_To_Move(SPEED_FOOT, true, false)) {
InfantryClass * infantry = new InfantryClass(INFANTRY_E1, House->Class->House);
if (infantry != NULL) {
if (!infantry->Paradrop(Center_Coord())) {
delete infantry;
/*
** Parachute a survivor if possible.
*/
if (Class->IsCrew && Percent_Chance(90) && Map[Center_Coord()].Is_Clear_To_Move(SPEED_FOOT, true, false)) {
InfantryClass * infantry = new InfantryClass(INFANTRY_E1, House->Class->House);
if (infantry != NULL) {
if (!infantry->Paradrop(Center_Coord())) {
delete infantry;
}
}
}
}
delete this;
delete this;
}
break;
default:

View file

@ -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 {

View file

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

View file

@ -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);
}
}

View file

@ -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());

View file

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

View file

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

View file

@ -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.
*/

View file

@ -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,

View file

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

View file

@ -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()) {
OutList.Add(EventClass(TargetClass(tech), MISSION_GUARD_AREA));
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++) {

View file

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

View file

@ -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 {

View file

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

View file

@ -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);
}

View file

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

View file

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

View file

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

View file

@ -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++;
}

View file

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

View file

@ -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);
}

View file

@ -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();

View file

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

View file

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

View file

@ -47,6 +47,12 @@
*/
#define STRAY_DISTANCE 2
struct TeamFormDataStruct
{
MPHType TeamMaxSpeed[MAX_TEAMS];
SpeedType TeamSpeed[MAX_TEAMS];
};
class TeamClass : public AbstractClass
{
public:

View file

@ -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);
}

View file

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

View file

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

View file

@ -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++) {
CELL cell = center;
CELL bestcell = 0;
int tiberium = 0;
int besttiberium = 0;
for (int x = -radius; x <= radius; x++) {
CELL cell = center;
if (Tiberium_Check(cell, x, -radius)) {
Assign_Destination(::As_Target(cell));
return(false);
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) {
action = ACTION_ENTER;
}
if (Is_Owned_By_Player() && House->Class->House == object->Owner() && object->What_Am_I() == RTTI_BUILDING && ((UnitClass *)this)->Transmit_Message(RADIO_CAN_LOAD, (TechnoClass*)object) == RADIO_ROGER) {
action = ACTION_ENTER;
}
/*
** Special return to friendly repair factory action.
*/
if (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;

View file

@ -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 &center, int x, int y);
int Tiberium_Check(CELL &center, 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.

View file

@ -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);
}
}

View file

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

View file

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

View file

@ -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());
Delete_This();
{
Kill_Cargo(source);
Death_Announcement();
COORDINATE coord = Target_Coord();
if (!(coord & 0xC000C000L)) {
new AnimClass(ANIM_FBALL1, coord);
}
Delete_This();
}
break;
default:

View file

@ -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,7 +291,11 @@ void AnimClass::Draw_It(int x, int y, WindowNumberType window)
*/
if (IsAlternate) {
flags = flags | SHAPE_FADING;
remap = Map.RemapTables[HOUSE_GOOD][0];
if (OwnerHouse != HOUSE_NONE) {
remap = HouseClass::As_Pointer(OwnerHouse)->Remap_Table(false, false);
} else {
remap = Map.RemapTables[HOUSE_GOOD][0];
}
}
if (transtable) flags = flags | SHAPE_GHOST;
@ -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;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3140,15 +3140,13 @@ void Handle_Team(int team, int action)
** If a non team member is currently selected, then deselect all objects
** before selecting this team.
*/
if (CurrentObject.Count()) {
switch (CurrentObject[0]->What_Am_I()) {
case RTTI_UNIT:
case RTTI_INFANTRY:
case RTTI_AIRCRAFT:
if (((FootClass *)CurrentObject[0])->Group != team) {
Unselect_All();
}
for (index = 0; index < CurrentObject.Count(); index++) {
ObjectClass * obj = CurrentObject[index];
if (obj->What_Am_I() == RTTI_UNIT || obj->What_Am_I() == RTTI_INFANTRY || obj->What_Am_I() == RTTI_AIRCRAFT) {
if (((FootClass *)obj)->Group != team) {
Unselect_All();
break;
}
}
}
for (index = 0; index < Units.Count(); index++) {

View file

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

View file

@ -106,7 +106,7 @@ typedef enum {
*/
#define RANDOM_START_POSITION 0x7f
#define KILL_PLAYER_ON_DISCONNECT 1
@ -1695,7 +1695,7 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Save_Load(bool save, const cha
}
result = Load_Game(file_path_and_name);
DLLExportClass::Set_Player_Context(DLLExportClass::GlyphxPlayerIDs[0], true);
Set_Logic_Page(SeenBuff);
VisiblePage.Clear();
@ -1747,9 +1747,6 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Player_Switch_To_AI(uin
if (PlayerWins || PlayerLoses || DLLExportClass::Get_Game_Over()) {
return;
}
HousesType house;
HouseClass *ptr;
GlyphX_Debug_Print("CNC_Handle_Player_Switch_To_AI");
@ -1757,9 +1754,28 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Player_Switch_To_AI(uin
return;
}
#ifdef KILL_PLAYER_ON_DISCONNECT
/*
** Kill player's units on disconnect.
*/
if (player_id != 0) {
DLLExportClass::Set_Player_Context(player_id);
if (PlayerPtr) {
PlayerPtr->Flag_To_Die();
}
}
#else //KILL_PLAYER_ON_DISCONNECT
if (player_id != 0) {
HousesType house;
HouseClass *ptr;
DLLExportClass::Set_Player_Context(player_id);
if (PlayerPtr) {
PlayerPtr->WasHuman = true;
PlayerPtr->IsHuman = false;
@ -1803,6 +1819,9 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Player_Switch_To_AI(uin
}
}
}
#endif //KILL_PLAYER_ON_DISCONNECT
}
@ -2489,18 +2508,26 @@ void DLLExportClass::On_Multiplayer_Game_Over(void)
event.GameOver.SabotagedStructureType = 0;
event.GameOver.TimerRemaining = -1;
// Trigger an event for each human player
for (int i=0 ; i<MPlayerCount ; i++) {
// Trigger an event for each human player, winner first (even if it's an AI)
for (int i = 0; i < MPlayerCount; i++) {
HouseClass* player_ptr = HouseClass::As_Pointer(MPlayerHouses[i]); //HouseClass::As_Pointer(HOUSE_MULTI2);
if ( player_ptr != NULL )
{
if ( player_ptr->IsHuman == true )
{
event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
event.GameOver.PlayerWins = !player_ptr->IsDefeated;
event.GameOver.RemainingCredits = player_ptr->Available_Money();
EventCallback(event);
}
if (player_ptr != NULL && !player_ptr->IsDefeated) {
event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
event.GameOver.IsHuman = player_ptr->IsHuman;
event.GameOver.PlayerWins = true;
event.GameOver.RemainingCredits = player_ptr->Available_Money();
EventCallback(event);
}
}
for (int i = 0; i < MPlayerCount; i++) {
HouseClass* player_ptr = HouseClass::As_Pointer(MPlayerHouses[i]); //HouseClass::As_Pointer(HOUSE_MULTI2);
if (player_ptr != NULL && player_ptr->IsHuman && player_ptr->IsDefeated) {
event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
event.GameOver.IsHuman = true;
event.GameOver.PlayerWins = false;
event.GameOver.RemainingCredits = player_ptr->Available_Money();
EventCallback(event);
}
}
}
@ -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()) {
OutList.Add(EventClass(tech->As_Target(), MISSION_GUARD_AREA));
if (tech && tech->Can_Player_Fire()) {
if (tech->Can_Player_Move()) {
OutList.Add(EventClass(tech->As_Target(), MISSION_GUARD_AREA));
} else {
OutList.Add(EventClass(tech->As_Target(), MISSION_GUARD));
}
}
}
}
@ -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++) {

View file

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

View file

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

View file

@ -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);
}

View file

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

View file

@ -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) {
TechnoClass * contact = Contact_With_Whom();
if (contact == NULL) {
contact = As_Techno(ArchiveTarget);
}
if (contact == NULL) {
contact = As_Techno(NavCom);
}
/*
** If the transport is already in radio contact, do nothing. Try to
** establish radio contact later.
*/
if (Transmit_Message(RADIO_HELLO, techno) == RADIO_ROGER) {
Assign_Destination(TARGET_NONE);
}
} else {
ArchiveTarget = TARGET_NONE;
/*
** If in contact, then let the transporter handle the movement coordination.
*/
if (contact != NULL) {
/*
** If the transport says to "bug off", then abort the enter mission. The transport may
** likely say all is 'ok' with the "RADIO ROGER", then try again later.
*/
if (Transmit_Message(RADIO_DOCKING, contact) != RADIO_ROGER && !IsTethered) {
Transmit_Message(RADIO_OVER_OUT);
Enter_Idle_Mode();
}
} else {
/*
** Since radio contact exists with the transport, maintain a dialogue so that
** the transport can give proper instructions to the passenger.
** Since there is no potential object to enter, then abort this
** mission with some default standby mission.
*/
if (Transmit_Message(RADIO_DOCKING) != RADIO_ROGER) {
Transmit_Message(RADIO_OVER_OUT);
Enter_Idle_Mode();
}
ArchiveTarget = TARGET_NONE;
Enter_Idle_Mode();
}
return(TICKS_PER_SECOND/2);
}

View file

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

View file

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

View file

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

View file

@ -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,8 +2086,12 @@ void InfantryClass::Scatter(COORDINATE threat, bool forced, bool nokidding)
newcell = Adjacent_Cell(Coord_Cell(Coord), newface);
if (Map.In_Radar(newcell) && Can_Enter_Cell(newcell) == MOVE_OK) {
Assign_Mission(MISSION_MOVE);
Assign_Destination(::As_Target(newcell));
if (!Class->IsAvoidingTiberium ||
Map[newcell].Overlay == OVERLAY_NONE ||
OverlayTypeClass::As_Reference(Map[newcell].Overlay).Land != LAND_TIBERIUM) {
Assign_Mission(MISSION_MOVE);
Assign_Destination(::As_Target(newcell));
}
}
}
}
@ -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
*/

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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();
}
}
}

View file

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

View file

@ -138,16 +138,6 @@ bool Start_Scenario(char *root, bool briefing)
}
#endif
/*
** Hack for laser-firing Orcas in the PATSUX secret mission
*/
if (GameToPlay == GAME_NORMAL && Scenario == 72) {
((AircraftTypeClass&)AircraftTypeClass::As_Reference(AIRCRAFT_ORCA)).Primary = WEAPON_OBELISK_LASER;
}
else {
((AircraftTypeClass&)AircraftTypeClass::As_Reference(AIRCRAFT_ORCA)).Primary = WEAPON_DRAGON;
}
/*
** Set the options values, since the palette has been initialized by Read_Scenario
*/
@ -786,4 +776,27 @@ bool Restate_Mission(char const * name, int button1, int button2)
#endif
}
return(false);
}
void Fixup_Scenario(void)
{
/*
** "Fraidycat" civilians avoid wandering into Tiberium for SCG08EB, since they're mission-critical.
*/
bool is_scg08ea = GameToPlay == GAME_NORMAL && PlayerPtr->ActLike == HOUSE_GOOD && Scenario == 8 && ScenVar == SCEN_VAR_B;
for (InfantryType index = INFANTRY_FIRST; index < INFANTRY_COUNT; index++) {
InfantryTypeClass& infantry_type = (InfantryTypeClass&)InfantryTypeClass::As_Reference(index);
if (infantry_type.IsFraidyCat) {
infantry_type.IsAvoidingTiberium = is_scg08ea;
}
}
/*
** Laser-firing Orcas in the PATSUX secret mission
*/
if (GameToPlay == GAME_NORMAL && Scenario == 72) {
((AircraftTypeClass&)AircraftTypeClass::As_Reference(AIRCRAFT_ORCA)).Primary = WEAPON_OBELISK_LASER;
} else {
((AircraftTypeClass&)AircraftTypeClass::As_Reference(AIRCRAFT_ORCA)).Primary = WEAPON_DRAGON;
}
}

View file

@ -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);
}
}
}
}
}

View file

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

View file

@ -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,28 +1804,39 @@ void UnitClass::Per_Cell_Process(bool center)
** When breaking away from a transport object or building, possibly
** scatter or otherwise begin normal unit operations.
*/
if (IsTethered && center && Mission != MISSION_ENTER && (*this != UNIT_APC || IsDriving || !Target_Legal(TarCom))) {
TechnoClass * contact = Contact_With_Whom();
if (Transmit_Message(RADIO_UNLOADED) == RADIO_RUN_AWAY) {
if (*this == UNIT_HARVESTER && contact && contact->What_Am_I() == RTTI_BUILDING) {
Assign_Mission(MISSION_HARVEST);
} else if (!Target_Legal(NavCom)) {
Scatter(0, true);
}
if (IsTethered && center &&
(Mission != MISSION_ENTER || (As_Techno(NavCom) != NULL && Contact_With_Whom() != As_Techno(NavCom))) &&
Mission != MISSION_UNLOAD) {
/*
** Special hack check to make sure that even though it has moved one
** cell, if it is still on the building (e.g., service depot), have
** it scatter again.
*/
if (Map[cell].Cell_Building() != NULL && !Target_Legal(NavCom)) {
Scatter(0, true, true);
} else {
if (*this == UNIT_HARVESTER) {
if (Target_Legal(ArchiveTarget)) {
TechnoClass * contact = Contact_With_Whom();
if (Transmit_Message(RADIO_UNLOADED) == RADIO_RUN_AWAY) {
if (*this == UNIT_HARVESTER && contact && contact->What_Am_I() == RTTI_BUILDING) {
Assign_Mission(MISSION_HARVEST);
Assign_Destination(ArchiveTarget);
ArchiveTarget = TARGET_NONE;
} else {
} else if (!Target_Legal(NavCom)) {
Scatter(0, true);
}
} else {
if (*this == UNIT_HARVESTER) {
if (Target_Legal(ArchiveTarget)) {
Assign_Mission(MISSION_HARVEST);
Assign_Destination(ArchiveTarget);
ArchiveTarget = TARGET_NONE;
} else {
/*
** Since there is no place to go, move away to clear
** the pad for another harvester.
*/
if (!Target_Legal(NavCom)) {
Scatter(0, true);
/*
** Since there is no place to go, move away to clear
** the pad for another harvester.
*/
if (!Target_Legal(NavCom)) {
Scatter(0, true);
}
}
}
}
@ -2204,7 +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 &center, int x, int y)
int UnitClass::Tiberium_Check(CELL &center, 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++) {
CELL cell = center;
CELL bestcell = 0;
int tiberium = 0;
int besttiberium = 0;
for (int x = -radius; x <= radius; x++) {
CELL cell = center;
if (Tiberium_Check(cell, x, -radius)) {
Assign_Destination(::As_Target(cell));
return(false);
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) {
action = ACTION_ENTER;
}
if (Is_Owned_By_Player() && House->Class->House == object->Owner() && object->What_Am_I() == RTTI_BUILDING && ((UnitClass *)this)->Transmit_Message(RADIO_CAN_LOAD, (TechnoClass*)object) == RADIO_ROGER) {
action = ACTION_ENTER;
}
/*
** Special return to friendly repair factory action.
*/
if (IsOwnedByPlayer && action == ACTION_SELECT && object->What_Am_I() == RTTI_BUILDING) {
if (Is_Owned_By_Player() && House->Class->House == object->Owner() && action == ACTION_SELECT && object->What_Am_I() == RTTI_BUILDING) {
BuildingClass * building = (BuildingClass *)object;
if (building->Class->Type == STRUCT_REPAIR && !building->In_Radio_Contact() && !building->Is_Something_Attached()) {
action = ACTION_MOVE;

View file

@ -75,7 +75,7 @@ class UnitClass : public TarComClass
bool Goto_Clear_Spot(void);
bool Try_To_Deploy(void);
bool Tiberium_Check(CELL &center, int x, int y);
int Tiberium_Check(CELL &center, 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);

View file

@ -4841,7 +4841,7 @@ extern "C" int __cdecl Confine_Rect ( int * x , int * y , int w , int h , int wi
/*
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/DrawMisc.cpp#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 **
;***************************************************************************

View file

@ -321,7 +321,7 @@ int __cdecl Desired_Facing8(long x1, long y1, long x2, long y2);
/*
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/FACINGFF.h#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 **
;***************************************************************************