Skip to content

Commit

Permalink
Feature: Configurable subsidy duration
Browse files Browse the repository at this point in the history
  • Loading branch information
2TallTyler committed Apr 22, 2021
1 parent 9fa38f5 commit 898752b
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 27 deletions.
16 changes: 11 additions & 5 deletions src/lang/english.txt
Expand Up @@ -883,11 +883,15 @@ STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION

STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Offer of subsidy expired:{}{}{STRING} from {STRING2} to {STRING2} will now not attract a subsidy
STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subsidy withdrawn:{}{}{STRING} service from {STRING2} to {STRING2} is no longer subsidised
STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Service subsidy offered:{}{}First {STRING} service from {STRING2} to {STRING2} will attract a year's subsidy from the local authority!
STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay 50% extra for the next year!
STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay double rates for the next year!
STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay triple rates for the next year!
STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay quadruple rates for the next year!
STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Service subsidy offered:{}{}First {STRING} service from {STRING2} to {STRING2} will attract a {STRING2} subsidy from the local authority!
STR_NEWS_SERVICE_SUBSIDY_OFFERED_ONE_YEAR :year's
STR_NEWS_SERVICE_SUBSIDY_OFFERED_MULTI_YEAR :{NUM} year
STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay 50% extra for the next {STRING2}!
STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay double rates for the next {STRING2}!
STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay triple rates for the next {STRING2}!
STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay quadruple rates for the next {STRING2}!
STR_NEWS_SERVICE_SUBSIDY_AWARDED_ONE_YEAR :year
STR_NEWS_SERVICE_SUBSIDY_AWARDED_MULTI_YEAR :{NUM} years

STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}Traffic chaos in {TOWN}!{}{}Road rebuilding programme funded by {RAW_STRING} brings 6 months of misery to motorists!
STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}Transport monopoly!
Expand Down Expand Up @@ -1202,6 +1206,8 @@ STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Vehicle breakdo
STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT :Control how often inadequately serviced vehicles may break down
STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :Subsidy multiplier: {STRING2}
STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Set how much is paid for subsidised connections
STR_CONFIG_SETTING_SUBSIDY_DURATION :Subsidy duration: {STRING2}
STR_CONFIG_SETTING_SUBSIDY_DURATION_HELPTEXT :Set the number of years for which a subsidy is awarded. Set to 0 to disable subsidies.
STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Construction costs: {STRING2}
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Set level of construction and purchase costs
STR_CONFIG_SETTING_RECESSIONS :Recessions: {STRING2}
Expand Down
1 change: 1 addition & 0 deletions src/saveload/saveload.h
Expand Up @@ -325,6 +325,7 @@ enum SaveLoadVersion : uint16 {
SLV_VEH_MOTION_COUNTER, ///< 288 PR#8591 Desync safe motion counter
SLV_INDUSTRY_TEXT, ///< 289 PR#8576 v1.11.0-RC1 Additional GS text for industries.
SLV_MAPGEN_SETTINGS_REVAMP, ///< 290 PR#8891 v1.11 Revamp of some mapgen settings (snow coverage, desert coverage, heightmap height, custom terrain type).
SLV_CUSTOM_SUBSIDY_DURATION, ///< 291 PR#9081 Configurable subsidy duration.

SL_MAX_VERSION, ///< Highest possible saveload version
};
Expand Down
17 changes: 9 additions & 8 deletions src/saveload/subsidy_sl.cpp
Expand Up @@ -16,14 +16,15 @@

