summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/train_cmd.cpp87
1 files changed, 87 insertions, 0 deletions
diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp
index 6f52554ee..7a017f472 100644
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -2646,6 +2646,50 @@ static bool TryReserveSafeTrack(const Vehicle* v, TileIndex tile, Trackdir td, b
}
}
+/**
+ * Query the next order after a certain order index.
+ *
+ * @param v The vehicle
+ * @param order_index [in/out] Index of the current order, returns index of the chosen order
+ * @return Pointer to the order or NULL if the order chain was completely followed
+ * without finding a suitable order.
+ */
+static const Order* GetNextTrainOrder(const Vehicle *v, VehicleOrderID *order_index)
+{
+ ++(*order_index);
+
+ do {
+ /* Wrap around. */
+ if (*order_index >= v->num_orders) *order_index = 0;
+
+ Order *order = GetVehicleOrder(v, *order_index);
+ assert(order != NULL);
+
+ switch (order->GetType()) {
+ case OT_GOTO_DEPOT:
+ /* Skip service in depot orders when the train doesn't need service. */
+ if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) break;
+ case OT_GOTO_STATION:
+ case OT_GOTO_WAYPOINT:
+ return order;
+ case OT_CONDITIONAL: {
+ VehicleOrderID next = ProcessConditionalOrder(order, v);
+ if (next != INVALID_VEH_ORDER_ID) {
+ *order_index = next;
+ continue;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ ++(*order_index);
+ } while (*order_index != v->cur_order_index);
+
+ return NULL;
+}
+
/* choose a track */
static Track ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck)
{
@@ -2739,6 +2783,49 @@ static Track ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir
if (got_reservation != NULL) *got_reservation = true;
+ /* Reservation target found and free, check if it is safe. */
+ Order cur_order = v->current_order;
+ TileIndex cur_dest_tile = v->dest_tile;
+ VehicleOrderID order_index = v->cur_order_index;
+ while (!IsSafeWaitingPosition(v, res_dest.tile, res_dest.trackdir, true, _settings_game.pf.forbid_90_deg)) {
+ /* Extend reservation until we have found a safe position. */
+ DiagDirection exitdir = TrackdirToExitdir(res_dest.trackdir);
+ TileIndex next_tile = TileAddByDiagDir(res_dest.tile, exitdir);
+ TrackBits reachable = TrackdirBitsToTrackBits((TrackdirBits)(GetTileTrackStatus(next_tile, TRANSPORT_RAIL, 0))) & DiagdirReachesTracks(exitdir);
+ if (_settings_game.pf.pathfinder_for_trains != VPF_NTP && _settings_game.pf.forbid_90_deg) {
+ reachable &= ~TrackCrossesTracks(TrackdirToTrack(res_dest.trackdir));
+ }
+
+ /* Get next order with destination. */
+ const Order *order = GetNextTrainOrder(v, &order_index);
+ if (order != NULL) {
+ v->current_order = *order;
+ UpdateOrderDest(v, order);
+ PBSTileInfo cur_dest;
+ DoTrainPathfind(v, next_tile, exitdir, reachable, NULL, true, &cur_dest);
+ if (cur_dest.tile != INVALID_TILE) {
+ res_dest = cur_dest;
+ if (res_dest.okay) continue;
+ /* Path found, but could not be reserved. */
+ FreeTrainTrackReservation(v);
+ if (mark_stuck) MarkTrainAsStuck(v);
+ if (got_reservation != NULL) *got_reservation = false;
+ changed_signal = false;
+ break;
+ }
+ }
+ /* No order or no safe position found, try any position. */
+ if (!TryReserveSafeTrack(v, res_dest.tile, res_dest.trackdir, true)) {
+ FreeTrainTrackReservation(v);
+ if (mark_stuck) MarkTrainAsStuck(v);
+ if (got_reservation != NULL) *got_reservation = false;
+ changed_signal = false;
+ }
+ break;
+ }
+ v->current_order = cur_order;
+ v->dest_tile = cur_dest_tile;
+
TryReserveRailTrack(v->tile, TrackdirToTrack(GetVehicleTrackdir(v)));
if (changed_signal) MarkTileDirtyByTile(tile);