summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/train_cmd.cpp52
1 files changed, 44 insertions, 8 deletions
diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp
index c87e08276..18881c719 100644
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -4434,8 +4434,23 @@ void ConnectMultiheadedTrains()
}
FOR_ALL_VEHICLES(v) {
- if (v->type == VEH_TRAIN && IsFrontEngine(v)) {
- for (Vehicle *u = v; u != NULL; u = u->Next()) {
+ if (v->type == VEH_TRAIN) {
+ /* Two ways to associate multiheaded parts to each other:
+ * sequential-matching: Trains shall be arranged to look like <..>..<..>..<..>..
+ * bracket-matching: Free vehicle chains shall be arranged to look like ..<..<..>..<..>..>..
+ *
+ * Note: Old savegames might contain chains which do not comply with these rules, e.g.
+ * - the front and read parts have invalid orders
+ * - different engine types might be combined
+ * - there might be different amounts of front and rear parts.
+ *
+ * Note: The multiheaded parts need to be matched exactly like they are matched on the server, else desyncs will occur.
+ * This is why two matching strategies are needed.
+ */
+
+ bool sequential_matching = IsFrontEngine(v);
+
+ for (Vehicle *u = v; u != NULL; u = GetNextVehicle(u)) {
if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one
if (IsMultiheaded(u)) {
@@ -4445,14 +4460,35 @@ void ConnectMultiheadedTrains()
u->spritenum--;
}
+ /* Find a matching back part */
+ EngineID eid = u->engine_type;
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 (sequential_matching) {
+ for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) {
+ if (w->engine_type != eid || w->u.rail.other_multiheaded_part != NULL || !IsMultiheaded(w)) continue;
+
+ /* 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++;
+ }
+ break;
+ }
+ } else {
+ uint stack_pos = 0;
+ for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) {
+ if (w->engine_type != eid || w->u.rail.other_multiheaded_part != NULL || !IsMultiheaded(w)) continue;
+
+ if (IsTrainEngine(w)) {
+ stack_pos++;
+ } else {
+ if (stack_pos == 0) break;
+ stack_pos--;
+ }
}
+ }
+
+ if (w != NULL) {
w->u.rail.other_multiheaded_part = u;
u->u.rail.other_multiheaded_part = w;
} else {