changeset 17143:d2394a934993 draft

(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
author smatz <smatz@openttd.org>
date Fri, 21 Jan 2011 16:48:41 +0000
parents 958bcdb45229
children 48e5ee157a02
files src/saveload/afterload.cpp
diffstat 1 files changed, 114 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -437,6 +437,42 @@
 	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 @@
 		}
 	}
 
+	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();