patch-import 9 years ago committed by Jonathan G Rennison
parent 67366cf03d
commit c72b29cfd0

@ -990,6 +990,47 @@ static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags
return cost;
}
/** Checks if an airport can be built at the given area.
* @param tile_area Area to check.
* @param flags Operation to perform.
* @param station StationID of airport allowed in search area.
* @return The cost in case of success, or an error code if it failed.
*/
static CommandCost CheckFlatLandAirport(TileArea tile_area, DoCommandFlag flags, StationID *station)
{
CommandCost cost(EXPENSES_CONSTRUCTION);
int allowed_z = -1;
TILE_AREA_LOOP(tile_cur, tile_area) {
CommandCost ret = CheckBuildableTile(tile_cur, 0, allowed_z, true);
if (ret.Failed()) return ret;
cost.AddCost(ret);
/* if station is set, then allow building on top of an already
* existing airport, either the one in *station if it is not
* INVALID_STATION, or anyone otherwise and store which one
* in *station */
if (station != NULL && IsTileType(tile_cur, MP_STATION)) {
if (!IsAirport(tile_cur)) {
return ClearTile_Station(tile_cur, DC_AUTO); // get error message
} else {
StationID st = GetStationIndex(tile_cur);
if (*station == INVALID_STATION) {
*station = st;
} else if (*station != st) {
return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
}
}
} else {
ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
if (ret.Failed()) return ret;
cost.AddCost(ret);
}
}
return cost;
}
/**
* Check whether we can expand the rail part of the given station.
* @param st the station to expand
@ -1069,16 +1110,16 @@ void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSp
/**
* Find a nearby station that joins this station.
* @tparam T the class to find a station for
* @tparam error_message the error message when building a station on top of others
* @param existing_station an existing station we build over
* @param station_to_join the station to join to
* @param adjacent whether adjacent stations are allowed
* @param ta the area of the newly build station
* @param st 'return' pointer for the found station
* @param error_message the error message when building a station on top of others
* @return command cost with the error or 'okay'
*/
template <class T, StringID error_message>
CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st)
template <class T>
CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st, StringID error_message)
{
assert(*st == NULL);
bool check_surrounding = true;
@ -1121,11 +1162,12 @@ CommandCost FindJoiningBaseStation(StationID existing_station, StationID station
* @param adjacent whether adjacent stations are allowed
* @param ta the area of the newly build station
* @param st 'return' pointer for the found station
* @param error_message the error message when building a station on top of others
* @return command cost with the error or 'okay'
*/
static CommandCost FindJoiningStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
static CommandCost FindJoiningStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Station **st, StringID error_message = STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST)
{
return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST>(existing_station, station_to_join, adjacent, ta, st);
return FindJoiningBaseStation<Station>(existing_station, station_to_join, adjacent, ta, st, error_message);
}
/**
@ -1139,7 +1181,7 @@ static CommandCost FindJoiningStation(StationID existing_station, StationID stat
*/
CommandCost FindJoiningWaypoint(StationID existing_waypoint, StationID waypoint_to_join, bool adjacent, TileArea ta, Waypoint **wp)
{
return FindJoiningBaseStation<Waypoint, STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST>(existing_waypoint, waypoint_to_join, adjacent, ta, wp);
return FindJoiningBaseStation<Waypoint>(existing_waypoint, waypoint_to_join, adjacent, ta, wp, STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST);
}
/**
@ -1731,7 +1773,7 @@ static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags);
*/
static CommandCost FindJoiningRoadStop(StationID existing_stop, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
{
return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST>(existing_stop, station_to_join, adjacent, ta, st);
return FindJoiningBaseStation<Station>(existing_stop, station_to_join, adjacent, ta, st, STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST);
}
/**
@ -2169,6 +2211,37 @@ void UpdateAirportsNoise()
}
}
/**
* Checks if an airport can be removed (no aircraft on it or landing)
* @param st Station whose airport is to be removed
* @param flags Operation to perform
* @return Cost or failure of operation
*/
static CommandCost CanRemoveAirport(Station *st, DoCommandFlag flags)
{
const Aircraft *a;
FOR_ALL_AIRCRAFT(a) {
if (!a->IsNormalAircraft()) continue;
if (a->targetairport == st->index && a->state != FLYING)
return_cmd_error(STR_ERROR_AIRCRAFT_IN_THE_WAY);
}
CommandCost cost(EXPENSES_CONSTRUCTION);
TILE_AREA_LOOP(tile_cur, st->airport) {
if (!st->TileBelongsToAirport(tile_cur)) continue;
CommandCost ret = EnsureNoVehicleOnGround(tile_cur);
if (ret.Failed()) return ret;
cost.AddCost(_price[PR_CLEAR_STATION_AIRPORT]);
}
return cost;
}
/**
* Place an Airport.
* @param tile tile where airport will be built
@ -2212,13 +2285,46 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
}
CommandCost cost = CheckFlatLand(airport_area, flags);
StationID est = INVALID_STATION;
CommandCost cost = CheckFlatLandAirport(airport_area, flags, &est);
if (cost.Failed()) return cost;
Station *st = NULL;
ret = FindJoiningStation(est, station_to_join, HasBit(p2, 0), airport_area, &st, STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST);
if (ret.Failed()) return ret;
/* Distant join */
if (st == NULL && distant_join) st = Station::GetIfValid(station_to_join);
ret = BuildStationPart(&st, flags, reuse, airport_area, (GetAirport(airport_type)->flags & AirportFTAClass::AIRPLANES) ? STATIONNAMING_AIRPORT : STATIONNAMING_HELIPORT);
if (ret.Failed()) return ret;
/* action to be performed */
enum {
AIRPORT_NEW, // airport is a new station
AIRPORT_ADD, // add an airport to an existing station
AIRPORT_UPGRADE, // upgrade the airport in a station
} action =
(est != INVALID_STATION) ? AIRPORT_UPGRADE :
(st != NULL) ? AIRPORT_ADD : AIRPORT_NEW;
if (action == AIRPORT_ADD && st->airport.tile != INVALID_TILE) {
return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT);
}
/* The noise level is the noise from the airport and reduce it to account for the distance to the town center. */
AirportTileTableIterator iter(as->table[layout], tile);
Town *nearest = AirportGetNearestTown(as, iter);
uint newnoise_level = GetAirportNoiseLevelForTown(as, iter, nearest->xy);
uint newnoise_level = nearest->noise_reached + GetAirportNoiseLevelForTown(as, iter, nearest->xy);
if (action == AIRPORT_UPGRADE) {
const AirportSpec *old_as = st->airport.GetSpec();
AirportTileTableIterator old_iter(old_as->table[st->airport.layout], st->airport.tile);
Town *old_nearest = AirportGetNearestTown(old_as, old_iter);
if (old_nearest == nearest) {
newnoise_level -= GetAirportNoiseLevelForTown(old_as, old_iter, nearest->xy);
}
}
/* Check if local auth would allow a new airport */
StringID authority_refuse_message = STR_NULL;
@ -2226,11 +2332,11 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
if (_settings_game.economy.station_noise_level) {
/* do not allow to build a new airport if this raise the town noise over the maximum allowed by town */
if ((nearest->noise_reached + newnoise_level) > nearest->MaxTownNoise()) {
if (newnoise_level > nearest->MaxTownNoise()) {
authority_refuse_message = STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE;
authority_refuse_town = nearest;
}
} else {
} else if (action != AIRPORT_UPGRADE) {
Town *t = ClosestTownFromTile(tile, UINT_MAX);
uint num = 0;
const Station *st;
@ -2248,18 +2354,11 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
return_cmd_error(authority_refuse_message);
}
Station *st = NULL;
ret = FindJoiningStation(INVALID_STATION, station_to_join, HasBit(p2, 0), airport_area, &st);
if (ret.Failed()) return ret;
/* Distant join */
if (st == NULL && distant_join) st = Station::GetIfValid(station_to_join);
ret = BuildStationPart(&st, flags, reuse, airport_area, (GetAirport(airport_type)->flags & AirportFTAClass::AIRPLANES) ? STATIONNAMING_AIRPORT : STATIONNAMING_HELIPORT);
if (ret.Failed()) return ret;
if (st != NULL && st->airport.tile != INVALID_TILE) {
return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT);
if (action == AIRPORT_UPGRADE) {
/* check that the old airport can be removed */
CommandCost r = CanRemoveAirport(st, flags);
if (r.Failed()) return r;
cost.AddCost(r);
}
for (AirportTileTableIterator iter(as->table[layout], tile); iter != INVALID_TILE; ++iter) {
@ -2267,8 +2366,38 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
}
if (flags & DC_EXEC) {
if (action == AIRPORT_UPGRADE) {
/* delete old airport if upgrading */
const AirportSpec *old_as = st->airport.GetSpec();
AirportTileTableIterator old_iter(old_as->table[st->airport.layout], st->airport.tile);
Town *old_nearest = AirportGetNearestTown(old_as, old_iter);
if (old_nearest != nearest) {
old_nearest->noise_reached -= GetAirportNoiseLevelForTown(old_as, old_iter, old_nearest->xy);
if (_settings_game.economy.station_noise_level) {
SetWindowDirty(WC_TOWN_VIEW, st->town->index);
}
}
TILE_AREA_LOOP(tile_cur, st->airport) {
if (IsHangarTile(tile_cur)) OrderBackup::Reset(tile_cur, false);
DeleteAnimatedTile(tile_cur);
DoClearSquare(tile_cur);
DeleteNewGRFInspectWindow(GSF_AIRPORTTILES, tile_cur);
}
for (uint i = 0; i < st->airport.GetNumHangars(); ++i) {
DeleteWindowById(
WC_VEHICLE_DEPOT, st->airport.GetHangarTile(i)
);
}
st->rect.AfterRemoveRect(st, st->airport);
st->airport.Clear();
}
/* Always add the noise, so there will be no need to recalculate when option toggles */
nearest->noise_reached += newnoise_level;
nearest->noise_reached = newnoise_level;
st->AddFacility(FACIL_AIRPORT, tile);
st->airport.type = airport_type;
@ -2291,12 +2420,16 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
AirportTileAnimationTrigger(st, iter, AAT_BUILT);
}
UpdateAirplanesOnNewStation(st);
if (action != AIRPORT_NEW) UpdateAirplanesOnNewStation(st);
Company::Get(st->owner)->infrastructure.airport++;
DirtyCompanyInfrastructureWindows(st->owner);
if (action == AIRPORT_UPGRADE) {
UpdateStationSignCoord(st);
} else {
Company::Get(st->owner)->infrastructure.airport++;
DirtyCompanyInfrastructureWindows(st->owner);
st->UpdateVirtCoord();
}
st->UpdateVirtCoord();
UpdateStationAcceptance(st, false);
st->RecomputeIndustriesNear();
InvalidateWindowData(WC_SELECT_STATION, 0, 0);
@ -2326,15 +2459,8 @@ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags)
if (ret.Failed()) return ret;
}
tile = st->airport.tile;
CommandCost cost(EXPENSES_CONSTRUCTION);
const Aircraft *a;
FOR_ALL_AIRCRAFT(a) {
if (!a->IsNormalAircraft()) continue;
if (a->targetairport == st->index && a->state != FLYING) return CMD_ERROR;
}
CommandCost cost = CanRemoveAirport(st, flags);
if (cost.Failed()) return cost;
if (flags & DC_EXEC) {
const AirportSpec *as = st->airport.GetSpec();
@ -2344,25 +2470,14 @@ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags)
AirportTileIterator it(st);
Town *nearest = AirportGetNearestTown(as, it);
nearest->noise_reached -= GetAirportNoiseLevelForTown(as, it, nearest->xy);
}
TILE_AREA_LOOP(tile_cur, st->airport) {
if (!st->TileBelongsToAirport(tile_cur)) continue;
CommandCost ret = EnsureNoVehicleOnGround(tile_cur);
if (ret.Failed()) return ret;
cost.AddCost(_price[PR_CLEAR_STATION_AIRPORT]);
if (flags & DC_EXEC) {
TILE_AREA_LOOP(tile_cur, st->airport) {
if (IsHangarTile(tile_cur)) OrderBackup::Reset(tile_cur, false);
DeleteAnimatedTile(tile_cur);
DoClearSquare(tile_cur);
DeleteNewGRFInspectWindow(GSF_AIRPORTTILES, tile_cur);
}
}
if (flags & DC_EXEC) {
/* Clear the persistent storage. */
delete st->airport.psa;

Loading…
Cancel
Save