mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-09 19:10:38 +00:00
This commit is contained in:
parent
89520f5665
commit
8a4a99b7e8
@ -25,6 +25,7 @@ constexpr TWaterRegionPatchLabel FIRST_REGION_LABEL = 1;
|
|||||||
constexpr TWaterRegionPatchLabel INVALID_WATER_REGION_PATCH = 0;
|
constexpr TWaterRegionPatchLabel INVALID_WATER_REGION_PATCH = 0;
|
||||||
|
|
||||||
static_assert(sizeof(TWaterRegionTraversabilityBits) * 8 == WATER_REGION_EDGE_LENGTH);
|
static_assert(sizeof(TWaterRegionTraversabilityBits) * 8 == WATER_REGION_EDGE_LENGTH);
|
||||||
|
static_assert(sizeof(TWaterRegionPatchLabel) == sizeof(byte)); // Important for the hash calculation.
|
||||||
|
|
||||||
static inline TrackBits GetWaterTracks(TileIndex tile) { return TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0)); }
|
static inline TrackBits GetWaterTracks(TileIndex tile) { return TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0)); }
|
||||||
static inline bool IsAqueductTile(TileIndex tile) { return IsBridgeTile(tile) && GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER; }
|
static inline bool IsAqueductTile(TileIndex tile) { return IsBridgeTile(tile) && GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER; }
|
||||||
@ -225,14 +226,23 @@ WaterRegion &GetUpdatedWaterRegion(TileIndex tile)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the index of the water region
|
* Returns the index of the water region.
|
||||||
* @param water_region The Water region to return the index for
|
* @param water_region The water region to return the index for.
|
||||||
*/
|
*/
|
||||||
TWaterRegionIndex GetWaterRegionIndex(const WaterRegionDesc &water_region)
|
TWaterRegionIndex GetWaterRegionIndex(const WaterRegionDesc &water_region)
|
||||||
{
|
{
|
||||||
return GetWaterRegionIndex(water_region.x, water_region.y);
|
return GetWaterRegionIndex(water_region.x, water_region.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates a number that uniquely identifies the provided water region patch.
|
||||||
|
* @param water_region_patch The Water region to calculate the hash for.
|
||||||
|
*/
|
||||||
|
int CalculateWaterRegionPatchHash(const WaterRegionPatchDesc &water_region_patch)
|
||||||
|
{
|
||||||
|
return water_region_patch.label | GetWaterRegionIndex(water_region_patch) << 8;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the center tile of a particular water region.
|
* Returns the center tile of a particular water region.
|
||||||
* @param water_region The water region to find the center tile for.
|
* @param water_region The water region to find the center tile for.
|
||||||
|
@ -50,6 +50,8 @@ struct WaterRegionDesc
|
|||||||
|
|
||||||
TWaterRegionIndex GetWaterRegionIndex(const WaterRegionDesc &water_region);
|
TWaterRegionIndex GetWaterRegionIndex(const WaterRegionDesc &water_region);
|
||||||
|
|
||||||
|
int CalculateWaterRegionPatchHash(const WaterRegionPatchDesc &water_region_patch);
|
||||||
|
|
||||||
TileIndex GetWaterRegionCenterTile(const WaterRegionDesc &water_region);
|
TileIndex GetWaterRegionCenterTile(const WaterRegionDesc &water_region);
|
||||||
|
|
||||||
WaterRegionDesc GetWaterRegionInfo(TileIndex tile);
|
WaterRegionDesc GetWaterRegionInfo(TileIndex tile);
|
||||||
|
@ -24,14 +24,12 @@ constexpr int MAX_NUMBER_OF_NODES = 65536;
|
|||||||
struct CYapfRegionPatchNodeKey {
|
struct CYapfRegionPatchNodeKey {
|
||||||
WaterRegionPatchDesc m_water_region_patch;
|
WaterRegionPatchDesc m_water_region_patch;
|
||||||
|
|
||||||
static_assert(sizeof(TWaterRegionPatchLabel) == sizeof(byte)); // Important for the hash calculation.
|
|
||||||
|
|
||||||
inline void Set(const WaterRegionPatchDesc &water_region_patch)
|
inline void Set(const WaterRegionPatchDesc &water_region_patch)
|
||||||
{
|
{
|
||||||
m_water_region_patch = water_region_patch;
|
m_water_region_patch = water_region_patch;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int CalcHash() const { return m_water_region_patch.label | GetWaterRegionIndex(m_water_region_patch) << 8; }
|
inline int CalcHash() const { return CalculateWaterRegionPatchHash(m_water_region_patch); }
|
||||||
inline bool operator==(const CYapfRegionPatchNodeKey &other) const { return CalcHash() == other.CalcHash(); }
|
inline bool operator==(const CYapfRegionPatchNodeKey &other) const { return CalcHash() == other.CalcHash(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "station_base.h"
|
#include "station_base.h"
|
||||||
#include "newgrf_engine.h"
|
#include "newgrf_engine.h"
|
||||||
#include "pathfinder/yapf/yapf.h"
|
#include "pathfinder/yapf/yapf.h"
|
||||||
|
#include "pathfinder/yapf/yapf_ship_regions.h"
|
||||||
#include "newgrf_sound.h"
|
#include "newgrf_sound.h"
|
||||||
#include "spritecache.h"
|
#include "spritecache.h"
|
||||||
#include "strings_func.h"
|
#include "strings_func.h"
|
||||||
@ -39,8 +40,13 @@
|
|||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include "safeguards.h"
|
#include "safeguards.h"
|
||||||
|
|
||||||
|
/** Max distance in tiles (as the crow flies) to search for depots when user clicks "go to depot". */
|
||||||
|
constexpr int MAX_SHIP_DEPOT_SEARCH_DISTANCE = 80;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine the effective #WaterClass for a ship travelling on a tile.
|
* Determine the effective #WaterClass for a ship travelling on a tile.
|
||||||
* @param tile Tile of interest
|
* @param tile Tile of interest
|
||||||
@ -145,21 +151,49 @@ void Ship::GetImage(Direction direction, EngineImageType image_type, VehicleSpri
|
|||||||
|
|
||||||
static const Depot *FindClosestShipDepot(const Vehicle *v, uint max_distance)
|
static const Depot *FindClosestShipDepot(const Vehicle *v, uint max_distance)
|
||||||
{
|
{
|
||||||
/* Find the closest depot */
|
const int max_region_distance = (max_distance / WATER_REGION_EDGE_LENGTH) + 1;
|
||||||
const Depot *best_depot = nullptr;
|
|
||||||
/* If we don't have a maximum distance, i.e. distance = 0,
|
|
||||||
* we want to find any depot so the best distance of no
|
|
||||||
* depot must be more than any correct distance. On the
|
|
||||||
* other hand if we have set a maximum distance, any depot
|
|
||||||
* further away than max_distance can safely be ignored. */
|
|
||||||
uint best_dist = max_distance == 0 ? UINT_MAX : max_distance + 1;
|
|
||||||
|
|
||||||
|
static std::unordered_set<int> visited_patch_hashes;
|
||||||
|
static std::deque<WaterRegionPatchDesc> patches_to_search;
|
||||||
|
visited_patch_hashes.clear();
|
||||||
|
patches_to_search.clear();
|
||||||
|
|
||||||
|
/* Step 1: find a set of reachable Water Region Patches using BFS. */
|
||||||
|
const WaterRegionPatchDesc start_patch = GetWaterRegionPatchInfo(v->tile);
|
||||||
|
patches_to_search.push_back(start_patch);
|
||||||
|
visited_patch_hashes.insert(CalculateWaterRegionPatchHash(start_patch));
|
||||||
|
|
||||||
|
while (!patches_to_search.empty()) {
|
||||||
|
/* Remove first patch from the queue and make it the current patch. */
|
||||||
|
const WaterRegionPatchDesc current_node = patches_to_search.front();
|
||||||
|
patches_to_search.pop_front();
|
||||||
|
|
||||||
|
/* Add neighbors of the current patch to the search queue. */
|
||||||
|
TVisitWaterRegionPatchCallBack visitFunc = [&](const WaterRegionPatchDesc &water_region_patch) {
|
||||||
|
/* Note that we check the max distance per axis, not the total distance. */
|
||||||
|
if (std::abs(water_region_patch.x - start_patch.x) > max_region_distance ||
|
||||||
|
std::abs(water_region_patch.y - start_patch.y) > max_region_distance) return;
|
||||||
|
|
||||||
|
const int hash = CalculateWaterRegionPatchHash(water_region_patch);
|
||||||
|
if (visited_patch_hashes.count(hash) == 0) {
|
||||||
|
visited_patch_hashes.insert(hash);
|
||||||
|
patches_to_search.push_back(water_region_patch);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
VisitWaterRegionPatchNeighbors(current_node, visitFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 2: Find the closest depot within the reachable Water Region Patches. */
|
||||||
|
const Depot *best_depot = nullptr;
|
||||||
|
uint best_dist_sq = std::numeric_limits<uint>::max();
|
||||||
for (const Depot *depot : Depot::Iterate()) {
|
for (const Depot *depot : Depot::Iterate()) {
|
||||||
TileIndex tile = depot->xy;
|
const TileIndex tile = depot->xy;
|
||||||
if (IsShipDepotTile(tile) && IsTileOwner(tile, v->owner)) {
|
if (IsShipDepotTile(tile) && IsTileOwner(tile, v->owner)) {
|
||||||
uint dist = DistanceManhattan(tile, v->tile);
|
const uint dist_sq = DistanceSquare(tile, v->tile);
|
||||||
if (dist < best_dist) {
|
if (dist_sq < best_dist_sq && dist_sq <= max_distance * max_distance &&
|
||||||
best_dist = dist;
|
visited_patch_hashes.count(CalculateWaterRegionPatchHash(GetWaterRegionPatchInfo(tile))) > 0) {
|
||||||
|
best_dist_sq = dist_sq;
|
||||||
best_depot = depot;
|
best_depot = depot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -934,7 +968,7 @@ CommandCost CmdBuildShip(DoCommandFlag flags, TileIndex tile, const Engine *e, V
|
|||||||
|
|
||||||
ClosestDepot Ship::FindClosestDepot()
|
ClosestDepot Ship::FindClosestDepot()
|
||||||
{
|
{
|
||||||
const Depot *depot = FindClosestShipDepot(this, 0);
|
const Depot *depot = FindClosestShipDepot(this, MAX_SHIP_DEPOT_SEARCH_DISTANCE);
|
||||||
if (depot == nullptr) return ClosestDepot();
|
if (depot == nullptr) return ClosestDepot();
|
||||||
|
|
||||||
return ClosestDepot(depot->xy, depot->index);
|
return ClosestDepot(depot->xy, depot->index);
|
||||||
|
Loading…
Reference in New Issue
Block a user