From 4d2a9e384ccb83eec9992ad36459f495bfcfe60f Mon Sep 17 00:00:00 2001 From: michi_cc Date: Mon, 21 Nov 2011 20:51:43 +0000 Subject: (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. --- src/saveload/vehicle_sl.cpp | 90 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) (limited to 'src/saveload/vehicle_sl.cpp') 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; -- cgit v1.2.3-70-g09d2