Index: src/station_cmd.cpp =================================================================== --- src/station_cmd.cpp 2008-05-29 17:13:28.000000000 +0200 +++ src/station_cmd.cpp 2008-06-03 20:52:57.000000000 +0200 @@ -668,9 +668,10 @@ * @param invalid_dirs prohibited directions (set of DiagDirections) * @param station StationID to be queried and returned if available * @param check_clear if clearing tile should be performed (in wich case, cost will be added) + * @param st station type to allow in search area * @return the cost in case of success, or an error code if it failed. */ -CommandCost CheckFlatLandBelow(TileIndex tile, uint w, uint h, uint flags, uint invalid_dirs, StationID *station, bool check_clear = true) +CommandCost CheckFlatLandBelow(TileIndex tile, uint w, uint h, uint flags, uint invalid_dirs, StationID *station, bool check_clear = true, StationType st = STATION_RAIL) { CommandCost cost(EXPENSES_CONSTRUCTION); int allowed_z = -1; @@ -720,11 +721,13 @@ return_cmd_error(STR_0007_FLAT_LAND_REQUIRED); } - /* if station is set, then we have special handling to allow building on top of already existing stations. - * so station points to INVALID_STATION if we can build on any station. - * Or it points to a station if we're only allowed to build on exactly that station. */ + /* if station is set, then allow building on top of an already + * existing station, either the one in *station if it is not + * INVALID_STATION, or anyone otherwise and store which one + * in *station + * also, only allow building over station tiles of type st */ if (station != NULL && IsTileType(tile_cur, MP_STATION)) { - if (!IsRailwayStation(tile_cur)) { + if (GetStationType(tile_cur) != st) { return ClearTile_Station(tile_cur, DC_AUTO); // get error message } else { StationID st = GetStationIndex(tile_cur); @@ -1724,6 +1727,41 @@ } +/** + * 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, uint32 flags) +{ + TileIndex tile = st->airport_tile; + + const AirportFTAClass *afc = st->Airport(); + int w = afc->size_x; + int h = afc->size_y; + + const Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (!(v->type == VEH_AIRCRAFT && IsNormalAircraft(v))) continue; + + if (v->u.air.targetairport == st->index && v->u.air.state != FLYING) + return_cmd_error(STR_A015_AIRCRAFT_IN_THE_WAY); + } + + BEGIN_TILE_LOOP(tile_cur, w, h, tile) { + if (!EnsureNoVehicleOnGround(tile_cur)) + return_cmd_error(STR_A015_AIRCRAFT_IN_THE_WAY); + + if (flags & DC_EXEC) { + DeleteAnimatedTile(tile_cur); + DoClearSquare(tile_cur); + } + } END_TILE_LOOP(tile_cur, w, h, tile) + + return CommandCost(EXPENSES_CONSTRUCTION, w * h * _price.remove_airport); +} + /** Place an Airport. * @param tile tile where airport will be built * @param flags operation to perform @@ -1732,8 +1770,6 @@ */ CommandCost CmdBuildAirport(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) { - bool airport_upgrade = true; - /* Check if a valid, buildable airport was chosen for construction */ if (p1 > lengthof(_airport_sections) || !HasBit(GetValidAirports(), p1)) return CMD_ERROR; @@ -1745,6 +1781,7 @@ const AirportFTAClass *afc = GetAirport(p1); int w = afc->size_x; int h = afc->size_y; + StationID est = INVALID_STATION; Station *st = NULL; if (w > _settings_game.station.station_spread || h > _settings_game.station.station_spread) { @@ -1752,25 +1789,50 @@ return CMD_ERROR; } - CommandCost cost = CheckFlatLandBelow(tile, w, h, flags, 0, NULL); + CommandCost cost = CheckFlatLandBelow(tile, w, h, flags, 0, &est, true, STATION_AIRPORT); if (CmdFailed(cost)) return cost; + if (!_settings_game.station.adjacent_stations || !HasBit(p2, 0)) { + st = GetStationAround(tile, w, h, est); + if (st == CHECK_STATIONS_ERR) return CMD_ERROR; + } else { + st = (est != INVALID_STATION) ? GetStation(est) : NULL; + } + + /* Find a station close to us */ + if (st == NULL) st = GetClosestStationFromTile(tile); + + /* 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; + /* Go get the final noise level, that is base noise minus factor from distance to town center */ - uint newnoise_level = GetAirportNoiseLevelForTown(afc, t->xy, tile); + uint newnoise_level = t->noise_reached + GetAirportNoiseLevelForTown(afc, t->xy, tile); + + if (action == AIRPORT_UPGRADE) { + newnoise_level -= GetAirportNoiseLevelForTown(st->Airport(), t->xy, st->airport_tile); + } /* Check if local auth would allow a new airport */ bool authority_refused; 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 */ - authority_refused = (t->noise_reached + newnoise_level) > t->MaxTownNoise(); - } else { + authority_refused = newnoise_level > t->MaxTownNoise(); + } else if (action != AIRPORT_UPGRADE) { uint num = 0; const Station *st; FOR_ALL_STATIONS(st) { if (st->town == t && st->facilities & FACIL_AIRPORT && st->airport_type != AT_OILRIG) num++; } authority_refused = (num >= 2); + } else { + authority_refused = false; } if (authority_refused) { @@ -1778,29 +1840,24 @@ return_cmd_error(STR_2035_LOCAL_AUTHORITY_REFUSES); } - if (!_settings_game.station.adjacent_stations || !HasBit(p2, 0)) { - st = GetStationAround(tile, w, h, INVALID_STATION); - if (st == CHECK_STATIONS_ERR) return CMD_ERROR; - } else { - st = NULL; - } - - /* Find a station close to us */ - if (st == NULL) st = GetClosestStationFromTile(tile); - - if (st != NULL) { + if (action != AIRPORT_NEW) { if (st->owner != _current_player) { return_cmd_error(STR_3009_TOO_CLOSE_TO_ANOTHER_STATION); } if (!st->rect.BeforeAddRect(tile, w, h, StationRect::ADD_TEST)) return CMD_ERROR; - if (st->airport_tile != 0) { - return_cmd_error(STR_300D_TOO_CLOSE_TO_ANOTHER_AIRPORT); + if (action != AIRPORT_UPGRADE) { + if (st->airport_tile != 0) { + return_cmd_error(STR_300D_TOO_CLOSE_TO_ANOTHER_AIRPORT); + } + } else { + /* check that old airport can be removed */ + CommandCost r = CanRemoveAirport(st, flags); + if (CmdFailed(r)) return r; + cost.AddCost(r); } } else { - airport_upgrade = false; - /* allocate and initialize new station */ if (!Station::CanAllocateItem()) return_cmd_error(STR_3008_TOO_MANY_STATIONS_LOADING); @@ -1820,8 +1877,22 @@ cost.AddCost(_price.build_airport * w * h); if (flags & DC_EXEC) { + if (action == AIRPORT_UPGRADE) { + /* delete old airport if upgrading */ + TileIndex otile = st->airport_tile; + const AirportFTAClass *oafc = st->Airport(); + + for (uint i = 0; i < oafc->nof_depots; ++i) { + DeleteWindowById( + WC_VEHICLE_DEPOT, otile + ToTileIndexDiff(oafc->airport_depots[i]) + ); + } + + st->rect.AfterRemoveRect(st, otile, oafc->size_x, oafc->size_y); + } + /* Always add the noise, so there will be no need to recalculate when option toggles */ - st->town->noise_reached += newnoise_level; + st->town->noise_reached = newnoise_level; st->airport_tile = tile; st->AddFacility(FACIL_AIRPORT, tile); @@ -1837,7 +1908,7 @@ * 1. airport is upgraded * 2. airport is added to existing station (unfortunately unavoideable) */ - if (airport_upgrade) UpdateAirplanesOnNewStation(st); + if (action != AIRPORT_NEW) UpdateAirplanesOnNewStation(st); { const byte *b = _airport_sections[p1]; @@ -1848,7 +1919,12 @@ } END_TILE_LOOP(tile_cur, w, h, tile) } - UpdateStationVirtCoordDirty(st); + if (action == AIRPORT_UPGRADE) { + UpdateStationSignCoord(st); + } else { + UpdateStationVirtCoordDirty(st); + } + UpdateStationAcceptance(st, false); InvalidateWindowData(WC_STATION_LIST, st->owner, 0); InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_PLANES); @@ -1867,31 +1943,14 @@ return CMD_ERROR; } - TileIndex tile = st->airport_tile; - - const AirportFTAClass *afc = st->Airport(); - int w = afc->size_x; - int h = afc->size_y; - - CommandCost cost(EXPENSES_CONSTRUCTION, w * h * _price.remove_airport); - - const Vehicle *v; - FOR_ALL_VEHICLES(v) { - if (!(v->type == VEH_AIRCRAFT && IsNormalAircraft(v))) continue; - - if (v->u.air.targetairport == st->index && v->u.air.state != FLYING) return CMD_ERROR; - } + CommandCost cost = CanRemoveAirport(st, flags); + if (CmdFailed(cost)) return cost; - BEGIN_TILE_LOOP(tile_cur, w, h, tile) { - if (!EnsureNoVehicleOnGround(tile_cur)) return CMD_ERROR; + if (flags & DC_EXEC) { + TileIndex tile = st->airport_tile; - if (flags & DC_EXEC) { - DeleteAnimatedTile(tile_cur); - DoClearSquare(tile_cur); - } - } END_TILE_LOOP(tile_cur, w, h, tile) + const AirportFTAClass *afc = st->Airport(); - if (flags & DC_EXEC) { for (uint i = 0; i < afc->nof_depots; ++i) { DeleteWindowById( WC_VEHICLE_DEPOT, tile + ToTileIndexDiff(afc->airport_depots[i]) @@ -1903,7 +1962,7 @@ * need of recalculation */ st->town->noise_reached -= GetAirportNoiseLevelForTown(afc, st->town->xy, tile); - st->rect.AfterRemoveRect(st, tile, w, h); + st->rect.AfterRemoveRect(st, tile, afc->size_x, afc->size_y); st->airport_tile = 0; st->facilities &= ~FACIL_AIRPORT; Index: src/unmovable_cmd.cpp =================================================================== --- src/unmovable_cmd.cpp 2008-05-29 17:13:28.000000000 +0200 +++ src/unmovable_cmd.cpp 2008-06-03 20:48:58.000000000 +0200 @@ -80,7 +80,7 @@ MarkTileDirtyByTile(tile + TileDiffXY(1, 1)); } -extern CommandCost CheckFlatLandBelow(TileIndex tile, uint w, uint h, uint flags, uint invalid_dirs, StationID *station, bool check_clear = true); +extern CommandCost CheckFlatLandBelow(TileIndex tile, uint w, uint h, uint flags, uint invalid_dirs, StationID *station, bool check_clear = true, StationType st = STATION_RAIL); /** Build or relocate the HQ. This depends if the HQ is already built or not * @param tile tile where the HQ will be built or relocated to