OpenTTD Source  20241120-master-g6d3adc6169
subsidy.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #include "stdafx.h"
11 #include "company_func.h"
12 #include "industry.h"
13 #include "town.h"
14 #include "news_func.h"
15 #include "ai/ai.hpp"
16 #include "station_base.h"
17 #include "strings_func.h"
18 #include "window_func.h"
19 #include "subsidy_base.h"
20 #include "subsidy_func.h"
21 #include "core/pool_func.hpp"
22 #include "core/random_func.hpp"
23 #include "core/container_func.hpp"
24 #include "game/game.hpp"
25 #include "command_func.h"
26 #include "string_func.h"
27 #include "tile_cmd.h"
28 #include "subsidy_cmd.h"
29 #include "timer/timer.h"
31 
32 #include "table/strings.h"
33 
34 #include "safeguards.h"
35 
38 
39 
43 void Subsidy::AwardTo(CompanyID company)
44 {
45  assert(!this->IsAwarded());
46 
47  this->awarded = company;
49 
50  SetDParam(0, company);
51  std::string company_name = GetString(STR_COMPANY_NAME);
52 
53  /* Add a news item */
54  std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(this, SubsidyDecodeParamType::NewsAwarded, 1);
55 
56  SetDParamStr(0, company_name);
58  STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF + _settings_game.difficulty.subsidy_multiplier,
60  reftype.first, this->src, reftype.second, this->dst
61  );
62  AI::BroadcastNewEvent(new ScriptEventSubsidyAwarded(this->index));
63  Game::NewEvent(new ScriptEventSubsidyAwarded(this->index));
64 
66 }
67 
75 std::pair<NewsReferenceType, NewsReferenceType> SetupSubsidyDecodeParam(const Subsidy *s, SubsidyDecodeParamType mode, uint parameter_offset)
76 {
77  NewsReferenceType reftype1 = NR_NONE;
78  NewsReferenceType reftype2 = NR_NONE;
79 
80  /* Always use the plural form of the cargo name - trying to decide between plural or singular causes issues for translations */
81  const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
82  SetDParam(parameter_offset, cs->name);
83 
84  switch (s->src_type) {
86  reftype1 = NR_INDUSTRY;
87  SetDParam(parameter_offset + 1, STR_INDUSTRY_NAME);
88  break;
89  case SourceType::Town:
90  reftype1 = NR_TOWN;
91  SetDParam(parameter_offset + 1, STR_TOWN_NAME);
92  break;
93  default: NOT_REACHED();
94  }
95  SetDParam(parameter_offset + 2, s->src);
96 
97  switch (s->dst_type) {
99  reftype2 = NR_INDUSTRY;
100  SetDParam(parameter_offset + 4, STR_INDUSTRY_NAME);
101  break;
102  case SourceType::Town:
103  reftype2 = NR_TOWN;
104  SetDParam(parameter_offset + 4, STR_TOWN_NAME);
105  break;
106  default: NOT_REACHED();
107  }
108  SetDParam(parameter_offset + 5, s->dst);
109 
110  /* If the subsidy is being offered or awarded, the news item mentions the subsidy duration. */
112  SetDParam(parameter_offset + 7, _settings_game.difficulty.subsidy_duration);
113  }
114 
115  return std::pair<NewsReferenceType, NewsReferenceType>(reftype1, reftype2);
116 }
117 
124 static inline void SetPartOfSubsidyFlag(SourceType type, SourceID index, PartOfSubsidy flag)
125 {
126  switch (type) {
127  case SourceType::Industry: Industry::Get(index)->part_of_subsidy |= flag; return;
128  case SourceType::Town: Town::Get(index)->cache.part_of_subsidy |= flag; return;
129  default: NOT_REACHED();
130  }
131 }
132 
135 {
136  for (Town *t : Town::Iterate()) t->cache.part_of_subsidy = POS_NONE;
137 
138  for (Industry *i : Industry::Iterate()) i->part_of_subsidy = POS_NONE;
139 
140  for (const Subsidy *s : Subsidy::Iterate()) {
141  SetPartOfSubsidyFlag(s->src_type, s->src, POS_SRC);
142  SetPartOfSubsidyFlag(s->dst_type, s->dst, POS_DST);
143  }
144 }
145 
152 {
153  bool dirty = false;
154 
155  for (Subsidy *s : Subsidy::Iterate()) {
156  if ((s->src_type == type && s->src == index) || (s->dst_type == type && s->dst == index)) {
157  delete s;
158  dirty = true;
159  }
160  }
161 
162  if (dirty) {
165  }
166 }
167 
177 static bool CheckSubsidyDuplicate(CargoID cargo, SourceType src_type, SourceID src, SourceType dst_type, SourceID dst)
178 {
179  for (const Subsidy *s : Subsidy::Iterate()) {
180  if (s->cargo_type == cargo &&
181  s->src_type == src_type && s->src == src &&
182  s->dst_type == dst_type && s->dst == dst) {
183  return true;
184  }
185  }
186  return false;
187 }
188 
197 static bool CheckSubsidyDistance(SourceType src_type, SourceID src, SourceType dst_type, SourceID dst)
198 {
199  TileIndex tile_src = (src_type == SourceType::Town) ? Town::Get(src)->xy : Industry::Get(src)->location.tile;
200  TileIndex tile_dst = (dst_type == SourceType::Town) ? Town::Get(dst)->xy : Industry::Get(dst)->location.tile;
201 
202  return (DistanceManhattan(tile_src, tile_dst) <= SUBSIDY_MAX_DISTANCE);
203 }
204 
213 void CreateSubsidy(CargoID cid, SourceType src_type, SourceID src, SourceType dst_type, SourceID dst)
214 {
215  Subsidy *s = new Subsidy();
216  s->cargo_type = cid;
217  s->src_type = src_type;
218  s->src = src;
219  s->dst_type = dst_type;
220  s->dst = dst;
223 
224  std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::NewsOffered);
225  AddNewsItem(STR_NEWS_SERVICE_SUBSIDY_OFFERED, NT_SUBSIDIES, NF_NORMAL, reftype.first, s->src, reftype.second, s->dst);
228  AI::BroadcastNewEvent(new ScriptEventSubsidyOffer(s->index));
229  Game::NewEvent(new ScriptEventSubsidyOffer(s->index));
230 
232 }
233 
245 {
246  if (!Subsidy::CanAllocateItem()) return CMD_ERROR;
247 
248  if (_current_company != OWNER_DEITY) return CMD_ERROR;
249 
250  if (cid >= NUM_CARGO || !::CargoSpec::Get(cid)->IsValid()) return CMD_ERROR;
251 
252  switch (src_type) {
253  case SourceType::Town:
254  if (!Town::IsValidID(src)) return CMD_ERROR;
255  break;
257  if (!Industry::IsValidID(src)) return CMD_ERROR;
258  break;
259  default:
260  return CMD_ERROR;
261  }
262  switch (dst_type) {
263  case SourceType::Town:
264  if (!Town::IsValidID(dst)) return CMD_ERROR;
265  break;
267  if (!Industry::IsValidID(dst)) return CMD_ERROR;
268  break;
269  default:
270  return CMD_ERROR;
271  }
272 
273  if (flags & DC_EXEC) {
274  CreateSubsidy(cid, src_type, src, dst_type, dst);
275  }
276 
277  return CommandCost();
278 }
279 
285 {
286  if (!Subsidy::CanAllocateItem()) return false;
287 
288  /* Pick a random TPE_PASSENGER type */
289  uint32_t r = RandomRange(static_cast<uint>(CargoSpec::town_production_cargoes[TPE_PASSENGERS].size()));
291 
292  const Town *src = Town::GetRandom();
294  src->GetPercentTransported(cid) > SUBSIDY_MAX_PCT_TRANSPORTED) {
295  return false;
296  }
297 
298  const Town *dst = Town::GetRandom();
299  if (dst->cache.population < SUBSIDY_PAX_MIN_POPULATION || src == dst) {
300  return false;
301  }
302 
303  if (DistanceManhattan(src->xy, dst->xy) > SUBSIDY_MAX_DISTANCE) return false;
304  if (CheckSubsidyDuplicate(cid, SourceType::Town, src->index, SourceType::Town, dst->index)) return false;
305 
307 
308  return true;
309 }
310 
311 bool FindSubsidyCargoDestination(CargoID cid, SourceType src_type, SourceID src);
312 
313 
319 {
320  if (!Subsidy::CanAllocateItem()) return false;
321 
322  SourceType src_type = SourceType::Town;
323 
324  /* Select a random town. */
325  const Town *src_town = Town::GetRandom();
326  if (src_town->cache.population < SUBSIDY_CARGO_MIN_POPULATION) return false;
327 
328  /* Calculate the produced cargo of houses around town center. */
329  CargoArray town_cargo_produced{};
330  TileArea ta = TileArea(src_town->xy, 1, 1).Expand(SUBSIDY_TOWN_CARGO_RADIUS);
331  for (TileIndex tile : ta) {
332  if (IsTileType(tile, MP_HOUSE)) {
333  AddProducedCargo(tile, town_cargo_produced);
334  }
335  }
336 
337  /* Passenger subsidies are not handled here. */
339  town_cargo_produced[cs->Index()] = 0;
340  }
341 
342  uint8_t cargo_count = town_cargo_produced.GetCount();
343 
344  /* No cargo produced at all? */
345  if (cargo_count == 0) return false;
346 
347  /* Choose a random cargo that is produced in the town. */
348  uint8_t cargo_number = RandomRange(cargo_count);
349  CargoID cid;
350  for (cid = 0; cid < NUM_CARGO; cid++) {
351  if (town_cargo_produced[cid] > 0) {
352  if (cargo_number == 0) break;
353  cargo_number--;
354  }
355  }
356 
357  /* Avoid using invalid NewGRF cargoes. */
358  if (!CargoSpec::Get(cid)->IsValid() ||
359  _settings_game.linkgraph.GetDistributionType(cid) != DT_MANUAL) {
360  return false;
361  }
362 
363  /* Quit if the percentage transported is large enough. */
364  if (src_town->GetPercentTransported(cid) > SUBSIDY_MAX_PCT_TRANSPORTED) return false;
365 
366  SourceID src = src_town->index;
367 
368  return FindSubsidyCargoDestination(cid, src_type, src);
369 }
370 
376 {
377  if (!Subsidy::CanAllocateItem()) return false;
378 
379  SourceType src_type = SourceType::Industry;
380 
381  /* Select a random industry. */
382  const Industry *src_ind = Industry::GetRandom();
383  if (src_ind == nullptr) return false;
384 
385  uint trans, total;
386 
387  CargoID cid;
388 
389  /* Randomize cargo type */
390  int num_cargos = std::count_if(std::begin(src_ind->produced), std::end(src_ind->produced), [](const auto &p) { return IsValidCargoID(p.cargo); });
391  if (num_cargos == 0) return false; // industry produces nothing
392  int cargo_num = RandomRange(num_cargos) + 1;
393 
394  auto it = std::begin(src_ind->produced);
395  for (/* nothing */; it != std::end(src_ind->produced); ++it) {
396  if (IsValidCargoID(it->cargo)) cargo_num--;
397  if (cargo_num == 0) break;
398  }
399  assert(it != std::end(src_ind->produced)); // indicates loop didn't end as intended
400 
401  cid = it->cargo;
402  trans = it->history[LAST_MONTH].PctTransported();
403  total = it->history[LAST_MONTH].production;
404 
405  /* Quit if no production in this industry
406  * or if the pct transported is already large enough
407  * or if the cargo is automatically distributed */
408  if (total == 0 || trans > SUBSIDY_MAX_PCT_TRANSPORTED ||
409  !IsValidCargoID(cid) ||
410  _settings_game.linkgraph.GetDistributionType(cid) != DT_MANUAL) {
411  return false;
412  }
413 
414  SourceID src = src_ind->index;
415 
416  return FindSubsidyCargoDestination(cid, src_type, src);
417 }
418 
427 {
428  /* Choose a random destination. */
430 
431  SourceID dst;
432  switch (dst_type) {
433  case SourceType::Town: {
434  /* Select a random town. */
435  const Town *dst_town = Town::GetRandom();
436 
437  /* Calculate cargo acceptance of houses around town center. */
438  CargoArray town_cargo_accepted{};
439  TileArea ta = TileArea(dst_town->xy, 1, 1).Expand(SUBSIDY_TOWN_CARGO_RADIUS);
440  for (TileIndex tile : ta) {
441  if (IsTileType(tile, MP_HOUSE)) {
442  AddAcceptedCargo(tile, town_cargo_accepted, nullptr);
443  }
444  }
445 
446  /* Check if the town can accept this cargo. */
447  if (town_cargo_accepted[cid] < 8) return false;
448 
449  dst = dst_town->index;
450  break;
451  }
452 
453  case SourceType::Industry: {
454  /* Select a random industry. */
455  const Industry *dst_ind = Industry::GetRandom();
456  if (dst_ind == nullptr) return false;
457 
458  /* The industry must accept the cargo */
459  if (!dst_ind->IsCargoAccepted(cid)) return false;
460 
461  dst = dst_ind->index;
462  break;
463  }
464 
465  default: NOT_REACHED();
466  }
467 
468  /* Check that the source and the destination are not the same. */
469  if (src_type == dst_type && src == dst) return false;
470 
471  /* Check distance between source and destination. */
472  if (!CheckSubsidyDistance(src_type, src, dst_type, dst)) return false;
473 
474  /* Avoid duplicate subsidies. */
475  if (CheckSubsidyDuplicate(cid, src_type, src, dst_type, dst)) return false;
476 
477  CreateSubsidy(cid, src_type, src, dst_type, dst);
478 
479  return true;
480 }
481 
483 static IntervalTimer<TimerGameEconomy> _economy_subsidies_monthly({TimerGameEconomy::MONTH, TimerGameEconomy::Priority::SUBSIDY}, [](auto)
484 {
485  bool modified = false;
486 
487  for (Subsidy *s : Subsidy::Iterate()) {
488  if (--s->remaining == 0) {
489  if (!s->IsAwarded()) {
490  std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::NewsWithdrawn);
491  AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NT_SUBSIDIES, NF_NORMAL, reftype.first, s->src, reftype.second, s->dst);
492  AI::BroadcastNewEvent(new ScriptEventSubsidyOfferExpired(s->index));
493  Game::NewEvent(new ScriptEventSubsidyOfferExpired(s->index));
494  } else {
495  if (s->awarded == _local_company) {
496  std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::NewsWithdrawn);
497  AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NT_SUBSIDIES, NF_NORMAL, reftype.first, s->src, reftype.second, s->dst);
498  }
499  AI::BroadcastNewEvent(new ScriptEventSubsidyExpired(s->index));
500  Game::NewEvent(new ScriptEventSubsidyExpired(s->index));
501  }
502  delete s;
503  modified = true;
504  }
505  }
506 
507  if (modified) {
509  } else if (_settings_game.difficulty.subsidy_duration == 0) {
510  /* If subsidy duration is set to 0, subsidies are disabled, so bail out. */
511  return;
516  /* Return early if there are no manually distributed cargoes and if we
517  * don't need to invalidate the subsidies window. */
518  return;
519  }
520 
521  bool passenger_subsidy = false;
522  bool town_subsidy = false;
523  bool industry_subsidy = false;
524 
525  int random_chance = RandomRange(16);
526 
527  if (random_chance < 2 && _settings_game.linkgraph.distribution_pax == DT_MANUAL) {
528  /* There is a 1/8 chance each month of generating a passenger subsidy. */
529  int n = 1000;
530 
531  do {
532  passenger_subsidy = FindSubsidyPassengerRoute();
533  } while (!passenger_subsidy && n--);
534  } else if (random_chance == 2) {
535  /* Cargo subsidies with a town as a source have a 1/16 chance. */
536  int n = 1000;
537 
538  do {
539  town_subsidy = FindSubsidyTownCargoRoute();
540  } while (!town_subsidy && n--);
541  } else if (random_chance == 3) {
542  /* Cargo subsidies with an industry as a source have a 1/16 chance. */
543  int n = 1000;
544 
545  do {
546  industry_subsidy = FindSubsidyIndustryCargoRoute();
547  } while (!industry_subsidy && n--);
548  }
549 
550  modified |= passenger_subsidy || town_subsidy || industry_subsidy;
551 
552  if (modified) InvalidateWindowData(WC_SUBSIDIES_LIST, 0);
553 });
554 
564 bool CheckSubsidised(CargoID cargo_type, CompanyID company, SourceType src_type, SourceID src, const Station *st)
565 {
566  /* If the source isn't subsidised, don't continue */
567  if (src == INVALID_SOURCE) return false;
568  switch (src_type) {
570  if (!(Industry::Get(src)->part_of_subsidy & POS_SRC)) return false;
571  break;
572  case SourceType::Town:
573  if (!(Town::Get(src)->cache.part_of_subsidy & POS_SRC)) return false;
574  break;
575  default: return false;
576  }
577 
578  /* Remember all towns near this station (at least one house in its catchment radius)
579  * which are destination of subsidised path. Do that only if needed */
580  std::vector<const Town *> towns_near;
581  if (!st->rect.IsEmpty()) {
582  for (const Subsidy *s : Subsidy::Iterate()) {
583  /* Don't create the cache if there is no applicable subsidy with town as destination */
584  if (s->dst_type != SourceType::Town) continue;
585  if (s->cargo_type != cargo_type || s->src_type != src_type || s->src != src) continue;
586  if (s->IsAwarded() && s->awarded != company) continue;
587 
589  for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
590  if (!IsTileType(tile, MP_HOUSE)) continue;
591  const Town *t = Town::GetByTile(tile);
592  if (t->cache.part_of_subsidy & POS_DST) include(towns_near, t);
593  }
594  break;
595  }
596  }
597 
598  bool subsidised = false;
599 
600  /* Check if there's a (new) subsidy that applies. There can be more subsidies triggered by this delivery!
601  * Think about the case that subsidies are A->B and A->C and station has both B and C in its catchment area */
602  for (Subsidy *s : Subsidy::Iterate()) {
603  if (s->cargo_type == cargo_type && s->src_type == src_type && s->src == src && (!s->IsAwarded() || s->awarded == company)) {
604  switch (s->dst_type) {
606  for (const auto &i : st->industries_near) {
607  if (s->dst == i.industry->index) {
608  assert(i.industry->part_of_subsidy & POS_DST);
609  subsidised = true;
610  if (!s->IsAwarded()) s->AwardTo(company);
611  }
612  }
613  break;
614  case SourceType::Town:
615  for (const Town *tp : towns_near) {
616  if (s->dst == tp->index) {
617  assert(tp->cache.part_of_subsidy & POS_DST);
618  subsidised = true;
619  if (!s->IsAwarded()) s->AwardTo(company);
620  }
621  }
622  break;
623  default:
624  NOT_REACHED();
625  }
626  }
627  }
628 
629  return subsidised;
630 }
Base functions for all AIs.
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:22
bool IsValidCargoID(CargoID t)
Test whether cargo type is not INVALID_CARGO.
Definition: cargo_type.h:107
uint16_t SourceID
Contains either industry ID, town ID or company ID (or INVALID_SOURCE)
Definition: cargo_type.h:143
static const SourceID INVALID_SOURCE
Invalid/unknown index of source.
Definition: cargo_type.h:144
static const CargoID NUM_CARGO
Maximum number of cargo types in a game.
Definition: cargo_type.h:74
SourceType
Types of cargo source and destination.
Definition: cargo_type.h:137
@ Industry
Source/destination is an industry.
@ Town
Source/destination is a town.
@ TPE_PASSENGERS
Cargo behaves passenger-like for production.
Definition: cargotype.h:36
static void BroadcastNewEvent(ScriptEvent *event, CompanyID skip_company=MAX_COMPANIES)
Broadcast a new event to all active AIs.
Definition: ai_core.cpp:263
Iterator to iterate over all tiles belonging to a bitmaptilearea.
Definition: bitmap_type.h:106
Common return value for all commands.
Definition: command_type.h:23
static void NewEvent(class ScriptEvent *event)
Queue a new event for a Game Script.
Definition: game_core.cpp:146
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition: timer.h:76
static constexpr int MONTHS_IN_YEAR
months per year
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
Definition: command_func.h:28
DoCommandFlag
List of flags for a command.
Definition: command_type.h:374
@ DC_EXEC
execute the given command
Definition: command_type.h:376
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:52
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:53
Functions related to companies.
Owner
Enum for all companies/owners.
Definition: company_type.h:18
@ INVALID_COMPANY
An invalid company.
Definition: company_type.h:30
@ OWNER_DEITY
The object is owned by a superuser / goal script.
Definition: company_type.h:27
Some simple functions to help with accessing containers.
bool include(Container &container, typename Container::const_reference &item)
Helper function to append an item to a container if it is not already contained.
Base functions for all Games.
Base of all industries.
@ DT_MANUAL
Manual distribution. No link graph calculations are run.
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition: map.cpp:146
Functions related to news.
void AddNewsItem(StringID string, NewsType type, NewsFlag flags, NewsReferenceType reftype1=NR_NONE, uint32_t ref1=UINT32_MAX, NewsReferenceType reftype2=NR_NONE, uint32_t ref2=UINT32_MAX, const NewsAllocatedData *data=nullptr)
Add a new newsitem to be shown.
Definition: news_gui.cpp:829
@ NT_SUBSIDIES
News about subsidies (announcements, expirations, acceptance)
Definition: news_type.h:38
NewsReferenceType
References to objects in news.
Definition: news_type.h:52
@ NR_TOWN
Reference town. Scroll to town when clicking on the news.
Definition: news_type.h:58
@ NR_INDUSTRY
Reference industry. Scroll to industry when clicking on the news. Delete news when industry is delete...
Definition: news_type.h:57
@ NR_NONE
Empty reference.
Definition: news_type.h:53
@ NF_NORMAL
Normal news item. (Newspaper with text only)
Definition: news_type.h:81
Some methods of Pool are placed here in order to reduce compilation time and binary size.
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
Definition: pool_func.hpp:237
Pseudo random number generator.
uint32_t RandomRange(uint32_t limit, const std::source_location location=std::source_location::current())
Pick a random number between 0 and limit - 1, inclusive.
Definition: random_func.hpp:88
bool Chance16(const uint32_t a, const uint32_t b, const std::source_location location=std::source_location::current())
Flips a coin with given probability.
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:57
Base classes/functions for stations.
Definition of base types and functions in a cross-platform compatible way.
Functions related to low-level strings.
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings.cpp:104
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition: strings.cpp:319
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition: strings.cpp:357
Functions related to OTTD's strings.
StationRect rect
NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions.
Class for storing amounts of cargo.
Definition: cargo_type.h:114
Specification of a cargo type.
Definition: cargotype.h:71
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition: cargotype.h:134
StringID name
Name of this type of cargo.
Definition: cargotype.h:88
static std::array< std::vector< const CargoSpec * >, NUM_TPE > town_production_cargoes
List of cargo specs for each Town Product Effect.
Definition: cargotype.h:193
uint16_t subsidy_duration
duration of subsidies
uint8_t subsidy_multiplier
payment multiplier for subsidized deliveries
DifficultySettings difficulty
settings related to the difficulty
LinkGraphSettings linkgraph
settings for link graph calculations
Defines the internal data of a functional industry.
Definition: industry.h:66
static Industry * GetRandom()
Return a random valid industry.
bool IsCargoAccepted() const
Test if this industry accepts any cargo.
Definition: industry.h:210
ProducedCargoes produced
produced cargo slots
Definition: industry.h:97
DistributionType distribution_mail
distribution type for mail
DistributionType distribution_default
distribution type for all other goods
DistributionType distribution_pax
distribution type for passengers
DistributionType distribution_armoured
distribution type for armoured cargo class
Represents the covered area of e.g.
Definition: tilearea_type.h:18
OrthogonalTileArea & Expand(int rad)
Expand a tile area by rad tiles in each direction, keeping within map bounds.
Definition: tilearea.cpp:123
Tindex index
Index of this pool item.
Definition: pool_type.hpp:238
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:339
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:328
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
Definition: pool_type.hpp:309
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition: pool_type.hpp:388
Base class for all pools.
Definition: pool_type.hpp:80
Station data structure.
Definition: station_base.h:439
IndustryList industries_near
Cached list of industries near the station that can accept cargo,.
Definition: station_base.h:471
BitmapTileArea catchment_tiles
NOSAVE: Set of individual tiles covered by catchment area.
Definition: station_base.h:459
Struct about subsidies, offered and awarded.
Definition: subsidy_base.h:22
SourceType dst_type
Destination of subsidised path (SourceType::Industry or SourceType::Town)
Definition: subsidy_base.h:27
SourceType src_type
Source of subsidised path (SourceType::Industry or SourceType::Town)
Definition: subsidy_base.h:26
CompanyID awarded
Subsidy is awarded to this company; INVALID_COMPANY if it's not awarded to anyone.
Definition: subsidy_base.h:25
CargoID cargo_type
Cargo type involved in this subsidy, INVALID_CARGO for invalid subsidy.
Definition: subsidy_base.h:23
uint16_t remaining
Remaining months when this subsidy is valid.
Definition: subsidy_base.h:24
SourceID src
Index of source. Either TownID or IndustryID.
Definition: subsidy_base.h:28
SourceID dst
Index of destination. Either TownID or IndustryID.
Definition: subsidy_base.h:29
uint32_t population
Current population of people.
Definition: town.h:44
PartOfSubsidy part_of_subsidy
Is this town a source/destination of a subsidy?
Definition: town.h:46
Town data structure.
Definition: town.h:54
TileIndex xy
town center tile
Definition: town.h:55
static Town * GetRandom()
Return a random valid town.
Definition: town_cmd.cpp:196
TownCache cache
Container for all cacheable data.
Definition: town.h:57
std::pair< NewsReferenceType, NewsReferenceType > SetupSubsidyDecodeParam(const Subsidy *s, SubsidyDecodeParamType mode, uint parameter_offset)
Setup the string parameters for printing the subsidy at the screen, and compute the news reference fo...
Definition: subsidy.cpp:75
static void SetPartOfSubsidyFlag(SourceType type, SourceID index, PartOfSubsidy flag)
Sets a flag indicating that given town/industry is part of subsidised route.
Definition: subsidy.cpp:124
SubsidyPool _subsidy_pool("Subsidy")
Pool for the subsidies.
bool FindSubsidyIndustryCargoRoute()
Tries to create a cargo subsidy with an industry as source.
Definition: subsidy.cpp:375
void CreateSubsidy(CargoID cid, SourceType src_type, SourceID src, SourceType dst_type, SourceID dst)
Creates a subsidy with the given parameters.
Definition: subsidy.cpp:213
bool FindSubsidyPassengerRoute()
Tries to create a passenger subsidy between two towns.
Definition: subsidy.cpp:284
bool FindSubsidyTownCargoRoute()
Tries to create a cargo subsidy with a town as source.
Definition: subsidy.cpp:318
bool CheckSubsidised(CargoID cargo_type, CompanyID company, SourceType src_type, SourceID src, const Station *st)
Tests whether given delivery is subsidised and possibly awards the subsidy to delivering company.
Definition: subsidy.cpp:564
static IntervalTimer< TimerGameEconomy > _economy_subsidies_monthly({TimerGameEconomy::MONTH, TimerGameEconomy::Priority::SUBSIDY}, [](auto) { bool modified=false;for(Subsidy *s :Subsidy::Iterate()) { if(--s->remaining==0) { if(!s->IsAwarded()) { std::pair< NewsReferenceType, NewsReferenceType > reftype=SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::NewsWithdrawn);AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NT_SUBSIDIES, NF_NORMAL, reftype.first, s->src, reftype.second, s->dst);AI::BroadcastNewEvent(new ScriptEventSubsidyOfferExpired(s->index));Game::NewEvent(new ScriptEventSubsidyOfferExpired(s->index));} else { if(s->awarded==_local_company) { std::pair< NewsReferenceType, NewsReferenceType > reftype=SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::NewsWithdrawn);AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NT_SUBSIDIES, NF_NORMAL, reftype.first, s->src, reftype.second, s->dst);} AI::BroadcastNewEvent(new ScriptEventSubsidyExpired(s->index));Game::NewEvent(new ScriptEventSubsidyExpired(s->index));} delete s;modified=true;} } if(modified) { RebuildSubsidisedSourceAndDestinationCache();} else if(_settings_game.difficulty.subsidy_duration==0) { return;} else if(_settings_game.linkgraph.distribution_pax !=DT_MANUAL &&_settings_game.linkgraph.distribution_mail !=DT_MANUAL &&_settings_game.linkgraph.distribution_armoured !=DT_MANUAL &&_settings_game.linkgraph.distribution_default !=DT_MANUAL) { return;} bool passenger_subsidy=false;bool town_subsidy=false;bool industry_subsidy=false;int random_chance=RandomRange(16);if(random_chance< 2 &&_settings_game.linkgraph.distribution_pax==DT_MANUAL) { int n=1000;do { passenger_subsidy=FindSubsidyPassengerRoute();} while(!passenger_subsidy &&n--);} else if(random_chance==2) { int n=1000;do { town_subsidy=FindSubsidyTownCargoRoute();} while(!town_subsidy &&n--);} else if(random_chance==3) { int n=1000;do { industry_subsidy=FindSubsidyIndustryCargoRoute();} while(!industry_subsidy &&n--);} modified|=passenger_subsidy||town_subsidy||industry_subsidy;if(modified) InvalidateWindowData(WC_SUBSIDIES_LIST, 0);})
Perform the economy monthly update of open subsidies, and try to create a new one.
void DeleteSubsidyWith(SourceType type, SourceID index)
Delete the subsidies associated with a given cargo source type and id.
Definition: subsidy.cpp:151
void RebuildSubsidisedSourceAndDestinationCache()
Perform a full rebuild of the subsidies cache.
Definition: subsidy.cpp:134
static bool CheckSubsidyDuplicate(CargoID cargo, SourceType src_type, SourceID src, SourceType dst_type, SourceID dst)
Check whether a specific subsidy already exists.
Definition: subsidy.cpp:177
CommandCost CmdCreateSubsidy(DoCommandFlag flags, CargoID cid, SourceType src_type, SourceID src, SourceType dst_type, SourceID dst)
Create a new subsidy.
Definition: subsidy.cpp:244
bool FindSubsidyCargoDestination(CargoID cid, SourceType src_type, SourceID src)
Tries to find a suitable destination for the given source and cargo.
Definition: subsidy.cpp:426
static bool CheckSubsidyDistance(SourceType src_type, SourceID src, SourceType dst_type, SourceID dst)
Checks if the source and destination of a subsidy are inside the distance limit.
Definition: subsidy.cpp:197
Subsidy base class.
static const uint SUBSIDY_MAX_DISTANCE
Max. length of subsidised route (DistanceManhattan)
Definition: subsidy_base.h:58
static const uint SUBSIDY_CARGO_MIN_POPULATION
Min. population of destination town for cargo route.
Definition: subsidy_base.h:56
static const uint SUBSIDY_TOWN_CARGO_RADIUS
Extent of a tile area around town center when scanning for town cargo acceptance and production (6 ~=...
Definition: subsidy_base.h:59
SubsidyDecodeParamType
Types of subsidy news messages, which determine how the date is printed and whether to use singular o...
Definition: subsidy_base.h:62
@ NewsAwarded
News item for an awarded subsidy.
@ NewsWithdrawn
News item for a subsidy offer withdrawn, or expired subsidy.
@ NewsOffered
News item for an offered subsidy.
static const uint SUBSIDY_PAX_MIN_POPULATION
Min. population of towns for subsidised pax route.
Definition: subsidy_base.h:55
static const uint SUBSIDY_MAX_PCT_TRANSPORTED
Subsidy will be created only for towns/industries with less % transported.
Definition: subsidy_base.h:57
static const uint SUBSIDY_OFFER_MONTHS
Constants related to subsidies.
Definition: subsidy_base.h:54
Command definitions related to subsidies.
Functions related to subsidies.
PartOfSubsidy
What part of a subsidy is something?
Definition: subsidy_type.h:16
@ POS_NONE
nothing
Definition: subsidy_type.h:17
@ POS_SRC
bit 0 set -> town/industry is source of subsidised path
Definition: subsidy_type.h:18
@ POS_DST
bit 1 set -> town/industry is destination of subsidised path
Definition: subsidy_type.h:19
Generic 'commands' that can be performed on all tiles.
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition: tile_map.h:150
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:95
@ MP_HOUSE
A house by a town.
Definition: tile_type.h:51
OrthogonalTileArea TileArea
Shorthand for the much more common orthogonal tile area.
Definition of Interval and OneShot timers.
Definition of the game-economy-timer.
Base of the town class.
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition: window.cpp:3211
Window functions not directly related to making/drawing windows.
@ WC_SUBSIDIES_LIST
Subsidies list; Window numbers:
Definition: window_type.h:260