diff options
author | rubidium <rubidium@openttd.org> | 2008-08-02 22:52:22 +0000 |
---|---|---|
committer | rubidium <rubidium@openttd.org> | 2008-08-02 22:52:22 +0000 |
commit | cd041b6944a392dedeef5fa8caa07c340200d9d7 (patch) | |
tree | 148f80b018662589c906dbe6416b5bf662508cd3 /src | |
parent | 773f19da0505d59f31ca7f22afe206ac89deb7af (diff) | |
download | openttd-cd041b6944a392dedeef5fa8caa07c340200d9d7.tar.xz |
(svn r13946) -Add [YAPP]: Implement track reserving for NPF as well. (michi_cc)
Diffstat (limited to 'src')
-rw-r--r-- | src/npf.cpp | 87 | ||||
-rw-r--r-- | src/npf.h | 6 |
2 files changed, 87 insertions, 6 deletions
diff --git a/src/npf.cpp b/src/npf.cpp index 478b62b61..b8cb499a8 100644 --- a/src/npf.cpp +++ b/src/npf.cpp @@ -441,9 +441,48 @@ static int32 NPFFindStationOrTile(AyStar* as, OpenListNode *current) } } -/* To be called when current contains the (shortest route to) the target node. +/** + * Find the node containing the first signal on the path. + * + * If the first signal is on the very first two tiles of the path, + * the second signal is returnd. If no suitable signal is present, the + * last node of the path is returned. + */ +static const PathNode* FindSafePosition(PathNode *path, const Vehicle *v) +{ + /* If there is no signal, reserve the whole path. */ + PathNode *sig = path; + + for(; path->parent != NULL; path = path->parent) { + if (IsSafeWaitingPosition(v, path->node.tile, (Trackdir)path->node.direction, true, _settings_game.pf.forbid_90_deg)) { + sig = path; + } + } + + return sig; +} + +/** + * Lift the reservation of the tiles from @p start till @p end, excluding @p end itself. + */ +static void ClearPathReservation(const PathNode *start, const PathNode *end) +{ + bool first_run = true; + for (; start != end; start = start->parent) { + if (IsRailwayStationTile(start->node.tile) && first_run) { + SetRailwayStationPlatformReservation(start->node.tile, TrackdirToExitdir((Trackdir)start->node.direction), false); + } else { + UnreserveRailTrack(start->node.tile, TrackdirToTrack((Trackdir)start->node.direction)); + } + first_run = false; + } +} + +/** + * To be called when @p current contains the (shortest route to) the target node. * Will fill the contents of the NPFFoundTargetData using - * AyStarNode[NPF_TRACKDIR_CHOICE]. + * AyStarNode[NPF_TRACKDIR_CHOICE]. If requested, path reservation + * is done here. */ static void NPFSaveTargetData(AyStar* as, OpenListNode* current) { @@ -452,6 +491,40 @@ static void NPFSaveTargetData(AyStar* as, OpenListNode* current) ftd->best_path_dist = current->g; ftd->best_bird_dist = 0; ftd->node = current->path.node; + ftd->res_okay = false; + + if (as->user_target != NULL && ((NPFFindStationOrTileData*)as->user_target)->reserve_path && as->user_data[NPF_TYPE] == TRANSPORT_RAIL) { + /* Path reservation is requested. */ + const Vehicle *v = ((NPFFindStationOrTileData*)as->user_target)->v; + + const PathNode *target = FindSafePosition(¤t->path, v); + ftd->node = target->node; + + /* If the target is a station skip to platform end. */ + if (IsRailwayStationTile(target->node.tile)) { + DiagDirection dir = TrackdirToExitdir((Trackdir)target->node.direction); + uint len = GetStationByTile(target->node.tile)->GetPlatformLength(target->node.tile, dir); + TileIndex end_tile = TILE_ADD(target->node.tile, (len - 1) * TileOffsByDiagDir(dir)); + + /* Update only end tile, trackdir of a station stays the same. */ + ftd->node.tile = end_tile; + if (!IsWaitingPositionFree(v, end_tile, (Trackdir)target->node.direction, _settings_game.pf.forbid_90_deg)) return; + SetRailwayStationPlatformReservation(target->node.tile, dir, true); + SetRailwayStationReservation(target->node.tile, false); + } else { + if (!IsWaitingPositionFree(v, target->node.tile, (Trackdir)target->node.direction, _settings_game.pf.forbid_90_deg)) return; + } + + for (const PathNode *cur = target; cur->parent != NULL; cur = cur->parent) { + if (!TryReserveRailTrack(cur->node.tile, TrackdirToTrack((Trackdir)cur->node.direction))) { + /* Reservation failed, undo. */ + ClearPathReservation(target, cur); + return; + } + } + + ftd->res_okay = true; + } } /** @@ -782,7 +855,9 @@ static NPFFoundTargetData NPFRouteInternal(AyStarNode* start1, bool ignore_start /* Initialize result */ result.best_bird_dist = (uint)-1; result.best_path_dist = (uint)-1; - result.best_trackdir = INVALID_TRACKDIR; + result.best_trackdir = INVALID_TRACKDIR; + result.node.tile = INVALID_TILE; + result.res_okay = false; _npf_aystar.user_path = &result; /* Initialize target */ @@ -868,7 +943,7 @@ NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, */ Queue depots; int r; - NPFFoundTargetData best_result = {(uint)-1, (uint)-1, INVALID_TRACKDIR, {INVALID_TILE, 0, {0, 0}}}; + NPFFoundTargetData best_result = {(uint)-1, (uint)-1, INVALID_TRACKDIR, {INVALID_TILE, 0, {0, 0}}, false}; NPFFoundTargetData result; NPFFindStationOrTileData target; AyStarNode start; @@ -973,7 +1048,7 @@ void InitializeNPF() _npf_aystar.max_search_nodes = _settings_game.pf.npf.npf_max_search_nodes; } -void NPFFillWithOrderData(NPFFindStationOrTileData* fstd, Vehicle* v) +void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, Vehicle *v, bool reserve_path) { /* Ships don't really reach their stations, but the tile in front. So don't * save the station id for ships. For roadvehs we don't store it either, @@ -989,4 +1064,6 @@ void NPFFillWithOrderData(NPFFindStationOrTileData* fstd, Vehicle* v) fstd->dest_coords = v->dest_tile; fstd->station_index = INVALID_STATION; } + fstd->reserve_path = reserve_path; + fstd->v = v; } @@ -45,6 +45,8 @@ enum { struct NPFFindStationOrTileData { TileIndex dest_coords; ///< An indication of where the station is, for heuristic purposes, or the target tile StationID station_index; ///< station index we're heading for, or INVALID_STATION when we're heading for a tile + bool reserve_path; ///< Indicates whether the found path should be reserved + const Vehicle* v; ///< The vehicle we are pathfinding for }; /* Indices into AyStar.userdata[] */ @@ -67,6 +69,7 @@ enum NPFNodeFlag { NPF_FLAG_REVERSE, ///< Used to mark that this node was reached from the second start node, if applicable 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 }; /* Meant to be stored in AyStar.userpath */ @@ -75,6 +78,7 @@ struct NPFFoundTargetData { uint best_path_dist; ///< The shortest path. Is (uint)-1 if no path is found Trackdir best_trackdir; ///< The trackdir that leads to the shortest path/closest birds dist AyStarNode node; ///< The node within the target the search led us to + bool res_okay; ///< True if a path reservation could be made }; /* These functions below are _not_ re-entrant, in favor of speed! */ @@ -105,7 +109,7 @@ NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir t * 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); -void NPFFillWithOrderData(NPFFindStationOrTileData* fstd, Vehicle* v); +void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, Vehicle *v, bool reserve_path = false); /* |