mirror of https://github.com/OpenTTD/OpenTTD
Merge d4d3c7def9
into 8f3bfb61bd
commit
144c7c5f8d
|
@ -20,11 +20,10 @@
|
||||||
/**
|
/**
|
||||||
* Finds the best path for given ship using YAPF.
|
* Finds the best path for given ship using YAPF.
|
||||||
* @param v the ship that needs to find a path
|
* @param v the ship that needs to find a path
|
||||||
* @param tile the tile to find the path from (should be next tile the ship is about to enter)
|
|
||||||
* @param path_found [out] Whether a path has been found (true) or has been guessed (false)
|
* @param path_found [out] Whether a path has been found (true) or has been guessed (false)
|
||||||
* @return the best trackdir for next turn or INVALID_TRACK if the path could not be found
|
* @return the best trackdir for next turn. This includes potential reverse directions.
|
||||||
*/
|
*/
|
||||||
Track YapfShipChooseTrack(const Ship *v, TileIndex tile, bool &path_found, ShipPathCache &path_cache);
|
Trackdir YapfShipChooseTrack(const Ship *v, bool &path_found, ShipPathCache &path_cache);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if it is better to reverse the ship before leaving depot using YAPF.
|
* Returns true if it is better to reverse the ship before leaving depot using YAPF.
|
||||||
|
@ -32,7 +31,7 @@ Track YapfShipChooseTrack(const Ship *v, TileIndex tile, bool &path_found, ShipP
|
||||||
* @param trackdir [out] the best of all possible reversed trackdirs
|
* @param trackdir [out] the best of all possible reversed trackdirs
|
||||||
* @return true if reversing is better
|
* @return true if reversing is better
|
||||||
*/
|
*/
|
||||||
bool YapfShipCheckReverse(const Ship *v, Trackdir *trackdir);
|
bool YapfShipCheckReverse(const Ship *v, Trackdir &trackdir);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the best path for given road vehicle using YAPF.
|
* Finds the best path for given road vehicle using YAPF.
|
||||||
|
|
|
@ -25,7 +25,9 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TileIndex origin_tile; ///< origin tile
|
TileIndex origin_tile; ///< origin tile
|
||||||
TrackdirBits origin_trackdirs; ///< origin trackdir mask
|
TrackdirBits origin_forward_trackdirs; ///< trackdirs considered for forward motion
|
||||||
|
TrackdirBits origin_reverse_trackdirs; ///< trackdirs considered for reversal
|
||||||
|
int reverse_penalty; ///< Cost penalty added for the reverse directions
|
||||||
|
|
||||||
/** to access inherited path finder */
|
/** to access inherited path finder */
|
||||||
inline Tpf &Yapf()
|
inline Tpf &Yapf()
|
||||||
|
@ -35,21 +37,29 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Set origin tile / trackdir mask */
|
/** Set origin tile / trackdir mask */
|
||||||
void SetOrigin(TileIndex tile, TrackdirBits trackdirs)
|
void SetOrigin(TileIndex tile, TrackdirBits forward_trackdirs, TrackdirBits reverse_trackdirs = TRACKDIR_BIT_NONE, int reverse_penalty = 0)
|
||||||
{
|
{
|
||||||
|
assert((forward_trackdirs & reverse_trackdirs) == TRACKDIR_BIT_NONE); // Forward dirs can't also be reverse dirs and vice versa
|
||||||
this->origin_tile = tile;
|
this->origin_tile = tile;
|
||||||
this->origin_trackdirs = trackdirs;
|
this->origin_forward_trackdirs = forward_trackdirs;
|
||||||
|
this->origin_reverse_trackdirs = reverse_trackdirs;
|
||||||
|
this->reverse_penalty = reverse_penalty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when YAPF needs to place origin nodes into open list */
|
/** Called when YAPF needs to place origin nodes into open list */
|
||||||
void PfSetStartupNodes()
|
void PfSetStartupNodes()
|
||||||
{
|
{
|
||||||
bool is_choice = (KillFirstBit(this->origin_trackdirs) != TRACKDIR_BIT_NONE);
|
const bool is_choice = CountBits(this->origin_forward_trackdirs | this->origin_reverse_trackdirs) > 1;
|
||||||
for (TrackdirBits tdb = this->origin_trackdirs; tdb != TRACKDIR_BIT_NONE; tdb = KillFirstBit(tdb)) {
|
for (Trackdir td : SetTrackdirBitIterator(this->origin_forward_trackdirs)) {
|
||||||
Trackdir td = (Trackdir)FindFirstBit(tdb);
|
Node &node = Yapf().CreateNewNode();
|
||||||
Node &n1 = Yapf().CreateNewNode();
|
node.Set(nullptr, this->origin_tile, td, is_choice);
|
||||||
n1.Set(nullptr, this->origin_tile, td, is_choice);
|
Yapf().AddStartupNode(node);
|
||||||
Yapf().AddStartupNode(n1);
|
}
|
||||||
|
for (Trackdir td : SetTrackdirBitIterator(this->origin_reverse_trackdirs)) {
|
||||||
|
Node &node = Yapf().CreateNewNode();
|
||||||
|
node.Set(nullptr, this->origin_tile, td, is_choice);
|
||||||
|
node.cost = reverse_penalty;
|
||||||
|
Yapf().AddStartupNode(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
constexpr int NUMBER_OR_WATER_REGIONS_LOOKAHEAD = 4;
|
constexpr int NUMBER_OR_WATER_REGIONS_LOOKAHEAD = 4;
|
||||||
constexpr int MAX_SHIP_PF_NODES = (NUMBER_OR_WATER_REGIONS_LOOKAHEAD + 1) * WATER_REGION_NUMBER_OF_TILES * 4; // 4 possible exit dirs per tile.
|
constexpr int MAX_SHIP_PF_NODES = (NUMBER_OR_WATER_REGIONS_LOOKAHEAD + 1) * WATER_REGION_NUMBER_OF_TILES * 4; // 4 possible exit dirs per tile.
|
||||||
|
constexpr int SHIP_REVERSE_PENALTY = 10 * YAPF_TILE_LENGTH;
|
||||||
constexpr int SHIP_LOST_PATH_LENGTH = 8; // The length of the (aimless) path assigned when a ship is lost.
|
constexpr int SHIP_LOST_PATH_LENGTH = 8; // The length of the (aimless) path assigned when a ship is lost.
|
||||||
|
|
||||||
template <class Types>
|
template <class Types>
|
||||||
|
@ -178,7 +178,7 @@ public:
|
||||||
return FindFirstTrackdir(trackdirs);
|
return FindFirstTrackdir(trackdirs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a random tile/trackdir that can be reached from the current tile/trackdir, or tile/INVALID_TRACK if none is available. */
|
/** Returns a random tile/trackdir that can be reached from the current tile/trackdir, or tile/INVALID_TRACKDIR if none is available. */
|
||||||
static std::pair<TileIndex, Trackdir> GetRandomFollowUpTileTrackdir(const Ship *v, TileIndex tile, Trackdir dir)
|
static std::pair<TileIndex, Trackdir> GetRandomFollowUpTileTrackdir(const Ship *v, TileIndex tile, Trackdir dir)
|
||||||
{
|
{
|
||||||
TrackFollower follower(v);
|
TrackFollower follower(v);
|
||||||
|
@ -198,10 +198,10 @@ public:
|
||||||
for (int i = 0; i < path_length; ++i) {
|
for (int i = 0; i < path_length; ++i) {
|
||||||
tile_dir = GetRandomFollowUpTileTrackdir(v, tile_dir.first, tile_dir.second);
|
tile_dir = GetRandomFollowUpTileTrackdir(v, tile_dir.first, tile_dir.second);
|
||||||
if (tile_dir.second == INVALID_TRACKDIR) break;
|
if (tile_dir.second == INVALID_TRACKDIR) break;
|
||||||
path_cache.push_back(tile_dir.second);
|
path_cache.emplace_back(tile_dir.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path_cache.empty()) return INVALID_TRACKDIR;
|
if (path_cache.empty()) return ReverseTrackdir(v->GetVehicleTrackdir());
|
||||||
|
|
||||||
/* Reverse the path so we can take from the end. */
|
/* Reverse the path so we can take from the end. */
|
||||||
std::reverse(std::begin(path_cache), std::end(path_cache));
|
std::reverse(std::begin(path_cache), std::end(path_cache));
|
||||||
|
@ -211,10 +211,15 @@ public:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Trackdir ChooseShipTrack(const Ship *v, TileIndex tile, TrackdirBits forward_dirs, TrackdirBits reverse_dirs,
|
static Trackdir ChooseShipTrack(const Ship *v, TrackdirBits forward_dirs, TrackdirBits reverse_dirs,
|
||||||
bool &path_found, ShipPathCache &path_cache, Trackdir &best_origin_dir)
|
bool &path_found, ShipPathCache &path_cache)
|
||||||
{
|
{
|
||||||
const std::vector<WaterRegionPatchDesc> high_level_path = YapfShipFindWaterRegionPath(v, tile, NUMBER_OR_WATER_REGIONS_LOOKAHEAD + 1);
|
assert(HasBit(forward_dirs, v->GetVehicleTrackdir()));
|
||||||
|
assert(HasBit(reverse_dirs, ReverseTrackdir(v->GetVehicleTrackdir())));
|
||||||
|
assert((forward_dirs & reverse_dirs) == TRACKDIR_BIT_NONE);
|
||||||
|
assert((TrackdirReachesTrackdirs(v->GetVehicleTrackdir()) & reverse_dirs) == TRACKDIR_BIT_NONE);
|
||||||
|
|
||||||
|
const std::vector<WaterRegionPatchDesc> high_level_path = YapfShipFindWaterRegionPath(v, v->tile, NUMBER_OR_WATER_REGIONS_LOOKAHEAD + 1);
|
||||||
if (high_level_path.empty()) {
|
if (high_level_path.empty()) {
|
||||||
path_found = false;
|
path_found = false;
|
||||||
/* Make the ship move around aimlessly. This prevents repeated pathfinder calls and clearly indicates that the ship is lost. */
|
/* Make the ship move around aimlessly. This prevents repeated pathfinder calls and clearly indicates that the ship is lost. */
|
||||||
|
@ -228,7 +233,7 @@ public:
|
||||||
Tpf pf(MAX_SHIP_PF_NODES);
|
Tpf pf(MAX_SHIP_PF_NODES);
|
||||||
|
|
||||||
/* Set origin and destination nodes */
|
/* Set origin and destination nodes */
|
||||||
pf.SetOrigin(v->tile, forward_dirs | reverse_dirs);
|
pf.SetOrigin(v->tile, forward_dirs, reverse_dirs, SHIP_REVERSE_PENALTY);
|
||||||
pf.SetDestination(v);
|
pf.SetDestination(v);
|
||||||
const bool is_intermediate_destination = static_cast<int>(high_level_path.size()) >= NUMBER_OR_WATER_REGIONS_LOOKAHEAD + 1;
|
const bool is_intermediate_destination = static_cast<int>(high_level_path.size()) >= NUMBER_OR_WATER_REGIONS_LOOKAHEAD + 1;
|
||||||
if (is_intermediate_destination) pf.SetIntermediateDestination(high_level_path.back());
|
if (is_intermediate_destination) pf.SetIntermediateDestination(high_level_path.back());
|
||||||
|
@ -249,17 +254,16 @@ public:
|
||||||
* to the final destination tile. The low-level pathfinder might actually prefer a different docking tile in a nearby region. Without
|
* to the final destination tile. The low-level pathfinder might actually prefer a different docking tile in a nearby region. Without
|
||||||
* caching the full path the ship can get stuck in a loop. */
|
* caching the full path the ship can get stuck in a loop. */
|
||||||
const WaterRegionPatchDesc end_water_patch = GetWaterRegionPatchInfo(node->GetTile());
|
const WaterRegionPatchDesc end_water_patch = GetWaterRegionPatchInfo(node->GetTile());
|
||||||
assert(GetWaterRegionPatchInfo(tile) == high_level_path.front());
|
assert(GetWaterRegionPatchInfo(v->tile) == high_level_path.front());
|
||||||
const WaterRegionPatchDesc start_water_patch = high_level_path.front();
|
const WaterRegionPatchDesc start_patch = high_level_path.front();
|
||||||
while (node->parent) {
|
while (node->parent) {
|
||||||
const WaterRegionPatchDesc node_water_patch = GetWaterRegionPatchInfo(node->GetTile());
|
const WaterRegionPatchDesc current_patch = GetWaterRegionPatchInfo(node->parent->GetTile());
|
||||||
|
const bool current_patch_on_high_level_path = std::ranges::find(high_level_path, current_patch) != high_level_path.end();
|
||||||
const bool node_water_patch_on_high_level_path = std::ranges::find(high_level_path, node_water_patch) != high_level_path.end();
|
const bool add_full_path = !is_intermediate_destination && current_patch != end_water_patch;
|
||||||
const bool add_full_path = !is_intermediate_destination && node_water_patch != end_water_patch;
|
|
||||||
|
|
||||||
/* The cached path must always lead to a region patch that's on the high level path.
|
/* The cached path must always lead to a region patch that's on the high level path.
|
||||||
* This is what can happen when that's not the case https://github.com/OpenTTD/OpenTTD/issues/12176. */
|
* This is what can happen when that's not the case https://github.com/OpenTTD/OpenTTD/issues/12176. */
|
||||||
if (add_full_path || !node_water_patch_on_high_level_path || node_water_patch == start_water_patch) {
|
if (add_full_path || !current_patch_on_high_level_path || current_patch == start_patch) {
|
||||||
path_cache.push_back(node->GetTrackdir());
|
path_cache.push_back(node->GetTrackdir());
|
||||||
} else {
|
} else {
|
||||||
path_cache.clear();
|
path_cache.clear();
|
||||||
|
@ -268,11 +272,10 @@ public:
|
||||||
}
|
}
|
||||||
assert(node->GetTile() == v->tile);
|
assert(node->GetTile() == v->tile);
|
||||||
|
|
||||||
/* Return INVALID_TRACKDIR to trigger a ship reversal if that is the best option. */
|
/* Return a reverse direction if that is the best option. */
|
||||||
best_origin_dir = node->GetTrackdir();
|
if (HasBit(reverse_dirs, node->GetTrackdir())) {
|
||||||
if ((TrackdirToTrackdirBits(best_origin_dir) & forward_dirs) == TRACKDIR_BIT_NONE) {
|
|
||||||
path_cache.clear();
|
path_cache.clear();
|
||||||
return INVALID_TRACKDIR;
|
return node->GetTrackdir();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A empty path means we are already at the destination. The pathfinder shouldn't have been called at all.
|
/* A empty path means we are already at the destination. The pathfinder shouldn't have been called at all.
|
||||||
|
@ -284,42 +287,12 @@ public:
|
||||||
path_cache.pop_back();
|
path_cache.pop_back();
|
||||||
|
|
||||||
/* Clear path cache when in final water region patch. This is to allow ships to spread over different docking tiles dynamically. */
|
/* Clear path cache when in final water region patch. This is to allow ships to spread over different docking tiles dynamically. */
|
||||||
if (start_water_patch == end_water_patch) path_cache.clear();
|
if (start_patch == end_water_patch) path_cache.clear();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return INVALID_TRACKDIR;
|
NOT_REACHED();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether a ship should reverse to reach its destination.
|
|
||||||
* Called when leaving depot.
|
|
||||||
* @param v Ship.
|
|
||||||
* @param trackdir [out] the best of all possible reversed trackdirs.
|
|
||||||
* @return true if the reverse direction is better.
|
|
||||||
*/
|
|
||||||
static bool CheckShipReverse(const Ship *v, Trackdir *trackdir)
|
|
||||||
{
|
|
||||||
bool path_found = false;
|
|
||||||
ShipPathCache dummy_cache;
|
|
||||||
Trackdir best_origin_dir = INVALID_TRACKDIR;
|
|
||||||
|
|
||||||
if (trackdir == nullptr) {
|
|
||||||
/* The normal case, typically called when ships leave a dock. */
|
|
||||||
const Trackdir reverse_dir = ReverseTrackdir(v->GetVehicleTrackdir());
|
|
||||||
const TrackdirBits forward_dirs = TrackdirToTrackdirBits(v->GetVehicleTrackdir());
|
|
||||||
const TrackdirBits reverse_dirs = TrackdirToTrackdirBits(reverse_dir);
|
|
||||||
(void)ChooseShipTrack(v, v->tile, forward_dirs, reverse_dirs, path_found, dummy_cache, best_origin_dir);
|
|
||||||
return path_found && best_origin_dir == reverse_dir;
|
|
||||||
} else {
|
|
||||||
/* This gets called when a ship suddenly can't move forward, e.g. due to terraforming. */
|
|
||||||
const DiagDirection entry = ReverseDiagDir(VehicleExitDir(v->direction, v->state));
|
|
||||||
const TrackdirBits reverse_dirs = DiagdirReachesTrackdirs(entry) & TrackStatusToTrackdirBits(GetTileTrackStatus(v->tile, TRANSPORT_WATER, 0, entry));
|
|
||||||
(void)ChooseShipTrack(v, v->tile, TRACKDIR_BIT_NONE, reverse_dirs, path_found, dummy_cache, best_origin_dir);
|
|
||||||
*trackdir = path_found && best_origin_dir != INVALID_TRACKDIR ? best_origin_dir : GetRandomTrackdir(reverse_dirs);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -424,16 +397,27 @@ struct CYapfShip : CYapfT<CYapfShip_TypesT<CYapfShip, CFollowTrackWater, CShipNo
|
||||||
explicit CYapfShip(int max_nodes) { this->max_search_nodes = max_nodes; }
|
explicit CYapfShip(int max_nodes) { this->max_search_nodes = max_nodes; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Ship controller helper - path finder invoker. */
|
Trackdir YapfShipChooseTrack(const Ship *v, bool &path_found, ShipPathCache &path_cache)
|
||||||
Track YapfShipChooseTrack(const Ship *v, TileIndex tile, bool &path_found, ShipPathCache &path_cache)
|
|
||||||
{
|
{
|
||||||
Trackdir best_origin_dir = INVALID_TRACKDIR;
|
/* This is always called when a ship is about to exit a tile, hence we add up to three reverse directions. */
|
||||||
const TrackdirBits origin_dirs = TrackdirToTrackdirBits(v->GetVehicleTrackdir());
|
const TrackdirBits forward_dirs = TrackdirToTrackdirBits(v->GetVehicleTrackdir());
|
||||||
const Trackdir td_ret = CYapfShip::ChooseShipTrack(v, tile, origin_dirs, TRACKDIR_BIT_NONE, path_found, path_cache, best_origin_dir);
|
const TrackdirBits all_water_dirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->tile, TRANSPORT_WATER, 0));
|
||||||
return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : INVALID_TRACK;
|
const TrackdirBits reverse_dirs = all_water_dirs & DiagdirReachesTrackdirs(ReverseDiagDir(TrackdirToExitdir(v->GetVehicleTrackdir())));
|
||||||
|
|
||||||
|
const Trackdir trackdir = CYapfShip::ChooseShipTrack(v, forward_dirs, reverse_dirs, path_found, path_cache);
|
||||||
|
assert(trackdir != INVALID_TRACKDIR);
|
||||||
|
return trackdir;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool YapfShipCheckReverse(const Ship *v, Trackdir *trackdir)
|
bool YapfShipCheckReverse(const Ship *v, Trackdir &trackdir)
|
||||||
{
|
{
|
||||||
return CYapfShip::CheckShipReverse(v, trackdir);
|
/* It is not clear where the ship is within its current track, so we only add the forward (current) and reverse direction. */
|
||||||
|
const TrackdirBits forward_dirs = TrackdirToTrackdirBits(v->GetVehicleTrackdir());
|
||||||
|
const TrackdirBits reverse_dirs = TrackdirToTrackdirBits(ReverseTrackdir(v->GetVehicleTrackdir()));
|
||||||
|
|
||||||
|
bool path_found = false;
|
||||||
|
ShipPathCache dummy_cache;
|
||||||
|
trackdir = CYapfShip::ChooseShipTrack(v, forward_dirs, reverse_dirs, path_found, dummy_cache);
|
||||||
|
assert(trackdir != INVALID_TRACKDIR);
|
||||||
|
return path_found && HasBit(reverse_dirs, trackdir);
|
||||||
}
|
}
|
||||||
|
|
|
@ -367,7 +367,7 @@ static Vehicle *EnsureNoMovingShipProc(Vehicle *v, void *)
|
||||||
return v->type == VEH_SHIP && v->cur_speed != 0 ? v : nullptr;
|
return v->type == VEH_SHIP && v->cur_speed != 0 ? v : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CheckReverseShip(const Ship *v, Trackdir *trackdir = nullptr)
|
static bool CheckReverseShip(const Ship *v, Trackdir &trackdir)
|
||||||
{
|
{
|
||||||
/* Ask pathfinder for best direction */
|
/* Ask pathfinder for best direction */
|
||||||
return YapfShipCheckReverse(v, trackdir);
|
return YapfShipCheckReverse(v, trackdir);
|
||||||
|
@ -405,7 +405,8 @@ static bool CheckShipLeaveDepot(Ship *v)
|
||||||
TrackBits north_tracks = DiagdirReachesTracks(north_dir) & GetTileShipTrackStatus(north_neighbour);
|
TrackBits north_tracks = DiagdirReachesTracks(north_dir) & GetTileShipTrackStatus(north_neighbour);
|
||||||
TrackBits south_tracks = DiagdirReachesTracks(south_dir) & GetTileShipTrackStatus(south_neighbour);
|
TrackBits south_tracks = DiagdirReachesTracks(south_dir) & GetTileShipTrackStatus(south_neighbour);
|
||||||
if (north_tracks && south_tracks) {
|
if (north_tracks && south_tracks) {
|
||||||
if (CheckReverseShip(v)) north_tracks = TRACK_BIT_NONE;
|
Trackdir dummy_trackdir;
|
||||||
|
if (CheckReverseShip(v, dummy_trackdir)) north_tracks = TRACK_BIT_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (north_tracks) {
|
if (north_tracks) {
|
||||||
|
@ -487,54 +488,39 @@ static void ShipArrivesAt(const Vehicle *v, Station *st)
|
||||||
* Runs the pathfinder to choose a track to continue along.
|
* Runs the pathfinder to choose a track to continue along.
|
||||||
*
|
*
|
||||||
* @param v Ship to navigate
|
* @param v Ship to navigate
|
||||||
* @param tile Tile, the ship is about to enter
|
* @param trackdirs Available trackdir choices on the vehicle's type
|
||||||
* @param tracks Available track choices on \a tile
|
* @return Trackdir to choose
|
||||||
* @return Track to choose, or INVALID_TRACK when to reverse.
|
|
||||||
*/
|
*/
|
||||||
static Track ChooseShipTrack(Ship *v, TileIndex tile, TrackBits tracks)
|
static Trackdir ChooseShipTrack(Ship *v, TrackdirBits trackdirs)
|
||||||
{
|
{
|
||||||
bool path_found = true;
|
bool path_found = true;
|
||||||
Track track;
|
Trackdir trackdir;
|
||||||
|
|
||||||
if (v->dest_tile == 0) {
|
if (v->dest_tile == 0) {
|
||||||
/* No destination, don't invoke pathfinder. */
|
/* No destination, don't invoke pathfinder. */
|
||||||
track = TrackBitsToTrack(v->state);
|
trackdir = FindFirstTrackdir(trackdirs);
|
||||||
if (!IsDiagonalTrack(track)) track = TrackToOppositeTrack(track);
|
if (trackdir == INVALID_TRACKDIR) trackdir = ReverseTrackdir(v->GetVehicleTrackdir());
|
||||||
if (!HasBit(tracks, track)) track = FindFirstTrack(tracks);
|
|
||||||
path_found = false;
|
path_found = false;
|
||||||
} else {
|
} else {
|
||||||
/* Attempt to follow cached path. */
|
/* Attempt to follow cached path. */
|
||||||
if (!v->path.empty()) {
|
if (!v->path.empty()) {
|
||||||
track = TrackdirToTrack(v->path.back().trackdir);
|
trackdir = v->path.back().trackdir;
|
||||||
|
|
||||||
if (HasBit(tracks, track)) {
|
if (HasBit(trackdirs, trackdir)) {
|
||||||
v->path.pop_back();
|
v->path.pop_back();
|
||||||
/* HandlePathfindResult() is not called here because this is not a new pathfinder result. */
|
/* HandlePathfindResult() is not called here because this is not a new pathfinder result. */
|
||||||
return track;
|
return trackdir;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cached path is invalid so continue with pathfinder. */
|
/* Cached path is invalid so continue with pathfinder. */
|
||||||
v->path.clear();
|
v->path.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
track = YapfShipChooseTrack(v, tile, path_found, v->path);
|
trackdir = YapfShipChooseTrack(v, path_found, v->path);
|
||||||
}
|
}
|
||||||
|
|
||||||
v->HandlePathfindingResult(path_found);
|
v->HandlePathfindingResult(path_found);
|
||||||
return track;
|
return trackdir;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the available water tracks on a tile for a ship entering a tile.
|
|
||||||
* @param tile The tile about to enter.
|
|
||||||
* @param dir The entry direction.
|
|
||||||
* @return The available trackbits on the next tile.
|
|
||||||
*/
|
|
||||||
static inline TrackBits GetAvailShipTracks(TileIndex tile, DiagDirection dir)
|
|
||||||
{
|
|
||||||
TrackBits tracks = GetTileShipTrackStatus(tile) & DiagdirReachesTracks(dir);
|
|
||||||
|
|
||||||
return tracks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Structure for ship sub-coordinate data for moving into a new tile via a Diagdir onto a Track. */
|
/** Structure for ship sub-coordinate data for moving into a new tile via a Diagdir onto a Track. */
|
||||||
|
@ -704,7 +690,8 @@ static void ShipController(Ship *v)
|
||||||
|
|
||||||
if (v->vehstatus.Test(VehState::Stopped)) return;
|
if (v->vehstatus.Test(VehState::Stopped)) return;
|
||||||
|
|
||||||
if (ProcessOrders(v) && CheckReverseShip(v)) return ReverseShip(v);
|
Trackdir best_reverse_dir = INVALID_TRACKDIR;
|
||||||
|
if (ProcessOrders(v) && CheckReverseShip(v, best_reverse_dir)) return ReverseShipIntoTrackdir(v, best_reverse_dir);
|
||||||
|
|
||||||
v->HandleLoading();
|
v->HandleLoading();
|
||||||
|
|
||||||
|
@ -792,19 +779,14 @@ static void ShipController(Ship *v)
|
||||||
|
|
||||||
const DiagDirection diagdir = DiagdirBetweenTiles(gp.old_tile, gp.new_tile);
|
const DiagDirection diagdir = DiagdirBetweenTiles(gp.old_tile, gp.new_tile);
|
||||||
assert(diagdir != INVALID_DIAGDIR);
|
assert(diagdir != INVALID_DIAGDIR);
|
||||||
const TrackBits tracks = GetAvailShipTracks(gp.new_tile, diagdir);
|
const TrackdirBits forward_trackdirs = TrackBitsToTrackdirBits(GetTileShipTrackStatus(gp.new_tile)) & DiagdirReachesTrackdirs(diagdir);
|
||||||
if (tracks == TRACK_BIT_NONE) {
|
|
||||||
Trackdir trackdir = INVALID_TRACKDIR;
|
|
||||||
CheckReverseShip(v, &trackdir);
|
|
||||||
if (trackdir == INVALID_TRACKDIR) return ReverseShip(v);
|
|
||||||
return ReverseShipIntoTrackdir(v, trackdir);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Choose a direction, and continue if we find one */
|
/* Choose a direction, which might require a reversal */
|
||||||
const Track track = ChooseShipTrack(v, gp.new_tile, tracks);
|
const Trackdir new_trackdir = ChooseShipTrack(v, forward_trackdirs);
|
||||||
if (track == INVALID_TRACK) return ReverseShip(v);
|
assert(new_trackdir != INVALID_TRACKDIR);
|
||||||
|
if (!HasBit(forward_trackdirs, new_trackdir)) return ReverseShipIntoTrackdir(v, new_trackdir);
|
||||||
|
|
||||||
const ShipSubcoordData &b = _ship_subcoord[diagdir][track];
|
const ShipSubcoordData &b = _ship_subcoord[diagdir][TrackdirToTrack(new_trackdir)];
|
||||||
|
|
||||||
gp.x = (gp.x & ~0xF) | b.x_subcoord;
|
gp.x = (gp.x & ~0xF) | b.x_subcoord;
|
||||||
gp.y = (gp.y & ~0xF) | b.y_subcoord;
|
gp.y = (gp.y & ~0xF) | b.y_subcoord;
|
||||||
|
@ -815,7 +797,7 @@ static void ShipController(Ship *v)
|
||||||
|
|
||||||
if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
|
if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
|
||||||
v->tile = gp.new_tile;
|
v->tile = gp.new_tile;
|
||||||
v->state = TrackToTrackBits(track);
|
v->state = TrackToTrackBits(TrackdirToTrack(new_trackdir));
|
||||||
|
|
||||||
/* Update ship cache when the water class changes. Aqueducts are always canals. */
|
/* Update ship cache when the water class changes. Aqueducts are always canals. */
|
||||||
if (GetEffectiveWaterClass(gp.old_tile) != GetEffectiveWaterClass(gp.new_tile)) v->UpdateCache();
|
if (GetEffectiveWaterClass(gp.old_tile) != GetEffectiveWaterClass(gp.new_tile)) v->UpdateCache();
|
||||||
|
|
Loading…
Reference in New Issue