OpenTTD Source  20241120-master-g6d3adc6169
station_cmd.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 "aircraft.h"
12 #include "bridge_map.h"
13 #include "vehiclelist_func.h"
14 #include "viewport_func.h"
15 #include "viewport_kdtree.h"
16 #include "command_func.h"
17 #include "town.h"
18 #include "news_func.h"
19 #include "train.h"
20 #include "ship.h"
21 #include "roadveh.h"
22 #include "industry.h"
23 #include "newgrf_cargo.h"
24 #include "newgrf_debug.h"
25 #include "newgrf_station.h"
26 #include "newgrf_canal.h" /* For the buoy */
28 #include "road_internal.h" /* For drawing catenary/checking road removal */
29 #include "autoslope.h"
30 #include "water.h"
31 #include "strings_internal.h"
32 #include "clear_func.h"
34 #include "vehicle_func.h"
35 #include "string_func.h"
36 #include "animated_tile_func.h"
37 #include "elrail_func.h"
38 #include "station_base.h"
39 #include "station_func.h"
40 #include "station_kdtree.h"
41 #include "roadstop_base.h"
42 #include "newgrf_railtype.h"
43 #include "newgrf_roadtype.h"
44 #include "waypoint_base.h"
45 #include "waypoint_func.h"
46 #include "pbs.h"
47 #include "debug.h"
48 #include "core/random_func.hpp"
49 #include "core/container_func.hpp"
50 #include "company_base.h"
51 #include "table/airporttile_ids.h"
52 #include "newgrf_airporttiles.h"
53 #include "order_backup.h"
54 #include "newgrf_house.h"
55 #include "company_gui.h"
57 #include "linkgraph/refresh.h"
58 #include "tunnelbridge_map.h"
59 #include "station_cmd.h"
60 #include "waypoint_cmd.h"
61 #include "landscape_cmd.h"
62 #include "rail_cmd.h"
63 #include "newgrf_roadstop.h"
64 #include "timer/timer.h"
67 #include "timer/timer_game_tick.h"
68 #include "cheat_type.h"
69 #include "road_func.h"
70 
71 #include "widgets/station_widget.h"
72 
73 #include "table/strings.h"
74 
75 #include <bitset>
76 
77 #include "safeguards.h"
78 
84 /* static */ const FlowStat::SharesMap FlowStat::empty_sharesmap;
85 
92 bool IsHangar(Tile t)
93 {
94  assert(IsTileType(t, MP_STATION));
95 
96  /* If the tile isn't an airport there's no chance it's a hangar. */
97  if (!IsAirport(t)) return false;
98 
99  const Station *st = Station::GetByTile(t);
100  const AirportSpec *as = st->airport.GetSpec();
101 
102  for (const auto &depot : as->depots) {
103  if (st->airport.GetRotatedTileFromOffset(depot.ti) == TileIndex(t)) return true;
104  }
105 
106  return false;
107 }
108 
118 template <class T, class F>
119 CommandCost GetStationAround(TileArea ta, StationID closest_station, CompanyID company, T **st, F filter)
120 {
121  ta.Expand(1);
122 
123  /* check around to see if there are any stations there owned by the company */
124  for (TileIndex tile_cur : ta) {
125  if (IsTileType(tile_cur, MP_STATION)) {
126  StationID t = GetStationIndex(tile_cur);
127  if (!T::IsValidID(t) || T::Get(t)->owner != company || !filter(T::Get(t))) continue;
128  if (closest_station == INVALID_STATION) {
129  closest_station = t;
130  } else if (closest_station != t) {
131  return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
132  }
133  }
134  }
135  *st = (closest_station == INVALID_STATION) ? nullptr : T::Get(closest_station);
136  return CommandCost();
137 }
138 
144 typedef bool (*CMSAMatcher)(TileIndex tile);
145 
153 {
154  int num = 0;
155 
156  for (int dx = -3; dx <= 3; dx++) {
157  for (int dy = -3; dy <= 3; dy++) {
158  TileIndex t = TileAddWrap(tile, dx, dy);
159  if (t != INVALID_TILE && cmp(t)) num++;
160  }
161  }
162 
163  return num;
164 }
165 
171 static bool CMSAMine(TileIndex tile)
172 {
173  /* No industry */
174  if (!IsTileType(tile, MP_INDUSTRY)) return false;
175 
176  const Industry *ind = Industry::GetByTile(tile);
177 
178  /* No extractive industry */
179  if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_EXTRACTIVE) == 0) return false;
180 
181  for (const auto &p : ind->produced) {
182  /* The industry extracts something non-liquid, i.e. no oil or plastic, so it is a mine.
183  * Also the production of passengers and mail is ignored. */
184  if (IsValidCargoID(p.cargo) &&
185  (CargoSpec::Get(p.cargo)->classes & (CC_LIQUID | CC_PASSENGERS | CC_MAIL)) == 0) {
186  return true;
187  }
188  }
189 
190  return false;
191 }
192 
198 static bool CMSAWater(TileIndex tile)
199 {
200  return IsTileType(tile, MP_WATER) && IsWater(tile);
201 }
202 
208 static bool CMSATree(TileIndex tile)
209 {
210  return IsTileType(tile, MP_TREES);
211 }
212 
213 #define M(x) ((x) - STR_SV_STNAME)
214 
215 enum StationNaming {
216  STATIONNAMING_RAIL,
217  STATIONNAMING_ROAD,
218  STATIONNAMING_AIRPORT,
219  STATIONNAMING_OILRIG,
220  STATIONNAMING_DOCK,
221  STATIONNAMING_HELIPORT,
222 };
223 
226  uint32_t free_names;
227  std::bitset<NUM_INDUSTRYTYPES> indtypes;
228 };
229 
238 static bool FindNearIndustryName(TileIndex tile, void *user_data)
239 {
240  /* All already found industry types */
242  if (!IsTileType(tile, MP_INDUSTRY)) return false;
243 
244  /* If the station name is undefined it means that it doesn't name a station */
245  IndustryType indtype = GetIndustryType(tile);
246  if (GetIndustrySpec(indtype)->station_name == STR_UNDEFINED) return false;
247 
248  /* In all cases if an industry that provides a name is found two of
249  * the standard names will be disabled. */
250  sni->free_names &= ~(1 << M(STR_SV_STNAME_OILFIELD) | 1 << M(STR_SV_STNAME_MINES));
251  return !sni->indtypes[indtype];
252 }
253 
254 static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming name_class)
255 {
256  static const uint32_t _gen_station_name_bits[] = {
257  0, // STATIONNAMING_RAIL
258  0, // STATIONNAMING_ROAD
259  1U << M(STR_SV_STNAME_AIRPORT), // STATIONNAMING_AIRPORT
260  1U << M(STR_SV_STNAME_OILFIELD), // STATIONNAMING_OILRIG
261  1U << M(STR_SV_STNAME_DOCKS), // STATIONNAMING_DOCK
262  1U << M(STR_SV_STNAME_HELIPORT), // STATIONNAMING_HELIPORT
263  };
264 
265  const Town *t = st->town;
266 
268  sni.free_names = UINT32_MAX;
269 
270  for (const Station *s : Station::Iterate()) {
271  if (s != st && s->town == t) {
272  if (s->indtype != IT_INVALID) {
273  sni.indtypes[s->indtype] = true;
274  StringID name = GetIndustrySpec(s->indtype)->station_name;
275  if (name != STR_UNDEFINED) {
276  /* Filter for other industrytypes with the same name */
277  for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
278  const IndustrySpec *indsp = GetIndustrySpec(it);
279  if (indsp->enabled && indsp->station_name == name) sni.indtypes[it] = true;
280  }
281  }
282  continue;
283  }
284  uint str = M(s->string_id);
285  if (str <= 0x20) {
286  if (str == M(STR_SV_STNAME_FOREST)) {
287  str = M(STR_SV_STNAME_WOODS);
288  }
289  ClrBit(sni.free_names, str);
290  }
291  }
292  }
293 
294  TileIndex indtile = tile;
295  if (CircularTileSearch(&indtile, 7, FindNearIndustryName, &sni)) {
296  /* An industry has been found nearby */
297  IndustryType indtype = GetIndustryType(indtile);
298  const IndustrySpec *indsp = GetIndustrySpec(indtype);
299  /* STR_NULL means it only disables oil rig/mines */
300  if (indsp->station_name != STR_NULL) {
301  st->indtype = indtype;
302  return STR_SV_STNAME_FALLBACK;
303  }
304  }
305 
306  /* Oil rigs/mines name could be marked not free by looking for a near by industry. */
307 
308  /* check default names */
309  uint32_t tmp = sni.free_names & _gen_station_name_bits[name_class];
310  if (tmp != 0) return STR_SV_STNAME + FindFirstBit(tmp);
311 
312  /* check mine? */
313  if (HasBit(sni.free_names, M(STR_SV_STNAME_MINES))) {
314  if (CountMapSquareAround(tile, CMSAMine) >= 2) {
315  return STR_SV_STNAME_MINES;
316  }
317  }
318 
319  /* check close enough to town to get central as name? */
320  if (DistanceMax(tile, t->xy) < 8) {
321  if (HasBit(sni.free_names, M(STR_SV_STNAME))) return STR_SV_STNAME;
322 
323  if (HasBit(sni.free_names, M(STR_SV_STNAME_CENTRAL))) return STR_SV_STNAME_CENTRAL;
324  }
325 
326  /* Check lakeside */
327  if (HasBit(sni.free_names, M(STR_SV_STNAME_LAKESIDE)) &&
328  DistanceFromEdge(tile) < 20 &&
329  CountMapSquareAround(tile, CMSAWater) >= 5) {
330  return STR_SV_STNAME_LAKESIDE;
331  }
332 
333  /* Check woods */
334  if (HasBit(sni.free_names, M(STR_SV_STNAME_WOODS)) && (
335  CountMapSquareAround(tile, CMSATree) >= 8 ||
337  ) {
338  return _settings_game.game_creation.landscape == LT_TROPIC ? STR_SV_STNAME_FOREST : STR_SV_STNAME_WOODS;
339  }
340 
341  /* check elevation compared to town */
342  int z = GetTileZ(tile);
343  int z2 = GetTileZ(t->xy);
344  if (z < z2) {
345  if (HasBit(sni.free_names, M(STR_SV_STNAME_VALLEY))) return STR_SV_STNAME_VALLEY;
346  } else if (z > z2) {
347  if (HasBit(sni.free_names, M(STR_SV_STNAME_HEIGHTS))) return STR_SV_STNAME_HEIGHTS;
348  }
349 
350  /* check direction compared to town */
351  static const int8_t _direction_and_table[] = {
352  ~( (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_EAST)) | (1 << M(STR_SV_STNAME_NORTH)) ),
353  ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_NORTH)) ),
354  ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_EAST)) | (1 << M(STR_SV_STNAME_NORTH)) ),
355  ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_EAST)) ),
356  };
357 
358  sni.free_names &= _direction_and_table[
359  (TileX(tile) < TileX(t->xy)) +
360  (TileY(tile) < TileY(t->xy)) * 2];
361 
363  static const uint32_t fallback_names = (
364  (1U << M(STR_SV_STNAME_NORTH)) |
365  (1U << M(STR_SV_STNAME_SOUTH)) |
366  (1U << M(STR_SV_STNAME_EAST)) |
367  (1U << M(STR_SV_STNAME_WEST)) |
368  (1U << M(STR_SV_STNAME_TRANSFER)) |
369  (1U << M(STR_SV_STNAME_HALT)) |
370  (1U << M(STR_SV_STNAME_EXCHANGE)) |
371  (1U << M(STR_SV_STNAME_ANNEXE)) |
372  (1U << M(STR_SV_STNAME_SIDINGS)) |
373  (1U << M(STR_SV_STNAME_BRANCH)) |
374  (1U << M(STR_SV_STNAME_UPPER)) |
375  (1U << M(STR_SV_STNAME_LOWER))
376  );
377 
378  sni.free_names &= fallback_names;
379  return (sni.free_names == 0) ? STR_SV_STNAME_FALLBACK : (STR_SV_STNAME + FindFirstBit(sni.free_names));
380 }
381 #undef M
382 
389 {
390  uint threshold = 8;
391 
392  Station *best_station = nullptr;
393  ForAllStationsRadius(tile, threshold, [&](Station *st) {
394  if (!st->IsInUse() && st->owner == _current_company) {
395  uint cur_dist = DistanceManhattan(tile, st->xy);
396 
397  if (cur_dist < threshold) {
398  threshold = cur_dist;
399  best_station = st;
400  } else if (cur_dist == threshold && best_station != nullptr) {
401  /* In case of a tie, lowest station ID wins */
402  if (st->index < best_station->index) best_station = st;
403  }
404  }
405  });
406 
407  return best_station;
408 }
409 
410 
412 {
413  switch (type) {
414  case STATION_RAIL:
415  *ta = this->train_station;
416  return;
417 
418  case STATION_AIRPORT:
419  *ta = this->airport;
420  return;
421 
422  case STATION_TRUCK:
423  *ta = this->truck_station;
424  return;
425 
426  case STATION_BUS:
427  *ta = this->bus_station;
428  return;
429 
430  case STATION_DOCK:
431  case STATION_OILRIG:
432  *ta = this->docking_station;
433  return;
434 
435  default: NOT_REACHED();
436  }
437 }
438 
443 {
444  Point pt = RemapCoords2(TileX(this->xy) * TILE_SIZE, TileY(this->xy) * TILE_SIZE);
445 
446  pt.y -= 32 * ZOOM_BASE;
447  if ((this->facilities & FACIL_AIRPORT) && this->airport.type == AT_OILRIG) pt.y -= 16 * ZOOM_BASE;
448 
449  if (this->sign.kdtree_valid) _viewport_sign_kdtree.Remove(ViewportSignKdtreeItem::MakeStation(this->index));
450 
451  SetDParam(0, this->index);
452  SetDParam(1, this->facilities);
453  this->sign.UpdatePosition(pt.x, pt.y, STR_VIEWPORT_STATION, STR_VIEWPORT_STATION_TINY);
454 
455  _viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeStation(this->index));
456 
458 }
459 
465 {
466  if (this->xy == new_xy) return;
467 
468  _station_kdtree.Remove(this->index);
469 
470  this->BaseStation::MoveSign(new_xy);
471 
472  _station_kdtree.Insert(this->index);
473 }
474 
477 {
478  for (BaseStation *st : BaseStation::Iterate()) {
479  st->UpdateVirtCoord();
480  }
481 }
482 
483 void BaseStation::FillCachedName() const
484 {
485  auto tmp_params = MakeParameters(this->index);
486  this->cached_name = GetStringWithArgs(Waypoint::IsExpected(this) ? STR_WAYPOINT_NAME : STR_STATION_NAME, tmp_params);
487 }
488 
489 void ClearAllStationCachedNames()
490 {
491  for (BaseStation *st : BaseStation::Iterate()) {
492  st->cached_name.clear();
493  }
494 }
495 
501 CargoTypes GetAcceptanceMask(const Station *st)
502 {
503  CargoTypes mask = 0;
504 
505  for (auto it = std::begin(st->goods); it != std::end(st->goods); ++it) {
506  if (HasBit(it->status, GoodsEntry::GES_ACCEPTANCE)) SetBit(mask, std::distance(std::begin(st->goods), it));
507  }
508  return mask;
509 }
510 
516 CargoTypes GetEmptyMask(const Station *st)
517 {
518  CargoTypes mask = 0;
519 
520  for (auto it = std::begin(st->goods); it != std::end(st->goods); ++it) {
521  if (it->cargo.TotalCount() == 0) SetBit(mask, std::distance(std::begin(st->goods), it));
522  }
523  return mask;
524 }
525 
532 static void ShowRejectOrAcceptNews(const Station *st, CargoTypes cargoes, bool reject)
533 {
534  SetDParam(0, st->index);
535  SetDParam(1, cargoes);
536  StringID msg = reject ? STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_LIST : STR_NEWS_STATION_NOW_ACCEPTS_CARGO_LIST;
538 }
539 
547 CargoArray GetProductionAroundTiles(TileIndex north_tile, int w, int h, int rad)
548 {
549  CargoArray produced{};
550  std::set<IndustryID> industries;
551  TileArea ta = TileArea(north_tile, w, h).Expand(rad);
552 
553  /* Loop over all tiles to get the produced cargo of
554  * everything except industries */
555  for (TileIndex tile : ta) {
556  if (IsTileType(tile, MP_INDUSTRY)) industries.insert(GetIndustryIndex(tile));
557  AddProducedCargo(tile, produced);
558  }
559 
560  /* Loop over the seen industries. They produce cargo for
561  * anything that is within 'rad' of any one of their tiles.
562  */
563  for (IndustryID industry : industries) {
564  const Industry *i = Industry::Get(industry);
565  /* Skip industry with neutral station */
566  if (i->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) continue;
567 
568  for (const auto &p : i->produced) {
569  if (IsValidCargoID(p.cargo)) produced[p.cargo]++;
570  }
571  }
572 
573  return produced;
574 }
575 
585 CargoArray GetAcceptanceAroundTiles(TileIndex center_tile, int w, int h, int rad, CargoTypes *always_accepted)
586 {
587  CargoArray acceptance{};
588  if (always_accepted != nullptr) *always_accepted = 0;
589 
590  TileArea ta = TileArea(center_tile, w, h).Expand(rad);
591 
592  for (TileIndex tile : ta) {
593  /* Ignore industry if it has a neutral station. */
594  if (!_settings_game.station.serve_neutral_industries && IsTileType(tile, MP_INDUSTRY) && Industry::GetByTile(tile)->neutral_station != nullptr) continue;
595 
596  AddAcceptedCargo(tile, acceptance, always_accepted);
597  }
598 
599  return acceptance;
600 }
601 
607 static CargoArray GetAcceptanceAroundStation(const Station *st, CargoTypes *always_accepted)
608 {
609  CargoArray acceptance{};
610  if (always_accepted != nullptr) *always_accepted = 0;
611 
613  for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
614  AddAcceptedCargo(tile, acceptance, always_accepted);
615  }
616 
617  return acceptance;
618 }
619 
625 void UpdateStationAcceptance(Station *st, bool show_msg)
626 {
627  /* old accepted goods types */
628  CargoTypes old_acc = GetAcceptanceMask(st);
629 
630  /* And retrieve the acceptance. */
631  CargoArray acceptance{};
632  if (!st->rect.IsEmpty()) {
633  acceptance = GetAcceptanceAroundStation(st, &st->always_accepted);
634  }
635 
636  /* Adjust in case our station only accepts fewer kinds of goods */
637  for (CargoID i = 0; i < NUM_CARGO; i++) {
638  uint amt = acceptance[i];
639 
640  /* Make sure the station can accept the goods type. */
641  bool is_passengers = IsCargoInClass(i, CC_PASSENGERS);
642  if ((!is_passengers && !(st->facilities & ~FACIL_BUS_STOP)) ||
643  (is_passengers && !(st->facilities & ~FACIL_TRUCK_STOP))) {
644  amt = 0;
645  }
646 
647  GoodsEntry &ge = st->goods[i];
648  SB(ge.status, GoodsEntry::GES_ACCEPTANCE, 1, amt >= 8);
650  (*LinkGraph::Get(ge.link_graph))[ge.node].SetDemand(amt / 8);
651  }
652  }
653 
654  /* Only show a message in case the acceptance was actually changed. */
655  CargoTypes new_acc = GetAcceptanceMask(st);
656  if (old_acc == new_acc) return;
657 
658  /* show a message to report that the acceptance was changed? */
659  if (show_msg && st->owner == _local_company && st->IsInUse()) {
660  /* Combine old and new masks to get changes */
661  CargoTypes accepts = new_acc & ~old_acc;
662  CargoTypes rejects = ~new_acc & old_acc;
663 
664  /* Show news message if there are any changes */
665  if (accepts != 0) ShowRejectOrAcceptNews(st, accepts, false);
666  if (rejects != 0) ShowRejectOrAcceptNews(st, rejects, true);
667  }
668 
669  /* redraw the station view since acceptance changed */
671 }
672 
673 static void UpdateStationSignCoord(BaseStation *st)
674 {
675  const StationRect *r = &st->rect;
676 
677  if (r->IsEmpty()) return; // no tiles belong to this station
678 
679  /* clamp sign coord to be inside the station rect */
680  TileIndex new_xy = TileXY(ClampU(TileX(st->xy), r->left, r->right), ClampU(TileY(st->xy), r->top, r->bottom));
681  st->MoveSign(new_xy);
682 
683  if (!Station::IsExpected(st)) return;
684  Station *full_station = Station::From(st);
685  for (const GoodsEntry &ge : full_station->goods) {
686  LinkGraphID lg = ge.link_graph;
687  if (!LinkGraph::IsValidID(lg)) continue;
688  (*LinkGraph::Get(lg))[ge.node].UpdateLocation(st->xy);
689  }
690 }
691 
701 static CommandCost BuildStationPart(Station **st, DoCommandFlag flags, bool reuse, TileArea area, StationNaming name_class)
702 {
703  /* Find a deleted station close to us */
704  if (*st == nullptr && reuse) *st = GetClosestDeletedStation(area.tile);
705 
706  if (*st != nullptr) {
707  if ((*st)->owner != _current_company) {
709  }
710 
711  CommandCost ret = (*st)->rect.BeforeAddRect(area.tile, area.w, area.h, StationRect::ADD_TEST);
712  if (ret.Failed()) return ret;
713  } else {
714  /* allocate and initialize new station */
715  if (!Station::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);
716 
717  if (flags & DC_EXEC) {
718  *st = new Station(area.tile);
719  _station_kdtree.Insert((*st)->index);
720 
721  (*st)->town = ClosestTownFromTile(area.tile, UINT_MAX);
722  (*st)->string_id = GenerateStationName(*st, area.tile, name_class);
723 
725  SetBit((*st)->town->have_ratings, _current_company);
726  }
727  }
728  }
729  return CommandCost();
730 }
731 
739 {
740  if (!st->IsInUse()) {
741  st->delete_ctr = 0;
743  }
744  /* station remains but it probably lost some parts - station sign should stay in the station boundaries */
745  UpdateStationSignCoord(st);
746 }
747 
754 {
755  this->UpdateVirtCoord();
757 
758  if (adding) {
759  this->RecomputeCatchment();
760  MarkCatchmentTilesDirty();
762  } else {
763  MarkCatchmentTilesDirty();
764  }
765 
766  switch (type) {
767  case STATION_RAIL:
769  break;
770  case STATION_AIRPORT:
771  break;
772  case STATION_TRUCK:
773  case STATION_BUS:
775  break;
776  case STATION_DOCK:
778  break;
779  default: NOT_REACHED();
780  }
781 
782  if (adding) {
783  UpdateStationAcceptance(this, false);
785  } else {
786  DeleteStationIfEmpty(this);
787  this->RecomputeCatchment();
788  }
789 
790 }
791 
793 
803 CommandCost CheckBuildableTile(TileIndex tile, uint invalid_dirs, int &allowed_z, bool allow_steep, bool check_bridge = true)
804 {
805  if (check_bridge && IsBridgeAbove(tile)) {
806  return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
807  }
808 
810  if (ret.Failed()) return ret;
811 
812  auto [tileh, z] = GetTileSlopeZ(tile);
813 
814  /* Prohibit building if
815  * 1) The tile is "steep" (i.e. stretches two height levels).
816  * 2) The tile is non-flat and the build_on_slopes switch is disabled.
817  */
818  if ((!allow_steep && IsSteepSlope(tileh)) ||
820  return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
821  }
822 
824  int flat_z = z + GetSlopeMaxZ(tileh);
825  if (tileh != SLOPE_FLAT) {
826  /* Forbid building if the tile faces a slope in a invalid direction. */
827  for (DiagDirection dir = DIAGDIR_BEGIN; dir != DIAGDIR_END; dir++) {
828  if (HasBit(invalid_dirs, dir) && !CanBuildDepotByTileh(dir, tileh)) {
829  return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
830  }
831  }
832  cost.AddCost(_price[PR_BUILD_FOUNDATION]);
833  }
834 
835  /* The level of this tile must be equal to allowed_z. */
836  if (allowed_z < 0) {
837  /* First tile. */
838  allowed_z = flat_z;
839  } else if (allowed_z != flat_z) {
840  return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
841  }
842 
843  return cost;
844 }
845 
853 {
855  int allowed_z = -1;
856 
857  for (; tile_iter != INVALID_TILE; ++tile_iter) {
858  CommandCost ret = CheckBuildableTile(tile_iter, 0, allowed_z, true);
859  if (ret.Failed()) return ret;
860  cost.AddCost(ret);
861 
862  ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile_iter);
863  if (ret.Failed()) return ret;
864  cost.AddCost(ret);
865  }
866 
867  return cost;
868 }
869 
886 static CommandCost CheckFlatLandRailStation(TileIndex tile_cur, TileIndex north_tile, int &allowed_z, DoCommandFlag flags, Axis axis, StationID *station, RailType rt, std::vector<Train *> &affected_vehicles, StationClassID spec_class, uint16_t spec_index, uint8_t plat_len, uint8_t numtracks)
887 {
889  uint invalid_dirs = 5 << axis;
890 
891  const StationSpec *statspec = StationClass::Get(spec_class)->GetSpec(spec_index);
892  bool slope_cb = statspec != nullptr && HasBit(statspec->callback_mask, CBM_STATION_SLOPE_CHECK);
893 
894  CommandCost ret = CheckBuildableTile(tile_cur, invalid_dirs, allowed_z, false);
895  if (ret.Failed()) return ret;
896  cost.AddCost(ret);
897 
898  if (slope_cb) {
899  /* Do slope check if requested. */
900  ret = PerformStationTileSlopeCheck(north_tile, tile_cur, statspec, axis, plat_len, numtracks);
901  if (ret.Failed()) return ret;
902  }
903 
904  /* if station is set, then we have special handling to allow building on top of already existing stations.
905  * so station points to INVALID_STATION if we can build on any station.
906  * Or it points to a station if we're only allowed to build on exactly that station. */
907  if (station != nullptr && IsTileType(tile_cur, MP_STATION)) {
908  if (!IsRailStation(tile_cur)) {
909  return ClearTile_Station(tile_cur, DC_AUTO); // get error message
910  } else {
911  StationID st = GetStationIndex(tile_cur);
912  if (*station == INVALID_STATION) {
913  *station = st;
914  } else if (*station != st) {
915  return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
916  }
917  }
918  } else {
919  /* If we are building a station with a valid railtype, we may be able to overbuild an existing rail tile. */
920  if (rt != INVALID_RAILTYPE && IsPlainRailTile(tile_cur)) {
921  /* Don't overbuild signals. */
922  if (HasSignals(tile_cur)) return_cmd_error(STR_ERROR_MUST_REMOVE_SIGNALS_FIRST);
923 
924  /* The current rail type must have power on the to-be-built type (e.g. convert normal rail to electrified rail). */
925  if (HasPowerOnRail(GetRailType(tile_cur), rt)) {
926  TrackBits tracks = GetTrackBits(tile_cur);
927  Track track = RemoveFirstTrack(&tracks);
928  Track expected_track = HasBit(invalid_dirs, DIAGDIR_NE) ? TRACK_X : TRACK_Y;
929 
930  /* The existing track must align with the desired station axis. */
931  if (tracks == TRACK_BIT_NONE && track == expected_track) {
932  /* Check for trains having a reservation for this tile. */
933  if (HasBit(GetRailReservationTrackBits(tile_cur), track)) {
934  Train *v = GetTrainForReservation(tile_cur, track);
935  if (v != nullptr) {
936  affected_vehicles.push_back(v);
937  }
938  }
939  ret = Command<CMD_REMOVE_SINGLE_RAIL>::Do(flags, tile_cur, track);
940  if (ret.Failed()) return ret;
941  cost.AddCost(ret);
942  /* With flags & ~DC_EXEC CmdLandscapeClear would fail since the rail still exists */
943  return cost;
944  }
945  }
946  }
947  ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile_cur);
948  if (ret.Failed()) return ret;
949  cost.AddCost(ret);
950  }
951 
952  return cost;
953 }
954 
968 CommandCost CheckFlatLandRoadStop(TileIndex cur_tile, int &allowed_z, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, StationType station_type, Axis axis, StationID *station, RoadType rt)
969 {
971 
972  CommandCost ret = CheckBuildableTile(cur_tile, invalid_dirs, allowed_z, !is_drive_through);
973  if (ret.Failed()) return ret;
974  cost.AddCost(ret);
975 
976  /* If station is set, then we have special handling to allow building on top of already existing stations.
977  * Station points to INVALID_STATION if we can build on any station.
978  * Or it points to a station if we're only allowed to build on exactly that station. */
979  if (station != nullptr && IsTileType(cur_tile, MP_STATION)) {
980  if (!IsAnyRoadStop(cur_tile)) {
981  return ClearTile_Station(cur_tile, DC_AUTO); // Get error message.
982  } else {
983  if (station_type != GetStationType(cur_tile) ||
984  is_drive_through != IsDriveThroughStopTile(cur_tile)) {
985  return ClearTile_Station(cur_tile, DC_AUTO); // Get error message.
986  }
987  /* Drive-through station in the wrong direction. */
988  if (is_drive_through && IsDriveThroughStopTile(cur_tile) && GetDriveThroughStopAxis(cur_tile) != axis) {
989  return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION);
990  }
991  StationID st = GetStationIndex(cur_tile);
992  if (*station == INVALID_STATION) {
993  *station = st;
994  } else if (*station != st) {
995  return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
996  }
997  }
998  } else {
999  bool build_over_road = is_drive_through && IsNormalRoadTile(cur_tile);
1000  /* Road bits in the wrong direction. */
1001  RoadBits rb = IsNormalRoadTile(cur_tile) ? GetAllRoadBits(cur_tile) : ROAD_NONE;
1002  if (build_over_road && (rb & (axis == AXIS_X ? ROAD_Y : ROAD_X)) != 0) {
1003  /* Someone was pedantic and *NEEDED* three fracking different error messages. */
1004  switch (CountBits(rb)) {
1005  case 1:
1006  return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION);
1007 
1008  case 2:
1009  if (rb == ROAD_X || rb == ROAD_Y) return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION);
1010  return_cmd_error(STR_ERROR_DRIVE_THROUGH_CORNER);
1011 
1012  default: // 3 or 4
1013  return_cmd_error(STR_ERROR_DRIVE_THROUGH_JUNCTION);
1014  }
1015  }
1016 
1017  if (build_over_road) {
1018  /* There is a road, check if we can build road+tram stop over it. */
1019  RoadType road_rt = GetRoadType(cur_tile, RTT_ROAD);
1020  if (road_rt != INVALID_ROADTYPE) {
1021  Owner road_owner = GetRoadOwner(cur_tile, RTT_ROAD);
1022  if (road_owner == OWNER_TOWN) {
1023  if (!_settings_game.construction.road_stop_on_town_road) return_cmd_error(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD);
1024  } else if (!_settings_game.construction.road_stop_on_competitor_road && road_owner != OWNER_NONE) {
1025  ret = CheckOwnership(road_owner);
1026  if (ret.Failed()) return ret;
1027  }
1028  uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_ROAD));
1029 
1030  if (rt != INVALID_ROADTYPE && RoadTypeIsRoad(rt) && !HasPowerOnRoad(rt, road_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD);
1031 
1032  if (GetDisallowedRoadDirections(cur_tile) != DRD_NONE && road_owner != OWNER_TOWN) {
1033  ret = CheckOwnership(road_owner);
1034  if (ret.Failed()) return ret;
1035  }
1036 
1037  cost.AddCost(RoadBuildCost(road_rt) * (2 - num_pieces));
1038  } else if (rt != INVALID_ROADTYPE && RoadTypeIsRoad(rt)) {
1039  cost.AddCost(RoadBuildCost(rt) * 2);
1040  }
1041 
1042  /* There is a tram, check if we can build road+tram stop over it. */
1043  RoadType tram_rt = GetRoadType(cur_tile, RTT_TRAM);
1044  if (tram_rt != INVALID_ROADTYPE) {
1045  Owner tram_owner = GetRoadOwner(cur_tile, RTT_TRAM);
1046  if (Company::IsValidID(tram_owner) &&
1048  /* Disallow breaking end-of-line of someone else
1049  * so trams can still reverse on this tile. */
1050  HasExactlyOneBit(GetRoadBits(cur_tile, RTT_TRAM)))) {
1051  ret = CheckOwnership(tram_owner);
1052  if (ret.Failed()) return ret;
1053  }
1054  uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_TRAM));
1055 
1056  if (rt != INVALID_ROADTYPE && RoadTypeIsTram(rt) && !HasPowerOnRoad(rt, tram_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD);
1057 
1058  cost.AddCost(RoadBuildCost(tram_rt) * (2 - num_pieces));
1059  } else if (rt != INVALID_ROADTYPE && RoadTypeIsTram(rt)) {
1060  cost.AddCost(RoadBuildCost(rt) * 2);
1061  }
1062  } else if (rt == INVALID_ROADTYPE) {
1063  return_cmd_error(STR_ERROR_THERE_IS_NO_ROAD);
1064  } else {
1065  ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, cur_tile);
1066  if (ret.Failed()) return ret;
1067  cost.AddCost(ret);
1068  cost.AddCost(RoadBuildCost(rt) * 2);
1069  }
1070  }
1071 
1072  return cost;
1073 }
1074 
1082 {
1083  TileArea cur_ta = st->train_station;
1084 
1085  /* determine new size of train station region.. */
1086  int x = std::min(TileX(cur_ta.tile), TileX(new_ta.tile));
1087  int y = std::min(TileY(cur_ta.tile), TileY(new_ta.tile));
1088  new_ta.w = std::max(TileX(cur_ta.tile) + cur_ta.w, TileX(new_ta.tile) + new_ta.w) - x;
1089  new_ta.h = std::max(TileY(cur_ta.tile) + cur_ta.h, TileY(new_ta.tile) + new_ta.h) - y;
1090  new_ta.tile = TileXY(x, y);
1091 
1092  /* make sure the final size is not too big. */
1094  return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
1095  }
1096 
1097  return CommandCost();
1098 }
1099 
1100 static inline uint8_t *CreateSingle(uint8_t *layout, int n)
1101 {
1102  int i = n;
1103  do *layout++ = 0; while (--i);
1104  layout[((n - 1) >> 1) - n] = 2;
1105  return layout;
1106 }
1107 
1108 static inline uint8_t *CreateMulti(uint8_t *layout, int n, uint8_t b)
1109 {
1110  int i = n;
1111  do *layout++ = b; while (--i);
1112  if (n > 4) {
1113  layout[0 - n] = 0;
1114  layout[n - 1 - n] = 0;
1115  }
1116  return layout;
1117 }
1118 
1126 void GetStationLayout(uint8_t *layout, uint numtracks, uint plat_len, const StationSpec *statspec)
1127 {
1128  if (statspec != nullptr) {
1129  auto found = statspec->layouts.find(GetStationLayoutKey(numtracks, plat_len));
1130  if (found != std::end(statspec->layouts)) {
1131  /* Custom layout defined, copy to buffer. */
1132  std::copy(std::begin(found->second), std::end(found->second), layout);
1133  return;
1134  }
1135  }
1136 
1137  if (plat_len == 1) {
1138  CreateSingle(layout, numtracks);
1139  } else {
1140  if (numtracks & 1) layout = CreateSingle(layout, plat_len);
1141  int n = numtracks >> 1;
1142 
1143  while (--n >= 0) {
1144  layout = CreateMulti(layout, plat_len, 4);
1145  layout = CreateMulti(layout, plat_len, 6);
1146  }
1147  }
1148 }
1149 
1162 template <class T, StringID error_message, class F>
1163 CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st, F filter)
1164 {
1165  assert(*st == nullptr);
1166  bool check_surrounding = true;
1167 
1168  if (existing_station != INVALID_STATION) {
1169  if (adjacent && existing_station != station_to_join) {
1170  /* You can't build an adjacent station over the top of one that
1171  * already exists. */
1172  return_cmd_error(error_message);
1173  } else {
1174  /* Extend the current station, and don't check whether it will
1175  * be near any other stations. */
1176  T *candidate = T::GetIfValid(existing_station);
1177  if (candidate != nullptr && filter(candidate)) *st = candidate;
1178  check_surrounding = (*st == nullptr);
1179  }
1180  } else {
1181  /* There's no station here. Don't check the tiles surrounding this
1182  * one if the company wanted to build an adjacent station. */
1183  if (adjacent) check_surrounding = false;
1184  }
1185 
1186  if (check_surrounding) {
1187  /* Make sure there is no more than one other station around us that is owned by us. */
1188  CommandCost ret = GetStationAround(ta, existing_station, _current_company, st, filter);
1189  if (ret.Failed()) return ret;
1190  }
1191 
1192  /* Distant join */
1193  if (*st == nullptr && station_to_join != INVALID_STATION) *st = T::GetIfValid(station_to_join);
1194 
1195  return CommandCost();
1196 }
1197 
1207 static CommandCost FindJoiningStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
1208 {
1209  return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST>(existing_station, station_to_join, adjacent, ta, st, [](const Station *) -> bool { return true; });
1210 }
1211 
1222 CommandCost FindJoiningWaypoint(StationID existing_waypoint, StationID waypoint_to_join, bool adjacent, TileArea ta, Waypoint **wp, bool is_road)
1223 {
1224  if (is_road) {
1225  return FindJoiningBaseStation<Waypoint, STR_ERROR_MUST_REMOVE_ROADWAYPOINT_FIRST>(existing_waypoint, waypoint_to_join, adjacent, ta, wp, [](const Waypoint *wp) -> bool { return HasBit(wp->waypoint_flags, WPF_ROAD); });
1226  } else {
1227  return FindJoiningBaseStation<Waypoint, STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST>(existing_waypoint, waypoint_to_join, adjacent, ta, wp, [](const Waypoint *wp) -> bool { return !HasBit(wp->waypoint_flags, WPF_ROAD); });
1228  }
1229 }
1230 
1236 {
1239  v = v->Last();
1241 }
1242 
1248 {
1250  TryPathReserve(v, true, true);
1251  v = v->Last();
1253 }
1254 
1269 static CommandCost CalculateRailStationCost(TileArea tile_area, DoCommandFlag flags, Axis axis, StationID *station, RailType rt, std::vector<Train *> &affected_vehicles, StationClassID spec_class, uint16_t spec_index, uint8_t plat_len, uint8_t numtracks)
1270 {
1272  bool length_price_ready = true;
1273  uint8_t tracknum = 0;
1274  int allowed_z = -1;
1275  for (TileIndex cur_tile : tile_area) {
1276  /* Clear the land below the station. */
1277  CommandCost ret = CheckFlatLandRailStation(cur_tile, tile_area.tile, allowed_z, flags, axis, station, rt, affected_vehicles, spec_class, spec_index, plat_len, numtracks);
1278  if (ret.Failed()) return ret;
1279 
1280  /* Only add _price[PR_BUILD_STATION_RAIL_LENGTH] once for each valid plat_len. */
1281  if (tracknum == numtracks) {
1282  length_price_ready = true;
1283  tracknum = 0;
1284  } else {
1285  tracknum++;
1286  }
1287 
1288  /* AddCost for new or rotated rail stations. */
1289  if (!IsRailStationTile(cur_tile) || (IsRailStationTile(cur_tile) && GetRailStationAxis(cur_tile) != axis)) {
1290  cost.AddCost(ret);
1291  cost.AddCost(_price[PR_BUILD_STATION_RAIL]);
1292  cost.AddCost(RailBuildCost(rt));
1293 
1294  if (length_price_ready) {
1295  cost.AddCost(_price[PR_BUILD_STATION_RAIL_LENGTH]);
1296  length_price_ready = false;
1297  }
1298  }
1299  }
1300 
1301  return cost;
1302 }
1303 
1311 {
1312  /* Default stations do not draw pylons under roofs (gfx >= 4) */
1313  if (statspec == nullptr || gfx >= statspec->tileflags.size()) return gfx < 4 ? StationSpec::TileFlags::Pylons : StationSpec::TileFlags::None;
1314  return statspec->tileflags[gfx];
1315 }
1316 
1322 void SetRailStationTileFlags(TileIndex tile, const StationSpec *statspec)
1323 {
1324  const auto flags = GetStationTileFlags(GetStationGfx(tile), statspec);
1328 }
1329 
1344 CommandCost CmdBuildRailStation(DoCommandFlag flags, TileIndex tile_org, RailType rt, Axis axis, uint8_t numtracks, uint8_t plat_len, StationClassID spec_class, uint16_t spec_index, StationID station_to_join, bool adjacent)
1345 {
1346  /* Does the authority allow this? */
1347  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile_org, flags);
1348  if (ret.Failed()) return ret;
1349 
1350  if (!ValParamRailType(rt) || !IsValidAxis(axis)) return CMD_ERROR;
1351 
1352  /* Check if the given station class is valid */
1353  if (static_cast<uint>(spec_class) >= StationClass::GetClassCount()) return CMD_ERROR;
1354  const StationClass *cls = StationClass::Get(spec_class);
1355  if (IsWaypointClass(*cls)) return CMD_ERROR;
1356  if (spec_index >= cls->GetSpecCount()) return CMD_ERROR;
1357  if (plat_len == 0 || numtracks == 0) return CMD_ERROR;
1358 
1359  int w_org, h_org;
1360  if (axis == AXIS_X) {
1361  w_org = plat_len;
1362  h_org = numtracks;
1363  } else {
1364  h_org = plat_len;
1365  w_org = numtracks;
1366  }
1367 
1368  bool reuse = (station_to_join != NEW_STATION);
1369  if (!reuse) station_to_join = INVALID_STATION;
1370  bool distant_join = (station_to_join != INVALID_STATION);
1371 
1372  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
1373 
1375 
1376  /* these values are those that will be stored in train_tile and station_platforms */
1377  TileArea new_location(tile_org, w_org, h_org);
1378 
1379  /* Make sure the area below consists of clear tiles. (OR tiles belonging to a certain rail station) */
1380  StationID est = INVALID_STATION;
1381  std::vector<Train *> affected_vehicles;
1382  /* Add construction and clearing expenses. */
1383  CommandCost cost = CalculateRailStationCost(new_location, flags, axis, &est, rt, affected_vehicles, spec_class, spec_index, plat_len, numtracks);
1384  if (cost.Failed()) return cost;
1385 
1386  Station *st = nullptr;
1387  ret = FindJoiningStation(est, station_to_join, adjacent, new_location, &st);
1388  if (ret.Failed()) return ret;
1389 
1390  ret = BuildStationPart(&st, flags, reuse, new_location, STATIONNAMING_RAIL);
1391  if (ret.Failed()) return ret;
1392 
1393  if (st != nullptr && st->train_station.tile != INVALID_TILE) {
1394  ret = CanExpandRailStation(st, new_location);
1395  if (ret.Failed()) return ret;
1396  }
1397 
1398  /* Check if we can allocate a custom stationspec to this station */
1399  const StationSpec *statspec = StationClass::Get(spec_class)->GetSpec(spec_index);
1400  int specindex = AllocateSpecToStation(statspec, st, (flags & DC_EXEC) != 0);
1401  if (specindex == -1) return_cmd_error(STR_ERROR_TOO_MANY_STATION_SPECS);
1402 
1403  if (statspec != nullptr) {
1404  /* Perform NewStation checks */
1405 
1406  /* Check if the station size is permitted */
1407  if (HasBit(statspec->disallowed_platforms, std::min(numtracks - 1, 7))) return_cmd_error(STR_ERROR_STATION_DISALLOWED_NUMBER_TRACKS);
1408  if (HasBit(statspec->disallowed_lengths, std::min(plat_len - 1, 7))) return_cmd_error(STR_ERROR_STATION_DISALLOWED_LENGTH);
1409 
1410  /* Check if the station is buildable */
1411  if (HasBit(statspec->callback_mask, CBM_STATION_AVAIL)) {
1412  uint16_t cb_res = GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, nullptr, INVALID_TILE);
1413  if (cb_res != CALLBACK_FAILED && !Convert8bitBooleanCallback(statspec->grf_prop.grffile, CBID_STATION_AVAILABILITY, cb_res)) return CMD_ERROR;
1414  }
1415  }
1416 
1417  if (flags & DC_EXEC) {
1418  st->train_station = new_location;
1419  st->AddFacility(FACIL_TRAIN, new_location.tile);
1420 
1421  st->rect.BeforeAddRect(tile_org, w_org, h_org, StationRect::ADD_TRY);
1422 
1423  if (statspec != nullptr) {
1424  /* Include this station spec's animation trigger bitmask
1425  * in the station's cached copy. */
1426  st->cached_anim_triggers |= statspec->animation.triggers;
1427  }
1428 
1429  TileIndexDiff tile_delta = TileOffsByAxis(axis); // offset to go to the next platform tile
1430  TileIndexDiff track_delta = TileOffsByAxis(OtherAxis(axis)); // offset to go to the next track
1431  Track track = AxisToTrack(axis);
1432 
1433  std::vector<uint8_t> layouts(numtracks * plat_len);
1434  GetStationLayout(layouts.data(), numtracks, plat_len, statspec);
1435 
1436  uint8_t numtracks_orig = numtracks;
1437 
1438  Company *c = Company::Get(st->owner);
1439  size_t layout_idx = 0;
1440  TileIndex tile_track = tile_org;
1441  do {
1442  TileIndex tile = tile_track;
1443  int w = plat_len;
1444  do {
1445  uint8_t layout = layouts[layout_idx++];
1446  if (IsRailStationTile(tile) && HasStationReservation(tile)) {
1447  /* Check for trains having a reservation for this tile. */
1449  if (v != nullptr) {
1450  affected_vehicles.push_back(v);
1452  }
1453  }
1454 
1455  /* Railtype can change when overbuilding. */
1456  if (IsRailStationTile(tile)) {
1457  if (!IsStationTileBlocked(tile)) c->infrastructure.rail[GetRailType(tile)]--;
1458  c->infrastructure.station--;
1459  }
1460 
1461  /* Remove animation if overbuilding */
1462  DeleteAnimatedTile(tile);
1463  uint8_t old_specindex = HasStationTileRail(tile) ? GetCustomStationSpecIndex(tile) : 0;
1464  MakeRailStation(tile, st->owner, st->index, axis, layout & ~1, rt);
1465  /* Free the spec if we overbuild something */
1466  DeallocateSpecFromStation(st, old_specindex);
1467 
1468  SetCustomStationSpecIndex(tile, specindex);
1469  SetStationTileRandomBits(tile, GB(Random(), 0, 4));
1470  SetAnimationFrame(tile, 0);
1471 
1472  if (statspec != nullptr) {
1473  /* Use a fixed axis for GetPlatformInfo as our platforms / numtracks are always the right way around */
1474  uint32_t platinfo = GetPlatformInfo(AXIS_X, GetStationGfx(tile), plat_len, numtracks_orig, plat_len - w, numtracks_orig - numtracks, false);
1475 
1476  /* As the station is not yet completely finished, the station does not yet exist. */
1477  uint16_t callback = GetStationCallback(CBID_STATION_BUILD_TILE_LAYOUT, platinfo, 0, statspec, nullptr, tile);
1478  if (callback != CALLBACK_FAILED) {
1479  if (callback <= UINT8_MAX) {
1480  SetStationGfx(tile, (callback & ~1) + axis);
1481  } else {
1483  }
1484  }
1485 
1486  /* Trigger station animation -- after building? */
1487  TriggerStationAnimation(st, tile, SAT_BUILT);
1488  }
1489 
1490  SetRailStationTileFlags(tile, statspec);
1491 
1492  if (!IsStationTileBlocked(tile)) c->infrastructure.rail[rt]++;
1493  c->infrastructure.station++;
1494 
1495  tile += tile_delta;
1496  } while (--w);
1497  AddTrackToSignalBuffer(tile_track, track, _current_company);
1498  YapfNotifyTrackLayoutChange(tile_track, track);
1499  tile_track += track_delta;
1500  } while (--numtracks);
1501 
1502  for (uint i = 0; i < affected_vehicles.size(); ++i) {
1503  /* Restore reservations of trains. */
1504  RestoreTrainReservation(affected_vehicles[i]);
1505  }
1506 
1507  /* Check whether we need to expand the reservation of trains already on the station. */
1508  TileArea update_reservation_area;
1509  if (axis == AXIS_X) {
1510  update_reservation_area = TileArea(tile_org, 1, numtracks_orig);
1511  } else {
1512  update_reservation_area = TileArea(tile_org, numtracks_orig, 1);
1513  }
1514 
1515  for (TileIndex tile : update_reservation_area) {
1516  /* Don't even try to make eye candy parts reserved. */
1517  if (IsStationTileBlocked(tile)) continue;
1518 
1519  DiagDirection dir = AxisToDiagDir(axis);
1520  TileIndexDiff tile_offset = TileOffsByDiagDir(dir);
1521  TileIndex platform_begin = tile;
1522  TileIndex platform_end = tile;
1523 
1524  /* We can only account for tiles that are reachable from this tile, so ignore primarily blocked tiles while finding the platform begin and end. */
1525  for (TileIndex next_tile = platform_begin - tile_offset; IsCompatibleTrainStationTile(next_tile, platform_begin); next_tile -= tile_offset) {
1526  platform_begin = next_tile;
1527  }
1528  for (TileIndex next_tile = platform_end + tile_offset; IsCompatibleTrainStationTile(next_tile, platform_end); next_tile += tile_offset) {
1529  platform_end = next_tile;
1530  }
1531 
1532  /* If there is at least on reservation on the platform, we reserve the whole platform. */
1533  bool reservation = false;
1534  for (TileIndex t = platform_begin; !reservation && t <= platform_end; t += tile_offset) {
1535  reservation = HasStationReservation(t);
1536  }
1537 
1538  if (reservation) {
1539  SetRailStationPlatformReservation(platform_begin, dir, true);
1540  }
1541  }
1542 
1543  st->MarkTilesDirty(false);
1544  st->AfterStationTileSetChange(true, STATION_RAIL);
1545  }
1546 
1547  return cost;
1548 }
1549 
1550 static TileArea MakeStationAreaSmaller(BaseStation *st, TileArea ta, bool (*func)(BaseStation *, TileIndex))
1551 {
1552 restart:
1553 
1554  /* too small? */
1555  if (ta.w != 0 && ta.h != 0) {
1556  /* check the left side, x = constant, y changes */
1557  for (uint i = 0; !func(st, ta.tile + TileDiffXY(0, i));) {
1558  /* the left side is unused? */
1559  if (++i == ta.h) {
1560  ta.tile += TileDiffXY(1, 0);
1561  ta.w--;
1562  goto restart;
1563  }
1564  }
1565 
1566  /* check the right side, x = constant, y changes */
1567  for (uint i = 0; !func(st, ta.tile + TileDiffXY(ta.w - 1, i));) {
1568  /* the right side is unused? */
1569  if (++i == ta.h) {
1570  ta.w--;
1571  goto restart;
1572  }
1573  }
1574 
1575  /* check the upper side, y = constant, x changes */
1576  for (uint i = 0; !func(st, ta.tile + TileDiffXY(i, 0));) {
1577  /* the left side is unused? */
1578  if (++i == ta.w) {
1579  ta.tile += TileDiffXY(0, 1);
1580  ta.h--;
1581  goto restart;
1582  }
1583  }
1584 
1585  /* check the lower side, y = constant, x changes */
1586  for (uint i = 0; !func(st, ta.tile + TileDiffXY(i, ta.h - 1));) {
1587  /* the left side is unused? */
1588  if (++i == ta.w) {
1589  ta.h--;
1590  goto restart;
1591  }
1592  }
1593  } else {
1594  ta.Clear();
1595  }
1596 
1597  return ta;
1598 }
1599 
1600 static bool TileBelongsToRailStation(BaseStation *st, TileIndex tile)
1601 {
1602  return st->TileBelongsToRailStation(tile);
1603 }
1604 
1605 static void MakeRailStationAreaSmaller(BaseStation *st)
1606 {
1607  st->train_station = MakeStationAreaSmaller(st, st->train_station, TileBelongsToRailStation);
1608 }
1609 
1610 static bool TileBelongsToShipStation(BaseStation *st, TileIndex tile)
1611 {
1612  return IsDockTile(tile) && GetStationIndex(tile) == st->index;
1613 }
1614 
1615 static void MakeShipStationAreaSmaller(Station *st)
1616 {
1617  st->ship_station = MakeStationAreaSmaller(st, st->ship_station, TileBelongsToShipStation);
1618  UpdateStationDockingTiles(st);
1619 }
1620 
1621 static bool TileBelongsToRoadWaypointStation(BaseStation *st, TileIndex tile)
1622 {
1623  return IsRoadWaypointTile(tile) && GetStationIndex(tile) == st->index;
1624 }
1625 
1626 void MakeRoadWaypointStationAreaSmaller(BaseStation *st, TileArea &road_waypoint_area)
1627 {
1628  road_waypoint_area = MakeStationAreaSmaller(st, road_waypoint_area, TileBelongsToRoadWaypointStation);
1629 }
1630 
1641 template <class T>
1642 CommandCost RemoveFromRailBaseStation(TileArea ta, std::vector<T *> &affected_stations, DoCommandFlag flags, Money removal_cost, bool keep_rail)
1643 {
1644  /* Count of the number of tiles removed */
1645  int quantity = 0;
1646  CommandCost total_cost(EXPENSES_CONSTRUCTION);
1647  /* Accumulator for the errors seen during clearing. If no errors happen,
1648  * and the quantity is 0 there is no station. Otherwise it will be one
1649  * of the other error that got accumulated. */
1650  CommandCost error;
1651 
1652  /* Do the action for every tile into the area */
1653  for (TileIndex tile : ta) {
1654  /* Make sure the specified tile is a rail station */
1655  if (!HasStationTileRail(tile)) continue;
1656 
1657  /* If there is a vehicle on ground, do not allow to remove (flood) the tile */
1659  error.AddCost(ret);
1660  if (ret.Failed()) continue;
1661 
1662  /* Check ownership of station */
1663  T *st = T::GetByTile(tile);
1664  if (st == nullptr) continue;
1665 
1666  if (_current_company != OWNER_WATER) {
1667  ret = CheckOwnership(st->owner);
1668  error.AddCost(ret);
1669  if (ret.Failed()) continue;
1670  }
1671 
1672  /* If we reached here, the tile is valid so increase the quantity of tiles we will remove */
1673  quantity++;
1674 
1675  if (keep_rail || IsStationTileBlocked(tile)) {
1676  /* Don't refund the 'steel' of the track when we keep the
1677  * rail, or when the tile didn't have any rail at all. */
1678  total_cost.AddCost(-_price[PR_CLEAR_RAIL]);
1679  }
1680 
1681  if (flags & DC_EXEC) {
1682  /* read variables before the station tile is removed */
1683  uint specindex = GetCustomStationSpecIndex(tile);
1684  Track track = GetRailStationTrack(tile);
1685  Owner owner = GetTileOwner(tile);
1686  RailType rt = GetRailType(tile);
1687  Train *v = nullptr;
1688 
1689  if (HasStationReservation(tile)) {
1690  v = GetTrainForReservation(tile, track);
1691  if (v != nullptr) FreeTrainReservation(v);
1692  }
1693 
1694  bool build_rail = keep_rail && !IsStationTileBlocked(tile);
1695  if (!build_rail && !IsStationTileBlocked(tile)) Company::Get(owner)->infrastructure.rail[rt]--;
1696 
1697  DoClearSquare(tile);
1698  DeleteNewGRFInspectWindow(GSF_STATIONS, tile.base());
1699  if (build_rail) MakeRailNormal(tile, owner, TrackToTrackBits(track), rt);
1700  Company::Get(owner)->infrastructure.station--;
1702 
1703  st->rect.AfterRemoveTile(st, tile);
1704  AddTrackToSignalBuffer(tile, track, owner);
1705  YapfNotifyTrackLayoutChange(tile, track);
1706 
1707  DeallocateSpecFromStation(st, specindex);
1708 
1709  include(affected_stations, st);
1710 
1711  if (v != nullptr) RestoreTrainReservation(v);
1712  }
1713  }
1714 
1715  if (quantity == 0) return error.Failed() ? error : CommandCost(STR_ERROR_THERE_IS_NO_STATION);
1716 
1717  for (T *st : affected_stations) {
1718 
1719  /* now we need to make the "spanned" area of the railway station smaller
1720  * if we deleted something at the edges.
1721  * we also need to adjust train_tile. */
1722  MakeRailStationAreaSmaller(st);
1723  UpdateStationSignCoord(st);
1724 
1725  /* if we deleted the whole station, delete the train facility. */
1726  if (st->train_station.tile == INVALID_TILE) {
1727  st->facilities &= ~FACIL_TRAIN;
1730  MarkCatchmentTilesDirty();
1731  st->UpdateVirtCoord();
1733  }
1734  }
1735 
1736  total_cost.AddCost(quantity * removal_cost);
1737  return total_cost;
1738 }
1739 
1750 {
1751  if (end == 0) end = start;
1752  if (start >= Map::Size() || end >= Map::Size()) return CMD_ERROR;
1753 
1754  TileArea ta(start, end);
1755  std::vector<Station *> affected_stations;
1756 
1757  CommandCost ret = RemoveFromRailBaseStation(ta, affected_stations, flags, _price[PR_CLEAR_STATION_RAIL], keep_rail);
1758  if (ret.Failed()) return ret;
1759 
1760  /* Do all station specific functions here. */
1761  for (Station *st : affected_stations) {
1762 
1764  st->MarkTilesDirty(false);
1765  MarkCatchmentTilesDirty();
1766  st->RecomputeCatchment();
1767  }
1768 
1769  /* Now apply the rail cost to the number that we deleted */
1770  return ret;
1771 }
1772 
1783 {
1784  if (end == 0) end = start;
1785  if (start >= Map::Size() || end >= Map::Size()) return CMD_ERROR;
1786 
1787  TileArea ta(start, end);
1788  std::vector<Waypoint *> affected_stations;
1789 
1790  return RemoveFromRailBaseStation(ta, affected_stations, flags, _price[PR_CLEAR_WAYPOINT_RAIL], keep_rail);
1791 }
1792 
1793 
1802 template <class T>
1804 {
1805  /* Current company owns the station? */
1806  if (_current_company != OWNER_WATER) {
1807  CommandCost ret = CheckOwnership(st->owner);
1808  if (ret.Failed()) return ret;
1809  }
1810 
1811  /* determine width and height of platforms */
1812  TileArea ta = st->train_station;
1813 
1814  assert(ta.w != 0 && ta.h != 0);
1815 
1817  /* clear all areas of the station */
1818  for (TileIndex tile : ta) {
1819  /* only remove tiles that are actually train station tiles */
1820  if (st->TileBelongsToRailStation(tile)) {
1821  std::vector<T*> affected_stations; // dummy
1822  CommandCost ret = RemoveFromRailBaseStation(TileArea(tile, 1, 1), affected_stations, flags, removal_cost, false);
1823  if (ret.Failed()) return ret;
1824  cost.AddCost(ret);
1825  }
1826  }
1827 
1828  return cost;
1829 }
1830 
1838 {
1839  /* if there is flooding, remove platforms tile by tile */
1840  if (_current_company == OWNER_WATER) {
1841  return Command<CMD_REMOVE_FROM_RAIL_STATION>::Do(DC_EXEC, tile, 0, false);
1842  }
1843 
1844  Station *st = Station::GetByTile(tile);
1845  CommandCost cost = RemoveRailStation(st, flags, _price[PR_CLEAR_STATION_RAIL]);
1846 
1847  if (flags & DC_EXEC) st->RecomputeCatchment();
1848 
1849  return cost;
1850 }
1851 
1859 {
1860  /* if there is flooding, remove waypoints tile by tile */
1861  if (_current_company == OWNER_WATER) {
1862  return Command<CMD_REMOVE_FROM_RAIL_WAYPOINT>::Do(DC_EXEC, tile, 0, false);
1863  }
1864 
1865  return RemoveRailStation(Waypoint::GetByTile(tile), flags, _price[PR_CLEAR_WAYPOINT_RAIL]);
1866 }
1867 
1868 
1874 static RoadStop **FindRoadStopSpot(bool truck_station, Station *st)
1875 {
1876  RoadStop **primary_stop = (truck_station) ? &st->truck_stops : &st->bus_stops;
1877 
1878  if (*primary_stop == nullptr) {
1879  /* we have no roadstop of the type yet, so write a "primary stop" */
1880  return primary_stop;
1881  } else {
1882  /* there are stops already, so append to the end of the list */
1883  RoadStop *stop = *primary_stop;
1884  while (stop->next != nullptr) stop = stop->next;
1885  return &stop->next;
1886  }
1887 }
1888 
1889 static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags, int replacement_spec_index = -1);
1890 CommandCost RemoveRoadWaypointStop(TileIndex tile, DoCommandFlag flags, int replacement_spec_index = -1);
1891 
1901 static CommandCost FindJoiningRoadStop(StationID existing_stop, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
1902 {
1903  return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST>(existing_stop, station_to_join, adjacent, ta, st, [](const Station *) -> bool { return true; });
1904 }
1905 
1919 CommandCost CalculateRoadStopCost(TileArea tile_area, DoCommandFlag flags, bool is_drive_through, StationType station_type, Axis axis, DiagDirection ddir, StationID *est, RoadType rt, Money unit_cost)
1920 {
1921  uint invalid_dirs = 0;
1922  if (is_drive_through) {
1923  SetBit(invalid_dirs, AxisToDiagDir(axis));
1924  SetBit(invalid_dirs, ReverseDiagDir(AxisToDiagDir(axis)));
1925  } else {
1926  SetBit(invalid_dirs, ddir);
1927  }
1928 
1929  /* Check every tile in the area. */
1930  int allowed_z = -1;
1932  for (TileIndex cur_tile : tile_area) {
1933  CommandCost ret = CheckFlatLandRoadStop(cur_tile, allowed_z, flags, invalid_dirs, is_drive_through, station_type, axis, est, rt);
1934  if (ret.Failed()) return ret;
1935 
1936  bool is_preexisting_roadstop = IsTileType(cur_tile, MP_STATION) && IsAnyRoadStop(cur_tile);
1937 
1938  /* Only add costs if a stop doesn't already exist in the location */
1939  if (!is_preexisting_roadstop) {
1940  cost.AddCost(ret);
1941  cost.AddCost(unit_cost);
1942  }
1943  }
1944 
1945  return cost;
1946 }
1947 
1964 CommandCost CmdBuildRoadStop(DoCommandFlag flags, TileIndex tile, uint8_t width, uint8_t length, RoadStopType stop_type, bool is_drive_through,
1965  DiagDirection ddir, RoadType rt, RoadStopClassID spec_class, uint16_t spec_index, StationID station_to_join, bool adjacent)
1966 {
1967  if (!ValParamRoadType(rt) || !IsValidDiagDirection(ddir) || stop_type >= ROADSTOP_END) return CMD_ERROR;
1968  bool reuse = (station_to_join != NEW_STATION);
1969  if (!reuse) station_to_join = INVALID_STATION;
1970  bool distant_join = (station_to_join != INVALID_STATION);
1971 
1972  /* Check if the given station class is valid */
1973  if (static_cast<uint>(spec_class) >= RoadStopClass::GetClassCount()) return CMD_ERROR;
1974  const RoadStopClass *cls = RoadStopClass::Get(spec_class);
1975  if (IsWaypointClass(*cls)) return CMD_ERROR;
1976  if (spec_index >= cls->GetSpecCount()) return CMD_ERROR;
1977 
1978  const RoadStopSpec *roadstopspec = cls->GetSpec(spec_index);
1979  if (roadstopspec != nullptr) {
1980  if (stop_type == ROADSTOP_TRUCK && roadstopspec->stop_type != ROADSTOPTYPE_FREIGHT && roadstopspec->stop_type != ROADSTOPTYPE_ALL) return CMD_ERROR;
1981  if (stop_type == ROADSTOP_BUS && roadstopspec->stop_type != ROADSTOPTYPE_PASSENGER && roadstopspec->stop_type != ROADSTOPTYPE_ALL) return CMD_ERROR;
1982  if (!is_drive_through && HasBit(roadstopspec->flags, RSF_DRIVE_THROUGH_ONLY)) return CMD_ERROR;
1983  }
1984 
1985  /* Check if the requested road stop is too big */
1986  if (width > _settings_game.station.station_spread || length > _settings_game.station.station_spread) return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
1987  /* Check for incorrect width / length. */
1988  if (width == 0 || length == 0) return CMD_ERROR;
1989  /* Check if the first tile and the last tile are valid */
1990  if (!IsValidTile(tile) || TileAddWrap(tile, width - 1, length - 1) == INVALID_TILE) return CMD_ERROR;
1991 
1992  TileArea roadstop_area(tile, width, length);
1993 
1994  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
1995 
1996  /* Trams only have drive through stops */
1997  if (!is_drive_through && RoadTypeIsTram(rt)) return CMD_ERROR;
1998 
1999  Axis axis = DiagDirToAxis(ddir);
2000 
2001  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags);
2002  if (ret.Failed()) return ret;
2003 
2004  bool is_truck_stop = stop_type != ROADSTOP_BUS;
2005 
2006  /* Total road stop cost. */
2007  Money unit_cost;
2008  if (roadstopspec != nullptr) {
2009  unit_cost = roadstopspec->GetBuildCost(is_truck_stop ? PR_BUILD_STATION_TRUCK : PR_BUILD_STATION_BUS);
2010  } else {
2011  unit_cost = _price[is_truck_stop ? PR_BUILD_STATION_TRUCK : PR_BUILD_STATION_BUS];
2012  }
2013  StationID est = INVALID_STATION;
2014  CommandCost cost = CalculateRoadStopCost(roadstop_area, flags, is_drive_through, is_truck_stop ? STATION_TRUCK : STATION_BUS, axis, ddir, &est, rt, unit_cost);
2015  if (cost.Failed()) return cost;
2016 
2017  Station *st = nullptr;
2018  ret = FindJoiningRoadStop(est, station_to_join, adjacent, roadstop_area, &st);
2019  if (ret.Failed()) return ret;
2020 
2021  /* Check if this number of road stops can be allocated. */
2022  if (!RoadStop::CanAllocateItem(static_cast<size_t>(roadstop_area.w) * roadstop_area.h)) return_cmd_error(is_truck_stop ? STR_ERROR_TOO_MANY_TRUCK_STOPS : STR_ERROR_TOO_MANY_BUS_STOPS);
2023 
2024  ret = BuildStationPart(&st, flags, reuse, roadstop_area, STATIONNAMING_ROAD);
2025  if (ret.Failed()) return ret;
2026 
2027  /* Check if we can allocate a custom stationspec to this station */
2028  int specindex = AllocateSpecToRoadStop(roadstopspec, st, (flags & DC_EXEC) != 0);
2029  if (specindex == -1) return_cmd_error(STR_ERROR_TOO_MANY_STATION_SPECS);
2030 
2031  if (roadstopspec != nullptr) {
2032  /* Perform NewGRF checks */
2033 
2034  /* Check if the road stop is buildable */
2035  if (HasBit(roadstopspec->callback_mask, CBM_ROAD_STOP_AVAIL)) {
2036  uint16_t cb_res = GetRoadStopCallback(CBID_STATION_AVAILABILITY, 0, 0, roadstopspec, nullptr, INVALID_TILE, rt, is_truck_stop ? STATION_TRUCK : STATION_BUS, 0);
2037  if (cb_res != CALLBACK_FAILED && !Convert8bitBooleanCallback(roadstopspec->grf_prop.grffile, CBID_STATION_AVAILABILITY, cb_res)) return CMD_ERROR;
2038  }
2039  }
2040 
2041  if (flags & DC_EXEC) {
2042  /* Check every tile in the area. */
2043  for (TileIndex cur_tile : roadstop_area) {
2044  /* Get existing road types and owners before any tile clearing */
2045  RoadType road_rt = MayHaveRoad(cur_tile) ? GetRoadType(cur_tile, RTT_ROAD) : INVALID_ROADTYPE;
2046  RoadType tram_rt = MayHaveRoad(cur_tile) ? GetRoadType(cur_tile, RTT_TRAM) : INVALID_ROADTYPE;
2047  Owner road_owner = road_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_ROAD) : _current_company;
2048  Owner tram_owner = tram_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_TRAM) : _current_company;
2049 
2050  if (IsTileType(cur_tile, MP_STATION) && IsStationRoadStop(cur_tile)) {
2051  RemoveRoadStop(cur_tile, flags, specindex);
2052  }
2053 
2054  if (roadstopspec != nullptr) {
2055  /* Include this road stop spec's animation trigger bitmask
2056  * in the station's cached copy. */
2057  st->cached_roadstop_anim_triggers |= roadstopspec->animation.triggers;
2058  }
2059 
2060  RoadStop *road_stop = new RoadStop(cur_tile);
2061  /* Insert into linked list of RoadStops. */
2062  RoadStop **currstop = FindRoadStopSpot(is_truck_stop, st);
2063  *currstop = road_stop;
2064 
2065  if (is_truck_stop) {
2066  st->truck_station.Add(cur_tile);
2067  } else {
2068  st->bus_station.Add(cur_tile);
2069  }
2070 
2071  /* Initialize an empty station. */
2072  st->AddFacility(is_truck_stop ? FACIL_TRUCK_STOP : FACIL_BUS_STOP, cur_tile);
2073 
2074  st->rect.BeforeAddTile(cur_tile, StationRect::ADD_TRY);
2075 
2076  RoadStopType rs_type = is_truck_stop ? ROADSTOP_TRUCK : ROADSTOP_BUS;
2077  if (is_drive_through) {
2078  /* Update company infrastructure counts. If the current tile is a normal road tile, remove the old
2079  * bits first. */
2080  if (IsNormalRoadTile(cur_tile)) {
2081  UpdateCompanyRoadInfrastructure(road_rt, road_owner, -(int)CountBits(GetRoadBits(cur_tile, RTT_ROAD)));
2082  UpdateCompanyRoadInfrastructure(tram_rt, tram_owner, -(int)CountBits(GetRoadBits(cur_tile, RTT_TRAM)));
2083  }
2084 
2085  if (road_rt == INVALID_ROADTYPE && RoadTypeIsRoad(rt)) road_rt = rt;
2086  if (tram_rt == INVALID_ROADTYPE && RoadTypeIsTram(rt)) tram_rt = rt;
2087 
2088  MakeDriveThroughRoadStop(cur_tile, st->owner, road_owner, tram_owner, st->index, (rs_type == ROADSTOP_BUS ? STATION_BUS : STATION_TRUCK), road_rt, tram_rt, axis);
2089  road_stop->MakeDriveThrough();
2090  } else {
2091  if (road_rt == INVALID_ROADTYPE && RoadTypeIsRoad(rt)) road_rt = rt;
2092  if (tram_rt == INVALID_ROADTYPE && RoadTypeIsTram(rt)) tram_rt = rt;
2093  MakeRoadStop(cur_tile, st->owner, st->index, rs_type, road_rt, tram_rt, ddir);
2094  }
2097  Company::Get(st->owner)->infrastructure.station++;
2098 
2099  SetCustomRoadStopSpecIndex(cur_tile, specindex);
2100  if (roadstopspec != nullptr) {
2101  st->SetRoadStopRandomBits(cur_tile, GB(Random(), 0, 8));
2102  TriggerRoadStopAnimation(st, cur_tile, SAT_BUILT);
2103  }
2104 
2105  MarkTileDirtyByTile(cur_tile);
2106  }
2107 
2108  if (st != nullptr) {
2109  st->AfterStationTileSetChange(true, is_truck_stop ? STATION_TRUCK: STATION_BUS);
2110  }
2111  }
2112  return cost;
2113 }
2114 
2115 
2116 static Vehicle *ClearRoadStopStatusEnum(Vehicle *v, void *)
2117 {
2118  if (v->type == VEH_ROAD) {
2119  /* Okay... we are a road vehicle on a drive through road stop.
2120  * But that road stop has just been removed, so we need to make
2121  * sure we are in a valid state... however, vehicles can also
2122  * turn on road stop tiles, so only clear the 'road stop' state
2123  * bits and only when the state was 'in road stop', otherwise
2124  * we'll end up clearing the turn around bits. */
2125  RoadVehicle *rv = RoadVehicle::From(v);
2127  }
2128 
2129  return nullptr;
2130 }
2131 
2132 
2140 static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags, int replacement_spec_index)
2141 {
2142  Station *st = Station::GetByTile(tile);
2143 
2144  if (_current_company != OWNER_WATER) {
2145  CommandCost ret = CheckOwnership(st->owner);
2146  if (ret.Failed()) return ret;
2147  }
2148 
2149  bool is_truck = IsTruckStop(tile);
2150 
2151  RoadStop **primary_stop;
2152  RoadStop *cur_stop;
2153  if (is_truck) { // truck stop
2154  primary_stop = &st->truck_stops;
2155  cur_stop = RoadStop::GetByTile(tile, ROADSTOP_TRUCK);
2156  } else {
2157  primary_stop = &st->bus_stops;
2158  cur_stop = RoadStop::GetByTile(tile, ROADSTOP_BUS);
2159  }
2160 
2161  assert(cur_stop != nullptr);
2162 
2163  /* don't do the check for drive-through road stops when company bankrupts */
2164  if (IsDriveThroughStopTile(tile) && (flags & DC_BANKRUPT)) {
2165  /* remove the 'going through road stop' status from all vehicles on that tile */
2166  if (flags & DC_EXEC) FindVehicleOnPos(tile, nullptr, &ClearRoadStopStatusEnum);
2167  } else {
2169  if (ret.Failed()) return ret;
2170  }
2171 
2172  const RoadStopSpec *spec = GetRoadStopSpec(tile);
2173 
2174  if (flags & DC_EXEC) {
2175  if (*primary_stop == cur_stop) {
2176  /* removed the first stop in the list */
2177  *primary_stop = cur_stop->next;
2178  /* removed the only stop? */
2179  if (*primary_stop == nullptr) {
2180  st->facilities &= (is_truck ? ~FACIL_TRUCK_STOP : ~FACIL_BUS_STOP);
2182  }
2183  } else {
2184  /* tell the predecessor in the list to skip this stop */
2185  RoadStop *pred = *primary_stop;
2186  while (pred->next != cur_stop) pred = pred->next;
2187  pred->next = cur_stop->next;
2188  }
2189 
2190  /* Update company infrastructure counts. */
2191  for (RoadTramType rtt : _roadtramtypes) {
2192  RoadType rt = GetRoadType(tile, rtt);
2193  UpdateCompanyRoadInfrastructure(rt, GetRoadOwner(tile, rtt), -static_cast<int>(ROAD_STOP_TRACKBIT_FACTOR));
2194  }
2195 
2196  Company::Get(st->owner)->infrastructure.station--;
2198 
2199  DeleteAnimatedTile(tile);
2200 
2201  uint specindex = GetCustomRoadStopSpecIndex(tile);
2202 
2203  DeleteNewGRFInspectWindow(GSF_ROADSTOPS, tile.base());
2204 
2205  if (IsDriveThroughStopTile(tile)) {
2206  /* Clears the tile for us */
2207  cur_stop->ClearDriveThrough();
2208  } else {
2209  DoClearSquare(tile);
2210  }
2211 
2212  delete cur_stop;
2213 
2214  /* Make sure no vehicle is going to the old roadstop. Narrow the search to any road vehicles with an order to
2215  * this station, then look for any currently heading to the tile. */
2216  StationID station_id = st->index;
2218  [](const Vehicle *v) { return v->type == VEH_ROAD; },
2219  [station_id](const Order *order) { return order->IsType(OT_GOTO_STATION) && order->GetDestination() == station_id; },
2220  [station_id, tile](Vehicle *v) {
2221  if (v->current_order.IsType(OT_GOTO_STATION) && v->dest_tile == tile) {
2222  v->SetDestTile(v->GetOrderStationLocation(station_id));
2223  }
2224  }
2225  );
2226 
2227  st->rect.AfterRemoveTile(st, tile);
2228 
2229  if (replacement_spec_index < 0) st->AfterStationTileSetChange(false, is_truck ? STATION_TRUCK: STATION_BUS);
2230 
2231  st->RemoveRoadStopTileData(tile);
2232  if ((int)specindex != replacement_spec_index) DeallocateSpecFromRoadStop(st, specindex);
2233 
2234  /* Update the tile area of the truck/bus stop */
2235  if (is_truck) {
2236  st->truck_station.Clear();
2237  for (const RoadStop *rs = st->truck_stops; rs != nullptr; rs = rs->next) st->truck_station.Add(rs->xy);
2238  } else {
2239  st->bus_station.Clear();
2240  for (const RoadStop *rs = st->bus_stops; rs != nullptr; rs = rs->next) st->bus_station.Add(rs->xy);
2241  }
2242  }
2243 
2244  Price category = is_truck ? PR_CLEAR_STATION_TRUCK : PR_CLEAR_STATION_BUS;
2245  return CommandCost(EXPENSES_CONSTRUCTION, spec != nullptr ? spec->GetClearCost(category) : _price[category]);
2246 }
2247 
2255 CommandCost RemoveRoadWaypointStop(TileIndex tile, DoCommandFlag flags, int replacement_spec_index)
2256 {
2257  Waypoint *wp = Waypoint::GetByTile(tile);
2258 
2259  if (_current_company != OWNER_WATER) {
2260  CommandCost ret = CheckOwnership(wp->owner);
2261  if (ret.Failed()) return ret;
2262  }
2263 
2264  /* Ignore vehicles when the company goes bankrupt. The road will remain, any vehicles going to the waypoint will be removed. */
2265  if (!(flags & DC_BANKRUPT)) {
2267  if (ret.Failed()) return ret;
2268  }
2269 
2270  const RoadStopSpec *spec = GetRoadStopSpec(tile);
2271 
2272  if (flags & DC_EXEC) {
2273  /* Update company infrastructure counts. */
2274  for (RoadTramType rtt : _roadtramtypes) {
2275  RoadType rt = GetRoadType(tile, rtt);
2276  UpdateCompanyRoadInfrastructure(rt, GetRoadOwner(tile, rtt), -static_cast<int>(ROAD_STOP_TRACKBIT_FACTOR));
2277  }
2278 
2279  Company::Get(wp->owner)->infrastructure.station--;
2281 
2282  DeleteAnimatedTile(tile);
2283 
2284  uint specindex = GetCustomRoadStopSpecIndex(tile);
2285 
2286  DeleteNewGRFInspectWindow(GSF_ROADSTOPS, tile.base());
2287 
2288  DoClearSquare(tile);
2289 
2290  wp->rect.AfterRemoveTile(wp, tile);
2291 
2292  wp->RemoveRoadStopTileData(tile);
2293  if ((int)specindex != replacement_spec_index) DeallocateSpecFromRoadStop(wp, specindex);
2294 
2295  if (replacement_spec_index < 0) {
2296  MakeRoadWaypointStationAreaSmaller(wp, wp->road_waypoint_area);
2297 
2298  UpdateStationSignCoord(wp);
2299 
2300  /* if we deleted the whole waypoint, delete the road facility. */
2301  if (wp->road_waypoint_area.tile == INVALID_TILE) {
2304  wp->UpdateVirtCoord();
2306  }
2307  }
2308  }
2309 
2310  return CommandCost(EXPENSES_CONSTRUCTION, spec != nullptr ? spec->GetClearCost(PR_CLEAR_STATION_TRUCK) : _price[PR_CLEAR_STATION_TRUCK]);
2311 }
2312 
2321 static CommandCost RemoveGenericRoadStop(DoCommandFlag flags, const TileArea &roadstop_area, StationType station_type, bool remove_road)
2322 {
2324  CommandCost last_error(STR_ERROR_THERE_IS_NO_STATION);
2325  bool had_success = false;
2326 
2327  for (TileIndex cur_tile : roadstop_area) {
2328  /* Make sure the specified tile is a road stop of the correct type */
2329  if (!IsTileType(cur_tile, MP_STATION) || !IsAnyRoadStop(cur_tile) || GetStationType(cur_tile) != station_type) continue;
2330 
2331  /* Save information on to-be-restored roads before the stop is removed. */
2332  RoadBits road_bits = ROAD_NONE;
2333  RoadType road_type[] = { INVALID_ROADTYPE, INVALID_ROADTYPE };
2334  Owner road_owner[] = { OWNER_NONE, OWNER_NONE };
2335  if (IsDriveThroughStopTile(cur_tile)) {
2336  for (RoadTramType rtt : _roadtramtypes) {
2337  road_type[rtt] = GetRoadType(cur_tile, rtt);
2338  if (road_type[rtt] == INVALID_ROADTYPE) continue;
2339  road_owner[rtt] = GetRoadOwner(cur_tile, rtt);
2340  /* If we don't want to preserve our roads then restore only roads of others. */
2341  if (remove_road && road_owner[rtt] == _current_company) road_type[rtt] = INVALID_ROADTYPE;
2342  }
2343  road_bits = AxisToRoadBits(GetDriveThroughStopAxis(cur_tile));
2344  }
2345 
2346  CommandCost ret;
2347  if (station_type == STATION_ROADWAYPOINT) {
2348  ret = RemoveRoadWaypointStop(cur_tile, flags);
2349  } else {
2350  ret = RemoveRoadStop(cur_tile, flags);
2351  }
2352  if (ret.Failed()) {
2353  last_error = ret;
2354  continue;
2355  }
2356  cost.AddCost(ret);
2357  had_success = true;
2358 
2359  /* Restore roads. */
2360  if ((flags & DC_EXEC) && (road_type[RTT_ROAD] != INVALID_ROADTYPE || road_type[RTT_TRAM] != INVALID_ROADTYPE)) {
2361  MakeRoadNormal(cur_tile, road_bits, road_type[RTT_ROAD], road_type[RTT_TRAM], ClosestTownFromTile(cur_tile, UINT_MAX)->index,
2362  road_owner[RTT_ROAD], road_owner[RTT_TRAM]);
2363 
2364  /* Update company infrastructure counts. */
2365  int count = CountBits(road_bits);
2366  UpdateCompanyRoadInfrastructure(road_type[RTT_ROAD], road_owner[RTT_ROAD], count);
2367  UpdateCompanyRoadInfrastructure(road_type[RTT_TRAM], road_owner[RTT_TRAM], count);
2368  }
2369  }
2370 
2371  return had_success ? cost : last_error;
2372 }
2373 
2384 CommandCost CmdRemoveRoadStop(DoCommandFlag flags, TileIndex tile, uint8_t width, uint8_t height, RoadStopType stop_type, bool remove_road)
2385 {
2386  if (stop_type >= ROADSTOP_END) return CMD_ERROR;
2387  /* Check for incorrect width / height. */
2388  if (width == 0 || height == 0) return CMD_ERROR;
2389  /* Check if the first tile and the last tile are valid */
2390  if (!IsValidTile(tile) || TileAddWrap(tile, width - 1, height - 1) == INVALID_TILE) return CMD_ERROR;
2391  /* Bankrupting company is not supposed to remove roads, there may be road vehicles. */
2392  if (remove_road && (flags & DC_BANKRUPT)) return CMD_ERROR;
2393 
2394  TileArea roadstop_area(tile, width, height);
2395 
2396  return RemoveGenericRoadStop(flags, roadstop_area, stop_type == ROADSTOP_BUS ? STATION_BUS : STATION_TRUCK, remove_road);
2397 }
2398 
2407 {
2408  if (end == 0) end = start;
2409  if (start >= Map::Size() || end >= Map::Size()) return CMD_ERROR;
2410 
2411  TileArea roadstop_area(start, end);
2412 
2413  return RemoveGenericRoadStop(flags, roadstop_area, STATION_ROADWAYPOINT, false);
2414 }
2415 
2424 uint8_t GetAirportNoiseLevelForDistance(const AirportSpec *as, uint distance)
2425 {
2426  /* 0 cannot be accounted, and 1 is the lowest that can be reduced from town.
2427  * So no need to go any further*/
2428  if (as->noise_level < 2) return as->noise_level;
2429 
2430  /* The steps for measuring noise reduction are based on the "magical" (and arbitrary) 8 base distance
2431  * adding the town_council_tolerance 4 times, as a way to graduate, depending of the tolerance.
2432  * Basically, it says that the less tolerant a town is, the bigger the distance before
2433  * an actual decrease can be granted */
2434  uint8_t town_tolerance_distance = 8 + (_settings_game.difficulty.town_council_tolerance * 4);
2435 
2436  /* now, we want to have the distance segmented using the distance judged bareable by town
2437  * This will give us the coefficient of reduction the distance provides. */
2438  uint noise_reduction = distance / town_tolerance_distance;
2439 
2440  /* If the noise reduction equals the airport noise itself, don't give it for free.
2441  * Otherwise, simply reduce the airport's level. */
2442  return noise_reduction >= as->noise_level ? 1 : as->noise_level - noise_reduction;
2443 }
2444 
2455 Town *AirportGetNearestTown(const AirportSpec *as, Direction rotation, TileIndex tile, TileIterator &&it, uint &mindist)
2456 {
2457  assert(Town::GetNumItems() > 0);
2458 
2459  Town *nearest = nullptr;
2460 
2461  auto width = as->size_x;
2462  auto height = as->size_y;
2463  if (rotation == DIR_E || rotation == DIR_W) std::swap(width, height);
2464 
2465  uint perimeter_min_x = TileX(tile);
2466  uint perimeter_min_y = TileY(tile);
2467  uint perimeter_max_x = perimeter_min_x + width - 1;
2468  uint perimeter_max_y = perimeter_min_y + height - 1;
2469 
2470  mindist = UINT_MAX - 1; // prevent overflow
2471 
2472  for (TileIndex cur_tile = *it; cur_tile != INVALID_TILE; cur_tile = ++it) {
2473  assert(IsInsideBS(TileX(cur_tile), perimeter_min_x, width));
2474  assert(IsInsideBS(TileY(cur_tile), perimeter_min_y, height));
2475  if (TileX(cur_tile) == perimeter_min_x || TileX(cur_tile) == perimeter_max_x || TileY(cur_tile) == perimeter_min_y || TileY(cur_tile) == perimeter_max_y) {
2476  Town *t = CalcClosestTownFromTile(cur_tile, mindist + 1);
2477  if (t == nullptr) continue;
2478 
2479  uint dist = DistanceManhattan(t->xy, cur_tile);
2480  if (dist == mindist && t->index < nearest->index) nearest = t;
2481  if (dist < mindist) {
2482  nearest = t;
2483  mindist = dist;
2484  }
2485  }
2486  }
2487 
2488  return nearest;
2489 }
2490 
2498 static Town *AirportGetNearestTown(const Station *st, uint &mindist)
2499 {
2500  return AirportGetNearestTown(st->airport.GetSpec(), st->airport.rotation, st->airport.tile, AirportTileIterator(st), mindist);
2501 }
2502 
2503 
2506 {
2507  for (Town *t : Town::Iterate()) t->noise_reached = 0;
2508 
2509  for (const Station *st : Station::Iterate()) {
2510  if (st->airport.tile != INVALID_TILE && st->airport.type != AT_OILRIG) {
2511  uint dist;
2512  Town *nearest = AirportGetNearestTown(st, dist);
2513  nearest->noise_reached += GetAirportNoiseLevelForDistance(st->airport.GetSpec(), dist);
2514  }
2515  }
2516 }
2517 
2528 CommandCost CmdBuildAirport(DoCommandFlag flags, TileIndex tile, uint8_t airport_type, uint8_t layout, StationID station_to_join, bool allow_adjacent)
2529 {
2530  bool reuse = (station_to_join != NEW_STATION);
2531  if (!reuse) station_to_join = INVALID_STATION;
2532  bool distant_join = (station_to_join != INVALID_STATION);
2533 
2534  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
2535 
2536  if (airport_type >= NUM_AIRPORTS) return CMD_ERROR;
2537 
2538  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags);
2539  if (ret.Failed()) return ret;
2540 
2541  /* Check if a valid, buildable airport was chosen for construction */
2542  const AirportSpec *as = AirportSpec::Get(airport_type);
2543  if (!as->IsAvailable() || layout >= as->layouts.size()) return CMD_ERROR;
2544  if (!as->IsWithinMapBounds(layout, tile)) return CMD_ERROR;
2545 
2546  Direction rotation = as->layouts[layout].rotation;
2547  int w = as->size_x;
2548  int h = as->size_y;
2549  if (rotation == DIR_E || rotation == DIR_W) Swap(w, h);
2550  TileArea airport_area = TileArea(tile, w, h);
2551 
2553  return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
2554  }
2555 
2556  AirportTileTableIterator tile_iter(as->layouts[layout].tiles.data(), tile);
2557  CommandCost cost = CheckFlatLandAirport(tile_iter, flags);
2558  if (cost.Failed()) return cost;
2559 
2560  /* The noise level is the noise from the airport and reduce it to account for the distance to the town center. */
2561  uint dist;
2562  Town *nearest = AirportGetNearestTown(as, rotation, tile, std::move(tile_iter), dist);
2563  uint newnoise_level = GetAirportNoiseLevelForDistance(as, dist);
2564 
2565  /* Check if local auth would allow a new airport */
2566  StringID authority_refuse_message = STR_NULL;
2567  Town *authority_refuse_town = nullptr;
2568 
2570  /* do not allow to build a new airport if this raise the town noise over the maximum allowed by town */
2571  if ((nearest->noise_reached + newnoise_level) > nearest->MaxTownNoise()) {
2572  authority_refuse_message = STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE;
2573  authority_refuse_town = nearest;
2574  }
2575  } else if (_settings_game.difficulty.town_council_tolerance != TOWN_COUNCIL_PERMISSIVE) {
2576  Town *t = ClosestTownFromTile(tile, UINT_MAX);
2577  uint num = 0;
2578  for (const Station *st : Station::Iterate()) {
2579  if (st->town == t && (st->facilities & FACIL_AIRPORT) && st->airport.type != AT_OILRIG) num++;
2580  }
2581  if (num >= 2) {
2582  authority_refuse_message = STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT;
2583  authority_refuse_town = t;
2584  }
2585  }
2586 
2587  if (authority_refuse_message != STR_NULL) {
2588  SetDParam(0, authority_refuse_town->index);
2589  return_cmd_error(authority_refuse_message);
2590  }
2591 
2592  Station *st = nullptr;
2593  ret = FindJoiningStation(INVALID_STATION, station_to_join, allow_adjacent, airport_area, &st);
2594  if (ret.Failed()) return ret;
2595 
2596  /* Distant join */
2597  if (st == nullptr && distant_join) st = Station::GetIfValid(station_to_join);
2598 
2599  ret = BuildStationPart(&st, flags, reuse, airport_area, (GetAirport(airport_type)->flags & AirportFTAClass::AIRPLANES) ? STATIONNAMING_AIRPORT : STATIONNAMING_HELIPORT);
2600  if (ret.Failed()) return ret;
2601 
2602  if (st != nullptr && st->airport.tile != INVALID_TILE) {
2603  return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT);
2604  }
2605 
2606  for (AirportTileTableIterator iter(as->layouts[layout].tiles.data(), tile); iter != INVALID_TILE; ++iter) {
2607  cost.AddCost(_price[PR_BUILD_STATION_AIRPORT]);
2608  }
2609 
2610  if (flags & DC_EXEC) {
2611  /* Always add the noise, so there will be no need to recalculate when option toggles */
2612  nearest->noise_reached += newnoise_level;
2613 
2614  st->AddFacility(FACIL_AIRPORT, tile);
2615  st->airport.type = airport_type;
2616  st->airport.layout = layout;
2617  st->airport.flags = 0;
2618  st->airport.rotation = rotation;
2619 
2620  st->rect.BeforeAddRect(tile, w, h, StationRect::ADD_TRY);
2621 
2622  for (AirportTileTableIterator iter(as->layouts[layout].tiles.data(), tile); iter != INVALID_TILE; ++iter) {
2623  Tile t(iter);
2624  MakeAirport(t, st->owner, st->index, iter.GetStationGfx(), WATER_CLASS_INVALID);
2625  SetStationTileRandomBits(t, GB(Random(), 0, 4));
2626  st->airport.Add(iter);
2627 
2629  }
2630 
2631  /* Only call the animation trigger after all tiles have been built */
2632  for (AirportTileTableIterator iter(as->layouts[layout].tiles.data(), tile); iter != INVALID_TILE; ++iter) {
2633  AirportTileAnimationTrigger(st, iter, AAT_BUILT);
2634  }
2635 
2637 
2638  Company::Get(st->owner)->infrastructure.airport++;
2639 
2640  st->AfterStationTileSetChange(true, STATION_AIRPORT);
2642 
2644  SetWindowDirty(WC_TOWN_VIEW, nearest->index);
2645  }
2646  }
2647 
2648  return cost;
2649 }
2650 
2658 {
2659  Station *st = Station::GetByTile(tile);
2660 
2661  if (_current_company != OWNER_WATER) {
2662  CommandCost ret = CheckOwnership(st->owner);
2663  if (ret.Failed()) return ret;
2664  }
2665 
2666  tile = st->airport.tile;
2667 
2669 
2670  for (const Aircraft *a : Aircraft::Iterate()) {
2671  if (!a->IsNormalAircraft()) continue;
2672  if (a->targetairport == st->index && a->state != FLYING) {
2673  return_cmd_error(STR_ERROR_AIRCRAFT_IN_THE_WAY);
2674  }
2675  }
2676 
2677  if (flags & DC_EXEC) {
2678  for (uint i = 0; i < st->airport.GetNumHangars(); ++i) {
2679  TileIndex tile_cur = st->airport.GetHangarTile(i);
2680  OrderBackup::Reset(tile_cur, false);
2681  CloseWindowById(WC_VEHICLE_DEPOT, tile_cur);
2682  }
2683 
2684  /* The noise level is the noise from the airport and reduce it to account for the distance to the town center.
2685  * And as for construction, always remove it, even if the setting is not set, in order to avoid the
2686  * need of recalculation */
2687  uint dist;
2688  Town *nearest = AirportGetNearestTown(st, dist);
2690 
2692  SetWindowDirty(WC_TOWN_VIEW, nearest->index);
2693  }
2694  }
2695 
2696  for (TileIndex tile_cur : st->airport) {
2697  if (!st->TileBelongsToAirport(tile_cur)) continue;
2698 
2699  CommandCost ret = EnsureNoVehicleOnGround(tile_cur);
2700  if (ret.Failed()) return ret;
2701 
2702  cost.AddCost(_price[PR_CLEAR_STATION_AIRPORT]);
2703 
2704  if (flags & DC_EXEC) {
2705  DeleteAnimatedTile(tile_cur);
2706  DoClearSquare(tile_cur);
2707  DeleteNewGRFInspectWindow(GSF_AIRPORTTILES, tile_cur.base());
2708  }
2709  }
2710 
2711  if (flags & DC_EXEC) {
2712  /* Clear the persistent storage. */
2713  delete st->airport.psa;
2714 
2715  st->rect.AfterRemoveRect(st, st->airport);
2716 
2717  st->airport.Clear();
2718  st->facilities &= ~FACIL_AIRPORT;
2720 
2722 
2723  Company::Get(st->owner)->infrastructure.airport--;
2724 
2725  st->AfterStationTileSetChange(false, STATION_AIRPORT);
2726 
2727  DeleteNewGRFInspectWindow(GSF_AIRPORTS, st->index);
2728  }
2729 
2730  return cost;
2731 }
2732 
2739 CommandCost CmdOpenCloseAirport(DoCommandFlag flags, StationID station_id)
2740 {
2741  if (!Station::IsValidID(station_id)) return CMD_ERROR;
2742  Station *st = Station::Get(station_id);
2743 
2744  if (!(st->facilities & FACIL_AIRPORT) || st->owner == OWNER_NONE) return CMD_ERROR;
2745 
2746  CommandCost ret = CheckOwnership(st->owner);
2747  if (ret.Failed()) return ret;
2748 
2749  if (flags & DC_EXEC) {
2752  }
2753  return CommandCost();
2754 }
2755 
2762 bool HasStationInUse(StationID station, bool include_company, CompanyID company)
2763 {
2764  for (const OrderList *orderlist : OrderList::Iterate()) {
2765  const Vehicle *v = orderlist->GetFirstSharedVehicle();
2766  assert(v != nullptr);
2767  if ((v->owner == company) != include_company) continue;
2768 
2769  for (const Order *order = orderlist->GetFirstOrder(); order != nullptr; order = order->next) {
2770  if (order->GetDestination() == station && (order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT))) {
2771  return true;
2772  }
2773  }
2774  }
2775  return false;
2776 }
2777 
2778 static const TileIndexDiffC _dock_tileoffs_chkaround[] = {
2779  {-1, 0},
2780  { 0, 0},
2781  { 0, 0},
2782  { 0, -1}
2783 };
2784 static const uint8_t _dock_w_chk[4] = { 2, 1, 2, 1 };
2785 static const uint8_t _dock_h_chk[4] = { 1, 2, 1, 2 };
2786 
2795 CommandCost CmdBuildDock(DoCommandFlag flags, TileIndex tile, StationID station_to_join, bool adjacent)
2796 {
2797  bool reuse = (station_to_join != NEW_STATION);
2798  if (!reuse) station_to_join = INVALID_STATION;
2799  bool distant_join = (station_to_join != INVALID_STATION);
2800 
2801  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
2802 
2804  if (direction == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2805  direction = ReverseDiagDir(direction);
2806 
2807  /* Docks cannot be placed on rapids */
2808  if (HasTileWaterGround(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2809 
2810  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags);
2811  if (ret.Failed()) return ret;
2812 
2813  if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
2814 
2815  CommandCost cost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_STATION_DOCK]);
2816  ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
2817  if (ret.Failed()) return ret;
2818  cost.AddCost(ret);
2819 
2820  TileIndex tile_cur = tile + TileOffsByDiagDir(direction);
2821 
2822  if (!HasTileWaterGround(tile_cur) || !IsTileFlat(tile_cur)) {
2823  return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2824  }
2825 
2826  if (IsBridgeAbove(tile_cur)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
2827 
2828  /* Get the water class of the water tile before it is cleared.*/
2829  WaterClass wc = GetWaterClass(tile_cur);
2830 
2831  bool add_cost = !IsWaterTile(tile_cur);
2832  ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile_cur);
2833  if (ret.Failed()) return ret;
2834  if (add_cost) cost.AddCost(ret);
2835 
2836  tile_cur += TileOffsByDiagDir(direction);
2837  if (!IsTileType(tile_cur, MP_WATER) || !IsTileFlat(tile_cur)) {
2838  return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2839  }
2840 
2841  TileArea dock_area = TileArea(tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]),
2842  _dock_w_chk[direction], _dock_h_chk[direction]);
2843 
2844  /* middle */
2845  Station *st = nullptr;
2846  ret = FindJoiningStation(INVALID_STATION, station_to_join, adjacent, dock_area, &st);
2847  if (ret.Failed()) return ret;
2848 
2849  /* Distant join */
2850  if (st == nullptr && distant_join) st = Station::GetIfValid(station_to_join);
2851 
2852  ret = BuildStationPart(&st, flags, reuse, dock_area, STATIONNAMING_DOCK);
2853  if (ret.Failed()) return ret;
2854 
2855  if (flags & DC_EXEC) {
2856  st->ship_station.Add(tile);
2857  TileIndex flat_tile = tile + TileOffsByDiagDir(direction);
2858  st->ship_station.Add(flat_tile);
2859  st->AddFacility(FACIL_DOCK, tile);
2860 
2861  st->rect.BeforeAddRect(dock_area.tile, dock_area.w, dock_area.h, StationRect::ADD_TRY);
2862 
2863  /* If the water part of the dock is on a canal, update infrastructure counts.
2864  * This is needed as we've cleared that tile before.
2865  * Clearing object tiles may result in water tiles which are already accounted for in the water infrastructure total.
2866  * See: MakeWaterKeepingClass() */
2867  if (wc == WATER_CLASS_CANAL && !(HasTileWaterClass(flat_tile) && GetWaterClass(flat_tile) == WATER_CLASS_CANAL && IsTileOwner(flat_tile, _current_company))) {
2868  Company::Get(st->owner)->infrastructure.water++;
2869  }
2870  Company::Get(st->owner)->infrastructure.station += 2;
2871 
2872  MakeDock(tile, st->owner, st->index, direction, wc);
2873  UpdateStationDockingTiles(st);
2874 
2875  st->AfterStationTileSetChange(true, STATION_DOCK);
2876  }
2877 
2878  return cost;
2879 }
2880 
2881 void RemoveDockingTile(TileIndex t)
2882 {
2883  for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
2884  TileIndex tile = t + TileOffsByDiagDir(d);
2885  if (!IsValidTile(tile)) continue;
2886 
2887  if (IsTileType(tile, MP_STATION)) {
2888  Station *st = Station::GetByTile(tile);
2889  if (st != nullptr) UpdateStationDockingTiles(st);
2890  } else if (IsTileType(tile, MP_INDUSTRY)) {
2891  Station *neutral = Industry::GetByTile(tile)->neutral_station;
2892  if (neutral != nullptr) UpdateStationDockingTiles(neutral);
2893  }
2894  }
2895 }
2896 
2903 {
2904  assert(IsValidTile(tile));
2905 
2906  /* Clear and maybe re-set docking tile */
2907  for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
2908  TileIndex docking_tile = tile + TileOffsByDiagDir(d);
2909  if (!IsValidTile(docking_tile)) continue;
2910 
2911  if (IsPossibleDockingTile(docking_tile)) {
2912  SetDockingTile(docking_tile, false);
2913  CheckForDockingTile(docking_tile);
2914  }
2915  }
2916 }
2917 
2924 {
2925  assert(IsDockTile(t));
2926 
2927  StationGfx gfx = GetStationGfx(t);
2928  if (gfx < GFX_DOCK_BASE_WATER_PART) return t;
2929 
2930  for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
2931  TileIndex tile = t + TileOffsByDiagDir(d);
2932  if (!IsValidTile(tile)) continue;
2933  if (!IsDockTile(tile)) continue;
2934  if (GetStationGfx(tile) < GFX_DOCK_BASE_WATER_PART && tile + TileOffsByDiagDir(GetDockDirection(tile)) == t) return tile;
2935  }
2936 
2937  return INVALID_TILE;
2938 }
2939 
2947 {
2948  Station *st = Station::GetByTile(tile);
2949  CommandCost ret = CheckOwnership(st->owner);
2950  if (ret.Failed()) return ret;
2951 
2952  if (!IsDockTile(tile)) return CMD_ERROR;
2953 
2954  TileIndex tile1 = FindDockLandPart(tile);
2955  if (tile1 == INVALID_TILE) return CMD_ERROR;
2956  TileIndex tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1));
2957 
2958  ret = EnsureNoVehicleOnGround(tile1);
2959  if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2);
2960  if (ret.Failed()) return ret;
2961 
2962  if (flags & DC_EXEC) {
2963  DoClearSquare(tile1);
2964  MarkTileDirtyByTile(tile1);
2965  MakeWaterKeepingClass(tile2, st->owner);
2966 
2967  st->rect.AfterRemoveTile(st, tile1);
2968  st->rect.AfterRemoveTile(st, tile2);
2969 
2970  MakeShipStationAreaSmaller(st);
2971  if (st->ship_station.tile == INVALID_TILE) {
2972  st->ship_station.Clear();
2973  st->docking_station.Clear();
2974  st->facilities &= ~FACIL_DOCK;
2976  }
2977 
2978  Company::Get(st->owner)->infrastructure.station -= 2;
2979 
2980  st->AfterStationTileSetChange(false, STATION_DOCK);
2981 
2984 
2985  for (Ship *s : Ship::Iterate()) {
2986  /* Find all ships going to our dock. */
2987  if (s->current_order.GetDestination() != st->index) {
2988  continue;
2989  }
2990 
2991  /* Find ships that are marked as "loading" but are no longer on a
2992  * docking tile. Force them to leave the station (as they were loading
2993  * on the removed dock). */
2994  if (s->current_order.IsType(OT_LOADING) && !(IsDockingTile(s->tile) && IsShipDestinationTile(s->tile, st->index))) {
2995  s->LeaveStation();
2996  }
2997 
2998  /* If we no longer have a dock, mark the order as invalid and send
2999  * the ship to the next order (or, if there is none, make it
3000  * wander the world). */
3001  if (s->current_order.IsType(OT_GOTO_STATION) && !(st->facilities & FACIL_DOCK)) {
3002  s->SetDestTile(s->GetOrderStationLocation(st->index));
3003  }
3004  }
3005  }
3006 
3007  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_STATION_DOCK]);
3008 }
3009 
3010 #include "table/station_land.h"
3011 
3019 {
3020  const auto &layouts = _station_display_datas[st];
3021  if (gfx >= layouts.size()) gfx &= 1;
3022  return layouts.data() + gfx;
3023 }
3024 
3034 bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrackOffset *overlay_offset)
3035 {
3036  bool snow_desert;
3037  switch (*ground) {
3038  case SPR_RAIL_TRACK_X:
3039  case SPR_MONO_TRACK_X:
3040  case SPR_MGLV_TRACK_X:
3041  snow_desert = false;
3042  *overlay_offset = RTO_X;
3043  break;
3044 
3045  case SPR_RAIL_TRACK_Y:
3046  case SPR_MONO_TRACK_Y:
3047  case SPR_MGLV_TRACK_Y:
3048  snow_desert = false;
3049  *overlay_offset = RTO_Y;
3050  break;
3051 
3052  case SPR_RAIL_TRACK_X_SNOW:
3053  case SPR_MONO_TRACK_X_SNOW:
3054  case SPR_MGLV_TRACK_X_SNOW:
3055  snow_desert = true;
3056  *overlay_offset = RTO_X;
3057  break;
3058 
3059  case SPR_RAIL_TRACK_Y_SNOW:
3060  case SPR_MONO_TRACK_Y_SNOW:
3061  case SPR_MGLV_TRACK_Y_SNOW:
3062  snow_desert = true;
3063  *overlay_offset = RTO_Y;
3064  break;
3065 
3066  default:
3067  return false;
3068  }
3069 
3070  if (ti != nullptr) {
3071  /* Decide snow/desert from tile */
3073  case LT_ARCTIC:
3074  snow_desert = (uint)ti->z > GetSnowLine() * TILE_HEIGHT;
3075  break;
3076 
3077  case LT_TROPIC:
3078  snow_desert = GetTropicZone(ti->tile) == TROPICZONE_DESERT;
3079  break;
3080 
3081  default:
3082  break;
3083  }
3084  }
3085 
3086  *ground = snow_desert ? SPR_FLAT_SNOW_DESERT_TILE : SPR_FLAT_GRASS_TILE;
3087  return true;
3088 }
3089 
3090 static void DrawTile_Station(TileInfo *ti)
3091 {
3092  const NewGRFSpriteLayout *layout = nullptr;
3093  DrawTileSprites tmp_rail_layout;
3094  const DrawTileSprites *t = nullptr;
3095  int32_t total_offset;
3096  const RailTypeInfo *rti = nullptr;
3097  uint32_t relocation = 0;
3098  uint32_t ground_relocation = 0;
3099  BaseStation *st = nullptr;
3100  const StationSpec *statspec = nullptr;
3101  uint tile_layout = 0;
3102 
3103  if (HasStationRail(ti->tile)) {
3104  rti = GetRailTypeInfo(GetRailType(ti->tile));
3105  total_offset = rti->GetRailtypeSpriteOffset();
3106 
3107  if (IsCustomStationSpecIndex(ti->tile)) {
3108  /* look for customization */
3109  st = BaseStation::GetByTile(ti->tile);
3110  statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec;
3111 
3112  if (statspec != nullptr) {
3113  tile_layout = GetStationGfx(ti->tile);
3114 
3116  uint16_t callback = GetStationCallback(CBID_STATION_DRAW_TILE_LAYOUT, 0, 0, statspec, st, ti->tile);
3117  if (callback != CALLBACK_FAILED) tile_layout = (callback & ~1) + GetRailStationAxis(ti->tile);
3118  }
3119 
3120  /* Ensure the chosen tile layout is valid for this custom station */
3121  if (!statspec->renderdata.empty()) {
3122  layout = &statspec->renderdata[tile_layout < statspec->renderdata.size() ? tile_layout : (uint)GetRailStationAxis(ti->tile)];
3123  if (!layout->NeedsPreprocessing()) {
3124  t = layout;
3125  layout = nullptr;
3126  }
3127  }
3128  }
3129  }
3130  } else {
3131  total_offset = 0;
3132  }
3133 
3134  StationGfx gfx = GetStationGfx(ti->tile);
3135  if (IsAirport(ti->tile)) {
3136  gfx = GetAirportGfx(ti->tile);
3137  if (gfx >= NEW_AIRPORTTILE_OFFSET) {
3138  const AirportTileSpec *ats = AirportTileSpec::Get(gfx);
3139  if (ats->grf_prop.spritegroup[0] != nullptr && DrawNewAirportTile(ti, Station::GetByTile(ti->tile), ats)) {
3140  return;
3141  }
3142  /* No sprite group (or no valid one) found, meaning no graphics associated.
3143  * Use the substitute one instead */
3144  assert(ats->grf_prop.subst_id != INVALID_AIRPORTTILE);
3145  gfx = ats->grf_prop.subst_id;
3146  }
3147  switch (gfx) {
3148  case APT_RADAR_GRASS_FENCE_SW:
3149  t = &_station_display_datas_airport_radar_grass_fence_sw[GetAnimationFrame(ti->tile)];
3150  break;
3151  case APT_GRASS_FENCE_NE_FLAG:
3152  t = &_station_display_datas_airport_flag_grass_fence_ne[GetAnimationFrame(ti->tile)];
3153  break;
3154  case APT_RADAR_FENCE_SW:
3155  t = &_station_display_datas_airport_radar_fence_sw[GetAnimationFrame(ti->tile)];
3156  break;
3157  case APT_RADAR_FENCE_NE:
3158  t = &_station_display_datas_airport_radar_fence_ne[GetAnimationFrame(ti->tile)];
3159  break;
3160  case APT_GRASS_FENCE_NE_FLAG_2:
3161  t = &_station_display_datas_airport_flag_grass_fence_ne_2[GetAnimationFrame(ti->tile)];
3162  break;
3163  }
3164  }
3165 
3166  Owner owner = GetTileOwner(ti->tile);
3167 
3168  PaletteID palette;
3169  if (Company::IsValidID(owner)) {
3170  palette = COMPANY_SPRITE_COLOUR(owner);
3171  } else {
3172  /* Some stations are not owner by a company, namely oil rigs */
3173  palette = PALETTE_TO_GREY;
3174  }
3175 
3176  if (layout == nullptr && (t == nullptr || t->seq == nullptr)) t = GetStationTileLayout(GetStationType(ti->tile), gfx);
3177 
3178  /* don't show foundation for docks */
3179  if (ti->tileh != SLOPE_FLAT && !IsDock(ti->tile)) {
3180  if (statspec != nullptr && HasBit(statspec->flags, SSF_CUSTOM_FOUNDATIONS)) {
3181  /* Station has custom foundations.
3182  * Check whether the foundation continues beyond the tile's upper sides. */
3183  uint edge_info = 0;
3184  auto [slope, z] = GetFoundationPixelSlope(ti->tile);
3185  if (!HasFoundationNW(ti->tile, slope, z)) SetBit(edge_info, 0);
3186  if (!HasFoundationNE(ti->tile, slope, z)) SetBit(edge_info, 1);
3187  SpriteID image = GetCustomStationFoundationRelocation(statspec, st, ti->tile, tile_layout, edge_info);
3188  if (image == 0) goto draw_default_foundation;
3189 
3190  if (HasBit(statspec->flags, SSF_EXTENDED_FOUNDATIONS)) {
3191  /* Station provides extended foundations. */
3192 
3193  static const uint8_t foundation_parts[] = {
3194  0, 0, 0, 0, // Invalid, Invalid, Invalid, SLOPE_SW
3195  0, 1, 2, 3, // Invalid, SLOPE_EW, SLOPE_SE, SLOPE_WSE
3196  0, 4, 5, 6, // Invalid, SLOPE_NW, SLOPE_NS, SLOPE_NWS
3197  7, 8, 9 // SLOPE_NE, SLOPE_ENW, SLOPE_SEN
3198  };
3199 
3200  AddSortableSpriteToDraw(image + foundation_parts[ti->tileh], PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
3201  } else {
3202  /* Draw simple foundations, built up from 8 possible foundation sprites. */
3203 
3204  /* Each set bit represents one of the eight composite sprites to be drawn.
3205  * 'Invalid' entries will not drawn but are included for completeness. */
3206  static const uint8_t composite_foundation_parts[] = {
3207  /* Invalid (00000000), Invalid (11010001), Invalid (11100100), SLOPE_SW (11100000) */
3208  0x00, 0xD1, 0xE4, 0xE0,
3209  /* Invalid (11001010), SLOPE_EW (11001001), SLOPE_SE (11000100), SLOPE_WSE (11000000) */
3210  0xCA, 0xC9, 0xC4, 0xC0,
3211  /* Invalid (11010010), SLOPE_NW (10010001), SLOPE_NS (11100100), SLOPE_NWS (10100000) */
3212  0xD2, 0x91, 0xE4, 0xA0,
3213  /* SLOPE_NE (01001010), SLOPE_ENW (00001001), SLOPE_SEN (01000100) */
3214  0x4A, 0x09, 0x44
3215  };
3216 
3217  uint8_t parts = composite_foundation_parts[ti->tileh];
3218 
3219  /* If foundations continue beyond the tile's upper sides then
3220  * mask out the last two pieces. */
3221  if (HasBit(edge_info, 0)) ClrBit(parts, 6);
3222  if (HasBit(edge_info, 1)) ClrBit(parts, 7);
3223 
3224  if (parts == 0) {
3225  /* We always have to draw at least one sprite to make sure there is a boundingbox and a sprite with the
3226  * correct offset for the childsprites.
3227  * So, draw the (completely empty) sprite of the default foundations. */
3228  goto draw_default_foundation;
3229  }
3230 
3232  for (int i = 0; i < 8; i++) {
3233  if (HasBit(parts, i)) {
3234  AddSortableSpriteToDraw(image + i, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
3235  }
3236  }
3237  EndSpriteCombine();
3238  }
3239 
3240  OffsetGroundSprite(0, -8);
3242  } else {
3243 draw_default_foundation:
3245  }
3246  }
3247 
3248  bool draw_ground = false;
3249 
3250  if (IsBuoy(ti->tile)) {
3251  DrawWaterClassGround(ti);
3252  SpriteID sprite = GetCanalSprite(CF_BUOY, ti->tile);
3253  if (sprite != 0) total_offset = sprite - SPR_IMG_BUOY;
3254  } else if (IsDock(ti->tile) || (IsOilRig(ti->tile) && IsTileOnWater(ti->tile))) {
3255  if (ti->tileh == SLOPE_FLAT) {
3256  DrawWaterClassGround(ti);
3257  } else {
3258  assert(IsDock(ti->tile));
3259  TileIndex water_tile = ti->tile + TileOffsByDiagDir(GetDockDirection(ti->tile));
3260  WaterClass wc = HasTileWaterClass(water_tile) ? GetWaterClass(water_tile) : WATER_CLASS_INVALID;
3261  if (wc == WATER_CLASS_SEA) {
3262  DrawShoreTile(ti->tileh);
3263  } else {
3264  DrawClearLandTile(ti, 3);
3265  }
3266  }
3267  } else if (IsRoadWaypointTile(ti->tile)) {
3269  RoadType road_rt = GetRoadTypeRoad(ti->tile);
3270  RoadType tram_rt = GetRoadTypeTram(ti->tile);
3271  RoadBits road = (road_rt != INVALID_ROADTYPE) ? bits : ROAD_NONE;
3272  RoadBits tram = (tram_rt != INVALID_ROADTYPE) ? bits : ROAD_NONE;
3273  const RoadTypeInfo *road_rti = (road_rt != INVALID_ROADTYPE) ? GetRoadTypeInfo(road_rt) : nullptr;
3274  const RoadTypeInfo *tram_rti = (tram_rt != INVALID_ROADTYPE) ? GetRoadTypeInfo(tram_rt) : nullptr;
3275 
3276  if (ti->tileh != SLOPE_FLAT) {
3278  }
3279 
3280  DrawRoadGroundSprites(ti, road, tram, road_rti, tram_rti, GetRoadWaypointRoadside(ti->tile), IsRoadWaypointOnSnowOrDesert(ti->tile));
3281  } else {
3282  if (layout != nullptr) {
3283  /* Sprite layout which needs preprocessing */
3284  bool separate_ground = HasBit(statspec->flags, SSF_SEPARATE_GROUND);
3285  uint32_t var10_values = layout->PrepareLayout(total_offset, rti->fallback_railtype, 0, 0, separate_ground);
3286  for (uint8_t var10 : SetBitIterator(var10_values)) {
3287  uint32_t var10_relocation = GetCustomStationRelocation(statspec, st, ti->tile, var10);
3288  layout->ProcessRegisters(var10, var10_relocation, separate_ground);
3289  }
3290  tmp_rail_layout.seq = layout->GetLayout(&tmp_rail_layout.ground);
3291  t = &tmp_rail_layout;
3292  total_offset = 0;
3293  } else if (statspec != nullptr) {
3294  /* Simple sprite layout */
3295  ground_relocation = relocation = GetCustomStationRelocation(statspec, st, ti->tile, 0);
3296  if (HasBit(statspec->flags, SSF_SEPARATE_GROUND)) {
3297  ground_relocation = GetCustomStationRelocation(statspec, st, ti->tile, 1);
3298  }
3299  ground_relocation += rti->fallback_railtype;
3300  }
3301 
3302  draw_ground = true;
3303  }
3304 
3305  if (draw_ground && !IsAnyRoadStop(ti->tile)) {
3306  SpriteID image = t->ground.sprite;
3307  PaletteID pal = t->ground.pal;
3308  RailTrackOffset overlay_offset;
3309  if (rti != nullptr && rti->UsesOverlay() && SplitGroundSpriteForOverlay(ti, &image, &overlay_offset)) {
3310  SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
3311  DrawGroundSprite(image, PAL_NONE);
3312  DrawGroundSprite(ground + overlay_offset, PAL_NONE);
3313 
3314  if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasStationReservation(ti->tile)) {
3315  SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
3316  DrawGroundSprite(overlay + overlay_offset, PALETTE_CRASH);
3317  }
3318  } else {
3319  image += HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE) ? ground_relocation : total_offset;
3320  if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += ground_relocation;
3321  DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette));
3322 
3323  /* PBS debugging, draw reserved tracks darker */
3324  if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasStationRail(ti->tile) && HasStationReservation(ti->tile)) {
3326  }
3327  }
3328  }
3329 
3331 
3332  if (IsAnyRoadStop(ti->tile)) {
3333  RoadType road_rt = GetRoadTypeRoad(ti->tile);
3334  RoadType tram_rt = GetRoadTypeTram(ti->tile);
3335  const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt);
3336  const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt);
3337 
3338  StationGfx view = GetStationGfx(ti->tile);
3339  StationType type = GetStationType(ti->tile);
3340 
3341  const RoadStopSpec *stopspec = GetRoadStopSpec(ti->tile);
3342  RoadStopDrawMode stop_draw_mode{};
3343  if (stopspec != nullptr) {
3344  stop_draw_mode = stopspec->draw_mode;
3345  st = BaseStation::GetByTile(ti->tile);
3346  RoadStopResolverObject object(stopspec, st, ti->tile, INVALID_ROADTYPE, type, view);
3347  const SpriteGroup *group = object.Resolve();
3348  if (group != nullptr && group->type == SGT_TILELAYOUT) {
3349  if (HasBit(stopspec->flags, RSF_DRAW_MODE_REGISTER)) {
3350  stop_draw_mode = static_cast<RoadStopDrawMode>(GetRegister(0x100));
3351  }
3352  if (type == STATION_ROADWAYPOINT && (stop_draw_mode & ROADSTOP_DRAW_MODE_WAYP_GROUND)) {
3353  draw_ground = true;
3354  }
3355  t = ((const TileLayoutSpriteGroup *)group)->ProcessRegisters(nullptr);
3356  }
3357  }
3358 
3359  /* Draw ground sprite */
3360  if (draw_ground) {
3361  SpriteID image = t->ground.sprite;
3362  PaletteID pal = t->ground.pal;
3363  image += HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE) ? ground_relocation : total_offset;
3364  if (GB(image, 0, SPRITE_WIDTH) != 0) {
3365  if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += ground_relocation;
3366  DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette));
3367  }
3368  }
3369 
3370  if (IsDriveThroughStopTile(ti->tile)) {
3371  if (type != STATION_ROADWAYPOINT && (stopspec == nullptr || (stop_draw_mode & ROADSTOP_DRAW_MODE_OVERLAY) != 0)) {
3372  uint sprite_offset = GetDriveThroughStopAxis(ti->tile) == AXIS_X ? 1 : 0;
3373  DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset);
3374  }
3375  } else {
3376  /* Non-drivethrough road stops are only valid for roads. */
3377  assert(road_rt != INVALID_ROADTYPE && tram_rt == INVALID_ROADTYPE);
3378 
3379  if ((stopspec == nullptr || (stop_draw_mode & ROADSTOP_DRAW_MODE_ROAD) != 0) && road_rti->UsesOverlay()) {
3380  SpriteID ground = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_ROADSTOP);
3381  DrawGroundSprite(ground + view, PAL_NONE);
3382  }
3383  }
3384 
3385  if (stopspec == nullptr || !HasBit(stopspec->flags, RSF_NO_CATENARY)) {
3386  /* Draw road, tram catenary */
3387  DrawRoadCatenary(ti);
3388  }
3389  }
3390 
3391  if (IsRailWaypoint(ti->tile)) {
3392  /* Don't offset the waypoint graphics; they're always the same. */
3393  total_offset = 0;
3394  }
3395 
3396  DrawRailTileSeq(ti, t, TO_BUILDINGS, total_offset, relocation, palette);
3397 }
3398 
3399 void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, RoadType roadtype, int image)
3400 {
3401  int32_t total_offset = 0;
3402  PaletteID pal = COMPANY_SPRITE_COLOUR(_local_company);
3403  const DrawTileSprites *t = GetStationTileLayout(st, image);
3404  const RailTypeInfo *railtype_info = nullptr;
3405 
3406  if (railtype != INVALID_RAILTYPE) {
3407  railtype_info = GetRailTypeInfo(railtype);
3408  total_offset = railtype_info->GetRailtypeSpriteOffset();
3409  }
3410 
3411  SpriteID img = t->ground.sprite;
3412  RailTrackOffset overlay_offset;
3413  if (railtype_info != nullptr && railtype_info->UsesOverlay() && SplitGroundSpriteForOverlay(nullptr, &img, &overlay_offset)) {
3414  SpriteID ground = GetCustomRailSprite(railtype_info, INVALID_TILE, RTSG_GROUND);
3415  DrawSprite(img, PAL_NONE, x, y);
3416  DrawSprite(ground + overlay_offset, PAL_NONE, x, y);
3417  } else {
3418  DrawSprite(img + total_offset, HasBit(img, PALETTE_MODIFIER_COLOUR) ? pal : PAL_NONE, x, y);
3419  }
3420 
3421  if (roadtype != INVALID_ROADTYPE) {
3422  const RoadTypeInfo *roadtype_info = GetRoadTypeInfo(roadtype);
3423  if (image >= 4) {
3424  /* Drive-through stop */
3425  uint sprite_offset = 5 - image;
3426 
3427  /* Road underlay takes precedence over tram */
3428  if (roadtype_info->UsesOverlay()) {
3429  SpriteID ground = GetCustomRoadSprite(roadtype_info, INVALID_TILE, ROTSG_GROUND);
3430  DrawSprite(ground + sprite_offset, PAL_NONE, x, y);
3431 
3432  SpriteID overlay = GetCustomRoadSprite(roadtype_info, INVALID_TILE, ROTSG_OVERLAY);
3433  if (overlay) DrawSprite(overlay + sprite_offset, PAL_NONE, x, y);
3434  } else if (RoadTypeIsTram(roadtype)) {
3435  DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y);
3436  }
3437  } else {
3438  /* Bay stop */
3439  if (RoadTypeIsRoad(roadtype) && roadtype_info->UsesOverlay()) {
3440  SpriteID ground = GetCustomRoadSprite(roadtype_info, INVALID_TILE, ROTSG_ROADSTOP);
3441  DrawSprite(ground + image, PAL_NONE, x, y);
3442  }
3443  }
3444  }
3445 
3446  /* Default waypoint has no railtype specific sprites */
3447  DrawRailTileSeqInGUI(x, y, t, (st == STATION_WAYPOINT || st == STATION_ROADWAYPOINT) ? 0 : total_offset, 0, pal);
3448 }
3449 
3450 static int GetSlopePixelZ_Station(TileIndex tile, uint, uint, bool)
3451 {
3452  return GetTileMaxPixelZ(tile);
3453 }
3454 
3455 static Foundation GetFoundation_Station(TileIndex, Slope tileh)
3456 {
3457  return FlatteningFoundation(tileh);
3458 }
3459 
3460 static void FillTileDescRoadStop(TileIndex tile, TileDesc *td)
3461 {
3462  RoadType road_rt = GetRoadTypeRoad(tile);
3463  RoadType tram_rt = GetRoadTypeTram(tile);
3464  Owner road_owner = INVALID_OWNER;
3465  Owner tram_owner = INVALID_OWNER;
3466  if (road_rt != INVALID_ROADTYPE) {
3467  const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt);
3468  td->roadtype = rti->strings.name;
3469  td->road_speed = rti->max_speed / 2;
3470  road_owner = GetRoadOwner(tile, RTT_ROAD);
3471  }
3472 
3473  if (tram_rt != INVALID_ROADTYPE) {
3474  const RoadTypeInfo *rti = GetRoadTypeInfo(tram_rt);
3475  td->tramtype = rti->strings.name;
3476  td->tram_speed = rti->max_speed / 2;
3477  tram_owner = GetRoadOwner(tile, RTT_TRAM);
3478  }
3479 
3480  if (IsDriveThroughStopTile(tile)) {
3481  /* Is there a mix of owners? */
3482  if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) ||
3483  (road_owner != INVALID_OWNER && road_owner != td->owner[0])) {
3484  uint i = 1;
3485  if (road_owner != INVALID_OWNER) {
3486  td->owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER;
3487  td->owner[i] = road_owner;
3488  i++;
3489  }
3490  if (tram_owner != INVALID_OWNER) {
3491  td->owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER;
3492  td->owner[i] = tram_owner;
3493  }
3494  }
3495  }
3496 }
3497 
3498 void FillTileDescRailStation(TileIndex tile, TileDesc *td)
3499 {
3500  const StationSpec *spec = GetStationSpec(tile);
3501 
3502  if (spec != nullptr) {
3504  td->station_name = spec->name;
3505 
3506  if (spec->grf_prop.grffile != nullptr) {
3507  const GRFConfig *gc = GetGRFConfig(spec->grf_prop.grffile->grfid);
3508  td->grf = gc->GetName();
3509  }
3510  }
3511 
3512  const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
3513  td->rail_speed = rti->max_speed;
3514  td->railtype = rti->strings.name;
3515 }
3516 
3517 void FillTileDescAirport(TileIndex tile, TileDesc *td)
3518 {
3519  const AirportSpec *as = Station::GetByTile(tile)->airport.GetSpec();
3521  td->airport_name = as->name;
3522 
3523  const AirportTileSpec *ats = AirportTileSpec::GetByTile(tile);
3524  td->airport_tile_name = ats->name;
3525 
3526  if (as->grf_prop.grffile != nullptr) {
3527  const GRFConfig *gc = GetGRFConfig(as->grf_prop.grffile->grfid);
3528  td->grf = gc->GetName();
3529  } else if (ats->grf_prop.grffile != nullptr) {
3530  const GRFConfig *gc = GetGRFConfig(ats->grf_prop.grffile->grfid);
3531  td->grf = gc->GetName();
3532  }
3533 }
3534 
3535 static void GetTileDesc_Station(TileIndex tile, TileDesc *td)
3536 {
3537  td->owner[0] = GetTileOwner(tile);
3539 
3540  if (IsAnyRoadStop(tile)) FillTileDescRoadStop(tile, td);
3541  if (HasStationRail(tile)) FillTileDescRailStation(tile, td);
3542  if (IsAirport(tile)) FillTileDescAirport(tile, td);
3543 
3544  StringID str;
3545  switch (GetStationType(tile)) {
3546  default: NOT_REACHED();
3547  case STATION_RAIL: str = STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION; break;
3548  case STATION_AIRPORT:
3549  str = (IsHangar(tile) ? STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR : STR_LAI_STATION_DESCRIPTION_AIRPORT);
3550  break;
3551  case STATION_TRUCK: str = STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA; break;
3552  case STATION_BUS: str = STR_LAI_STATION_DESCRIPTION_BUS_STATION; break;
3553  case STATION_OILRIG: {
3554  const Industry *i = Station::GetByTile(tile)->industry;
3555  const IndustrySpec *is = GetIndustrySpec(i->type);
3556  td->owner[0] = i->owner;
3557  str = is->name;
3558  if (is->grf_prop.grffile != nullptr) td->grf = GetGRFConfig(is->grf_prop.grffile->grfid)->GetName();
3559  break;
3560  }
3561  case STATION_DOCK: str = STR_LAI_STATION_DESCRIPTION_SHIP_DOCK; break;
3562  case STATION_BUOY: str = STR_LAI_STATION_DESCRIPTION_BUOY; break;
3563  case STATION_WAYPOINT: str = STR_LAI_STATION_DESCRIPTION_WAYPOINT; break;
3564  case STATION_ROADWAYPOINT: str = STR_LAI_STATION_DESCRIPTION_WAYPOINT; break;
3565  }
3566  td->str = str;
3567 }
3568 
3569 
3570 static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
3571 {
3572  TrackBits trackbits = TRACK_BIT_NONE;
3573 
3574  switch (mode) {
3575  case TRANSPORT_RAIL:
3576  if (HasStationRail(tile) && !IsStationTileBlocked(tile)) {
3577  trackbits = TrackToTrackBits(GetRailStationTrack(tile));
3578  }
3579  break;
3580 
3581  case TRANSPORT_WATER:
3582  /* buoy is coded as a station, it is always on open water */
3583  if (IsBuoy(tile)) {
3584  trackbits = TRACK_BIT_ALL;
3585  /* remove tracks that connect NE map edge */
3586  if (TileX(tile) == 0) trackbits &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
3587  /* remove tracks that connect NW map edge */
3588  if (TileY(tile) == 0) trackbits &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
3589  }
3590  break;
3591 
3592  case TRANSPORT_ROAD:
3593  if (IsAnyRoadStop(tile)) {
3594  RoadTramType rtt = (RoadTramType)sub_mode;
3595  if (!HasTileRoadType(tile, rtt)) break;
3596 
3597  if (IsBayRoadStopTile(tile)) {
3598  DiagDirection dir = GetBayRoadStopDir(tile);
3599  if (side != INVALID_DIAGDIR && dir != side) break;
3600  trackbits = DiagDirToDiagTrackBits(dir);
3601  } else {
3602  Axis axis = GetDriveThroughStopAxis(tile);
3603  if (side != INVALID_DIAGDIR && axis != DiagDirToAxis(side)) break;
3604  trackbits = AxisToTrackBits(axis);
3605  }
3606  }
3607  break;
3608 
3609  default:
3610  break;
3611  }
3612 
3614 }
3615 
3616 
3617 static void TileLoop_Station(TileIndex tile)
3618 {
3619  /* FIXME -- GetTileTrackStatus_Station -> animated stationtiles
3620  * hardcoded.....not good */
3621  switch (GetStationType(tile)) {
3622  case STATION_AIRPORT:
3623  AirportTileAnimationTrigger(Station::GetByTile(tile), tile, AAT_TILELOOP);
3624  break;
3625 
3626  case STATION_DOCK:
3627  if (!IsTileFlat(tile)) break; // only handle water part
3628  [[fallthrough]];
3629 
3630  case STATION_OILRIG: //(station part)
3631  case STATION_BUOY:
3632  TileLoop_Water(tile);
3633  break;
3634 
3635  case STATION_ROADWAYPOINT: {
3637  case LT_ARCTIC:
3638  if (IsRoadWaypointOnSnowOrDesert(tile) != (GetTileZ(tile) > GetSnowLine())) {
3640  MarkTileDirtyByTile(tile);
3641  }
3642  break;
3643 
3644  case LT_TROPIC:
3647  MarkTileDirtyByTile(tile);
3648  }
3649  break;
3650 
3651  default: break;
3652  }
3653 
3654  HouseZonesBits new_zone = HZB_TOWN_EDGE;
3655  const Town *t = ClosestTownFromTile(tile, UINT_MAX);
3656  if (t != nullptr) {
3657  new_zone = GetTownRadiusGroup(t, tile);
3658  }
3659 
3660  /* Adjust road ground type depending on 'new_zone' */
3661  Roadside new_rs = new_zone > HZB_TOWN_EDGE ? ROADSIDE_PAVED : ROADSIDE_GRASS;
3662  Roadside cur_rs = GetRoadWaypointRoadside(tile);
3663 
3664  if (new_rs != cur_rs) {
3665  SetRoadWaypointRoadside(tile, cur_rs == ROADSIDE_BARREN ? new_rs : ROADSIDE_BARREN);
3666  MarkTileDirtyByTile(tile);
3667  }
3668  break;
3669  }
3670 
3671  default: break;
3672  }
3673 }
3674 
3675 
3676 static void AnimateTile_Station(TileIndex tile)
3677 {
3678  if (HasStationRail(tile)) {
3679  AnimateStationTile(tile);
3680  return;
3681  }
3682 
3683  if (IsAirport(tile)) {
3684  AnimateAirportTile(tile);
3685  return;
3686  }
3687 
3688  if (IsAnyRoadStopTile(tile)) {
3689  AnimateRoadStopTile(tile);
3690  return;
3691  }
3692 }
3693 
3694 
3695 static bool ClickTile_Station(TileIndex tile)
3696 {
3697  const BaseStation *bst = BaseStation::GetByTile(tile);
3698 
3699  if (bst->facilities & FACIL_WAYPOINT) {
3701  } else if (IsHangar(tile)) {
3702  const Station *st = Station::From(bst);
3704  } else {
3706  }
3707  return true;
3708 }
3709 
3710 static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, int x, int y)
3711 {
3712  if (v->type == VEH_TRAIN) {
3713  StationID station_id = GetStationIndex(tile);
3714  if (!v->current_order.ShouldStopAtStation(v, station_id)) return VETSB_CONTINUE;
3715  if (!IsRailStation(tile) || !v->IsFrontEngine()) return VETSB_CONTINUE;
3716 
3717  int station_ahead;
3718  int station_length;
3719  int stop = GetTrainStopLocation(station_id, tile, Train::From(v), &station_ahead, &station_length);
3720 
3721  /* Stop whenever that amount of station ahead + the distance from the
3722  * begin of the platform to the stop location is longer than the length
3723  * of the platform. Station ahead 'includes' the current tile where the
3724  * vehicle is on, so we need to subtract that. */
3725  if (stop + station_ahead - (int)TILE_SIZE >= station_length) return VETSB_CONTINUE;
3726 
3728 
3729  x &= 0xF;
3730  y &= 0xF;
3731 
3732  if (DiagDirToAxis(dir) != AXIS_X) Swap(x, y);
3733  if (y == TILE_SIZE / 2) {
3734  if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x;
3735  stop &= TILE_SIZE - 1;
3736 
3737  if (x == stop) {
3738  return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station
3739  } else if (x < stop) {
3741  uint16_t spd = std::max(0, (stop - x) * 20 - 15);
3742  if (spd < v->cur_speed) v->cur_speed = spd;
3743  }
3744  }
3745  } else if (v->type == VEH_ROAD) {
3746  RoadVehicle *rv = RoadVehicle::From(v);
3747  if (rv->state < RVSB_IN_ROAD_STOP && !IsReversingRoadTrackdir((Trackdir)rv->state) && rv->frame == 0) {
3748  if (IsStationRoadStop(tile) && rv->IsFrontEngine()) {
3749  /* Attempt to allocate a parking bay in a road stop */
3751  }
3752  }
3753  }
3754 
3755  return VETSB_CONTINUE;
3756 }
3757 
3763 {
3764  /* Collect cargoes accepted since the last big tick. */
3765  CargoTypes cargoes = 0;
3766  for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
3767  if (HasBit(st->goods[cid].status, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(cargoes, cid);
3768  }
3769 
3770  /* Anything to do? */
3771  if (cargoes == 0) return;
3772 
3773  /* Loop over all houses in the catchment. */
3775  for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
3776  if (IsTileType(tile, MP_HOUSE)) {
3777  WatchedCargoCallback(tile, cargoes);
3778  }
3779  }
3780 }
3781 
3789 {
3790  if (!st->IsInUse()) {
3791  if (++st->delete_ctr >= 8) delete st;
3792  return false;
3793  }
3794 
3795  if (Station::IsExpected(st)) {
3797 
3798  for (GoodsEntry &ge : Station::From(st)->goods) {
3800  }
3801  }
3802 
3803 
3804  if ((st->facilities & FACIL_WAYPOINT) == 0) UpdateStationAcceptance(Station::From(st), true);
3805 
3806  return true;
3807 }
3808 
3809 static inline void byte_inc_sat(uint8_t *p)
3810 {
3811  uint8_t b = *p + 1;
3812  if (b != 0) *p = b;
3813 }
3814 
3821 static void TruncateCargo(const CargoSpec *cs, GoodsEntry *ge, uint amount = UINT_MAX)
3822 {
3823  /* If truncating also punish the source stations' ratings to
3824  * decrease the flow of incoming cargo. */
3825 
3826  StationCargoAmountMap waiting_per_source;
3827  ge->cargo.Truncate(amount, &waiting_per_source);
3828  for (StationCargoAmountMap::iterator i(waiting_per_source.begin()); i != waiting_per_source.end(); ++i) {
3829  Station *source_station = Station::GetIfValid(i->first);
3830  if (source_station == nullptr) continue;
3831 
3832  GoodsEntry &source_ge = source_station->goods[cs->Index()];
3833  source_ge.max_waiting_cargo = std::max(source_ge.max_waiting_cargo, i->second);
3834  }
3835 }
3836 
3837 static void UpdateStationRating(Station *st)
3838 {
3839  bool waiting_changed = false;
3840 
3841  byte_inc_sat(&st->time_since_load);
3842  byte_inc_sat(&st->time_since_unload);
3843 
3844  for (const CargoSpec *cs : CargoSpec::Iterate()) {
3845  GoodsEntry *ge = &st->goods[cs->Index()];
3846  /* Slowly increase the rating back to its original level in the case we
3847  * didn't deliver cargo yet to this station. This happens when a bribe
3848  * failed while you didn't moved that cargo yet to a station. */
3849  if (!ge->HasRating() && ge->rating < INITIAL_STATION_RATING) {
3850  ge->rating++;
3851  }
3852 
3853  /* Only change the rating if we are moving this cargo */
3854  if (ge->HasRating()) {
3855  byte_inc_sat(&ge->time_since_pickup);
3856  if (ge->time_since_pickup == 255 && _settings_game.order.selectgoods) {
3858  ge->last_speed = 0;
3859  TruncateCargo(cs, ge);
3860  waiting_changed = true;
3861  continue;
3862  }
3863 
3864  bool skip = false;
3865  int rating = 0;
3866  uint waiting = ge->cargo.AvailableCount();
3867 
3868  /* num_dests is at least 1 if there is any cargo as
3869  * INVALID_STATION is also a destination.
3870  */
3871  uint num_dests = (uint)ge->cargo.Packets()->MapSize();
3872 
3873  /* Average amount of cargo per next hop, but prefer solitary stations
3874  * with only one or two next hops. They are allowed to have more
3875  * cargo waiting per next hop.
3876  * With manual cargo distribution waiting_avg = waiting / 2 as then
3877  * INVALID_STATION is the only destination.
3878  */
3879  uint waiting_avg = waiting / (num_dests + 1);
3880 
3882  ge->rating = rating = MAX_STATION_RATING;
3883  skip = true;
3884  } else if (HasBit(cs->callback_mask, CBM_CARGO_STATION_RATING_CALC)) {
3885  /* Perform custom station rating. If it succeeds the speed, days in transit and
3886  * waiting cargo ratings must not be executed. */
3887 
3888  /* NewGRFs expect last speed to be 0xFF when no vehicle has arrived yet. */
3889  uint last_speed = ge->HasVehicleEverTriedLoading() ? ge->last_speed : 0xFF;
3890 
3891  uint32_t var18 = ClampTo<uint8_t>(ge->time_since_pickup)
3892  | (ClampTo<uint16_t>(ge->max_waiting_cargo) << 8)
3893  | (ClampTo<uint8_t>(last_speed) << 24);
3894  /* Convert to the 'old' vehicle types */
3895  uint32_t var10 = (st->last_vehicle_type == VEH_INVALID) ? 0x0 : (st->last_vehicle_type + 0x10);
3896  uint16_t callback = GetCargoCallback(CBID_CARGO_STATION_RATING_CALC, var10, var18, cs);
3897  if (callback != CALLBACK_FAILED) {
3898  skip = true;
3899  rating = GB(callback, 0, 14);
3900 
3901  /* Simulate a 15 bit signed value */
3902  if (HasBit(callback, 14)) rating -= 0x4000;
3903  }
3904  }
3905 
3906  if (!skip) {
3907  int b = ge->last_speed - 85;
3908  if (b >= 0) rating += b >> 2;
3909 
3910  uint8_t waittime = ge->time_since_pickup;
3911  if (st->last_vehicle_type == VEH_SHIP) waittime >>= 2;
3912  if (waittime <= 21) rating += 25;
3913  if (waittime <= 12) rating += 25;
3914  if (waittime <= 6) rating += 45;
3915  if (waittime <= 3) rating += 35;
3916 
3917  rating -= 90;
3918  if (ge->max_waiting_cargo <= 1500) rating += 55;
3919  if (ge->max_waiting_cargo <= 1000) rating += 35;
3920  if (ge->max_waiting_cargo <= 600) rating += 10;
3921  if (ge->max_waiting_cargo <= 300) rating += 20;
3922  if (ge->max_waiting_cargo <= 100) rating += 10;
3923  }
3924 
3925  if (Company::IsValidID(st->owner) && HasBit(st->town->statues, st->owner)) rating += 26;
3926 
3927  uint8_t age = ge->last_age;
3928  if (age < 3) rating += 10;
3929  if (age < 2) rating += 10;
3930  if (age < 1) rating += 13;
3931 
3932  {
3933  int or_ = ge->rating; // old rating
3934 
3935  /* only modify rating in steps of -2, -1, 0, 1 or 2 */
3936  ge->rating = rating = or_ + Clamp(ClampTo<uint8_t>(rating) - or_, -2, 2);
3937 
3938  /* if rating is <= 64 and more than 100 items waiting on average per destination,
3939  * remove some random amount of goods from the station */
3940  if (rating <= 64 && waiting_avg >= 100) {
3941  int dec = Random() & 0x1F;
3942  if (waiting_avg < 200) dec &= 7;
3943  waiting -= (dec + 1) * num_dests;
3944  waiting_changed = true;
3945  }
3946 
3947  /* if rating is <= 127 and there are any items waiting, maybe remove some goods. */
3948  if (rating <= 127 && waiting != 0) {
3949  uint32_t r = Random();
3950  if (rating <= (int)GB(r, 0, 7)) {
3951  /* Need to have int, otherwise it will just overflow etc. */
3952  waiting = std::max((int)waiting - (int)((GB(r, 8, 2) - 1) * num_dests), 0);
3953  waiting_changed = true;
3954  }
3955  }
3956 
3957  /* At some point we really must cap the cargo. Previously this
3958  * was a strict 4095, but now we'll have a less strict, but
3959  * increasingly aggressive truncation of the amount of cargo. */
3960  static const uint WAITING_CARGO_THRESHOLD = 1 << 12;
3961  static const uint WAITING_CARGO_CUT_FACTOR = 1 << 6;
3962  static const uint MAX_WAITING_CARGO = 1 << 15;
3963 
3964  if (waiting > WAITING_CARGO_THRESHOLD) {
3965  uint difference = waiting - WAITING_CARGO_THRESHOLD;
3966  waiting -= (difference / WAITING_CARGO_CUT_FACTOR);
3967 
3968  waiting = std::min(waiting, MAX_WAITING_CARGO);
3969  waiting_changed = true;
3970  }
3971 
3972  /* We can't truncate cargo that's already reserved for loading.
3973  * Thus StoredCount() here. */
3974  if (waiting_changed && waiting < ge->cargo.AvailableCount()) {
3975  /* Feed back the exact own waiting cargo at this station for the
3976  * next rating calculation. */
3977  ge->max_waiting_cargo = 0;
3978 
3979  TruncateCargo(cs, ge, ge->cargo.AvailableCount() - waiting);
3980  } else {
3981  /* If the average number per next hop is low, be more forgiving. */
3982  ge->max_waiting_cargo = waiting_avg;
3983  }
3984  }
3985  }
3986  }
3987 
3988  StationID index = st->index;
3989  if (waiting_changed) {
3990  SetWindowDirty(WC_STATION_VIEW, index); // update whole window
3991  } else {
3992  SetWindowWidgetDirty(WC_STATION_VIEW, index, WID_SV_ACCEPT_RATING_LIST); // update only ratings list
3993  }
3994 }
3995 
4004 void RerouteCargo(Station *st, CargoID c, StationID avoid, StationID avoid2)
4005 {
4006  GoodsEntry &ge = st->goods[c];
4007 
4008  /* Reroute cargo in station. */
4009  ge.cargo.Reroute(UINT_MAX, &ge.cargo, avoid, avoid2, &ge);
4010 
4011  /* Reroute cargo staged to be transferred. */
4012  for (Vehicle *v : st->loading_vehicles) {
4013  for (Vehicle *u = v; u != nullptr; u = u->Next()) {
4014  if (u->cargo_type != c) continue;
4015  u->cargo.Reroute(UINT_MAX, &u->cargo, avoid, avoid2, &ge);
4016  }
4017  }
4018 }
4019 
4029 {
4030  for (CargoID c = 0; c < NUM_CARGO; ++c) {
4031  const bool auto_distributed = (_settings_game.linkgraph.GetDistributionType(c) != DT_MANUAL);
4032  GoodsEntry &ge = from->goods[c];
4034  if (lg == nullptr) continue;
4035  std::vector<NodeID> to_remove{};
4036  for (Edge &edge : (*lg)[ge.node].edges) {
4037  Station *to = Station::Get((*lg)[edge.dest_node].station);
4038  assert(to->goods[c].node == edge.dest_node);
4039  assert(TimerGameEconomy::date >= edge.LastUpdate());
4040  auto timeout = TimerGameEconomy::Date(LinkGraph::MIN_TIMEOUT_DISTANCE + (DistanceManhattan(from->xy, to->xy) >> 3));
4041  if (TimerGameEconomy::date - edge.LastUpdate() > timeout) {
4042  bool updated = false;
4043 
4044  if (auto_distributed) {
4045  /* Have all vehicles refresh their next hops before deciding to
4046  * remove the node. */
4047  std::vector<Vehicle *> vehicles;
4048  for (OrderList *l : OrderList::Iterate()) {
4049  bool found_from = false;
4050  bool found_to = false;
4051  for (Order *order = l->GetFirstOrder(); order != nullptr; order = order->next) {
4052  if (!order->IsType(OT_GOTO_STATION) && !order->IsType(OT_IMPLICIT)) continue;
4053  if (order->GetDestination() == from->index) {
4054  found_from = true;
4055  if (found_to) break;
4056  } else if (order->GetDestination() == to->index) {
4057  found_to = true;
4058  if (found_from) break;
4059  }
4060  }
4061  if (!found_to || !found_from) continue;
4062  vehicles.push_back(l->GetFirstSharedVehicle());
4063  }
4064 
4065  auto iter = vehicles.begin();
4066  while (iter != vehicles.end()) {
4067  Vehicle *v = *iter;
4068  /* Do not refresh links of vehicles that have been stopped in depot for a long time. */
4070  LinkRefresher::Run(v, false); // Don't allow merging. Otherwise lg might get deleted.
4071  }
4072  if (edge.LastUpdate() == TimerGameEconomy::date) {
4073  updated = true;
4074  break;
4075  }
4076 
4077  Vehicle *next_shared = v->NextShared();
4078  if (next_shared) {
4079  *iter = next_shared;
4080  ++iter;
4081  } else {
4082  iter = vehicles.erase(iter);
4083  }
4084 
4085  if (iter == vehicles.end()) iter = vehicles.begin();
4086  }
4087  }
4088 
4089  if (!updated) {
4090  /* If it's still considered dead remove it. */
4091  to_remove.emplace_back(to->goods[c].node);
4092  ge.flows.DeleteFlows(to->index);
4093  RerouteCargo(from, c, to->index, from->index);
4094  }
4095  } else if (edge.last_unrestricted_update != EconomyTime::INVALID_DATE && TimerGameEconomy::date - edge.last_unrestricted_update > timeout) {
4096  edge.Restrict();
4097  ge.flows.RestrictFlows(to->index);
4098  RerouteCargo(from, c, to->index, from->index);
4099  } else if (edge.last_restricted_update != EconomyTime::INVALID_DATE && TimerGameEconomy::date - edge.last_restricted_update > timeout) {
4100  edge.Release();
4101  }
4102  }
4103  /* Remove dead edges. */
4104  for (NodeID r : to_remove) (*lg)[ge.node].RemoveEdge(r);
4105 
4106  assert(TimerGameEconomy::date >= lg->LastCompression());
4108  lg->Compress();
4109  }
4110  }
4111 }
4112 
4122 void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage, uint32_t time, EdgeUpdateMode mode)
4123 {
4124  GoodsEntry &ge1 = st->goods[cargo];
4125  Station *st2 = Station::Get(next_station_id);
4126  GoodsEntry &ge2 = st2->goods[cargo];
4127  LinkGraph *lg = nullptr;
4128  if (ge1.link_graph == INVALID_LINK_GRAPH) {
4129  if (ge2.link_graph == INVALID_LINK_GRAPH) {
4131  lg = new LinkGraph(cargo);
4133  ge2.link_graph = lg->index;
4134  ge2.node = lg->AddNode(st2);
4135  } else {
4136  Debug(misc, 0, "Can't allocate link graph");
4137  }
4138  } else {
4139  lg = LinkGraph::Get(ge2.link_graph);
4140  }
4141  if (lg) {
4142  ge1.link_graph = lg->index;
4143  ge1.node = lg->AddNode(st);
4144  }
4145  } else if (ge2.link_graph == INVALID_LINK_GRAPH) {
4146  lg = LinkGraph::Get(ge1.link_graph);
4147  ge2.link_graph = lg->index;
4148  ge2.node = lg->AddNode(st2);
4149  } else {
4150  lg = LinkGraph::Get(ge1.link_graph);
4151  if (ge1.link_graph != ge2.link_graph) {
4152  LinkGraph *lg2 = LinkGraph::Get(ge2.link_graph);
4153  if (lg->Size() < lg2->Size()) {
4155  lg2->Merge(lg); // Updates GoodsEntries of lg
4156  lg = lg2;
4157  } else {
4159  lg->Merge(lg2); // Updates GoodsEntries of lg2
4160  }
4161  }
4162  }
4163  if (lg != nullptr) {
4164  (*lg)[ge1.node].UpdateEdge(ge2.node, capacity, usage, time, mode);
4165  }
4166 }
4167 
4174 void IncreaseStats(Station *st, const Vehicle *front, StationID next_station_id, uint32_t time)
4175 {
4176  for (const Vehicle *v = front; v != nullptr; v = v->Next()) {
4177  if (v->refit_cap > 0) {
4178  /* The cargo count can indeed be higher than the refit_cap if
4179  * wagons have been auto-replaced and subsequently auto-
4180  * refitted to a higher capacity. The cargo gets redistributed
4181  * among the wagons in that case.
4182  * As usage is not such an important figure anyway we just
4183  * ignore the additional cargo then.*/
4184  IncreaseStats(st, v->cargo_type, next_station_id, v->refit_cap,
4185  std::min<uint>(v->refit_cap, v->cargo.StoredCount()), time, EUM_INCREASE);
4186  }
4187  }
4188 }
4189 
4190 /* called for every station each tick */
4191 static void StationHandleSmallTick(BaseStation *st)
4192 {
4193  if ((st->facilities & FACIL_WAYPOINT) != 0 || !st->IsInUse()) return;
4194 
4195  uint8_t b = st->delete_ctr + 1;
4196  if (b >= Ticks::STATION_RATING_TICKS) b = 0;
4197  st->delete_ctr = b;
4198 
4199  if (b == 0) UpdateStationRating(Station::From(st));
4200 }
4201 
4202 void OnTick_Station()
4203 {
4204  if (_game_mode == GM_EDITOR) return;
4205 
4206  for (BaseStation *st : BaseStation::Iterate()) {
4207  StationHandleSmallTick(st);
4208 
4209  /* Clean up the link graph about once a week. */
4212  };
4213 
4214  /* Spread out big-tick over STATION_ACCEPTANCE_TICKS ticks. */
4216  /* Stop processing this station if it was deleted */
4217  if (!StationHandleBigTick(st)) continue;
4218  }
4219 
4220  /* Spread out station animation over STATION_ACCEPTANCE_TICKS ticks. */
4222  TriggerStationAnimation(st, st->xy, SAT_250_TICKS);
4223  TriggerRoadStopAnimation(st, st->xy, SAT_250_TICKS);
4224  if (Station::IsExpected(st)) AirportAnimationTrigger(Station::From(st), AAT_STATION_250_TICKS);
4225  }
4226  }
4227 }
4228 
4230 static IntervalTimer<TimerGameEconomy> _economy_stations_monthly({TimerGameEconomy::MONTH, TimerGameEconomy::Priority::STATION}, [](auto)
4231 {
4232  for (Station *st : Station::Iterate()) {
4233  for (GoodsEntry &ge : st->goods) {
4236  }
4237  }
4238 });
4239 
4240 void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius)
4241 {
4242  ForAllStationsRadius(tile, radius, [&](Station *st) {
4243  if (st->owner == owner && DistanceManhattan(tile, st->xy) <= radius) {
4244  for (GoodsEntry &ge : st->goods) {
4245  if (ge.status != 0) {
4246  ge.rating = ClampTo<uint8_t>(ge.rating + amount);
4247  }
4248  }
4249  }
4250  });
4251 }
4252 
4253 static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceType source_type, SourceID source_id)
4254 {
4255  /* We can't allocate a CargoPacket? Then don't do anything
4256  * at all; i.e. just discard the incoming cargo. */
4257  if (!CargoPacket::CanAllocateItem()) return 0;
4258 
4259  GoodsEntry &ge = st->goods[type];
4260  amount += ge.amount_fract;
4261  ge.amount_fract = GB(amount, 0, 8);
4262 
4263  amount >>= 8;
4264  /* No new "real" cargo item yet. */
4265  if (amount == 0) return 0;
4266 
4267  StationID next = ge.GetVia(st->index);
4268  ge.cargo.Append(new CargoPacket(st->index, amount, source_type, source_id), next);
4269  LinkGraph *lg = nullptr;
4270  if (ge.link_graph == INVALID_LINK_GRAPH) {
4272  lg = new LinkGraph(type);
4274  ge.link_graph = lg->index;
4275  ge.node = lg->AddNode(st);
4276  } else {
4277  Debug(misc, 0, "Can't allocate link graph");
4278  }
4279  } else {
4280  lg = LinkGraph::Get(ge.link_graph);
4281  }
4282  if (lg != nullptr) (*lg)[ge.node].UpdateSupply(amount);
4283 
4284  if (!ge.HasRating()) {
4287  }
4288 
4290  TriggerStationAnimation(st, st->xy, SAT_NEW_CARGO, type);
4291  AirportAnimationTrigger(st, AAT_STATION_NEW_CARGO, type);
4293  TriggerRoadStopAnimation(st, st->xy, SAT_NEW_CARGO, type);
4294 
4295 
4297  st->MarkTilesDirty(true);
4298  return amount;
4299 }
4300 
4301 static bool IsUniqueStationName(const std::string &name)
4302 {
4303  for (const Station *st : Station::Iterate()) {
4304  if (!st->name.empty() && st->name == name) return false;
4305  }
4306 
4307  return true;
4308 }
4309 
4317 CommandCost CmdRenameStation(DoCommandFlag flags, StationID station_id, const std::string &text)
4318 {
4319  Station *st = Station::GetIfValid(station_id);
4320  if (st == nullptr) return CMD_ERROR;
4321 
4322  CommandCost ret = CheckOwnership(st->owner);
4323  if (ret.Failed()) return ret;
4324 
4325  bool reset = text.empty();
4326 
4327  if (!reset) {
4329  if (!IsUniqueStationName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
4330  }
4331 
4332  if (flags & DC_EXEC) {
4333  st->cached_name.clear();
4334  if (reset) {
4335  st->name.clear();
4336  } else {
4337  st->name = text;
4338  }
4339 
4340  st->UpdateVirtCoord();
4342  }
4343 
4344  return CommandCost();
4345 }
4346 
4347 static void AddNearbyStationsByCatchment(TileIndex tile, StationList &stations, StationList &nearby)
4348 {
4349  for (Station *st : nearby) {
4350  if (st->TileIsInCatchment(tile)) stations.insert(st);
4351  }
4352 }
4353 
4359 {
4360  if (this->tile != INVALID_TILE) {
4361  if (IsTileType(this->tile, MP_HOUSE)) {
4362  /* Town nearby stations need to be filtered per tile. */
4363  assert(this->w == 1 && this->h == 1);
4364  AddNearbyStationsByCatchment(this->tile, this->stations, Town::GetByTile(this->tile)->stations_near);
4365  } else {
4366  ForAllStationsAroundTiles(*this, [this](Station *st, TileIndex) {
4367  this->stations.insert(st);
4368  return true;
4369  });
4370  }
4371  this->tile = INVALID_TILE;
4372  }
4373  return this->stations;
4374 }
4375 
4376 
4377 static bool CanMoveGoodsToStation(const Station *st, CargoID type)
4378 {
4379  /* Is the station reserved exclusively for somebody else? */
4380  if (st->owner != OWNER_NONE && st->town->exclusive_counter > 0 && st->town->exclusivity != st->owner) return false;
4381 
4382  /* Lowest possible rating, better not to give cargo anymore. */
4383  if (st->goods[type].rating == 0) return false;
4384 
4385  /* Selectively servicing stations, and not this one. */
4386  if (_settings_game.order.selectgoods && !st->goods[type].HasVehicleEverTriedLoading()) return false;
4387 
4388  if (IsCargoInClass(type, CC_PASSENGERS)) {
4389  /* Passengers are never served by just a truck stop. */
4390  if (st->facilities == FACIL_TRUCK_STOP) return false;
4391  } else {
4392  /* Non-passengers are never served by just a bus stop. */
4393  if (st->facilities == FACIL_BUS_STOP) return false;
4394  }
4395  return true;
4396 }
4397 
4398 uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, SourceID source_id, const StationList &all_stations, Owner exclusivity)
4399 {
4400  /* Return if nothing to do. Also the rounding below fails for 0. */
4401  if (all_stations.empty()) return 0;
4402  if (amount == 0) return 0;
4403 
4404  Station *first_station = nullptr;
4405  typedef std::pair<Station *, uint> StationInfo;
4406  std::vector<StationInfo> used_stations;
4407 
4408  for (Station *st : all_stations) {
4409  if (exclusivity != INVALID_OWNER && exclusivity != st->owner) continue;
4410  if (!CanMoveGoodsToStation(st, type)) continue;
4411 
4412  /* Avoid allocating a vector if there is only one station to significantly
4413  * improve performance in this common case. */
4414  if (first_station == nullptr) {
4415  first_station = st;
4416  continue;
4417  }
4418  if (used_stations.empty()) {
4419  used_stations.reserve(2);
4420  used_stations.emplace_back(first_station, 0);
4421  }
4422  used_stations.emplace_back(st, 0);
4423  }
4424 
4425  /* no stations around at all? */
4426  if (first_station == nullptr) return 0;
4427 
4428  if (used_stations.empty()) {
4429  /* only one station around */
4430  amount *= first_station->goods[type].rating + 1;
4431  return UpdateStationWaiting(first_station, type, amount, source_type, source_id);
4432  }
4433 
4434  uint company_best[OWNER_NONE + 1] = {}; // best rating for each company, including OWNER_NONE
4435  uint company_sum[OWNER_NONE + 1] = {}; // sum of ratings for each company
4436  uint best_rating = 0;
4437  uint best_sum = 0; // sum of best ratings for each company
4438 
4439  for (auto &p : used_stations) {
4440  auto owner = p.first->owner;
4441  auto rating = p.first->goods[type].rating;
4442  if (rating > company_best[owner]) {
4443  best_sum += rating - company_best[owner]; // it's usually faster than iterating companies later
4444  company_best[owner] = rating;
4445  if (rating > best_rating) best_rating = rating;
4446  }
4447  company_sum[owner] += rating;
4448  }
4449 
4450  /* From now we'll calculate with fractional cargo amounts.
4451  * First determine how much cargo we really have. */
4452  amount *= best_rating + 1;
4453 
4454  uint moving = 0;
4455  for (auto &p : used_stations) {
4456  uint owner = p.first->owner;
4457  /* Multiply the amount by (company best / sum of best for each company) to get cargo allocated to a company
4458  * and by (station rating / sum of ratings in a company) to get the result for a single station. */
4459  p.second = amount * company_best[owner] * p.first->goods[type].rating / best_sum / company_sum[owner];
4460  moving += p.second;
4461  }
4462 
4463  /* If there is some cargo left due to rounding issues distribute it among the best rated stations. */
4464  if (amount > moving) {
4465  std::stable_sort(used_stations.begin(), used_stations.end(), [type](const StationInfo &a, const StationInfo &b) {
4466  return b.first->goods[type].rating < a.first->goods[type].rating;
4467  });
4468 
4469  assert(amount - moving <= used_stations.size());
4470  for (uint i = 0; i < amount - moving; i++) {
4471  used_stations[i].second++;
4472  }
4473  }
4474 
4475  uint moved = 0;
4476  for (auto &p : used_stations) {
4477  moved += UpdateStationWaiting(p.first, type, p.second, source_type, source_id);
4478  }
4479 
4480  return moved;
4481 }
4482 
4483 void UpdateStationDockingTiles(Station *st)
4484 {
4485  st->docking_station.Clear();
4486 
4487  /* For neutral stations, start with the industry area instead of dock area */
4488  const TileArea *area = st->industry != nullptr ? &st->industry->location : &st->ship_station;
4489 
4490  if (area->tile == INVALID_TILE) return;
4491 
4492  int x = TileX(area->tile);
4493  int y = TileY(area->tile);
4494 
4495  /* Expand the area by a tile on each side while
4496  * making sure that we remain inside the map. */
4497  int x2 = std::min<int>(x + area->w + 1, Map::SizeX());
4498  int x1 = std::max<int>(x - 1, 0);
4499 
4500  int y2 = std::min<int>(y + area->h + 1, Map::SizeY());
4501  int y1 = std::max<int>(y - 1, 0);
4502 
4503  TileArea ta(TileXY(x1, y1), TileXY(x2 - 1, y2 - 1));
4504  for (TileIndex tile : ta) {
4505  if (IsValidTile(tile) && IsPossibleDockingTile(tile)) CheckForDockingTile(tile);
4506  }
4507 }
4508 
4509 void BuildOilRig(TileIndex tile)
4510 {
4511  if (!Station::CanAllocateItem()) {
4512  Debug(misc, 0, "Can't allocate station for oilrig at 0x{:X}, reverting to oilrig only", tile);
4513  return;
4514  }
4515 
4516  Station *st = new Station(tile);
4517  _station_kdtree.Insert(st->index);
4518  st->town = ClosestTownFromTile(tile, UINT_MAX);
4519 
4520  st->string_id = GenerateStationName(st, tile, STATIONNAMING_OILRIG);
4521 
4522  assert(IsTileType(tile, MP_INDUSTRY));
4523  /* Mark industry as associated both ways */
4524  st->industry = Industry::GetByTile(tile);
4525  st->industry->neutral_station = st;
4526  DeleteAnimatedTile(tile);
4527  MakeOilrig(tile, st->index, GetWaterClass(tile));
4528 
4529  st->owner = OWNER_NONE;
4530  st->airport.type = AT_OILRIG;
4531  st->airport.Add(tile);
4532  st->ship_station.Add(tile);
4535  UpdateStationDockingTiles(st);
4536 
4537  st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE);
4538 
4539  st->UpdateVirtCoord();
4540 
4541  /* An industry tile has now been replaced with a station tile, this may change the overlap between station catchments and industry tiles.
4542  * Recalculate the station catchment for all stations currently in the industry's nearby list.
4543  * Clear the industry's station nearby list first because Station::RecomputeCatchment cannot remove nearby industries in this case. */
4545  StationList nearby = std::move(st->industry->stations_near);
4546  st->industry->stations_near.clear();
4547  for (Station *near : nearby) {
4548  near->RecomputeCatchment(true);
4549  UpdateStationAcceptance(near, true);
4550  }
4551  }
4552 
4553  st->RecomputeCatchment();
4554  UpdateStationAcceptance(st, false);
4555 }
4556 
4557 void DeleteOilRig(TileIndex tile)
4558 {
4559  Station *st = Station::GetByTile(tile);
4560 
4561  MakeWaterKeepingClass(tile, OWNER_NONE);
4562 
4563  /* The oil rig station is not supposed to be shared with anything else */
4564  assert(st->facilities == (FACIL_AIRPORT | FACIL_DOCK) && st->airport.type == AT_OILRIG);
4565  if (st->industry != nullptr && st->industry->neutral_station == st) {
4566  /* Don't leave dangling neutral station pointer */
4567  st->industry->neutral_station = nullptr;
4568  }
4569  delete st;
4570 }
4571 
4572 static void ChangeTileOwner_Station(TileIndex tile, Owner old_owner, Owner new_owner)
4573 {
4574  if (IsAnyRoadStopTile(tile)) {
4575  for (RoadTramType rtt : _roadtramtypes) {
4576  /* Update all roadtypes, no matter if they are present */
4577  if (GetRoadOwner(tile, rtt) == old_owner) {
4578  RoadType rt = GetRoadType(tile, rtt);
4579  if (rt != INVALID_ROADTYPE) {
4580  /* A drive-through road-stop has always two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */
4581  Company::Get(old_owner)->infrastructure.road[rt] -= 2;
4582  if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += 2;
4583  }
4584  SetRoadOwner(tile, rtt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner);
4585  }
4586  }
4587  }
4588 
4589  if (!IsTileOwner(tile, old_owner)) return;
4590 
4591  if (new_owner != INVALID_OWNER) {
4592  /* Update company infrastructure counts. Only do it here
4593  * if the new owner is valid as otherwise the clear
4594  * command will do it for us. No need to dirty windows
4595  * here, we'll redraw the whole screen anyway.*/
4596  Company *old_company = Company::Get(old_owner);
4597  Company *new_company = Company::Get(new_owner);
4598 
4599  /* Update counts for underlying infrastructure. */
4600  switch (GetStationType(tile)) {
4601  case STATION_RAIL:
4602  case STATION_WAYPOINT:
4603  if (!IsStationTileBlocked(tile)) {
4604  old_company->infrastructure.rail[GetRailType(tile)]--;
4605  new_company->infrastructure.rail[GetRailType(tile)]++;
4606  }
4607  break;
4608 
4609  case STATION_BUS:
4610  case STATION_TRUCK:
4611  case STATION_ROADWAYPOINT:
4612  /* Road stops were already handled above. */
4613  break;
4614 
4615  case STATION_BUOY:
4616  case STATION_DOCK:
4617  if (GetWaterClass(tile) == WATER_CLASS_CANAL) {
4618  old_company->infrastructure.water--;
4619  new_company->infrastructure.water++;
4620  }
4621  break;
4622 
4623  default:
4624  break;
4625  }
4626 
4627  /* Update station tile count. */
4628  if (!IsBuoy(tile) && !IsAirport(tile)) {
4629  old_company->infrastructure.station--;
4630  new_company->infrastructure.station++;
4631  }
4632 
4633  /* for buoys, owner of tile is owner of water, st->owner == OWNER_NONE */
4634  SetTileOwner(tile, new_owner);
4636  } else {
4637  if (IsDriveThroughStopTile(tile)) {
4638  /* Remove the drive-through road stop */
4639  if (IsRoadWaypoint(tile)) {
4641  } else {
4642  Command<CMD_REMOVE_ROAD_STOP>::Do(DC_EXEC | DC_BANKRUPT, tile, 1, 1, (GetStationType(tile) == STATION_TRUCK) ? ROADSTOP_TRUCK : ROADSTOP_BUS, false);
4643  }
4644  assert(IsTileType(tile, MP_ROAD));
4645  /* Change owner of tile and all roadtypes */
4646  ChangeTileOwner(tile, old_owner, new_owner);
4647  } else {
4649  /* Set tile owner of water under (now removed) buoy and dock to OWNER_NONE.
4650  * Update owner of buoy if it was not removed (was in orders).
4651  * Do not update when owned by OWNER_WATER (sea and rivers). */
4652  if ((IsTileType(tile, MP_WATER) || IsBuoyTile(tile)) && IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
4653  }
4654  }
4655 }
4656 
4666 {
4667  /* Water flooding can always clear road stops. */
4668  if (_current_company == OWNER_WATER) return CommandCost();
4669 
4670  CommandCost ret;
4671 
4672  if (GetRoadTypeTram(tile) != INVALID_ROADTYPE) {
4673  Owner tram_owner = GetRoadOwner(tile, RTT_TRAM);
4674  if (tram_owner != OWNER_NONE) {
4675  ret = CheckOwnership(tram_owner);
4676  if (ret.Failed()) return ret;
4677  }
4678  }
4679 
4680  if (GetRoadTypeRoad(tile) != INVALID_ROADTYPE) {
4681  Owner road_owner = GetRoadOwner(tile, RTT_ROAD);
4682  if (road_owner == OWNER_TOWN) {
4683  ret = CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, RTT_ROAD), OWNER_TOWN, RTT_ROAD, flags);
4684  if (ret.Failed()) return ret;
4685  } else if (road_owner != OWNER_NONE) {
4686  ret = CheckOwnership(road_owner);
4687  if (ret.Failed()) return ret;
4688  }
4689  }
4690 
4691  return CommandCost();
4692 }
4693 
4701 {
4702  if (flags & DC_AUTO) {
4703  switch (GetStationType(tile)) {
4704  default: break;
4705  case STATION_RAIL: return_cmd_error(STR_ERROR_MUST_DEMOLISH_RAILROAD);
4706  case STATION_WAYPOINT: return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
4707  case STATION_AIRPORT: return_cmd_error(STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST);
4708  case STATION_TRUCK: return_cmd_error(HasTileRoadType(tile, RTT_TRAM) ? STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST);
4709  case STATION_BUS: return_cmd_error(HasTileRoadType(tile, RTT_TRAM) ? STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST);
4710  case STATION_ROADWAYPOINT: return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
4711  case STATION_BUOY: return_cmd_error(STR_ERROR_BUOY_IN_THE_WAY);
4712  case STATION_DOCK: return_cmd_error(STR_ERROR_MUST_DEMOLISH_DOCK_FIRST);
4713  case STATION_OILRIG:
4714  SetDParam(1, STR_INDUSTRY_NAME_OIL_RIG);
4715  return_cmd_error(STR_ERROR_GENERIC_OBJECT_IN_THE_WAY);
4716  }
4717  }
4718 
4719  switch (GetStationType(tile)) {
4720  case STATION_RAIL: return RemoveRailStation(tile, flags);
4721  case STATION_WAYPOINT: return RemoveRailWaypoint(tile, flags);
4722  case STATION_AIRPORT: return RemoveAirport(tile, flags);
4723  case STATION_TRUCK: [[fallthrough]];
4724  case STATION_BUS:
4725  if (IsDriveThroughStopTile(tile)) {
4726  CommandCost remove_road = CanRemoveRoadWithStop(tile, flags);
4727  if (remove_road.Failed()) return remove_road;
4728  }
4729  return RemoveRoadStop(tile, flags);
4730  case STATION_ROADWAYPOINT: {
4731  CommandCost remove_road = CanRemoveRoadWithStop(tile, flags);
4732  if (remove_road.Failed()) return remove_road;
4733  return RemoveRoadWaypointStop(tile, flags);
4734  }
4735  case STATION_BUOY: return RemoveBuoy(tile, flags);
4736  case STATION_DOCK: return RemoveDock(tile, flags);
4737  default: break;
4738  }
4739 
4740  return CMD_ERROR;
4741 }
4742 
4743 static CommandCost TerraformTile_Station(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
4744 {
4746  /* TODO: If you implement newgrf callback 149 'land slope check', you have to decide what to do with it here.
4747  * TTDP does not call it.
4748  */
4749  if (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new)) {
4750  switch (GetStationType(tile)) {
4751  case STATION_WAYPOINT:
4752  case STATION_RAIL: {
4753  if (!AutoslopeCheckForAxis(tile, z_new, tileh_new, GetRailStationAxis(tile))) break;
4754  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
4755  }
4756 
4757  case STATION_AIRPORT:
4758  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
4759 
4760  case STATION_TRUCK:
4761  case STATION_BUS:
4762  case STATION_ROADWAYPOINT: {
4763  if (IsDriveThroughStopTile(tile)) {
4764  if (!AutoslopeCheckForAxis(tile, z_new, tileh_new, GetDriveThroughStopAxis(tile))) break;
4765  } else {
4766  if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetBayRoadStopDir(tile))) break;
4767  }
4768  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
4769  }
4770 
4771  default: break;
4772  }
4773  }
4774  }
4775  return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
4776 }
4777 
4783 uint FlowStat::GetShare(StationID st) const
4784 {
4785  uint32_t prev = 0;
4786  for (const auto &it : this->shares) {
4787  if (it.second == st) {
4788  return it.first - prev;
4789  } else {
4790  prev = it.first;
4791  }
4792  }
4793  return 0;
4794 }
4795 
4802 StationID FlowStat::GetVia(StationID excluded, StationID excluded2) const
4803 {
4804  if (this->unrestricted == 0) return INVALID_STATION;
4805  assert(!this->shares.empty());
4806  SharesMap::const_iterator it = this->shares.upper_bound(RandomRange(this->unrestricted));
4807  assert(it != this->shares.end() && it->first <= this->unrestricted);
4808  if (it->second != excluded && it->second != excluded2) return it->second;
4809 
4810  /* We've hit one of the excluded stations.
4811  * Draw another share, from outside its range. */
4812 
4813  uint end = it->first;
4814  uint begin = (it == this->shares.begin() ? 0 : (--it)->first);
4815  uint interval = end - begin;
4816  if (interval >= this->unrestricted) return INVALID_STATION; // Only one station in the map.
4817  uint new_max = this->unrestricted - interval;
4818  uint rand = RandomRange(new_max);
4819  SharesMap::const_iterator it2 = (rand < begin) ? this->shares.upper_bound(rand) :
4820  this->shares.upper_bound(rand + interval);
4821  assert(it2 != this->shares.end() && it2->first <= this->unrestricted);
4822  if (it2->second != excluded && it2->second != excluded2) return it2->second;
4823 
4824  /* We've hit the second excluded station.
4825  * Same as before, only a bit more complicated. */
4826 
4827  uint end2 = it2->first;
4828  uint begin2 = (it2 == this->shares.begin() ? 0 : (--it2)->first);
4829  uint interval2 = end2 - begin2;
4830  if (interval2 >= new_max) return INVALID_STATION; // Only the two excluded stations in the map.
4831  new_max -= interval2;
4832  if (begin > begin2) {
4833  Swap(begin, begin2);
4834  Swap(end, end2);
4835  Swap(interval, interval2);
4836  }
4837  rand = RandomRange(new_max);
4838  SharesMap::const_iterator it3 = this->shares.upper_bound(this->unrestricted);
4839  if (rand < begin) {
4840  it3 = this->shares.upper_bound(rand);
4841  } else if (rand < begin2 - interval) {
4842  it3 = this->shares.upper_bound(rand + interval);
4843  } else {
4844  it3 = this->shares.upper_bound(rand + interval + interval2);
4845  }
4846  assert(it3 != this->shares.end() && it3->first <= this->unrestricted);
4847  return it3->second;
4848 }
4849 
4856 {
4857  assert(!this->shares.empty());
4858  SharesMap new_shares;
4859  uint i = 0;
4860  for (const auto &it : this->shares) {
4861  new_shares[++i] = it.second;
4862  if (it.first == this->unrestricted) this->unrestricted = i;
4863  }
4864  this->shares.swap(new_shares);
4865  assert(!this->shares.empty() && this->unrestricted <= (--this->shares.end())->first);
4866 }
4867 
4874 void FlowStat::ChangeShare(StationID st, int flow)
4875 {
4876  /* We assert only before changing as afterwards the shares can actually
4877  * be empty. In that case the whole flow stat must be deleted then. */
4878  assert(!this->shares.empty());
4879 
4880  uint removed_shares = 0;
4881  uint added_shares = 0;
4882  uint last_share = 0;
4883  SharesMap new_shares;
4884  for (const auto &it : this->shares) {
4885  if (it.second == st) {
4886  if (flow < 0) {
4887  uint share = it.first - last_share;
4888  if (flow == INT_MIN || (uint)(-flow) >= share) {
4889  removed_shares += share;
4890  if (it.first <= this->unrestricted) this->unrestricted -= share;
4891  if (flow != INT_MIN) flow += share;
4892  last_share = it.first;
4893  continue; // remove the whole share
4894  }
4895  removed_shares += (uint)(-flow);
4896  } else {
4897  added_shares += (uint)(flow);
4898  }
4899  if (it.first <= this->unrestricted) this->unrestricted += flow;
4900 
4901  /* If we don't continue above the whole flow has been added or
4902  * removed. */
4903  flow = 0;
4904  }
4905  new_shares[it.first + added_shares - removed_shares] = it.second;
4906  last_share = it.first;
4907  }
4908  if (flow > 0) {
4909  new_shares[last_share + (uint)flow] = st;
4910  if (this->unrestricted < last_share) {
4911  this->ReleaseShare(st);
4912  } else {
4913  this->unrestricted += flow;
4914  }
4915  }
4916  this->shares.swap(new_shares);
4917 }
4918 
4924 void FlowStat::RestrictShare(StationID st)
4925 {
4926  assert(!this->shares.empty());
4927  uint flow = 0;
4928  uint last_share = 0;
4929  SharesMap new_shares;
4930  for (auto &it : this->shares) {
4931  if (flow == 0) {
4932  if (it.first > this->unrestricted) return; // Not present or already restricted.
4933  if (it.second == st) {
4934  flow = it.first - last_share;
4935  this->unrestricted -= flow;
4936  } else {
4937  new_shares[it.first] = it.second;
4938  }
4939  } else {
4940  new_shares[it.first - flow] = it.second;
4941  }
4942  last_share = it.first;
4943  }
4944  if (flow == 0) return;
4945  new_shares[last_share + flow] = st;
4946  this->shares.swap(new_shares);
4947  assert(!this->shares.empty());
4948 }
4949 
4955 void FlowStat::ReleaseShare(StationID st)
4956 {
4957  assert(!this->shares.empty());
4958  uint flow = 0;
4959  uint next_share = 0;
4960  bool found = false;
4961  for (SharesMap::reverse_iterator it(this->shares.rbegin()); it != this->shares.rend(); ++it) {
4962  if (it->first < this->unrestricted) return; // Note: not <= as the share may hit the limit.
4963  if (found) {
4964  flow = next_share - it->first;
4965  this->unrestricted += flow;
4966  break;
4967  } else {
4968  if (it->first == this->unrestricted) return; // !found -> Limit not hit.
4969  if (it->second == st) found = true;
4970  }
4971  next_share = it->first;
4972  }
4973  if (flow == 0) return;
4974  SharesMap new_shares;
4975  new_shares[flow] = st;
4976  for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) {
4977  if (it->second != st) {
4978  new_shares[flow + it->first] = it->second;
4979  } else {
4980  flow = 0;
4981  }
4982  }
4983  this->shares.swap(new_shares);
4984  assert(!this->shares.empty());
4985 }
4986 
4992 void FlowStat::ScaleToMonthly(uint runtime)
4993 {
4994  assert(runtime > 0);
4995  SharesMap new_shares;
4996  uint share = 0;
4997  for (auto i : this->shares) {
4998  share = std::max(share + 1, i.first * 30 / runtime);
4999  new_shares[share] = i.second;
5000  if (this->unrestricted == i.first) this->unrestricted = share;
5001  }
5002  this->shares.swap(new_shares);
5003 }
5004 
5011 void FlowStatMap::AddFlow(StationID origin, StationID via, uint flow)
5012 {
5013  FlowStatMap::iterator origin_it = this->find(origin);
5014  if (origin_it == this->end()) {
5015  this->emplace(origin, FlowStat(via, flow));
5016  } else {
5017  origin_it->second.ChangeShare(via, flow);
5018  assert(!origin_it->second.GetShares()->empty());
5019  }
5020 }
5021 
5030 void FlowStatMap::PassOnFlow(StationID origin, StationID via, uint flow)
5031 {
5032  FlowStatMap::iterator prev_it = this->find(origin);
5033  if (prev_it == this->end()) {
5034  FlowStat fs(via, flow);
5035  fs.AppendShare(INVALID_STATION, flow);
5036  this->emplace(origin, fs);
5037  } else {
5038  prev_it->second.ChangeShare(via, flow);
5039  prev_it->second.ChangeShare(INVALID_STATION, flow);
5040  assert(!prev_it->second.GetShares()->empty());
5041  }
5042 }
5043 
5049 {
5050  for (auto &i : *this) {
5051  FlowStat &fs = i.second;
5052  uint local = fs.GetShare(INVALID_STATION);
5053  if (local > INT_MAX) { // make sure it fits in an int
5054  fs.ChangeShare(self, -INT_MAX);
5055  fs.ChangeShare(INVALID_STATION, -INT_MAX);
5056  local -= INT_MAX;
5057  }
5058  fs.ChangeShare(self, -(int)local);
5059  fs.ChangeShare(INVALID_STATION, -(int)local);
5060 
5061  /* If the local share is used up there must be a share for some
5062  * remote station. */
5063  assert(!fs.GetShares()->empty());
5064  }
5065 }
5066 
5074 {
5075  StationIDStack ret;
5076  for (FlowStatMap::iterator f_it = this->begin(); f_it != this->end();) {
5077  FlowStat &s_flows = f_it->second;
5078  s_flows.ChangeShare(via, INT_MIN);
5079  if (s_flows.GetShares()->empty()) {
5080  ret.Push(f_it->first);
5081  this->erase(f_it++);
5082  } else {
5083  ++f_it;
5084  }
5085  }
5086  return ret;
5087 }
5088 
5093 void FlowStatMap::RestrictFlows(StationID via)
5094 {
5095  for (auto &it : *this) {
5096  it.second.RestrictShare(via);
5097  }
5098 }
5099 
5104 void FlowStatMap::ReleaseFlows(StationID via)
5105 {
5106  for (auto &it : *this) {
5107  it.second.ReleaseShare(via);
5108  }
5109 }
5110 
5116 {
5117  uint ret = 0;
5118  for (const auto &it : *this) {
5119  ret += (--(it.second.GetShares()->end()))->first;
5120  }
5121  return ret;
5122 }
5123 
5129 uint FlowStatMap::GetFlowVia(StationID via) const
5130 {
5131  uint ret = 0;
5132  for (const auto &it : *this) {
5133  ret += it.second.GetShare(via);
5134  }
5135  return ret;
5136 }
5137 
5143 uint FlowStatMap::GetFlowFrom(StationID from) const
5144 {
5145  FlowStatMap::const_iterator i = this->find(from);
5146  if (i == this->end()) return 0;
5147  return (--(i->second.GetShares()->end()))->first;
5148 }
5149 
5156 uint FlowStatMap::GetFlowFromVia(StationID from, StationID via) const
5157 {
5158  FlowStatMap::const_iterator i = this->find(from);
5159  if (i == this->end()) return 0;
5160  return i->second.GetShare(via);
5161 }
5162 
5163 extern const TileTypeProcs _tile_type_station_procs = {
5164  DrawTile_Station, // draw_tile_proc
5165  GetSlopePixelZ_Station, // get_slope_z_proc
5166  ClearTile_Station, // clear_tile_proc
5167  nullptr, // add_accepted_cargo_proc
5168  GetTileDesc_Station, // get_tile_desc_proc
5169  GetTileTrackStatus_Station, // get_tile_track_status_proc
5170  ClickTile_Station, // click_tile_proc
5171  AnimateTile_Station, // animate_tile_proc
5172  TileLoop_Station, // tile_loop_proc
5173  ChangeTileOwner_Station, // change_tile_owner_proc
5174  nullptr, // add_produced_cargo_proc
5175  VehicleEnter_Station, // vehicle_enter_tile_proc
5176  GetFoundation_Station, // get_foundation_proc
5177  TerraformTile_Station, // terraform_tile_proc
5178 };
Base for aircraft.
void UpdateAirplanesOnNewStation(const Station *st)
Updates the status of the Aircraft heading or in the station.
const AirportFTAClass * GetAirport(const uint8_t airport_type)
Get the finite state machine of an airport type.
Definition: airport.cpp:207
static const uint INVALID_AIRPORTTILE
id for an invalid airport tile
Definition: airport.h:25
static const uint NEW_AIRPORTTILE_OFFSET
offset of first newgrf airport tile
Definition: airport.h:24
@ NUM_AIRPORTS
Maximal number of airports in total.
Definition: airport.h:41
@ AT_OILRIG
Oilrig airport.
Definition: airport.h:38
static const uint64_t AIRPORT_CLOSED_block
Dummy block for indicating a closed airport.
Definition: airport.h:128
@ FLYING
Vehicle is flying in the air.
Definition: airport.h:75
Enum of the default airport tiles.
void DeleteAnimatedTile(TileIndex tile)
Removes the given tile from the animated tile table.
void AddAnimatedTile(TileIndex tile, bool mark_dirty)
Add the given tile to the animated tile table (if it does not exist yet).
Tile animation!
Functions related to autoslope.
bool AutoslopeCheckForAxis(TileIndex tile, int z_new, Slope tileh_new, Axis axis)
Autoslope check for tiles with something built along an axis.
Definition: autoslope.h:51
bool AutoslopeCheckForEntranceEdge(TileIndex tile, int z_new, Slope tileh_new, DiagDirection entrance)
Autoslope check for tiles with an entrance on an edge.
Definition: autoslope.h:31
bool AutoslopeEnabled()
Tests if autoslope is enabled for _current_company.
Definition: autoslope.h:65
constexpr bool HasExactlyOneBit(T value)
Test whether value has exactly 1 bit set.
constexpr debug_inline bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SB(T &x, const uint8_t s, const uint8_t n, const U d)
Set n bits in x starting at bit s to d.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr uint8_t FindFirstBit(T x)
Search the first set bit in a value.
constexpr uint CountBits(T value)
Counts the number of set bits in a variable.
constexpr static debug_inline uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
Map accessor functions for bridges.
bool IsBridgeAbove(Tile t)
checks if a bridge is set above the ground of this tile
Definition: bridge_map.h:45
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 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
bool IsCargoInClass(CargoID c, CargoClass cc)
Does cargo c have cargo class cc?
Definition: cargotype.h:232
@ CC_MAIL
Mail.
Definition: cargotype.h:51
@ CC_LIQUID
Liquids (Oil, Water, Rubber)
Definition: cargotype.h:56
@ CC_PASSENGERS
Passengers.
Definition: cargotype.h:50
Cheats _cheats
All the cheats.
Definition: cheat.cpp:16
Types related to cheating.
Iterator to iterate over all tiles belonging to an airport.
Definition: station_base.h:525
Iterator to iterate over all tiles belonging to an airport spec.
Iterator to iterate over all tiles belonging to a bitmaptilearea.
Definition: bitmap_type.h:106
const Tcont * Packets() const
Returns a pointer to the cargo packet list (so you can iterate over it etc).
Definition: cargopacket.h:329
Common return value for all commands.
Definition: command_type.h:23
bool Succeeded() const
Did this command succeed?
Definition: command_type.h:162
void AddCost(const Money &cost)
Adds the given cost to the cost of the command.
Definition: command_type.h:63
bool Failed() const
Did this command fail?
Definition: command_type.h:171
uint GetFlow() const
Get the sum of all flows from this FlowStatMap.
void PassOnFlow(StationID origin, StationID via, uint amount)
Pass on some flow, remembering it as invalid, for later subtraction from locally consumed flow.
void AddFlow(StationID origin, StationID via, uint amount)
Add some flow from "origin", going via "via".
uint GetFlowFrom(StationID from) const
Get the sum of flows from a specific station from this FlowStatMap.
void FinalizeLocalConsumption(StationID self)
Subtract invalid flows from locally consumed flow.
void ReleaseFlows(StationID via)
Release all flows at a station for specific cargo and destination.
StationIDStack DeleteFlows(StationID via)
Delete all flows at a station for specific cargo and destination.
uint GetFlowFromVia(StationID from, StationID via) const
Get the flow from a specific station via a specific other station.
uint GetFlowVia(StationID via) const
Get the sum of flows via a specific station from this FlowStatMap.
void RestrictFlows(StationID via)
Restrict all flows at a station for specific cargo and destination.
Flow statistics telling how much flow should be sent along a link.
Definition: station_base.h:32
static const SharesMap empty_sharesmap
Static instance of FlowStat::SharesMap.
Definition: station_base.h:36
void ScaleToMonthly(uint runtime)
Scale all shares from link graph's runtime to monthly values.
void RestrictShare(StationID st)
Restrict a flow by moving it to the end of the map and decreasing the amount of unrestricted flow.
uint GetShare(StationID st) const
Get flow for a station.
StationID GetVia() const
Get a station a package can be routed to.
Definition: station_base.h:130
SharesMap shares
Shares of flow to be sent via specified station (or consumed locally).
Definition: station_base.h:143
void ReleaseShare(StationID st)
Release ("unrestrict") a flow by moving it to the begin of the map and increasing the amount of unres...
void ChangeShare(StationID st, int flow)
Change share for specified station.
const SharesMap * GetShares() const
Get the actual shares as a const pointer so that they can be iterated over.
Definition: station_base.h:88
void AppendShare(StationID st, uint flow, bool restricted=false)
Add some flow to the end of the shares map.
Definition: station_base.h:66
void Invalidate()
Reduce all flows to minimum capacity so that they don't get in the way of link usage statistics too m...
uint unrestricted
Limit for unrestricted shares.
Definition: station_base.h:144
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition: timer.h:76
void Insert(const T &element)
Insert a single element in the tree.
Definition: kdtree.hpp:398
void Remove(const T &element)
Remove a single element from the tree, if it exists.
Definition: kdtree.hpp:417
static LinkGraphSchedule instance
Static instance of LinkGraphSchedule.
void Unqueue(LinkGraph *lg)
Remove a link graph from the execution queue.
void Queue(LinkGraph *lg)
Queue a link graph for execution.
A connected component of a link graph.
Definition: linkgraph.h:37
void Merge(LinkGraph *other)
Merge a link graph with another one.
Definition: linkgraph.cpp:90
TimerGameEconomy::Date LastCompression() const
Get date of last compression.
Definition: linkgraph.h:236
NodeID AddNode(const Station *st)
Add a node to the component and create empty edges associated with it.
Definition: linkgraph.cpp:149
NodeID Size() const
Get the current size of the component.
Definition: linkgraph.h:230
static const uint MIN_TIMEOUT_DISTANCE
Minimum effective distance for timeout calculation.
Definition: linkgraph.h:170
static constexpr TimerGameEconomy::Date STALE_LINK_DEPOT_TIMEOUT
Number of days before deleting links served only by vehicles stopped in depot.
Definition: linkgraph.h:173
static constexpr TimerGameEconomy::Date COMPRESSION_INTERVAL
Minimum number of days between subsequent compressions of a LG.
Definition: linkgraph.h:176
static void Run(Vehicle *v, bool allow_merge=true, bool is_full_loading=false)
Refresh all links the given vehicle will visit.
Definition: refresh.cpp:26
size_t MapSize() const
Count the number of ranges with equal keys in this MultiMap.
Definition: multimap.hpp:347
Struct containing information relating to NewGRF classes for stations and airports.
Definition: newgrf_class.h:26
StringID name
Name of this class.
Definition: newgrf_class.h:49
static NewGRFClass * Get(Tindex class_index)
Get a particular class.
uint GetSpecCount() const
Get the number of allocated specs within the class.
Definition: newgrf_class.h:70
static uint GetClassCount()
Get the number of allocated classes.
const Tspec * GetSpec(uint index) const
Get a spec from the class at a given index.
This struct contains all the info that is needed to draw and construct tracks.
Definition: rail.h:127
SpriteID single_x
single piece of rail in X direction, without ground
Definition: rail.h:137
uint16_t max_speed
Maximum speed for vehicles travelling on this rail type.
Definition: rail.h:231
struct RailTypeInfo::@23 base_sprites
Struct containing the main sprites.
struct RailTypeInfo::@26 strings
Strings associated with the rail type.
SpriteID single_y
single piece of rail in Y direction, without ground
Definition: rail.h:138
StringID name
Name of this rail type.
Definition: rail.h:176
uint8_t fallback_railtype
Original railtype number to use when drawing non-newgrf railtypes, or when drawing stations.
Definition: rail.h:201
uint GetRailtypeSpriteOffset() const
Offset between the current railtype and normal rail.
Definition: rail.h:295
struct RoadTypeInfo::@29 strings
Strings associated with the rail type.
uint16_t max_speed
Maximum speed for vehicles travelling on this road type.
Definition: road.h:142
StringID name
Name of this rail type.
Definition: road.h:103
Minimal stack that uses a pool to avoid pointers.
void Push(const Titem &item)
Pushes a new item onto the stack if there is still space in the underlying pool.
uint Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge)
Routes packets with station "avoid" as next hop to a different place.
uint AvailableCount() const
Returns sum of cargo still available for loading at the sation.
Definition: cargopacket.h:588
void Append(CargoPacket *cp, StationID next)
Appends the given cargo packet to the range of packets with the same next station.
uint Truncate(uint max_move=UINT_MAX, StationCargoAmountMap *cargo_per_source=nullptr)
Truncates where each destination loses roughly the same percentage of its cargo.
const StationList & GetStations()
Run a tile loop to find stations around a tile, on demand.
StationList stations
List of stations nearby.
Definition: station_type.h:101
static constexpr TimerGameTick::Ticks STATION_LINKGRAPH_TICKS
Cycle duration for cleaning dead links.
static constexpr TimerGameTick::Ticks STATION_ACCEPTANCE_TICKS
Cycle duration for updating station acceptance.
static constexpr TimerGameTick::Ticks STATION_RATING_TICKS
Cycle duration for updating station rating.
Base class for tile iterators.
Wrapper class to abstract away the way the tiles are stored.
Definition: map_func.h:25
static Date date
Current date in days (day counter).
static constexpr TimerGame< struct Economy >::Date INVALID_DATE
Representation of an invalid date.
static Date date
Current date in days (day counter).
static TickCounter counter
Monotonic counter, in ticks, since start of game.
uint StoredCount() const
Returns sum of cargo on board the vehicle (ie not only reserved).
Definition: cargopacket.h:434
Functions related to clear (MP_CLEAR) land.
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
Definition: command_func.h:28
#define return_cmd_error(errcode)
Returns from a function with a specific StringID as error.
Definition: command_func.h:38
DoCommandFlag
List of flags for a command.
Definition: command_type.h:374
@ DC_AUTO
don't allow building on structures
Definition: command_type.h:377
@ DC_BANKRUPT
company bankrupts, skip money check, skip vehicle on tile check in some cases
Definition: command_type.h:382
@ DC_EXEC
execute the given command
Definition: command_type.h:376
Definition of stuff that is very close to a company, like the company struct itself.
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
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
void DirtyCompanyInfrastructureWindows(CompanyID company)
Redraw all windows with company infrastructure counts.
GUI Functions related to companies.
Owner
Enum for all companies/owners.
Definition: company_type.h:18
@ INVALID_OWNER
An invalid owner.
Definition: company_type.h:29
@ OWNER_NONE
The tile has no ownership.
Definition: company_type.h:25
@ OWNER_WATER
The tile/execution is done by "water".
Definition: company_type.h:26
@ OWNER_TOWN
A town owns the tile, or a town is expanding.
Definition: company_type.h:24
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.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
bool CanBuildDepotByTileh(DiagDirection direction, Slope tileh)
Find out if the slope of the tile is suitable to build a depot of given direction.
Definition: depot_func.h:27
void ShowDepotWindow(TileIndex tile, VehicleType type)
Opens a depot window.
Definition: depot_gui.cpp:1164
bool IsValidAxis(Axis d)
Checks if an integer value is a valid Axis.
DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
bool IsValidDiagDirection(DiagDirection d)
Checks if an integer value is a valid DiagDirection.
DiagDirection AxisToDiagDir(Axis a)
Converts an Axis to a DiagDirection.
Axis OtherAxis(Axis a)
Select the other axis as provided.
Axis DiagDirToAxis(DiagDirection d)
Convert a DiagDirection to the axis.
DiagDirection DirToDiagDir(Direction dir)
Convert a Direction to a DiagDirection.
Direction
Defines the 8 directions on the map.
@ DIR_W
West.
@ DIR_E
East.
Axis
Allow incrementing of DiagDirDiff variables.
@ AXIS_X
The X axis.
DiagDirection
Enumeration for diagonal directions.
@ DIAGDIR_NE
Northeast, upper right on your monitor.
@ DIAGDIR_SE
Southeast.
@ DIAGDIR_END
Used for iterations.
@ DIAGDIR_BEGIN
Used for iterations.
@ INVALID_DIAGDIR
Flag for an invalid DiagDirection.
@ DIAGDIR_SW
Southwest.
static const uint ROAD_STOP_TRACKBIT_FACTOR
Multiplier for how many regular track bits a bay stop counts.
Definition: economy_type.h:247
@ EXPENSES_CONSTRUCTION
Construction costs.
Definition: economy_type.h:173
Price
Enumeration of all base prices for use with Prices.
Definition: economy_type.h:89
void DrawRailCatenary(const TileInfo *ti)
Draws overhead wires and pylons for electric railways.
Definition: elrail.cpp:568
header file for electrified rail specific functions
bool HasRailCatenaryDrawn(RailType rt)
Test if we should draw rail catenary.
Definition: elrail_func.h:30
constexpr debug_inline bool HasFlag(const T x, const T y)
Checks if a value in a bitset enum is set.
Definition: enum_type.hpp:58
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition: gfx.cpp:988
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:18
uint32_t PaletteID
The number of the palette.
Definition: gfx_type.h:19
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
Definition: landscape.cpp:609
void MarkTilesDirty(bool cargo_change) const
Marks the tiles of the station as dirty.
Definition: station.cpp:243
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
Definition: viewport.cpp:2057
Base of all industries.
bool IsTileForestIndustry(TileIndex tile)
Check whether the tile is a forest.
const IndustrySpec * GetIndustrySpec(IndustryType thistype)
Accessor for array _industry_specs.
IndustryType GetIndustryType(Tile tile)
Retrieve the type for this industry.
IndustryID GetIndustryIndex(Tile t)
Get the industry ID of the given tile.
Definition: industry_map.h:63
static const IndustryType NUM_INDUSTRYTYPES
total number of industry types, new and old; limited to 240 because we need some special ids like INV...
Definition: industry_type.h:26
@ INDUSTRYLIFE_EXTRACTIVE
Like mines.
Definition: industrytype.h:24
void ChangeTileOwner(TileIndex tile, Owner old_owner, Owner new_owner)
Change the owner of a tile.
Definition: landscape.cpp:565
void DrawFoundation(TileInfo *ti, Foundation f)
Draw foundation f at tile ti.
Definition: landscape.cpp:425
std::tuple< Slope, int > GetFoundationPixelSlope(TileIndex tile)
Get slope of a tile on top of a (possible) foundation If a tile does not have a foundation,...
Definition: landscape.h:65
uint ApplyPixelFoundationToSlope(Foundation f, Slope &s)
Applies a foundation to a slope.
Definition: landscape.h:126
Point RemapCoords2(int x, int y)
Map 3D world or tile coordinate to equivalent 2D coordinate as used in the viewports and smallmap.
Definition: landscape.h:95
Command definitions related to landscape (slopes etc.).
Some typedefs for the main game.
@ DT_MANUAL
Manual distribution. No link graph calculations are run.
EdgeUpdateMode
Special modes for updating links.
@ EUM_INCREASE
Increase capacity.
bool CircularTileSearch(TileIndex *tile, uint size, TestTileOnSearchProc proc, void *user_data)
Function performing a search around a center tile and going outward, thus in circle.
Definition: map.cpp:247
uint DistanceFromEdge(TileIndex tile)
Param the minimum distance to an edge.
Definition: map.cpp:206
uint DistanceMax(TileIndex t0, TileIndex t1)
Gets the biggest distance component (x or y) between the two given tiles.
Definition: map.cpp:178
TileIndex TileAddWrap(TileIndex tile, int addx, int addy)
This function checks if we add addx/addy to tile, if we do wrap around the edges.
Definition: map.cpp:97
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition: map.cpp:146
static debug_inline TileIndex TileXY(uint x, uint y)
Returns the TileIndex of a coordinate.
Definition: map_func.h:373
TileIndexDiff ToTileIndexDiff(TileIndexDiffC tidc)
Return the offset between two tiles from a TileIndexDiffC struct.
Definition: map_func.h:440
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition: map_func.h:389
TileIndexDiff TileOffsByAxis(Axis axis)
Convert an Axis to a TileIndexDiff.
Definition: map_func.h:552
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition: map_func.h:425
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition: map_func.h:415
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition: map_func.h:567
int32_t TileIndexDiff
An offset value between two tiles.
Definition: map_type.h:23
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
Definition: math_func.hpp:252
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:79
constexpr uint ClampU(const uint a, const uint min, const uint max)
Clamp an unsigned integer between an interval.
Definition: math_func.hpp:150
constexpr void Swap(T &a, T &b)
Type safe swap operation.
Definition: math_func.hpp:283
uint8_t StationGfx
Copy from station_map.h.
StationGfx GetTranslatedAirportTileID(StationGfx gfx)
Do airporttile gfx ID translation for NewGRFs.
NewGRF handling of airport tiles.
@ AAT_BUILT
Triggered when the airport is built (for all tiles at the same time).
@ AAT_STATION_NEW_CARGO
Triggered when new cargo arrives at the station (for all tiles at the same time).
@ AAT_TILELOOP
Triggered in the periodic tile loop.
@ AAT_STATION_250_TICKS
Triggered every 250 ticks (for all tiles at the same time).
static const uint8_t ANIM_STATUS_NO_ANIMATION
There is no animation.
@ SAT_NEW_CARGO
Trigger station on new cargo arrival.
@ SAT_BUILT
Trigger tile when built.
@ SAT_250_TICKS
Trigger station every 250 ticks.
@ CBM_STATION_DRAW_TILE_LAYOUT
Use callback to select a tile layout to use when drawing.
@ CBM_STATION_SLOPE_CHECK
Check slope of new station tiles.
@ CBM_STATION_AVAIL
Availability of station in construction window.
@ CBID_STATION_BUILD_TILE_LAYOUT
Called when building a station to customize the tile layout.
@ CBID_STATION_DRAW_TILE_LAYOUT
Choose a tile layout to draw, instead of the standard range.
@ CBID_CARGO_STATION_RATING_CALC
Called to calculate part of a station rating.
@ CBID_STATION_AVAILABILITY
Determine whether a newstation should be made available to build.
@ CBM_ROAD_STOP_AVAIL
Availability of road stop in construction window.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
@ CBM_CARGO_STATION_RATING_CALC
custom station rating for this cargo type
SpriteID GetCanalSprite(CanalFeature feature, TileIndex tile)
Lookup the base sprite to use for a canal.
Handling of NewGRF canals.
Cargo support for NewGRFs.
void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
bool Convert8bitBooleanCallback(const GRFFile *grffile, uint16_t cbid, uint16_t cb_res)
Converts a callback result into a boolean.
GRFConfig * GetGRFConfig(uint32_t grfid, uint32_t mask)
Retrieve a NewGRF from the current config by its grfid.
Functions/types related to NewGRF debugging.
void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
Delete inspect window for a given feature and index.
void WatchedCargoCallback(TileIndex tile, CargoTypes trigger_cargoes)
Run watched cargo accepted callback for a house.
Functions related to NewGRF houses.
SpriteID GetCustomRailSprite(const RailTypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg, TileContext context, uint *num_results)
Get the sprite to draw for the given tile.
NewGRF handling of rail types.
NewGRF definitions and structures for road stops.
RoadStopDrawMode
Different draw modes to disallow rendering of some parts of the stop or road.
@ ROADSTOP_DRAW_MODE_ROAD
Bay stops: Draw the road itself.
@ ROADSTOP_DRAW_MODE_OVERLAY
Drive-through stops: Draw the road overlay, e.g. pavement.
@ ROADSTOP_DRAW_MODE_WAYP_GROUND
Waypoints: Draw the sprite layout ground tile (on top of the road)
@ RSRT_NEW_CARGO
Trigger roadstop on arrival of new cargo.
bool IsWaypointClass(const RoadStopClass &cls)
Test if a RoadStopClass is the waypoint class.
RoadStopClassID
@ ROADSTOPTYPE_FREIGHT
This RoadStop is for freight (truck) stops.
@ ROADSTOPTYPE_ALL
This RoadStop is for both types of station road stops.
@ ROADSTOPTYPE_PASSENGER
This RoadStop is for passenger (bus) stops.
@ RSF_NO_CATENARY
Do not show catenary.
@ RSF_DRAW_MODE_REGISTER
Read draw mode from register 0x100.
@ RSF_DRIVE_THROUGH_ONLY
Stop is drive-through only.
void TriggerRoadStopRandomisation(Station *st, TileIndex tile, RoadStopRandomTrigger trigger, CargoID cargo_type=INVALID_CARGO)
Trigger road stop randomisation.
SpriteID GetCustomRoadSprite(const RoadTypeInfo *rti, TileIndex tile, RoadTypeSpriteGroup rtsg, TileContext context, uint *num_results)
Get the sprite to draw for the given tile.
NewGRF handling of road types.
uint32_t GetRegister(uint i)
Gets the value of a so-called newgrf "register".
int AllocateSpecToStation(const StationSpec *statspec, BaseStation *st, bool exec)
Allocate a StationSpec to a Station.
uint32_t GetPlatformInfo(Axis axis, uint8_t tile, int platforms, int length, int x, int y, bool centred)
Evaluate a tile's position within a station, and return the result in a bit-stuffed format.
SpriteID GetCustomStationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint32_t var10)
Resolve sprites for drawing a station tile.
void TriggerStationRandomisation(Station *st, TileIndex trigger_tile, StationRandomTrigger trigger, CargoID cargo_type)
Trigger station randomisation.
SpriteID GetCustomStationFoundationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint layout, uint edge_info)
Resolve the sprites for custom station foundations.
void DeallocateSpecFromStation(BaseStation *st, uint8_t specindex)
Deallocate a StationSpec from a Station.
CommandCost PerformStationTileSlopeCheck(TileIndex north_tile, TileIndex cur_tile, const StationSpec *statspec, Axis axis, uint8_t plat_len, uint8_t numtracks)
Check the slope of a tile of a new station.
Header file for NewGRF stations.
@ SSF_SEPARATE_GROUND
Use different sprite set for ground sprites.
@ SSF_CUSTOM_FOUNDATIONS
Draw custom foundations.
@ SSF_EXTENDED_FOUNDATIONS
Extended foundation block instead of simple.
uint16_t GetStationLayoutKey(uint8_t platforms, uint8_t length)
Get the station layout key for a given station layout size.
@ SRT_NEW_CARGO
Trigger station on new cargo arrival.
StationClassID
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_ACCEPTANCE
A type of cargo is (no longer) accepted.
Definition: news_type.h:37
@ NR_STATION
Reference station. Scroll to station when clicking on the news. Delete news when station is deleted.
Definition: news_type.h:56
@ NF_INCOLOUR
Bit value for coloured news.
Definition: news_type.h:74
@ NF_SMALL
Small news item. (Information window with text and viewport)
Definition: news_type.h:80
Functions related to order backups.
void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool b)
Set the reservation for a complete station platform.
Definition: pbs.cpp:57
Train * GetTrainForReservation(TileIndex tile, Track track)
Find the train which has reserved a specific path.
Definition: pbs.cpp:330
PBS support routines.
bool ValParamRailType(const RailType rail)
Validate functions for rail building.
Definition: rail.cpp:206
@ RTSG_GROUND
Main group of ground images.
Definition: rail.h:52
@ RTSG_OVERLAY
Images for overlaying track.
Definition: rail.h:51
Money RailBuildCost(RailType railtype)
Returns the cost of building the specified railtype.
Definition: rail.h:375
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition: rail.h:307
bool HasPowerOnRail(RailType enginetype, RailType tiletype)
Checks if an engine of the given RailType got power on a tile with a given RailType.
Definition: rail.h:335
RailTrackOffset
Offsets for sprites within an overlay/underlay set.
Definition: rail.h:70
@ RTO_Y
Piece of rail in Y direction.
Definition: rail.h:72
@ RTO_X
Piece of rail in X direction.
Definition: rail.h:71
Command definitions for rail.
RailType GetRailType(Tile t)
Gets the rail type of the given tile.
Definition: rail_map.h:115
TrackBits GetTrackBits(Tile tile)
Gets the track bits of the given tile.
Definition: rail_map.h:136
TrackBits GetRailReservationTrackBits(Tile t)
Returns the reserved track bits of the tile.
Definition: rail_map.h:194
bool HasSignals(Tile t)
Checks if a rail tile has signals.
Definition: rail_map.h:72
static debug_inline bool IsPlainRailTile(Tile t)
Checks whether the tile is a rail tile or rail tile with signals.
Definition: rail_map.h:60
RailType
Enumeration for all possible railtypes.
Definition: rail_type.h:27
@ INVALID_RAILTYPE
Flag for invalid railtype.
Definition: rail_type.h:34
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
Definition of link refreshing utility.
bool ValParamRoadType(RoadType roadtype)
Validate functions for rail building.
Definition: road.cpp:153
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition: road.h:227
bool HasPowerOnRoad(RoadType enginetype, RoadType tiletype)
Checks if an engine of the given RoadType got power on a tile with a given RoadType.
Definition: road.h:242
@ ROTSG_OVERLAY
Optional: Images for overlaying track.
Definition: road.h:61
@ ROTSG_ROADSTOP
Required: Bay stop surface.
Definition: road.h:70
@ ROTSG_GROUND
Required: Main group of ground images.
Definition: road.h:62
Money RoadBuildCost(RoadType roadtype)
Returns the cost of building the specified roadtype.
Definition: road.h:252
CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, RoadTramType rtt, DoCommandFlag flags, bool town_check)
Is it allowed to remove the given road bits from the given tile?
Definition: road_cmd.cpp:262
void DrawRoadGroundSprites(const TileInfo *ti, RoadBits road, RoadBits tram, const RoadTypeInfo *road_rti, const RoadTypeInfo *tram_rti, Roadside roadside, bool snow_or_desert)
Draw road ground sprites.
Definition: road_cmd.cpp:1605
void DrawRoadCatenary(const TileInfo *ti)
Draws the catenary for the given tile.
Definition: road_cmd.cpp:1451
void UpdateCompanyRoadInfrastructure(RoadType rt, Owner o, int count)
Update road infrastructure counts for a company.
Definition: road_cmd.cpp:190
void DrawRoadOverlays(const TileInfo *ti, PaletteID pal, const RoadTypeInfo *road_rti, const RoadTypeInfo *tram_rti, uint road_offset, uint tram_offset, bool draw_underlay)
Draw road underlay and overlay sprites.
Definition: road_cmd.cpp:1515
Functions related to roads.
RoadBits AxisToRoadBits(Axis a)
Create the road-part which belongs to the given Axis.
Definition: road_func.h:111
Functions used internally by the roads.
RoadBits GetAnyRoadBits(Tile tile, RoadTramType rtt, bool straight_tunnel_bridge_entrance)
Returns the RoadBits on an arbitrary tile Special behaviour:
Definition: road_map.cpp:33
void SetRoadOwner(Tile t, RoadTramType rtt, Owner o)
Set the owner of a specific road type.
Definition: road_map.h:251
static debug_inline bool IsNormalRoadTile(Tile t)
Return whether a tile is a normal road tile.
Definition: road_map.h:74
RoadBits GetRoadBits(Tile t, RoadTramType rtt)
Get the present road bits for a specific road type.
Definition: road_map.h:128
bool MayHaveRoad(Tile t)
Test whether a tile can have road/tram types.
Definition: road_map.h:33
DisallowedRoadDirections GetDisallowedRoadDirections(Tile t)
Gets the disallowed directions.
Definition: road_map.h:301
bool HasTileRoadType(Tile t, RoadTramType rtt)
Check if a tile has a road or a tram road type.
Definition: road_map.h:211
void MakeRoadNormal(Tile t, RoadBits bits, RoadType road_rt, RoadType tram_rt, TownID town, Owner road, Owner tram)
Make a normal road tile.
Definition: road_map.h:635
RoadBits GetAllRoadBits(Tile tile)
Get all set RoadBits on the given tile.
Definition: road_map.h:141
Owner GetRoadOwner(Tile t, RoadTramType rtt)
Get the owner of a specific road type.
Definition: road_map.h:234
Roadside
The possible road side decorations.
Definition: road_map.h:477
@ ROADSIDE_PAVED
Road with paved sidewalks.
Definition: road_map.h:480
@ ROADSIDE_BARREN
Road on barren land.
Definition: road_map.h:478
@ ROADSIDE_GRASS
Road on grass.
Definition: road_map.h:479
RoadBits
Enumeration for the road parts on a tile.
Definition: road_type.h:52
@ ROAD_NONE
No road-part is build.
Definition: road_type.h:53
@ ROAD_Y
Full road along the y-axis (north-west + south-east)
Definition: road_type.h:59
@ ROAD_X
Full road along the x-axis (south-west + north-east)
Definition: road_type.h:58
RoadType
The different roadtypes we support.
Definition: road_type.h:25
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition: road_type.h:30
@ DRD_NONE
None of the directions are disallowed.
Definition: road_type.h:74
Base class for roadstops.
Road vehicle states.
@ RVSB_IN_ROAD_STOP
The vehicle is in a road stop.
Definition: roadveh.h:49
@ RVSB_ROAD_STOP_TRACKDIR_MASK
Only bits 0 and 3 are used to encode the trackdir for road stops.
Definition: roadveh.h:57
@ RVS_IN_DT_ROAD_STOP
The vehicle is in a drive-through road stop.
Definition: roadveh.h:46
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
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:56
Base for ships.
bool IsShipDestinationTile(TileIndex tile, StationID station)
Test if a tile is a docking tile for the given station.
Definition: ship_cmd.cpp:647
void AddTrackToSignalBuffer(TileIndex tile, Track track, Owner owner)
Add track to signal update buffer.
Definition: signal.cpp:592
static constexpr int GetSlopeMaxZ(Slope s)
Returns the height of the highest corner of a slope relative to TileZ (= minimal height)
Definition: slope_func.h:160
static constexpr bool IsSteepSlope(Slope s)
Checks if a slope is steep.
Definition: slope_func.h:36
Foundation FlatteningFoundation(Slope s)
Returns the foundation needed to flatten a slope.
Definition: slope_func.h:369
DiagDirection GetInclinedSlopeDirection(Slope s)
Returns the direction of an inclined slope.
Definition: slope_func.h:239
Slope
Enumeration for the slope-type.
Definition: slope_type.h:48
@ SLOPE_FLAT
a flat tile
Definition: slope_type.h:49
Foundation
Enumeration for Foundations.
Definition: slope_type.h:93
@ FOUNDATION_LEVELED
The tile is leveled up to a flat slope.
Definition: slope_type.h:95
#define M(x)
Helper for creating a bitset of slopes.
Definition: slope_type.h:84
void DrawRailTileSeqInGUI(int x, int y, const DrawTileSprites *dts, int32_t total_offset, uint32_t newgrf_offset, PaletteID default_palette)
Draw tile sprite sequence in GUI with railroad specifics.
Definition: sprite.h:99
void DrawRailTileSeq(const struct TileInfo *ti, const DrawTileSprites *dts, TransparencyOption to, int32_t total_offset, uint32_t newgrf_offset, PaletteID default_palette)
Draw tile sprite sequence on tile with railroad specifics.
Definition: sprite.h:89
PaletteID GroundSpritePaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
Applies PALETTE_MODIFIER_COLOUR to a palette entry of a ground sprite.
Definition: sprite.h:168
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition: sprites.h:1605
static constexpr uint8_t SPRITE_MODIFIER_CUSTOM_SPRITE
these masks change the colours of the palette for a sprite.
Definition: sprites.h:1545
static constexpr uint8_t SPRITE_WIDTH
number of bits for the sprite number
Definition: sprites.h:1535
static constexpr uint8_t PALETTE_MODIFIER_COLOUR
this bit is set when a recolouring process is in action
Definition: sprites.h:1548
Base classes/functions for stations.
void ForAllStationsAroundTiles(const TileArea &ta, Func func)
Call a function on all stations that have any part of the requested area within their catchment.
Definition: station_base.h:564
CommandCost RemoveFromRailBaseStation(TileArea ta, std::vector< T * > &affected_stations, DoCommandFlag flags, Money removal_cost, bool keep_rail)
Remove a number of tiles from any rail station within the area.
CommandCost CmdOpenCloseAirport(DoCommandFlag flags, StationID station_id)
Open/close an airport to incoming aircraft.
CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags)
Clear a single tile of a station.
CargoTypes GetEmptyMask(const Station *st)
Get a mask of the cargo types that are empty at the station.
static CommandCost BuildStationPart(Station **st, DoCommandFlag flags, bool reuse, TileArea area, StationNaming name_class)
Common part of building various station parts and possibly attaching them to an existing one.
uint8_t GetAirportNoiseLevelForDistance(const AirportSpec *as, uint distance)
Get a possible noise reduction factor based on distance from town center.
CommandCost CmdRemoveRoadStop(DoCommandFlag flags, TileIndex tile, uint8_t width, uint8_t height, RoadStopType stop_type, bool remove_road)
Remove bus or truck stops.
CargoArray GetAcceptanceAroundTiles(TileIndex center_tile, int w, int h, int rad, CargoTypes *always_accepted)
Get the acceptance of cargoes around the tile in 1/8.
static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming name_class)
CommandCost CanExpandRailStation(const BaseStation *st, TileArea &new_ta)
Check whether we can expand the rail part of the given station.
void ClearDockingTilesCheckingNeighbours(TileIndex tile)
Clear docking tile status from tiles around a removed dock, if the tile has no neighbours which would...
static RoadStop ** FindRoadStopSpot(bool truck_station, Station *st)
bool(* CMSAMatcher)(TileIndex tile)
Function to check whether the given tile matches some criterion.
bool IsHangar(Tile t)
Check whether the given tile is a hangar.
Definition: station_cmd.cpp:92
CommandCost CmdRemoveFromRoadWaypoint(DoCommandFlag flags, TileIndex start, TileIndex end)
Remove road waypoints.
void RerouteCargo(Station *st, CargoID c, StationID avoid, StationID avoid2)
Reroute cargo of type c at station st or in any vehicles unloading there.
static CommandCost CheckFlatLandRailStation(TileIndex tile_cur, TileIndex north_tile, int &allowed_z, DoCommandFlag flags, Axis axis, StationID *station, RailType rt, std::vector< Train * > &affected_vehicles, StationClassID spec_class, uint16_t spec_index, uint8_t plat_len, uint8_t numtracks)
Checks if a rail station can be built at the given tile.
static bool CMSAMine(TileIndex tile)
Check whether the tile is a mine.
CommandCost CmdRemoveFromRailStation(DoCommandFlag flags, TileIndex start, TileIndex end, bool keep_rail)
Remove a single tile from a rail station.
static void TruncateCargo(const CargoSpec *cs, GoodsEntry *ge, uint amount=UINT_MAX)
Truncate the cargo by a specific amount.
Town * AirportGetNearestTown(const AirportSpec *as, Direction rotation, TileIndex tile, TileIterator &&it, uint &mindist)
Finds the town nearest to given airport.
static CommandCost CheckFlatLandAirport(AirportTileTableIterator tile_iter, DoCommandFlag flags)
Checks if an airport can be built at the given location and clear the area.
CommandCost FindJoiningWaypoint(StationID existing_waypoint, StationID waypoint_to_join, bool adjacent, TileArea ta, Waypoint **wp, bool is_road)
Find a nearby waypoint that joins this waypoint.
static Station * GetClosestDeletedStation(TileIndex tile)
Find the closest deleted station of the current company.
CommandCost GetStationAround(TileArea ta, StationID closest_station, CompanyID company, T **st, F filter)
Look for a station owned by the given company around the given tile area.
bool HasStationInUse(StationID station, bool include_company, CompanyID company)
Tests whether the company's vehicles have this station in orders.
static int CountMapSquareAround(TileIndex tile, CMSAMatcher cmp)
Counts the numbers of tiles matching a specific type in the area around.
static StationSpec::TileFlags GetStationTileFlags(StationGfx gfx, const StationSpec *statspec)
Get station tile flags for the given StationGfx.
CommandCost CmdBuildDock(DoCommandFlag flags, TileIndex tile, StationID station_to_join, bool adjacent)
Build a dock/haven.
void GetStationLayout(uint8_t *layout, uint numtracks, uint plat_len, const StationSpec *statspec)
Create the station layout for the given number of tracks and platform length.
static bool FindNearIndustryName(TileIndex tile, void *user_data)
Find a station action 0 property 24 station name, or reduce the free_names if needed.
static CommandCost RemoveRailWaypoint(TileIndex tile, DoCommandFlag flags)
Remove a rail waypoint.
void UpdateAllStationVirtCoords()
Update the virtual coords needed to draw the station sign for all stations.
static bool CMSAWater(TileIndex tile)
Check whether the tile is water.
static CommandCost CalculateRailStationCost(TileArea tile_area, DoCommandFlag flags, Axis axis, StationID *station, RailType rt, std::vector< Train * > &affected_vehicles, StationClassID spec_class, uint16_t spec_index, uint8_t plat_len, uint8_t numtracks)
Calculates cost of new rail stations within the area.
void TriggerWatchedCargoCallbacks(Station *st)
Run the watched cargo callback for all houses in the catchment area.
CommandCost CmdBuildAirport(DoCommandFlag flags, TileIndex tile, uint8_t airport_type, uint8_t layout, StationID station_to_join, bool allow_adjacent)
Place an Airport.
CommandCost CmdBuildRoadStop(DoCommandFlag flags, TileIndex tile, uint8_t width, uint8_t length, RoadStopType stop_type, bool is_drive_through, DiagDirection ddir, RoadType rt, RoadStopClassID spec_class, uint16_t spec_index, StationID station_to_join, bool adjacent)
Build a bus or truck stop.
CommandCost CheckFlatLandRoadStop(TileIndex cur_tile, int &allowed_z, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, StationType station_type, Axis axis, StationID *station, RoadType rt)
Checks if a road stop can be built at the given tile.
CommandCost CmdRemoveFromRailWaypoint(DoCommandFlag flags, TileIndex start, TileIndex end, bool keep_rail)
Remove a single tile from a waypoint.
static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags)
Remove an airport.
static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags)
Remove a dock.
CargoTypes GetAcceptanceMask(const Station *st)
Get a mask of the cargo types that the station accepts.
CommandCost CheckBuildableTile(TileIndex tile, uint invalid_dirs, int &allowed_z, bool allow_steep, bool check_bridge=true)
Checks if the given tile is buildable, flat and has a certain height.
static void RestoreTrainReservation(Train *v)
Restore platform reservation during station building/removing.
void UpdateAirportsNoise()
Recalculate the noise generated by the airports of each town.
static bool CMSATree(TileIndex tile)
Check whether the tile is a tree.
void UpdateStationAcceptance(Station *st, bool show_msg)
Update the acceptance for a station.
CommandCost CmdBuildRailStation(DoCommandFlag flags, TileIndex tile_org, RailType rt, Axis axis, uint8_t numtracks, uint8_t plat_len, StationClassID spec_class, uint16_t spec_index, StationID station_to_join, bool adjacent)
Build rail station.
static CommandCost FindJoiningRoadStop(StationID existing_stop, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
Find a nearby station that joins this road stop.
CommandCost CmdRenameStation(DoCommandFlag flags, StationID station_id, const std::string &text)
Rename a station.
static TileIndex FindDockLandPart(TileIndex t)
Find the part of a dock that is land-based.
static CommandCost RemoveGenericRoadStop(DoCommandFlag flags, const TileArea &roadstop_area, StationType station_type, bool remove_road)
Remove a tile area of road stop or road waypoints.
static void FreeTrainReservation(Train *v)
Clear platform reservation during station building/removing.
void SetRailStationTileFlags(TileIndex tile, const StationSpec *statspec)
Set rail station tile flags for the given tile.
static CommandCost CanRemoveRoadWithStop(TileIndex tile, DoCommandFlag flags)
Check if a drive-through road stop tile can be cleared.
static CargoArray GetAcceptanceAroundStation(const Station *st, CargoTypes *always_accepted)
Get the acceptance of cargoes around the station in.
bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrackOffset *overlay_offset)
Check whether a sprite is a track sprite, which can be replaced by a non-track ground sprite and a ra...
CargoArray GetProductionAroundTiles(TileIndex north_tile, int w, int h, int rad)
Get the cargo types being produced around the tile (in a rectangle).
void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage, uint32_t time, EdgeUpdateMode mode)
Increase capacity for a link stat given by station cargo and next hop.
static CommandCost FindJoiningStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
Find a nearby station that joins this station.
static IntervalTimer< TimerGameEconomy > _economy_stations_monthly({TimerGameEconomy::MONTH, TimerGameEconomy::Priority::STATION}, [](auto) { for(Station *st :Station::Iterate()) { for(GoodsEntry &ge :st->goods) { SB(ge.status, GoodsEntry::GES_LAST_MONTH, 1, GB(ge.status, GoodsEntry::GES_CURRENT_MONTH, 1));ClrBit(ge.status, GoodsEntry::GES_CURRENT_MONTH);} } })
Economy monthly loop for stations.
void DeleteStaleLinks(Station *from)
Check all next hops of cargo packets in this station for existence of a a valid link they may use to ...
CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st, F filter)
Find a nearby station that joins this station.
const DrawTileSprites * GetStationTileLayout(StationType st, uint8_t gfx)
Get station tile layout for a station type and its station gfx.
static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags, int replacement_spec_index=-1)
Remove a bus station/truck stop.
CommandCost CalculateRoadStopCost(TileArea tile_area, DoCommandFlag flags, bool is_drive_through, StationType station_type, Axis axis, DiagDirection ddir, StationID *est, RoadType rt, Money unit_cost)
Calculates cost of new road stops within the area.
static bool StationHandleBigTick(BaseStation *st)
This function is called for each station once every 250 ticks.
CommandCost RemoveRoadWaypointStop(TileIndex tile, DoCommandFlag flags, int replacement_spec_index=-1)
Remove a road waypoint.
static void ShowRejectOrAcceptNews(const Station *st, CargoTypes cargoes, bool reject)
Add news item for when a station changes which cargoes it accepts.
CommandCost RemoveRailStation(T *st, DoCommandFlag flags, Money removal_cost)
Remove a rail station/waypoint.
static void DeleteStationIfEmpty(BaseStation *st)
This is called right after a station was deleted.
Command definitions related to stations.
Functions related to stations.
void ShowStationViewWindow(StationID station)
Opens StationViewWindow for given station.
Declarations for accessing the k-d tree of stations.
void ForAllStationsRadius(TileIndex center, uint radius, Func func)
Call a function on all stations whose sign is within a radius of a center tile.
Sprites to use and how to display them for station tiles.
void MakeAirport(Tile t, Owner o, StationID sid, uint8_t section, WaterClass wc)
Make the given tile an airport tile.
Definition: station_map.h:811
StationType GetStationType(Tile t)
Get the station type of this tile.
Definition: station_map.h:44
StationGfx GetStationGfx(Tile t)
Get the station graphics of this tile.
Definition: station_map.h:68
void SetStationGfx(Tile t, StationGfx gfx)
Set the station graphics of this tile.
Definition: station_map.h:80
void MakeRoadStop(Tile t, Owner o, StationID sid, RoadStopType rst, RoadType road_rt, RoadType tram_rt, DiagDirection d)
Make the given tile a roadstop tile.
Definition: station_map.h:775
void SetCustomStationSpecIndex(Tile t, uint8_t specindex)
Set the custom station spec for this tile.
Definition: station_map.h:630
void SetStationTileHaveWires(Tile t, bool b)
Set the catenary wires state of the rail station.
Definition: station_map.h:467
bool IsAirport(Tile t)
Is this station tile an airport?
Definition: station_map.h:157
bool IsBayRoadStopTile(Tile t)
Is tile t a bay (non-drive through) road stop station?
Definition: station_map.h:266
uint GetCustomRoadStopSpecIndex(Tile t)
Get the custom road stop spec for this tile.
Definition: station_map.h:678
static const int GFX_DOCK_BASE_WATER_PART
The offset for the water parts.
Definition: station_map.h:35
bool IsBuoy(Tile t)
Is tile t a buoy tile?
Definition: station_map.h:400
bool IsCompatibleTrainStationTile(Tile test_tile, Tile station_tile)
Check if a tile is a valid continuation to a railstation tile.
Definition: station_map.h:544
bool IsRoadWaypoint(Tile t)
Is the station at t a road waypoint?
Definition: station_map.h:202
void MakeDriveThroughRoadStop(Tile t, Owner station, Owner road, Owner tram, StationID sid, StationType rst, RoadType road_rt, RoadType tram_rt, Axis a)
Make the given tile a drivethrough roadstop tile.
Definition: station_map.h:795
bool IsDriveThroughStopTile(Tile t)
Is tile t a drive through road stop station or waypoint?
Definition: station_map.h:276
static Roadside GetRoadWaypointRoadside(Tile tile)
Get the decorations of a road waypoint.
Definition: station_map.h:288
bool IsRailStationTile(Tile t)
Is this tile a station tile and a rail station?
Definition: station_map.h:102
Track GetRailStationTrack(Tile t)
Get the rail track of a rail station tile.
Definition: station_map.h:515
static void ToggleRoadWaypointOnSnowOrDesert(Tile t)
Toggle the snow/desert state of a road waypoint tile.
Definition: station_map.h:320
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition: station_map.h:28
bool HasStationTileRail(Tile t)
Has this station tile a rail? In other words, is this station tile a rail station or rail waypoint?
Definition: station_map.h:146
StationGfx GetAirportGfx(Tile t)
Get the station graphics of this airport tile.
Definition: station_map.h:332
uint GetCustomStationSpecIndex(Tile t)
Get the custom station spec for this tile.
Definition: station_map.h:642
bool IsRailWaypoint(Tile t)
Is this station tile a rail waypoint?
Definition: station_map.h:113
bool IsRailStation(Tile t)
Is this station tile a rail station?
Definition: station_map.h:92
bool IsDockTile(Tile t)
Is tile t a dock tile?
Definition: station_map.h:389
static void SetRoadWaypointRoadside(Tile tile, Roadside s)
Set the decorations of a road waypoint.
Definition: station_map.h:299
void SetStationTileRandomBits(Tile t, uint8_t random_bits)
Set the random bits for a station tile.
Definition: station_map.h:690
bool IsAnyRoadStop(Tile t)
Is the station at t a road station?
Definition: station_map.h:245
void MakeOilrig(Tile t, StationID sid, WaterClass wc)
Make the given tile an oilrig tile.
Definition: station_map.h:850
DiagDirection GetDockDirection(Tile t)
Get the direction of a dock.
Definition: station_map.h:595
Axis GetRailStationAxis(Tile t)
Get the rail direction of a rail station.
Definition: station_map.h:503
static bool IsRoadWaypointOnSnowOrDesert(Tile t)
Check if a road waypoint tile has snow/desert.
Definition: station_map.h:310
bool IsRoadWaypointTile(Tile t)
Is this tile a station tile and a road waypoint?
Definition: station_map.h:212
bool IsStationTileBlocked(Tile t)
Is tile t a blocked tile?
Definition: station_map.h:431
bool IsTruckStop(Tile t)
Is the station at t a truck stop?
Definition: station_map.h:180
bool IsStationRoadStop(Tile t)
Is the station at t a road station?
Definition: station_map.h:223
bool IsCustomStationSpecIndex(Tile t)
Is there a custom rail station spec on this tile?
Definition: station_map.h:618
bool HasStationRail(Tile t)
Has this station tile a rail? In other words, is this station tile a rail station or rail waypoint?
Definition: station_map.h:135
Axis GetDriveThroughStopAxis(Tile t)
Gets the axis of the drive through stop.
Definition: station_map.h:356
void SetStationTileHavePylons(Tile t, bool b)
Set the catenary pylon state of the rail station.
Definition: station_map.h:491
bool IsOilRig(Tile t)
Is tile t part of an oilrig?
Definition: station_map.h:368
bool IsBuoyTile(Tile t)
Is tile t a buoy tile?
Definition: station_map.h:410
void MakeRailStation(Tile t, Owner o, StationID sid, Axis a, uint8_t section, RailType rt)
Make the given tile a rail station tile.
Definition: station_map.h:742
bool HasStationReservation(Tile t)
Get the reservation state of the rail station.
Definition: station_map.h:559
void MakeDock(Tile t, Owner o, StationID sid, DiagDirection d, WaterClass wc)
Make the given tile a dock tile.
Definition: station_map.h:838
DiagDirection GetBayRoadStopDir(Tile t)
Gets the direction the bay road stop entrance points towards.
Definition: station_map.h:344
bool IsDock(Tile t)
Is tile t a dock tile?
Definition: station_map.h:379
bool IsAnyRoadStopTile(Tile t)
Is tile t a road stop station?
Definition: station_map.h:256
void SetStationTileBlocked(Tile t, bool b)
Set the blocked state of the rail station.
Definition: station_map.h:443
RoadStopType GetRoadStopType(Tile t)
Get the road stop type of this tile.
Definition: station_map.h:56
void SetCustomRoadStopSpecIndex(Tile t, uint8_t specindex)
Set the custom road stop spec for this tile.
Definition: station_map.h:666
RoadStopType
Types of RoadStops.
Definition: station_type.h:45
@ ROADSTOP_BUS
A standard stop for buses.
Definition: station_type.h:46
@ ROADSTOP_TRUCK
A standard stop for trucks.
Definition: station_type.h:47
@ ROADSTOP_END
End of valid types.
Definition: station_type.h:48
@ FACIL_DOCK
Station with a dock.
Definition: station_type.h:58
@ FACIL_BUS_STOP
Station with bus stops.
Definition: station_type.h:56
@ FACIL_AIRPORT
Station with an airport.
Definition: station_type.h:57
@ FACIL_WAYPOINT
Station is a waypoint.
Definition: station_type.h:59
@ FACIL_TRUCK_STOP
Station with truck stops.
Definition: station_type.h:55
@ FACIL_TRAIN
Station with train station.
Definition: station_type.h:54
StationType
Station types.
Definition: station_type.h:31
std::set< Station *, StationCompare > StationList
List of stations.
Definition: station_type.h:94
static const uint MAX_LENGTH_STATION_NAME_CHARS
The maximum length of a station name in characters including '\0'.
Definition: station_type.h:87
Types related to the station widgets.
@ WID_SV_CLOSE_AIRPORT
'Close airport' button.
@ WID_SV_ROADVEHS
List of scheduled road vehs button.
@ WID_SV_ACCEPT_RATING_LIST
List of accepted cargoes / rating of cargoes.
@ WID_SV_SHIPS
List of scheduled ships button.
@ WID_SV_TRAINS
List of scheduled trains button.
Definition of base types and functions in a cross-platform compatible way.
size_t Utf8StringLength(const char *s)
Get the length of an UTF-8 encoded string in number of characters and thus not the number of bytes th...
Definition: string.cpp:359
Functions related to low-level strings.
void GetStringWithArgs(StringBuilder &builder, StringID string, StringParameters &args, uint case_index, bool game_script)
Get a parsed string with most special stringcodes replaced by the string parameters.
Definition: strings.cpp:243
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
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition: aircraft.h:72
@ AIRPLANES
Can planes land on this airport type?
Definition: airport.h:147
Defines the data structure for an airport.
StringID name
name of this airport
std::vector< AirportTileLayout > layouts
List of layouts composing the airport.
struct GRFFileProps grf_prop
Properties related to the grf file.
bool IsWithinMapBounds(uint8_t table, TileIndex index) const
Check if the airport would be within the map bounds at the given tile.
uint8_t size_y
size of airport in y direction
uint8_t size_x
size of airport in x direction
static const AirportSpec * Get(uint8_t type)
Retrieve airport spec for the given airport.
std::span< const HangarTileTable > depots
Position of the depots on the airports.
bool IsAvailable() const
Check whether this airport is available to build.
uint8_t noise_level
noise that this airport generates
Defines the data structure of each individual tile of an airport.
static const AirportTileSpec * Get(StationGfx gfx)
Retrieve airport tile spec for the given airport tile.
StringID name
Tile Subname string, land information on this tile will give you "AirportName (TileSubname)".
AnimationInfo animation
Information about the animation.
static const AirportTileSpec * GetByTile(TileIndex tile)
Retrieve airport tile spec for the given airport tile.
GRFFileProps grf_prop
properties related the the grf file
TileIndex GetRotatedTileFromOffset(TileIndexDiffC tidc) const
Add the tileoffset to the base tile of this airport but rotate it first.
Definition: station_base.h:336
uint GetHangarNum(TileIndex tile) const
Get the hangar number of the hangar at a specific tile.
Definition: station_base.h:387
Direction rotation
How this airport is rotated.
Definition: station_base.h:296
uint8_t type
Type of this airport,.
Definition: station_base.h:294
PersistentStorage * psa
Persistent storage for NewGRF airports.
Definition: station_base.h:298
uint GetNumHangars() const
Get the number of hangars on this airport.
Definition: station_base.h:394
uint64_t flags
stores which blocks on the airport are taken. was 16 bit earlier on, then 32
Definition: station_base.h:293
TileIndex GetHangarTile(uint hangar_num) const
Get the first tile of the given hangar.
Definition: station_base.h:358
const AirportSpec * GetSpec() const
Get the AirportSpec that from the airport type of this airport.
Definition: station_base.h:305
uint8_t layout
Airport layout number.
Definition: station_base.h:295
uint16_t triggers
The triggers that trigger animation.
uint8_t status
Status; 0: no looping, 1: looping, 0xFF: no animation.
Base class for all station-ish types.
StationFacility facilities
The facilities that this station has.
StringID string_id
Default name (town area) of station.
TileIndex xy
Base tile of the station.
std::vector< SpecMapping< StationSpec > > speclist
List of rail station specs of this station.
uint8_t cached_anim_triggers
NOSAVE: Combined animation trigger bitmask, used to determine if trigger processing should happen.
std::string cached_name
NOSAVE: Cache of the resolved name of the station, if not using a custom name.
TileArea train_station
Tile area the train 'station' part covers.
uint8_t cached_roadstop_anim_triggers
NOSAVE: Combined animation trigger bitmask for road stops, used to determine if trigger processing sh...
Owner owner
The owner of this station.
virtual void UpdateVirtCoord()=0
Update the coordinated of the sign (as shown in the viewport).
uint8_t delete_ctr
Delete counter. If greater than 0 then it is decremented until it reaches 0; the waypoint is then is ...
StationRect rect
NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions.
bool IsInUse() const
Check whether the base station currently is in use; in use means that it is not scheduled for deletio...
Town * town
The town this station is associated with.
virtual bool TileBelongsToRailStation(TileIndex tile) const =0
Check whether a specific tile belongs to this station.
TrackedViewportSign sign
NOSAVE: Dimensions of sign.
static BaseStation * GetByTile(TileIndex tile)
Get the base station belonging to a specific tile.
TimerGameCalendar::Date build_date
Date of construction.
std::string name
Custom name.
VehicleType type
Type of vehicle.
Definition: vehicle_type.h:51
Class for storing amounts of cargo.
Definition: cargo_type.h:114
Container for cargo from the same location and time.
Definition: cargopacket.h:40
Specification of a cargo type.
Definition: cargotype.h:71
CargoClasses classes
Classes of this cargo type.
Definition: cargotype.h:78
CargoID Index() const
Determines index of this cargospec.
Definition: cargotype.h:105
static IterateWrapper Iterate(size_t from=0)
Returns an iterable ensemble of all valid CargoSpec.
Definition: cargotype.h:190
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition: cargotype.h:134
bool value
tells if the bool cheat is active or not
Definition: cheat_type.h:18
Cheat station_rating
Fix station ratings at 100%.
Definition: cheat_type.h:35
GUISettings gui
settings related to the GUI
uint32_t station
Count of company owned station tiles.
Definition: company_base.h:37
std::array< uint32_t, RAILTYPE_END > rail
Count of company owned track bits for each rail type.
Definition: company_base.h:33
uint32_t water
Count of company owned track bits for canals.
Definition: company_base.h:36
CompanyInfrastructure infrastructure
NOSAVE: Counts of company owned infrastructure.
Definition: company_base.h:147
bool build_on_slopes
allow building on slopes
bool road_stop_on_town_road
allow building of drive-through road stops on town owned roads
bool road_stop_on_competitor_road
allow building of drive-through road stops on roads owned by competitors
uint8_t town_council_tolerance
minimum required town ratings to be allowed to demolish stuff
Ground palette sprite of a tile, together with its sprite layout.
Definition: sprite.h:58
const DrawTileSeqStruct * seq
Array of child sprites. Terminated with a terminator entry.
Definition: sprite.h:60
PalSpriteID ground
Palette and sprite for the ground.
Definition: sprite.h:59
bool station_noise_level
build new airports when the town noise level is still within accepted limits
Information about GRF, used in the game and (part of it) in savegames.
const char * GetName() const
Get the name of this grf.
const struct GRFFile * grffile
grf file that introduced this entity
std::array< const struct SpriteGroup *, Tcnt > spritegroup
pointers to the different sprites of the entity
bool show_track_reservation
highlight reserved tracks.
uint8_t landscape
the landscape we're currently in
EconomySettings economy
settings to change the economy
ConstructionSettings construction
construction of things in-game
DifficultySettings difficulty
settings related to the difficulty
GameCreationSettings game_creation
settings used during the creation of a game (map)
StationSettings station
settings related to station management
LinkGraphSettings linkgraph
settings for link graph calculations
OrderSettings order
settings related to orders
Stores station stats for a single cargo.
Definition: station_base.h:166
FlowStatMap flows
Planned flows through this station.
Definition: station_base.h:211
uint max_waiting_cargo
Max cargo from this station waiting at any station.
Definition: station_base.h:213
bool HasRating() const
Does this cargo have a rating at this station?
Definition: station_base.h:258
@ GES_ACCEPTANCE
Set when the station accepts the cargo currently for final deliveries.
Definition: station_base.h:173
@ GES_LAST_MONTH
Set when cargo was delivered for final delivery last month.
Definition: station_base.h:195
@ GES_RATING
This indicates whether a cargo has a rating at the station.
Definition: station_base.h:183
@ GES_CURRENT_MONTH
Set when cargo was delivered for final delivery this month.
Definition: station_base.h:201
@ GES_ACCEPTED_BIGTICK
Set when cargo was delivered for final delivery during the current STATION_ACCEPTANCE_TICKS interval.
Definition: station_base.h:207
uint8_t last_speed
Maximum speed (up to 255) of the last vehicle that tried to load this cargo.
Definition: station_base.h:237
uint8_t last_age
Age in years (up to 255) of the last vehicle that tried to load this cargo.
Definition: station_base.h:243
uint8_t time_since_pickup
Number of rating-intervals (up to 255) since the last vehicle tried to load this cargo.
Definition: station_base.h:224
NodeID node
ID of node in link graph referring to this goods entry.
Definition: station_base.h:214
StationCargoList cargo
The cargo packets of cargo waiting in this station.
Definition: station_base.h:210
uint8_t amount_fract
Fractional part of the amount in the cargo list.
Definition: station_base.h:245
LinkGraphID link_graph
Link graph this station belongs to.
Definition: station_base.h:215
bool HasVehicleEverTriedLoading() const
Reports whether a vehicle has ever tried to load the cargo at this station.
Definition: station_base.h:252
uint8_t rating
Station rating for this cargo.
Definition: station_base.h:226
uint8_t status
Status of this cargo, see GoodsEntryStatus.
Definition: station_base.h:217
StationID GetVia(StationID source) const
Get the best next hop for a cargo packet from station source.
Definition: station_base.h:268
Defines the data structure for constructing industry.
Definition: industrytype.h:101
StringID name
Displayed name of the industry.
Definition: industrytype.h:121
GRFFileProps grf_prop
properties related to the grf file
Definition: industrytype.h:132
StringID station_name
Default name for nearby station.
Definition: industrytype.h:126
IndustryLifeType life_type
This is also known as Industry production flag, in newgrf specs.
Definition: industrytype.h:117
bool enabled
entity still available (by default true).newgrf can disable it, though
Definition: industrytype.h:131
Defines the internal data of a functional industry.
Definition: industry.h:66
IndustryType type
type of industry.
Definition: industry.h:102
static Industry * GetByTile(TileIndex tile)
Get the industry of the given tile.
Definition: industry.h:238
ProducedCargoes produced
produced cargo slots
Definition: industry.h:97
Owner owner
owner of the industry. Which SHOULD always be (imho) OWNER_NONE
Definition: industry.h:103
TileArea location
Location of the industry.
Definition: industry.h:94
Station * neutral_station
Associated neutral station.
Definition: industry.h:96
StationList stations_near
NOSAVE: List of nearby stations.
Definition: industry.h:110
An edge in the link graph.
Definition: linkgraph.h:42
static uint SizeY()
Get the size of the map along the Y.
Definition: map_func.h:279
static debug_inline uint SizeX()
Get the size of the map along the X.
Definition: map_func.h:270
static debug_inline uint Size()
Get the size of the map.
Definition: map_func.h:288
Tindex class_index
Class index of this spec, invalid until class is allocated.
Definition: newgrf_class.h:18
NewGRF supplied spritelayout.
uint32_t PrepareLayout(uint32_t orig_offset, uint32_t newgrf_ground_offset, uint32_t newgrf_offset, uint constr_stage, bool separate_ground) const
Prepares a sprite layout before resolving action-1-2-3 chains.
void ProcessRegisters(uint8_t resolved_var10, uint32_t resolved_sprite, bool separate_ground) const
Evaluates the register modifiers and integrates them into the preprocessed sprite layout.
bool NeedsPreprocessing() const
Tests whether this spritelayout needs preprocessing by PrepareLayout() and ProcessRegisters(),...
const DrawTileSeqStruct * GetLayout(PalSpriteID *ground) const
Returns the result spritelayout after preprocessing.
static void Reset(TileIndex tile=INVALID_TILE, bool from_gui=true)
Reset the OrderBackups from GUI/game logic.
Shared order list linking together the linked list of orders and the list of vehicles sharing this or...
Definition: order_base.h:259
bool selectgoods
only send the goods to station if a train has been there
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition: order_base.h:70
Order * next
Pointer to next order. If nullptr, end of list.
Definition: order_base.h:59
bool ShouldStopAtStation(const Vehicle *v, StationID station) const
Check whether the given vehicle should stop at the given station based on this order and the non-stop...
Definition: order_cmd.cpp:2225
Represents the covered area of e.g.
Definition: tilearea_type.h:18
uint16_t w
The width of the area.
Definition: tilearea_type.h:20
void Add(TileIndex to_add)
Add a single tile to a tile area; enlarge if needed.
Definition: tilearea.cpp:43
void Clear()
Clears the 'tile area', i.e.
Definition: tilearea_type.h:40
TileIndex tile
The base tile of the area.
Definition: tilearea_type.h:19
uint16_t h
The height of the area.
Definition: tilearea_type.h:21
OrthogonalTileArea & Expand(int rad)
Expand a tile area by rad tiles in each direction, keeping within map bounds.
Definition: tilearea.cpp:123
SpriteID sprite
The 'real' sprite.
Definition: gfx_type.h:24
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition: gfx_type.h:25
Coordinates of a point in 2D.
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 size_t GetNumItems()
Returns number of valid items in the pool.
Definition: pool_type.hpp:369
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 Titem * GetIfValid(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:350
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition: pool_type.hpp:388
Road stop resolver.
Road stop specification.
Money GetBuildCost(Price category) const
Get the cost for building a road stop of this type.
GRFFilePropsBase< NUM_CARGO+3 > grf_prop
Properties related the the grf file.
Money GetClearCost(Price category) const
Get the cost for clearing a road stop of this type.
A Stop for a Road Vehicle.
Definition: roadstop_base.h:22
RoadStop * next
Next stop of the given type at this station.
Definition: roadstop_base.h:70
bool Enter(RoadVehicle *rv)
Enter the road stop.
Definition: roadstop.cpp:231
static RoadStop * GetByTile(TileIndex tile, RoadStopType type)
Find a roadstop at given tile.
Definition: roadstop.cpp:264
void MakeDriveThrough()
Join this road stop to another 'base' road stop if possible; fill all necessary data to become an act...
Definition: roadstop.cpp:62
void ClearDriveThrough()
Prepare for removal of this stop; update other neighbouring stops if needed.
Definition: roadstop.cpp:129
Buses, trucks and trams belong to this class.
Definition: roadveh.h:98
uint8_t state
Definition: roadveh.h:100
Iterable ensemble of each set bit in a value.
All ships have this type.
Definition: ship.h:32
static Station * GetIfValid(size_t index)
Returns station if the index is a valid index for this station type.
static Pool::IterateWrapper< Station > Iterate(size_t from=0)
Returns an iterable ensemble of all valid stations of type T.
static bool IsExpected(const BaseStation *st)
Helper for checking whether the given station is of this type.
static Station * Get(size_t index)
Gets station with given index.
static Station * GetByTile(TileIndex tile)
Get the station belonging to a specific tile.
static bool IsValidID(size_t index)
Tests whether given index is a valid index for station of this type.
static Station * From(BaseStation *st)
Converts a BaseStation to SpecializedStation with type checking.
T * Last()
Get the last vehicle in the chain.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
static Pool::IterateWrapper< Aircraft > Iterate(size_t from=0)
Returns an iterable ensemble of all valid vehicles of type T.
virtual const SpriteGroup * Resolve([[maybe_unused]] ResolverObject &object) const
Base sprite group resolver.
Information to handle station action 0 property 24 correctly.
std::bitset< NUM_INDUSTRYTYPES > indtypes
Bit set indicating when an industry type has been found.
uint32_t free_names
Current bitset of free names (we can remove names).
StationRect - used to track station spread out rectangle - cheaper than scanning whole map.
uint8_t station_spread
amount a station may spread
bool serve_neutral_industries
company stations can serve industries with attached neutral stations
bool distant_join_stations
allow to join non-adjacent stations
Station specification.
uint8_t callback_mask
Bitmask of station callbacks that have to be called.
uint8_t disallowed_lengths
Bitmask of platform lengths available for the station.
StringID name
Name of this station.
uint8_t disallowed_platforms
Bitmask of number of platforms available for the station.
uint8_t flags
Bitmask of flags, bit 0: use different sprite set; bit 1: divide cargo about by station size.
std::unordered_map< uint16_t, std::vector< uint8_t > > layouts
Custom platform layouts, keyed by platform and length combined.
@ NoWires
Tile should NOT contain catenary wires.
@ Pylons
Tile should contain catenary pylons.
@ Blocked
Tile is blocked to vehicles.
std::vector< TileFlags > tileflags
List of tile flags.
GRFFilePropsBase< NUM_CARGO+3 > grf_prop
Properties related the the grf file.
std::vector< NewGRFSpriteLayout > renderdata
Number of tile layouts.
Station data structure.
Definition: station_base.h:439
RoadStop * bus_stops
All the road stops.
Definition: station_base.h:448
TileArea ship_station
Tile area the ship 'station' part covers.
Definition: station_base.h:454
IndustryType indtype
Industry type to get the name from.
Definition: station_base.h:457
TileArea docking_station
Tile area the docking tiles cover.
Definition: station_base.h:455
CargoTypes always_accepted
Bitmask of always accepted cargo types (by houses, HQs, industry tiles when industry doesn't accept c...
Definition: station_base.h:469
GoodsEntry goods[NUM_CARGO]
Goods at this station.
Definition: station_base.h:468
void GetTileArea(TileArea *ta, StationType type) const override
Get the tile area for a given station type.
Industry * industry
NOSAVE: Associated industry for neutral stations. (Rebuilt on load from Industry->st)
Definition: station_base.h:472
void MoveSign(TileIndex new_xy) override
Move the station main coordinate somewhere else.
TileArea bus_station
Tile area the bus 'station' part covers.
Definition: station_base.h:449
BitmapTileArea catchment_tiles
NOSAVE: Set of individual tiles covered by catchment area.
Definition: station_base.h:459
void RecomputeCatchment(bool no_clear_nearby_lists=false)
Recompute tiles covered in our catchment area.
Definition: station.cpp:462
void AfterStationTileSetChange(bool adding, StationType type)
After adding/removing tiles to station, update some station-related stuff.
Airport airport
Tile area the airport covers.
Definition: station_base.h:453
void UpdateVirtCoord() override
Update the virtual coords needed to draw the station sign.
TileArea truck_station
Tile area the truck 'station' part covers.
Definition: station_base.h:451
RoadStop * truck_stops
All the truck stops.
Definition: station_base.h:450
void AddFacility(StationFacility new_facility_bit, TileIndex facil_xy)
Called when new facility is built on the station.
Definition: station.cpp:226
Tile description for the 'land area information' tool.
Definition: tile_cmd.h:52
uint16_t rail_speed
Speed limit of rail (bridges and track)
Definition: tile_cmd.h:65
StringID station_name
Type of station within the class.
Definition: tile_cmd.h:59
StringID str
Description of the tile.
Definition: tile_cmd.h:53
TimerGameCalendar::Date build_date
Date of construction of tile contents.
Definition: tile_cmd.h:57
StringID airport_class
Name of the airport class.
Definition: tile_cmd.h:60
StringID airport_name
Name of the airport.
Definition: tile_cmd.h:61
uint16_t tram_speed
Speed limit of tram (bridges and track)
Definition: tile_cmd.h:69
StringID roadtype
Type of road on the tile.
Definition: tile_cmd.h:66
StringID tramtype
Type of tram on the tile.
Definition: tile_cmd.h:68
StringID railtype
Type of rail on the tile.
Definition: tile_cmd.h:64
uint16_t road_speed
Speed limit of road (bridges and track)
Definition: tile_cmd.h:67
const char * grf
newGRF used for the tile contents
Definition: tile_cmd.h:63
StringID airport_tile_name
Name of the airport tile.
Definition: tile_cmd.h:62
Owner owner[4]
Name of the owner(s)
Definition: tile_cmd.h:55
StringID owner_type[4]
Type of each owner.
Definition: tile_cmd.h:56
StringID station_class
Class of station.
Definition: tile_cmd.h:58
A pair-construct of a TileIndexDiff.
Definition: map_type.h:31
Tile information, used while rendering the tile.
Definition: tile_cmd.h:43
int z
Height.
Definition: tile_cmd.h:48
int x
X position of the tile in unit coordinates.
Definition: tile_cmd.h:44
Slope tileh
Slope of the tile.
Definition: tile_cmd.h:46
TileIndex tile
Tile index.
Definition: tile_cmd.h:47
int y
Y position of the tile in unit coordinates.
Definition: tile_cmd.h:45
Action 2 sprite layout for houses, industry tiles, objects and airport tiles.
Set of callback functions for performing tile operations of a given tile type.
Definition: tile_cmd.h:158
Town data structure.
Definition: town.h:54
CompanyMask statues
which companies have a statue?
Definition: town.h:70
TileIndex xy
town center tile
Definition: town.h:55
uint16_t noise_reached
level of noise that all the airports are generating
Definition: town.h:68
uint16_t MaxTownNoise() const
Calculate the max town noise.
Definition: town.h:125
CompanyID exclusivity
which company has exclusivity
Definition: town.h:75
uint8_t exclusive_counter
months till the exclusivity expires
Definition: town.h:76
void UpdatePosition(int center, int top, StringID str, StringID str_small=STR_NULL)
Update the position of the viewport sign.
Definition: viewport_type.h:60
bool kdtree_valid
Are the sign data valid for use with the _viewport_sign_kdtree?
Definition: viewport_type.h:52
'Train' is either a loco or a wagon.
Definition: train.h:89
Trackdir GetVehicleTrackdir() const override
Get the tracks of the train vehicle.
Definition: train_cmd.cpp:4220
Vehicle data structure.
Definition: vehicle_base.h:244
Direction direction
facing
Definition: vehicle_base.h:307
bool IsStoppedInDepot() const
Check whether the vehicle is in the depot and stopped.
Definition: vehicle_base.h:560
VehicleCargoList cargo
The cargo this vehicle is carrying.
Definition: vehicle_base.h:341
TimerGameEconomy::Date date_of_last_service
Last economy date the vehicle had a service at a depot.
Definition: vehicle_base.h:295
virtual TileIndex GetOrderStationLocation([[maybe_unused]] StationID station)
Determine the location for the station where the vehicle goes to next.
Definition: vehicle_base.h:796
Vehicle * Next() const
Get the next vehicle of this vehicle.
Definition: vehicle_base.h:632
debug_inline bool IsFrontEngine() const
Check if the vehicle is a front engine.
Definition: vehicle_base.h:945
Order current_order
The current order (+ status, like: loading)
Definition: vehicle_base.h:356
CargoID cargo_type
type of cargo this vehicle is carrying
Definition: vehicle_base.h:342
uint16_t refit_cap
Capacity left over from before last refit.
Definition: vehicle_base.h:345
uint8_t vehstatus
Status.
Definition: vehicle_base.h:354
uint16_t cur_speed
current speed
Definition: vehicle_base.h:328
Vehicle * NextShared() const
Get the next vehicle of the shared vehicle chain.
Definition: vehicle_base.h:714
TileIndex tile
Current tile index.
Definition: vehicle_base.h:264
TileIndex dest_tile
Heading for this tile.
Definition: vehicle_base.h:271
Owner owner
Which company owns the vehicle?
Definition: vehicle_base.h:309
Representation of a waypoint.
Definition: waypoint_base.h:23
TileArea road_waypoint_area
Tile area the road waypoint part covers.
Definition: waypoint_base.h:26
uint16_t waypoint_flags
Waypoint flags, see WaypointFlags.
Definition: waypoint_base.h:25
void UpdateVirtCoord() override
Update the virtual coords needed to draw the waypoint sign.
VehicleEnterTileStatus
The returned bits of VehicleEnterTile.
Definition: tile_cmd.h:21
@ VETSB_CANNOT_ENTER
The vehicle cannot enter the tile.
Definition: tile_cmd.h:38
@ VETS_STATION_ID_OFFSET
Shift the VehicleEnterTileStatus this many bits to the right to get the station ID when VETS_ENTERED_...
Definition: tile_cmd.h:31
@ VETSB_ENTERED_STATION
The vehicle entered a station.
Definition: tile_cmd.h:36
@ VETSB_CONTINUE
Bit sets of the above specified bits.
Definition: tile_cmd.h:35
bool IsTileFlat(TileIndex tile, int *h)
Check if a given tile is flat.
Definition: tile_map.cpp:95
std::tuple< Slope, int > GetTileSlopeZ(TileIndex tile)
Return the slope of a given tile inside the map.
Definition: tile_map.cpp:55
int GetTileMaxZ(TileIndex t)
Get top height of the tile inside the map.
Definition: tile_map.cpp:136
int GetTileZ(TileIndex tile)
Get bottom height of the tile.
Definition: tile_map.cpp:116
bool IsTileOwner(Tile tile, Owner owner)
Checks if a tile belongs to the given owner.
Definition: tile_map.h:214
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition: tile_map.h:178
void SetTileOwner(Tile tile, Owner owner)
Sets the owner of a tile.
Definition: tile_map.h:198
int GetTileMaxPixelZ(TileIndex tile)
Get top height of the tile.
Definition: tile_map.h:312
uint8_t GetAnimationFrame(Tile t)
Get the current animation frame.
Definition: tile_map.h:250
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition: tile_map.h:161
TropicZone GetTropicZone(Tile tile)
Get the tropic zone.
Definition: tile_map.h:238
void SetAnimationFrame(Tile t, uint8_t frame)
Set a new animation frame.
Definition: tile_map.h:262
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition: tile_map.h:150
Slope GetTileSlope(TileIndex tile)
Return the slope of a given tile inside the map.
Definition: tile_map.h:279
@ TROPICZONE_DESERT
Tile is desert.
Definition: tile_type.h:78
static const uint TILE_HEIGHT
Height of a height level in world coordinate AND in pixels in #ZOOM_BASE.
Definition: tile_type.h:18
static const uint TILE_SIZE
Tile size in world coordinates.
Definition: tile_type.h:15
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:95
@ MP_TREES
Tile got trees.
Definition: tile_type.h:52
@ MP_ROAD
A tile with road (or tram tracks)
Definition: tile_type.h:50
@ MP_STATION
A tile of a station.
Definition: tile_type.h:53
@ MP_HOUSE
A house by a town.
Definition: tile_type.h:51
@ MP_WATER
Water tile.
Definition: tile_type.h:54
@ MP_INDUSTRY
Part of an industry.
Definition: tile_type.h:56
OrthogonalTileArea TileArea
Shorthand for the much more common orthogonal tile area.
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.
Definition of the game-economy-timer.
Definition of the tick-based game-timer.
Base of the town class.
HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile)
Returns the bit corresponding to the town zone of the specified tile.
Definition: town_cmd.cpp:2447
Town * CalcClosestTownFromTile(TileIndex tile, uint threshold=UINT_MAX)
Return the town closest to the given tile within threshold.
Definition: town_cmd.cpp:3852
CommandCost CheckIfAuthorityAllowsNewStation(TileIndex tile, DoCommandFlag flags)
Checks whether the local authority allows construction of a new station (rail, road,...
Definition: town_cmd.cpp:3828
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold.
Definition: town_cmd.cpp:3870
TrackBits TrackToTrackBits(Track track)
Maps a Track to the corresponding TrackBits value.
Definition: track_func.h:77
TrackdirBits TrackBitsToTrackdirBits(TrackBits bits)
Converts TrackBits to TrackdirBits while allowing both directions.
Definition: track_func.h:319
bool IsReversingRoadTrackdir(Trackdir dir)
Checks whether the trackdir means that we are reversing.
Definition: track_func.h:673
Trackdir ReverseTrackdir(Trackdir trackdir)
Maps a trackdir to the reverse trackdir.
Definition: track_func.h:247
TrackStatus CombineTrackStatus(TrackdirBits trackdirbits, TrackdirBits red_signals)
Builds a TrackStatus.
Definition: track_func.h:388
TrackBits AxisToTrackBits(Axis a)
Maps an Axis to the corresponding TrackBits value.
Definition: track_func.h:88
TrackBits DiagDirToDiagTrackBits(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal track bits incidating with that diagdir.
Definition: track_func.h:524
Track AxisToTrack(Axis a)
Convert an Axis to the corresponding Track AXIS_X -> TRACK_X AXIS_Y -> TRACK_Y Uses the fact that the...
Definition: track_func.h:66
Track RemoveFirstTrack(TrackBits *tracks)
Removes first Track from TrackBits and returns it.
Definition: track_func.h:131
DiagDirection TrackdirToExitdir(Trackdir trackdir)
Maps a trackdir to the (4-way) direction the tile is exited when following that trackdir.
Definition: track_func.h:439
TrackBits
Allow incrementing of Track variables.
Definition: track_type.h:35
@ TRACK_BIT_UPPER
Upper track.
Definition: track_type.h:39
@ TRACK_BIT_LEFT
Left track.
Definition: track_type.h:41
@ TRACK_BIT_Y
Y-axis track.
Definition: track_type.h:38
@ TRACK_BIT_NONE
No track.
Definition: track_type.h:36
@ TRACK_BIT_X
X-axis track.
Definition: track_type.h:37
@ TRACK_BIT_ALL
All possible tracks.
Definition: track_type.h:50
@ TRACK_BIT_RIGHT
Right track.
Definition: track_type.h:42
Trackdir
Enumeration for tracks and directions.
Definition: track_type.h:67
@ TRACKDIR_BIT_NONE
No track build.
Definition: track_type.h:99
Track
These are used to specify a single track.
Definition: track_type.h:19
@ TRACK_Y
Track along the y-axis (north-west to south-east)
Definition: track_type.h:22
@ TRACK_X
Track along the x-axis (north-east to south-west)
Definition: track_type.h:21
Base for the train class.
bool TryPathReserve(Train *v, bool mark_as_stuck=false, bool first_tile_okay=false)
Try to reserve a path to a safe position.
Definition: train_cmd.cpp:2866
void FreeTrainTrackReservation(const Train *v)
Free the reserved path in front of a vehicle.
Definition: train_cmd.cpp:2386
int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length)
Get the stop location of (the center) of the front vehicle of a train at a platform of a station.
Definition: train_cmd.cpp:263
@ TO_BUILDINGS
company buildings - depots, stations, HQ, ...
Definition: transparency.h:27
TransportType
Available types of transport.
@ TRANSPORT_RAIL
Transport by train.
@ TRANSPORT_ROAD
Transport by road vehicle.
@ TRANSPORT_WATER
Transport over water.
Functions that have tunnels and bridges in common.
CommandCost EnsureNoVehicleOnGround(TileIndex tile)
Ensure there is no vehicle at the ground at the given position.
Definition: vehicle.cpp:546
void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
Find a vehicle from a specific location.
Definition: vehicle.cpp:505
@ VS_TRAIN_SLOWING
Train is slowing down.
Definition: vehicle_base.h:37
Functions related to vehicles.
@ VEH_INVALID
Non-existing type of vehicle.
Definition: vehicle_type.h:35
@ VEH_ROAD
Road vehicle type.
Definition: vehicle_type.h:25
@ VEH_AIRCRAFT
Aircraft vehicle type.
Definition: vehicle_type.h:27
@ VEH_SHIP
Ship vehicle type.
Definition: vehicle_type.h:26
@ VEH_TRAIN
Train vehicle type.
Definition: vehicle_type.h:24
Functions and type for generating vehicle lists.
void FindVehiclesWithOrder(VehiclePredicate veh_pred, OrderPredicate ord_pred, VehicleFunc veh_func)
Find vehicles matching an order.
void OffsetGroundSprite(int x, int y)
Called when a foundation has been drawn for the current tile.
Definition: viewport.cpp:599
void StartSpriteCombine()
Starts a block of sprites, which are "combined" into a single bounding box.
Definition: viewport.cpp:767
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub)
Draw a (transparent) sprite at given coordinates with a given bounding box.
Definition: viewport.cpp:671
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition: viewport.cpp:777
void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
Draws a ground sprite for the current tile.
Definition: viewport.cpp:587
Functions related to (drawing on) viewports.
Functions related to water (management)
void TileLoop_Water(TileIndex tile)
Let a water tile floods its diagonal adjoining tiles called from tunnelbridge_cmd,...
Definition: water_cmd.cpp:1245
void CheckForDockingTile(TileIndex t)
Mark the supplied tile as a docking tile if it is suitable for docking.
Definition: water_cmd.cpp:195
bool HasTileWaterGround(Tile t)
Checks whether the tile has water at the ground.
Definition: water_map.h:350
bool IsTileOnWater(Tile t)
Tests if the tile was built on water.
Definition: water_map.h:136
WaterClass
classes of water (for WATER_TILE_CLEAR water tile type).
Definition: water_map.h:39
@ WATER_CLASS_SEA
Sea.
Definition: water_map.h:40
@ WATER_CLASS_CANAL
Canal.
Definition: water_map.h:41
@ WATER_CLASS_INVALID
Used for industry tiles on land (also for oilrig if newgrf says so).
Definition: water_map.h:43
bool HasTileWaterClass(Tile t)
Checks whether the tile has an waterclass associated.
Definition: water_map.h:101
WaterClass GetWaterClass(Tile t)
Get the water class at a tile.
Definition: water_map.h:112
bool IsDockingTile(Tile t)
Checks whether the tile is marked as a dockling tile.
Definition: water_map.h:371
void SetDockingTile(Tile t, bool b)
Set the docking tile state of a tile.
Definition: water_map.h:361
bool IsWater(Tile t)
Is it a plain water tile?
Definition: water_map.h:147
bool IsWaterTile(Tile t)
Is it a water tile with plain water?
Definition: water_map.h:190
Base of waypoints.
@ WPF_ROAD
This is a road waypoint.
Definition: waypoint_base.h:19
CommandCost RemoveBuoy(TileIndex tile, DoCommandFlag flags)
Remove a buoy.
Command definitions related to waypoints.
Functions related to waypoints.
void ShowWaypointWindow(const Waypoint *wp)
Show the window for the given waypoint.
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition: window.cpp:1140
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition: window.cpp:3119
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
void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, WidgetID widget_index)
Mark a particular widget in a particular window as dirty (in need of repainting)
Definition: window.cpp:3106
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition: window.cpp:3093
void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
Mark window data of all windows of a given class as invalid (in need of re-computing) Note that by de...
Definition: window.cpp:3228
@ WC_STATION_LIST
Station list; Window numbers:
Definition: window_type.h:302
@ WC_VEHICLE_ORDERS
Vehicle orders; Window numbers:
Definition: window_type.h:212
@ WC_VEHICLE_DEPOT
Depot view; Window numbers:
Definition: window_type.h:351
@ WC_SELECT_STATION
Select station (when joining stations); Window numbers:
Definition: window_type.h:242
@ WC_STATION_VIEW
Station view; Window numbers:
Definition: window_type.h:345
@ WC_TOWN_VIEW
Town view; Window numbers:
Definition: window_type.h:333
Entry point for OpenTTD to YAPF's cache.
void YapfNotifyTrackLayoutChange(TileIndex tile, Track track)
Use this function to notify YAPF that track layout (or signal configuration) has change.
Definition: yapf_rail.cpp:635