Index: src/station_cmd.cpp =================================================================== --- src/station_cmd.cpp 2007-12-16 00:11:18.000000000 +0100 +++ src/station_cmd.cpp 2007-12-17 21:06:36.000000000 +0100 @@ -703,9 +703,10 @@ * @param invalid_dirs prohibited directions * @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; int allowed_z = -1; @@ -754,11 +755,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); @@ -1650,6 +1653,37 @@ _airport_sections_helistation // Helistation }; +/* Checks if an airport can be removed (no aircraft on it or landing) */ +/* Returns cost on success, else an error */ +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(w * h * _price.remove_airport); +} + /** Place an Airport. * @param tile tile where airport will be built * @param flags operation to perform @@ -1658,8 +1692,6 @@ */ CommandCost CmdBuildAirport(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) { - bool airport_upgrade = true; - SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); /* Check if a valid, buildable airport was chosen for construction */ @@ -1668,10 +1700,35 @@ 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 = NULL; + + if (!_patches.adjacent_stations || !HasBit(p2, 0)) { + st = GetStationAround(tile, w, h, est); + if (st == CHECK_STATIONS_ERR) return CMD_ERROR; + } + + // 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) { @@ -1684,21 +1741,6 @@ } } - const AirportFTAClass *afc = GetAirport(p1); - int w = afc->size_x; - int h = afc->size_y; - - CommandCost ret = CheckFlatLandBelow(tile, w, h, flags, 0, NULL); - if (CmdFailed(ret)) return ret; - CommandCost cost(ret.GetCost()); - - 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); @@ -1711,17 +1753,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); @@ -1747,6 +1794,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; @@ -1761,7 +1822,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]; @@ -1789,38 +1850,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(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 2007-11-19 22:32:20.000000000 +0100 +++ src/unmovable_cmd.cpp 2007-12-17 20:42:50.000000000 +0100 @@ -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