summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsmatz <smatz@openttd.org>2011-01-21 16:48:41 +0000
committersmatz <smatz@openttd.org>2011-01-21 16:48:41 +0000
commit2a2363e819612a7c01f1a02210043e426775eb4d (patch)
tree90f15533fac739a0c7a928c1b12ea0ed07a75c2e
parenta6fcd7853882abf9dea0a1a035f1372751de432f (diff)
downloadopenttd-2a2363e819612a7c01f1a02210043e426775eb4d.tar.xz
(svn r21881) -Codechange: ensure that vehicle's GOINGUP/DOWN bits are set correctly and that it has correct z_pos when converting from older savegames
-rw-r--r--src/saveload/afterload.cpp114
1 files changed, 114 insertions, 0 deletions
diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp
index da7db48d9..679b0244f 100644
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -437,6 +437,42 @@ static void FixOwnerOfRailTrack(TileIndex t)
MakeClear(t, CLEAR_GRASS, 0);
}
+/**
+ * Fixes inclination of a vehicle. Older OpenTTD versions didn't update the bits correctly.
+ * @param v vehicle
+ * @param dir vehicle's direction, or # INVALID_DIR if it can be ignored
+ * @return inclination bits to set
+ */
+static uint FixVehicleInclination(Vehicle *v, Direction dir)
+{
+ /* Compute place where this vehicle entered the tile */
+ int entry_x = v->x_pos;
+ int entry_y = v->y_pos;
+ switch (dir) {
+ case DIR_NE: entry_x |= TILE_UNIT_MASK; break;
+ case DIR_NW: entry_y |= TILE_UNIT_MASK; break;
+ case DIR_SW: entry_x &= ~TILE_UNIT_MASK; break;
+ case DIR_SE: entry_y &= ~TILE_UNIT_MASK; break;
+ case INVALID_DIR: break;
+ default: NOT_REACHED();
+ }
+ byte entry_z = GetSlopeZ(entry_x, entry_y);
+
+ /* Compute middle of the tile. */
+ int middle_x = (v->x_pos & ~TILE_UNIT_MASK) + HALF_TILE_SIZE;
+ int middle_y = (v->y_pos & ~TILE_UNIT_MASK) + HALF_TILE_SIZE;
+ byte middle_z = GetSlopeZ(middle_x, middle_y);
+
+ /* middle_z == entry_z, no height change. */
+ if (middle_z == entry_z) return 0;
+
+ /* middle_z < entry_z, we are going downwards. */
+ if (middle_z < entry_z) return 1U << GVF_GOINGDOWN_BIT;
+
+ /* middle_z > entry_z, we are going upwards. */
+ return 1U << GVF_GOINGUP_BIT;
+}
+
bool AfterLoadGame()
{
SetSignalHandlers();
@@ -2419,6 +2455,84 @@ bool AfterLoadGame()
}
}
+ if (IsSavegameVersionBefore(158)) {
+ Vehicle *v;
+ FOR_ALL_VEHICLES(v) {
+ switch (v->type) {
+ case VEH_TRAIN: {
+ Train *t = Train::From(v);
+ /* Clear both bits first. */
+ ClrBit(t->gv_flags, GVF_GOINGUP_BIT);
+ ClrBit(t->gv_flags, GVF_GOINGDOWN_BIT);
+
+ /* Crashed vehicles can't be going up/down. */
+ if (t->vehstatus & VS_CRASHED) break;
+
+ /* Only X/Y tracks can be sloped. */
+ if (t->track != TRACK_BIT_X && t->track != TRACK_BIT_Y) break;
+
+ t->gv_flags |= FixVehicleInclination(t, t->direction);
+ break;
+ }
+ case VEH_ROAD: {
+ RoadVehicle *rv = RoadVehicle::From(v);
+ ClrBit(rv->gv_flags, GVF_GOINGUP_BIT);
+ ClrBit(rv->gv_flags, GVF_GOINGDOWN_BIT);
+
+ /* Crashed vehicles can't be going up/down. */
+ if (rv->vehstatus & VS_CRASHED) break;
+
+ if (rv->state == RVSB_IN_DEPOT || rv->state == RVSB_WORMHOLE) break;
+
+ TrackStatus ts = GetTileTrackStatus(rv->tile, TRANSPORT_ROAD, rv->compatible_roadtypes);
+ TrackBits trackbits = TrackStatusToTrackBits(ts);
+
+ /* Only X/Y tracks can be sloped. */
+ if (trackbits != TRACK_BIT_X && trackbits != TRACK_BIT_Y) break;
+
+ Direction dir = rv->direction;
+
+ /* Test if we are reversing. */
+ Axis a = trackbits == TRACK_BIT_X ? AXIS_X : AXIS_Y;
+ if (AxisToDirection(a) != dir &&
+ AxisToDirection(a) != ReverseDir(dir)) {
+ /* When reversing, the road vehicle is on the edge of the tile,
+ * so it can be safely compared to the middle of the tile. */
+ dir = INVALID_DIR;
+ }
+
+ rv->gv_flags |= FixVehicleInclination(rv, dir);
+ break;
+ }
+ case VEH_SHIP:
+ break;
+
+ default:
+ continue;
+ }
+
+ if (IsBridgeTile(v->tile) && TileVirtXY(v->x_pos, v->y_pos) == v->tile) {
+ /* In old versions, z_pos was 1 unit lower on bridge heads.
+ * However, this invalid state could be converted to new savegames
+ * by loading and saving the game in a new version. */
+ v->z_pos = GetSlopeZ(v->x_pos, v->y_pos);
+ DiagDirection dir = GetTunnelBridgeDirection(v->tile);
+ if (v->type == VEH_TRAIN && !(v->vehstatus & VS_CRASHED) &&
+ v->direction != DiagDirToDir(dir)) {
+ /* If the train has left the bridge, it shouldn't have
+ * track == TRACK_BIT_WORMHOLE - this could happen
+ * when the train was reversed while on the last "tick"
+ * on the ramp before leaving the ramp to the bridge. */
+ Train::From(v)->track = DiagDirToDiagTrackBits(dir);
+ }
+ }
+
+ /* If the vehicle is really above v->tile (not in a wormhole),
+ * it should have set v->z_pos correctly. */
+ assert(v->tile != TileVirtXY(v->x_pos, v->y_pos) || v->z_pos == GetSlopeZ(v->x_pos, v->y_pos));
+ }
+ }
+
/* Road stops is 'only' updating some caches */
AfterLoadRoadStops();
AfterLoadLabelMaps();