(svn r17160) [0.7] -Backport from trunk:

- Fix: A stuck train could free the reservation of another train if it was reversed or did crash (r17152)
- Fix: A train entering a PBS section through a block signal could cause a train crash if another reservation ending at a safe tile was already present in the section [FS#3104] (r17151)
- Fix: Update vehicle position cache when the vehicle sprite changes [FS#3060] (r17121)
- Fix: News message about ordered refits failing was not very clear [FS#3091] (r17096)
This commit is contained in:
rubidium 2009-08-12 15:51:35 +00:00
parent 53983ec1af
commit c16325b939
7 changed files with 54 additions and 68 deletions

View File

@ -706,11 +706,9 @@ void SetAircraftPosition(Vehicle *v, int x, int y, int z)
v->y_pos = y; v->y_pos = y;
v->z_pos = z; v->z_pos = z;
v->cur_image = v->GetImage(v->direction); v->UpdateViewport(true, false);
if (v->subtype == AIR_HELICOPTER) v->Next()->Next()->cur_image = GetRotorImage(v); if (v->subtype == AIR_HELICOPTER) v->Next()->Next()->cur_image = GetRotorImage(v);
VehicleMove(v, true);
Vehicle *u = v->Next(); Vehicle *u = v->Next();
int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE); int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE);
@ -1293,9 +1291,8 @@ TileIndex Aircraft::GetOrderStationLocation(StationID station)
void Aircraft::MarkDirty() void Aircraft::MarkDirty()
{ {
this->cur_image = this->GetImage(this->direction); this->UpdateViewport(false, false);
if (this->subtype == AIR_HELICOPTER) this->Next()->Next()->cur_image = GetRotorImage(this); if (this->subtype == AIR_HELICOPTER) this->Next()->Next()->cur_image = GetRotorImage(this);
MarkSingleVehicleDirty(this);
} }
static void CrashAirplane(Vehicle *v) static void CrashAirplane(Vehicle *v)

View File

@ -3270,7 +3270,7 @@ STR_MASS_START_LIST_TIP :{BLACK}Click to
STR_SHORT_DATE :{WHITE}{DATE_TINY} STR_SHORT_DATE :{WHITE}{DATE_TINY}
STR_SIGN_LIST_CAPTION :{WHITE}Sign List - {COMMA} Sign{P "" s} STR_SIGN_LIST_CAPTION :{WHITE}Sign List - {COMMA} Sign{P "" s}
STR_ORDER_REFIT_FAILED :{WHITE}Order refit failure stopped {VEHICLE} STR_ORDER_REFIT_FAILED :{WHITE}{VEHICLE} stopped because an ordered refit failed
############ Lists rail types ############ Lists rail types

View File

@ -486,8 +486,7 @@ CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
void RoadVehicle::MarkDirty() void RoadVehicle::MarkDirty()
{ {
for (Vehicle *v = this; v != NULL; v = v->Next()) { for (Vehicle *v = this; v != NULL; v = v->Next()) {
v->cur_image = v->GetImage(v->direction); v->UpdateViewport(false, false);
MarkSingleVehicleDirty(v);
} }
} }
@ -536,7 +535,7 @@ static void DeleteLastRoadVeh(Vehicle *v)
delete v; delete v;
} }
static byte SetRoadVehPosition(Vehicle *v, int x, int y) static byte SetRoadVehPosition(Vehicle *v, int x, int y, bool turned)
{ {
byte new_z, old_z; byte new_z, old_z;
@ -548,7 +547,7 @@ static byte SetRoadVehPosition(Vehicle *v, int x, int y)
old_z = v->z_pos; old_z = v->z_pos;
v->z_pos = new_z; v->z_pos = new_z;
VehicleMove(v, true); v->UpdateViewport(true, turned);
return old_z; return old_z;
} }
@ -562,9 +561,7 @@ static void RoadVehSetRandomDirection(Vehicle *v)
uint32 r = Random(); uint32 r = Random();
v->direction = ChangeDir(v->direction, delta[r & 3]); v->direction = ChangeDir(v->direction, delta[r & 3]);
v->UpdateDeltaXY(v->direction); SetRoadVehPosition(v, v->x_pos, v->y_pos, true);
v->cur_image = v->GetImage(v->direction);
SetRoadVehPosition(v, v->x_pos, v->y_pos);
} while ((v = v->Next()) != NULL); } while ((v = v->Next()) != NULL);
} }
@ -1256,8 +1253,7 @@ static bool RoadVehLeaveDepot(Vehicle *v, bool first)
v->u.road.state = tdir; v->u.road.state = tdir;
v->u.road.frame = RVC_DEPOT_START_FRAME; v->u.road.frame = RVC_DEPOT_START_FRAME;
v->UpdateDeltaXY(v->direction); SetRoadVehPosition(v, x, y, true);
SetRoadVehPosition(v, x, y);
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
@ -1384,8 +1380,7 @@ static bool IndividualRoadVehicleController(Vehicle *v, const Vehicle *prev)
if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) { if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
/* Vehicle has just entered a bridge or tunnel */ /* Vehicle has just entered a bridge or tunnel */
v->UpdateDeltaXY(v->direction); SetRoadVehPosition(v, gp.x, gp.y, true);
SetRoadVehPosition(v, gp.x, gp.y);
return true; return true;
} }
@ -1530,8 +1525,7 @@ again:
v->cur_speed -= v->cur_speed >> 2; v->cur_speed -= v->cur_speed >> 2;
} }
v->UpdateDeltaXY(v->direction); RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true));
RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y));
return true; return true;
} }
@ -1595,8 +1589,7 @@ again:
v->cur_speed -= v->cur_speed >> 2; v->cur_speed -= v->cur_speed >> 2;
} }
v->UpdateDeltaXY(v->direction); RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true));
RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y));
return true; return true;
} }
@ -1635,8 +1628,7 @@ again:
v->cur_speed -= (v->cur_speed >> 2); v->cur_speed -= (v->cur_speed >> 2);
if (old_dir != v->u.road.state) { if (old_dir != v->u.road.state) {
/* The vehicle is in a road stop */ /* The vehicle is in a road stop */
v->UpdateDeltaXY(v->direction); SetRoadVehPosition(v, v->x_pos, v->y_pos, true);
SetRoadVehPosition(v, v->x_pos, v->y_pos);
/* Note, return here means that the frame counter is not incremented /* Note, return here means that the frame counter is not incremented
* for vehicles changing direction in a road stop. This causes frames to * for vehicles changing direction in a road stop. This causes frames to
* be repeated. (XXX) Is this intended? */ * be repeated. (XXX) Is this intended? */
@ -1683,7 +1675,7 @@ again:
v->u.road.slot_age = 14; v->u.road.slot_age = 14;
v->u.road.frame++; v->u.road.frame++;
RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y)); RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, false));
return true; return true;
} }
} }
@ -1758,8 +1750,7 @@ again:
* in a depot or entered a tunnel/bridge */ * in a depot or entered a tunnel/bridge */
if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->u.road.frame++; if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->u.road.frame++;
v->UpdateDeltaXY(v->direction); RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true));
RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y));
return true; return true;
} }
@ -1818,9 +1809,7 @@ static void RoadVehController(Vehicle *v)
for (Vehicle *u = v; u != NULL; u = u->Next()) { for (Vehicle *u = v; u != NULL; u = u->Next()) {
if ((u->vehstatus & VS_HIDDEN) != 0) continue; if ((u->vehstatus & VS_HIDDEN) != 0) continue;
uint16 old_image = u->cur_image; u->UpdateViewport(false, false);
u->cur_image = u->GetImage(u->direction);
if (old_image != u->cur_image) VehicleMove(u, true);
} }
if (v->progress == 0) v->progress = j; if (v->progress == 0) v->progress = j;

