diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj index bf10c3c042..2b8d7257ae 100644 --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -1487,6 +1487,10 @@ RelativePath=".\..\src\subsidy_func.h" > + + diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj index 0e07feca72..5b65ba9773 100644 --- a/projects/openttd_vs90.vcproj +++ b/projects/openttd_vs90.vcproj @@ -1484,6 +1484,10 @@ RelativePath=".\..\src\subsidy_func.h" > + + diff --git a/source.list b/source.list index 4318e4dc41..ca42b24307 100644 --- a/source.list +++ b/source.list @@ -300,6 +300,7 @@ strings_func.h strings_type.h subsidy_base.h subsidy_func.h +subsidy_type.h tar_type.h terraform_gui.h textbuf_gui.h diff --git a/src/ai/api/ai_changelog.hpp b/src/ai/api/ai_changelog.hpp index 5750ab0aca..a8e5110303 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 fd3e29745c..39358e963a 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 7be86b0e8b..96ad92c31c 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 30145f266f..0222af8061 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 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 65514e647f..355cabebb0 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 414003faa4..de8268a98c 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 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 45cab5c594..f8bba522c3 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 85def7807a..af31e8c7d3 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 404a4e25a6..090f9267de 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 f38648a158..3efc21a35f 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 ca5c5bf70a..6ed40ea981 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 fa772cac15..0331feed72 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 d0a7783b8f..7a6a1c812b 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 f8fc0b7778..14db853bfb 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 731679dc5c..ddb374dd07 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 b1e889e8fa..163a9ce8c0 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 81c6c186df..749c811745 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 6d007dfcc5..842c35134e 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 d09030df44..ad79c37e01 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(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 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 1460c4eecb..4750605bc6 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 5ec466a5f6..1cca00a590 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 de7d71c570..becc4d97a5 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 0000000000..db7f989ebb --- /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 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 38327fa414..d41b1fc827 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 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 bb16c11e12..b4249a1f86 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 832318dd51..0aec67b6a3 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)); } }