summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsmatz <smatz@openttd.org>2008-03-19 20:50:19 +0000
committersmatz <smatz@openttd.org>2008-03-19 20:50:19 +0000
commitac4ec8c2d2120d308d6710104ef0d04a02ae5424 (patch)
treee774ea23b6e94d9b81b383a3d13deff48bfd8762
parentab7542e912c54907690d34779d743eaef874b7e8 (diff)
downloadopenttd-ac4ec8c2d2120d308d6710104ef0d04a02ae5424.tar.xz
(svn r12386) -Fix [FS#1841](r2428): train could break apart when reversed while partially in a depot
-rw-r--r--src/rail.h1
-rw-r--r--src/rail_cmd.cpp23
-rw-r--r--src/train_cmd.cpp83
3 files changed, 93 insertions, 14 deletions
diff --git a/src/rail.h b/src/rail.h
index 5f91490c9..eb31bb4ab 100644
--- a/src/rail.h
+++ b/src/rail.h
@@ -181,6 +181,7 @@ void *UpdateTrainPowerProc(Vehicle *v, void *data);
void DrawTrainDepotSprite(int x, int y, int image, RailType railtype);
void DrawDefaultWaypointSprite(int x, int y, RailType railtype);
void *EnsureNoTrainOnTrackProc(Vehicle *v, void *data);
+int TicksToLeaveDepot(const Vehicle *v);
/**
* Draws overhead wires and pylons for electric railways.
diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp
index 118551c2e..724a7213d 100644
--- a/src/rail_cmd.cpp
+++ b/src/rail_cmd.cpp
@@ -2230,6 +2230,29 @@ static const signed char _deltacoord_leaveoffset[8] = {
0, 1, 0, -1 /* y */
};
+
+/** Compute number of ticks when next wagon will leave a depot.
+ * Negative means next wagon should have left depot n ticks before.
+ * @param v vehicle outside (leaving) the depot
+ * @return number of ticks when the next wagon will leave
+ */
+int TicksToLeaveDepot(const Vehicle *v)
+{
+ DiagDirection dir = GetRailDepotDirection(v->tile);
+ int length = v->u.rail.cached_veh_length;
+
+ switch (dir) {
+ case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
+ case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
+ case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
+ default:
+ case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
+ }
+
+ return 0; // make compilers happy
+}
+
+
static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *v, TileIndex tile, int x, int y)
{
byte fract_coord;
diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp
index 643828a4b..a5cffd820 100644
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -1716,31 +1716,86 @@ static inline void MaybeBarCrossingWithSound(TileIndex tile)
/**
* Advances wagons for train reversing, needed for variable length wagons.
- * Needs to be called once before the train is reversed, and once after it.
+ * This one is called before the train is reversed.
* @param v First vehicle in chain
- * @param before Set to true for the call before reversing, false otherwise
*/
-static void AdvanceWagons(Vehicle *v, bool before)
+static void AdvanceWagonsBeforeSwap(Vehicle *v)
{
Vehicle *base = v;
- Vehicle *first = base->Next();
+ Vehicle *first = base; // first vehicle to move
+ Vehicle *last = GetLastVehicleInChain(v); // last vehicle to move
uint length = CountVehiclesInChain(v);
while (length > 2) {
- /* find pairwise matching wagon
- * start<>end, start+1<>end-1, ... */
- Vehicle *last = first;
- for (uint i = length - 3; i > 0; i--) last = last->Next();
+ last = last->Previous();
+ first = first->Next();
- int differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length;
- if (before) differential *= -1;
+ int differential = base->u.rail.cached_veh_length - last->u.rail.cached_veh_length;
/* do not update images now
- * negative differential will are handled in the second run */
+ * negative differential will be handled in AdvanceWagonsAfterSwap() */
for (int i = 0; i < differential; i++) TrainController(first, last->Next(), false);
- base = first;
+ base = first; // == base->Next()
+ length -= 2;
+ }
+}
+
+
+/**
+ * Advances wagons for train reversing, needed for variable length wagons.
+ * This one is called after the train is reversed.
+ * @param v First vehicle in chain
+ */
+static void AdvanceWagonsAfterSwap(Vehicle *v)
+{
+ /* first of all, fix the situation when the train was entering a depot */
+ Vehicle *dep = v; // last vehicle in front of just left depot
+ while (dep->Next() != NULL && (dep->u.rail.track == TRACK_BIT_DEPOT || dep->Next()->u.rail.track != TRACK_BIT_DEPOT)) {
+ dep = dep->Next(); // find first vehicle outside of a depot, with next vehicle inside a depot
+ }
+
+ Vehicle *leave = dep->Next(); // first vehicle in a depot we are leaving now
+
+ if (leave != NULL) {
+ /* 'pull' next wagon out of the depot, so we won't miss it (it could stay in depot forever) */
+ int d = TicksToLeaveDepot(dep);
+
+ if (d <= 0) {
+ leave->vehstatus &= ~VS_HIDDEN; // move it out of the depot
+ leave->u.rail.track = AxisToTrackBits(DiagDirToAxis(GetRailDepotDirection(leave->tile)));
+ for (int i = 0; i >= d; i--) TrainController(leave, NULL, false); // maybe move it, and maybe let another wagon leave
+ }
+ } else {
+ dep = NULL; // no vehicle in a depot, so no vehicle leaving a depot
+ }
+
+ Vehicle *base = v;
+ Vehicle *first = base; // first vehicle to move
+ Vehicle *last = GetLastVehicleInChain(v); // last vehicle to move
+ uint length = CountVehiclesInChain(v);
+
+ /* we have to make sure all wagons that leave a depot because of train reversing are moved coorectly
+ * they have already correct spacing, so we have to make sure they are moved how they should */
+ bool nomove = (dep == NULL); // if there is no vehicle leaving a depot, limit the number of wagons moved immediatelly
+
+ while (length > 2) {
+ /* we reached vehicle (originally) in front of a depot, stop now
+ * (we would move wagons that are alredy moved with new wagon length) */
+ if (base == dep) break;
+
+ /* the last wagon was that one leaving a depot, so do not move it anymore */
+ if (last == dep) nomove = true;
+
+ last = last->Previous();
first = first->Next();
+
+ int differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length;
+
+ /* do not update images now */
+ for (int i = 0; i < differential; i++) TrainController(first, (nomove ? last->Next() : NULL), false);
+
+ base = first; // == base->Next()
length -= 2;
}
}
@@ -1759,7 +1814,7 @@ static void ReverseTrainDirection(Vehicle *v)
int r = 0; ///< number of vehicles - 1
for (const Vehicle *u = v; (u = u->Next()) != NULL;) { r++; }
- AdvanceWagons(v, true);
+ AdvanceWagonsBeforeSwap(v);
/* swap start<>end, start+1<>end-1, ... */
int l = 0;
@@ -1767,7 +1822,7 @@ static void ReverseTrainDirection(Vehicle *v)
ReverseTrainSwapVeh(v, l++, r--);
} while (l <= r);
- AdvanceWagons(v, false);
+ AdvanceWagonsAfterSwap(v);
if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) {
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);