diff --git a/src/npf.cpp b/src/npf.cpp --- a/src/npf.cpp +++ b/src/npf.cpp @@ -456,6 +456,17 @@ static int32 NPFFindDepot(AyStar* as, Op AYSTAR_FOUND_END_NODE : AYSTAR_DONE; } +/** Find any safe and free tile. */ +static int32 NPFFindSafeTile(AyStar *as, OpenListNode *current) +{ + const Vehicle *v = ((NPFFindStationOrTileData*)as->user_target)->v; + + return + IsSafeWaitingPosition(v, current->path.node.tile, (Trackdir)current->path.node.direction, true, _settings_game.pf.forbid_90_deg) && + IsWaitingPositionFree(v, current->path.node.tile, (Trackdir)current->path.node.direction, _settings_game.pf.forbid_90_deg) ? + AYSTAR_FOUND_END_NODE : AYSTAR_DONE; +} + /* Will find a station identified using the NPFFindStationOrTileData */ static int32 NPFFindStationOrTile(AyStar* as, OpenListNode *current) { @@ -820,6 +831,18 @@ static void NPFFollowTrack(AyStar* aysta } } + if (NPFGetFlag(¤t->path.node, NPF_FLAG_IGNORE_RESERVED)) { + /* Mask out any reserved tracks. */ + TrackBits reserved = GetReservedTrackbits(dst_tile); + trackdirbits &= ~TrackBitsToTrackdirBits(reserved); + + uint bits = TrackdirBitsToTrackBits(trackdirbits); + int i; + FOR_EACH_SET_BIT(i, bits) { + if (TracksOverlap(reserved | TrackToTrackBits((Track)i))) trackdirbits &= ~TrackToTrackdirBits((Track)i); + } + } + /* Enumerate possible track */ uint i = 0; while (trackdirbits != 0) { @@ -1065,6 +1088,30 @@ NPFFoundTargetData NPFRouteToDepotTrialE return best_result; } +NPFFoundTargetData NPFRouteToSafeTile(const Vehicle *v, TileIndex tile, Trackdir trackdir, bool override_railtype) +{ + assert(v->type == VEH_TRAIN); + + NPFFindStationOrTileData fstd; + fstd.v = v; + fstd.reserve_path = true; + + AyStarNode start1; + start1.tile = tile; + /* We set this in case the target is also the start tile, we will just + * return a not found then */ + start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; + start1.direction = trackdir; + NPFSetFlag(&start1, NPF_FLAG_IGNORE_RESERVED, true); + + RailTypes railtypes = v->u.rail.compatible_railtypes; + if (override_railtype) railtypes |= GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes; + + /* perform a breadth first search. Target is NULL, + * since we are just looking for any safe tile...*/ + return NPFRouteInternal(&start1, true, NULL, false, &fstd, NPFFindSafeTile, NPFCalcZero, TRANSPORT_RAIL, 0, v->owner, railtypes, 0); +} + void InitializeNPF() { static bool first_init = true; diff --git a/src/npf.h b/src/npf.h --- a/src/npf.h +++ b/src/npf.h @@ -72,6 +72,7 @@ enum NPFNodeFlag { NPF_FLAG_LAST_SIGNAL_RED, ///< Used to mark that the last signal on this path was red NPF_FLAG_IGNORE_START_TILE, ///< Used to mark that the start tile is invalid, and searching should start from the second tile on NPF_FLAG_TARGET_RESERVED, ///< Used to mark that the possible reservation target is already reserved + NPF_FLAG_IGNORE_RESERVED, ///< Used to mark that reserved tiles should be considered impassable }; /* Meant to be stored in AyStar.userpath */ @@ -111,6 +112,12 @@ NPFFoundTargetData NPFRouteToDepotBreadt * of choices and accurate heuristics, such as water. */ NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, bool ignore_start_tile, TransportType type, uint sub_type, Owner owner, RailTypes railtypes); +/** + * Search for any safe tile using a breadth first search and try to reserve a path. + */ +NPFFoundTargetData NPFRouteToSafeTile(const Vehicle *v, TileIndex tile, Trackdir trackdir,bool override_railtype); + + void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, Vehicle *v, bool reserve_path = false);