--- a/src/station_cmd.cpp Mon May 26 11:36:42 2008 +0000
+++ b/src/station_cmd.cpp Mon May 26 13:52:59 2008 +0000
@@ -296,7 +296,7 @@
CountMapSquareAround(tile, CMSATree) >= 8 ||
CountMapSquareAround(tile, CMSAForest) >= 2)
) {
- return _opt.landscape == LT_TROPIC ? STR_SV_STNAME_FOREST : STR_SV_STNAME_WOODS;
+ return _settings.game_creation.landscape == LT_TROPIC ? STR_SV_STNAME_FOREST : STR_SV_STNAME_WOODS;
}
/* check elevation compared to town */
@@ -563,7 +563,7 @@
TileXY(rect.left, rect.bottom),
rect.right - rect.left + 1,
rect.top - rect.bottom + 1,
- _patches.modified_catchment ? FindCatchmentRadius(st) : (uint)CA_UNMODIFIED
+ _settings.station.modified_catchment ? FindCatchmentRadius(st) : (uint)CA_UNMODIFIED
);
} else {
memset(accepts, 0, sizeof(accepts));
@@ -692,7 +692,7 @@
* b) the build_on_slopes switch is disabled
*/
if (IsSteepSlope(tileh) ||
- ((!_patches.build_on_slopes) && tileh != SLOPE_FLAT)) {
+ ((!_settings.construction.build_on_slopes) && tileh != SLOPE_FLAT)) {
return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
}
@@ -750,7 +750,7 @@
uint w = fin[1];
uint h = fin[2];
- if (_patches.nonuniform_stations) {
+ if (_settings.station.nonuniform_stations) {
/* determine new size of train station region.. */
int x = min(TileX(st->train_tile), TileX(tile));
int y = min(TileY(st->train_tile), TileY(tile));
@@ -794,7 +794,7 @@
}
}
/* make sure the final size is not too big. */
- if (curw > _patches.station_spread || curh > _patches.station_spread) {
+ if (curw > _settings.station.station_spread || curh > _settings.station.station_spread) {
_error_message = STR_306C_STATION_TOO_SPREAD_OUT;
return false;
}
@@ -883,7 +883,7 @@
w_org = numtracks;
}
- if (h_org > _patches.station_spread || w_org > _patches.station_spread) return CMD_ERROR;
+ if (h_org > _settings.station.station_spread || w_org > _settings.station.station_spread) return CMD_ERROR;
/* these values are those that will be stored in train_tile and station_platforms */
uint finalvalues[3];
@@ -896,14 +896,14 @@
/* If DC_EXEC is in flag, do not want to pass it to CheckFlatLandBelow, because of a nice bug
* for detail info, see:
* https://sourceforge.net/tracker/index.php?func=detail&aid=1029064&group_id=103924&atid=636365 */
- CommandCost ret = CheckFlatLandBelow(tile_org, w_org, h_org, flags & ~DC_EXEC, 5 << axis, _patches.nonuniform_stations ? &est : NULL);
+ CommandCost ret = CheckFlatLandBelow(tile_org, w_org, h_org, flags & ~DC_EXEC, 5 << axis, _settings.station.nonuniform_stations ? &est : NULL);
if (CmdFailed(ret)) return ret;
CommandCost cost(EXPENSES_CONSTRUCTION, ret.GetCost() + (numtracks * _price.train_station_track + _price.train_station_length) * plat_len);
Station *st = NULL;
bool check_surrounding = true;
- if (_patches.adjacent_stations) {
+ if (_settings.station.adjacent_stations) {
if (est != INVALID_STATION) {
if (HasBit(p1, 24)) {
/* You can't build an adjacent station over the top of one that
@@ -938,7 +938,7 @@
if (st->train_tile != 0) {
/* check if we want to expanding an already existing station? */
- if (!_patches.join_stations)
+ if (!_settings.station.join_stations)
return_cmd_error(STR_3005_TOO_CLOSE_TO_ANOTHER_RAILROAD);
if (!CanExpandRailroadStation(st, finalvalues, axis))
return CMD_ERROR;
@@ -993,7 +993,7 @@
/* Now really clear the land below the station
* It should never return CMD_ERROR.. but you never know ;)
* (a bit strange function name for it, but it really does clear the land, when DC_EXEC is in flags) */
- ret = CheckFlatLandBelow(tile_org, w_org, h_org, flags, 5 << axis, _patches.nonuniform_stations ? &est : NULL);
+ ret = CheckFlatLandBelow(tile_org, w_org, h_org, flags, 5 << axis, _settings.station.nonuniform_stations ? &est : NULL);
if (CmdFailed(ret)) return ret;
st->train_tile = finalvalues[0];
@@ -1162,7 +1162,7 @@
/* Do not allow removing from stations if non-uniform stations are not enabled
* The check must be here to give correct error message
*/
- if (!_patches.nonuniform_stations) return_cmd_error(STR_NONUNIFORM_STATIONS_DISALLOWED);
+ if (!_settings.station.nonuniform_stations) return_cmd_error(STR_NONUNIFORM_STATIONS_DISALLOWED);
/* If we reached here, the tile is valid so increase the quantity of tiles we will remove */
quantity++;
@@ -1207,7 +1207,7 @@
static CommandCost RemoveRailroadStation(Station *st, TileIndex tile, uint32 flags)
{
/* if there is flooding and non-uniform stations are enabled, remove platforms tile by tile */
- if (_current_player == OWNER_WATER && _patches.nonuniform_stations) {
+ if (_current_player == OWNER_WATER && _settings.station.nonuniform_stations) {
return DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAILROAD_STATION);
}
@@ -1300,7 +1300,7 @@
bool type = HasBit(p2, 0);
bool is_drive_through = HasBit(p2, 1);
bool build_over_road = is_drive_through && IsNormalRoadTile(tile);
- bool town_owned_road = build_over_road && IsTileOwner(tile, OWNER_TOWN);
+ bool town_owned_road = false;
RoadTypes rts = (RoadTypes)GB(p2, 2, 3);
if (!AreValidRoadTypes(rts) || !HasRoadTypesAvail(_current_player, rts)) return CMD_ERROR;
@@ -1319,14 +1319,17 @@
/* Not allowed to build over this road */
if (build_over_road) {
- if (IsTileOwner(tile, OWNER_TOWN) && !_patches.road_stop_on_town_road) return_cmd_error(STR_DRIVE_THROUGH_ERROR_ON_TOWN_ROAD);
-
RoadTypes cur_rts = GetRoadTypes(tile);
/* there is a road, check if we can build road+tram stop over it */
if (HasBit(cur_rts, ROADTYPE_ROAD)) {
Owner road_owner = GetRoadOwner(tile, ROADTYPE_ROAD);
- if (road_owner != OWNER_TOWN && road_owner != OWNER_NONE && !CheckOwnership(road_owner)) return CMD_ERROR;
+ if (road_owner == OWNER_TOWN) {
+ town_owned_road = true;
+ if (!_settings.construction.road_stop_on_town_road) return_cmd_error(STR_DRIVE_THROUGH_ERROR_ON_TOWN_ROAD);
+ } else {
+ if (road_owner != OWNER_NONE && !CheckOwnership(road_owner)) return CMD_ERROR;
+ }
}
/* there is a tram, check if we can build road+tram stop over it */
@@ -1347,7 +1350,7 @@
Station *st = NULL;
- if (!_patches.adjacent_stations || !HasBit(p2, 5)) {
+ if (!_settings.station.adjacent_stations || !HasBit(p2, 5)) {
st = GetStationAround(tile, 1, 1, INVALID_STATION);
if (st == CHECK_STATIONS_ERR) return CMD_ERROR;
}
@@ -1610,6 +1613,88 @@
_airport_sections_helistation // Helistation
};
+/** Recalculate the noise generated by the airports of each town */
+void UpdateAirportsNoise()
+{
+ Town *t;
+ const Station *st;
+
+ FOR_ALL_TOWNS(t) t->noise_reached = 0;
+
+ FOR_ALL_STATIONS(st) {
+ if (IsAirport(st->xy)) {
+ st->town->noise_reached += GetAirportNoiseLevelForTown(GetAirport(st->airport_type), st->town->xy, st->xy);
+ }
+ }
+}
+
+/** Get a possible noise reduction factor based on distance from town center.
+ * The further you get, the less noise you generate.
+ * So all those folks at city council can now happily slee... work in their offices
+ * @param afc AirportFTAClass pointer of the class being proposed
+ * @param town_tile TileIndex of town's center, the one who will receive the airport's candidature
+ * @param tile TileIndex where the new airport might be built
+ * @return the noise that will be generated, according to distance
+ */
+uint8 GetAirportNoiseLevelForTown(const AirportFTAClass *afc, TileIndex town_tile, TileIndex tile)
+{
+ struct TileIndexDistance {
+ TileIndex index;
+ uint distance;
+ };
+
+ uint distance;
+
+ /* 0 cannot be accounted, and 1 is the lowest that can be reduced from town.
+ * So no need to go any further*/
+ if (afc->noise_level < 2) return afc->noise_level;
+
+ /* Find the airport-to-be's closest corner to the town */
+ if (afc->size_x == 1 && afc->size_y == 1) {
+ distance = DistanceManhattan(town_tile, tile); // ont tile, one corner, it's THE corner
+ } else {
+ /* calculate manhattan distance to town of each side of the airport */
+ TileIndexDistance dist[4]; ///< Array that will contain all 4 corners in TileIndex and distance
+ uint min_tile = UINT_MAX; ///< Sentinel value
+ uint min_indice = 4;
+
+ /* Based on the size of the airport, establish location of each corner*/
+ dist[0].index = tile; // north tile
+ dist[1].index = TileAddWrap(tile, afc->size_x - 1, afc->size_y - 1); // south tile
+ dist[2].index = TileAddWrap(tile, afc->size_x - 1, 0); // west tile
+ dist[3].index = TileAddWrap(tile, 0, afc->size_y - 1); //east tile
+
+ /* now, go and find the smallest one, thus the closest to town */
+ for (uint i = 0; i < 4; i++) {
+ dist[i].distance = DistanceManhattan(town_tile, dist[i].index);
+
+ if (dist[i].distance < min_tile) {
+ min_tile = dist[i].distance; // here's a new candidate
+ min_indice = i;
+ }
+ }
+
+ distance = dist[min_indice].distance;
+ }
+
+ /* The steps for measuring noise reduction are based on the "magical" (and arbitrary) 8 base distance
+ * adding the town_council_tolerance 4 times, as a way to graduate, depending of the tolerance.
+ * Basically, it says that the less tolerant a town is, the bigger the distance before
+ * an actual decrease can be granted */
+ uint8 town_tolerance_distance = 8 + (_settings.difficulty.town_council_tolerance * 4);
+
+ /* The airport is in the "inner" distance where there is no noise reduction */
+ if (distance < town_tolerance_distance) return afc->noise_level;
+
+ /* now, we want to have the distance segmented using the distance judged bareable by town
+ * This will give us the coefficient of reduction the distance provides. */
+ uint noise_reduction = min(afc->noise_level, distance / town_tolerance_distance);
+
+ /* If the noise reduction equals the airport noise itself, don't give it for free. Use it all minus 1.
+ * Otherwise, simply reduce the airport's level. */
+ return max(1U, noise_reduction == afc->noise_level ? afc->noise_level - 1 : afc->noise_level - noise_reduction);
+}
+
/** Place an Airport.
* @param tile tile where airport will be built
* @param flags operation to perform
@@ -1633,7 +1718,7 @@
int h = afc->size_y;
Station *st = NULL;
- if (w > _patches.station_spread || h > _patches.station_spread) {
+ if (w > _settings.station.station_spread || h > _settings.station.station_spread) {
_error_message = STR_306C_STATION_TOO_SPREAD_OUT;
return CMD_ERROR;
}
@@ -1641,17 +1726,30 @@
CommandCost cost = CheckFlatLandBelow(tile, w, h, flags, 0, NULL);
if (CmdFailed(cost)) return cost;
- /* Check if local auth refuses a new airport */
- uint num = 0;
- FOR_ALL_STATIONS(st) {
- if (st->town == t && st->facilities & FACIL_AIRPORT && st->airport_type != AT_OILRIG) num++;
+ /* 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);
+
+ /* Check if local auth would allow a new airport */
+ bool authority_refused;
+
+ if (_settings.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 {
+ 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);
}
- if (num >= 2) {
+
+ if (authority_refused) {
SetDParam(0, t->index);
return_cmd_error(STR_2035_LOCAL_AUTHORITY_REFUSES);
}
- if (!_patches.adjacent_stations || !HasBit(p2, 0)) {
+ if (!_settings.station.adjacent_stations || !HasBit(p2, 0)) {
st = GetStationAround(tile, w, h, INVALID_STATION);
if (st == CHECK_STATIONS_ERR) return CMD_ERROR;
} else {
@@ -1693,6 +1791,9 @@
cost.AddCost(_price.build_airport * w * h);
if (flags & DC_EXEC) {
+ /* Always add the noise, so there will be no need to recalculate when option toggles */
+ st->town->noise_reached += newnoise_level;
+
st->airport_tile = tile;
st->AddFacility(FACIL_AIRPORT, tile);
st->airport_type = (byte)p1;
@@ -1722,6 +1823,10 @@
UpdateStationAcceptance(st, false);
InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_PLANES);
+
+ if (_settings.economy.station_noise_level) {
+ InvalidateWindow(WC_TOWN_VIEW, st->town->index);
+ }
}
return cost;
@@ -1764,12 +1869,22 @@
);
}
+ /* Go get the final noise level, that is base noise minus factor from distance to town center.
+ * And as for construction, always remove it, even if the patch is not set, in order to avoid the
+ * need of recalculation */
+ st->town->noise_reached -= GetAirportNoiseLevelForTown(afc, st->town->xy, tile);
+
st->rect.AfterRemoveRect(st, tile, w, h);
st->airport_tile = 0;
st->facilities &= ~FACIL_AIRPORT;
InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_PLANES);
+
+ if (_settings.economy.station_noise_level) {
+ InvalidateWindow(WC_TOWN_VIEW, st->town->index);
+ }
+
UpdateStationVirtCoordDirty(st);
DeleteStationIfEmpty(st);
}
@@ -1929,7 +2044,7 @@
/* middle */
Station *st = NULL;
- if (!_patches.adjacent_stations || !HasBit(p1, 0)) {
+ if (!_settings.station.adjacent_stations || !HasBit(p1, 0)) {
st = GetStationAround(
tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]),
_dock_w_chk[direction], _dock_h_chk[direction], INVALID_STATION);
@@ -2188,7 +2303,12 @@
static void GetTileDesc_Station(TileIndex tile, TileDesc *td)
{
- td->owner = GetTileOwner(tile);
+ td->owner[0] = GetTileOwner(tile);
+ if (IsDriveThroughStopTile(tile) && HasTileRoadType(tile, ROADTYPE_ROAD) && GetStopBuiltOnTownRoad(tile)) {
+ /* Display a second owner */
+ td->owner_type[1] = STR_ROAD_OWNER;
+ td->owner[1] = OWNER_TOWN;
+ }
td->build_date = GetStationByTile(tile)->build_date;
StringID str;
@@ -2654,7 +2774,7 @@
int w_prod; // width and height of the "producer" of the cargo
int h_prod;
int max_rad;
- if (_patches.modified_catchment) {
+ if (_settings.station.modified_catchment) {
w_prod = w;
h_prod = h;
w += 2 * MAX_CATCHMENT;
@@ -2677,7 +2797,7 @@
if (st->IsBuoy()) continue; // bouys don't accept cargo
- if (_patches.modified_catchment) {
+ if (_settings.station.modified_catchment) {
/* min and max coordinates of the producer relative */
const int x_min_prod = max_rad + 1;
const int x_max_prod = max_rad + w_prod;
@@ -2731,7 +2851,7 @@
if (st->goods[type].rating == 0) continue; // Lowest possible rating, better not to give cargo anymore
- if (_patches.selectgoods && st->goods[type].last_speed == 0) continue; // Selectively servicing stations, and not this one
+ if (_settings.order.selectgoods && st->goods[type].last_speed == 0) continue; // Selectively servicing stations, and not this one
if (IsCargoInClass(type, CC_PASSENGERS)) {
if (st->facilities == FACIL_TRUCK_STOP) continue; // passengers are never served by just a truck stop
@@ -2875,16 +2995,15 @@
* Road stops built on town-owned roads check the conditions
* that would allow clearing of the original road.
* @param tile road stop tile to check
+ * @param flags command flags
* @return true if the road can be cleared
*/
-static bool CanRemoveRoadWithStop(TileIndex tile)
+static bool CanRemoveRoadWithStop(TileIndex tile, uint32 flags)
{
/* The road can always be cleared if it was not a town-owned road */
if (!GetStopBuiltOnTownRoad(tile)) return true;
- bool edge_road;
- return CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, ROADTYPE_ROAD), OWNER_TOWN, &edge_road, ROADTYPE_ROAD) &&
- CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, ROADTYPE_TRAM), OWNER_TOWN, &edge_road, ROADTYPE_TRAM);
+ return CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, ROADTYPE_ROAD), OWNER_TOWN, ROADTYPE_ROAD, flags);
}
static CommandCost ClearTile_Station(TileIndex tile, byte flags)
@@ -2909,11 +3028,11 @@
case STATION_RAIL: return RemoveRailroadStation(st, tile, flags);
case STATION_AIRPORT: return RemoveAirport(st, flags);
case STATION_TRUCK:
- if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile))
+ if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags))
return_cmd_error(STR_3047_MUST_DEMOLISH_TRUCK_STATION);
return RemoveRoadStop(st, flags, tile);
case STATION_BUS:
- if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile))
+ if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags))
return_cmd_error(STR_3046_MUST_DEMOLISH_BUS_STATION);
return RemoveRoadStop(st, flags, tile);
case STATION_BUOY: return RemoveBuoy(st, flags);
@@ -2957,7 +3076,7 @@
static CommandCost TerraformTile_Station(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
{
- if (_patches.build_on_slopes && AutoslopeEnabled()) {
+ if (_settings.construction.build_on_slopes && AutoslopeEnabled()) {
/* TODO: If you implement newgrf callback 149 'land slope check', you have to decide what to do with it here.
* TTDP does not call it.
*/