diff options
-rw-r--r-- | src/train_cmd.cpp | 52 |
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 { |