static const SaveLoad _subsidies_desc[] = {
SLE_VAR(Subsidy, cargo_type, SLE_UINT8),
SLE_VAR(Subsidy, remaining, SLE_UINT8),
SLE_CONDVAR(Subsidy, awarded, SLE_UINT8, SLV_125, SL_MAX_VERSION),
SLE_CONDVAR(Subsidy, src_type, SLE_UINT8, SLV_125, SL_MAX_VERSION),
SLE_CONDVAR(Subsidy, dst_type, SLE_UINT8, SLV_125, SL_MAX_VERSION),
SLE_CONDVAR(Subsidy, src, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5),
SLE_CONDVAR(Subsidy, src, SLE_UINT16, SLV_5, SL_MAX_VERSION),
SLE_CONDVAR(Subsidy, dst, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5),
SLE_CONDVAR(Subsidy, dst, SLE_UINT16, SLV_5, SL_MAX_VERSION),
SLE_VAR(Subsidy, remaining, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_CUSTOM_SUBSIDY_DURATION),
SLE_CONDVAR(Subsidy, remaining, SLE_UINT16, SLV_CUSTOM_SUBSIDY_DURATION, SL_MAX_VERSION),
SLE_CONDVAR(Subsidy, awarded, SLE_UINT8, SLV_125, SL_MAX_VERSION),
SLE_CONDVAR(Subsidy, src_type, SLE_UINT8, SLV_125, SL_MAX_VERSION),
SLE_CONDVAR(Subsidy, dst_type, SLE_UINT8, SLV_125, SL_MAX_VERSION),
SLE_CONDVAR(Subsidy, src, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5),
SLE_CONDVAR(Subsidy, src, SLE_UINT16, SLV_5, SL_MAX_VERSION),
SLE_CONDVAR(Subsidy, dst, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5),
SLE_CONDVAR(Subsidy, dst, SLE_UINT16, SLV_5, SL_MAX_VERSION),
SLE_END()
};

