summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ai/api/ai_changelog.hpp2
-rw-r--r--src/ai/api/ai_subsidy.cpp19
-rw-r--r--src/ai/api/ai_subsidy.hpp16
-rw-r--r--src/cargo_type.h10
-rw-r--r--src/cargopacket.cpp27
-rw-r--r--src/cargopacket.h11
-rw-r--r--src/economy.cpp43
-rw-r--r--src/economy_func.h2
-rw-r--r--src/industry.h3
-rw-r--r--src/industry_cmd.cpp5
-rw-r--r--src/lang/english.txt12
-rw-r--r--src/saveload/afterload.cpp19
-rw-r--r--src/saveload/cargopacket_sl.cpp2
-rw-r--r--src/saveload/oldloader_sl.cpp2
-rw-r--r--src/saveload/saveload.cpp2
-rw-r--r--src/saveload/subsidy_sl.cpp13
-rw-r--r--src/station.cpp3
-rw-r--r--src/station_cmd.cpp12
-rw-r--r--src/subsidy.cpp202
-rw-r--r--src/subsidy_base.h19
-rw-r--r--src/subsidy_func.h4
-rw-r--r--src/subsidy_gui.cpp9
-rw-r--r--src/subsidy_type.h22
-rw-r--r--src/town.h3
-rw-r--r--src/town_cmd.cpp8
-rw-r--r--src/unmovable_cmd.cpp7
26 files changed, 300 insertions, 177 deletions
diff --git a/src/ai/api/ai_changelog.hpp b/src/ai/api/ai_changelog.hpp
index 5750ab0ac..a8e511030 100644
--- a/src/ai/api/ai_changelog.hpp
+++ b/src/ai/api/ai_changelog.hpp
@@ -29,6 +29,8 @@
* \li WaypointID was replaced by StationID. All WaypointIDs from previous
* savegames are invalid
* \li WAYPOINT_INVALID is now deprecated, use STATION_INVALID instead
+ * \li AISubsidy::GetSource and AISubsidy::GetDestination return STATION_INVALID
+ * for awarded subsidies
* \li AIs can create subclasses of API classes and use API constants as part
* of their own constants
* \li AIVehicleList_Station now also works for waypoints
diff --git a/src/ai/api/ai_subsidy.cpp b/src/ai/api/ai_subsidy.cpp
index fd3e29745..39358e963 100644
--- a/src/ai/api/ai_subsidy.cpp
+++ b/src/ai/api/ai_subsidy.cpp
@@ -4,6 +4,7 @@
#include "ai_subsidy.hpp"
#include "ai_date.hpp"
+#include "ai_log.hpp"
#include "../../subsidy_base.h"
#include "../../station_base.h"
#include "../../cargotype.h"
@@ -24,7 +25,7 @@
{
if (!IsAwarded(subsidy_id)) return AICompany::COMPANY_INVALID;
- return (AICompany::CompanyID)((byte)::Station::Get(::Subsidy::Get(subsidy_id)->src)->owner);
+ return (AICompany::CompanyID)((byte)::Subsidy::Get(subsidy_id)->awarded);
}
/* static */ int32 AISubsidy::GetExpireDate(SubsidyID subsidy_id)
@@ -34,11 +35,7 @@
int year = AIDate::GetYear(AIDate::GetCurrentDate());
int month = AIDate::GetMonth(AIDate::GetCurrentDate());
- if (IsAwarded(subsidy_id)) {
- month += 24 - ::Subsidy::Get(subsidy_id)->age;
- } else {
- month += 12 - ::Subsidy::Get(subsidy_id)->age;
- }
+ month += ::Subsidy::Get(subsidy_id)->remaining;
year += (month - 1) / 12;
month = ((month - 1) % 12) + 1;
@@ -64,6 +61,11 @@
{
if (!IsValidSubsidy(subsidy_id)) return INVALID_STATION;
+ if (IsAwarded(subsidy_id)) {
+ AILog::Error("AISubsidy::GetSource returned INVALID_STATION due to internal changes in the Subsidy logic.");
+ return INVALID_STATION;
+ }
+
return ::Subsidy::Get(subsidy_id)->src;
}
@@ -78,5 +80,10 @@
{
if (!IsValidSubsidy(subsidy_id)) return INVALID_STATION;
+ if (IsAwarded(subsidy_id)) {
+ AILog::Error("AISubsidy::GetDestination returned INVALID_STATION due to internal changes in the Subsidy logic.");
+ return INVALID_STATION;
+ }
+
return ::Subsidy::Get(subsidy_id)->dst;
}
diff --git a/src/ai/api/ai_subsidy.hpp b/src/ai/api/ai_subsidy.hpp
index 7be86b0e8..96ad92c31 100644
--- a/src/ai/api/ai_subsidy.hpp
+++ b/src/ai/api/ai_subsidy.hpp
@@ -69,12 +69,12 @@ public:
/**
* Return the source TownID/IndustryID/StationID the subsidy is for.
- * 1) IsAwarded(subsidy_id) -> return the StationID the subsidy is awarded to.
- * 2) !IsAwarded(subsidy_id) && SourceIsTown(subsidy_id) -> return the TownID.
- * 3) !IsAwarded(subsidy_id) && !SourceIsTown(subsidy_id) -> return the IndustryID.
+ * \li IsAwarded(subsidy_id) -> return INVALID_STATION.
+ * \li !IsAwarded(subsidy_id) && SourceIsTown(subsidy_id) -> return the TownID.
+ * \li !IsAwarded(subsidy_id) && !SourceIsTown(subsidy_id) -> return the IndustryID.
* @param subsidy_id The SubsidyID to check.
* @pre IsValidSubsidy(subsidy_id).
- * @return One of TownID/IndustryID/StationID.
+ * @return One of TownID/IndustryID/INVALID_STATION.
*/
static int32 GetSource(SubsidyID subsidy_id);
@@ -88,12 +88,12 @@ public:
/**
* Return the destination TownID/IndustryID/StationID the subsidy is for.
- * 1) IsAwarded(subsidy_id) -> return the StationID the subsidy is awarded to.
- * 2) !IsAwarded(subsidy_id) && SourceIsTown(subsidy_id) -> return the TownID.
- * 3) !IsAwarded(subsidy_id) && !SourceIsTown(subsidy_id) -> return the IndustryID.
+ * \li IsAwarded(subsidy_id) -> return INVALID_STATION.
+ * \li !IsAwarded(subsidy_id) && DestinationIsTown(subsidy_id) -> return the TownID.
+ * \li !IsAwarded(subsidy_id) && !DestinationIsTown(subsidy_id) -> return the IndustryID.
* @param subsidy_id the SubsidyID to check.
* @pre IsValidSubsidy(subsidy_id).
- * @return One of TownID/IndustryID/StationID.
+ * @return One of TownID/IndustryID/INVALID_STATION.
*/
static int32 GetDestination(SubsidyID subsidy_id);
};
diff --git a/src/cargo_type.h b/src/cargo_type.h
index 30145f266..0222af806 100644
--- a/src/cargo_type.h
+++ b/src/cargo_type.h
@@ -85,15 +85,15 @@ public:
};
-/** Types of subsidy source and destination */
+/** Types of cargo source and destination */
enum SourceType {
- ST_INDUSTRY, ///< Source/destination is an industry
- ST_TOWN, ///< Source/destination is a town
- ST_STATION, ///< Source/destination is a station
+ ST_INDUSTRY, ///< Source/destination is an industry
+ ST_TOWN, ///< Source/destination is a town
+ ST_HEADQUARTERS, ///< Source/destination are company headquarters
};
typedef SimpleTinyEnumT<SourceType, byte> SourceTypeByte;
-typedef uint16 SourceID; ///< Contains either industry ID, town ID or station ID (or INVALID_SOURCE)
+typedef uint16 SourceID; ///< Contains either industry ID, town ID or company ID (or INVALID_SOURCE)
static const SourceID INVALID_SOURCE = 0xFFFF; ///< Invalid/unknown index of source
#endif /* CARGO_TYPE_H */
diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp
index 65514e647..355cabebb 100644
--- a/src/cargopacket.cpp
+++ b/src/cargopacket.cpp
@@ -16,17 +16,33 @@ void InitializeCargoPackets()
_cargopacket_pool.CleanPool();
}
-CargoPacket::CargoPacket(StationID source, uint16 count)
+CargoPacket::CargoPacket(StationID source, uint16 count, SourceType source_type, SourceID source_id)
{
if (source != INVALID_STATION) assert(count != 0);
- this->source = source;
+// this->feeder_share = 0; // no need to zero already zeroed data (by operator new)
this->source_xy = (source != INVALID_STATION) ? Station::Get(source)->xy : 0;
this->loaded_at_xy = this->source_xy;
+ this->source = source;
this->count = count;
- this->days_in_transit = 0;
- this->feeder_share = 0;
+// this->days_in_transit = 0;
+
+ this->source_type = source_type;
+ this->source_id = source_id;
+}
+
+/**
+ * Invalidates (sets source_id to INVALID_SOURCE) all cargo packets from given source
+ * @param src_type type of source
+ * @param src index of source
+ */
+/* static */ void CargoPacket::InvalidateAllFrom(SourceType src_type, SourceID src)
+{
+ CargoPacket *cp;
+ FOR_ALL_CARGOPACKETS(cp) {
+ if (cp->source_type == src_type && cp->source_id == src) cp->source_id = INVALID_SOURCE;
+ }
}
/*
@@ -149,6 +165,9 @@ bool CargoList::MoveTo(CargoList *dest, uint count, CargoList::MoveToAction mta,
cp_new->days_in_transit = cp->days_in_transit;
cp_new->feeder_share = fs;
+ cp_new->source_type = cp->source_type;
+ cp_new->source_id = cp->source_id;
+
cp_new->count = count;
dest->packets.push_back(cp_new);
diff --git a/src/cargopacket.h b/src/cargopacket.h
index 414003faa..de8268a98 100644
--- a/src/cargopacket.h
+++ b/src/cargopacket.h
@@ -9,6 +9,7 @@
#include "economy_type.h"
#include "tile_type.h"
#include "station_type.h"
+#include "cargo_type.h"
#include <list>
typedef uint32 CargoPacketID;
@@ -30,13 +31,16 @@ struct CargoPacket : CargoPacketPool::PoolItem<&_cargopacket_pool> {
uint16 count; ///< The amount of cargo in this packet
byte days_in_transit; ///< Amount of days this packet has been in transit
+ SourceTypeByte source_type; ///< Type of #source_id
+ SourceID source_id; ///< Index of source, INVALID_SOURCE if unknown/invalid
+
/**
* Creates a new cargo packet
* @param source the source of the packet
* @param count the number of cargo entities to put in this packet
* @pre count != 0 || source == INVALID_STATION
*/
- CargoPacket(StationID source = INVALID_STATION, uint16 count = 0);
+ CargoPacket(StationID source = INVALID_STATION, uint16 count = 0, SourceType source_type = ST_INDUSTRY, SourceID source_id = INVALID_SOURCE);
/** Destroy the packet */
~CargoPacket() { }
@@ -49,8 +53,11 @@ struct CargoPacket : CargoPacketPool::PoolItem<&_cargopacket_pool> {
*/
FORCEINLINE bool SameSource(const CargoPacket *cp) const
{
- return this->source_xy == cp->source_xy && this->days_in_transit == cp->days_in_transit;
+ return this->source_xy == cp->source_xy && this->days_in_transit == cp->days_in_transit &&
+ this->source_type == cp->source_type && this->source_id == cp->source_id;
}
+
+ static void InvalidateAllFrom(SourceType src_type, SourceID src);
};
/**
diff --git a/src/economy.cpp b/src/economy.cpp
index 45cab5c59..f8bba522c 100644
--- a/src/economy.cpp
+++ b/src/economy.cpp
@@ -328,11 +328,13 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner)
Company::Get(old_owner)->money = UINT64_MAX >> 2; // jackpot ;p
}
- if (new_owner == INVALID_OWNER) {
- Subsidy *s;
- FOR_ALL_SUBSIDIES(s) {
- if (s->IsAwarded() && Station::Get(s->dst)->owner == old_owner) {
- s->cargo_type = CT_INVALID;
+ Subsidy *s;
+ FOR_ALL_SUBSIDIES(s) {
+ if (s->awarded == old_owner) {
+ if (new_owner == INVALID_OWNER) {
+ DeleteSubsidy(s);
+ } else {
+ s->awarded = new_owner;
}
}
}
@@ -916,45 +918,38 @@ static void DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, int nu
/**
* Delivers goods to industries/towns and calculates the payment
* @param num_pieces amount of cargo delivered
- * @param source Originstation of the cargo
* @param dest Station the cargo has been unloaded
* @param source_tile The origin of the cargo for distance calculation
* @param days_in_transit Travel time
* @param company The company delivering the cargo
- * The cargo is just added to the stockpile of the industry. It is due to the caller to trigger the industry's production machinery
+ * @param src_type Type of source of cargo (industry, town, headquarters)
+ * @param src Index of source of cargo
+ * @return Revenue for delivering cargo
+ * @note The cargo is just added to the stockpile of the industry. It is due to the caller to trigger the industry's production machinery
*/
-static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID source, StationID dest, TileIndex source_tile, byte days_in_transit, Company *company)
+static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID dest, TileIndex source_tile, byte days_in_transit, Company *company, SourceType src_type, SourceID src)
{
- bool subsidised = false;
-
assert(num_pieces > 0);
/* Update company statistics */
company->cur_economy.delivered_cargo += num_pieces;
SetBit(company->cargo_types, cargo_type);
- const Station *s_to = Station::Get(dest);
-
- if (source != INVALID_STATION) {
- const Station *s_from = Station::Get(source);
-
- /* Check if a subsidy applies. */
- subsidised = CheckSubsidised(s_from, s_to, cargo_type, company->index);
- }
+ const Station *st = Station::Get(dest);
/* Increase town's counter for some special goods types */
const CargoSpec *cs = CargoSpec::Get(cargo_type);
- if (cs->town_effect == TE_FOOD) s_to->town->new_act_food += num_pieces;
- if (cs->town_effect == TE_WATER) s_to->town->new_act_water += num_pieces;
+ if (cs->town_effect == TE_FOOD) st->town->new_act_food += num_pieces;
+ if (cs->town_effect == TE_WATER) st->town->new_act_water += num_pieces;
/* Give the goods to the industry. */
- DeliverGoodsToIndustry(s_to, cargo_type, num_pieces);
+ DeliverGoodsToIndustry(st, cargo_type, num_pieces);
/* Determine profit */
- Money profit = GetTransportedGoodsIncome(num_pieces, DistanceManhattan(source_tile, s_to->xy), days_in_transit, cargo_type);
+ Money profit = GetTransportedGoodsIncome(num_pieces, DistanceManhattan(source_tile, st->xy), days_in_transit, cargo_type);
/* Modify profit if a subsidy is in effect */
- if (subsidised) {
+ if (CheckSubsidised(cargo_type, company->index, src_type, src, st)) {
switch (_settings_game.difficulty.subsidy_multiplier) {
case 0: profit += profit >> 1; break;
case 1: profit *= 2; break;
@@ -1051,7 +1046,7 @@ void CargoPayment::PayFinalDelivery(CargoPacket *cp, uint count)
}
/* Handle end of route payment */
- Money profit = DeliverGoods(count, this->ct, cp->source, this->current_station, cp->source_xy, cp->days_in_transit, this->owner);
+ Money profit = DeliverGoods(count, this->ct, this->current_station, cp->source_xy, cp->days_in_transit, this->owner, cp->source_type, cp->source_id);
this->route_profit += profit;
/* The vehicle's profit is whatever route profit there is minus feeder shares. */
diff --git a/src/economy_func.h b/src/economy_func.h
index 85def7807..af31e8c7d 100644
--- a/src/economy_func.h
+++ b/src/economy_func.h
@@ -32,7 +32,7 @@ int UpdateCompanyRatingAndValue(Company *c, bool update);
void StartupIndustryDailyChanges(bool init_counter);
Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type);
-uint MoveGoodsToStation(TileIndex tile, int w, int h, CargoID type, uint amount);
+uint MoveGoodsToStation(TileIndex tile, int w, int h, CargoID type, uint amount, SourceType source_type, SourceID source_id);
void PrepareUnload(Vehicle *front_v);
void LoadUnloadStation(Station *st);
diff --git a/src/industry.h b/src/industry.h
index 404a4e25a..090f9267d 100644
--- a/src/industry.h
+++ b/src/industry.h
@@ -19,6 +19,7 @@
#include "tile_type.h"
#include "company_type.h"
#include "strings_type.h"
+#include "subsidy_type.h"
enum {
INVALID_INDUSTRY = 0xFFFF,
@@ -125,6 +126,8 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
Year last_prod_year; ///< last year of production
byte was_cargo_delivered; ///< flag that indicate this has been the closest industry chosen for cargo delivery by a station. see DeliverGoodsToIndustry
+ PartOfSubsidyByte part_of_subsidy; ///< NOSAVE: is this industry a source/destination of a subsidy?
+
OwnerByte founder; ///< Founder of the industry
Date construction_date; ///< Date of the construction of the industry
uint8 construction_type; ///< Way the industry was constructed (@see IndustryConstructionType)
diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp
index f38648a15..3efc21a35 100644
--- a/src/industry_cmd.cpp
+++ b/src/industry_cmd.cpp
@@ -167,11 +167,12 @@ Industry::~Industry()
DecIndustryTypeCount(this->type);
- DeleteSubsidyWith(ST_INDUSTRY, this->index);
DeleteIndustryNews(this->index);
DeleteWindowById(WC_INDUSTRY_VIEW, this->index);
InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
+ DeleteSubsidyWith(ST_INDUSTRY, this->index);
+ CargoPacket::InvalidateAllFrom(ST_INDUSTRY, this->index);
Station::RecomputeIndustriesNearForAll();
}
@@ -479,7 +480,7 @@ static void TransportIndustryGoods(TileIndex tile)
i->this_month_production[j] += cw;
- uint am = MoveGoodsToStation(i->xy, i->width, i->height, i->produced_cargo[j], cw);
+ uint am = MoveGoodsToStation(i->xy, i->width, i->height, i->produced_cargo[j], cw, ST_INDUSTRY, i->index);
i->this_month_transported[j] += am;
moved_cargo |= (am != 0);
diff --git a/src/lang/english.txt b/src/lang/english.txt
index ca5c5bf70..6ed40ea98 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -797,12 +797,12 @@ STR_NEWS_STATION_NOW_ACCEPTS_CARGO :{WHITE}{STATION
STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION} now accepts {STRING} and {STRING}
STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIGFONT}{BLACK}Offer of subsidy expired:{}{}{STRING} from {STRING2} to {STRING2} will now not attract a subsidy.
-STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIGFONT}{BLACK}Subsidy withdrawn:{}{}{STRING} service from {STATION} to {STATION} is no longer subsidised.
+STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIGFONT}{BLACK}Subsidy withdrawn:{}{}{STRING} service from {STRING2} to {STRING2} is no longer subsidised.
STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIGFONT}{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 :{BIGFONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STATION} to {STATION} will pay 50% extra for the next year!
-STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIGFONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STATION} to {STATION} will pay double rates for the next year!
-STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIGFONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STATION} to {STATION} will pay triple rates for the next year!
-STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIGFONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STATION} to {STATION} will pay quadruple rates for the next year!
+STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIGFONT}{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 :{BIGFONT}{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 :{BIGFONT}{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 :{BIGFONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay quadruple rates for the next year!
STR_NEWS_ROAD_REBUILDING :{BIGFONT}{BLACK}Traffic chaos in {TOWN}!{}{}Road rebuilding programme funded by {RAW_STRING} brings 6 months of misery to motorists!
@@ -2397,7 +2397,7 @@ STR_SUBSIDIES_OFFERED_TITLE :{BLACK}Subsidie
STR_SUBSIDIES_OFFERED_FROM_TO :{ORANGE}{STRING} from {STRING2} to {STRING2}{YELLOW} (by {DATE_SHORT})
STR_SUBSIDIES_NONE :{ORANGE}None
STR_SUBSIDIES_SUBSIDISED_TITLE :{BLACK}Services already subsidised:
-STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} from {STATION} to {STATION}{YELLOW} ({COMPANY}{YELLOW}, until {DATE_SHORT})
+STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} from {STRING2} to {STRING2}{YELLOW} ({COMPANY}{YELLOW}, until {DATE_SHORT})
STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Click on service to centre view on industry/town
# Station list window
diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp
index fa772cac1..0331feed7 100644
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -32,6 +32,7 @@
#include "../economy_base.h"
#include "../animated_tile_func.h"
#include "../subsidy_base.h"
+#include "../subsidy_func.h"
#include "table/strings.h"
@@ -230,6 +231,7 @@ static bool InitializeWindowsAndCaches()
SetCachedEngineCounts();
Station::RecomputeIndustriesNearForAll();
+ RebuildSubsidisedSourceAndDestinationCache();
/* Towns have a noise controlled number of airports system
* So each airport's noise value must be added to the town->noise_reached value
@@ -1868,17 +1870,15 @@ bool AfterLoadGame()
}
}
- {
- /* Delete invalid subsidies possibly present in old versions (but converted to new savegame) */
+ if (CheckSavegameVersion(125)) {
+ /* Convert old subsidies */
Subsidy *s;
FOR_ALL_SUBSIDIES(s) {
- if (s->IsAwarded()) {
- /* Station -> Station */
- const Station *from = Station::GetIfValid(s->src);
- const Station *to = Station::GetIfValid(s->dst);
- s->src_type = s->dst_type = ST_STATION;
- if (from != NULL && to != NULL && from->owner == to->owner && Company::IsValidID(from->owner)) continue;
- } else {
+ /* Convert only nonawarded subsidies. The original source and destination town/industry
+ * anymore for awarded subsidies, so invalidate them. */
+ if (s->remaining < 12) {
+ s->remaining = 12 - s->remaining; // convert "age" to "remaining"
+ s->awarded = INVALID_COMPANY; // not awarded to anyone
const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
switch (cs->town_effect) {
case TE_PASSENGERS:
@@ -1901,6 +1901,7 @@ bool AfterLoadGame()
break;
}
}
+ /* Awarded subsidy or invalid source/destination, invalidate */
s->cargo_type = CT_INVALID;
}
}
diff --git a/src/saveload/cargopacket_sl.cpp b/src/saveload/cargopacket_sl.cpp
index d0a7783b8..7a6a1c812 100644
--- a/src/saveload/cargopacket_sl.cpp
+++ b/src/saveload/cargopacket_sl.cpp
@@ -14,6 +14,8 @@ static const SaveLoad _cargopacket_desc[] = {
SLE_VAR(CargoPacket, count, SLE_UINT16),
SLE_VAR(CargoPacket, days_in_transit, SLE_UINT8),
SLE_VAR(CargoPacket, feeder_share, SLE_INT64),
+ SLE_CONDVAR(CargoPacket, source_type, SLE_UINT8, 125, SL_MAX_VERSION),
+ SLE_CONDVAR(CargoPacket, source_id, SLE_UINT16, 125, SL_MAX_VERSION),
/* Used to be paid_for, but that got changed. */
SLE_CONDNULL(1, 0, 120),
diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp
index f8fc0b777..14db853bf 100644
--- a/src/saveload/oldloader_sl.cpp
+++ b/src/saveload/oldloader_sl.cpp
@@ -1468,7 +1468,7 @@ static bool LoadOldEngineName(LoadgameState *ls, int num)
static const OldChunks subsidy_chunk[] = {
OCL_SVAR( OC_UINT8, Subsidy, cargo_type ),
- OCL_SVAR( OC_UINT8, Subsidy, age ),
+ OCL_SVAR( OC_UINT8, Subsidy, remaining ),
OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Subsidy, src ),
OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Subsidy, dst ),
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
index 731679dc5..ddb374dd0 100644
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -41,7 +41,7 @@
#include "saveload_internal.h"
-extern const uint16 SAVEGAME_VERSION = 124;
+extern const uint16 SAVEGAME_VERSION = 125;
SavegameType _savegame_type; ///< type of savegame we are loading
diff --git a/src/saveload/subsidy_sl.cpp b/src/saveload/subsidy_sl.cpp
index b1e889e8f..163a9ce8c 100644
--- a/src/saveload/subsidy_sl.cpp
+++ b/src/saveload/subsidy_sl.cpp
@@ -9,11 +9,14 @@
static const SaveLoad _subsidies_desc[] = {
SLE_VAR(Subsidy, cargo_type, SLE_UINT8),
- SLE_VAR(Subsidy, age, SLE_UINT8),
- SLE_CONDVAR(Subsidy, src, SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
- SLE_CONDVAR(Subsidy, src, SLE_UINT16, 5, SL_MAX_VERSION),
- SLE_CONDVAR(Subsidy, dst, SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
- SLE_CONDVAR(Subsidy, dst, SLE_UINT16, 5, SL_MAX_VERSION),
+ SLE_VAR(Subsidy, remaining, SLE_UINT8),
+ SLE_CONDVAR(Subsidy, awarded, SLE_UINT8, 125, SL_MAX_VERSION),
+ SLE_CONDVAR(Subsidy, src_type, SLE_UINT8, 125, SL_MAX_VERSION),
+ SLE_CONDVAR(Subsidy, dst_type, SLE_UINT8, 125, SL_MAX_VERSION),
+ SLE_CONDVAR(Subsidy, src, SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
+ SLE_CONDVAR(Subsidy, src, SLE_UINT16, 5, SL_MAX_VERSION),
+ SLE_CONDVAR(Subsidy, dst, SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
+ SLE_CONDVAR(Subsidy, dst, SLE_UINT16, 5, SL_MAX_VERSION),
SLE_END()
};
diff --git a/src/station.cpp b/src/station.cpp
index 81c6c186d..749c81174 100644
--- a/src/station.cpp
+++ b/src/station.cpp
@@ -90,9 +90,6 @@ Station::~Station()
/* Now delete all orders that go to the station */
RemoveOrderFromAllVehicles(OT_GOTO_STATION, this->index);
- /* Subsidies need removal as well */
- DeleteSubsidyWith(ST_STATION, this->index);
-
/* Remove all news items */
DeleteStationNews(this->index);
diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp
index 6d007dfcc..842c35134 100644
--- a/src/station_cmd.cpp
+++ b/src/station_cmd.cpp
@@ -2840,9 +2840,9 @@ void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint rad
}
}
-static void UpdateStationWaiting(Station *st, CargoID type, uint amount)
+static void UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceType source_type, SourceID source_id)
{
- st->goods[type].cargo.Append(new CargoPacket(st->index, amount));
+ st->goods[type].cargo.Append(new CargoPacket(st->index, amount, source_type, source_id));
SetBit(st->goods[type].acceptance_pickup, GoodsEntry::PICKUP);
StationAnimationTrigger(st, st->xy, STAT_ANIM_NEW_CARGO, type);
@@ -2926,7 +2926,7 @@ void FindStationsAroundTiles(TileIndex tile, int w_prod, int h_prod, StationList
}
}
-uint MoveGoodsToStation(TileIndex tile, int w, int h, CargoID type, uint amount)
+uint MoveGoodsToStation(TileIndex tile, int w, int h, CargoID type, uint amount, SourceType source_type, SourceID source_id)
{
/* Return if nothing to do. Also the rounding below fails for 0. */
if (amount == 0) return 0;
@@ -2968,7 +2968,7 @@ uint MoveGoodsToStation(TileIndex tile, int w, int h, CargoID type, uint amount)
if (st2 == NULL) {
/* only one station around */
uint moved = amount * best_rating1 / 256 + 1;
- UpdateStationWaiting(st1, type, moved);
+ UpdateStationWaiting(st1, type, moved, source_type, source_id);
return moved;
}
@@ -2987,13 +2987,13 @@ uint MoveGoodsToStation(TileIndex tile, int w, int h, CargoID type, uint amount)
if (t != 0) {
moved = t * best_rating1 / 256 + 1;
amount -= t;
- UpdateStationWaiting(st1, type, moved);
+ UpdateStationWaiting(st1, type, moved, source_type, source_id);
}
if (amount != 0) {
amount = amount * best_rating2 / 256 + 1;
moved += amount;
- UpdateStationWaiting(st2, type, amount);
+ UpdateStationWaiting(st2, type, amount, source_type, source_id);
}
return moved;
diff --git a/src/subsidy.cpp b/src/subsidy.cpp
index d09030df4..ad79c37e0 100644
--- a/src/subsidy.cpp
+++ b/src/subsidy.cpp
@@ -22,27 +22,23 @@
/**
* Marks subsidy as awarded, creates news and AI event
- * @param from source station
- * @param to destination station
* @param company awarded company
*/
-void Subsidy::AwardTo(StationID from, StationID to, CompanyID company)
+void Subsidy::AwardTo(CompanyID company)
{
assert(!this->IsAwarded());
- this->age = 12;
- this->src_type = this->dst_type = ST_STATION;
- this->src = from;
- this->dst = to;
-
- /* Add a news item */
- Pair reftype = SetupSubsidyDecodeParam(this, 0);
- InjectDParam(1);
+ this->awarded = company;
+ this->remaining = 12;
char *company_name = MallocT<char>(MAX_LENGTH_COMPANY_NAME_BYTES);
SetDParam(0, company);
GetString(company_name, STR_COMPANY_NAME, company_name + MAX_LENGTH_COMPANY_NAME_BYTES - 1);
+ /* Add a news item */
+ Pair reftype = SetupSubsidyDecodeParam(this, 0);
+ InjectDParam(1);
+
SetDParamStr(0, company_name);
AddNewsItem(
STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF + _settings_game.difficulty.subsidy_multiplier,
@@ -62,7 +58,10 @@ void Subsidy::AwardTo(StationID from, StationID to, CompanyID company)
/* static */ Subsidy *Subsidy::AllocateItem()
{
for (Subsidy *s = Subsidy::array; s < endof(Subsidy::array); s++) {
- if (!s->IsValid()) return s;
+ if (!s->IsValid()) {
+ s->awarded = INVALID_COMPANY;
+ return s;
+ }
}
return NULL;
@@ -105,10 +104,6 @@ Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode)
reftype1 = NR_TOWN;
SetDParam(1, STR_TOWN_NAME);
break;
- case ST_STATION:
- reftype1 = NR_STATION;
- SetDParam(1, s->src);
- break;
default: NOT_REACHED();
}
SetDParam(2, s->src);
@@ -122,10 +117,6 @@ Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode)
reftype2 = NR_TOWN;
SetDParam(4, STR_TOWN_NAME);
break;
- case ST_STATION:
- reftype2 = NR_STATION;
- SetDParam(2, s->dst);
- break;
default: NOT_REACHED();
}
SetDParam(5, s->dst);
@@ -136,6 +127,42 @@ Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode)
return p;
}
+/**
+ * Sets a flag indicating that given town/industry is part of subsidised route.
+ * @param type is it a town or an industry?
+ * @param index index of town/industry
+ * @param flag flag to set
+ */
+static inline void SetPartOfSubsidyFlag(SourceType type, SourceID index, PartOfSubsidy flag)
+{
+ switch (type) {
+ case ST_INDUSTRY: Industry::Get(index)->part_of_subsidy |= flag; return;
+ case ST_TOWN: Town::Get(index)->part_of_subsidy |= flag; return;
+ default: NOT_REACHED();
+ }
+}
+
+void RebuildSubsidisedSourceAndDestinationCache()
+{
+ Town *t;
+ FOR_ALL_TOWNS(t) t->part_of_subsidy = POS_NONE;
+
+ Industry *i;
+ FOR_ALL_INDUSTRIES(i) i->part_of_subsidy = POS_NONE;
+
+ const Subsidy *s;
+ FOR_ALL_SUBSIDIES(s) {
+ SetPartOfSubsidyFlag(s->src_type, s->src, POS_SRC);
+ SetPartOfSubsidyFlag(s->dst_type, s->dst, POS_DST);
+ }
+}
+
+void DeleteSubsidy(Subsidy *s)
+{
+ s->cargo_type = CT_INVALID;
+ RebuildSubsidisedSourceAndDestinationCache();
+}
+
void DeleteSubsidyWith(SourceType type, SourceID index)
{
bool dirty = false;
@@ -252,23 +279,20 @@ void SubsidyMonthlyLoop()
Subsidy *s;
FOR_ALL_SUBSIDIES(s) {
- if (s->age == 12 - 1) {
- Pair reftype = SetupSubsidyDecodeParam(s, 1);
- AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NS_SUBSIDIES, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst);
- s->cargo_type = CT_INVALID;
- modified = true;
- AI::BroadcastNewEvent(new AIEventSubsidyOfferExpired(s->Index()));
- } else if (s->age == 2 * 12 - 1) {
- Station *st = Station::Get(s->dst);
- if (st->owner == _local_company) {
+ if (--s->remaining == 0) {
+ if (!s->IsAwarded()) {
Pair reftype = SetupSubsidyDecodeParam(s, 1);
- AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NS_SUBSIDIES, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst);
+ AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NS_SUBSIDIES, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst);
+ AI::BroadcastNewEvent(new AIEventSubsidyOfferExpired(s->Index()));
+ } else {
+ if (s->awarded == _local_company) {
+ Pair reftype = SetupSubsidyDecodeParam(s, 1);
+ AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NS_SUBSIDIES, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst);
+ }
+ AI::BroadcastNewEvent(new AIEventSubsidyExpired(s->Index()));
}
- s->cargo_type = CT_INVALID;
+ DeleteSubsidy(s);
modified = true;
- AI::BroadcastNewEvent(new AIEventSubsidyExpired(s->Index()));
- } else {
- s->age++;
}
}
@@ -306,9 +330,11 @@ void SubsidyMonthlyLoop()
}
add_subsidy:
if (!CheckSubsidyDuplicate(s)) {
- s->age = 0;
+ s->remaining = 12;
Pair reftype = SetupSubsidyDecodeParam(s, 0);
AddNewsItem(STR_NEWS_SERVICE_SUBSIDY_OFFERED, NS_SUBSIDIES, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst);
+ SetPartOfSubsidyFlag(s->src_type, s->src, POS_SRC);
+ SetPartOfSubsidyFlag(s->dst_type, s->dst, POS_DST);
AI::BroadcastNewEvent(new AIEventSubsidyOffer(s->Index()));
modified = true;
break;
@@ -321,51 +347,85 @@ no_add:;
InvalidateWindow(WC_SUBSIDIES_LIST, 0);
}
-bool CheckSubsidised(const Station *from, const Station *to, CargoID cargo_type, CompanyID company)
+/**
+ * Tests whether given delivery is subsidised and possibly awards the subsidy to delivering company
+ * @param cargo_type type of cargo
+ * @param company company delivering the cargo
+ * @param src_type type of #src
+ * @param src index of source
+ * @param st station where the cargo is delivered to
+ * @return is the delivery subsidised?
+ */
+bool CheckSubsidised(CargoID cargo_type, CompanyID company, SourceType src_type, SourceID src, const Station *st)
{
- Subsidy *s;
- TileIndex xy;
+ /* If the source isn't subsidised, don't continue */
+ if (src == INVALID_SOURCE) return false;
+ switch (src_type) {
+ case ST_INDUSTRY:
+ if (!(Industry::Get(src)->part_of_subsidy & POS_SRC)) return false;
+ break;
+ case ST_TOWN:
+ if (!( Town::Get(src)->part_of_subsidy & POS_SRC)) return false;
+ break;
+ default: return false;
+ }
- /* check if there is an already existing subsidy that applies to us */
- FOR_ALL_SUBSIDIES(s) {
- if (s->cargo_type == cargo_type &&
- s->IsAwarded() &&
- s->src == from->index &&
- s->dst == to->index) {
- return true;
+ /* Remember all towns near this station (at least one house in its catchment radius)
+ * which are destination of subsidised path. Do that only if needed */
+ SmallVector<const Town *, 2> towns_near;
+ if (!st->rect.IsEmpty()) {
+ Subsidy *s;
+ FOR_ALL_SUBSIDIES(s) {
+ /* Don't create the cache if there is no applicable subsidy with town as destination */
+ if (s->dst_type != ST_TOWN) continue;
+ if (s->cargo_type != cargo_type || s->src_type != src_type || s->src != src) continue;
+ if (s->IsAwarded() && s->awarded != company) continue;
+
+ Rect rect = st->GetCatchmentRect();
+
+ for (int y = rect.top; y <= rect.bottom; y++) {
+ for (int x = rect.left; x <= rect.right; x++) {
+ TileIndex tile = TileXY(x, y);
+ if (!IsTileType(tile, MP_HOUSE)) continue;
+ const Town *t = Town::GetByTile(tile);
+ if (t->part_of_subsidy & POS_DST) towns_near.Include(t);
+ }
+ }
+ break;
}
}
- /* check if there's a new subsidy that applies.. */
+ bool subsidised = false;
+
+ /* Check if there's a (new) subsidy that applies. There can be more subsidies triggered by this delivery!
+ * Think about the case that subsidies are A->B and A->C and station has both B and C in its catchment area */
+ Subsidy *s;
FOR_ALL_SUBSIDIES(s) {
- if (s->cargo_type == cargo_type && !s->IsAwarded()) {
- /* Check distance from source */
- const CargoSpec *cs = CargoSpec::Get(cargo_type);
- if (cs->town_effect == TE_PASSENGERS || cs->town_effect == TE_MAIL) {
- xy = Town::Get(s->src)->xy;
- } else {
- xy = Industry::Get(s->src)->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->dst)->xy;
+ if (s->cargo_type == cargo_type && s->src_type == src_type && s->src == src && (!s->IsAwarded() || s->awarded == company)) {
+ switch (s->dst_type) {
+ case ST_INDUSTRY:
+ for (const Industry * const *ip = st->industries_near.Begin(); ip != st->industries_near.End(); ip++) {
+ if (s->dst == (*ip)->index) {
+ assert((*ip)->part_of_subsidy & POS_DST);
+ subsidised = true;
+ if (!s->IsAwarded()) s->AwardTo(company);
+ }
+ }
break;
-
- default:
- xy = Industry::Get(s->dst)->xy;
+ case ST_TOWN:
+ for (const Town * const *tp = towns_near.Begin(); tp != towns_near.End(); tp++) {
+ if (s->dst == (*tp)->index) {
+ assert((*tp)->part_of_subsidy & POS_DST);
+ subsidised = true;
+ if (!s->IsAwarded()) s->AwardTo(company);
+ }
+ }
break;
+ default:
+ NOT_REACHED();
}
- if (DistanceMax(xy, to->xy) > 9) continue;
-
- s->AwardTo(from->index, to->index, company);
- return true;
}
}
- return false;
+
+ return subsidised;
}
diff --git a/src/subsidy_base.h b/src/subsidy_base.h
index 1460c4eec..4750605bc 100644
--- a/src/subsidy_base.h
+++ b/src/subsidy_base.h
@@ -7,18 +7,17 @@
#include "cargo_type.h"
#include "company_type.h"
-#include "station_type.h"
-
-typedef uint16 SubsidyID; ///< ID of a subsidy
+#include "subsidy_type.h"
/** Struct about subsidies, offered and awarded */
struct Subsidy {
CargoID cargo_type; ///< Cargo type involved in this subsidy, CT_INVALID for invalid subsidy
- byte age; ///< Subsidy age; < 12 is unawarded, >= 12 is awarded
- SourceTypeByte src_type; ///< Source of subsidised path
- SourceTypeByte dst_type; ///< Destination of subsidised path
- uint16 src; ///< Index of source. Either TownID, IndustryID or StationID, when awarded
- uint16 dst; ///< Index of destination. Either TownID, IndustryID or StationID, when awarded
+ byte remaining; ///< Remaining months when this subsidy is valid
+ CompanyByte awarded; ///< Subsidy is awarded to this company; INVALID_COMPANY if it's not awarded to anyone
+ SourceTypeByte src_type; ///< Source of subsidised path (ST_INDUSTRY or ST_TOWN)
+ SourceTypeByte dst_type; ///< Destination of subsidised path (ST_INDUSTRY or ST_TOWN)
+ SourceID src; ///< Index of source. Either TownID or IndustryID
+ SourceID dst; ///< Index of destination. Either TownID or IndustryID
/**
* Tests whether this subsidy has been awarded to someone
@@ -26,10 +25,10 @@ struct Subsidy {
*/
FORCEINLINE bool IsAwarded() const
{
- return this->age >= 12;
+ return this->awarded != INVALID_COMPANY;
}
- void AwardTo(StationID from, StationID to, CompanyID company);
+ void AwardTo(CompanyID company);
/**
* Determines index of this subsidy
diff --git a/src/subsidy_func.h b/src/subsidy_func.h
index 5ec466a5f..1cca00a59 100644
--- a/src/subsidy_func.h
+++ b/src/subsidy_func.h
@@ -13,7 +13,9 @@
Pair SetupSubsidyDecodeParam(const struct Subsidy *s, bool mode);
void DeleteSubsidyWith(SourceType type, SourceID index);
-bool CheckSubsidised(const Station *from, const Station *to, CargoID cargo_type, CompanyID company);
+bool CheckSubsidised(CargoID cargo_type, CompanyID company, SourceType src_type, SourceID src, const Station *st);
void SubsidyMonthlyHandler();
+void RebuildSubsidisedSourceAndDestinationCache();
+void DeleteSubsidy(struct Subsidy *s);
#endif /* SUBSIDY_FUNC_H */
diff --git a/src/subsidy_gui.cpp b/src/subsidy_gui.cpp
index de7d71c57..becc4d97a 100644
--- a/src/subsidy_gui.cpp
+++ b/src/subsidy_gui.cpp
@@ -83,7 +83,6 @@ struct SubsidyListWindow : Window {
switch (s->src_type) {
case ST_INDUSTRY: xy = Industry::Get(s->src)->xy; break;
case ST_TOWN: xy = Town::Get(s->src)->xy; break;
- case ST_STATION: xy = Station::Get(s->src)->xy; break;
default: NOT_REACHED();
}
@@ -94,11 +93,9 @@ struct SubsidyListWindow : Window {
switch (s->dst_type) {
case ST_INDUSTRY: xy = Industry::Get(s->dst)->xy; break;
case ST_TOWN: xy = Town::Get(s->dst)->xy; break;
- case ST_STATION: xy = Station::Get(s->dst)->xy; break;
default: NOT_REACHED();
}
-
if (_ctrl_pressed) {
ShowExtraViewPortWindow(xy);
} else {
@@ -129,7 +126,7 @@ struct SubsidyListWindow : Window {
if (!s->IsAwarded()) {
/* Displays the two offered towns */
SetupSubsidyDecodeParam(s, 1);
- SetDParam(7, _date - ymd.day + 384 - s->age * 32);
+ SetDParam(7, _date - ymd.day + s->remaining * 32);
DrawString(x + 2, right - 2, y, STR_SUBSIDIES_OFFERED_FROM_TO);
y += FONT_HEIGHT_NORMAL;
@@ -150,8 +147,8 @@ struct SubsidyListWindow : Window {
FOR_ALL_SUBSIDIES(s) {
if (s->IsAwarded()) {
SetupSubsidyDecodeParam(s, 1);
- SetDParam(3, Station::Get(s->dst)->owner);
- SetDParam(4, _date - ymd.day + 768 - s->age * 32);
+ SetDParam(7, s->awarded);
+ SetDParam(8, _date - ymd.day + s->remaining * 32);
/* Displays the two connected stations */
DrawString(x + 2, right - 2, y, STR_SUBSIDIES_SUBSIDISED_FROM_TO);
diff --git a/src/subsidy_type.h b/src/subsidy_type.h
new file mode 100644
index 000000000..db7f989eb
--- /dev/null
+++ b/src/subsidy_type.h
@@ -0,0 +1,22 @@
+/* $Id$ */
+
+/** @file subsidy_type.h basic types related to subsidies */
+
+#ifndef SUBSIDY_TYPE_H
+#define SUBSIDY_TYPE_H
+
+#include "core/enum_type.hpp"
+
+enum PartOfSubsidy {
+ POS_NONE = 0,
+ POS_SRC = 1 << 0, ///< bit 0 set -> town/industry is source of subsidised path
+ POS_DST = 1 << 1, ///< bit 1 set -> town/industry is destination of subsidised path
+};
+typedef SimpleTinyEnumT<PartOfSubsidy, byte> PartOfSubsidyByte;
+
+DECLARE_ENUM_AS_BIT_SET(PartOfSubsidy);
+
+typedef uint16 SubsidyID; ///< ID of a subsidy
+struct Subsidy;
+
+#endif /* SUBSIDY_TYPE_H */
diff --git a/src/town.h b/src/town.h
index 38327fa41..d41b1fc82 100644
--- a/src/town.h
+++ b/src/town.h
@@ -20,6 +20,7 @@
#include "map_type.h"
#include "command_type.h"
#include "town_map.h"
+#include "subsidy_type.h"
template <typename T>
struct BuildingCounts {
@@ -107,6 +108,8 @@ struct Town : TownPool::PoolItem<&_town_pool> {
bool larger_town;
TownLayoutByte layout; ///< town specific road layout
+ PartOfSubsidyByte part_of_subsidy; ///< NOSAVE: is this town a source/destination of a subsidy?
+
/* NOSAVE: UpdateTownRadius updates this given the house count. */
uint32 squared_town_zone_radius[HZB_END];
diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp
index bb16c11e1..b4249a1f8 100644
--- a/src/town_cmd.cpp
+++ b/src/town_cmd.cpp
@@ -99,7 +99,7 @@ Town::~Town()
}
DeleteSubsidyWith(ST_TOWN, this->index);
-
+ CargoPacket::InvalidateAllFrom(ST_TOWN, this->index);
MarkWholeScreenDirty();
}
@@ -460,7 +460,7 @@ static void TileLoop_Town(TileIndex tile)
uint amt = GB(callback, 0, 8);
if (amt == 0) continue;
- uint moved = MoveGoodsToStation(tile, 1, 1, cargo, amt);
+ uint moved = MoveGoodsToStation(tile, 1, 1, cargo, amt, ST_TOWN, t->index);
const CargoSpec *cs = CargoSpec::Get(cargo);
switch (cs->town_effect) {
@@ -484,7 +484,7 @@ static void TileLoop_Town(TileIndex tile)
if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
t->new_max_pass += amt;
- t->new_act_pass += MoveGoodsToStation(tile, 1, 1, CT_PASSENGERS, amt);
+ t->new_act_pass += MoveGoodsToStation(tile, 1, 1, CT_PASSENGERS, amt, ST_TOWN, t->index);
}
if (GB(r, 8, 8) < hs->mail_generation) {
@@ -492,7 +492,7 @@ static void TileLoop_Town(TileIndex tile)
if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
t->new_max_mail += amt;
- t->new_act_mail += MoveGoodsToStation(tile, 1, 1, CT_MAIL, amt);
+ t->new_act_mail += MoveGoodsToStation(tile, 1, 1, CT_MAIL, amt, ST_TOWN, t->index);
}
}
diff --git a/src/unmovable_cmd.cpp b/src/unmovable_cmd.cpp
index 832318dd5..0aec67b6a 100644
--- a/src/unmovable_cmd.cpp
+++ b/src/unmovable_cmd.cpp
@@ -23,6 +23,7 @@
#include "cheat_type.h"
#include "landscape_type.h"
#include "unmovable.h"
+#include "cargopacket.h"
#include "table/strings.h"
#include "table/sprites.h"
@@ -62,6 +63,8 @@ static CommandCost DestroyCompanyHQ(CompanyID cid, DoCommandFlag flags)
DoClearSquare(t + TileDiffXY(1, 1));
c->location_of_HQ = INVALID_TILE; // reset HQ position
InvalidateWindow(WC_COMPANY, cid);
+
+ CargoPacket::InvalidateAllFrom(ST_HEADQUARTERS, cid);
}
/* cost of relocating company is 1% of company value */
@@ -335,7 +338,7 @@ static void TileLoop_Unmovable(TileIndex tile)
if (GB(r, 0, 8) < (256 / 4 / (6 - level))) {
uint amt = GB(r, 0, 8) / 8 / 4 + 1;
if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
- MoveGoodsToStation(tile, 2, 2, CT_PASSENGERS, amt);
+ MoveGoodsToStation(tile, 2, 2, CT_PASSENGERS, amt, ST_HEADQUARTERS, GetTileOwner(tile));
}
/* Top town building generates 90, HQ can make up to 196. The
@@ -344,7 +347,7 @@ static void TileLoop_Unmovable(TileIndex tile)
if (GB(r, 8, 8) < (196 / 4 / (6 - level))) {
uint amt = GB(r, 8, 8) / 8 / 4 + 1;
if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
- MoveGoodsToStation(tile, 2, 2, CT_MAIL, amt);
+ MoveGoodsToStation(tile, 2, 2, CT_MAIL, amt, ST_HEADQUARTERS, GetTileOwner(tile));
}
}