summaryrefslogtreecommitdiff
path: root/src/saveload
diff options
context:
space:
mode:
authormichi_cc <michi_cc@openttd.org>2011-11-21 20:51:43 +0000
committermichi_cc <michi_cc@openttd.org>2011-11-21 20:51:43 +0000
commit4d2a9e384ccb83eec9992ad36459f495bfcfe60f (patch)
tree26d51a4b166e5dfeff2c1e2bbe753b73df80332b /src/saveload
parent3748cab60876e98e530c514307e303a071498461 (diff)
downloadopenttd-4d2a9e384ccb83eec9992ad36459f495bfcfe60f.tar.xz
(svn r23290) -Fix [FS#2379,FS#3569]: Change the centre of train vehicles to depend on the vehicle length instead of being fixed at 4/8th of the original vehicle length to make sure shortened vehicles don't block tiles they shouldn't block.
Diffstat (limited to 'src/saveload')
-rw-r--r--src/saveload/afterload.cpp3
-rw-r--r--src/saveload/saveload.cpp3
-rw-r--r--src/saveload/saveload_internal.h1
-rw-r--r--src/saveload/vehicle_sl.cpp90
4 files changed, 94 insertions, 3 deletions
diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp
index 2fc3e0e5e..97f35e6d4 100644
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -2667,6 +2667,9 @@ bool AfterLoadGame()
}
}
+ /* The center of train vehicles was changed, fix up spacing. */
+ if (IsSavegameVersionBefore(164)) FixupTrainLengths();
+
/* When any NewGRF has been changed the availability of some vehicles might
* have been changed too. e->company_avail must be set to 0 in that case
* which is done by StartupEngines(). */
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
index c2c158824..e74659d66 100644
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -228,8 +228,9 @@
* 161 22567
* 162 22713
* 163 22767
+ * 164 23290
*/
-extern const uint16 SAVEGAME_VERSION = 163; ///< Current savegame version of OpenTTD.
+extern const uint16 SAVEGAME_VERSION = 164; ///< Current savegame version of OpenTTD.
SavegameType _savegame_type; ///< type of savegame we are loading
diff --git a/src/saveload/saveload_internal.h b/src/saveload/saveload_internal.h
index b400861b4..613ff262a 100644
--- a/src/saveload/saveload_internal.h
+++ b/src/saveload/saveload_internal.h
@@ -27,6 +27,7 @@ void MoveWaypointsToBaseStations();
const SaveLoad *GetBaseStationDescription();
void AfterLoadVehicles(bool part_of_load);
+void FixupTrainLengths();
void AfterLoadStations();
void AfterLoadRoadStops();
void AfterLoadLabelMaps();
diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp
index 4dc0a7fe2..1e47094eb 100644
--- a/src/saveload/vehicle_sl.cpp
+++ b/src/saveload/vehicle_sl.cpp
@@ -249,8 +249,6 @@ void AfterLoadVehicles(bool part_of_load)
if (v->Next() != NULL) v->Next()->previous = v;
if (v->NextShared() != NULL) v->NextShared()->previous_shared = v;
- v->UpdateDeltaXY(v->direction);
-
if (part_of_load) v->fill_percent_te_id = INVALID_TE_ID;
v->first = NULL;
if (v->IsGroundVehicle()) v->GetGroundVehicleCache()->first_engine = INVALID_ENGINE;
@@ -442,11 +440,99 @@ void AfterLoadVehicles(bool part_of_load)
default: break;
}
+ v->UpdateDeltaXY(v->direction);
v->coord.left = INVALID_COORD;
VehicleMove(v, false);
}
}
+bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // From train_cmd.cpp
+void ReverseTrainDirection(Train *v);
+void ReverseTrainSwapVeh(Train *v, int l, int r);
+
+/** Fixup old train spacing. */
+void FixupTrainLengths()
+{
+ /* Vehicle center was moved from 4 units behind the front to half the length
+ * behind the front. Move vehicles so they end up on the same spot. */
+ Vehicle *v;
+ FOR_ALL_VEHICLES(v) {
+ if (v->type == VEH_TRAIN && v->IsPrimaryVehicle()) {
+ /* The vehicle center is now more to the front depending on vehicle length,
+ * so we need to move all vehicles forward to cover the difference to the
+ * old center, otherwise wagon spacing in trains would be broken upon load. */
+ for (Train *u = Train::From(v); u != NULL; u = u->Next()) {
+ if (u->track == TRACK_BIT_DEPOT || (u->vehstatus & VS_CRASHED)) continue;
+
+ Train *next = u->Next();
+
+ /* Try to pull the vehicle half its length forward. */
+ int diff = (VEHICLE_LENGTH - u->gcache.cached_veh_length) / 2;
+ int done;
+ for (done = 0; done < diff; done++) {
+ if (!TrainController(u, next, false)) break;
+ }
+
+ if (next != NULL && done < diff && u->IsFrontEngine()) {
+ /* Pulling the front vehicle forwards failed, we either encountered a dead-end
+ * or a red signal. To fix this, we try to move the whole train the required
+ * space backwards and re-do the fix up of the front vehicle. */
+
+ /* Ignore any signals when backtracking. */
+ TrainForceProceeding old_tfp = u->force_proceed;
+ u->force_proceed = TFP_SIGNAL;
+
+ /* Swap start<>end, start+1<>end-1, ... */
+ int r = CountVehiclesInChain(u) - 1; // number of vehicles - 1
+ int l = 0;
+ do ReverseTrainSwapVeh(u, l++, r--); while (l <= r);
+
+ /* We moved the first vehicle which is now the last. Move it back to the
+ * original position as we will fix up the last vehicle later in the loop. */
+ for (int i = 0; i < done; i++) TrainController(u->Last(), NULL);
+
+ /* Move the train backwards to get space for the first vehicle. As the stopping
+ * distance from a line end is rounded up, move the train one unit more to cater
+ * for front vehicles with odd lengths. */
+ int moved;
+ for (moved = 0; moved < diff + 1; moved++) {
+ if (!TrainController(u, NULL, false)) break;
+ }
+
+ /* Swap start<>end, start+1<>end-1, ... again. */
+ r = CountVehiclesInChain(u) - 1; // number of vehicles - 1
+ l = 0;
+ do ReverseTrainSwapVeh(u, l++, r--); while (l <= r);
+
+ u->force_proceed = old_tfp;
+
+ /* Tracks are too short to fix the train length. The player has to fix the
+ * train in a depot. Bail out so we don't damage the vehicle chain any more. */
+ if (moved < diff + 1) break;
+
+ /* Re-do the correction for the first vehicle. */
+ for (done = 0; done < diff; done++) TrainController(u, next, false);
+
+ /* We moved one unit more backwards than needed for even-length front vehicles,
+ * try to move that unit forward again. We don't care if this step fails. */
+ TrainController(u, NULL, false);
+ }
+
+ /* If the next wagon is still in a depot, check if it shouldn't be outside already. */
+ if (next != NULL && next->track == TRACK_BIT_DEPOT) {
+ int d = TicksToLeaveDepot(u);
+ if (d <= 0) {
+ /* Next vehicle should have left the depot already, show it and pull forward. */
+ next->vehstatus &= ~VS_HIDDEN;
+ next->track = TrackToTrackBits(GetRailDepotTrack(next->tile));
+ for (int i = 0; i >= d; i--) TrainController(next, NULL);
+ }
+ }
+ }
+ }
+ }
+}
+
static uint8 _cargo_days;
static uint16 _cargo_source;
static uint32 _cargo_source_xy;