From d3b7b89493e025654d218fb77da095649b4f6ba2 Mon Sep 17 00:00:00 2001 From: michi_cc Date: Sat, 3 Dec 2011 23:40:46 +0000 Subject: [PATCH] (svn r23415) -Feature: Infrastructure maintenance costs. --- src/company_gui.cpp | 86 ++++++++++++++++++++++++++++++++---- src/core/math_func.cpp | 30 +++++++++++++ src/core/math_func.hpp | 2 + src/economy.cpp | 34 +++++++++++--- src/economy_type.h | 5 +++ src/lang/english.txt | 3 ++ src/newgrf.cpp | 9 ++++ src/newgrf_airport.h | 1 + src/rail.h | 28 ++++++++++++ src/road_func.h | 14 ++++++ src/saveload/saveload.cpp | 3 +- src/settings.cpp | 11 +++++ src/settings_gui.cpp | 1 + src/settings_type.h | 1 + src/station.cpp | 19 ++++++++ src/station_func.h | 13 ++++++ src/table/airport_defaults.h | 34 +++++++------- src/table/pricebase.h | 5 +++ src/table/railtypes.h | 12 +++++ src/table/settings.ini | 9 ++++ src/water.h | 12 +++++ 21 files changed, 300 insertions(+), 32 deletions(-) diff --git a/src/company_gui.cpp b/src/company_gui.cpp index f200141003..20ff13667b 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -34,6 +34,9 @@ #include "rail.h" #include "engine_base.h" #include "window_func.h" +#include "road_func.h" +#include "water.h" +#include "station_func.h" #include "table/strings.h" @@ -1624,6 +1627,8 @@ enum CompanyInfrastructureWindowWidgets { CIW_WIDGET_WATER_COUNT, CIW_WIDGET_STATION_DESC, CIW_WIDGET_STATION_COUNT, + CIW_WIDGET_TOTAL_DESC, + CIW_WIDGET_TOTAL, }; static const NWidgetPart _nested_company_infrastructure_widgets[] = { @@ -1651,6 +1656,10 @@ static const NWidgetPart _nested_company_infrastructure_widgets[] = { NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_STATION_DESC), SetMinimalTextLines(3, 0), SetFill(1, 0), NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_STATION_COUNT), SetMinimalTextLines(3, 0), SetFill(0, 1), EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2), + NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_TOTAL_DESC), SetFill(1, 0), + NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_TOTAL), SetFill(0, 1), + EndContainer(), EndContainer(), EndContainer(), }; @@ -1663,6 +1672,8 @@ struct CompanyInfrastructureWindow : Window RailTypes railtypes; ///< Valid railtypes. RoadTypes roadtypes; ///< Valid roadtypes. + uint total_width; ///< String width of the total cost line. + CompanyInfrastructureWindow(const WindowDesc *desc, WindowNumber window_number) : Window() { this->UpdateRailRoadTypes(); @@ -1697,6 +1708,27 @@ struct CompanyInfrastructureWindow : Window } } + /** Get total infrastructure maintenance cost. */ + Money GetTotalMaintenanceCost() const + { + const Company *c = Company::Get((CompanyID)this->window_number); + Money total; + + for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { + if (HasBit(this->railtypes, rt)) total += RailMaintenanceCost(rt, c->infrastructure.rail[rt]); + } + total += SignalMaintenanceCost(c->infrastructure.signal); + + if (HasBit(this->roadtypes, ROADTYPE_ROAD)) total += RoadMaintenanceCost(ROADTYPE_ROAD, c->infrastructure.road[ROADTYPE_ROAD]); + if (HasBit(this->roadtypes, ROADTYPE_TRAM)) total += RoadMaintenanceCost(ROADTYPE_TRAM, c->infrastructure.road[ROADTYPE_TRAM]); + + total += CanalMaintenanceCost(c->infrastructure.water); + total += StationMaintenanceCost(c->infrastructure.station); + total += AirportMaintenanceCost(c->index); + + return total; + } + virtual void SetStringParameters(int widget) const { switch (widget) { @@ -1749,22 +1781,42 @@ struct CompanyInfrastructureWindow : Window case CIW_WIDGET_RAIL_COUNT: case CIW_WIDGET_ROAD_COUNT: case CIW_WIDGET_WATER_COUNT: - case CIW_WIDGET_STATION_COUNT: { + case CIW_WIDGET_STATION_COUNT: + case CIW_WIDGET_TOTAL: { /* Find the maximum count that is displayed. */ uint32 max_val = 100000; // Some random number to reserve enough space. + Money max_cost = 100000; // Some random number to reserve enough space. for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) { max_val = max(max_val, c->infrastructure.rail[rt]); + max_cost = max(max_cost, RailMaintenanceCost(rt, c->infrastructure.rail[rt])); } max_val = max(max_val, c->infrastructure.signal); + max_cost = max(max_cost, SignalMaintenanceCost(c->infrastructure.signal)); for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) { max_val = max(max_val, c->infrastructure.road[rt]); + max_cost = max(max_cost, RoadMaintenanceCost(rt, c->infrastructure.road[rt])); } max_val = max(max_val, c->infrastructure.water); + max_cost = max(max_cost, CanalMaintenanceCost(c->infrastructure.water)); max_val = max(max_val, c->infrastructure.station); + max_cost = max(max_cost, StationMaintenanceCost(c->infrastructure.station)); max_val = max(max_val, c->infrastructure.airport); + max_cost = max(max_cost, AirportMaintenanceCost(c->index)); SetDParam(0, max_val); - size->width = max(size->width, GetStringBoundingBox(STR_WHITE_COMMA).width + 15); // Reserve some wiggle room. + SetDParam(1, max_cost * 12); // Convert to per year + size->width = max(size->width, GetStringBoundingBox(_settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA).width + 20); // Reserve some wiggle room. + + if (_settings_game.economy.infrastructure_maintenance) { + SetDParam(0, this->GetTotalMaintenanceCost()); + this->total_width = GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL).width + 20; + size->width = max(size->width, this->total_width); + } + + /* Set height of the total line. */ + if (widget == CIW_WIDGET_TOTAL) { + size->height = _settings_game.economy.infrastructure_maintenance ? max(size->height, EXP_LINESPACE + FONT_HEIGHT_NORMAL) : 0; + } break; } } @@ -1803,12 +1855,14 @@ struct CompanyInfrastructureWindow : Window for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { if (HasBit(this->railtypes, rt)) { SetDParam(0, c->infrastructure.rail[rt]); - DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, STR_WHITE_COMMA); + SetDParam(1, RailMaintenanceCost(rt, c->infrastructure.rail[rt]) * 12); // Convert to per year + DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA); } } if (this->railtypes != RAILTYPES_NONE) { SetDParam(0, c->infrastructure.signal); - DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, STR_WHITE_COMMA); + SetDParam(1, SignalMaintenanceCost(c->infrastructure.signal) * 12); // Convert to per year + DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA); } break; @@ -1828,11 +1882,13 @@ struct CompanyInfrastructureWindow : Window case CIW_WIDGET_ROAD_COUNT: if (HasBit(this->roadtypes, ROADTYPE_ROAD)) { SetDParam(0, c->infrastructure.road[ROADTYPE_ROAD]); - DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, STR_WHITE_COMMA); + SetDParam(1, RoadMaintenanceCost(ROADTYPE_ROAD, c->infrastructure.road[ROADTYPE_ROAD]) * 12); // Convert to per year + DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA); } if (HasBit(this->roadtypes, ROADTYPE_TRAM)) { SetDParam(0, c->infrastructure.road[ROADTYPE_TRAM]); - DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, STR_WHITE_COMMA); + SetDParam(1, RoadMaintenanceCost(ROADTYPE_TRAM, c->infrastructure.road[ROADTYPE_TRAM]) * 12); // Convert to per year + DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA); } break; @@ -1843,7 +1899,17 @@ struct CompanyInfrastructureWindow : Window case CIW_WIDGET_WATER_COUNT: SetDParam(0, c->infrastructure.water); - DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, STR_WHITE_COMMA); + SetDParam(1, CanalMaintenanceCost(c->infrastructure.water) * 12); // Convert to per year + DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA); + break; + + case CIW_WIDGET_TOTAL: + if (_settings_game.economy.infrastructure_maintenance) { + GfxFillRect(r.left, y, r.left + this->total_width, y, PC_WHITE); + y += EXP_LINESPACE; + SetDParam(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year + DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL); + } break; case CIW_WIDGET_STATION_DESC: @@ -1854,9 +1920,11 @@ struct CompanyInfrastructureWindow : Window case CIW_WIDGET_STATION_COUNT: SetDParam(0, c->infrastructure.station); - DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, STR_WHITE_COMMA); + SetDParam(1, StationMaintenanceCost(c->infrastructure.station) * 12); // Convert to per year + DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA); SetDParam(0, c->infrastructure.airport); - DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, STR_WHITE_COMMA); + SetDParam(1, AirportMaintenanceCost(c->index) * 12); // Convert to per year + DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA); break; } } diff --git a/src/core/math_func.cpp b/src/core/math_func.cpp index 7f0630a97b..2b8ca33092 100644 --- a/src/core/math_func.cpp +++ b/src/core/math_func.cpp @@ -46,3 +46,33 @@ int GreatestCommonDivisor(int a, int b) return a; } + +/** + * Compute the integer square root. + * @param num Radicand. + * @return Rounded integer square root. + * @note Algorithm taken from http://en.wikipedia.org/wiki/Methods_of_computing_square_roots + */ +uint32 IntSqrt(uint32 num) +{ + uint32 res = 0; + uint32 bit = 1UL << 30; // Second to top bit number. + + /* 'bit' starts at the highest power of four <= the argument. */ + while (bit > num) bit >>= 2; + + while (bit != 0) { + if (num >= res + bit) { + num -= res + bit; + res = (res >> 1) + bit; + } else { + res >>= 1; + } + bit >>= 2; + } + + /* Arithmetic rounding to nearest integer. */ + if (num > res) res++; + + return res; +} diff --git a/src/core/math_func.hpp b/src/core/math_func.hpp index 19f2f53d65..92893ed318 100644 --- a/src/core/math_func.hpp +++ b/src/core/math_func.hpp @@ -346,4 +346,6 @@ static FORCEINLINE int RoundDivSU(int a, uint b) } } +uint32 IntSqrt(uint32 num); + #endif /* MATH_FUNC_HPP */ diff --git a/src/economy.cpp b/src/economy.cpp index ada4fc2272..9fa2e11de7 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -46,6 +46,7 @@ #include "core/pool_func.hpp" #include "newgrf.h" #include "core/backup_type.hpp" +#include "water.h" #include "table/strings.h" #include "table/pricebase.h" @@ -584,17 +585,39 @@ static void CompaniesGenStatistics() Station *st; Backup cur_company(_current_company, FILE_LINE); - FOR_ALL_STATIONS(st) { - cur_company.Change(st->owner); - CommandCost cost(EXPENSES_PROPERTY, _price[PR_STATION_VALUE] >> 1); - SubtractMoneyFromCompany(cost); + Company *c; + + if (!_settings_game.economy.infrastructure_maintenance) { + FOR_ALL_STATIONS(st) { + cur_company.Change(st->owner); + CommandCost cost(EXPENSES_PROPERTY, _price[PR_STATION_VALUE] >> 1); + SubtractMoneyFromCompany(cost); + } + } else { + /* Improved monthly infrastructure costs. */ + FOR_ALL_COMPANIES(c) { + cur_company.Change(c->index); + + CommandCost cost(EXPENSES_PROPERTY); + for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) { + if (c->infrastructure.rail[rt] != 0) cost.AddCost(RailMaintenanceCost(rt, c->infrastructure.rail[rt])); + } + cost.AddCost(SignalMaintenanceCost(c->infrastructure.signal)); + for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) { + if (c->infrastructure.road[rt] != 0) cost.AddCost(RoadMaintenanceCost(rt, c->infrastructure.road[rt])); + } + cost.AddCost(CanalMaintenanceCost(c->infrastructure.water)); + cost.AddCost(StationMaintenanceCost(c->infrastructure.station)); + cost.AddCost(AirportMaintenanceCost(c->index)); + + SubtractMoneyFromCompany(cost); + } } cur_company.Restore(); /* Only run the economic statics and update company stats every 3rd month (1st of quarter). */ if (!HasBit(1 << 0 | 1 << 3 | 1 << 6 | 1 << 9, _cur_month)) return; - Company *c; FOR_ALL_COMPANIES(c) { memmove(&c->old_economy[1], &c->old_economy[0], sizeof(c->old_economy) - sizeof(c->old_economy[0])); c->old_economy[0] = c->cur_economy; @@ -713,6 +736,7 @@ void RecomputePrices() SetWindowClassesDirty(WC_BUILD_VEHICLE); SetWindowClassesDirty(WC_REPLACE_VEHICLE); SetWindowClassesDirty(WC_VEHICLE_DETAILS); + SetWindowClassesDirty(WC_COMPANY_INFRASTRUCTURE); InvalidateWindowData(WC_PAYMENT_RATES, 0); } diff --git a/src/economy_type.h b/src/economy_type.h index 644bb6a557..82a4e2cfac 100644 --- a/src/economy_type.h +++ b/src/economy_type.h @@ -132,6 +132,11 @@ enum Price { PR_CLEAR_AQUEDUCT, PR_BUILD_LOCK, PR_CLEAR_LOCK, + PR_INFRASTRUCTURE_RAIL, + PR_INFRASTRUCTURE_ROAD, + PR_INFRASTRUCTURE_WATER, + PR_INFRASTRUCTURE_STATION, + PR_INFRASTRUCTURE_AIRPORT, PR_END, INVALID_PRICE = 0xFF diff --git a/src/lang/english.txt b/src/lang/english.txt index 96d67d4200..cc80abe3d3 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1156,6 +1156,7 @@ STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD :{LTBLUE}Allow d STR_CONFIG_SETTING_ADJACENT_STATIONS :{LTBLUE}Allow building adjacent stations: {ORANGE}{STRING} STR_CONFIG_SETTING_DYNAMIC_ENGINES :{LTBLUE}Enable multiple NewGRF engine sets: {ORANGE}{STRING} STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Changing this setting is not possible when there are vehicles +STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :{LTBLUE}Infrastructure maintenance: {ORANGE}{STRING1} STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :{LTBLUE}Airports never expire: {ORANGE}{STRING1} @@ -2788,6 +2789,8 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canals STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stations: STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}Station tiles STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS :{WHITE}Airports +STR_COMPANY_INFRASTRUCTURE_VIEW_COST :{WHITE}{1:CURRENCY_LONG}/yr ({0:COMMA}) +STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENCY_LONG}/yr # Industry directory STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}Industries diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 5a2175737f..49e8cf3eb0 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -3635,6 +3635,10 @@ static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, B _string_to_grf_mapping[&as->name] = _cur.grffile->grfid; break; + case 0x11: // Maintenance cost factor + as->maintenance_cost = buf->ReadWord(); + break; + default: ret = CIR_UNKNOWN; break; @@ -3941,6 +3945,10 @@ static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteR _string_to_grf_mapping[&rti->strings.name] = _cur.grffile->grfid; break; + case 0x1C: // Maintenance cost factor + rti->maintenance_multiplier = buf->ReadWord(); + break; + default: ret = CIR_UNKNOWN; break; @@ -3984,6 +3992,7 @@ static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, Byte case 0x13: // Construction cost case 0x14: // Speed limit case 0x1B: // Name of railtype + case 0x1C: // Maintenance cost factor buf->ReadWord(); break; diff --git a/src/newgrf_airport.h b/src/newgrf_airport.h index d0ec38c05d..b00c3667c2 100644 --- a/src/newgrf_airport.h +++ b/src/newgrf_airport.h @@ -76,6 +76,7 @@ struct AirportSpec { TTDPAirportType ttd_airport_type; ///< ttdpatch airport type (Small/Large/Helipad/Oilrig) AirportClassID cls_id; ///< the class to which this airport type belongs SpriteID preview_sprite; ///< preview sprite for this airport + uint16 maintenance_cost; ///< maintenance cost mulltiplier /* Newgrf data */ bool enabled; ///< entity still avaible (by default true).newgrf can disable it, though struct GRFFileProps grf_prop; ///< properties related the the grf file diff --git a/src/rail.h b/src/rail.h index 54b5c27b61..43672d058b 100644 --- a/src/rail.h +++ b/src/rail.h @@ -20,6 +20,7 @@ #include "slope_type.h" #include "strings_type.h" #include "date_type.h" +#include "core/math_func.hpp" /** Railtype flags. */ enum RailTypeFlags { @@ -188,6 +189,11 @@ struct RailtypeInfo { */ uint16 cost_multiplier; + /** + * Cost multiplier for maintenance of this rail type + */ + uint16 maintenance_multiplier; + /** * Acceleration type of this rail type */ @@ -363,6 +369,28 @@ static inline Money RailConvertCost(RailType from, RailType to) return rebuildcost; } +/** + * Calculates the maintenance cost of a number of track bits. + * @param railtype The railtype to get the cost of. + * @param num Number of track bits. + * @return Total cost. + */ +static inline Money RailMaintenanceCost(RailType railtype, uint32 num) +{ + assert(railtype < RAILTYPE_END); + return (_price[PR_INFRASTRUCTURE_RAIL] * GetRailTypeInfo(railtype)->maintenance_multiplier * num * (1 + IntSqrt(num))) >> 11; // 4 bits fraction for the multiplier and 7 bits scaling. +} + +/** + * Calculates the maintenance cost of a number of signals. + * @param num Number of signals. + * @return Total cost. + */ +static inline Money SignalMaintenanceCost(uint32 num) +{ + return (_price[PR_INFRASTRUCTURE_RAIL] * 15 * num * (1 + IntSqrt(num))) >> 8; // 1 bit fraction for the multiplier and 7 bits scaling. +} + void DrawTrainDepotSprite(int x, int y, int image, RailType railtype); int TicksToLeaveDepot(const Train *v); diff --git a/src/road_func.h b/src/road_func.h index 2f286730f4..126ab5c821 100644 --- a/src/road_func.h +++ b/src/road_func.h @@ -17,6 +17,7 @@ #include "direction_type.h" #include "company_type.h" #include "tile_type.h" +#include "economy_func.h" /** * Iterate through each set RoadType in a RoadTypes value. @@ -148,6 +149,19 @@ static inline RoadBits AxisToRoadBits(Axis a) return a == AXIS_X ? ROAD_X : ROAD_Y; } + +/** + * Calculates the maintenance cost of a number of road bits. + * @param roadtype Road type to get the cost for. + * @param num Number of road bits. + * @return Total cost. + */ +static inline Money RoadMaintenanceCost(RoadType roadtype, uint32 num) +{ + assert(roadtype < ROADTYPE_END); + return (_price[PR_INFRASTRUCTURE_ROAD] * (roadtype == ROADTYPE_TRAM ? 3 : 2) * num * (1 + IntSqrt(num))) >> 9; // 2 bits fraction for the multiplier and 7 bits scaling. +} + bool HasRoadTypesAvail(const CompanyID company, const RoadTypes rts); bool ValParamRoadType(const RoadType rt); RoadTypes GetCompanyRoadtypes(const CompanyID company); diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 8de4773a34..c603f58436 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -230,8 +230,9 @@ * 163 22767 * 164 23290 * 165 23304 + * 166 23415 */ -extern const uint16 SAVEGAME_VERSION = 165; ///< Current savegame version of OpenTTD. +extern const uint16 SAVEGAME_VERSION = 166; ///< Current savegame version of OpenTTD. SavegameType _savegame_type; ///< type of savegame we are loading diff --git a/src/settings.cpp b/src/settings.cpp index 8a9d0548a4..a72bf58749 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -946,6 +946,17 @@ static bool RedrawTownAuthority(int32 p1) return true; } +/** + * Invalidate the company infrastructure details window after a infrastructure maintenance setting change. + * @param p1 Unused. + * @return Always true. + */ +static bool InvalidateCompanyInfrastructureWindow(int32 p1) +{ + InvalidateWindowClassesData(WC_COMPANY_INFRASTRUCTURE); + return true; +} + /* * A: competitors * B: competitor start time. Deprecated since savegame version 110. diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index c11e220937..4a4282ea77 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1492,6 +1492,7 @@ static SettingEntry _settings_economy[] = { SettingEntry("economy.inflation"), SettingEntry("economy.smooth_economy"), SettingEntry("economy.feeder_payment_share"), + SettingEntry("economy.infrastructure_maintenance"), }; /** Economy sub-page */ static SettingsPage _settings_economy_page = {_settings_economy, lengthof(_settings_economy)}; diff --git a/src/settings_type.h b/src/settings_type.h index b1d6228441..6562cb3653 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -416,6 +416,7 @@ struct EconomySettings { bool station_noise_level; ///< build new airports when the town noise level is still within accepted limits uint16 town_noise_population[3]; ///< population to base decision on noise evaluation (@see town_council_tolerance) bool allow_town_level_crossings; ///< towns are allowed to build level crossings + bool infrastructure_maintenance; ///< enable monthly maintenance fee for owner infrastructure }; /** Settings related to stations. */ diff --git a/src/station.cpp b/src/station.cpp index a3df6fe74d..5fc2bbdf5a 100644 --- a/src/station.cpp +++ b/src/station.cpp @@ -523,3 +523,22 @@ StationRect& StationRect::operator = (const Rect &src) this->bottom = src.bottom; return *this; } + +/** + * Calculates the maintenance cost of all airports of a company. + * @param owner Company. + * @return Total cost. + */ +Money AirportMaintenanceCost(Owner owner) +{ + Money total_cost = 0; + + const Station *st; + FOR_ALL_STATIONS(st) { + if (st->owner == owner && (st->facilities & FACIL_AIRPORT)) { + total_cost += _price[PR_INFRASTRUCTURE_AIRPORT] * st->airport.GetSpec()->maintenance_cost; + } + } + /* 3 bits fraction for the maintenance cost factor. */ + return total_cost >> 3; +} diff --git a/src/station_func.h b/src/station_func.h index 0fe5b2f848..8f29017454 100644 --- a/src/station_func.h +++ b/src/station_func.h @@ -18,6 +18,7 @@ #include "road_type.h" #include "cargo_type.h" #include "company_type.h" +#include "economy_func.h" void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius); @@ -46,4 +47,16 @@ bool IsStationTileElectrifiable(TileIndex tile); void UpdateAirportsNoise(); +/** + * Calculates the maintenance cost of a number of station tiles. + * @param num Number of station tiles. + * @return Total cost. + */ +static inline Money StationMaintenanceCost(uint32 num) +{ + return (_price[PR_INFRASTRUCTURE_STATION] * num * (1 + IntSqrt(num))) >> 7; // 7 bits scaling. +} + +Money AirportMaintenanceCost(Owner owner); + #endif /* STATION_FUNC_H */ diff --git a/src/table/airport_defaults.h b/src/table/airport_defaults.h index f4b4cd4beb..01a55ce89e 100644 --- a/src/table/airport_defaults.h +++ b/src/table/airport_defaults.h @@ -381,36 +381,36 @@ static Direction _default_airports_rotation[] = { #undef MKEND /** General AirportSpec definition. */ -#define AS_GENERIC(fsm, att, rot, att_len, depot_tbl, num_depots, size_x, size_y, noise, catchment, min_year, max_year, ttdpatch_type, class_id, name, preview, enabled) \ - {fsm, att, rot, att_len, depot_tbl, num_depots, size_x, size_y, noise, catchment, min_year, max_year, name, ttdpatch_type, class_id, preview, enabled, GRFFileProps(AT_INVALID)} +#define AS_GENERIC(fsm, att, rot, att_len, depot_tbl, num_depots, size_x, size_y, noise, catchment, min_year, max_year, maint_cost, ttdpatch_type, class_id, name, preview, enabled) \ + {fsm, att, rot, att_len, depot_tbl, num_depots, size_x, size_y, noise, catchment, min_year, max_year, name, ttdpatch_type, class_id, preview, maint_cost, enabled, GRFFileProps(AT_INVALID)} /** AirportSpec definition for airports without any depot. */ -#define AS_ND(ap_name, size_x, size_y, min_year, max_year, catchment, noise, ttdpatch_type, class_id, name, preview) \ +#define AS_ND(ap_name, size_x, size_y, min_year, max_year, catchment, noise, maint_cost, ttdpatch_type, class_id, name, preview) \ AS_GENERIC(&_airportfta_##ap_name, _tile_table_##ap_name, _default_airports_rotation, lengthof(_tile_table_##ap_name), NULL, 0, \ - size_x, size_y, noise, catchment, min_year, max_year, ttdpatch_type, class_id, name, preview, true) + size_x, size_y, noise, catchment, min_year, max_year, maint_cost, ttdpatch_type, class_id, name, preview, true) /** AirportSpec definition for airports with at least one depot. */ -#define AS(ap_name, size_x, size_y, min_year, max_year, catchment, noise, ttdpatch_type, class_id, name, preview) \ +#define AS(ap_name, size_x, size_y, min_year, max_year, catchment, noise, maint_cost, ttdpatch_type, class_id, name, preview) \ AS_GENERIC(&_airportfta_##ap_name, _tile_table_##ap_name, _default_airports_rotation, lengthof(_tile_table_##ap_name), _airport_depots_##ap_name, lengthof(_airport_depots_##ap_name), \ - size_x, size_y, noise, catchment, min_year, max_year, ttdpatch_type, class_id, name, preview, true) + size_x, size_y, noise, catchment, min_year, max_year, maint_cost, ttdpatch_type, class_id, name, preview, true) /* The helidepot and helistation have ATP_TTDP_SMALL because they are at ground level */ extern const AirportSpec _origin_airport_specs[] = { - AS(country, 4, 3, 0, 1959, 4, 3, ATP_TTDP_SMALL, APC_SMALL, STR_AIRPORT_SMALL, SPR_AIRPORT_PREVIEW_SMALL), - AS(city, 6, 6, 1955, MAX_YEAR, 5, 5, ATP_TTDP_LARGE, APC_LARGE, STR_AIRPORT_CITY, SPR_AIRPORT_PREVIEW_LARGE), - AS_ND(heliport, 1, 1, 1963, MAX_YEAR, 4, 1, ATP_TTDP_HELIPORT, APC_HELIPORT, STR_AIRPORT_HELIPORT, SPR_AIRPORT_PREVIEW_HELIPORT), - AS(metropolitan, 6, 6, 1980, MAX_YEAR, 6, 8, ATP_TTDP_LARGE, APC_LARGE, STR_AIRPORT_METRO, SPR_AIRPORT_PREVIEW_METROPOLITAN), - AS(international, 7, 7, 1990, MAX_YEAR, 8, 17, ATP_TTDP_LARGE, APC_HUB, STR_AIRPORT_INTERNATIONAL, SPR_AIRPORT_PREVIEW_INTERNATIONAL), - AS(commuter, 5, 4, 1983, MAX_YEAR, 4, 4, ATP_TTDP_SMALL, APC_SMALL, STR_AIRPORT_COMMUTER, SPR_AIRPORT_PREVIEW_COMMUTER), - AS(helidepot, 2, 2, 1976, MAX_YEAR, 4, 2, ATP_TTDP_SMALL, APC_HELIPORT, STR_AIRPORT_HELIDEPOT, SPR_AIRPORT_PREVIEW_HELIDEPOT), - AS(intercontinental, 9, 11, 2002, MAX_YEAR, 10, 25, ATP_TTDP_LARGE, APC_HUB, STR_AIRPORT_INTERCONTINENTAL, SPR_AIRPORT_PREVIEW_INTERCONTINENTAL), - AS(helistation, 4, 2, 1980, MAX_YEAR, 4, 3, ATP_TTDP_SMALL, APC_HELIPORT, STR_AIRPORT_HELISTATION, SPR_AIRPORT_PREVIEW_HELISTATION), - AS_GENERIC(&_airportfta_oilrig, NULL, _default_airports_rotation, 0, NULL, 0, 1, 1, 0, 4, 0, 0, ATP_TTDP_OILRIG, APC_HELIPORT, STR_NULL, 0, false), + AS(country, 4, 3, 0, 1959, 4, 3, 7, ATP_TTDP_SMALL, APC_SMALL, STR_AIRPORT_SMALL, SPR_AIRPORT_PREVIEW_SMALL), + AS(city, 6, 6, 1955, MAX_YEAR, 5, 5, 24, ATP_TTDP_LARGE, APC_LARGE, STR_AIRPORT_CITY, SPR_AIRPORT_PREVIEW_LARGE), + AS_ND(heliport, 1, 1, 1963, MAX_YEAR, 4, 1, 4, ATP_TTDP_HELIPORT, APC_HELIPORT, STR_AIRPORT_HELIPORT, SPR_AIRPORT_PREVIEW_HELIPORT), + AS(metropolitan, 6, 6, 1980, MAX_YEAR, 6, 8, 28, ATP_TTDP_LARGE, APC_LARGE, STR_AIRPORT_METRO, SPR_AIRPORT_PREVIEW_METROPOLITAN), + AS(international, 7, 7, 1990, MAX_YEAR, 8, 17, 42, ATP_TTDP_LARGE, APC_HUB, STR_AIRPORT_INTERNATIONAL, SPR_AIRPORT_PREVIEW_INTERNATIONAL), + AS(commuter, 5, 4, 1983, MAX_YEAR, 4, 4, 20, ATP_TTDP_SMALL, APC_SMALL, STR_AIRPORT_COMMUTER, SPR_AIRPORT_PREVIEW_COMMUTER), + AS(helidepot, 2, 2, 1976, MAX_YEAR, 4, 2, 7, ATP_TTDP_SMALL, APC_HELIPORT, STR_AIRPORT_HELIDEPOT, SPR_AIRPORT_PREVIEW_HELIDEPOT), + AS(intercontinental, 9, 11, 2002, MAX_YEAR, 10, 25, 72, ATP_TTDP_LARGE, APC_HUB, STR_AIRPORT_INTERCONTINENTAL, SPR_AIRPORT_PREVIEW_INTERCONTINENTAL), + AS(helistation, 4, 2, 1980, MAX_YEAR, 4, 3, 14, ATP_TTDP_SMALL, APC_HELIPORT, STR_AIRPORT_HELISTATION, SPR_AIRPORT_PREVIEW_HELISTATION), + AS_GENERIC(&_airportfta_oilrig, NULL, _default_airports_rotation, 0, NULL, 0, 1, 1, 0, 4, 0, 0, 0, ATP_TTDP_OILRIG, APC_HELIPORT, STR_NULL, 0, false), }; assert_compile(NEW_AIRPORT_OFFSET == lengthof(_origin_airport_specs)); -AirportSpec AirportSpec::dummy = AS_GENERIC(&_airportfta_dummy, NULL, _default_airports_rotation, 0, NULL, 0, 0, 0, 0, 0, MIN_YEAR, MIN_YEAR, ATP_TTDP_LARGE, APC_BEGIN, STR_NULL, 0, false); +AirportSpec AirportSpec::dummy = AS_GENERIC(&_airportfta_dummy, NULL, _default_airports_rotation, 0, NULL, 0, 0, 0, 0, 0, MIN_YEAR, MIN_YEAR, 0, ATP_TTDP_LARGE, APC_BEGIN, STR_NULL, 0, false); #undef AS #undef AS_ND diff --git a/src/table/pricebase.h b/src/table/pricebase.h index 84d23b3bd7..ee62e9faf7 100644 --- a/src/table/pricebase.h +++ b/src/table/pricebase.h @@ -76,5 +76,10 @@ extern const PriceBaseSpec _price_base_specs[] = { { 2000, PCAT_CONSTRUCTION, GSF_END, PR_CLEAR_BRIDGE }, ///< PR_CLEAR_AQUEDUCT { 7500, PCAT_CONSTRUCTION, GSF_END, PR_CLEAR_WATER }, ///< PR_BUILD_LOCK { 2000, PCAT_CONSTRUCTION, GSF_END, PR_CLEAR_WATER }, ///< PR_CLEAR_LOCK + { 12, PCAT_RUNNING, GSF_END, PR_BUILD_RAIL }, ///< PR_INFRASTRUCTURE_RAIL + { 10, PCAT_RUNNING, GSF_END, PR_BUILD_ROAD }, ///< PR_INFRASTRUCTURE_ROAD + { 8, PCAT_RUNNING, GSF_END, PR_BUILD_CANAL }, ///< PR_INFRASTRUCTURE_WATER + { 100, PCAT_RUNNING, GSF_END, PR_STATION_VALUE }, ///< PR_INFRASTRUCTURE_STATION + { 5000, PCAT_RUNNING, GSF_END, PR_BUILD_STATION_AIRPORT}, ///< PR_INFRASTRUCTURE_AIRPORT }; assert_compile(lengthof(_price_base_specs) == PR_END); diff --git a/src/table/railtypes.h b/src/table/railtypes.h index 39e2b28626..065f78720e 100644 --- a/src/table/railtypes.h +++ b/src/table/railtypes.h @@ -81,6 +81,9 @@ static const RailtypeInfo _original_railtypes[] = { /* cost multiplier */ 8, + /* maintenance cost multiplier */ + 8, + /* acceleration type */ 0, @@ -175,6 +178,9 @@ static const RailtypeInfo _original_railtypes[] = { /* cost multiplier */ 12, + /* maintenance cost multiplier */ + 12, + /* acceleration type */ 0, @@ -265,6 +271,9 @@ static const RailtypeInfo _original_railtypes[] = { /* cost multiplier */ 16, + /* maintenance cost multiplier */ + 16, + /* acceleration type */ 1, @@ -355,6 +364,9 @@ static const RailtypeInfo _original_railtypes[] = { /* cost multiplier */ 24, + /* maintenance cost multiplier */ + 24, + /* acceleration type */ 2, diff --git a/src/table/settings.ini b/src/table/settings.ini index 48dc333bb7..965eaeb17e 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -39,6 +39,7 @@ static bool InvalidateNewGRFChangeWindows(int32 p1); static bool InvalidateIndustryViewWindow(int32 p1); static bool InvalidateAISettingsWindow(int32 p1); static bool RedrawTownAuthority(int32 p1); +static bool InvalidateCompanyInfrastructureWindow(int32 p1); extern bool UpdateNewGRFConfigPalette(int32 p1); static bool ZoomMinMaxChanged(int32 p1); @@ -1237,6 +1238,14 @@ def = 4000 min = 800 max = 65535 +[SDT_BOOL] +base = GameSettings +var = economy.infrastructure_maintenance +from = 166 +def = false +str = STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE +proc = InvalidateCompanyInfrastructureWindow + ## [SDT_VAR] base = GameSettings diff --git a/src/water.h b/src/water.h index 56bd92fde1..bf26cf90dd 100644 --- a/src/water.h +++ b/src/water.h @@ -16,6 +16,8 @@ #include "company_type.h" #include "slope_type.h" #include "water_map.h" +#include "economy_func.h" +#include "core/math_func.hpp" /** * Describes the behaviour of a tile during flooding. @@ -43,4 +45,14 @@ void MakeWaterKeepingClass(TileIndex tile, Owner o); bool RiverModifyDesertZone(TileIndex tile, void *data); +/** + * Calculates the maintenance cost of a number of canal tiles. + * @param num Number of canal tiles. + * @return Total cost. + */ +static inline Money CanalMaintenanceCost(uint32 num) +{ + return (_price[PR_INFRASTRUCTURE_WATER] * num * (1 + IntSqrt(num))) >> 6; // 6 bits scaling. +} + #endif /* WATER_H */