summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--openttd.c5
-rw-r--r--saveload.c2
-rw-r--r--train.h3
-rw-r--r--train_cmd.c152
-rw-r--r--vehicle.c101
-rw-r--r--vehicle.h1
6 files changed, 162 insertions, 102 deletions
diff --git a/openttd.c b/openttd.c
index d84e73b18..28c97c3b5 100644
--- a/openttd.c
+++ b/openttd.c
@@ -40,6 +40,7 @@
#include "depot.h"
#include "waypoint.h"
#include "ai/ai.h"
+#include "train.h"
#include <stdarg.h>
@@ -1144,6 +1145,10 @@ bool AfterLoadGame(void)
* subtype to the new format */
if (CheckSavegameVersionOldStyle(17, 1)) ConvertOldMultiheadToNew();
+ /* Connect front and rear engines of multiheaded trains
+ since this info were no longer saved in savegame version 20 */
+ if (!CheckSavegameVersion(20)) ConnectMultiheadedTrains();
+
// Update current year
SetDate(_date);
diff --git a/saveload.c b/saveload.c
index fb141cc91..386233160 100644
--- a/saveload.c
+++ b/saveload.c
@@ -29,7 +29,7 @@
#include <setjmp.h>
enum {
- SAVEGAME_VERSION = 19,
+ SAVEGAME_VERSION = 20,
};
diff --git a/train.h b/train.h
index 9cb3a78d2..8399e8cc2 100644
--- a/train.h
+++ b/train.h
@@ -205,4 +205,7 @@ static inline Vehicle *GetLastEnginePart(Vehicle *v)
return v;
}
+void ConvertOldMultiheadToNew(void);
+void ConnectMultiheadedTrains(void);
+
#endif /* TRAIN_H */
diff --git a/train_cmd.c b/train_cmd.c
index f1f444252..424e53b5a 100644
--- a/train_cmd.c
+++ b/train_cmd.c
@@ -3700,3 +3700,155 @@ void InitializeTrains(void)
{
_age_cargo_skip_counter = 1;
}
+
+/*
+ * Link front and rear multiheaded engines to each other
+ * This is done when loading a savegame
+ */
+void ConnectMultiheadedTrains(void)
+{
+ Vehicle *v;
+
+ FOR_ALL_VEHICLES(v) {
+ if (v->type == VEH_Train) {
+ v->u.rail.other_multiheaded_part = NULL;
+ }
+ }
+
+ FOR_ALL_VEHICLES(v) {
+ if (v->type == VEH_Train && IsFrontEngine(v)) {
+ Vehicle *u = v;
+
+ BEGIN_ENUM_WAGONS(u) {
+ if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one
+
+ if (IsMultiheaded(u)) {
+ if (!IsTrainEngine(u)) {
+ /* we got a rear car without a front car. We will convert it to a front one */
+ SetTrainEngine(u);
+ u->spritenum--;
+ }
+
+ {
+ Vehicle *w;
+
+ for(w = u->next; w != NULL && (w->engine_type != u->engine_type || w->u.rail.other_multiheaded_part != NULL); w = GetNextVehicle(w));
+ if (w != NULL) {
+ /* we found a car to partner with this engine. Now we will make sure it face the right way */
+ if (IsTrainEngine(w)) {
+ ClearTrainEngine(w);
+ w->spritenum++;
+ }
+ }
+
+ if (w != NULL) {
+ w->u.rail.other_multiheaded_part = u;
+ u->u.rail.other_multiheaded_part = w;
+ } else {
+ /* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */
+ ClearMultiheaded(u);
+ }
+ }
+ }
+ } END_ENUM_WAGONS(u)
+ }
+ }
+}
+
+/*
+ * Converts all trains to the new subtype format introduced in savegame 16.2
+ * It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found
+ */
+void ConvertOldMultiheadToNew(void)
+{
+ Vehicle *v;
+ FOR_ALL_VEHICLES(v) {
+ if (v->type == VEH_Train) {
+ SETBIT(v->subtype, 7); // indicates that it's the old format and needs to be converted in the next loop
+ }
+ }
+
+ FOR_ALL_VEHICLES(v) {
+ if (v->type == VEH_Train) {
+ if (HASBIT(v->subtype, 7) && ((v->subtype & ~0x80) == 0 || (v->subtype & ~0x80) == 4)) {
+ Vehicle *u = v;
+
+ BEGIN_ENUM_WAGONS(u)
+ const RailVehicleInfo *rvi = RailVehInfo(u->engine_type);
+ CLRBIT(u->subtype, 7);
+ switch (u->subtype) {
+ case 0: /* TS_Front_Engine */
+ if (rvi->flags & RVI_MULTIHEAD) {
+ SetMultiheaded(u);
+ }
+ SetFrontEngine(u);
+ SetTrainEngine(u);
+ break;
+ case 1: /* TS_Artic_Part */
+ u->subtype = 0;
+ SetArticulatedPart(u);
+ break;
+ case 2: /* TS_Not_First */
+ u->subtype = 0;
+ if (rvi->flags & RVI_WAGON) {
+ // normal wagon
+ SetTrainWagon(u);
+ break;
+ }
+ if (rvi->flags & RVI_MULTIHEAD && rvi->image_index == u->spritenum - 1) {
+ // rear end of a multiheaded engine
+ SetMultiheaded(u);
+ break;
+ }
+ if (rvi->flags & RVI_MULTIHEAD) {
+ SetMultiheaded(u);
+ }
+ SetTrainEngine(u);
+ break;
+ case 4: /* TS_Free_Car */
+ u->subtype = 0;
+ SetTrainWagon(u);
+ SetFreeWagon(u);
+ break;
+ default: NOT_REACHED(); break;
+ }
+ END_ENUM_WAGONS(u)
+ u = v;
+ BEGIN_ENUM_WAGONS(u)
+ const RailVehicleInfo *rvi = RailVehInfo(u->engine_type);
+
+ if (u->u.rail.other_multiheaded_part != NULL) continue;
+
+ if (rvi->flags & RVI_MULTIHEAD) {
+ if (!IsTrainEngine(u)) {
+ /* we got a rear car without a front car. We will convert it to a front one */
+ SetTrainEngine(u);
+ u->spritenum--;
+ }
+
+ {
+ Vehicle *w;
+
+ for(w = u->next; w != NULL && (w->engine_type != u->engine_type || w->u.rail.other_multiheaded_part != NULL); w = GetNextVehicle(w));
+ if (w != NULL) {
+ /* we found a car to partner with this engine. Now we will make sure it face the right way */
+ if (IsTrainEngine(w)) {
+ ClearTrainEngine(w);
+ w->spritenum++;
+ }
+ }
+
+ if (w != NULL) {
+ w->u.rail.other_multiheaded_part = u;
+ u->u.rail.other_multiheaded_part = w;
+ } else {
+ /* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */
+ ClearMultiheaded(u);
+ }
+ }
+ }
+ END_ENUM_WAGONS(u)
+ }
+ }
+ }
+}
diff --git a/vehicle.c b/vehicle.c
index b7fa42aee..8e3111552 100644
--- a/vehicle.c
+++ b/vehicle.c
@@ -2128,7 +2128,7 @@ static const SaveLoad _train_desc[] = {
SLE_CONDARR(NullStruct, null, SLE_FILE_U8 | SLE_VAR_NULL, 2, 2, 255),
- SLE_CONDREFX(offsetof(Vehicle,u)+offsetof(VehicleRail,other_multiheaded_part), REF_VEHICLE, 2, 255), // added with 17.1, but was blank since 2
+ SLE_CONDREFX(offsetof(Vehicle,u)+offsetof(VehicleRail,other_multiheaded_part), REF_VEHICLE, 2, 19), // added with 17.1, but was blank since 2. Removed in 20
// reserve extra space in savegame here. (currently 3 bytes)
SLE_CONDARR(NullStruct,null,SLE_FILE_U8 | SLE_VAR_NULL, 3, 2, 255),
@@ -2282,105 +2282,6 @@ static void Save_VEHS(void)
}
}
-/*
- * Converts all trains to the new subtype format introduced in savegame 16.2
- * It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found
- */
-void ConvertOldMultiheadToNew(void)
-{
- Vehicle *v;
- FOR_ALL_VEHICLES(v) {
- if (v->type == VEH_Train) {
- v->u.rail.other_multiheaded_part = NULL;
- SETBIT(v->subtype, 7); // indicates that it's the old format and needs to be converted in the next loop
- }
- }
-
- FOR_ALL_VEHICLES(v) {
- if (v->type == VEH_Train) {
- if (HASBIT(v->subtype, 7) && ((v->subtype & ~0x80) == 0 || (v->subtype & ~0x80) == 4)) {
- Vehicle *u = v;
-
- BEGIN_ENUM_WAGONS(u)
- const RailVehicleInfo *rvi = RailVehInfo(u->engine_type);
- CLRBIT(u->subtype, 7);
- switch (u->subtype) {
- case 0: /* TS_Front_Engine */
- if (rvi->flags & RVI_MULTIHEAD) {
- SetMultiheaded(u);
- }
- SetFrontEngine(u);
- SetTrainEngine(u);
- break;
- case 1: /* TS_Artic_Part */
- u->subtype = 0;
- SetArticulatedPart(u);
- break;
- case 2: /* TS_Not_First */
- u->subtype = 0;
- if (rvi->flags & RVI_WAGON) {
- // normal wagon
- SetTrainWagon(u);
- break;
- }
- if (rvi->flags & RVI_MULTIHEAD && rvi->image_index == u->spritenum - 1) {
- // rear end of a multiheaded engine
- SetMultiheaded(u);
- break;
- }
- if (rvi->flags & RVI_MULTIHEAD) {
- SetMultiheaded(u);
- }
- SetTrainEngine(u);
- break;
- case 4: /* TS_Free_Car */
- u->subtype = 0;
- SetTrainWagon(u);
- SetFreeWagon(u);
- break;
- default: NOT_REACHED(); break;
- }
- END_ENUM_WAGONS(u)
- u = v;
- BEGIN_ENUM_WAGONS(u)
- const RailVehicleInfo *rvi = RailVehInfo(u->engine_type);
-
- if (u->u.rail.other_multiheaded_part != NULL) continue;
-
- if (rvi->flags & RVI_MULTIHEAD) {
- if (!IsTrainEngine(u)) {
- /* we got a rear car without a front car. We will convert it to a front one */
- SetTrainEngine(u);
- u->spritenum--;
- }
-
- {
- Vehicle *w;
-
- for(w = u->next; w != NULL && (w->engine_type != u->engine_type || w->u.rail.other_multiheaded_part != NULL); w = GetNextVehicle(w));
- if (w != NULL) {
- /* we found a car to partner with this engine. Now we will make sure it face the right way */
- if (IsTrainEngine(w)) {
- ClearTrainEngine(w);
- w->spritenum++;
- }
- }
-
- if (w != NULL) {
- w->u.rail.other_multiheaded_part = u;
- u->u.rail.other_multiheaded_part = w;
- } else {
- /* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */
- ClearMultiheaded(u);
- }
- }
- }
- END_ENUM_WAGONS(u)
- }
- }
- }
-}
-
// Will be called when vehicles need to be loaded.
static void Load_VEHS(void)
{
diff --git a/vehicle.h b/vehicle.h
index c00f0b8da..7136ed172 100644
--- a/vehicle.h
+++ b/vehicle.h
@@ -313,7 +313,6 @@ int32 GetTrainRunningCost(const Vehicle *v);
int CheckTrainStoppedInDepot(const Vehicle *v);
bool VehicleNeedsService(const Vehicle *v);
-void ConvertOldMultiheadToNew(void);
typedef struct GetNewVehiclePosResult {
int x,y;