diff --git a/src/script/api/script_airport.cpp b/src/script/api/script_airport.cpp index 0df4465e63..f5c6ed20c5 100644 --- a/src/script/api/script_airport.cpp +++ b/src/script/api/script_airport.cpp @@ -15,7 +15,7 @@ #include "../../safeguards.h" -extern Town *AirportGetNearestTown(const struct AirportSpec *as, TileIndex tile, const TileIterator &it, uint &mindist); +extern Town *AirportGetNearestTown(const struct AirportSpec *as, Direction rotation, TileIndex tile, TileIterator &&it, uint &mindist); extern uint8 GetAirportNoiseLevelForDistance(const struct AirportSpec *as, uint distance); /* static */ bool ScriptAirport::IsValidAirportType(AirportType type) @@ -140,9 +140,8 @@ extern uint8 GetAirportNoiseLevelForDistance(const struct AirportSpec *as, uint if (!as->IsWithinMapBounds(0, tile)) return -1; if (_settings_game.economy.station_noise_level) { - AirportTileTableIterator it(as->table[0], tile); uint dist; - AirportGetNearestTown(as, tile, it, dist); + AirportGetNearestTown(as, DIR_N, tile, AirportTileTableIterator(as->table[0], tile), dist); return GetAirportNoiseLevelForDistance(as, dist); } @@ -158,7 +157,7 @@ extern uint8 GetAirportNoiseLevelForDistance(const struct AirportSpec *as, uint if (!as->IsWithinMapBounds(0, tile)) return INVALID_TOWN; uint dist; - return AirportGetNearestTown(as, tile, AirportTileTableIterator(as->table[0], tile), dist)->index; + return AirportGetNearestTown(as, DIR_N, tile, AirportTileTableIterator(as->table[0], tile), dist)->index; } /* static */ SQInteger ScriptAirport::GetMaintenanceCostFactor(AirportType type) diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 7ae79e8c1f..4c7586b431 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -2599,28 +2599,32 @@ uint8 GetAirportNoiseLevelForDistance(const AirportSpec *as, uint distance) * Finds the town nearest to given airport. Based on minimal manhattan distance to any airport's tile. * If two towns have the same distance, town with lower index is returned. * @param as airport's description + * @param rotation airport's rotation * @param tile origin tile (top corner of the airport) - * @param it An iterator over all airport tiles + * @param it An iterator over all airport tiles (consumed) * @param[out] mindist Minimum distance to town * @return nearest town to airport */ -Town *AirportGetNearestTown(const AirportSpec *as, TileIndex tile, const TileIterator &it, uint &mindist) +Town *AirportGetNearestTown(const AirportSpec *as, Direction rotation, TileIndex tile, TileIterator &&it, uint &mindist) { assert(Town::GetNumItems() > 0); Town *nearest = nullptr; + int width = as->size_x; + int height = as->size_y; + if (rotation == DIR_E || rotation == DIR_W) std::swap(width, height); + uint perimeter_min_x = TileX(tile); uint perimeter_min_y = TileY(tile); - uint perimeter_max_x = perimeter_min_x + as->size_x - 1; - uint perimeter_max_y = perimeter_min_y + as->size_y - 1; + uint perimeter_max_x = perimeter_min_x + width - 1; + uint perimeter_max_y = perimeter_min_y + height - 1; mindist = UINT_MAX - 1; // prevent overflow - std::unique_ptr copy(it.Clone()); - for (TileIndex cur_tile = *copy; cur_tile != INVALID_TILE; cur_tile = ++*copy) { - assert(IsInsideBS(TileX(cur_tile), perimeter_min_x, as->size_x)); - assert(IsInsideBS(TileY(cur_tile), perimeter_min_y, as->size_y)); + for (TileIndex cur_tile = *it; cur_tile != INVALID_TILE; cur_tile = ++it) { + assert(IsInsideBS(TileX(cur_tile), perimeter_min_x, width)); + assert(IsInsideBS(TileY(cur_tile), perimeter_min_y, height)); if (TileX(cur_tile) == perimeter_min_x || TileX(cur_tile) == perimeter_max_x || TileY(cur_tile) == perimeter_min_y || TileY(cur_tile) == perimeter_max_y) { Town *t = CalcClosestTownFromTile(cur_tile, mindist + 1); if (t == nullptr) continue; @@ -2637,6 +2641,18 @@ Town *AirportGetNearestTown(const AirportSpec *as, TileIndex tile, const TileIte return nearest; } +/** + * Finds the town nearest to given existing airport. Based on minimal manhattan distance to any airport's tile. + * If two towns have the same distance, town with lower index is returned. + * @param station existing station with airport + * @param[out] mindist Minimum distance to town + * @return nearest town to airport + */ +Town *AirportGetNearestTown(const Station *st, uint &mindist) +{ + return AirportGetNearestTown(st->airport.GetSpec(), st->airport.rotation, st->airport.tile, AirportTileIterator(st), mindist); +} + /** Recalculate the noise generated by the airports of each town */ void UpdateAirportsNoise() @@ -2647,11 +2663,9 @@ void UpdateAirportsNoise() for (const Station *st : Station::Iterate()) { if (st->airport.tile != INVALID_TILE && st->airport.type != AT_OILRIG) { - const AirportSpec *as = st->airport.GetSpec(); - AirportTileIterator it(st); uint dist; - Town *nearest = AirportGetNearestTown(as, st->airport.tile, it, dist); - nearest->noise_reached += GetAirportNoiseLevelForDistance(as, dist); + Town *nearest = AirportGetNearestTown(st, dist); + nearest->noise_reached += GetAirportNoiseLevelForDistance(st->airport.GetSpec(), dist); } } } @@ -2763,17 +2777,16 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint } /* The noise level is the noise from the airport and reduce it to account for the distance to the town center. */ + AirportTileTableIterator nearest_town_iter = iter; uint dist; - Town *nearest = AirportGetNearestTown(as, tile, iter, dist); + Town *nearest = AirportGetNearestTown(as, rotation, tile, std::move(nearest_town_iter), dist); uint newnoise_level = nearest->noise_reached + GetAirportNoiseLevelForDistance(as, dist); if (action == AIRPORT_UPGRADE) { - const AirportSpec *old_as = st->airport.GetSpec(); - AirportTileTableIterator old_iter(old_as->table[st->airport.layout], st->airport.tile); uint old_dist; - Town *old_nearest = AirportGetNearestTown(old_as, st->airport.tile, old_iter, old_dist); + Town *old_nearest = AirportGetNearestTown(st, old_dist); if (old_nearest == nearest) { - newnoise_level -= GetAirportNoiseLevelForDistance(old_as, old_dist); + newnoise_level -= GetAirportNoiseLevelForDistance(st->airport.GetSpec(), old_dist); } } @@ -2827,13 +2840,11 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint CloseWindowById(WC_VEHICLE_DEPOT, tile_cur); } - const AirportSpec *old_as = st->airport.GetSpec(); - AirportTileTableIterator old_iter(old_as->table[st->airport.layout], st->airport.tile); uint old_dist; - Town *old_nearest = AirportGetNearestTown(old_as, st->airport.tile, old_iter, old_dist); + Town *old_nearest = AirportGetNearestTown(st, old_dist); if (old_nearest != nearest) { - old_nearest->noise_reached -= GetAirportNoiseLevelForDistance(old_as, old_dist); + old_nearest->noise_reached -= GetAirportNoiseLevelForDistance(st->airport.GetSpec(), old_dist); if (_settings_game.economy.station_noise_level) { SetWindowDirty(WC_TOWN_VIEW, st->town->index); } @@ -2919,14 +2930,12 @@ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags) } ZoningMarkDirtyStationCoverageArea(st); - const AirportSpec *as = st->airport.GetSpec(); /* The noise level is the noise from the airport and reduce it to account for the distance to the town center. * And as for construction, always remove it, even if the setting is not set, in order to avoid the * need of recalculation */ - AirportTileIterator it(st); uint dist; - Town *nearest = AirportGetNearestTown(as, st->airport.tile, it, dist); - nearest->noise_reached -= GetAirportNoiseLevelForDistance(as, dist); + Town *nearest = AirportGetNearestTown(st, dist); + nearest->noise_reached -= GetAirportNoiseLevelForDistance(st->airport.GetSpec(), dist); if (_settings_game.economy.station_noise_level) { SetWindowDirty(WC_TOWN_VIEW, nearest->index);