View File

@ -211,8 +211,7 @@ static void HandleBrokenShip(Vehicle *v)
void Ship::MarkDirty() void Ship::MarkDirty()
{ {
this->cur_image = this->GetImage(this->direction); this->UpdateViewport(false, false);
MarkSingleVehicleDirty(this);
} }
static void PlayShipSound(const Vehicle *v) static void PlayShipSound(const Vehicle *v)
@ -265,9 +264,7 @@ void Ship::UpdateDeltaXY(Direction direction)
void RecalcShipStuff(Vehicle *v) void RecalcShipStuff(Vehicle *v)
{ {
v->UpdateDeltaXY(v->direction); v->UpdateViewport(false, true);
v->cur_image = v->GetImage(v->direction);
v->MarkDirty();
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
} }
@ -693,9 +690,7 @@ static void ShipController(Vehicle *v)
v->z_pos = GetSlopeZ(gp.x, gp.y); v->z_pos = GetSlopeZ(gp.x, gp.y);
getout: getout:
v->UpdateDeltaXY(dir); v->UpdateViewport(true, true);
v->cur_image = v->GetImage(dir);
VehicleMove(v, true);
return; return;
reverse_direction: reverse_direction:

View File

@ -1533,13 +1533,6 @@ void Train::UpdateDeltaXY(Direction direction)
this->z_extent = 6; this->z_extent = 6;
} }
static void UpdateVarsAfterSwap(Vehicle *v)
{
v->UpdateDeltaXY(v->direction);
v->cur_image = v->GetImage(v->direction);
VehicleMove(v, true);
}
static inline void SetLastSpeed(Vehicle *v, int spd) static inline void SetLastSpeed(Vehicle *v, int spd)
{ {
int old = v->u.rail.last_speed; int old = v->u.rail.last_speed;
@ -1627,15 +1620,15 @@ static void ReverseTrainSwapVeh(Vehicle *v, int l, int r)
SwapTrainFlags(&a->u.rail.flags, &b->u.rail.flags); SwapTrainFlags(&a->u.rail.flags, &b->u.rail.flags);
/* update other vars */ /* update other vars */
UpdateVarsAfterSwap(a); a->UpdateViewport(true, true);
UpdateVarsAfterSwap(b); b->UpdateViewport(true, true);
/* call the proper EnterTile function unless we are in a wormhole */ /* call the proper EnterTile function unless we are in a wormhole */
if (a->u.rail.track != TRACK_BIT_WORMHOLE) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos); if (a->u.rail.track != TRACK_BIT_WORMHOLE) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
if (b->u.rail.track != TRACK_BIT_WORMHOLE) VehicleEnterTile(b, b->tile, b->x_pos, b->y_pos); if (b->u.rail.track != TRACK_BIT_WORMHOLE) VehicleEnterTile(b, b->tile, b->x_pos, b->y_pos);
} else { } else {
if (a->u.rail.track != TRACK_BIT_DEPOT) a->direction = ReverseDir(a->direction); if (a->u.rail.track != TRACK_BIT_DEPOT) a->direction = ReverseDir(a->direction);
UpdateVarsAfterSwap(a); a->UpdateViewport(true, true);
if (a->u.rail.track != TRACK_BIT_WORMHOLE) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos); if (a->u.rail.track != TRACK_BIT_WORMHOLE) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
} }
@ -1828,8 +1821,8 @@ static void ReverseTrainDirection(Vehicle *v)
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
} }
/* Clear path reservation in front. */ /* Clear path reservation in front if train is not stuck. */
FreeTrainTrackReservation(v); if (!HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v);
/* Check if we were approaching a rail/road-crossing */ /* Check if we were approaching a rail/road-crossing */
TileIndex crossing = TrainApproachingCrossingTile(v); TileIndex crossing = TrainApproachingCrossingTile(v);
@ -1859,7 +1852,7 @@ static void ReverseTrainDirection(Vehicle *v)
TrainConsistChanged(v, true); TrainConsistChanged(v, true);
/* update all images */ /* update all images */
for (Vehicle *u = v; u != NULL; u = u->Next()) u->cur_image = u->GetImage(u->direction); for (Vehicle *u = v; u != NULL; u = u->Next()) u->UpdateViewport(false, false);
/* update crossing we were approaching */ /* update crossing we were approaching */
if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing); if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
@ -3086,6 +3079,15 @@ bool TryPathReserve(Vehicle *v, bool mark_as_stuck, bool first_tile_okay)
bool other_train = false; bool other_train = false;
PBSTileInfo origin = FollowTrainReservation(v, &other_train); PBSTileInfo origin = FollowTrainReservation(v, &other_train);
/* The path we are driving on is alread blocked by some other train.
* This can only happen in certain situations when mixing path and
* block signals or when changing tracks and/or signals.
* Exit here as doing any further reservations will probably just
* make matters worse. */
if (other_train && v->tile != origin.tile) {
if (mark_as_stuck) MarkTrainAsStuck(v);
return false;
}
/* If we have a reserved path and the path ends at a safe tile, we are finished already. */ /* If we have a reserved path and the path ends at a safe tile, we are finished already. */
if (origin.okay && (v->tile != origin.tile || first_tile_okay)) { if (origin.okay && (v->tile != origin.tile || first_tile_okay)) {
/* Can't be stuck then. */ /* Can't be stuck then. */
@ -3093,14 +3095,6 @@ bool TryPathReserve(Vehicle *v, bool mark_as_stuck, bool first_tile_okay)
ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK); ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK);
return true; return true;
} }
/* The path we are driving on is alread blocked by some other train.
* This can only happen when tracks and signals are changed. A crash
* is probably imminent, don't do any further reservation because
* it might cause stale reservations. */
if (other_train && v->tile != origin.tile) {
if (mark_as_stuck) MarkTrainAsStuck(v);
return false;
}
/* If we are in a depot, tentativly reserve the depot. */ /* If we are in a depot, tentativly reserve the depot. */
if (v->u.rail.track & TRACK_BIT_DEPOT) { if (v->u.rail.track & TRACK_BIT_DEPOT) {
@ -3253,8 +3247,7 @@ void Train::MarkDirty()
{ {
Vehicle *v = this; Vehicle *v = this;
do { do {
v->cur_image = v->GetImage(v->direction); v->UpdateViewport(false, false);
MarkSingleVehicleDirty(v);
} while ((v = v->Next()) != NULL); } while ((v = v->Next()) != NULL);
/* need to update acceleration and cached values since the goods on the train changed. */ /* need to update acceleration and cached values since the goods on the train changed. */
@ -3478,11 +3471,10 @@ static void SetVehicleCrashed(Vehicle *v)
{ {
if (v->u.rail.crash_anim_pos != 0) return; if (v->u.rail.crash_anim_pos != 0) return;
/* Free a possible path reservation and try to mark all tiles occupied by the train reserved. */
if (IsFrontEngine(v)) { if (IsFrontEngine(v)) {
/* Remove all reservations, also the ones currently under the train /* Remove the reserved path in front of the train if it is not stuck.
* and any railway station paltform reservation. */ * Also clear all reserved tracks the train is currently on. */
FreeTrainTrackReservation(v); if (!HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v);
for (const Vehicle *u = v; u != NULL; u = u->Next()) { for (const Vehicle *u = v; u != NULL; u = u->Next()) {
ClearPathReservation(u, u->tile, GetVehicleTrackdir(u)); ClearPathReservation(u, u->tile, GetVehicleTrackdir(u));
if (IsTileType(u->tile, MP_TUNNELBRIDGE)) { if (IsTileType(u->tile, MP_TUNNELBRIDGE)) {
@ -4369,9 +4361,7 @@ static void TrainLocoHandler(Vehicle *v, bool mode)
for (Vehicle *u = v; u != NULL; u = u->Next()) { for (Vehicle *u = v; u != NULL; u = u->Next()) {
if ((u->vehstatus & VS_HIDDEN) != 0) continue; if ((u->vehstatus & VS_HIDDEN) != 0) continue;
uint16 old_image = u->cur_image; u->UpdateViewport(false, false);
u->cur_image = u->GetImage(u->direction);
if (old_image != u->cur_image) VehicleMove(u, true);
} }
if (v->progress == 0) v->progress = j; // Save unused spd for next time, if TrainController didn't set progress if (v->progress == 0) v->progress = j; // Save unused spd for next time, if TrainController didn't set progress

View File

@ -461,6 +461,21 @@ public:
*/ */
virtual void OnNewDay() {}; virtual void OnNewDay() {};
/**
* Update vehicle sprite- and position caches
* @param moved Was the vehicle moved?
* @param turned Did the vehicle direction change?
*/
inline void UpdateViewport(bool moved, bool turned)
{
extern void VehicleMove(Vehicle *v, bool update_viewport);
if (turned) this->UpdateDeltaXY(this->direction);
SpriteID old_image = this->cur_image;
this->cur_image = this->GetImage(this->direction);
if (moved || this->cur_image != old_image) VehicleMove(this, true);
}
/** /**
* Gets the running cost of a vehicle that can be sent into SetDParam for string processing. * Gets the running cost of a vehicle that can be sent into SetDParam for string processing.
* @return the vehicle's running cost * @return the vehicle's running cost

View File

@ -808,7 +808,7 @@ static void FloodVehicle(Vehicle *v)
/* FreeTrainTrackReservation() calls GetVehicleTrackdir() that doesn't like crashed vehicles. /* FreeTrainTrackReservation() calls GetVehicleTrackdir() that doesn't like crashed vehicles.
* In this case, v->direction matches v->u.rail.track, so we can do this (it wasn't crashed before) */ * In this case, v->direction matches v->u.rail.track, so we can do this (it wasn't crashed before) */
v->vehstatus &= ~VS_CRASHED; v->vehstatus &= ~VS_CRASHED;
FreeTrainTrackReservation(v); if (!HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v);
v->vehstatus |= VS_CRASHED; v->vehstatus |= VS_CRASHED;
} }
v->u.rail.crash_anim_pos = 4000; // max 4440, disappear pretty fast v->u.rail.crash_anim_pos = 4000; // max 4440, disappear pretty fast