| 148 | } |
| 149 | |
| 150 | static const Depot *FindClosestShipDepot(const Vehicle *v, uint max_distance) |
| 151 | { |
| 152 | const int max_region_distance = (max_distance / WATER_REGION_EDGE_LENGTH) + 1; |
| 153 | |
| 154 | static std::unordered_set<int> visited_patch_hashes; |
| 155 | static std::deque<WaterRegionPatchDesc> patches_to_search; |
| 156 | visited_patch_hashes.clear(); |
| 157 | patches_to_search.clear(); |
| 158 | |
| 159 | /* Step 1: find a set of reachable Water Region Patches using BFS. */ |
| 160 | const WaterRegionPatchDesc start_patch = GetWaterRegionPatchInfo(v->tile); |
| 161 | patches_to_search.push_back(start_patch); |
| 162 | visited_patch_hashes.insert(CalculateWaterRegionPatchHash(start_patch)); |
| 163 | |
| 164 | while (!patches_to_search.empty()) { |
| 165 | /* Remove first patch from the queue and make it the current patch. */ |
| 166 | const WaterRegionPatchDesc current_node = patches_to_search.front(); |
| 167 | patches_to_search.pop_front(); |
| 168 | |
| 169 | /* Add neighbours of the current patch to the search queue. */ |
| 170 | VisitWaterRegionPatchCallback visit_func = [&](const WaterRegionPatchDesc &water_region_patch) { |
| 171 | /* Note that we check the max distance per axis, not the total distance. */ |
| 172 | if (std::abs(water_region_patch.x - start_patch.x) > max_region_distance || |
| 173 | std::abs(water_region_patch.y - start_patch.y) > max_region_distance) return; |
| 174 | |
| 175 | const int hash = CalculateWaterRegionPatchHash(water_region_patch); |
| 176 | if (visited_patch_hashes.count(hash) == 0) { |
| 177 | visited_patch_hashes.insert(hash); |
| 178 | patches_to_search.push_back(water_region_patch); |
| 179 | } |
| 180 | }; |
| 181 | |
| 182 | VisitWaterRegionPatchNeighbours(current_node, visit_func); |
| 183 | } |
| 184 | |
| 185 | /* Step 2: Find the closest depot within the reachable Water Region Patches. */ |
| 186 | const Depot *best_depot = nullptr; |
| 187 | uint best_dist_sq = std::numeric_limits<uint>::max(); |
| 188 | for (const Depot *depot : Depot::Iterate()) { |
| 189 | const TileIndex tile = depot->xy; |
| 190 | if (IsShipDepotTile(tile) && IsTileOwner(tile, v->owner)) { |
| 191 | const uint dist_sq = DistanceSquare(tile, v->tile); |
| 192 | if (dist_sq < best_dist_sq && dist_sq <= max_distance * max_distance && |
| 193 | visited_patch_hashes.count(CalculateWaterRegionPatchHash(GetWaterRegionPatchInfo(tile))) > 0) { |
| 194 | best_dist_sq = dist_sq; |
| 195 | best_depot = depot; |
| 196 | } |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | return best_depot; |
| 201 | } |
| 202 | |
| 203 | static void CheckIfShipNeedsService(Vehicle *v) |
| 204 | { |
no test coverage detected