summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--projects/openttd_vs80.vcproj12
-rw-r--r--projects/openttd_vs90.vcproj12
-rw-r--r--source.list3
-rw-r--r--src/ai/api/ai_subsidy.cpp2
-rw-r--r--src/ai/api/ai_subsidylist.cpp2
-rw-r--r--src/date.cpp2
-rw-r--r--src/economy.cpp339
-rw-r--r--src/economy_func.h5
-rw-r--r--src/economy_type.h8
-rw-r--r--src/industry_cmd.cpp1
-rw-r--r--src/saveload/oldloader_sl.cpp1
-rw-r--r--src/saveload/subsidy_sl.cpp2
-rw-r--r--src/station.cpp1
-rw-r--r--src/subsidy.cpp354
-rw-r--r--src/subsidy_func.h22
-rw-r--r--src/subsidy_gui.cpp1
-rw-r--r--src/subsidy_type.h21
-rw-r--r--src/town_cmd.cpp1
18 files changed, 435 insertions, 354 deletions
diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj
index f87499382..016f26028 100644
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -720,6 +720,10 @@
>
</File>
<File
+ RelativePath=".\..\src\subsidy.cpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\texteff.cpp"
>
</File>
@@ -1444,6 +1448,14 @@
>
</File>
<File
+ RelativePath=".\..\src\subsidy_func.h"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\subsidy_type.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\tar_type.h"
>
</File>
diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj
index ec1db4894..3ca3c8363 100644
--- a/projects/openttd_vs90.vcproj
+++ b/projects/openttd_vs90.vcproj
@@ -717,6 +717,10 @@
>
</File>
<File
+ RelativePath=".\..\src\subsidy.cpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\texteff.cpp"
>
</File>
@@ -1441,6 +1445,14 @@
>
</File>
<File
+ RelativePath=".\..\src\subsidy_func.h"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\subsidy_type.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\tar_type.h"
>
</File>
diff --git a/source.list b/source.list
index 83ad09ed6..bb05a91da 100644
--- a/source.list
+++ b/source.list
@@ -74,6 +74,7 @@ spritecache.cpp
station.cpp
string.cpp
strings.cpp
+subsidy.cpp
texteff.cpp
tgp.cpp
#if HAVE_THREAD
@@ -291,6 +292,8 @@ string_func.h
string_type.h
strings_func.h
strings_type.h
+subsidy_func.h
+subsidy_type.h
tar_type.h
terraform_gui.h
textbuf_gui.h
diff --git a/src/ai/api/ai_subsidy.cpp b/src/ai/api/ai_subsidy.cpp
index 4ffdbac2a..d8804a828 100644
--- a/src/ai/api/ai_subsidy.cpp
+++ b/src/ai/api/ai_subsidy.cpp
@@ -4,7 +4,7 @@
#include "ai_subsidy.hpp"
#include "ai_date.hpp"
-#include "../../economy_func.h"
+#include "../../subsidy_type.h"
#include "../../station_base.h"
#include "../../cargotype.h"
diff --git a/src/ai/api/ai_subsidylist.cpp b/src/ai/api/ai_subsidylist.cpp
index 8e5d96ad9..cfda16e9a 100644
--- a/src/ai/api/ai_subsidylist.cpp
+++ b/src/ai/api/ai_subsidylist.cpp
@@ -4,7 +4,7 @@
#include "ai_subsidylist.hpp"
#include "ai_subsidy.hpp"
-#include "../../economy_func.h"
+#include "../../subsidy_type.h"
AISubsidyList::AISubsidyList()
{
diff --git a/src/date.cpp b/src/date.cpp
index 2f297591d..46cf23582 100644
--- a/src/date.cpp
+++ b/src/date.cpp
@@ -163,6 +163,7 @@ extern void EnginesMonthlyLoop();
extern void TownsMonthlyLoop();
extern void IndustryMonthlyLoop();
extern void StationMonthlyLoop();
+extern void SubsidyMonthlyLoop();
extern void CompaniesYearlyLoop();
extern void VehiclesYearlyLoop();
@@ -249,6 +250,7 @@ void IncreaseDate()
InvalidateWindowClasses(WC_CHEATS);
CompaniesMonthlyLoop();
+ SubsidyMonthlyLoop();
EnginesMonthlyLoop();
TownsMonthlyLoop();
IndustryMonthlyLoop();
diff --git a/src/economy.cpp b/src/economy.cpp
index 0f90b8bdc..90732b78b 100644
--- a/src/economy.cpp
+++ b/src/economy.cpp
@@ -33,6 +33,7 @@
#include "autoreplace_func.h"
#include "company_gui.h"
#include "signs_base.h"
+#include "subsidy_func.h"
#include "table/strings.h"
#include "table/sprites.h"
@@ -87,7 +88,6 @@ const ScoreInfo _score_info[] = {
int _score_part[MAX_COMPANIES][SCORE_END];
Economy _economy;
-Subsidy _subsidies[MAX_COMPANIES];
Prices _price;
uint16 _price_frac[NUM_PRICES];
Money _cargo_payment_rates[NUM_CARGO];
@@ -857,274 +857,6 @@ Money GetPriceByIndex(uint8 index)
return ((Money*)&_price)[index];
}
-
-Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode)
-{
- TileIndex tile;
- TileIndex tile2;
- Pair tp;
-
- /* if mode is false, use the singular form */
- const CargoSpec *cs = GetCargo(s->cargo_type);
- SetDParam(0, mode ? cs->name : cs->name_single);
-
- if (s->age < 12) {
- if (cs->town_effect != TE_PASSENGERS && cs->town_effect != TE_MAIL) {
- SetDParam(1, STR_INDUSTRY);
- SetDParam(2, s->from);
- tile = Industry::Get(s->from)->xy;
-
- if (cs->town_effect != TE_GOODS && cs->town_effect != TE_FOOD) {
- SetDParam(4, STR_INDUSTRY);
- SetDParam(5, s->to);
- tile2 = Industry::Get(s->to)->xy;
- } else {
- SetDParam(4, STR_TOWN);
- SetDParam(5, s->to);
- tile2 = Town::Get(s->to)->xy;
- }
- } else {
- SetDParam(1, STR_TOWN);
- SetDParam(2, s->from);
- tile = Town::Get(s->from)->xy;
-
- SetDParam(4, STR_TOWN);
- SetDParam(5, s->to);
- tile2 = Town::Get(s->to)->xy;
- }
- } else {
- SetDParam(1, s->from);
- tile = Station::Get(s->from)->xy;
-
- SetDParam(2, s->to);
- tile2 = Station::Get(s->to)->xy;
- }
-
- tp.a = tile;
- tp.b = tile2;
-
- return tp;
-}
-
-void DeleteSubsidyWithTown(TownID index)
-{
- Subsidy *s;
-
- for (s = _subsidies; s != endof(_subsidies); s++) {
- if (s->cargo_type != CT_INVALID && s->age < 12) {
- const CargoSpec *cs = GetCargo(s->cargo_type);
- if (((cs->town_effect == TE_PASSENGERS || cs->town_effect == TE_MAIL) && (index == s->from || index == s->to)) ||
- ((cs->town_effect == TE_GOODS || cs->town_effect == TE_FOOD) && index == s->to)) {
- s->cargo_type = CT_INVALID;
- }
- }
- }
-}
-
-void DeleteSubsidyWithIndustry(IndustryID index)
-{
- Subsidy *s;
-
- for (s = _subsidies; s != endof(_subsidies); s++) {
- if (s->cargo_type != CT_INVALID && s->age < 12) {
- const CargoSpec *cs = GetCargo(s->cargo_type);
- if (cs->town_effect != TE_PASSENGERS && cs->town_effect != TE_MAIL &&
- (index == s->from || (cs->town_effect != TE_GOODS && cs->town_effect != TE_FOOD && index == s->to))) {
- s->cargo_type = CT_INVALID;
- }
- }
- }
-}
-
-void DeleteSubsidyWithStation(StationID index)
-{
- Subsidy *s;
- bool dirty = false;
-
- for (s = _subsidies; s != endof(_subsidies); s++) {
- if (s->cargo_type != CT_INVALID && s->age >= 12 &&
- (s->from == index || s->to == index)) {
- s->cargo_type = CT_INVALID;
- dirty = true;
- }
- }
-
- if (dirty)
- InvalidateWindow(WC_SUBSIDIES_LIST, 0);
-}
-
-struct FoundRoute {
- uint distance;
- CargoID cargo;
- void *from;
- void *to;
-};
-
-static void FindSubsidyPassengerRoute(FoundRoute *fr)
-{
- Town *from, *to;
-
- fr->distance = UINT_MAX;
-
- fr->from = from = GetRandomTown();
- if (from == NULL || from->population < 400) return;
-
- fr->to = to = GetRandomTown();
- if (from == to || to == NULL || to->population < 400 || to->pct_pass_transported > 42)
- return;
-
- fr->distance = DistanceManhattan(from->xy, to->xy);
-}
-
-static void FindSubsidyCargoRoute(FoundRoute *fr)
-{
- Industry *i;
- int trans, total;
- CargoID cargo;
-
- fr->distance = UINT_MAX;
-
- fr->from = i = GetRandomIndustry();
- if (i == NULL) return;
-
- /* Randomize cargo type */
- if (HasBit(Random(), 0) && i->produced_cargo[1] != CT_INVALID) {
- cargo = i->produced_cargo[1];
- trans = i->last_month_pct_transported[1];
- total = i->last_month_production[1];
- } else {
- cargo = i->produced_cargo[0];
- trans = i->last_month_pct_transported[0];
- total = i->last_month_production[0];
- }
-
- /* Quit if no production in this industry
- * or if the cargo type is passengers
- * or if the pct transported is already large enough */
- if (total == 0 || trans > 42 || cargo == CT_INVALID) return;
-
- const CargoSpec *cs = GetCargo(cargo);
- if (cs->town_effect == TE_PASSENGERS) return;
-
- fr->cargo = cargo;
-
- if (cs->town_effect == TE_GOODS || cs->town_effect == TE_FOOD) {
- /* The destination is a town */
- Town *t = GetRandomTown();
-
- /* Only want big towns */
- if (t == NULL || t->population < 900) return;
-
- fr->distance = DistanceManhattan(i->xy, t->xy);
- fr->to = t;
- } else {
- /* The destination is an industry */
- Industry *i2 = GetRandomIndustry();
-
- /* The industry must accept the cargo */
- if (i2 == NULL || i == i2 ||
- (cargo != i2->accepts_cargo[0] &&
- cargo != i2->accepts_cargo[1] &&
- cargo != i2->accepts_cargo[2])) {
- return;
- }
- fr->distance = DistanceManhattan(i->xy, i2->xy);
- fr->to = i2;
- }
-}
-
-static bool CheckSubsidyDuplicate(Subsidy *s)
-{
- const Subsidy *ss;
-
- for (ss = _subsidies; ss != endof(_subsidies); ss++) {
- if (s != ss &&
- ss->from == s->from &&
- ss->to == s->to &&
- ss->cargo_type == s->cargo_type) {
- s->cargo_type = CT_INVALID;
- return true;
- }
- }
- return false;
-}
-
-
-static void SubsidyMonthlyHandler()
-{
- Subsidy *s;
- Pair pair;
- Station *st;
- uint n;
- FoundRoute fr;
- bool modified = false;
-
- for (s = _subsidies; s != endof(_subsidies); s++) {
- if (s->cargo_type == CT_INVALID) continue;
-
- if (s->age == 12 - 1) {
- pair = SetupSubsidyDecodeParam(s, 1);
- AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NS_SUBSIDIES, pair.a, pair.b);
- s->cargo_type = CT_INVALID;
- modified = true;
- AI::BroadcastNewEvent(new AIEventSubsidyOfferExpired(s - _subsidies));
- } else if (s->age == 2 * 12 - 1) {
- st = Station::Get(s->to);
- if (st->owner == _local_company) {
- pair = SetupSubsidyDecodeParam(s, 1);
- AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NS_SUBSIDIES, pair.a, pair.b);
- }
- s->cargo_type = CT_INVALID;
- modified = true;
- AI::BroadcastNewEvent(new AIEventSubsidyExpired(s - _subsidies));
- } else {
- s->age++;
- }
- }
-
- /* 25% chance to go on */
- if (Chance16(1, 4)) {
- /* Find a free slot*/
- s = _subsidies;
- while (s->cargo_type != CT_INVALID) {
- if (++s == endof(_subsidies))
- goto no_add;
- }
-
- n = 1000;
- do {
- FindSubsidyPassengerRoute(&fr);
- if (fr.distance <= 70) {
- s->cargo_type = CT_PASSENGERS;
- s->from = ((Town*)fr.from)->index;
- s->to = ((Town*)fr.to)->index;
- goto add_subsidy;
- }
- FindSubsidyCargoRoute(&fr);
- if (fr.distance <= 70) {
- s->cargo_type = fr.cargo;
- s->from = ((Industry*)fr.from)->index;
- {
- const CargoSpec *cs = GetCargo(fr.cargo);
- s->to = (cs->town_effect == TE_GOODS || cs->town_effect == TE_FOOD) ? ((Town*)fr.to)->index : ((Industry*)fr.to)->index;
- }
- add_subsidy:
- if (!CheckSubsidyDuplicate(s)) {
- s->age = 0;
- pair = SetupSubsidyDecodeParam(s, 0);
- AddNewsItem(STR_NEWS_SERVICE_SUBSIDY_OFFERED, NS_SUBSIDIES, pair.a, pair.b);
- AI::BroadcastNewEvent(new AIEventSubsidyOffer(s - _subsidies));
- modified = true;
- break;
- }
- }
- } while (n--);
- }
-no_add:;
- if (modified)
- InvalidateWindow(WC_SUBSIDIES_LIST, 0);
-}
-
Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type)
{
const CargoSpec *cs = GetCargo(cargo_type);
@@ -1173,7 +905,6 @@ Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, C
return BigMulS(dist * time_factor * num_pieces, _cargo_payment_rates[cargo_type], 21);
}
-
struct FindIndustryToDeliverData {
const Rect *rect; ///< Station acceptance rectangle
CargoID cargo_type; ///< Cargo type that was delivered
@@ -1273,73 +1004,6 @@ static void DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, int nu
}
}
-static bool CheckSubsidised(Station *from, Station *to, CargoID cargo_type)
-{
- Subsidy *s;
- TileIndex xy;
- Pair pair;
-
- /* check if there is an already existing subsidy that applies to us */
- for (s = _subsidies; s != endof(_subsidies); s++) {
- if (s->cargo_type == cargo_type &&
- s->age >= 12 &&
- s->from == from->index &&
- s->to == to->index) {
- return true;
- }
- }
-
- /* check if there's a new subsidy that applies.. */
- for (s = _subsidies; s != endof(_subsidies); s++) {
- if (s->cargo_type == cargo_type && s->age < 12) {
- /* Check distance from source */
- const CargoSpec *cs = GetCargo(cargo_type);
- if (cs->town_effect == TE_PASSENGERS || cs->town_effect == TE_MAIL) {
- xy = Town::Get(s->from)->xy;
- } else {
- xy = Industry::Get(s->from)->xy;
- }
- if (DistanceMax(xy, from->xy) > 9) continue;
-
- /* Check distance from dest */
- switch (cs->town_effect) {
- case TE_PASSENGERS:
- case TE_MAIL:
- case TE_GOODS:
- case TE_FOOD:
- xy = Town::Get(s->to)->xy;
- break;
-
- default:
- xy = Industry::Get(s->to)->xy;
- break;
- }
- if (DistanceMax(xy, to->xy) > 9) continue;
-
- /* Found a subsidy, change the values to indicate that it's in use */
- s->age = 12;
- s->from = from->index;
- s->to = to->index;
-
- /* Add a news item */
- pair = SetupSubsidyDecodeParam(s, 0);
- InjectDParam(1);
-
- SetDParam(0, _current_company);
- AddNewsItem(
- STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF + _settings_game.difficulty.subsidy_multiplier,
- NS_SUBSIDIES,
- pair.a, pair.b
- );
- AI::BroadcastNewEvent(new AIEventSubsidyAwarded(s - _subsidies));
-
- InvalidateWindow(WC_SUBSIDIES_LIST, 0);
- return true;
- }
- }
- return false;
-}
-
/**
* Delivers goods to industries/towns and calculates the payment
* @param num_pieces amount of cargo delivered
@@ -1826,7 +1490,6 @@ void CompaniesMonthlyLoop()
/* Reset the _current_company flag */
_current_company = OWNER_NONE;
HandleEconomyFluctuations();
- SubsidyMonthlyHandler();
}
static void DoAcquireCompany(Company *c)
diff --git a/src/economy_func.h b/src/economy_func.h
index 8bbb4a7cc..73d5f7e83 100644
--- a/src/economy_func.h
+++ b/src/economy_func.h
@@ -22,7 +22,6 @@ void ResetEconomy();
extern const ScoreInfo _score_info[];
extern int _score_part[MAX_COMPANIES][SCORE_END];
extern Economy _economy;
-extern Subsidy _subsidies[MAX_COMPANIES];
/* Prices and also the fractional part. */
extern Prices _price;
extern uint16 _price_frac[NUM_PRICES];
@@ -30,10 +29,6 @@ extern Money _cargo_payment_rates[NUM_CARGO];
extern uint16 _cargo_payment_rates_frac[NUM_CARGO];
int UpdateCompanyRatingAndValue(Company *c, bool update);
-Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode);
-void DeleteSubsidyWithTown(TownID index);
-void DeleteSubsidyWithIndustry(IndustryID index);
-void DeleteSubsidyWithStation(StationID index);
void StartupIndustryDailyChanges(bool init_counter);
Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type);
diff --git a/src/economy_type.h b/src/economy_type.h
index 7559612dc..415e17373 100644
--- a/src/economy_type.h
+++ b/src/economy_type.h
@@ -23,14 +23,6 @@ struct Economy {
uint32 industry_daily_increment; ///< The value which will increment industry_daily_change_counter. Computed value. NOSAVE
};
-struct Subsidy {
- CargoID cargo_type;
- byte age;
- /* from and to can either be TownID, StationID or IndustryID */
- uint16 from;
- uint16 to;
-};
-
enum ScoreID {
SCORE_BEGIN = 0,
SCORE_VEHICLES = 0,
diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp
index 902bc9097..ecb2a3c23 100644
--- a/src/industry_cmd.cpp
+++ b/src/industry_cmd.cpp
@@ -34,6 +34,7 @@
#include "effectvehicle_func.h"
#include "ai/ai.hpp"
#include "core/pool_func.hpp"
+#include "subsidy_func.h"
#include "table/strings.h"
#include "table/industry_land.h"
diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp
index 080ea6c90..37860ba16 100644
--- a/src/saveload/oldloader_sl.cpp
+++ b/src/saveload/oldloader_sl.cpp
@@ -11,6 +11,7 @@
#include "../ship.h"
#include "../train.h"
#include "../signs_base.h"
+#include "../subsidy_type.h"
#include "../debug.h"
#include "../depot_base.h"
#include "../newgrf_config.h"
diff --git a/src/saveload/subsidy_sl.cpp b/src/saveload/subsidy_sl.cpp
index dca315f96..7ff23e6f8 100644
--- a/src/saveload/subsidy_sl.cpp
+++ b/src/saveload/subsidy_sl.cpp
@@ -3,7 +3,7 @@
/** @file subsidy_sl.cpp Code handling saving and loading of subsidies */
#include "../stdafx.h"
-#include "../economy_func.h"
+#include "../subsidy_type.h"
#include "saveload.h"
diff --git a/src/station.cpp b/src/station.cpp
index c3a3c4e38..b8946aeb4 100644
--- a/src/station.cpp
+++ b/src/station.cpp
@@ -20,6 +20,7 @@
#include "aircraft.h"
#include "vehicle_gui.h"
#include "settings_type.h"
+#include "subsidy_func.h"
#include "core/pool_func.hpp"
#include "table/strings.h"
diff --git a/src/subsidy.cpp b/src/subsidy.cpp
new file mode 100644
index 000000000..2ee28c720
--- /dev/null
+++ b/src/subsidy.cpp
@@ -0,0 +1,354 @@
+/* $Id$ */
+
+/** @file subsidy.cpp Handling of subsidies. */
+
+#include "stdafx.h"
+#include "company_func.h"
+#include "industry.h"
+#include "map_func.h"
+#include "town.h"
+#include "news_func.h"
+#include "ai/ai.hpp"
+#include "station_base.h"
+#include "cargotype.h"
+#include "strings_func.h"
+#include "window_func.h"
+#include "subsidy_type.h"
+
+#include "table/strings.h"
+
+Subsidy _subsidies[MAX_COMPANIES];
+
+Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode)
+{
+ TileIndex tile;
+ TileIndex tile2;
+ Pair tp;
+
+ /* if mode is false, use the singular form */
+ const CargoSpec *cs = GetCargo(s->cargo_type);
+ SetDParam(0, mode ? cs->name : cs->name_single);
+
+ if (s->age < 12) {
+ if (cs->town_effect != TE_PASSENGERS && cs->town_effect != TE_MAIL) {
+ SetDParam(1, STR_INDUSTRY);
+ SetDParam(2, s->from);
+ tile = Industry::Get(s->from)->xy;
+
+ if (cs->town_effect != TE_GOODS && cs->town_effect != TE_FOOD) {
+ SetDParam(4, STR_INDUSTRY);
+ SetDParam(5, s->to);
+ tile2 = Industry::Get(s->to)->xy;
+ } else {
+ SetDParam(4, STR_TOWN);
+ SetDParam(5, s->to);
+ tile2 = Town::Get(s->to)->xy;
+ }
+ } else {
+ SetDParam(1, STR_TOWN);
+ SetDParam(2, s->from);
+ tile = Town::Get(s->from)->xy;
+
+ SetDParam(4, STR_TOWN);
+ SetDParam(5, s->to);
+ tile2 = Town::Get(s->to)->xy;
+ }
+ } else {
+ SetDParam(1, s->from);
+ tile = Station::Get(s->from)->xy;
+
+ SetDParam(2, s->to);
+ tile2 = Station::Get(s->to)->xy;
+ }
+
+ tp.a = tile;
+ tp.b = tile2;
+
+ return tp;
+}
+
+void DeleteSubsidyWithTown(TownID index)
+{
+ Subsidy *s;
+
+ for (s = _subsidies; s != endof(_subsidies); s++) {
+ if (s->cargo_type != CT_INVALID && s->age < 12) {
+ const CargoSpec *cs = GetCargo(s->cargo_type);
+ if (((cs->town_effect == TE_PASSENGERS || cs->town_effect == TE_MAIL) && (index == s->from || index == s->to)) ||
+ ((cs->town_effect == TE_GOODS || cs->town_effect == TE_FOOD) && index == s->to)) {
+ s->cargo_type = CT_INVALID;
+ }
+ }
+ }
+}
+
+void DeleteSubsidyWithIndustry(IndustryID index)
+{
+ Subsidy *s;
+
+ for (s = _subsidies; s != endof(_subsidies); s++) {
+ if (s->cargo_type != CT_INVALID && s->age < 12) {
+ const CargoSpec *cs = GetCargo(s->cargo_type);
+ if (cs->town_effect != TE_PASSENGERS && cs->town_effect != TE_MAIL &&
+ (index == s->from || (cs->town_effect != TE_GOODS && cs->town_effect != TE_FOOD && index == s->to))) {
+ s->cargo_type = CT_INVALID;
+ }
+ }
+ }
+}
+
+void DeleteSubsidyWithStation(StationID index)
+{
+ Subsidy *s;
+ bool dirty = false;
+
+ for (s = _subsidies; s != endof(_subsidies); s++) {
+ if (s->cargo_type != CT_INVALID && s->age >= 12 &&
+ (s->from == index || s->to == index)) {
+ s->cargo_type = CT_INVALID;
+ dirty = true;
+ }
+ }
+
+ if (dirty)
+ InvalidateWindow(WC_SUBSIDIES_LIST, 0);
+}
+
+struct FoundRoute {
+ uint distance;
+ CargoID cargo;
+ void *from;
+ void *to;
+};
+
+static void FindSubsidyPassengerRoute(FoundRoute *fr)
+{
+ Town *from, *to;
+
+ fr->distance = UINT_MAX;
+
+ fr->from = from = GetRandomTown();
+ if (from == NULL || from->population < 400) return;
+
+ fr->to = to = GetRandomTown();
+ if (from == to || to == NULL || to->population < 400 || to->pct_pass_transported > 42)
+ return;
+
+ fr->distance = DistanceManhattan(from->xy, to->xy);
+}
+
+static void FindSubsidyCargoRoute(FoundRoute *fr)
+{
+ Industry *i;
+ int trans, total;
+ CargoID cargo;
+
+ fr->distance = UINT_MAX;
+
+ fr->from = i = GetRandomIndustry();
+ if (i == NULL) return;
+
+ /* Randomize cargo type */
+ if (HasBit(Random(), 0) && i->produced_cargo[1] != CT_INVALID) {
+ cargo = i->produced_cargo[1];
+ trans = i->last_month_pct_transported[1];
+ total = i->last_month_production[1];
+ } else {
+ cargo = i->produced_cargo[0];
+ trans = i->last_month_pct_transported[0];
+ total = i->last_month_production[0];
+ }
+
+ /* Quit if no production in this industry
+ * or if the cargo type is passengers
+ * or if the pct transported is already large enough */
+ if (total == 0 || trans > 42 || cargo == CT_INVALID) return;
+
+ const CargoSpec *cs = GetCargo(cargo);
+ if (cs->town_effect == TE_PASSENGERS) return;
+
+ fr->cargo = cargo;
+
+ if (cs->town_effect == TE_GOODS || cs->town_effect == TE_FOOD) {
+ /* The destination is a town */
+ Town *t = GetRandomTown();
+
+ /* Only want big towns */
+ if (t == NULL || t->population < 900) return;
+
+ fr->distance = DistanceManhattan(i->xy, t->xy);
+ fr->to = t;
+ } else {
+ /* The destination is an industry */
+ Industry *i2 = GetRandomIndustry();
+
+ /* The industry must accept the cargo */
+ if (i2 == NULL || i == i2 ||
+ (cargo != i2->accepts_cargo[0] &&
+ cargo != i2->accepts_cargo[1] &&
+ cargo != i2->accepts_cargo[2])) {
+ return;
+ }
+ fr->distance = DistanceManhattan(i->xy, i2->xy);
+ fr->to = i2;
+ }
+}
+
+static bool CheckSubsidyDuplicate(Subsidy *s)
+{
+ const Subsidy *ss;
+
+ for (ss = _subsidies; ss != endof(_subsidies); ss++) {
+ if (s != ss &&
+ ss->from == s->from &&
+ ss->to == s->to &&
+ ss->cargo_type == s->cargo_type) {
+ s->cargo_type = CT_INVALID;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void SubsidyMonthlyLoop()
+{
+ Subsidy *s;
+ Pair pair;
+ Station *st;
+ uint n;
+ FoundRoute fr;
+ bool modified = false;
+
+ for (s = _subsidies; s != endof(_subsidies); s++) {
+ if (s->cargo_type == CT_INVALID) continue;
+
+ if (s->age == 12 - 1) {
+ pair = SetupSubsidyDecodeParam(s, 1);
+ AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NS_SUBSIDIES, pair.a, pair.b);
+ s->cargo_type = CT_INVALID;
+ modified = true;
+ AI::BroadcastNewEvent(new AIEventSubsidyOfferExpired(s - _subsidies));
+ } else if (s->age == 2 * 12 - 1) {
+ st = Station::Get(s->to);
+ if (st->owner == _local_company) {
+ pair = SetupSubsidyDecodeParam(s, 1);
+ AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NS_SUBSIDIES, pair.a, pair.b);
+ }
+ s->cargo_type = CT_INVALID;
+ modified = true;
+ AI::BroadcastNewEvent(new AIEventSubsidyExpired(s - _subsidies));
+ } else {
+ s->age++;
+ }
+ }
+
+ /* 25% chance to go on */
+ if (Chance16(1, 4)) {
+ /* Find a free slot*/
+ s = _subsidies;
+ while (s->cargo_type != CT_INVALID) {
+ if (++s == endof(_subsidies))
+ goto no_add;
+ }
+
+ n = 1000;
+ do {
+ FindSubsidyPassengerRoute(&fr);
+ if (fr.distance <= 70) {
+ s->cargo_type = CT_PASSENGERS;
+ s->from = ((Town*)fr.from)->index;
+ s->to = ((Town*)fr.to)->index;
+ goto add_subsidy;
+ }
+ FindSubsidyCargoRoute(&fr);
+ if (fr.distance <= 70) {
+ s->cargo_type = fr.cargo;
+ s->from = ((Industry*)fr.from)->index;
+ {
+ const CargoSpec *cs = GetCargo(fr.cargo);
+ s->to = (cs->town_effect == TE_GOODS || cs->town_effect == TE_FOOD) ? ((Town*)fr.to)->index : ((Industry*)fr.to)->index;
+ }
+ add_subsidy:
+ if (!CheckSubsidyDuplicate(s)) {
+ s->age = 0;
+ pair = SetupSubsidyDecodeParam(s, 0);
+ AddNewsItem(STR_NEWS_SERVICE_SUBSIDY_OFFERED, NS_SUBSIDIES, pair.a, pair.b);
+ AI::BroadcastNewEvent(new AIEventSubsidyOffer(s - _subsidies));
+ modified = true;
+ break;
+ }
+ }
+ } while (n--);
+ }
+no_add:;
+ if (modified)
+ InvalidateWindow(WC_SUBSIDIES_LIST, 0);
+}
+
+bool CheckSubsidised(Station *from, Station *to, CargoID cargo_type)
+{
+ Subsidy *s;
+ TileIndex xy;
+ Pair pair;
+
+ /* check if there is an already existing subsidy that applies to us */
+ for (s = _subsidies; s != endof(_subsidies); s++) {
+ if (s->cargo_type == cargo_type &&
+ s->age >= 12 &&
+ s->from == from->index &&
+ s->to == to->index) {
+ return true;
+ }
+ }
+
+ /* check if there's a new subsidy that applies.. */
+ for (s = _subsidies; s != endof(_subsidies); s++) {
+ if (s->cargo_type == cargo_type && s->age < 12) {
+ /* Check distance from source */
+ const CargoSpec *cs = GetCargo(cargo_type);
+ if (cs->town_effect == TE_PASSENGERS || cs->town_effect == TE_MAIL) {
+ xy = Town::Get(s->from)->xy;
+ } else {
+ xy = Industry::Get(s->from)->xy;
+ }
+ if (DistanceMax(xy, from->xy) > 9) continue;
+
+ /* Check distance from dest */
+ switch (cs->town_effect) {
+ case TE_PASSENGERS:
+ case TE_MAIL:
+ case TE_GOODS:
+ case TE_FOOD:
+ xy = Town::Get(s->to)->xy;
+ break;
+
+ default:
+ xy = Industry::Get(s->to)->xy;
+ break;
+ }
+ if (DistanceMax(xy, to->xy) > 9) continue;
+
+ /* Found a subsidy, change the values to indicate that it's in use */
+ s->age = 12;
+ s->from = from->index;
+ s->to = to->index;
+
+ /* Add a news item */
+ pair = SetupSubsidyDecodeParam(s, 0);
+ InjectDParam(1);
+
+ SetDParam(0, _current_company);
+ AddNewsItem(
+ STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF + _settings_game.difficulty.subsidy_multiplier,
+ NS_SUBSIDIES,
+ pair.a, pair.b
+ );
+ AI::BroadcastNewEvent(new AIEventSubsidyAwarded(s - _subsidies));
+
+ InvalidateWindow(WC_SUBSIDIES_LIST, 0);
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/subsidy_func.h b/src/subsidy_func.h
new file mode 100644
index 000000000..608dadfed
--- /dev/null
+++ b/src/subsidy_func.h
@@ -0,0 +1,22 @@
+/* $Id$ */
+
+/** @file subsidy_func.h Functions related to subsidies. */
+
+#ifndef SUBSIDY_FUNC_H
+#define SUBSIDY_FUNC_H
+
+#include "core/geometry_type.hpp"
+#include "station_type.h"
+#include "town_type.h"
+#include "industry_type.h"
+#include "company_type.h"
+#include "subsidy_type.h"
+
+Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode);
+void DeleteSubsidyWithTown(TownID index);
+void DeleteSubsidyWithIndustry(IndustryID index);
+void DeleteSubsidyWithStation(StationID index);
+bool CheckSubsidised(Station *from, Station *to, CargoID cargo_type);
+void SubsidyMonthlyHandler();
+
+#endif /* SUBSIDY_FUNC_H */
diff --git a/src/subsidy_gui.cpp b/src/subsidy_gui.cpp
index 8d666fca1..14ae1348a 100644
--- a/src/subsidy_gui.cpp
+++ b/src/subsidy_gui.cpp
@@ -14,6 +14,7 @@
#include "viewport_func.h"
#include "gfx_func.h"
#include "gui.h"
+#include "subsidy_func.h"
#include "table/strings.h"
diff --git a/src/subsidy_type.h b/src/subsidy_type.h
new file mode 100644
index 000000000..bec1a2cd4
--- /dev/null
+++ b/src/subsidy_type.h
@@ -0,0 +1,21 @@
+/* $Id$ */
+
+/** @file subsidy_type.h Types related to subsidies. */
+
+#ifndef SUBSIDY_TYPE_H
+#define SUBSIDY_TYPE_H
+
+#include "cargo_type.h"
+#include "company_type.h"
+
+struct Subsidy {
+ CargoID cargo_type;
+ byte age;
+ /* from and to can either be TownID, StationID or IndustryID */
+ uint16 from;
+ uint16 to;
+};
+
+extern Subsidy _subsidies[MAX_COMPANIES];
+
+#endif /* SUBSIDY_TYPE_H */
diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp
index 825ef33f1..4dcd3dcd3 100644
--- a/src/town_cmd.cpp
+++ b/src/town_cmd.cpp
@@ -40,6 +40,7 @@
#include "functions.h"
#include "animated_tile_func.h"
#include "date_func.h"
+#include "subsidy_func.h"
#include "core/smallmap_type.hpp"
#include "core/pool_func.hpp"