diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index 5cdb912cbc..fe79756757 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -706,11 +706,9 @@ void SetAircraftPosition(Vehicle *v, int x, int y, int z) v->y_pos = y; 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); - VehicleMove(v, true); - Vehicle *u = v->Next(); int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE); @@ -1293,9 +1291,8 @@ TileIndex Aircraft::GetOrderStationLocation(StationID station) 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); - MarkSingleVehicleDirty(this); } static void CrashAirplane(Vehicle *v) diff --git a/src/lang/english.txt b/src/lang/english.txt index 90b7c7090b..f0fd2d8c45 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -3270,7 +3270,7 @@ STR_MASS_START_LIST_TIP :{BLACK}Click to STR_SHORT_DATE :{WHITE}{DATE_TINY} 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 diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 7c7f5063a2..a2ebf5abe8 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -486,8 +486,7 @@ CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 void RoadVehicle::MarkDirty() { for (Vehicle *v = this; v != NULL; v = v->Next()) { - v->cur_image = v->GetImage(v->direction); - MarkSingleVehicleDirty(v); + v->UpdateViewport(false, false); } } @@ -536,7 +535,7 @@ static void DeleteLastRoadVeh(Vehicle *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; @@ -548,7 +547,7 @@ static byte SetRoadVehPosition(Vehicle *v, int x, int y) old_z = v->z_pos; v->z_pos = new_z; - VehicleMove(v, true); + v->UpdateViewport(true, turned); return old_z; } @@ -562,9 +561,7 @@ static void RoadVehSetRandomDirection(Vehicle *v) uint32 r = Random(); v->direction = ChangeDir(v->direction, delta[r & 3]); - v->UpdateDeltaXY(v->direction); - v->cur_image = v->GetImage(v->direction); - SetRoadVehPosition(v, v->x_pos, v->y_pos); + SetRoadVehPosition(v, v->x_pos, v->y_pos, true); } while ((v = v->Next()) != NULL); } @@ -1256,8 +1253,7 @@ static bool RoadVehLeaveDepot(Vehicle *v, bool first) v->u.road.state = tdir; v->u.road.frame = RVC_DEPOT_START_FRAME; - v->UpdateDeltaXY(v->direction); - SetRoadVehPosition(v, x, y); + SetRoadVehPosition(v, x, y, true); 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)) { /* Vehicle has just entered a bridge or tunnel */ - v->UpdateDeltaXY(v->direction); - SetRoadVehPosition(v, gp.x, gp.y); + SetRoadVehPosition(v, gp.x, gp.y, true); return true; } @@ -1530,8 +1525,7 @@ again: v->cur_speed -= v->cur_speed >> 2; } - v->UpdateDeltaXY(v->direction); - RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y)); + RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true)); return true; } @@ -1595,8 +1589,7 @@ again: v->cur_speed -= v->cur_speed >> 2; } - v->UpdateDeltaXY(v->direction); - RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y)); + RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true)); return true; } @@ -1635,8 +1628,7 @@ again: v->cur_speed -= (v->cur_speed >> 2); if (old_dir != v->u.road.state) { /* The vehicle is in a road stop */ - v->UpdateDeltaXY(v->direction); - SetRoadVehPosition(v, v->x_pos, v->y_pos); + SetRoadVehPosition(v, v->x_pos, v->y_pos, true); /* Note, return here means that the frame counter is not incremented * for vehicles changing direction in a road stop. This causes frames to * be repeated. (XXX) Is this intended? */ @@ -1683,7 +1675,7 @@ again: v->u.road.slot_age = 14; v->u.road.frame++; - RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y)); + RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, false)); return true; } } @@ -1758,8 +1750,7 @@ again: * in a depot or entered a tunnel/bridge */ if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->u.road.frame++; - v->UpdateDeltaXY(v->direction); - RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y)); + RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true)); return true; } @@ -1818,9 +1809,7 @@ static void RoadVehController(Vehicle *v) for (Vehicle *u = v; u != NULL; u = u->Next()) { if ((u->vehstatus & VS_HIDDEN) != 0) continue; - uint16 old_image = u->cur_image; - u->cur_image = u->GetImage(u->direction); - if (old_image != u->cur_image) VehicleMove(u, true); + u->UpdateViewport(false, false); } if (v->progress == 0) v->progress = j; diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index e359a081db..39a74fab0c 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -211,8 +211,7 @@ static void HandleBrokenShip(Vehicle *v) void Ship::MarkDirty() { - this->cur_image = this->GetImage(this->direction); - MarkSingleVehicleDirty(this); + this->UpdateViewport(false, false); } static void PlayShipSound(const Vehicle *v) @@ -265,9 +264,7 @@ void Ship::UpdateDeltaXY(Direction direction) void RecalcShipStuff(Vehicle *v) { - v->UpdateDeltaXY(v->direction); - v->cur_image = v->GetImage(v->direction); - v->MarkDirty(); + v->UpdateViewport(false, true); InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); } @@ -693,9 +690,7 @@ static void ShipController(Vehicle *v) v->z_pos = GetSlopeZ(gp.x, gp.y); getout: - v->UpdateDeltaXY(dir); - v->cur_image = v->GetImage(dir); - VehicleMove(v, true); + v->UpdateViewport(true, true); return; reverse_direction: diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index a3d63280d4..392a0dfc2d 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -1533,13 +1533,6 @@ void Train::UpdateDeltaXY(Direction direction) 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) { 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); /* update other vars */ - UpdateVarsAfterSwap(a); - UpdateVarsAfterSwap(b); + a->UpdateViewport(true, true); + b->UpdateViewport(true, true); /* 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 (b->u.rail.track != TRACK_BIT_WORMHOLE) VehicleEnterTile(b, b->tile, b->x_pos, b->y_pos); } else { 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); } @@ -1828,8 +1821,8 @@ static void ReverseTrainDirection(Vehicle *v) InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); } - /* Clear path reservation in front. */ - FreeTrainTrackReservation(v); + /* Clear path reservation in front if train is not stuck. */ + if (!HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v); /* Check if we were approaching a rail/road-crossing */ TileIndex crossing = TrainApproachingCrossingTile(v); @@ -1859,7 +1852,7 @@ static void ReverseTrainDirection(Vehicle *v) TrainConsistChanged(v, true); /* 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 */ 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; 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 (origin.okay && (v->tile != origin.tile || first_tile_okay)) { /* 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); 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 (v->u.rail.track & TRACK_BIT_DEPOT) { @@ -3253,8 +3247,7 @@ void Train::MarkDirty() { Vehicle *v = this; do { - v->cur_image = v->GetImage(v->direction); - MarkSingleVehicleDirty(v); + v->UpdateViewport(false, false); } while ((v = v->Next()) != NULL); /* 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; - /* Free a possible path reservation and try to mark all tiles occupied by the train reserved. */ if (IsFrontEngine(v)) { - /* Remove all reservations, also the ones currently under the train - * and any railway station paltform reservation. */ - FreeTrainTrackReservation(v); + /* Remove the reserved path in front of the train if it is not stuck. + * Also clear all reserved tracks the train is currently on. */ + if (!HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v); for (const Vehicle *u = v; u != NULL; u = u->Next()) { ClearPathReservation(u, u->tile, GetVehicleTrackdir(u)); 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()) { if ((u->vehstatus & VS_HIDDEN) != 0) continue; - uint16 old_image = u->cur_image; - u->cur_image = u->GetImage(u->direction); - if (old_image != u->cur_image) VehicleMove(u, true); + u->UpdateViewport(false, false); } if (v->progress == 0) v->progress = j; // Save unused spd for next time, if TrainController didn't set progress diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 9baf817b0f..e2b75f9789 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -461,6 +461,21 @@ public: */ 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. * @return the vehicle's running cost diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index 7b49b3fcfb..f90a5c4c2a 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -808,7 +808,7 @@ static void FloodVehicle(Vehicle *v) /* 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) */ v->vehstatus &= ~VS_CRASHED; - FreeTrainTrackReservation(v); + if (!HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v); v->vehstatus |= VS_CRASHED; } v->u.rail.crash_anim_pos = 4000; // max 4440, disappear pretty fast