Expand Down
1 change: 1 addition & 0 deletions src/settings_gui.cpp
Expand Up @@ -1707,6 +1707,7 @@ static SettingsContainer &GetSettingsTree()
accounting->Add(new SettingEntry("difficulty.initial_interest"));
accounting->Add(new SettingEntry("difficulty.max_loan"));
accounting->Add(new SettingEntry("difficulty.subsidy_multiplier"));
accounting->Add(new SettingEntry("difficulty.subsidy_duration"));
accounting->Add(new SettingEntry("economy.feeder_payment_share"));
accounting->Add(new SettingEntry("economy.infrastructure_maintenance"));
accounting->Add(new SettingEntry("difficulty.vehicle_costs"));
Expand Down
3 changes: 2 additions & 1 deletion src/settings_type.h
Expand Up @@ -69,7 +69,8 @@ struct DifficultySettings {
byte vehicle_costs; ///< amount of money spent on vehicle running cost
byte competitor_speed; ///< the speed at which the AI builds
byte vehicle_breakdowns; ///< likelihood of vehicles breaking down
byte subsidy_multiplier; ///< amount of subsidy
byte subsidy_multiplier; ///< payment multiplier for subsidized deliveries
byte subsidy_duration; ///< duration of subsidies
byte construction_cost; ///< how expensive is building
byte terrain_type; ///< the mountainousness of the landscape
byte quantity_sea_lakes; ///< the amount of seas/lakes
Expand Down
43 changes: 35 additions & 8 deletions src/subsidy.cpp
Expand Up @@ -41,7 +41,7 @@ void Subsidy::AwardTo(CompanyID company)
assert(!this->IsAwarded());

this->awarded = company;
this->remaining = SUBSIDY_CONTRACT_MONTHS;
this->remaining = _settings_game.difficulty.subsidy_duration * 12;

char company_name[MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH];
SetDParam(0, company);
Expand All @@ -50,7 +50,7 @@ void Subsidy::AwardTo(CompanyID company)
char *cn = stredup(company_name);

/* Add a news item */
std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(this, false);
std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(this, SUBSIDY_NEWS_AWARDED);
InjectDParam(1);

SetDParamStr(0, cn);
Expand All @@ -72,14 +72,18 @@ void Subsidy::AwardTo(CompanyID company)
* @param mode Unit of cargo used, \c true means general name, \c false means singular form.
* @return Reference of the subsidy in the news system.
*/
std::pair<NewsReferenceType, NewsReferenceType> SetupSubsidyDecodeParam(const Subsidy *s, bool mode)
std::pair<NewsReferenceType, NewsReferenceType> SetupSubsidyDecodeParam(const Subsidy *s, SubsidyDecodeParamType mode)
{
NewsReferenceType reftype1 = NR_NONE;
NewsReferenceType reftype2 = NR_NONE;

/* if mode is false, use the singular form */
/* Choose whether to use the singular or plural form of the cargo name based on how we're printing the subsidy */
const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
SetDParam(0, mode ? cs->name : cs->name_single);
if (mode == SUBSIDY_GUI || mode == SUBSIDY_NEWS_WITHDRAWN) {
SetDParam(0, cs->name);
} else {
SetDParam(0, cs->name_single);
}

switch (s->src_type) {
case ST_INDUSTRY:
Expand Down Expand Up @@ -107,6 +111,26 @@ std::pair<NewsReferenceType, NewsReferenceType> SetupSubsidyDecodeParam(const Su
}
SetDParam(5, s->dst);

/* If the subsidy is being offered or awarded, add the right string to communicate the duration. */
if (mode == SUBSIDY_NEWS_OFFERED) {
if (_settings_game.difficulty.subsidy_duration == 1) {
SetDParam(7, STR_NEWS_SERVICE_SUBSIDY_OFFERED_ONE_YEAR);
}
else {
SetDParam(7, STR_NEWS_SERVICE_SUBSIDY_OFFERED_MULTI_YEAR);
SetDParam(8, _settings_game.difficulty.subsidy_duration);
}
}
else if (mode == SUBSIDY_NEWS_AWARDED) {
if (_settings_game.difficulty.subsidy_duration == 1) {
SetDParam(7, STR_NEWS_SERVICE_SUBSIDY_AWARDED_ONE_YEAR);
}
else {
SetDParam(7, STR_NEWS_SERVICE_SUBSIDY_AWARDED_MULTI_YEAR);
SetDParam(8, _settings_game.difficulty.subsidy_duration);
}
}

return std::pair<NewsReferenceType, NewsReferenceType>(reftype1, reftype2);
}

Expand Down Expand Up @@ -216,7 +240,7 @@ void CreateSubsidy(CargoID cid, SourceType src_type, SourceID src, SourceType ds
s->remaining = SUBSIDY_OFFER_MONTHS;
s->awarded = INVALID_COMPANY;

std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(s, false);
std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(s, SUBSIDY_NEWS_OFFERED);
AddNewsItem(STR_NEWS_SERVICE_SUBSIDY_OFFERED, NT_SUBSIDIES, NF_NORMAL, reftype.first, s->src, reftype.second, s->dst);
SetPartOfSubsidyFlag(s->src_type, s->src, POS_SRC);
SetPartOfSubsidyFlag(s->dst_type, s->dst, POS_DST);
Expand Down Expand Up @@ -491,13 +515,13 @@ void SubsidyMonthlyLoop()
for (Subsidy *s : Subsidy::Iterate()) {
if (--s->remaining == 0) {
if (!s->IsAwarded()) {
std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(s, true);
std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(s, SUBSIDY_NEWS_WITHDRAWN);
AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NT_SUBSIDIES, NF_NORMAL, reftype.first, s->src, reftype.second, s->dst);
AI::BroadcastNewEvent(new ScriptEventSubsidyOfferExpired(s->index));
Game::NewEvent(new ScriptEventSubsidyOfferExpired(s->index));
} else {
if (s->awarded == _local_company) {
std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(s, true);
std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(s, SUBSIDY_NEWS_WITHDRAWN);
AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NT_SUBSIDIES, NF_NORMAL, reftype.first, s->src, reftype.second, s->dst);
}
AI::BroadcastNewEvent(new ScriptEventSubsidyExpired(s->index));
Expand All @@ -510,6 +534,9 @@ void SubsidyMonthlyLoop()

if (modified) {
RebuildSubsidisedSourceAndDestinationCache();
} else if (_settings_game.difficulty.subsidy_duration == 0) {
/* If subsidy duration is set to 0, subsidies are disabled, so bail out. */
return;
} else if (_settings_game.linkgraph.distribution_pax != DT_MANUAL &&
_settings_game.linkgraph.distribution_mail != DT_MANUAL &&
_settings_game.linkgraph.distribution_armoured != DT_MANUAL &&
Expand Down
11 changes: 9 additions & 2 deletions src/subsidy_base.h
Expand Up @@ -21,7 +21,7 @@ extern SubsidyPool _subsidy_pool;
/** Struct about subsidies, offered and awarded */
struct Subsidy : SubsidyPool::PoolItem<&_subsidy_pool> {
CargoID cargo_type; ///< Cargo type involved in this subsidy, CT_INVALID for invalid subsidy
byte remaining; ///< Remaining months when this subsidy is valid
uint16 remaining; ///< Remaining months when this subsidy is valid
CompanyID awarded; ///< Subsidy is awarded to this company; INVALID_COMPANY if it's not awarded to anyone
SourceType src_type; ///< Source of subsidised path (ST_INDUSTRY or ST_TOWN)
SourceType dst_type; ///< Destination of subsidised path (ST_INDUSTRY or ST_TOWN)
Expand Down Expand Up @@ -52,11 +52,18 @@ struct Subsidy : SubsidyPool::PoolItem<&_subsidy_pool> {

/** Constants related to subsidies */
static const uint SUBSIDY_OFFER_MONTHS = 12; ///< Duration of subsidy offer
static const uint SUBSIDY_CONTRACT_MONTHS = 12; ///< Duration of subsidy after awarding
static const uint SUBSIDY_PAX_MIN_POPULATION = 400; ///< Min. population of towns for subsidised pax route
static const uint SUBSIDY_CARGO_MIN_POPULATION = 900; ///< Min. population of destination town for cargo route
static const uint SUBSIDY_MAX_PCT_TRANSPORTED = 42; ///< Subsidy will be created only for towns/industries with less % transported
static const uint SUBSIDY_MAX_DISTANCE = 70; ///< Max. length of subsidised route (DistanceManhattan)
static const uint SUBSIDY_TOWN_CARGO_RADIUS = 6; ///< Extent of a tile area around town center when scanning for town cargo acceptance and production (6 ~= min catchmement + min station / 2)

/** Types of subsidy news messages, which determine how the date is printed and whether to use singular or plural cargo names */
enum SubsidyDecodeParamType {
SUBSIDY_NEWS_OFFERED = 0, ///< News item for an offered subsidy
SUBSIDY_NEWS_AWARDED = 1, ///< News item for an awarded subsidy
SUBSIDY_NEWS_WITHDRAWN = 2, ///< News item for a subsidy offer withdrawn, or expired subsidy
SUBSIDY_GUI = 3, ///< Subsidies listed in the Subsidy GUI
};

#endif /* SUBSIDY_BASE_H */
3 changes: 2 additions & 1 deletion src/subsidy_func.h
Expand Up @@ -15,8 +15,9 @@
#include "company_type.h"
#include "cargo_type.h"
#include "news_type.h"
#include "subsidy_base.h"

std::pair<NewsReferenceType, NewsReferenceType> SetupSubsidyDecodeParam(const struct Subsidy *s, bool mode);
std::pair<NewsReferenceType, NewsReferenceType> SetupSubsidyDecodeParam(const struct Subsidy *s, SubsidyDecodeParamType mode);
void DeleteSubsidyWith(SourceType type, SourceID index);
bool CheckSubsidised(CargoID cargo_type, CompanyID company, SourceType src_type, SourceID src, const Station *st);
void RebuildSubsidisedSourceAndDestinationCache();
Expand Down
4 changes: 2 additions & 2 deletions src/subsidy_gui.cpp
Expand Up @@ -161,7 +161,7 @@ struct SubsidyListWindow : Window {
if (!s->IsAwarded()) {
if (IsInsideMM(pos, 0, cap)) {
/* Displays the two offered towns */
SetupSubsidyDecodeParam(s, true);
SetupSubsidyDecodeParam(s, SUBSIDY_GUI);
SetDParam(7, _date - ymd.day + s->remaining * 32);
DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_SUBSIDIES_OFFERED_FROM_TO);
}
Expand All @@ -184,7 +184,7 @@ struct SubsidyListWindow : Window {
for (const Subsidy *s : Subsidy::Iterate()) {
if (s->IsAwarded()) {
if (IsInsideMM(pos, 0, cap)) {
SetupSubsidyDecodeParam(s, true);
SetupSubsidyDecodeParam(s, SUBSIDY_GUI);
SetDParam(7, s->awarded);
SetDParam(8, _date - ymd.day + s->remaining * 32);

Expand Down
13 changes: 13 additions & 0 deletions src/table/settings.ini
Expand Up @@ -243,6 +243,19 @@ str = STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER
strhelp = STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT
strval = STR_SUBSIDY_X1_5
[SDT_VAR]
base = GameSettings
var = difficulty.subsidy_duration
type = SLE_UINT8
from = SLV_CUSTOM_SUBSIDY_DURATION
def = 1
min = 0
max = 255
interval = 1
str = STR_CONFIG_SETTING_SUBSIDY_DURATION
strhelp = STR_CONFIG_SETTING_SUBSIDY_DURATION_HELPTEXT
strval = STR_JUST_INT
[SDT_VAR]
base = GameSettings
var = difficulty.construction_cost
Expand Down

0 comments on commit 898752b

Please sign in to comment.