Index: src/station_cmd.cpp =================================================================== --- src/station_cmd.cpp 2008-04-03 21:55:40.000000000 +0200 +++ src/station_cmd.cpp 2008-04-05 20:51:57.000000000 +0200 @@ -699,9 +699,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; @@ -751,11 +752,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); @@ -1656,6 +1659,41 @@ _airport_sections_helistation // Helistation }; +/** + * 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; + + 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 @@ -1664,18 +1702,46 @@ */ 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; if (!(flags & DC_NO_TOWN_RATING) && !CheckIfAuthorityAllows(tile)) return CMD_ERROR; + const AirportFTAClass *afc = GetAirport(p1); + int w = afc->size_x; + int h = afc->size_y; + + /* Make sure the area below is clear or only overlaps one airport */ + StationID est = INVALID_STATION; + CommandCost cost = CheckFlatLandBelow(tile, w, h, flags & ~DC_EXEC, 0, &est, true, STATION_AIRPORT); + if (CmdFailed(cost)) return cost; + + Station *st; + + if (!_patches.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; + Town *t = ClosestTownFromTile(tile, (uint)-1); /* Check if local auth refuses a new airport */ - { + if (action != AIRPORT_UPGRADE) { uint num = 0; const Station *st; FOR_ALL_STATIONS(st) { @@ -1688,23 +1754,6 @@ } } - const AirportFTAClass *afc = GetAirport(p1); - int w = afc->size_x; - int h = afc->size_y; - - CommandCost cost = CheckFlatLandBelow(tile, w, h, flags, 0, NULL); - if (CmdFailed(cost)) return cost; - - Station *st = NULL; - - if (!_patches.adjacent_stations || !HasBit(p2, 0)) { - st = GetStationAround(tile, w, h, INVALID_STATION); - if (st == CHECK_STATIONS_ERR) return CMD_ERROR; - } - - /* Find a station close to us */ - if (st == NULL) st = GetClosestStationFromTile(tile); - if (w > _patches.station_spread || h > _patches.station_spread) { _error_message = STR_306C_STATION_TOO_SPREAD_OUT; return CMD_ERROR; @@ -1714,17 +1763,22 @@ * to test if everything is OK. In this case we need to delete it before return. */ AutoPtrT st_auto_delete; - 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 */ st = new Station(tile); if (st == NULL) return_cmd_error(STR_3008_TOO_MANY_STATIONS_LOADING); @@ -1750,6 +1804,20 @@ 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); + } + st->airport_tile = tile; st->AddFacility(FACIL_AIRPORT, tile); st->airport_type = (byte)p1; @@ -1764,7 +1832,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]; @@ -1775,7 +1843,12 @@ } END_TILE_LOOP(tile_cur, w, h, tile) } - UpdateStationVirtCoordDirty(st); + if (action == AIRPORT_UPGRADE) { + UpdateStationSignCoord(st); + } else { + UpdateStationVirtCoordDirty(st); + } + UpdateStationAcceptance(st, false); RebuildStationLists(); InvalidateWindow(WC_STATION_LIST, st->owner); @@ -1792,38 +1865,21 @@ if (_current_player != OWNER_WATER && !CheckOwnership(st->owner)) 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); - - 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]) ); } - 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-04-03 21:55:40.000000000 +0200 +++ src/unmovable_cmd.cpp 2008-04-05 19:02:23.000000000 +0200 @@ -76,7 +76,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