Changeset - r28344:611d328c4327
[Not reviewed]
master
0 3 0
Jonathan G Rennison - 11 months ago 2023-12-28 21:43:05
j.g.rennison@gmail.com
Fix #11629: AirportGetNearestTown for rotated airports (#11631)

Add rotation parameter to AirportGetNearestTown
Add wrapper for existing stations
Remove unnecessary iterator cloning
3 files changed with 32 insertions and 21 deletions:
0 comments (0 inline, 0 general)
src/script/api/script_airport.cpp
Show inline comments
 
@@ -134,15 +134,14 @@
 
	if (!IsAirportInformationAvailable(type)) return -1;
 

	
 
	const AirportSpec *as = ::AirportSpec::Get(type);
 
	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, as->rotation[0], tile, AirportTileTableIterator(as->table[0], tile), dist);
 
		return GetAirportNoiseLevelForDistance(as, dist);
 
	}
 

	
 
	return 1;
 
}
 

	
 
@@ -152,13 +151,13 @@
 
	if (!IsAirportInformationAvailable(type)) return INVALID_TOWN;
 

	
 
	const AirportSpec *as = AirportSpec::Get(type);
 
	if (!as->IsWithinMapBounds(0, tile)) return INVALID_TOWN;
 

	
 
	uint dist;
 
	return AirportGetNearestTown(as, tile, AirportTileTableIterator(as->table[0], tile), dist)->index;
 
	return AirportGetNearestTown(as, as->rotation[0], tile, AirportTileTableIterator(as->table[0], tile), dist)->index;
 
}
 

	
 
/* static */ SQInteger ScriptAirport::GetMaintenanceCostFactor(AirportType type)
 
{
 
	if (!IsAirportInformationAvailable(type)) return 0;
 

	
src/station_cmd.cpp
Show inline comments
 
@@ -2300,34 +2300,38 @@ uint8_t GetAirportNoiseLevelForDistance(
 
}
 

	
 
/**
 
 * 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;
 

	
 
	auto width = as->size_x;
 
	auto 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<TileIterator> 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;
 

	
 
			uint dist = DistanceManhattan(t->xy, cur_tile);
 
			if (dist == mindist && t->index < nearest->index) nearest = t;
 
@@ -2338,25 +2342,35 @@ Town *AirportGetNearestTown(const Airpor
 
		}
 
	}
 

	
 
	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
 
 */
 
static 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()
 
{
 
	for (Town *t : Town::Iterate()) t->noise_reached = 0;
 

	
 
	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);
 
		}
 
	}
 
}
 

	
 
/**
 
 * Place an Airport.
 
@@ -2399,13 +2413,13 @@ CommandCost CmdBuildAirport(DoCommandFla
 
	AirportTileTableIterator tile_iter(as->table[layout], tile);
 
	CommandCost cost = CheckFlatLandAirport(tile_iter, flags);
 
	if (cost.Failed()) return cost;
 

	
 
	/* The noise level is the noise from the airport and reduce it to account for the distance to the town center. */
 
	uint dist;
 
	Town *nearest = AirportGetNearestTown(as, tile, tile_iter, dist);
 
	Town *nearest = AirportGetNearestTown(as, rotation, tile, std::move(tile_iter), dist);
 
	uint newnoise_level = GetAirportNoiseLevelForDistance(as, dist);
 

	
 
	/* Check if local auth would allow a new airport */
 
	StringID authority_refuse_message = STR_NULL;
 
	Town *authority_refuse_town = nullptr;
 

	
 
@@ -2521,20 +2535,18 @@ static CommandCost RemoveAirport(TileInd
 
		for (uint i = 0; i < st->airport.GetNumHangars(); ++i) {
 
			TileIndex tile_cur = st->airport.GetHangarTile(i);
 
			OrderBackup::Reset(tile_cur, false);
 
			CloseWindowById(WC_VEHICLE_DEPOT, tile_cur);
 
		}
 

	
 
		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);
 
		}
 
	}
 

	
src/station_cmd.h
Show inline comments
 
@@ -13,13 +13,13 @@
 
#include "command_type.h"
 
#include "station_type.h"
 

	
 
enum StationClassID : byte;
 
enum RoadStopClassID : byte;
 

	
 
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_t GetAirportNoiseLevelForDistance(const struct AirportSpec *as, uint distance);
 

	
 
CommandCost CmdBuildAirport(DoCommandFlag flags, TileIndex tile, byte airport_type, byte layout, StationID station_to_join, bool allow_adjacent);
 
CommandCost CmdBuildDock(DoCommandFlag flags, TileIndex tile, StationID station_to_join, bool adjacent);
 
CommandCost CmdBuildRailStation(DoCommandFlag flags, TileIndex tile_org, RailType rt, Axis axis, byte numtracks, byte plat_len, StationClassID spec_class, uint16_t spec_index, StationID station_to_join, bool adjacent);
 
CommandCost CmdRemoveFromRailStation(DoCommandFlag flags, TileIndex start, TileIndex end, bool keep_rail);
0 comments (0 inline, 0 general)