summaryrefslogtreecommitdiff
path: root/src/station_cmd.cpp
diff options
context:
space:
mode:
authorbelugas <belugas@openttd.org>2008-05-24 02:54:47 +0000
committerbelugas <belugas@openttd.org>2008-05-24 02:54:47 +0000
commitfc35ad9ee9077869ab7b5a06b44327c835df3e5f (patch)
tree6e9667beb04ac4a18b43294a74456ab52a123a5a /src/station_cmd.cpp
parent6f233b1f8f18beb1e347c943685f6086d886993e (diff)
downloadopenttd-fc35ad9ee9077869ab7b5a06b44327c835df3e5f.tar.xz
(svn r13226) -Feature: Allow to have more than only two airports per town. The number of airports is now controlled by the noise each of them generates, the distance from town's center and how tolerant the town is.
Initial concept : TTDPatch (moreairpots), Initial code : Pasky Thanks to BigBB (help coding), Smatz Skidd13 and frosch for bugcatches and advices
Diffstat (limited to 'src/station_cmd.cpp')
-rw-r--r--src/station_cmd.cpp122
1 files changed, 117 insertions, 5 deletions
diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp
index 2cc60b4ef..0fe4bebf2 100644
--- a/src/station_cmd.cpp
+++ b/src/station_cmd.cpp
@@ -1610,6 +1610,88 @@ static const byte * const _airport_sections[] = {
_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 + (_opt.diff.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
@@ -1641,12 +1723,25 @@ CommandCost CmdBuildAirport(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
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 autority_refused;
+
+ if (_patches.station_noise_level) {
+ /* do not allow to build a new airport if this raise the town noise over the maximum allowed by town */
+ autority_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++;
+ }
+ autority_refused = (num >= 2);
}
- if (num >= 2) {
+
+ if (autority_refused) {
SetDParam(0, t->index);
return_cmd_error(STR_2035_LOCAL_AUTHORITY_REFUSES);
}
@@ -1693,6 +1788,9 @@ CommandCost CmdBuildAirport(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
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 +1820,10 @@ CommandCost CmdBuildAirport(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
UpdateStationAcceptance(st, false);
InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_PLANES);
+
+ if (_patches.station_noise_level) {
+ InvalidateWindow(WC_TOWN_VIEW, st->town->index);
+ }
}
return cost;
@@ -1764,12 +1866,22 @@ static CommandCost RemoveAirport(Station *st, uint32 flags)
);
}
+ /* 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 (_patches.station_noise_level) {
+ InvalidateWindow(WC_TOWN_VIEW, st->town->index);
+ }
+
UpdateStationVirtCoordDirty(st);
DeleteStationIfEmpty(st);
}