OpenTTD Source  1.10.0-RC1
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 "cmd_helper.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_func.h"
32 #include "clear_func.h"
33 #include "date_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_kdtree.h"
40 #include "roadstop_base.h"
41 #include "newgrf_railtype.h"
42 #include "newgrf_roadtype.h"
43 #include "waypoint_base.h"
44 #include "waypoint_func.h"
45 #include "pbs.h"
46 #include "debug.h"
47 #include "core/random_func.hpp"
48 #include "company_base.h"
49 #include "table/airporttile_ids.h"
50 #include "newgrf_airporttiles.h"
51 #include "order_backup.h"
52 #include "newgrf_house.h"
53 #include "company_gui.h"
55 #include "linkgraph/refresh.h"
56 #include "widgets/station_widget.h"
57 #include "tunnelbridge_map.h"
58 
59 #include "table/strings.h"
60 
61 #include "safeguards.h"
62 
68 /* static */ const FlowStat::SharesMap FlowStat::empty_sharesmap;
69 
77 {
78  assert(IsTileType(t, MP_STATION));
79 
80  /* If the tile isn't an airport there's no chance it's a hangar. */
81  if (!IsAirport(t)) return false;
82 
83  const Station *st = Station::GetByTile(t);
84  const AirportSpec *as = st->airport.GetSpec();
85 
86  for (uint i = 0; i < as->nof_depots; i++) {
87  if (st->airport.GetHangarTile(i) == t) return true;
88  }
89 
90  return false;
91 }
92 
101 template <class T>
102 CommandCost GetStationAround(TileArea ta, StationID closest_station, CompanyID company, T **st)
103 {
104  ta.Expand(1);
105 
106  /* check around to see if there are any stations there owned by the company */
107  TILE_AREA_LOOP(tile_cur, ta) {
108  if (IsTileType(tile_cur, MP_STATION)) {
109  StationID t = GetStationIndex(tile_cur);
110  if (!T::IsValidID(t) || Station::Get(t)->owner != company) continue;
111  if (closest_station == INVALID_STATION) {
112  closest_station = t;
113  } else if (closest_station != t) {
114  return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
115  }
116  }
117  }
118  *st = (closest_station == INVALID_STATION) ? nullptr : T::Get(closest_station);
119  return CommandCost();
120 }
121 
127 typedef bool (*CMSAMatcher)(TileIndex tile);
128 
136 {
137  int num = 0;
138 
139  for (int dx = -3; dx <= 3; dx++) {
140  for (int dy = -3; dy <= 3; dy++) {
141  TileIndex t = TileAddWrap(tile, dx, dy);
142  if (t != INVALID_TILE && cmp(t)) num++;
143  }
144  }
145 
146  return num;
147 }
148 
154 static bool CMSAMine(TileIndex tile)
155 {
156  /* No industry */
157  if (!IsTileType(tile, MP_INDUSTRY)) return false;
158 
159  const Industry *ind = Industry::GetByTile(tile);
160 
161  /* No extractive industry */
162  if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_EXTRACTIVE) == 0) return false;
163 
164  for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
165  /* The industry extracts something non-liquid, i.e. no oil or plastic, so it is a mine.
166  * Also the production of passengers and mail is ignored. */
167  if (ind->produced_cargo[i] != CT_INVALID &&
169  return true;
170  }
171  }
172 
173  return false;
174 }
175 
181 static bool CMSAWater(TileIndex tile)
182 {
183  return IsTileType(tile, MP_WATER) && IsWater(tile);
184 }
185 
191 static bool CMSATree(TileIndex tile)
192 {
193  return IsTileType(tile, MP_TREES);
194 }
195 
196 #define M(x) ((x) - STR_SV_STNAME)
197 
198 enum StationNaming {
199  STATIONNAMING_RAIL,
200  STATIONNAMING_ROAD,
201  STATIONNAMING_AIRPORT,
202  STATIONNAMING_OILRIG,
203  STATIONNAMING_DOCK,
204  STATIONNAMING_HELIPORT,
205 };
206 
209  uint32 free_names;
210  bool *indtypes;
211 };
212 
221 static bool FindNearIndustryName(TileIndex tile, void *user_data)
222 {
223  /* All already found industry types */
225  if (!IsTileType(tile, MP_INDUSTRY)) return false;
226 
227  /* If the station name is undefined it means that it doesn't name a station */
228  IndustryType indtype = GetIndustryType(tile);
229  if (GetIndustrySpec(indtype)->station_name == STR_UNDEFINED) return false;
230 
231  /* In all cases if an industry that provides a name is found two of
232  * the standard names will be disabled. */
233  sni->free_names &= ~(1 << M(STR_SV_STNAME_OILFIELD) | 1 << M(STR_SV_STNAME_MINES));
234  return !sni->indtypes[indtype];
235 }
236 
237 static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming name_class)
238 {
239  static const uint32 _gen_station_name_bits[] = {
240  0, // STATIONNAMING_RAIL
241  0, // STATIONNAMING_ROAD
242  1U << M(STR_SV_STNAME_AIRPORT), // STATIONNAMING_AIRPORT
243  1U << M(STR_SV_STNAME_OILFIELD), // STATIONNAMING_OILRIG
244  1U << M(STR_SV_STNAME_DOCKS), // STATIONNAMING_DOCK
245  1U << M(STR_SV_STNAME_HELIPORT), // STATIONNAMING_HELIPORT
246  };
247 
248  const Town *t = st->town;
249  uint32 free_names = UINT32_MAX;
250 
252  memset(indtypes, 0, sizeof(indtypes));
253 
254  for (const Station *s : Station::Iterate()) {
255  if (s != st && s->town == t) {
256  if (s->indtype != IT_INVALID) {
257  indtypes[s->indtype] = true;
258  StringID name = GetIndustrySpec(s->indtype)->station_name;
259  if (name != STR_UNDEFINED) {
260  /* Filter for other industrytypes with the same name */
261  for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
262  const IndustrySpec *indsp = GetIndustrySpec(it);
263  if (indsp->enabled && indsp->station_name == name) indtypes[it] = true;
264  }
265  }
266  continue;
267  }
268  uint str = M(s->string_id);
269  if (str <= 0x20) {
270  if (str == M(STR_SV_STNAME_FOREST)) {
271  str = M(STR_SV_STNAME_WOODS);
272  }
273  ClrBit(free_names, str);
274  }
275  }
276  }
277 
278  TileIndex indtile = tile;
279  StationNameInformation sni = { free_names, indtypes };
280  if (CircularTileSearch(&indtile, 7, FindNearIndustryName, &sni)) {
281  /* An industry has been found nearby */
282  IndustryType indtype = GetIndustryType(indtile);
283  const IndustrySpec *indsp = GetIndustrySpec(indtype);
284  /* STR_NULL means it only disables oil rig/mines */
285  if (indsp->station_name != STR_NULL) {
286  st->indtype = indtype;
287  return STR_SV_STNAME_FALLBACK;
288  }
289  }
290 
291  /* Oil rigs/mines name could be marked not free by looking for a near by industry. */
292  free_names = sni.free_names;
293 
294  /* check default names */
295  uint32 tmp = free_names & _gen_station_name_bits[name_class];
296  if (tmp != 0) return STR_SV_STNAME + FindFirstBit(tmp);
297 
298  /* check mine? */
299  if (HasBit(free_names, M(STR_SV_STNAME_MINES))) {
300  if (CountMapSquareAround(tile, CMSAMine) >= 2) {
301  return STR_SV_STNAME_MINES;
302  }
303  }
304 
305  /* check close enough to town to get central as name? */
306  if (DistanceMax(tile, t->xy) < 8) {
307  if (HasBit(free_names, M(STR_SV_STNAME))) return STR_SV_STNAME;
308 
309  if (HasBit(free_names, M(STR_SV_STNAME_CENTRAL))) return STR_SV_STNAME_CENTRAL;
310  }
311 
312  /* Check lakeside */
313  if (HasBit(free_names, M(STR_SV_STNAME_LAKESIDE)) &&
314  DistanceFromEdge(tile) < 20 &&
315  CountMapSquareAround(tile, CMSAWater) >= 5) {
316  return STR_SV_STNAME_LAKESIDE;
317  }
318 
319  /* Check woods */
320  if (HasBit(free_names, M(STR_SV_STNAME_WOODS)) && (
321  CountMapSquareAround(tile, CMSATree) >= 8 ||
323  ) {
324  return _settings_game.game_creation.landscape == LT_TROPIC ? STR_SV_STNAME_FOREST : STR_SV_STNAME_WOODS;
325  }
326 
327  /* check elevation compared to town */
328  int z = GetTileZ(tile);
329  int z2 = GetTileZ(t->xy);
330  if (z < z2) {
331  if (HasBit(free_names, M(STR_SV_STNAME_VALLEY))) return STR_SV_STNAME_VALLEY;
332  } else if (z > z2) {
333  if (HasBit(free_names, M(STR_SV_STNAME_HEIGHTS))) return STR_SV_STNAME_HEIGHTS;
334  }
335 
336  /* check direction compared to town */
337  static const int8 _direction_and_table[] = {
338  ~( (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_EAST)) | (1 << M(STR_SV_STNAME_NORTH)) ),
339  ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_NORTH)) ),
340  ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_EAST)) | (1 << M(STR_SV_STNAME_NORTH)) ),
341  ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_EAST)) ),
342  };
343 
344  free_names &= _direction_and_table[
345  (TileX(tile) < TileX(t->xy)) +
346  (TileY(tile) < TileY(t->xy)) * 2];
347 
348  tmp = free_names & ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 6) | (1 << 7) | (1 << 12) | (1 << 26) | (1 << 27) | (1 << 28) | (1 << 29) | (1 << 30));
349  return (tmp == 0) ? STR_SV_STNAME_FALLBACK : (STR_SV_STNAME + FindFirstBit(tmp));
350 }
351 #undef M
352 
359 {
360  uint threshold = 8;
361 
362  Station *best_station = nullptr;
363  ForAllStationsRadius(tile, threshold, [&](Station *st) {
364  if (!st->IsInUse() && st->owner == _current_company) {
365  uint cur_dist = DistanceManhattan(tile, st->xy);
366 
367  if (cur_dist < threshold) {
368  threshold = cur_dist;
369  best_station = st;
370  } else if (cur_dist == threshold && best_station != nullptr) {
371  /* In case of a tie, lowest station ID wins */
372  if (st->index < best_station->index) best_station = st;
373  }
374  }
375  });
376 
377  return best_station;
378 }
379 
380 
382 {
383  switch (type) {
384  case STATION_RAIL:
385  *ta = this->train_station;
386  return;
387 
388  case STATION_AIRPORT:
389  *ta = this->airport;
390  return;
391 
392  case STATION_TRUCK:
393  *ta = this->truck_station;
394  return;
395 
396  case STATION_BUS:
397  *ta = this->bus_station;
398  return;
399 
400  case STATION_DOCK:
401  case STATION_OILRIG:
402  *ta = this->docking_station;
403  break;
404 
405  default: NOT_REACHED();
406  }
407 
408  ta->w = 1;
409  ta->h = 1;
410 }
411 
416 {
417  Point pt = RemapCoords2(TileX(this->xy) * TILE_SIZE, TileY(this->xy) * TILE_SIZE);
418 
419  pt.y -= 32 * ZOOM_LVL_BASE;
420  if ((this->facilities & FACIL_AIRPORT) && this->airport.type == AT_OILRIG) pt.y -= 16 * ZOOM_LVL_BASE;
421 
422  if (this->sign.kdtree_valid) _viewport_sign_kdtree.Remove(ViewportSignKdtreeItem::MakeStation(this->index));
423 
424  SetDParam(0, this->index);
425  SetDParam(1, this->facilities);
426  this->sign.UpdatePosition(pt.x, pt.y, STR_VIEWPORT_STATION);
427 
428  _viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeStation(this->index));
429 
430  SetWindowDirty(WC_STATION_VIEW, this->index);
431 }
432 
438 {
439  if (this->xy == new_xy) return;
440 
441  _station_kdtree.Remove(this->index);
442 
443  this->BaseStation::MoveSign(new_xy);
444 
445  _station_kdtree.Insert(this->index);
446 }
447 
450 {
451  for (BaseStation *st : BaseStation::Iterate()) {
452  st->UpdateVirtCoord();
453  }
454 }
455 
456 void BaseStation::FillCachedName() const
457 {
459  int64 args_array[] = { this->index };
460  StringParameters tmp_params(args_array);
461  char *end = GetStringWithArgs(buf, Waypoint::IsExpected(this) ? STR_WAYPOINT_NAME : STR_STATION_NAME, &tmp_params, lastof(buf));
462  this->cached_name.assign(buf, end);
463 }
464 
465 void ClearAllStationCachedNames()
466 {
467  for (BaseStation *st : BaseStation::Iterate()) {
468  st->cached_name.clear();
469  }
470 }
471 
477 static CargoTypes GetAcceptanceMask(const Station *st)
478 {
479  CargoTypes mask = 0;
480 
481  for (CargoID i = 0; i < NUM_CARGO; i++) {
482  if (HasBit(st->goods[i].status, GoodsEntry::GES_ACCEPTANCE)) SetBit(mask, i);
483  }
484  return mask;
485 }
486 
491 static void ShowRejectOrAcceptNews(const Station *st, uint num_items, CargoID *cargo, StringID msg)
492 {
493  for (uint i = 0; i < num_items; i++) {
494  SetDParam(i + 1, CargoSpec::Get(cargo[i])->name);
495  }
496 
497  SetDParam(0, st->index);
499 }
500 
508 CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad)
509 {
510  CargoArray produced;
511  std::set<IndustryID> industries;
512  TileArea ta = TileArea(tile, w, h).Expand(rad);
513 
514  /* Loop over all tiles to get the produced cargo of
515  * everything except industries */
516  TILE_AREA_LOOP(tile, ta) {
517  if (IsTileType(tile, MP_INDUSTRY)) industries.insert(GetIndustryIndex(tile));
518  AddProducedCargo(tile, produced);
519  }
520 
521  /* Loop over the seen industries. They produce cargo for
522  * anything that is within 'rad' of any one of their tiles.
523  */
524  for (IndustryID industry : industries) {
525  const Industry *i = Industry::Get(industry);
526  /* Skip industry with neutral station */
527  if (i->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) continue;
528 
529  for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
530  CargoID cargo = i->produced_cargo[j];
531  if (cargo != CT_INVALID) produced[cargo]++;
532  }
533  }
534 
535  return produced;
536 }
537 
547 CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, CargoTypes *always_accepted)
548 {
549  CargoArray acceptance;
550  if (always_accepted != nullptr) *always_accepted = 0;
551 
552  TileArea ta = TileArea(tile, w, h).Expand(rad);
553 
554  TILE_AREA_LOOP(tile, ta) {
555  /* Ignore industry if it has a neutral station. */
556  if (!_settings_game.station.serve_neutral_industries && IsTileType(tile, MP_INDUSTRY) && Industry::GetByTile(tile)->neutral_station != nullptr) continue;
557 
558  AddAcceptedCargo(tile, acceptance, always_accepted);
559  }
560 
561  return acceptance;
562 }
563 
569 static CargoArray GetAcceptanceAroundStation(const Station *st, CargoTypes *always_accepted)
570 {
571  CargoArray acceptance;
572  if (always_accepted != nullptr) *always_accepted = 0;
573 
575  for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
576  AddAcceptedCargo(tile, acceptance, always_accepted);
577  }
578 
579  return acceptance;
580 }
581 
587 void UpdateStationAcceptance(Station *st, bool show_msg)
588 {
589  /* old accepted goods types */
590  CargoTypes old_acc = GetAcceptanceMask(st);
591 
592  /* And retrieve the acceptance. */
593  CargoArray acceptance;
594  if (!st->rect.IsEmpty()) {
595  acceptance = GetAcceptanceAroundStation(st, &st->always_accepted);
596  }
597 
598  /* Adjust in case our station only accepts fewer kinds of goods */
599  for (CargoID i = 0; i < NUM_CARGO; i++) {
600  uint amt = acceptance[i];
601 
602  /* Make sure the station can accept the goods type. */
603  bool is_passengers = IsCargoInClass(i, CC_PASSENGERS);
604  if ((!is_passengers && !(st->facilities & ~FACIL_BUS_STOP)) ||
605  (is_passengers && !(st->facilities & ~FACIL_TRUCK_STOP))) {
606  amt = 0;
607  }
608 
609  GoodsEntry &ge = st->goods[i];
610  SB(ge.status, GoodsEntry::GES_ACCEPTANCE, 1, amt >= 8);
612  (*LinkGraph::Get(ge.link_graph))[ge.node].SetDemand(amt / 8);
613  }
614  }
615 
616  /* Only show a message in case the acceptance was actually changed. */
617  CargoTypes new_acc = GetAcceptanceMask(st);
618  if (old_acc == new_acc) return;
619 
620  /* show a message to report that the acceptance was changed? */
621  if (show_msg && st->owner == _local_company && st->IsInUse()) {
622  /* List of accept and reject strings for different number of
623  * cargo types */
624  static const StringID accept_msg[] = {
625  STR_NEWS_STATION_NOW_ACCEPTS_CARGO,
626  STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO,
627  };
628  static const StringID reject_msg[] = {
629  STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO,
630  STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO,
631  };
632 
633  /* Array of accepted and rejected cargo types */
634  CargoID accepts[2] = { CT_INVALID, CT_INVALID };
635  CargoID rejects[2] = { CT_INVALID, CT_INVALID };
636  uint num_acc = 0;
637  uint num_rej = 0;
638 
639  /* Test each cargo type to see if its acceptance has changed */
640  for (CargoID i = 0; i < NUM_CARGO; i++) {
641  if (HasBit(new_acc, i)) {
642  if (!HasBit(old_acc, i) && num_acc < lengthof(accepts)) {
643  /* New cargo is accepted */
644  accepts[num_acc++] = i;
645  }
646  } else {
647  if (HasBit(old_acc, i) && num_rej < lengthof(rejects)) {
648  /* Old cargo is no longer accepted */
649  rejects[num_rej++] = i;
650  }
651  }
652  }
653 
654  /* Show news message if there are any changes */
655  if (num_acc > 0) ShowRejectOrAcceptNews(st, num_acc, accepts, accept_msg[num_acc - 1]);
656  if (num_rej > 0) ShowRejectOrAcceptNews(st, num_rej, rejects, reject_msg[num_rej - 1]);
657  }
658 
659  /* redraw the station view since acceptance changed */
661 }
662 
663 static void UpdateStationSignCoord(BaseStation *st)
664 {
665  const StationRect *r = &st->rect;
666 
667  if (r->IsEmpty()) return; // no tiles belong to this station
668 
669  /* clamp sign coord to be inside the station rect */
670  TileIndex new_xy = TileXY(ClampU(TileX(st->xy), r->left, r->right), ClampU(TileY(st->xy), r->top, r->bottom));
671  st->MoveSign(new_xy);
672 
673  if (!Station::IsExpected(st)) return;
674  Station *full_station = Station::From(st);
675  for (CargoID c = 0; c < NUM_CARGO; ++c) {
676  LinkGraphID lg = full_station->goods[c].link_graph;
677  if (!LinkGraph::IsValidID(lg)) continue;
678  (*LinkGraph::Get(lg))[full_station->goods[c].node].UpdateLocation(st->xy);
679  }
680 }
681 
691 static CommandCost BuildStationPart(Station **st, DoCommandFlag flags, bool reuse, TileArea area, StationNaming name_class)
692 {
693  /* Find a deleted station close to us */
694  if (*st == nullptr && reuse) *st = GetClosestDeletedStation(area.tile);
695 
696  if (*st != nullptr) {
697  if ((*st)->owner != _current_company) {
699  }
700 
701  CommandCost ret = (*st)->rect.BeforeAddRect(area.tile, area.w, area.h, StationRect::ADD_TEST);
702  if (ret.Failed()) return ret;
703  } else {
704  /* allocate and initialize new station */
705  if (!Station::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);
706 
707  if (flags & DC_EXEC) {
708  *st = new Station(area.tile);
709  _station_kdtree.Insert((*st)->index);
710 
711  (*st)->town = ClosestTownFromTile(area.tile, UINT_MAX);
712  (*st)->string_id = GenerateStationName(*st, area.tile, name_class);
713 
715  SetBit((*st)->town->have_ratings, _current_company);
716  }
717  }
718  }
719  return CommandCost();
720 }
721 
729 {
730  if (!st->IsInUse()) {
731  st->delete_ctr = 0;
733  }
734  /* station remains but it probably lost some parts - station sign should stay in the station boundaries */
735  UpdateStationSignCoord(st);
736 }
737 
744 {
745  this->UpdateVirtCoord();
746  this->RecomputeCatchment();
748  if (adding) InvalidateWindowData(WC_STATION_LIST, this->owner, 0);
749 
750  switch (type) {
751  case STATION_RAIL:
753  break;
754  case STATION_AIRPORT:
755  break;
756  case STATION_TRUCK:
757  case STATION_BUS:
759  break;
760  case STATION_DOCK:
762  break;
763  default: NOT_REACHED();
764  }
765 
766  if (adding) {
767  UpdateStationAcceptance(this, false);
769  } else {
770  DeleteStationIfEmpty(this);
771  }
772 
773 }
774 
776 
786 CommandCost CheckBuildableTile(TileIndex tile, uint invalid_dirs, int &allowed_z, bool allow_steep, bool check_bridge = true)
787 {
788  if (check_bridge && IsBridgeAbove(tile)) {
789  return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
790  }
791 
793  if (ret.Failed()) return ret;
794 
795  int z;
796  Slope tileh = GetTileSlope(tile, &z);
797 
798  /* Prohibit building if
799  * 1) The tile is "steep" (i.e. stretches two height levels).
800  * 2) The tile is non-flat and the build_on_slopes switch is disabled.
801  */
802  if ((!allow_steep && IsSteepSlope(tileh)) ||
804  return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
805  }
806 
808  int flat_z = z + GetSlopeMaxZ(tileh);
809  if (tileh != SLOPE_FLAT) {
810  /* Forbid building if the tile faces a slope in a invalid direction. */
811  for (DiagDirection dir = DIAGDIR_BEGIN; dir != DIAGDIR_END; dir++) {
812  if (HasBit(invalid_dirs, dir) && !CanBuildDepotByTileh(dir, tileh)) {
813  return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
814  }
815  }
816  cost.AddCost(_price[PR_BUILD_FOUNDATION]);
817  }
818 
819  /* The level of this tile must be equal to allowed_z. */
820  if (allowed_z < 0) {
821  /* First tile. */
822  allowed_z = flat_z;
823  } else if (allowed_z != flat_z) {
824  return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
825  }
826 
827  return cost;
828 }
829 
837 {
839  int allowed_z = -1;
840 
841  for (; tile_iter != INVALID_TILE; ++tile_iter) {
842  CommandCost ret = CheckBuildableTile(tile_iter, 0, allowed_z, true);
843  if (ret.Failed()) return ret;
844  cost.AddCost(ret);
845 
846  ret = DoCommand(tile_iter, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
847  if (ret.Failed()) return ret;
848  cost.AddCost(ret);
849  }
850 
851  return cost;
852 }
853 
868 static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag flags, Axis axis, StationID *station, RailType rt, std::vector<Train *> &affected_vehicles, StationClassID spec_class, byte spec_index, byte plat_len, byte numtracks)
869 {
871  int allowed_z = -1;
872  uint invalid_dirs = 5 << axis;
873 
874  const StationSpec *statspec = StationClass::Get(spec_class)->GetSpec(spec_index);
875  bool slope_cb = statspec != nullptr && HasBit(statspec->callback_mask, CBM_STATION_SLOPE_CHECK);
876 
877  TILE_AREA_LOOP(tile_cur, tile_area) {
878  CommandCost ret = CheckBuildableTile(tile_cur, invalid_dirs, allowed_z, false);
879  if (ret.Failed()) return ret;
880  cost.AddCost(ret);
881 
882  if (slope_cb) {
883  /* Do slope check if requested. */
884  ret = PerformStationTileSlopeCheck(tile_area.tile, tile_cur, statspec, axis, plat_len, numtracks);
885  if (ret.Failed()) return ret;
886  }
887 
888  /* if station is set, then we have special handling to allow building on top of already existing stations.
889  * so station points to INVALID_STATION if we can build on any station.
890  * Or it points to a station if we're only allowed to build on exactly that station. */
891  if (station != nullptr && IsTileType(tile_cur, MP_STATION)) {
892  if (!IsRailStation(tile_cur)) {
893  return ClearTile_Station(tile_cur, DC_AUTO); // get error message
894  } else {
895  StationID st = GetStationIndex(tile_cur);
896  if (*station == INVALID_STATION) {
897  *station = st;
898  } else if (*station != st) {
899  return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
900  }
901  }
902  } else {
903  /* Rail type is only valid when building a railway station; if station to
904  * build isn't a rail station it's INVALID_RAILTYPE. */
905  if (rt != INVALID_RAILTYPE &&
906  IsPlainRailTile(tile_cur) && !HasSignals(tile_cur) &&
907  HasPowerOnRail(GetRailType(tile_cur), rt)) {
908  /* Allow overbuilding if the tile:
909  * - has rail, but no signals
910  * - it has exactly one track
911  * - the track is in line with the station
912  * - the current rail type has power on the to-be-built type (e.g. convert normal rail to el rail)
913  */
914  TrackBits tracks = GetTrackBits(tile_cur);
915  Track track = RemoveFirstTrack(&tracks);
916  Track expected_track = HasBit(invalid_dirs, DIAGDIR_NE) ? TRACK_X : TRACK_Y;
917 
918  if (tracks == TRACK_BIT_NONE && track == expected_track) {
919  /* Check for trains having a reservation for this tile. */
920  if (HasBit(GetRailReservationTrackBits(tile_cur), track)) {
921  Train *v = GetTrainForReservation(tile_cur, track);
922  if (v != nullptr) {
923  affected_vehicles.push_back(v);
924  }
925  }
926  CommandCost ret = DoCommand(tile_cur, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
927  if (ret.Failed()) return ret;
928  cost.AddCost(ret);
929  /* With flags & ~DC_EXEC CmdLandscapeClear would fail since the rail still exists */
930  continue;
931  }
932  }
933  ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
934  if (ret.Failed()) return ret;
935  cost.AddCost(ret);
936  }
937  }
938 
939  return cost;
940 }
941 
954 static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, bool is_truck_stop, Axis axis, StationID *station, RoadType rt)
955 {
957  int allowed_z = -1;
958 
959  TILE_AREA_LOOP(cur_tile, tile_area) {
960  CommandCost ret = CheckBuildableTile(cur_tile, invalid_dirs, allowed_z, !is_drive_through);
961  if (ret.Failed()) return ret;
962  cost.AddCost(ret);
963 
964  /* If station is set, then we have special handling to allow building on top of already existing stations.
965  * Station points to INVALID_STATION if we can build on any station.
966  * Or it points to a station if we're only allowed to build on exactly that station. */
967  if (station != nullptr && IsTileType(cur_tile, MP_STATION)) {
968  if (!IsRoadStop(cur_tile)) {
969  return ClearTile_Station(cur_tile, DC_AUTO); // Get error message.
970  } else {
971  if (is_truck_stop != IsTruckStop(cur_tile) ||
972  is_drive_through != IsDriveThroughStopTile(cur_tile)) {
973  return ClearTile_Station(cur_tile, DC_AUTO); // Get error message.
974  }
975  /* Drive-through station in the wrong direction. */
976  if (is_drive_through && IsDriveThroughStopTile(cur_tile) && DiagDirToAxis(GetRoadStopDir(cur_tile)) != axis){
977  return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION);
978  }
979  StationID st = GetStationIndex(cur_tile);
980  if (*station == INVALID_STATION) {
981  *station = st;
982  } else if (*station != st) {
983  return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
984  }
985  }
986  } else {
987  bool build_over_road = is_drive_through && IsNormalRoadTile(cur_tile);
988  /* Road bits in the wrong direction. */
989  RoadBits rb = IsNormalRoadTile(cur_tile) ? GetAllRoadBits(cur_tile) : ROAD_NONE;
990  if (build_over_road && (rb & (axis == AXIS_X ? ROAD_Y : ROAD_X)) != 0) {
991  /* Someone was pedantic and *NEEDED* three fracking different error messages. */
992  switch (CountBits(rb)) {
993  case 1:
994  return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION);
995 
996  case 2:
997  if (rb == ROAD_X || rb == ROAD_Y) return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION);
998  return_cmd_error(STR_ERROR_DRIVE_THROUGH_CORNER);
999 
1000  default: // 3 or 4
1001  return_cmd_error(STR_ERROR_DRIVE_THROUGH_JUNCTION);
1002  }
1003  }
1004 
1005  if (build_over_road) {
1006  /* There is a road, check if we can build road+tram stop over it. */
1007  RoadType road_rt = GetRoadType(cur_tile, RTT_ROAD);
1008  if (road_rt != INVALID_ROADTYPE) {
1009  Owner road_owner = GetRoadOwner(cur_tile, RTT_ROAD);
1010  if (road_owner == OWNER_TOWN) {
1011  if (!_settings_game.construction.road_stop_on_town_road) return_cmd_error(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD);
1012  } else if (!_settings_game.construction.road_stop_on_competitor_road && road_owner != OWNER_NONE) {
1013  CommandCost ret = CheckOwnership(road_owner);
1014  if (ret.Failed()) return ret;
1015  }
1016  uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_ROAD));
1017 
1018  if (RoadTypeIsRoad(rt) && !HasPowerOnRoad(rt, road_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD);
1019 
1020  if (GetDisallowedRoadDirections(cur_tile) != DRD_NONE && road_owner != OWNER_TOWN) {
1021  CommandCost ret = CheckOwnership(road_owner);
1022  if (ret.Failed()) return ret;
1023  }
1024 
1025  cost.AddCost(RoadBuildCost(road_rt) * (2 - num_pieces));
1026  } else if (RoadTypeIsRoad(rt)) {
1027  cost.AddCost(RoadBuildCost(rt) * 2);
1028  }
1029 
1030  /* There is a tram, check if we can build road+tram stop over it. */
1031  RoadType tram_rt = GetRoadType(cur_tile, RTT_TRAM);
1032  if (tram_rt != INVALID_ROADTYPE) {
1033  Owner tram_owner = GetRoadOwner(cur_tile, RTT_TRAM);
1034  if (Company::IsValidID(tram_owner) &&
1036  /* Disallow breaking end-of-line of someone else
1037  * so trams can still reverse on this tile. */
1038  HasExactlyOneBit(GetRoadBits(cur_tile, RTT_TRAM)))) {
1039  CommandCost ret = CheckOwnership(tram_owner);
1040  if (ret.Failed()) return ret;
1041  }
1042  uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_TRAM));
1043 
1044  if (RoadTypeIsTram(rt) && !HasPowerOnRoad(rt, tram_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD);
1045 
1046  cost.AddCost(RoadBuildCost(tram_rt) * (2 - num_pieces));
1047  } else if (RoadTypeIsTram(rt)) {
1048  cost.AddCost(RoadBuildCost(rt) * 2);
1049  }
1050  } else {
1051  ret = DoCommand(cur_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
1052  if (ret.Failed()) return ret;
1053  cost.AddCost(ret);
1054  cost.AddCost(RoadBuildCost(rt) * 2);
1055  }
1056  }
1057  }
1058 
1059  return cost;
1060 }
1061 
1070 {
1071  TileArea cur_ta = st->train_station;
1072 
1073  /* determine new size of train station region.. */
1074  int x = min(TileX(cur_ta.tile), TileX(new_ta.tile));
1075  int y = min(TileY(cur_ta.tile), TileY(new_ta.tile));
1076  new_ta.w = max(TileX(cur_ta.tile) + cur_ta.w, TileX(new_ta.tile) + new_ta.w) - x;
1077  new_ta.h = max(TileY(cur_ta.tile) + cur_ta.h, TileY(new_ta.tile) + new_ta.h) - y;
1078  new_ta.tile = TileXY(x, y);
1079 
1080  /* make sure the final size is not too big. */
1082  return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
1083  }
1084 
1085  return CommandCost();
1086 }
1087 
1088 static inline byte *CreateSingle(byte *layout, int n)
1089 {
1090  int i = n;
1091  do *layout++ = 0; while (--i);
1092  layout[((n - 1) >> 1) - n] = 2;
1093  return layout;
1094 }
1095 
1096 static inline byte *CreateMulti(byte *layout, int n, byte b)
1097 {
1098  int i = n;
1099  do *layout++ = b; while (--i);
1100  if (n > 4) {
1101  layout[0 - n] = 0;
1102  layout[n - 1 - n] = 0;
1103  }
1104  return layout;
1105 }
1106 
1114 void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec)
1115 {
1116  if (statspec != nullptr && statspec->lengths >= plat_len &&
1117  statspec->platforms[plat_len - 1] >= numtracks &&
1118  statspec->layouts[plat_len - 1][numtracks - 1]) {
1119  /* Custom layout defined, follow it. */
1120  memcpy(layout, statspec->layouts[plat_len - 1][numtracks - 1],
1121  plat_len * numtracks);
1122  return;
1123  }
1124 
1125  if (plat_len == 1) {
1126  CreateSingle(layout, numtracks);
1127  } else {
1128  if (numtracks & 1) layout = CreateSingle(layout, plat_len);
1129  numtracks >>= 1;
1130 
1131  while (--numtracks >= 0) {
1132  layout = CreateMulti(layout, plat_len, 4);
1133  layout = CreateMulti(layout, plat_len, 6);
1134  }
1135  }
1136 }
1137 
1149 template <class T, StringID error_message>
1150 CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st)
1151 {
1152  assert(*st == nullptr);
1153  bool check_surrounding = true;
1154 
1156  if (existing_station != INVALID_STATION) {
1157  if (adjacent && existing_station != station_to_join) {
1158  /* You can't build an adjacent station over the top of one that
1159  * already exists. */
1160  return_cmd_error(error_message);
1161  } else {
1162  /* Extend the current station, and don't check whether it will
1163  * be near any other stations. */
1164  *st = T::GetIfValid(existing_station);
1165  check_surrounding = (*st == nullptr);
1166  }
1167  } else {
1168  /* There's no station here. Don't check the tiles surrounding this
1169  * one if the company wanted to build an adjacent station. */
1170  if (adjacent) check_surrounding = false;
1171  }
1172  }
1173 
1174  if (check_surrounding) {
1175  /* Make sure there is no more than one other station around us that is owned by us. */
1176  CommandCost ret = GetStationAround(ta, existing_station, _current_company, st);
1177  if (ret.Failed()) return ret;
1178  }
1179 
1180  /* Distant join */
1181  if (*st == nullptr && station_to_join != INVALID_STATION) *st = T::GetIfValid(station_to_join);
1182 
1183  return CommandCost();
1184 }
1185 
1195 static CommandCost FindJoiningStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
1196 {
1197  return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST>(existing_station, station_to_join, adjacent, ta, st);
1198 }
1199 
1209 CommandCost FindJoiningWaypoint(StationID existing_waypoint, StationID waypoint_to_join, bool adjacent, TileArea ta, Waypoint **wp)
1210 {
1211  return FindJoiningBaseStation<Waypoint, STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST>(existing_waypoint, waypoint_to_join, adjacent, ta, wp);
1212 }
1213 
1219 {
1222  v = v->Last();
1224 }
1225 
1231 {
1233  TryPathReserve(v, true, true);
1234  v = v->Last();
1236 }
1237 
1255 CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1256 {
1257  /* Unpack parameters */
1258  RailType rt = Extract<RailType, 0, 6>(p1);
1259  Axis axis = Extract<Axis, 6, 1>(p1);
1260  byte numtracks = GB(p1, 8, 8);
1261  byte plat_len = GB(p1, 16, 8);
1262  bool adjacent = HasBit(p1, 24);
1263 
1264  StationClassID spec_class = Extract<StationClassID, 0, 8>(p2);
1265  byte spec_index = GB(p2, 8, 8);
1266  StationID station_to_join = GB(p2, 16, 16);
1267 
1268  /* Does the authority allow this? */
1269  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile_org, flags);
1270  if (ret.Failed()) return ret;
1271 
1272  if (!ValParamRailtype(rt)) return CMD_ERROR;
1273 
1274  /* Check if the given station class is valid */
1275  if ((uint)spec_class >= StationClass::GetClassCount() || spec_class == STAT_CLASS_WAYP) return CMD_ERROR;
1276  if (spec_index >= StationClass::Get(spec_class)->GetSpecCount()) return CMD_ERROR;
1277  if (plat_len == 0 || numtracks == 0) return CMD_ERROR;
1278 
1279  int w_org, h_org;
1280  if (axis == AXIS_X) {
1281  w_org = plat_len;
1282  h_org = numtracks;
1283  } else {
1284  h_org = plat_len;
1285  w_org = numtracks;
1286  }
1287 
1288  bool reuse = (station_to_join != NEW_STATION);
1289  if (!reuse) station_to_join = INVALID_STATION;
1290  bool distant_join = (station_to_join != INVALID_STATION);
1291 
1292  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
1293 
1295 
1296  /* these values are those that will be stored in train_tile and station_platforms */
1297  TileArea new_location(tile_org, w_org, h_org);
1298 
1299  /* Make sure the area below consists of clear tiles. (OR tiles belonging to a certain rail station) */
1300  StationID est = INVALID_STATION;
1301  std::vector<Train *> affected_vehicles;
1302  /* Clear the land below the station. */
1303  CommandCost cost = CheckFlatLandRailStation(new_location, flags, axis, &est, rt, affected_vehicles, spec_class, spec_index, plat_len, numtracks);
1304  if (cost.Failed()) return cost;
1305  /* Add construction expenses. */
1306  cost.AddCost((numtracks * _price[PR_BUILD_STATION_RAIL] + _price[PR_BUILD_STATION_RAIL_LENGTH]) * plat_len);
1307  cost.AddCost(numtracks * plat_len * RailBuildCost(rt));
1308 
1309  Station *st = nullptr;
1310  ret = FindJoiningStation(est, station_to_join, adjacent, new_location, &st);
1311  if (ret.Failed()) return ret;
1312 
1313  ret = BuildStationPart(&st, flags, reuse, new_location, STATIONNAMING_RAIL);
1314  if (ret.Failed()) return ret;
1315 
1316  if (st != nullptr && st->train_station.tile != INVALID_TILE) {
1317  CommandCost ret = CanExpandRailStation(st, new_location, axis);
1318  if (ret.Failed()) return ret;
1319  }
1320 
1321  /* Check if we can allocate a custom stationspec to this station */
1322  const StationSpec *statspec = StationClass::Get(spec_class)->GetSpec(spec_index);
1323  int specindex = AllocateSpecToStation(statspec, st, (flags & DC_EXEC) != 0);
1324  if (specindex == -1) return_cmd_error(STR_ERROR_TOO_MANY_STATION_SPECS);
1325 
1326  if (statspec != nullptr) {
1327  /* Perform NewStation checks */
1328 
1329  /* Check if the station size is permitted */
1330  if (HasBit(statspec->disallowed_platforms, min(numtracks - 1, 7)) || HasBit(statspec->disallowed_lengths, min(plat_len - 1, 7))) {
1331  return CMD_ERROR;
1332  }
1333 
1334  /* Check if the station is buildable */
1335  if (HasBit(statspec->callback_mask, CBM_STATION_AVAIL)) {
1336  uint16 cb_res = GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, nullptr, INVALID_TILE);
1337  if (cb_res != CALLBACK_FAILED && !Convert8bitBooleanCallback(statspec->grf_prop.grffile, CBID_STATION_AVAILABILITY, cb_res)) return CMD_ERROR;
1338  }
1339  }
1340 
1341  if (flags & DC_EXEC) {
1342  TileIndexDiff tile_delta;
1343  byte *layout_ptr;
1344  byte numtracks_orig;
1345  Track track;
1346 
1347  st->train_station = new_location;
1348  st->AddFacility(FACIL_TRAIN, new_location.tile);
1349 
1350  st->rect.BeforeAddRect(tile_org, w_org, h_org, StationRect::ADD_TRY);
1351 
1352  if (statspec != nullptr) {
1353  /* Include this station spec's animation trigger bitmask
1354  * in the station's cached copy. */
1355  st->cached_anim_triggers |= statspec->animation.triggers;
1356  }
1357 
1358  tile_delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
1359  track = AxisToTrack(axis);
1360 
1361  layout_ptr = AllocaM(byte, numtracks * plat_len);
1362  GetStationLayout(layout_ptr, numtracks, plat_len, statspec);
1363 
1364  numtracks_orig = numtracks;
1365 
1366  Company *c = Company::Get(st->owner);
1367  TileIndex tile_track = tile_org;
1368  do {
1369  TileIndex tile = tile_track;
1370  int w = plat_len;
1371  do {
1372  byte layout = *layout_ptr++;
1373  if (IsRailStationTile(tile) && HasStationReservation(tile)) {
1374  /* Check for trains having a reservation for this tile. */
1376  if (v != nullptr) {
1377  affected_vehicles.push_back(v);
1379  }
1380  }
1381 
1382  /* Railtype can change when overbuilding. */
1383  if (IsRailStationTile(tile)) {
1384  if (!IsStationTileBlocked(tile)) c->infrastructure.rail[GetRailType(tile)]--;
1385  c->infrastructure.station--;
1386  }
1387 
1388  /* Remove animation if overbuilding */
1389  DeleteAnimatedTile(tile);
1390  byte old_specindex = HasStationTileRail(tile) ? GetCustomStationSpecIndex(tile) : 0;
1391  MakeRailStation(tile, st->owner, st->index, axis, layout & ~1, rt);
1392  /* Free the spec if we overbuild something */
1393  DeallocateSpecFromStation(st, old_specindex);
1394 
1395  SetCustomStationSpecIndex(tile, specindex);
1396  SetStationTileRandomBits(tile, GB(Random(), 0, 4));
1397  SetAnimationFrame(tile, 0);
1398 
1399  if (!IsStationTileBlocked(tile)) c->infrastructure.rail[rt]++;
1400  c->infrastructure.station++;
1401 
1402  if (statspec != nullptr) {
1403  /* Use a fixed axis for GetPlatformInfo as our platforms / numtracks are always the right way around */
1404  uint32 platinfo = GetPlatformInfo(AXIS_X, GetStationGfx(tile), plat_len, numtracks_orig, plat_len - w, numtracks_orig - numtracks, false);
1405 
1406  /* As the station is not yet completely finished, the station does not yet exist. */
1407  uint16 callback = GetStationCallback(CBID_STATION_TILE_LAYOUT, platinfo, 0, statspec, nullptr, tile);
1408  if (callback != CALLBACK_FAILED) {
1409  if (callback < 8) {
1410  SetStationGfx(tile, (callback & ~1) + axis);
1411  } else {
1413  }
1414  }
1415 
1416  /* Trigger station animation -- after building? */
1417  TriggerStationAnimation(st, tile, SAT_BUILT);
1418  }
1419 
1420  tile += tile_delta;
1421  } while (--w);
1422  AddTrackToSignalBuffer(tile_track, track, _current_company);
1423  YapfNotifyTrackLayoutChange(tile_track, track);
1424  tile_track += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta
1425  } while (--numtracks);
1426 
1427  for (uint i = 0; i < affected_vehicles.size(); ++i) {
1428  /* Restore reservations of trains. */
1429  RestoreTrainReservation(affected_vehicles[i]);
1430  }
1431 
1432  /* Check whether we need to expand the reservation of trains already on the station. */
1433  TileArea update_reservation_area;
1434  if (axis == AXIS_X) {
1435  update_reservation_area = TileArea(tile_org, 1, numtracks_orig);
1436  } else {
1437  update_reservation_area = TileArea(tile_org, numtracks_orig, 1);
1438  }
1439 
1440  TILE_AREA_LOOP(tile, update_reservation_area) {
1441  /* Don't even try to make eye candy parts reserved. */
1442  if (IsStationTileBlocked(tile)) continue;
1443 
1444  DiagDirection dir = AxisToDiagDir(axis);
1445  TileIndexDiff tile_offset = TileOffsByDiagDir(dir);
1446  TileIndex platform_begin = tile;
1447  TileIndex platform_end = tile;
1448 
1449  /* We can only account for tiles that are reachable from this tile, so ignore primarily blocked tiles while finding the platform begin and end. */
1450  for (TileIndex next_tile = platform_begin - tile_offset; IsCompatibleTrainStationTile(next_tile, platform_begin); next_tile -= tile_offset) {
1451  platform_begin = next_tile;
1452  }
1453  for (TileIndex next_tile = platform_end + tile_offset; IsCompatibleTrainStationTile(next_tile, platform_end); next_tile += tile_offset) {
1454  platform_end = next_tile;
1455  }
1456 
1457  /* If there is at least on reservation on the platform, we reserve the whole platform. */
1458  bool reservation = false;
1459  for (TileIndex t = platform_begin; !reservation && t <= platform_end; t += tile_offset) {
1460  reservation = HasStationReservation(t);
1461  }
1462 
1463  if (reservation) {
1464  SetRailStationPlatformReservation(platform_begin, dir, true);
1465  }
1466  }
1467 
1468  st->MarkTilesDirty(false);
1469  st->AfterStationTileSetChange(true, STATION_RAIL);
1470  }
1471 
1472  return cost;
1473 }
1474 
1475 static TileArea MakeStationAreaSmaller(BaseStation *st, TileArea ta, bool (*func)(BaseStation *, TileIndex))
1476 {
1477 restart:
1478 
1479  /* too small? */
1480  if (ta.w != 0 && ta.h != 0) {
1481  /* check the left side, x = constant, y changes */
1482  for (uint i = 0; !func(st, ta.tile + TileDiffXY(0, i));) {
1483  /* the left side is unused? */
1484  if (++i == ta.h) {
1485  ta.tile += TileDiffXY(1, 0);
1486  ta.w--;
1487  goto restart;
1488  }
1489  }
1490 
1491  /* check the right side, x = constant, y changes */
1492  for (uint i = 0; !func(st, ta.tile + TileDiffXY(ta.w - 1, i));) {
1493  /* the right side is unused? */
1494  if (++i == ta.h) {
1495  ta.w--;
1496  goto restart;
1497  }
1498  }
1499 
1500  /* check the upper side, y = constant, x changes */
1501  for (uint i = 0; !func(st, ta.tile + TileDiffXY(i, 0));) {
1502  /* the left side is unused? */
1503  if (++i == ta.w) {
1504  ta.tile += TileDiffXY(0, 1);
1505  ta.h--;
1506  goto restart;
1507  }
1508  }
1509 
1510  /* check the lower side, y = constant, x changes */
1511  for (uint i = 0; !func(st, ta.tile + TileDiffXY(i, ta.h - 1));) {
1512  /* the left side is unused? */
1513  if (++i == ta.w) {
1514  ta.h--;
1515  goto restart;
1516  }
1517  }
1518  } else {
1519  ta.Clear();
1520  }
1521 
1522  return ta;
1523 }
1524 
1525 static bool TileBelongsToRailStation(BaseStation *st, TileIndex tile)
1526 {
1527  return st->TileBelongsToRailStation(tile);
1528 }
1529 
1530 static void MakeRailStationAreaSmaller(BaseStation *st)
1531 {
1532  st->train_station = MakeStationAreaSmaller(st, st->train_station, TileBelongsToRailStation);
1533 }
1534 
1535 static bool TileBelongsToShipStation(BaseStation *st, TileIndex tile)
1536 {
1537  return IsDockTile(tile) && GetStationIndex(tile) == st->index;
1538 }
1539 
1540 static void MakeShipStationAreaSmaller(Station *st)
1541 {
1542  st->ship_station = MakeStationAreaSmaller(st, st->ship_station, TileBelongsToShipStation);
1543  UpdateStationDockingTiles(st);
1544 }
1545 
1556 template <class T>
1557 CommandCost RemoveFromRailBaseStation(TileArea ta, std::vector<T *> &affected_stations, DoCommandFlag flags, Money removal_cost, bool keep_rail)
1558 {
1559  /* Count of the number of tiles removed */
1560  int quantity = 0;
1561  CommandCost total_cost(EXPENSES_CONSTRUCTION);
1562  /* Accumulator for the errors seen during clearing. If no errors happen,
1563  * and the quantity is 0 there is no station. Otherwise it will be one
1564  * of the other error that got accumulated. */
1566 
1567  /* Do the action for every tile into the area */
1568  TILE_AREA_LOOP(tile, ta) {
1569  /* Make sure the specified tile is a rail station */
1570  if (!HasStationTileRail(tile)) continue;
1571 
1572  /* If there is a vehicle on ground, do not allow to remove (flood) the tile */
1574  error.AddCost(ret);
1575  if (ret.Failed()) continue;
1576 
1577  /* Check ownership of station */
1578  T *st = T::GetByTile(tile);
1579  if (st == nullptr) continue;
1580 
1581  if (_current_company != OWNER_WATER) {
1582  CommandCost ret = CheckOwnership(st->owner);
1583  error.AddCost(ret);
1584  if (ret.Failed()) continue;
1585  }
1586 
1587  /* If we reached here, the tile is valid so increase the quantity of tiles we will remove */
1588  quantity++;
1589 
1590  if (keep_rail || IsStationTileBlocked(tile)) {
1591  /* Don't refund the 'steel' of the track when we keep the
1592  * rail, or when the tile didn't have any rail at all. */
1593  total_cost.AddCost(-_price[PR_CLEAR_RAIL]);
1594  }
1595 
1596  if (flags & DC_EXEC) {
1597  /* read variables before the station tile is removed */
1598  uint specindex = GetCustomStationSpecIndex(tile);
1599  Track track = GetRailStationTrack(tile);
1600  Owner owner = GetTileOwner(tile);
1601  RailType rt = GetRailType(tile);
1602  Train *v = nullptr;
1603 
1604  if (HasStationReservation(tile)) {
1605  v = GetTrainForReservation(tile, track);
1606  if (v != nullptr) FreeTrainReservation(v);
1607  }
1608 
1609  bool build_rail = keep_rail && !IsStationTileBlocked(tile);
1610  if (!build_rail && !IsStationTileBlocked(tile)) Company::Get(owner)->infrastructure.rail[rt]--;
1611 
1612  DoClearSquare(tile);
1613  DeleteNewGRFInspectWindow(GSF_STATIONS, tile);
1614  if (build_rail) MakeRailNormal(tile, owner, TrackToTrackBits(track), rt);
1615  Company::Get(owner)->infrastructure.station--;
1617 
1618  st->rect.AfterRemoveTile(st, tile);
1619  AddTrackToSignalBuffer(tile, track, owner);
1620  YapfNotifyTrackLayoutChange(tile, track);
1621 
1622  DeallocateSpecFromStation(st, specindex);
1623 
1624  include(affected_stations, st);
1625 
1626  if (v != nullptr) RestoreTrainReservation(v);
1627  }
1628  }
1629 
1630  if (quantity == 0) return error.Failed() ? error : CommandCost(STR_ERROR_THERE_IS_NO_STATION);
1631 
1632  for (T *st : affected_stations) {
1633 
1634  /* now we need to make the "spanned" area of the railway station smaller
1635  * if we deleted something at the edges.
1636  * we also need to adjust train_tile. */
1637  MakeRailStationAreaSmaller(st);
1638  UpdateStationSignCoord(st);
1639 
1640  /* if we deleted the whole station, delete the train facility. */
1641  if (st->train_station.tile == INVALID_TILE) {
1642  st->facilities &= ~FACIL_TRAIN;
1644  st->UpdateVirtCoord();
1646  }
1647  }
1648 
1649  total_cost.AddCost(quantity * removal_cost);
1650  return total_cost;
1651 }
1652 
1664 CommandCost CmdRemoveFromRailStation(TileIndex start, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1665 {
1666  TileIndex end = p1 == 0 ? start : p1;
1667  if (start >= MapSize() || end >= MapSize()) return CMD_ERROR;
1668 
1669  TileArea ta(start, end);
1670  std::vector<Station *> affected_stations;
1671 
1672  CommandCost ret = RemoveFromRailBaseStation(ta, affected_stations, flags, _price[PR_CLEAR_STATION_RAIL], HasBit(p2, 0));
1673  if (ret.Failed()) return ret;
1674 
1675  /* Do all station specific functions here. */
1676  for (Station *st : affected_stations) {
1677 
1679  st->MarkTilesDirty(false);
1680  st->RecomputeCatchment();
1681  }
1682 
1683  /* Now apply the rail cost to the number that we deleted */
1684  return ret;
1685 }
1686 
1698 CommandCost CmdRemoveFromRailWaypoint(TileIndex start, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1699 {
1700  TileIndex end = p1 == 0 ? start : p1;
1701  if (start >= MapSize() || end >= MapSize()) return CMD_ERROR;
1702 
1703  TileArea ta(start, end);
1704  std::vector<Waypoint *> affected_stations;
1705 
1706  return RemoveFromRailBaseStation(ta, affected_stations, flags, _price[PR_CLEAR_WAYPOINT_RAIL], HasBit(p2, 0));
1707 }
1708 
1709 
1718 template <class T>
1720 {
1721  /* Current company owns the station? */
1722  if (_current_company != OWNER_WATER) {
1723  CommandCost ret = CheckOwnership(st->owner);
1724  if (ret.Failed()) return ret;
1725  }
1726 
1727  /* determine width and height of platforms */
1728  TileArea ta = st->train_station;
1729 
1730  assert(ta.w != 0 && ta.h != 0);
1731 
1733  /* clear all areas of the station */
1734  TILE_AREA_LOOP(tile, ta) {
1735  /* only remove tiles that are actually train station tiles */
1736  if (st->TileBelongsToRailStation(tile)) {
1737  std::vector<T*> affected_stations; // dummy
1738  CommandCost ret = RemoveFromRailBaseStation(TileArea(tile, 1, 1), affected_stations, flags, removal_cost, false);
1739  if (ret.Failed()) return ret;
1740  cost.AddCost(ret);
1741  }
1742  }
1743 
1744  return cost;
1745 }
1746 
1754 {
1755  /* if there is flooding, remove platforms tile by tile */
1756  if (_current_company == OWNER_WATER) {
1757  return DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAIL_STATION);
1758  }
1759 
1760  Station *st = Station::GetByTile(tile);
1761  CommandCost cost = RemoveRailStation(st, flags, _price[PR_CLEAR_STATION_RAIL]);
1762 
1763  if (flags & DC_EXEC) st->RecomputeCatchment();
1764 
1765  return cost;
1766 }
1767 
1775 {
1776  /* if there is flooding, remove waypoints tile by tile */
1777  if (_current_company == OWNER_WATER) {
1778  return DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAIL_WAYPOINT);
1779  }
1780 
1781  return RemoveRailStation(Waypoint::GetByTile(tile), flags, _price[PR_CLEAR_WAYPOINT_RAIL]);
1782 }
1783 
1784 
1790 static RoadStop **FindRoadStopSpot(bool truck_station, Station *st)
1791 {
1792  RoadStop **primary_stop = (truck_station) ? &st->truck_stops : &st->bus_stops;
1793 
1794  if (*primary_stop == nullptr) {
1795  /* we have no roadstop of the type yet, so write a "primary stop" */
1796  return primary_stop;
1797  } else {
1798  /* there are stops already, so append to the end of the list */
1799  RoadStop *stop = *primary_stop;
1800  while (stop->next != nullptr) stop = stop->next;
1801  return &stop->next;
1802  }
1803 }
1804 
1806 
1816 static CommandCost FindJoiningRoadStop(StationID existing_stop, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
1817 {
1818  return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST>(existing_stop, station_to_join, adjacent, ta, st);
1819 }
1820 
1837 CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1838 {
1839  bool type = HasBit(p2, 0);
1840  bool is_drive_through = HasBit(p2, 1);
1841  RoadType rt = Extract<RoadType, 5, 6>(p2);
1842  if (!ValParamRoadType(rt)) return CMD_ERROR;
1843  StationID station_to_join = GB(p2, 16, 16);
1844  bool reuse = (station_to_join != NEW_STATION);
1845  if (!reuse) station_to_join = INVALID_STATION;
1846  bool distant_join = (station_to_join != INVALID_STATION);
1847 
1848  uint8 width = (uint8)GB(p1, 0, 8);
1849  uint8 length = (uint8)GB(p1, 8, 8);
1850 
1851  /* Check if the requested road stop is too big */
1852  if (width > _settings_game.station.station_spread || length > _settings_game.station.station_spread) return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
1853  /* Check for incorrect width / length. */
1854  if (width == 0 || length == 0) return CMD_ERROR;
1855  /* Check if the first tile and the last tile are valid */
1856  if (!IsValidTile(tile) || TileAddWrap(tile, width - 1, length - 1) == INVALID_TILE) return CMD_ERROR;
1857 
1858  TileArea roadstop_area(tile, width, length);
1859 
1860  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
1861 
1862  /* Trams only have drive through stops */
1863  if (!is_drive_through && RoadTypeIsTram(rt)) return CMD_ERROR;
1864 
1865  DiagDirection ddir;
1866  Axis axis;
1867  if (is_drive_through) {
1868  /* By definition axis is valid, due to there being 2 axes and reading 1 bit. */
1869  axis = Extract<Axis, 3, 1>(p2);
1870  ddir = AxisToDiagDir(axis);
1871  } else {
1872  /* By definition ddir is valid, due to there being 4 diagonal directions and reading 2 bits. */
1873  ddir = Extract<DiagDirection, 3, 2>(p2);
1874  axis = DiagDirToAxis(ddir);
1875  }
1876 
1877  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags);
1878  if (ret.Failed()) return ret;
1879 
1880  /* Total road stop cost. */
1881  CommandCost cost(EXPENSES_CONSTRUCTION, roadstop_area.w * roadstop_area.h * _price[type ? PR_BUILD_STATION_TRUCK : PR_BUILD_STATION_BUS]);
1882  StationID est = INVALID_STATION;
1883  ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 5 << axis : 1 << ddir, is_drive_through, type, axis, &est, rt);
1884  if (ret.Failed()) return ret;
1885  cost.AddCost(ret);
1886 
1887  Station *st = nullptr;
1888  ret = FindJoiningRoadStop(est, station_to_join, HasBit(p2, 2), roadstop_area, &st);
1889  if (ret.Failed()) return ret;
1890 
1891  /* Check if this number of road stops can be allocated. */
1892  if (!RoadStop::CanAllocateItem(roadstop_area.w * roadstop_area.h)) return_cmd_error(type ? STR_ERROR_TOO_MANY_TRUCK_STOPS : STR_ERROR_TOO_MANY_BUS_STOPS);
1893 
1894  ret = BuildStationPart(&st, flags, reuse, roadstop_area, STATIONNAMING_ROAD);
1895  if (ret.Failed()) return ret;
1896 
1897  if (flags & DC_EXEC) {
1898  /* Check every tile in the area. */
1899  TILE_AREA_LOOP(cur_tile, roadstop_area) {
1900  /* Get existing road types and owners before any tile clearing */
1901  RoadType road_rt = MayHaveRoad(cur_tile) ? GetRoadType(cur_tile, RTT_ROAD) : INVALID_ROADTYPE;
1902  RoadType tram_rt = MayHaveRoad(cur_tile) ? GetRoadType(cur_tile, RTT_TRAM) : INVALID_ROADTYPE;
1903  Owner road_owner = road_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_ROAD) : _current_company;
1904  Owner tram_owner = tram_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_TRAM) : _current_company;
1905 
1906  if (IsTileType(cur_tile, MP_STATION) && IsRoadStop(cur_tile)) {
1907  RemoveRoadStop(cur_tile, flags);
1908  }
1909 
1910  RoadStop *road_stop = new RoadStop(cur_tile);
1911  /* Insert into linked list of RoadStops. */
1912  RoadStop **currstop = FindRoadStopSpot(type, st);
1913  *currstop = road_stop;
1914 
1915  if (type) {
1916  st->truck_station.Add(cur_tile);
1917  } else {
1918  st->bus_station.Add(cur_tile);
1919  }
1920 
1921  /* Initialize an empty station. */
1922  st->AddFacility((type) ? FACIL_TRUCK_STOP : FACIL_BUS_STOP, cur_tile);
1923 
1924  st->rect.BeforeAddTile(cur_tile, StationRect::ADD_TRY);
1925 
1926  RoadStopType rs_type = type ? ROADSTOP_TRUCK : ROADSTOP_BUS;
1927  if (is_drive_through) {
1928  /* Update company infrastructure counts. If the current tile is a normal road tile, remove the old
1929  * bits first. */
1930  if (IsNormalRoadTile(cur_tile)) {
1931  UpdateCompanyRoadInfrastructure(road_rt, road_owner, -(int)CountBits(GetRoadBits(cur_tile, RTT_ROAD)));
1932  UpdateCompanyRoadInfrastructure(tram_rt, tram_owner, -(int)CountBits(GetRoadBits(cur_tile, RTT_TRAM)));
1933  }
1934 
1935  if (road_rt == INVALID_ROADTYPE && RoadTypeIsRoad(rt)) road_rt = rt;
1936  if (tram_rt == INVALID_ROADTYPE && RoadTypeIsTram(rt)) tram_rt = rt;
1937 
1938  UpdateCompanyRoadInfrastructure(road_rt, road_owner, 2);
1939  UpdateCompanyRoadInfrastructure(tram_rt, tram_owner, 2);
1940 
1941  MakeDriveThroughRoadStop(cur_tile, st->owner, road_owner, tram_owner, st->index, rs_type, road_rt, tram_rt, axis);
1942  road_stop->MakeDriveThrough();
1943  } else {
1944  if (road_rt == INVALID_ROADTYPE && RoadTypeIsRoad(rt)) road_rt = rt;
1945  if (tram_rt == INVALID_ROADTYPE && RoadTypeIsTram(rt)) tram_rt = rt;
1946  /* Non-drive-through stop never overbuild and always count as two road bits. */
1947  Company::Get(st->owner)->infrastructure.road[rt] += 2;
1948  MakeRoadStop(cur_tile, st->owner, st->index, rs_type, road_rt, tram_rt, ddir);
1949  }
1950  Company::Get(st->owner)->infrastructure.station++;
1951 
1952  MarkTileDirtyByTile(cur_tile);
1953  }
1954  }
1955 
1956  if (st != nullptr) {
1957  st->AfterStationTileSetChange(true, type ? STATION_TRUCK: STATION_BUS);
1958  }
1959  return cost;
1960 }
1961 
1962 
1963 static Vehicle *ClearRoadStopStatusEnum(Vehicle *v, void *)
1964 {
1965  if (v->type == VEH_ROAD) {
1966  /* Okay... we are a road vehicle on a drive through road stop.
1967  * But that road stop has just been removed, so we need to make
1968  * sure we are in a valid state... however, vehicles can also
1969  * turn on road stop tiles, so only clear the 'road stop' state
1970  * bits and only when the state was 'in road stop', otherwise
1971  * we'll end up clearing the turn around bits. */
1972  RoadVehicle *rv = RoadVehicle::From(v);
1974  }
1975 
1976  return nullptr;
1977 }
1978 
1979 
1987 {
1988  Station *st = Station::GetByTile(tile);
1989 
1990  if (_current_company != OWNER_WATER) {
1991  CommandCost ret = CheckOwnership(st->owner);
1992  if (ret.Failed()) return ret;
1993  }
1994 
1995  bool is_truck = IsTruckStop(tile);
1996 
1997  RoadStop **primary_stop;
1998  RoadStop *cur_stop;
1999  if (is_truck) { // truck stop
2000  primary_stop = &st->truck_stops;
2001  cur_stop = RoadStop::GetByTile(tile, ROADSTOP_TRUCK);
2002  } else {
2003  primary_stop = &st->bus_stops;
2004  cur_stop = RoadStop::GetByTile(tile, ROADSTOP_BUS);
2005  }
2006 
2007  assert(cur_stop != nullptr);
2008 
2009  /* don't do the check for drive-through road stops when company bankrupts */
2010  if (IsDriveThroughStopTile(tile) && (flags & DC_BANKRUPT)) {
2011  /* remove the 'going through road stop' status from all vehicles on that tile */
2012  if (flags & DC_EXEC) FindVehicleOnPos(tile, nullptr, &ClearRoadStopStatusEnum);
2013  } else {
2015  if (ret.Failed()) return ret;
2016  }
2017 
2018  if (flags & DC_EXEC) {
2019  if (*primary_stop == cur_stop) {
2020  /* removed the first stop in the list */
2021  *primary_stop = cur_stop->next;
2022  /* removed the only stop? */
2023  if (*primary_stop == nullptr) {
2024  st->facilities &= (is_truck ? ~FACIL_TRUCK_STOP : ~FACIL_BUS_STOP);
2025  }
2026  } else {
2027  /* tell the predecessor in the list to skip this stop */
2028  RoadStop *pred = *primary_stop;
2029  while (pred->next != cur_stop) pred = pred->next;
2030  pred->next = cur_stop->next;
2031  }
2032 
2033  /* Update company infrastructure counts. */
2034  FOR_ALL_ROADTRAMTYPES(rtt) {
2035  RoadType rt = GetRoadType(tile, rtt);
2036  UpdateCompanyRoadInfrastructure(rt, GetRoadOwner(tile, rtt), -2);
2037  }
2038 
2039  Company::Get(st->owner)->infrastructure.station--;
2041 
2042  if (IsDriveThroughStopTile(tile)) {
2043  /* Clears the tile for us */
2044  cur_stop->ClearDriveThrough();
2045  } else {
2046  DoClearSquare(tile);
2047  }
2048 
2049  delete cur_stop;
2050 
2051  /* Make sure no vehicle is going to the old roadstop */
2052  for (RoadVehicle *v : RoadVehicle::Iterate()) {
2053  if (v->First() == v && v->current_order.IsType(OT_GOTO_STATION) &&
2054  v->dest_tile == tile) {
2055  v->SetDestTile(v->GetOrderStationLocation(st->index));
2056  }
2057  }
2058 
2059  st->rect.AfterRemoveTile(st, tile);
2060 
2061  st->AfterStationTileSetChange(false, is_truck ? STATION_TRUCK: STATION_BUS);
2062 
2063  /* Update the tile area of the truck/bus stop */
2064  if (is_truck) {
2065  st->truck_station.Clear();
2066  for (const RoadStop *rs = st->truck_stops; rs != nullptr; rs = rs->next) st->truck_station.Add(rs->xy);
2067  } else {
2068  st->bus_station.Clear();
2069  for (const RoadStop *rs = st->bus_stops; rs != nullptr; rs = rs->next) st->bus_station.Add(rs->xy);
2070  }
2071  }
2072 
2073  return CommandCost(EXPENSES_CONSTRUCTION, _price[is_truck ? PR_CLEAR_STATION_TRUCK : PR_CLEAR_STATION_BUS]);
2074 }
2075 
2087 CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
2088 {
2089  uint8 width = (uint8)GB(p1, 0, 8);
2090  uint8 height = (uint8)GB(p1, 8, 8);
2091  bool keep_drive_through_roads = !HasBit(p2, 1);
2092 
2093  /* Check for incorrect width / height. */
2094  if (width == 0 || height == 0) return CMD_ERROR;
2095  /* Check if the first tile and the last tile are valid */
2096  if (!IsValidTile(tile) || TileAddWrap(tile, width - 1, height - 1) == INVALID_TILE) return CMD_ERROR;
2097  /* Bankrupting company is not supposed to remove roads, there may be road vehicles. */
2098  if (!keep_drive_through_roads && (flags & DC_BANKRUPT)) return CMD_ERROR;
2099 
2100  TileArea roadstop_area(tile, width, height);
2101 
2103  CommandCost last_error(STR_ERROR_THERE_IS_NO_STATION);
2104  bool had_success = false;
2105 
2106  TILE_AREA_LOOP(cur_tile, roadstop_area) {
2107  /* Make sure the specified tile is a road stop of the correct type */
2108  if (!IsTileType(cur_tile, MP_STATION) || !IsRoadStop(cur_tile) || (uint32)GetRoadStopType(cur_tile) != GB(p2, 0, 1)) continue;
2109 
2110  /* Save information on to-be-restored roads before the stop is removed. */
2111  RoadBits road_bits = ROAD_NONE;
2112  RoadType road_type[] = { INVALID_ROADTYPE, INVALID_ROADTYPE };
2113  Owner road_owner[] = { OWNER_NONE, OWNER_NONE };
2114  if (IsDriveThroughStopTile(cur_tile)) {
2115  FOR_ALL_ROADTRAMTYPES(rtt) {
2116  road_type[rtt] = GetRoadType(cur_tile, rtt);
2117  if (road_type[rtt] == INVALID_ROADTYPE) continue;
2118  road_owner[rtt] = GetRoadOwner(cur_tile, rtt);
2119  /* If we don't want to preserve our roads then restore only roads of others. */
2120  if (!keep_drive_through_roads && road_owner[rtt] == _current_company) road_type[rtt] = INVALID_ROADTYPE;
2121  }
2122  road_bits = AxisToRoadBits(DiagDirToAxis(GetRoadStopDir(cur_tile)));
2123  }
2124 
2125  CommandCost ret = RemoveRoadStop(cur_tile, flags);
2126  if (ret.Failed()) {
2127  last_error = ret;
2128  continue;
2129  }
2130  cost.AddCost(ret);
2131  had_success = true;
2132 
2133  /* Restore roads. */
2134  if ((flags & DC_EXEC) && (road_type[RTT_ROAD] != INVALID_ROADTYPE || road_type[RTT_TRAM] != INVALID_ROADTYPE)) {
2135  MakeRoadNormal(cur_tile, road_bits, road_type[RTT_ROAD], road_type[RTT_TRAM], ClosestTownFromTile(cur_tile, UINT_MAX)->index,
2136  road_owner[RTT_ROAD], road_owner[RTT_TRAM]);
2137 
2138  /* Update company infrastructure counts. */
2139  int count = CountBits(road_bits);
2140  UpdateCompanyRoadInfrastructure(road_type[RTT_ROAD], road_owner[RTT_ROAD], count);
2141  UpdateCompanyRoadInfrastructure(road_type[RTT_TRAM], road_owner[RTT_TRAM], count);
2142  }
2143  }
2144 
2145  return had_success ? cost : last_error;
2146 }
2147 
2156 uint8 GetAirportNoiseLevelForDistance(const AirportSpec *as, uint distance)
2157 {
2158  /* 0 cannot be accounted, and 1 is the lowest that can be reduced from town.
2159  * So no need to go any further*/
2160  if (as->noise_level < 2) return as->noise_level;
2161 
2162  /* The steps for measuring noise reduction are based on the "magical" (and arbitrary) 8 base distance
2163  * adding the town_council_tolerance 4 times, as a way to graduate, depending of the tolerance.
2164  * Basically, it says that the less tolerant a town is, the bigger the distance before
2165  * an actual decrease can be granted */
2166  uint8 town_tolerance_distance = 8 + (_settings_game.difficulty.town_council_tolerance * 4);
2167 
2168  /* now, we want to have the distance segmented using the distance judged bareable by town
2169  * This will give us the coefficient of reduction the distance provides. */
2170  uint noise_reduction = distance / town_tolerance_distance;
2171 
2172  /* If the noise reduction equals the airport noise itself, don't give it for free.
2173  * Otherwise, simply reduce the airport's level. */
2174  return noise_reduction >= as->noise_level ? 1 : as->noise_level - noise_reduction;
2175 }
2176 
2185 Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it, uint &mindist)
2186 {
2187  assert(Town::GetNumItems() > 0);
2188 
2189  Town *nearest = nullptr;
2190 
2191  uint perimeter_min_x = TileX(it);
2192  uint perimeter_min_y = TileY(it);
2193  uint perimeter_max_x = perimeter_min_x + as->size_x - 1;
2194  uint perimeter_max_y = perimeter_min_y + as->size_y - 1;
2195 
2196  mindist = UINT_MAX - 1; // prevent overflow
2197 
2198  std::unique_ptr<TileIterator> copy(it.Clone());
2199  for (TileIndex cur_tile = *copy; cur_tile != INVALID_TILE; cur_tile = ++*copy) {
2200  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) {
2201  Town *t = CalcClosestTownFromTile(cur_tile, mindist + 1);
2202  if (t == nullptr) continue;
2203 
2204  uint dist = DistanceManhattan(t->xy, cur_tile);
2205  if (dist == mindist && t->index < nearest->index) nearest = t;
2206  if (dist < mindist) {
2207  nearest = t;
2208  mindist = dist;
2209  }
2210  }
2211  }
2212 
2213  return nearest;
2214 }
2215 
2216 
2219 {
2220  for (Town *t : Town::Iterate()) t->noise_reached = 0;
2221 
2222  for (const Station *st : Station::Iterate()) {
2223  if (st->airport.tile != INVALID_TILE && st->airport.type != AT_OILRIG) {
2224  const AirportSpec *as = st->airport.GetSpec();
2225  AirportTileIterator it(st);
2226  uint dist;
2227  Town *nearest = AirportGetNearestTown(as, it, dist);
2228  nearest->noise_reached += GetAirportNoiseLevelForDistance(as, dist);
2229  }
2230  }
2231 }
2232 
2246 CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
2247 {
2248  StationID station_to_join = GB(p2, 16, 16);
2249  bool reuse = (station_to_join != NEW_STATION);
2250  if (!reuse) station_to_join = INVALID_STATION;
2251  bool distant_join = (station_to_join != INVALID_STATION);
2252  byte airport_type = GB(p1, 0, 8);
2253  byte layout = GB(p1, 8, 8);
2254 
2255  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
2256 
2257  if (airport_type >= NUM_AIRPORTS) return CMD_ERROR;
2258 
2259  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags);
2260  if (ret.Failed()) return ret;
2261 
2262  /* Check if a valid, buildable airport was chosen for construction */
2263  const AirportSpec *as = AirportSpec::Get(airport_type);
2264  if (!as->IsAvailable() || layout >= as->num_table) return CMD_ERROR;
2265  if (!as->IsWithinMapBounds(layout, tile)) return CMD_ERROR;
2266 
2267  Direction rotation = as->rotation[layout];
2268  int w = as->size_x;
2269  int h = as->size_y;
2270  if (rotation == DIR_E || rotation == DIR_W) Swap(w, h);
2271  TileArea airport_area = TileArea(tile, w, h);
2272 
2274  return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
2275  }
2276 
2277  AirportTileTableIterator iter(as->table[layout], tile);
2278  CommandCost cost = CheckFlatLandAirport(iter, flags);
2279  if (cost.Failed()) return cost;
2280 
2281  /* The noise level is the noise from the airport and reduce it to account for the distance to the town center. */
2282  uint dist;
2283  Town *nearest = AirportGetNearestTown(as, iter, dist);
2284  uint newnoise_level = GetAirportNoiseLevelForDistance(as, dist);
2285 
2286  /* Check if local auth would allow a new airport */
2287  StringID authority_refuse_message = STR_NULL;
2288  Town *authority_refuse_town = nullptr;
2289 
2291  /* do not allow to build a new airport if this raise the town noise over the maximum allowed by town */
2292  if ((nearest->noise_reached + newnoise_level) > nearest->MaxTownNoise()) {
2293  authority_refuse_message = STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE;
2294  authority_refuse_town = nearest;
2295  }
2296  } else {
2297  Town *t = ClosestTownFromTile(tile, UINT_MAX);
2298  uint num = 0;
2299  for (const Station *st : Station::Iterate()) {
2300  if (st->town == t && (st->facilities & FACIL_AIRPORT) && st->airport.type != AT_OILRIG) num++;
2301  }
2302  if (num >= 2) {
2303  authority_refuse_message = STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT;
2304  authority_refuse_town = t;
2305  }
2306  }
2307 
2308  if (authority_refuse_message != STR_NULL) {
2309  SetDParam(0, authority_refuse_town->index);
2310  return_cmd_error(authority_refuse_message);
2311  }
2312 
2313  Station *st = nullptr;
2314  ret = FindJoiningStation(INVALID_STATION, station_to_join, HasBit(p2, 0), airport_area, &st);
2315  if (ret.Failed()) return ret;
2316 
2317  /* Distant join */
2318  if (st == nullptr && distant_join) st = Station::GetIfValid(station_to_join);
2319 
2320  ret = BuildStationPart(&st, flags, reuse, airport_area, (GetAirport(airport_type)->flags & AirportFTAClass::AIRPLANES) ? STATIONNAMING_AIRPORT : STATIONNAMING_HELIPORT);
2321  if (ret.Failed()) return ret;
2322 
2323  if (st != nullptr && st->airport.tile != INVALID_TILE) {
2324  return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT);
2325  }
2326 
2327  for (AirportTileTableIterator iter(as->table[layout], tile); iter != INVALID_TILE; ++iter) {
2328  cost.AddCost(_price[PR_BUILD_STATION_AIRPORT]);
2329  }
2330 
2331  if (flags & DC_EXEC) {
2332  /* Always add the noise, so there will be no need to recalculate when option toggles */
2333  nearest->noise_reached += newnoise_level;
2334 
2335  st->AddFacility(FACIL_AIRPORT, tile);
2336  st->airport.type = airport_type;
2337  st->airport.layout = layout;
2338  st->airport.flags = 0;
2339  st->airport.rotation = rotation;
2340 
2341  st->rect.BeforeAddRect(tile, w, h, StationRect::ADD_TRY);
2342 
2343  for (AirportTileTableIterator iter(as->table[layout], tile); iter != INVALID_TILE; ++iter) {
2344  MakeAirport(iter, st->owner, st->index, iter.GetStationGfx(), WATER_CLASS_INVALID);
2345  SetStationTileRandomBits(iter, GB(Random(), 0, 4));
2346  st->airport.Add(iter);
2347 
2349  }
2350 
2351  /* Only call the animation trigger after all tiles have been built */
2352  for (AirportTileTableIterator iter(as->table[layout], tile); iter != INVALID_TILE; ++iter) {
2353  AirportTileAnimationTrigger(st, iter, AAT_BUILT);
2354  }
2355 
2357 
2358  Company::Get(st->owner)->infrastructure.airport++;
2359 
2360  st->AfterStationTileSetChange(true, STATION_AIRPORT);
2362 
2365  }
2366  }
2367 
2368  return cost;
2369 }
2370 
2378 {
2379  Station *st = Station::GetByTile(tile);
2380 
2381  if (_current_company != OWNER_WATER) {
2382  CommandCost ret = CheckOwnership(st->owner);
2383  if (ret.Failed()) return ret;
2384  }
2385 
2386  tile = st->airport.tile;
2387 
2389 
2390  for (const Aircraft *a : Aircraft::Iterate()) {
2391  if (!a->IsNormalAircraft()) continue;
2392  if (a->targetairport == st->index && a->state != FLYING) {
2393  return_cmd_error(STR_ERROR_AIRCRAFT_IN_THE_WAY);
2394  }
2395  }
2396 
2397  if (flags & DC_EXEC) {
2398  const AirportSpec *as = st->airport.GetSpec();
2399  /* The noise level is the noise from the airport and reduce it to account for the distance to the town center.
2400  * And as for construction, always remove it, even if the setting is not set, in order to avoid the
2401  * need of recalculation */
2402  AirportTileIterator it(st);
2403  uint dist;
2404  Town *nearest = AirportGetNearestTown(as, it, dist);
2405  nearest->noise_reached -= GetAirportNoiseLevelForDistance(as, dist);
2406  }
2407 
2408  TILE_AREA_LOOP(tile_cur, st->airport) {
2409  if (!st->TileBelongsToAirport(tile_cur)) continue;
2410 
2411  CommandCost ret = EnsureNoVehicleOnGround(tile_cur);
2412  if (ret.Failed()) return ret;
2413 
2414  cost.AddCost(_price[PR_CLEAR_STATION_AIRPORT]);
2415 
2416  if (flags & DC_EXEC) {
2417  if (IsHangarTile(tile_cur)) OrderBackup::Reset(tile_cur, false);
2418  DeleteAnimatedTile(tile_cur);
2419  DoClearSquare(tile_cur);
2420  DeleteNewGRFInspectWindow(GSF_AIRPORTTILES, tile_cur);
2421  }
2422  }
2423 
2424  if (flags & DC_EXEC) {
2425  /* Clear the persistent storage. */
2426  delete st->airport.psa;
2427 
2428  for (uint i = 0; i < st->airport.GetNumHangars(); ++i) {
2431  );
2432  }
2433 
2434  st->rect.AfterRemoveRect(st, st->airport);
2435 
2436  st->airport.Clear();
2437  st->facilities &= ~FACIL_AIRPORT;
2438 
2440 
2443  }
2444 
2445  Company::Get(st->owner)->infrastructure.airport--;
2446 
2447  st->AfterStationTileSetChange(false, STATION_AIRPORT);
2448 
2449  DeleteNewGRFInspectWindow(GSF_AIRPORTS, st->index);
2450  }
2451 
2452  return cost;
2453 }
2454 
2464 CommandCost CmdOpenCloseAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
2465 {
2466  if (!Station::IsValidID(p1)) return CMD_ERROR;
2467  Station *st = Station::Get(p1);
2468 
2469  if (!(st->facilities & FACIL_AIRPORT) || st->owner == OWNER_NONE) return CMD_ERROR;
2470 
2471  CommandCost ret = CheckOwnership(st->owner);
2472  if (ret.Failed()) return ret;
2473 
2474  if (flags & DC_EXEC) {
2477  }
2478  return CommandCost();
2479 }
2480 
2487 bool HasStationInUse(StationID station, bool include_company, CompanyID company)
2488 {
2489  for (const Vehicle *v : Vehicle::Iterate()) {
2490  if ((v->owner == company) == include_company) {
2491  const Order *order;
2492  FOR_VEHICLE_ORDERS(v, order) {
2493  if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station) {
2494  return true;
2495  }
2496  }
2497  }
2498  }
2499  return false;
2500 }
2501 
2502 static const TileIndexDiffC _dock_tileoffs_chkaround[] = {
2503  {-1, 0},
2504  { 0, 0},
2505  { 0, 0},
2506  { 0, -1}
2507 };
2508 static const byte _dock_w_chk[4] = { 2, 1, 2, 1 };
2509 static const byte _dock_h_chk[4] = { 1, 2, 1, 2 };
2510 
2520 CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
2521 {
2522  StationID station_to_join = GB(p2, 16, 16);
2523  bool reuse = (station_to_join != NEW_STATION);
2524  if (!reuse) station_to_join = INVALID_STATION;
2525  bool distant_join = (station_to_join != INVALID_STATION);
2526 
2527  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
2528 
2530  if (direction == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2531  direction = ReverseDiagDir(direction);
2532 
2533  /* Docks cannot be placed on rapids */
2534  if (HasTileWaterGround(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2535 
2536  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags);
2537  if (ret.Failed()) return ret;
2538 
2539  if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
2540 
2541  ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
2542  if (ret.Failed()) return ret;
2543 
2544  TileIndex tile_cur = tile + TileOffsByDiagDir(direction);
2545 
2546  if (!IsTileType(tile_cur, MP_WATER) || !IsTileFlat(tile_cur)) {
2547  return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2548  }
2549 
2550  if (IsBridgeAbove(tile_cur)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
2551 
2552  /* Get the water class of the water tile before it is cleared.*/
2553  WaterClass wc = GetWaterClass(tile_cur);
2554 
2555  ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
2556  if (ret.Failed()) return ret;
2557 
2558  tile_cur += TileOffsByDiagDir(direction);
2559  if (!IsTileType(tile_cur, MP_WATER) || !IsTileFlat(tile_cur)) {
2560  return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2561  }
2562 
2563  TileArea dock_area = TileArea(tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]),
2564  _dock_w_chk[direction], _dock_h_chk[direction]);
2565 
2566  /* middle */
2567  Station *st = nullptr;
2568  ret = FindJoiningStation(INVALID_STATION, station_to_join, HasBit(p1, 0), dock_area, &st);
2569  if (ret.Failed()) return ret;
2570 
2571  /* Distant join */
2572  if (st == nullptr && distant_join) st = Station::GetIfValid(station_to_join);
2573 
2574  ret = BuildStationPart(&st, flags, reuse, dock_area, STATIONNAMING_DOCK);
2575  if (ret.Failed()) return ret;
2576 
2577  if (flags & DC_EXEC) {
2578  st->ship_station.Add(tile);
2579  st->ship_station.Add(tile + TileOffsByDiagDir(direction));
2580  st->AddFacility(FACIL_DOCK, tile);
2581 
2582  st->rect.BeforeAddRect(dock_area.tile, dock_area.w, dock_area.h, StationRect::ADD_TRY);
2583 
2584  /* If the water part of the dock is on a canal, update infrastructure counts.
2585  * This is needed as we've unconditionally cleared that tile before. */
2586  if (wc == WATER_CLASS_CANAL) {
2587  Company::Get(st->owner)->infrastructure.water++;
2588  }
2589  Company::Get(st->owner)->infrastructure.station += 2;
2590 
2591  MakeDock(tile, st->owner, st->index, direction, wc);
2592  UpdateStationDockingTiles(st);
2593 
2594  st->AfterStationTileSetChange(true, STATION_DOCK);
2595  }
2596 
2597  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_STATION_DOCK]);
2598 }
2599 
2600 void RemoveDockingTile(TileIndex t)
2601 {
2602  for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
2603  TileIndex tile = t + TileOffsByDiagDir(d);
2604  if (!IsValidTile(tile)) continue;
2605 
2606  if (IsTileType(tile, MP_STATION)) {
2607  UpdateStationDockingTiles(Station::GetByTile(tile));
2608  } else if (IsTileType(tile, MP_INDUSTRY)) {
2609  Station *neutral = Industry::GetByTile(tile)->neutral_station;
2610  if (neutral != nullptr) UpdateStationDockingTiles(neutral);
2611  }
2612  }
2613 }
2614 
2621 {
2622  assert(IsValidTile(tile));
2623 
2624  /* Clear and maybe re-set docking tile */
2625  for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
2626  TileIndex docking_tile = tile + TileOffsByDiagDir(d);
2627  if (!IsValidTile(docking_tile)) continue;
2628 
2629  if (IsPossibleDockingTile(docking_tile)) {
2630  SetDockingTile(docking_tile, false);
2631  CheckForDockingTile(docking_tile);
2632  }
2633  }
2634 }
2635 
2643 {
2644  assert(IsDockTile(t));
2645 
2647  static const uint8 _valid_docking_tile[] = {
2648  0, 0, 0, 0, // No docking against the slope part.
2649  1 << DIAGDIR_NE | 1 << DIAGDIR_SW, // Docking permitted at the end
2650  1 << DIAGDIR_NW | 1 << DIAGDIR_SE, // of the flat piers.
2651  };
2652 
2653  StationGfx gfx = GetStationGfx(t);
2654  assert(gfx < lengthof(_valid_docking_tile));
2655  return HasBit(_valid_docking_tile[gfx], d);
2656 }
2657 
2664 {
2665  assert(IsDockTile(t));
2666 
2667  StationGfx gfx = GetStationGfx(t);
2668  if (gfx < GFX_DOCK_BASE_WATER_PART) return t;
2669 
2670  for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
2671  TileIndex tile = t + TileOffsByDiagDir(d);
2672  if (!IsValidTile(tile)) continue;
2673  if (!IsDockTile(tile)) continue;
2674  if (GetStationGfx(tile) < GFX_DOCK_BASE_WATER_PART && tile + TileOffsByDiagDir(GetDockDirection(tile)) == t) return tile;
2675  }
2676 
2677  return INVALID_TILE;
2678 }
2679 
2687 {
2688  Station *st = Station::GetByTile(tile);
2689  CommandCost ret = CheckOwnership(st->owner);
2690  if (ret.Failed()) return ret;
2691 
2692  if (!IsDockTile(tile)) return CMD_ERROR;
2693 
2694  TileIndex tile1 = FindDockLandPart(tile);
2695  if (tile1 == INVALID_TILE) return CMD_ERROR;
2696  TileIndex tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1));
2697 
2698  ret = EnsureNoVehicleOnGround(tile1);
2699  if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2);
2700  if (ret.Failed()) return ret;
2701 
2702  if (flags & DC_EXEC) {
2703  DoClearSquare(tile1);
2704  MarkTileDirtyByTile(tile1);
2705  MakeWaterKeepingClass(tile2, st->owner);
2706 
2707  st->rect.AfterRemoveTile(st, tile1);
2708  st->rect.AfterRemoveTile(st, tile2);
2709 
2710  MakeShipStationAreaSmaller(st);
2711  if (st->ship_station.tile == INVALID_TILE) {
2712  st->ship_station.Clear();
2713  st->docking_station.Clear();
2714  st->facilities &= ~FACIL_DOCK;
2715  }
2716 
2717  Company::Get(st->owner)->infrastructure.station -= 2;
2718 
2719  st->AfterStationTileSetChange(false, STATION_DOCK);
2720 
2723 
2724  /* All ships that were going to our station, can't go to it anymore.
2725  * Just clear the order, then automatically the next appropriate order
2726  * will be selected and in case of no appropriate order it will just
2727  * wander around the world. */
2728  if (!(st->facilities & FACIL_DOCK)) {
2729  for (Ship *s : Ship::Iterate()) {
2730  if (s->current_order.IsType(OT_LOADING) && s->current_order.GetDestination() == st->index) {
2731  s->LeaveStation();
2732  }
2733 
2734  if (s->current_order.IsType(OT_GOTO_STATION) && s->current_order.GetDestination() == st->index) {
2735  s->SetDestTile(s->GetOrderStationLocation(st->index));
2736  }
2737  }
2738  }
2739  }
2740 
2741  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_STATION_DOCK]);
2742 }
2743 
2744 #include "table/station_land.h"
2745 
2746 const DrawTileSprites *GetStationTileLayout(StationType st, byte gfx)
2747 {
2748  return &_station_display_datas[st][gfx];
2749 }
2750 
2760 bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrackOffset *overlay_offset)
2761 {
2762  bool snow_desert;
2763  switch (*ground) {
2764  case SPR_RAIL_TRACK_X:
2765  case SPR_MONO_TRACK_X:
2766  case SPR_MGLV_TRACK_X:
2767  snow_desert = false;
2768  *overlay_offset = RTO_X;
2769  break;
2770 
2771  case SPR_RAIL_TRACK_Y:
2772  case SPR_MONO_TRACK_Y:
2773  case SPR_MGLV_TRACK_Y:
2774  snow_desert = false;
2775  *overlay_offset = RTO_Y;
2776  break;
2777 
2778  case SPR_RAIL_TRACK_X_SNOW:
2779  case SPR_MONO_TRACK_X_SNOW:
2780  case SPR_MGLV_TRACK_X_SNOW:
2781  snow_desert = true;
2782  *overlay_offset = RTO_X;
2783  break;
2784 
2785  case SPR_RAIL_TRACK_Y_SNOW:
2786  case SPR_MONO_TRACK_Y_SNOW:
2787  case SPR_MGLV_TRACK_Y_SNOW:
2788  snow_desert = true;
2789  *overlay_offset = RTO_Y;
2790  break;
2791 
2792  default:
2793  return false;
2794  }
2795 
2796  if (ti != nullptr) {
2797  /* Decide snow/desert from tile */
2799  case LT_ARCTIC:
2800  snow_desert = (uint)ti->z > GetSnowLine() * TILE_HEIGHT;
2801  break;
2802 
2803  case LT_TROPIC:
2804  snow_desert = GetTropicZone(ti->tile) == TROPICZONE_DESERT;
2805  break;
2806 
2807  default:
2808  break;
2809  }
2810  }
2811 
2812  *ground = snow_desert ? SPR_FLAT_SNOW_DESERT_TILE : SPR_FLAT_GRASS_TILE;
2813  return true;
2814 }
2815 
2816 static void DrawTile_Station(TileInfo *ti)
2817 {
2818  const NewGRFSpriteLayout *layout = nullptr;
2819  DrawTileSprites tmp_rail_layout;
2820  const DrawTileSprites *t = nullptr;
2821  int32 total_offset;
2822  const RailtypeInfo *rti = nullptr;
2823  uint32 relocation = 0;
2824  uint32 ground_relocation = 0;
2825  BaseStation *st = nullptr;
2826  const StationSpec *statspec = nullptr;
2827  uint tile_layout = 0;
2828 
2829  if (HasStationRail(ti->tile)) {
2830  rti = GetRailTypeInfo(GetRailType(ti->tile));
2831  total_offset = rti->GetRailtypeSpriteOffset();
2832 
2833  if (IsCustomStationSpecIndex(ti->tile)) {
2834  /* look for customization */
2835  st = BaseStation::GetByTile(ti->tile);
2836  statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec;
2837 
2838  if (statspec != nullptr) {
2839  tile_layout = GetStationGfx(ti->tile);
2840 
2842  uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile);
2843  if (callback != CALLBACK_FAILED) tile_layout = (callback & ~1) + GetRailStationAxis(ti->tile);
2844  }
2845 
2846  /* Ensure the chosen tile layout is valid for this custom station */
2847  if (statspec->renderdata != nullptr) {
2848  layout = &statspec->renderdata[tile_layout < statspec->tiles ? tile_layout : (uint)GetRailStationAxis(ti->tile)];
2849  if (!layout->NeedsPreprocessing()) {
2850  t = layout;
2851  layout = nullptr;
2852  }
2853  }
2854  }
2855  }
2856  } else {
2857  total_offset = 0;
2858  }
2859 
2860  StationGfx gfx = GetStationGfx(ti->tile);
2861  if (IsAirport(ti->tile)) {
2862  gfx = GetAirportGfx(ti->tile);
2863  if (gfx >= NEW_AIRPORTTILE_OFFSET) {
2864  const AirportTileSpec *ats = AirportTileSpec::Get(gfx);
2865  if (ats->grf_prop.spritegroup[0] != nullptr && DrawNewAirportTile(ti, Station::GetByTile(ti->tile), gfx, ats)) {
2866  return;
2867  }
2868  /* No sprite group (or no valid one) found, meaning no graphics associated.
2869  * Use the substitute one instead */
2870  assert(ats->grf_prop.subst_id != INVALID_AIRPORTTILE);
2871  gfx = ats->grf_prop.subst_id;
2872  }
2873  switch (gfx) {
2874  case APT_RADAR_GRASS_FENCE_SW:
2875  t = &_station_display_datas_airport_radar_grass_fence_sw[GetAnimationFrame(ti->tile)];
2876  break;
2877  case APT_GRASS_FENCE_NE_FLAG:
2878  t = &_station_display_datas_airport_flag_grass_fence_ne[GetAnimationFrame(ti->tile)];
2879  break;
2880  case APT_RADAR_FENCE_SW:
2881  t = &_station_display_datas_airport_radar_fence_sw[GetAnimationFrame(ti->tile)];
2882  break;
2883  case APT_RADAR_FENCE_NE:
2884  t = &_station_display_datas_airport_radar_fence_ne[GetAnimationFrame(ti->tile)];
2885  break;
2886  case APT_GRASS_FENCE_NE_FLAG_2:
2887  t = &_station_display_datas_airport_flag_grass_fence_ne_2[GetAnimationFrame(ti->tile)];
2888  break;
2889  }
2890  }
2891 
2892  Owner owner = GetTileOwner(ti->tile);
2893 
2894  PaletteID palette;
2895  if (Company::IsValidID(owner)) {
2896  palette = COMPANY_SPRITE_COLOUR(owner);
2897  } else {
2898  /* Some stations are not owner by a company, namely oil rigs */
2899  palette = PALETTE_TO_GREY;
2900  }
2901 
2902  if (layout == nullptr && (t == nullptr || t->seq == nullptr)) t = GetStationTileLayout(GetStationType(ti->tile), gfx);
2903 
2904  /* don't show foundation for docks */
2905  if (ti->tileh != SLOPE_FLAT && !IsDock(ti->tile)) {
2906  if (statspec != nullptr && HasBit(statspec->flags, SSF_CUSTOM_FOUNDATIONS)) {
2907  /* Station has custom foundations.
2908  * Check whether the foundation continues beyond the tile's upper sides. */
2909  uint edge_info = 0;
2910  int z;
2911  Slope slope = GetFoundationPixelSlope(ti->tile, &z);
2912  if (!HasFoundationNW(ti->tile, slope, z)) SetBit(edge_info, 0);
2913  if (!HasFoundationNE(ti->tile, slope, z)) SetBit(edge_info, 1);
2914  SpriteID image = GetCustomStationFoundationRelocation(statspec, st, ti->tile, tile_layout, edge_info);
2915  if (image == 0) goto draw_default_foundation;
2916 
2917  if (HasBit(statspec->flags, SSF_EXTENDED_FOUNDATIONS)) {
2918  /* Station provides extended foundations. */
2919 
2920  static const uint8 foundation_parts[] = {
2921  0, 0, 0, 0, // Invalid, Invalid, Invalid, SLOPE_SW
2922  0, 1, 2, 3, // Invalid, SLOPE_EW, SLOPE_SE, SLOPE_WSE
2923  0, 4, 5, 6, // Invalid, SLOPE_NW, SLOPE_NS, SLOPE_NWS
2924  7, 8, 9 // SLOPE_NE, SLOPE_ENW, SLOPE_SEN
2925  };
2926 
2927  AddSortableSpriteToDraw(image + foundation_parts[ti->tileh], PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
2928  } else {
2929  /* Draw simple foundations, built up from 8 possible foundation sprites. */
2930 
2931  /* Each set bit represents one of the eight composite sprites to be drawn.
2932  * 'Invalid' entries will not drawn but are included for completeness. */
2933  static const uint8 composite_foundation_parts[] = {
2934  /* Invalid (00000000), Invalid (11010001), Invalid (11100100), SLOPE_SW (11100000) */
2935  0x00, 0xD1, 0xE4, 0xE0,
2936  /* Invalid (11001010), SLOPE_EW (11001001), SLOPE_SE (11000100), SLOPE_WSE (11000000) */
2937  0xCA, 0xC9, 0xC4, 0xC0,
2938  /* Invalid (11010010), SLOPE_NW (10010001), SLOPE_NS (11100100), SLOPE_NWS (10100000) */
2939  0xD2, 0x91, 0xE4, 0xA0,
2940  /* SLOPE_NE (01001010), SLOPE_ENW (00001001), SLOPE_SEN (01000100) */
2941  0x4A, 0x09, 0x44
2942  };
2943 
2944  uint8 parts = composite_foundation_parts[ti->tileh];
2945 
2946  /* If foundations continue beyond the tile's upper sides then
2947  * mask out the last two pieces. */
2948  if (HasBit(edge_info, 0)) ClrBit(parts, 6);
2949  if (HasBit(edge_info, 1)) ClrBit(parts, 7);
2950 
2951  if (parts == 0) {
2952  /* We always have to draw at least one sprite to make sure there is a boundingbox and a sprite with the
2953  * correct offset for the childsprites.
2954  * So, draw the (completely empty) sprite of the default foundations. */
2955  goto draw_default_foundation;
2956  }
2957 
2959  for (int i = 0; i < 8; i++) {
2960  if (HasBit(parts, i)) {
2961  AddSortableSpriteToDraw(image + i, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
2962  }
2963  }
2964  EndSpriteCombine();
2965  }
2966 
2967  OffsetGroundSprite(31, 1);
2969  } else {
2970 draw_default_foundation:
2972  }
2973  }
2974 
2975  if (IsBuoy(ti->tile)) {
2976  DrawWaterClassGround(ti);
2977  SpriteID sprite = GetCanalSprite(CF_BUOY, ti->tile);
2978  if (sprite != 0) total_offset = sprite - SPR_IMG_BUOY;
2979  } else if (IsDock(ti->tile) || (IsOilRig(ti->tile) && IsTileOnWater(ti->tile))) {
2980  if (ti->tileh == SLOPE_FLAT) {
2981  DrawWaterClassGround(ti);
2982  } else {
2983  assert(IsDock(ti->tile));
2984  TileIndex water_tile = ti->tile + TileOffsByDiagDir(GetDockDirection(ti->tile));
2985  WaterClass wc = HasTileWaterClass(water_tile) ? GetWaterClass(water_tile) : WATER_CLASS_INVALID;
2986  if (wc == WATER_CLASS_SEA) {
2987  DrawShoreTile(ti->tileh);
2988  } else {
2989  DrawClearLandTile(ti, 3);
2990  }
2991  }
2992  } else {
2993  if (layout != nullptr) {
2994  /* Sprite layout which needs preprocessing */
2995  bool separate_ground = HasBit(statspec->flags, SSF_SEPARATE_GROUND);
2996  uint32 var10_values = layout->PrepareLayout(total_offset, rti->fallback_railtype, 0, 0, separate_ground);
2997  uint8 var10;
2998  FOR_EACH_SET_BIT(var10, var10_values) {
2999  uint32 var10_relocation = GetCustomStationRelocation(statspec, st, ti->tile, var10);
3000  layout->ProcessRegisters(var10, var10_relocation, separate_ground);
3001  }
3002  tmp_rail_layout.seq = layout->GetLayout(&tmp_rail_layout.ground);
3003  t = &tmp_rail_layout;
3004  total_offset = 0;
3005  } else if (statspec != nullptr) {
3006  /* Simple sprite layout */
3007  ground_relocation = relocation = GetCustomStationRelocation(statspec, st, ti->tile, 0);
3008  if (HasBit(statspec->flags, SSF_SEPARATE_GROUND)) {
3009  ground_relocation = GetCustomStationRelocation(statspec, st, ti->tile, 1);
3010  }
3011  ground_relocation += rti->fallback_railtype;
3012  }
3013 
3014  SpriteID image = t->ground.sprite;
3015  PaletteID pal = t->ground.pal;
3016  RailTrackOffset overlay_offset;
3017  if (rti != nullptr && rti->UsesOverlay() && SplitGroundSpriteForOverlay(ti, &image, &overlay_offset)) {
3018  SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
3019  DrawGroundSprite(image, PAL_NONE);
3020  DrawGroundSprite(ground + overlay_offset, PAL_NONE);
3021 
3022  if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasStationReservation(ti->tile)) {
3023  SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
3024  DrawGroundSprite(overlay + overlay_offset, PALETTE_CRASH);
3025  }
3026  } else {
3027  image += HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE) ? ground_relocation : total_offset;
3028  if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += ground_relocation;
3029  DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette));
3030 
3031  /* PBS debugging, draw reserved tracks darker */
3032  if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasStationRail(ti->tile) && HasStationReservation(ti->tile)) {
3033  const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
3035  }
3036  }
3037  }
3038 
3040 
3041  if (IsRoadStop(ti->tile)) {
3042  RoadType road_rt = GetRoadTypeRoad(ti->tile);
3043  RoadType tram_rt = GetRoadTypeTram(ti->tile);
3044  const RoadTypeInfo* road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt);
3045  const RoadTypeInfo* tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt);
3046 
3047  if (IsDriveThroughStopTile(ti->tile)) {
3048  Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y;
3049  uint sprite_offset = axis == AXIS_X ? 1 : 0;
3050 
3051  DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset);
3052  } else {
3053  /* Non-drivethrough road stops are only valid for roads. */
3054  assert(road_rt != INVALID_ROADTYPE && tram_rt == INVALID_ROADTYPE);
3055 
3056  if (road_rti->UsesOverlay()) {
3057  DiagDirection dir = GetRoadStopDir(ti->tile);
3058  SpriteID ground = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_ROADSTOP);
3059  DrawGroundSprite(ground + dir, PAL_NONE);
3060  }
3061  }
3062 
3063  /* Draw road, tram catenary */
3064  DrawRoadCatenary(ti);
3065  }
3066 
3067  if (IsRailWaypoint(ti->tile)) {
3068  /* Don't offset the waypoint graphics; they're always the same. */
3069  total_offset = 0;
3070  }
3071 
3072  DrawRailTileSeq(ti, t, TO_BUILDINGS, total_offset, relocation, palette);
3073 }
3074 
3075 void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, RoadType roadtype, int image)
3076 {
3077  int32 total_offset = 0;
3078  PaletteID pal = COMPANY_SPRITE_COLOUR(_local_company);
3079  const DrawTileSprites *t = GetStationTileLayout(st, image);
3080  const RailtypeInfo *rti = nullptr;
3081 
3082  if (railtype != INVALID_RAILTYPE) {
3083  rti = GetRailTypeInfo(railtype);
3084  total_offset = rti->GetRailtypeSpriteOffset();
3085  }
3086 
3087  SpriteID img = t->ground.sprite;
3088  RailTrackOffset overlay_offset;
3089  if (rti != nullptr && rti->UsesOverlay() && SplitGroundSpriteForOverlay(nullptr, &img, &overlay_offset)) {
3091  DrawSprite(img, PAL_NONE, x, y);
3092  DrawSprite(ground + overlay_offset, PAL_NONE, x, y);
3093  } else {
3094  DrawSprite(img + total_offset, HasBit(img, PALETTE_MODIFIER_COLOUR) ? pal : PAL_NONE, x, y);
3095  }
3096 
3097  if (roadtype != INVALID_ROADTYPE) {
3098  const RoadTypeInfo* rti = GetRoadTypeInfo(roadtype);
3099  if (image >= 4) {
3100  /* Drive-through stop */
3101  uint sprite_offset = 5 - image;
3102 
3103  /* Road underlay takes precedence over tram */
3104  if (rti->UsesOverlay()) {
3106  DrawSprite(ground + sprite_offset, PAL_NONE, x, y);
3107 
3109  if (overlay) DrawSprite(overlay + sprite_offset, PAL_NONE, x, y);
3110  } else if (RoadTypeIsTram(roadtype)) {
3111  DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y);
3112  }
3113  } else {
3114  /* Drive-in stop */
3115  if (RoadTypeIsRoad(roadtype) && rti->UsesOverlay()) {
3117  DrawSprite(ground + image, PAL_NONE, x, y);
3118  }
3119  }
3120  }
3121 
3122  /* Default waypoint has no railtype specific sprites */
3123  DrawRailTileSeqInGUI(x, y, t, st == STATION_WAYPOINT ? 0 : total_offset, 0, pal);
3124 }
3125 
3126 static int GetSlopePixelZ_Station(TileIndex tile, uint x, uint y)
3127 {
3128  return GetTileMaxPixelZ(tile);
3129 }
3130 
3131 static Foundation GetFoundation_Station(TileIndex tile, Slope tileh)
3132 {
3133  return FlatteningFoundation(tileh);
3134 }
3135 
3136 static void GetTileDesc_Station(TileIndex tile, TileDesc *td)
3137 {
3138  td->owner[0] = GetTileOwner(tile);
3139 
3140  if (IsRoadStopTile(tile)) {
3141  RoadType road_rt = GetRoadTypeRoad(tile);
3142  RoadType tram_rt = GetRoadTypeTram(tile);
3143  Owner road_owner = INVALID_OWNER;
3144  Owner tram_owner = INVALID_OWNER;
3145  if (road_rt != INVALID_ROADTYPE) {
3146  const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt);
3147  td->roadtype = rti->strings.name;
3148  td->road_speed = rti->max_speed / 2;
3149  road_owner = GetRoadOwner(tile, RTT_ROAD);
3150  }
3151 
3152  if (tram_rt != INVALID_ROADTYPE) {
3153  const RoadTypeInfo *rti = GetRoadTypeInfo(tram_rt);
3154  td->tramtype = rti->strings.name;
3155  td->tram_speed = rti->max_speed / 2;
3156  tram_owner = GetRoadOwner(tile, RTT_TRAM);
3157  }
3158 
3159  if (IsDriveThroughStopTile(tile)) {
3160  /* Is there a mix of owners? */
3161  if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) ||
3162  (road_owner != INVALID_OWNER && road_owner != td->owner[0])) {
3163  uint i = 1;
3164  if (road_owner != INVALID_OWNER) {
3165  td->owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER;
3166  td->owner[i] = road_owner;
3167  i++;
3168  }
3169  if (tram_owner != INVALID_OWNER) {
3170  td->owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER;
3171  td->owner[i] = tram_owner;
3172  }
3173  }
3174  }
3175  }
3176 
3178 
3179  if (HasStationTileRail(tile)) {
3180  const StationSpec *spec = GetStationSpec(tile);
3181 
3182  if (spec != nullptr) {
3184  td->station_name = spec->name;
3185 
3186  if (spec->grf_prop.grffile != nullptr) {
3187  const GRFConfig *gc = GetGRFConfig(spec->grf_prop.grffile->grfid);
3188  td->grf = gc->GetName();
3189  }
3190  }
3191 
3192  const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
3193  td->rail_speed = rti->max_speed;
3194  td->railtype = rti->strings.name;
3195  }
3196 
3197  if (IsAirport(tile)) {
3198  const AirportSpec *as = Station::GetByTile(tile)->airport.GetSpec();
3200  td->airport_name = as->name;
3201 
3202  const AirportTileSpec *ats = AirportTileSpec::GetByTile(tile);
3203  td->airport_tile_name = ats->name;
3204 
3205  if (as->grf_prop.grffile != nullptr) {
3206  const GRFConfig *gc = GetGRFConfig(as->grf_prop.grffile->grfid);
3207  td->grf = gc->GetName();
3208  } else if (ats->grf_prop.grffile != nullptr) {
3209  const GRFConfig *gc = GetGRFConfig(ats->grf_prop.grffile->grfid);
3210  td->grf = gc->GetName();
3211  }
3212  }
3213 
3214  StringID str;
3215  switch (GetStationType(tile)) {
3216  default: NOT_REACHED();
3217  case STATION_RAIL: str = STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION; break;
3218  case STATION_AIRPORT:
3219  str = (IsHangar(tile) ? STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR : STR_LAI_STATION_DESCRIPTION_AIRPORT);
3220  break;
3221  case STATION_TRUCK: str = STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA; break;
3222  case STATION_BUS: str = STR_LAI_STATION_DESCRIPTION_BUS_STATION; break;
3223  case STATION_OILRIG: {
3224  const Industry *i = Station::GetByTile(tile)->industry;
3225  const IndustrySpec *is = GetIndustrySpec(i->type);
3226  td->owner[0] = i->owner;
3227  str = is->name;
3228  if (is->grf_prop.grffile != nullptr) td->grf = GetGRFConfig(is->grf_prop.grffile->grfid)->GetName();
3229  break;
3230  }
3231  case STATION_DOCK: str = STR_LAI_STATION_DESCRIPTION_SHIP_DOCK; break;
3232  case STATION_BUOY: str = STR_LAI_STATION_DESCRIPTION_BUOY; break;
3233  case STATION_WAYPOINT: str = STR_LAI_STATION_DESCRIPTION_WAYPOINT; break;
3234  }
3235  td->str = str;
3236 }
3237 
3238 
3239 static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
3240 {
3241  TrackBits trackbits = TRACK_BIT_NONE;
3242 
3243  switch (mode) {
3244  case TRANSPORT_RAIL:
3245  if (HasStationRail(tile) && !IsStationTileBlocked(tile)) {
3246  trackbits = TrackToTrackBits(GetRailStationTrack(tile));
3247  }
3248  break;
3249 
3250  case TRANSPORT_WATER:
3251  /* buoy is coded as a station, it is always on open water */
3252  if (IsBuoy(tile)) {
3253  trackbits = TRACK_BIT_ALL;
3254  /* remove tracks that connect NE map edge */
3255  if (TileX(tile) == 0) trackbits &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
3256  /* remove tracks that connect NW map edge */
3257  if (TileY(tile) == 0) trackbits &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
3258  }
3259  break;
3260 
3261  case TRANSPORT_ROAD:
3262  if (IsRoadStop(tile)) {
3263  RoadTramType rtt = (RoadTramType)sub_mode;
3264  if (!HasTileRoadType(tile, rtt)) break;
3265 
3266  DiagDirection dir = GetRoadStopDir(tile);
3267  Axis axis = DiagDirToAxis(dir);
3268 
3269  if (side != INVALID_DIAGDIR) {
3270  if (axis != DiagDirToAxis(side) || (IsStandardRoadStopTile(tile) && dir != side)) break;
3271  }
3272 
3273  trackbits = AxisToTrackBits(axis);
3274  }
3275  break;
3276 
3277  default:
3278  break;
3279  }
3280 
3282 }
3283 
3284 
3285 static void TileLoop_Station(TileIndex tile)
3286 {
3287  /* FIXME -- GetTileTrackStatus_Station -> animated stationtiles
3288  * hardcoded.....not good */
3289  switch (GetStationType(tile)) {
3290  case STATION_AIRPORT:
3291  AirportTileAnimationTrigger(Station::GetByTile(tile), tile, AAT_TILELOOP);
3292  break;
3293 
3294  case STATION_DOCK:
3295  if (!IsTileFlat(tile)) break; // only handle water part
3296  FALLTHROUGH;
3297 
3298  case STATION_OILRIG: //(station part)
3299  case STATION_BUOY:
3300  TileLoop_Water(tile);
3301  break;
3302 
3303  default: break;
3304  }
3305 }
3306 
3307 
3308 static void AnimateTile_Station(TileIndex tile)
3309 {
3310  if (HasStationRail(tile)) {
3311  AnimateStationTile(tile);
3312  return;
3313  }
3314 
3315  if (IsAirport(tile)) {
3316  AnimateAirportTile(tile);
3317  }
3318 }
3319 
3320 
3321 static bool ClickTile_Station(TileIndex tile)
3322 {
3323  const BaseStation *bst = BaseStation::GetByTile(tile);
3324 
3325  if (bst->facilities & FACIL_WAYPOINT) {
3327  } else if (IsHangar(tile)) {
3328  const Station *st = Station::From(bst);
3330  } else {
3332  }
3333  return true;
3334 }
3335 
3336 static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, int x, int y)
3337 {
3338  if (v->type == VEH_TRAIN) {
3339  StationID station_id = GetStationIndex(tile);
3340  if (!v->current_order.ShouldStopAtStation(v, station_id)) return VETSB_CONTINUE;
3341  if (!IsRailStation(tile) || !v->IsFrontEngine()) return VETSB_CONTINUE;
3342 
3343  int station_ahead;
3344  int station_length;
3345  int stop = GetTrainStopLocation(station_id, tile, Train::From(v), &station_ahead, &station_length);
3346 
3347  /* Stop whenever that amount of station ahead + the distance from the
3348  * begin of the platform to the stop location is longer than the length
3349  * of the platform. Station ahead 'includes' the current tile where the
3350  * vehicle is on, so we need to subtract that. */
3351  if (stop + station_ahead - (int)TILE_SIZE >= station_length) return VETSB_CONTINUE;
3352 
3354 
3355  x &= 0xF;
3356  y &= 0xF;
3357 
3358  if (DiagDirToAxis(dir) != AXIS_X) Swap(x, y);
3359  if (y == TILE_SIZE / 2) {
3360  if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x;
3361  stop &= TILE_SIZE - 1;
3362 
3363  if (x == stop) {
3364  return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station
3365  } else if (x < stop) {
3367  uint16 spd = max(0, (stop - x) * 20 - 15);
3368  if (spd < v->cur_speed) v->cur_speed = spd;
3369  }
3370  }
3371  } else if (v->type == VEH_ROAD) {
3372  RoadVehicle *rv = RoadVehicle::From(v);
3373  if (rv->state < RVSB_IN_ROAD_STOP && !IsReversingRoadTrackdir((Trackdir)rv->state) && rv->frame == 0) {
3374  if (IsRoadStop(tile) && rv->IsFrontEngine()) {
3375  /* Attempt to allocate a parking bay in a road stop */
3377  }
3378  }
3379  }
3380 
3381  return VETSB_CONTINUE;
3382 }
3383 
3389 {
3390  /* Collect cargoes accepted since the last big tick. */
3391  CargoTypes cargoes = 0;
3392  for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
3393  if (HasBit(st->goods[cid].status, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(cargoes, cid);
3394  }
3395 
3396  /* Anything to do? */
3397  if (cargoes == 0) return;
3398 
3399  /* Loop over all houses in the catchment. */
3401  for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
3402  if (IsTileType(tile, MP_HOUSE)) {
3403  WatchedCargoCallback(tile, cargoes);
3404  }
3405  }
3406 }
3407 
3415 {
3416  if (!st->IsInUse()) {
3417  if (++st->delete_ctr >= 8) delete st;
3418  return false;
3419  }
3420 
3421  if (Station::IsExpected(st)) {
3423 
3424  for (CargoID i = 0; i < NUM_CARGO; i++) {
3425  ClrBit(Station::From(st)->goods[i].status, GoodsEntry::GES_ACCEPTED_BIGTICK);
3426  }
3427  }
3428 
3429 
3430  if ((st->facilities & FACIL_WAYPOINT) == 0) UpdateStationAcceptance(Station::From(st), true);
3431 
3432  return true;
3433 }
3434 
3435 static inline void byte_inc_sat(byte *p)
3436 {
3437  byte b = *p + 1;
3438  if (b != 0) *p = b;
3439 }
3440 
3447 static void TruncateCargo(const CargoSpec *cs, GoodsEntry *ge, uint amount = UINT_MAX)
3448 {
3449  /* If truncating also punish the source stations' ratings to
3450  * decrease the flow of incoming cargo. */
3451 
3452  StationCargoAmountMap waiting_per_source;
3453  ge->cargo.Truncate(amount, &waiting_per_source);
3454  for (StationCargoAmountMap::iterator i(waiting_per_source.begin()); i != waiting_per_source.end(); ++i) {
3455  Station *source_station = Station::GetIfValid(i->first);
3456  if (source_station == nullptr) continue;
3457 
3458  GoodsEntry &source_ge = source_station->goods[cs->Index()];
3459  source_ge.max_waiting_cargo = max(source_ge.max_waiting_cargo, i->second);
3460  }
3461 }
3462 
3463 static void UpdateStationRating(Station *st)
3464 {
3465  bool waiting_changed = false;
3466 
3467  byte_inc_sat(&st->time_since_load);
3468  byte_inc_sat(&st->time_since_unload);
3469 
3470  const CargoSpec *cs;
3471  FOR_ALL_CARGOSPECS(cs) {
3472  GoodsEntry *ge = &st->goods[cs->Index()];
3473  /* Slowly increase the rating back to his original level in the case we
3474  * didn't deliver cargo yet to this station. This happens when a bribe
3475  * failed while you didn't moved that cargo yet to a station. */
3476  if (!ge->HasRating() && ge->rating < INITIAL_STATION_RATING) {
3477  ge->rating++;
3478  }
3479 
3480  /* Only change the rating if we are moving this cargo */
3481  if (ge->HasRating()) {
3482  byte_inc_sat(&ge->time_since_pickup);
3483  if (ge->time_since_pickup == 255 && _settings_game.order.selectgoods) {
3485  ge->last_speed = 0;
3486  TruncateCargo(cs, ge);
3487  waiting_changed = true;
3488  continue;
3489  }
3490 
3491  bool skip = false;
3492  int rating = 0;
3493  uint waiting = ge->cargo.AvailableCount();
3494 
3495  /* num_dests is at least 1 if there is any cargo as
3496  * INVALID_STATION is also a destination.
3497  */
3498  uint num_dests = (uint)ge->cargo.Packets()->MapSize();
3499 
3500  /* Average amount of cargo per next hop, but prefer solitary stations
3501  * with only one or two next hops. They are allowed to have more
3502  * cargo waiting per next hop.
3503  * With manual cargo distribution waiting_avg = waiting / 2 as then
3504  * INVALID_STATION is the only destination.
3505  */
3506  uint waiting_avg = waiting / (num_dests + 1);
3507 
3509  /* Perform custom station rating. If it succeeds the speed, days in transit and
3510  * waiting cargo ratings must not be executed. */
3511 
3512  /* NewGRFs expect last speed to be 0xFF when no vehicle has arrived yet. */
3513  uint last_speed = ge->HasVehicleEverTriedLoading() ? ge->last_speed : 0xFF;
3514 
3515  uint32 var18 = min(ge->time_since_pickup, 0xFF) | (min(ge->max_waiting_cargo, 0xFFFF) << 8) | (min(last_speed, 0xFF) << 24);
3516  /* Convert to the 'old' vehicle types */
3517  uint32 var10 = (st->last_vehicle_type == VEH_INVALID) ? 0x0 : (st->last_vehicle_type + 0x10);
3518  uint16 callback = GetCargoCallback(CBID_CARGO_STATION_RATING_CALC, var10, var18, cs);
3519  if (callback != CALLBACK_FAILED) {
3520  skip = true;
3521  rating = GB(callback, 0, 14);
3522 
3523  /* Simulate a 15 bit signed value */
3524  if (HasBit(callback, 14)) rating -= 0x4000;
3525  }
3526  }
3527 
3528  if (!skip) {
3529  int b = ge->last_speed - 85;
3530  if (b >= 0) rating += b >> 2;
3531 
3532  byte waittime = ge->time_since_pickup;
3533  if (st->last_vehicle_type == VEH_SHIP) waittime >>= 2;
3534  if (waittime <= 21) rating += 25;
3535  if (waittime <= 12) rating += 25;
3536  if (waittime <= 6) rating += 45;
3537  if (waittime <= 3) rating += 35;
3538 
3539  rating -= 90;
3540  if (ge->max_waiting_cargo <= 1500) rating += 55;
3541  if (ge->max_waiting_cargo <= 1000) rating += 35;
3542  if (ge->max_waiting_cargo <= 600) rating += 10;
3543  if (ge->max_waiting_cargo <= 300) rating += 20;
3544  if (ge->max_waiting_cargo <= 100) rating += 10;
3545  }
3546 
3547  if (Company::IsValidID(st->owner) && HasBit(st->town->statues, st->owner)) rating += 26;
3548 
3549  byte age = ge->last_age;
3550  if (age < 3) rating += 10;
3551  if (age < 2) rating += 10;
3552  if (age < 1) rating += 13;
3553 
3554  {
3555  int or_ = ge->rating; // old rating
3556 
3557  /* only modify rating in steps of -2, -1, 0, 1 or 2 */
3558  ge->rating = rating = or_ + Clamp(Clamp(rating, 0, 255) - or_, -2, 2);
3559 
3560  /* if rating is <= 64 and more than 100 items waiting on average per destination,
3561  * remove some random amount of goods from the station */
3562  if (rating <= 64 && waiting_avg >= 100) {
3563  int dec = Random() & 0x1F;
3564  if (waiting_avg < 200) dec &= 7;
3565  waiting -= (dec + 1) * num_dests;
3566  waiting_changed = true;
3567  }
3568 
3569  /* if rating is <= 127 and there are any items waiting, maybe remove some goods. */
3570  if (rating <= 127 && waiting != 0) {
3571  uint32 r = Random();
3572  if (rating <= (int)GB(r, 0, 7)) {
3573  /* Need to have int, otherwise it will just overflow etc. */
3574  waiting = max((int)waiting - (int)((GB(r, 8, 2) - 1) * num_dests), 0);
3575  waiting_changed = true;
3576  }
3577  }
3578 
3579  /* At some point we really must cap the cargo. Previously this
3580  * was a strict 4095, but now we'll have a less strict, but
3581  * increasingly aggressive truncation of the amount of cargo. */
3582  static const uint WAITING_CARGO_THRESHOLD = 1 << 12;
3583  static const uint WAITING_CARGO_CUT_FACTOR = 1 << 6;
3584  static const uint MAX_WAITING_CARGO = 1 << 15;
3585 
3586  if (waiting > WAITING_CARGO_THRESHOLD) {
3587  uint difference = waiting - WAITING_CARGO_THRESHOLD;
3588  waiting -= (difference / WAITING_CARGO_CUT_FACTOR);
3589 
3590  waiting = min(waiting, MAX_WAITING_CARGO);
3591  waiting_changed = true;
3592  }
3593 
3594  /* We can't truncate cargo that's already reserved for loading.
3595  * Thus StoredCount() here. */
3596  if (waiting_changed && waiting < ge->cargo.AvailableCount()) {
3597  /* Feed back the exact own waiting cargo at this station for the
3598  * next rating calculation. */
3599  ge->max_waiting_cargo = 0;
3600 
3601  TruncateCargo(cs, ge, ge->cargo.AvailableCount() - waiting);
3602  } else {
3603  /* If the average number per next hop is low, be more forgiving. */
3604  ge->max_waiting_cargo = waiting_avg;
3605  }
3606  }
3607  }
3608  }
3609 
3610  StationID index = st->index;
3611  if (waiting_changed) {
3612  SetWindowDirty(WC_STATION_VIEW, index); // update whole window
3613  } else {
3614  SetWindowWidgetDirty(WC_STATION_VIEW, index, WID_SV_ACCEPT_RATING_LIST); // update only ratings list
3615  }
3616 }
3617 
3626 void RerouteCargo(Station *st, CargoID c, StationID avoid, StationID avoid2)
3627 {
3628  GoodsEntry &ge = st->goods[c];
3629 
3630  /* Reroute cargo in station. */
3631  ge.cargo.Reroute(UINT_MAX, &ge.cargo, avoid, avoid2, &ge);
3632 
3633  /* Reroute cargo staged to be transferred. */
3634  for (std::list<Vehicle *>::iterator it(st->loading_vehicles.begin()); it != st->loading_vehicles.end(); ++it) {
3635  for (Vehicle *v = *it; v != nullptr; v = v->Next()) {
3636  if (v->cargo_type != c) continue;
3637  v->cargo.Reroute(UINT_MAX, &v->cargo, avoid, avoid2, &ge);
3638  }
3639  }
3640 }
3641 
3651 {
3652  for (CargoID c = 0; c < NUM_CARGO; ++c) {
3653  const bool auto_distributed = (_settings_game.linkgraph.GetDistributionType(c) != DT_MANUAL);
3654  GoodsEntry &ge = from->goods[c];
3656  if (lg == nullptr) continue;
3657  Node node = (*lg)[ge.node];
3658  for (EdgeIterator it(node.Begin()); it != node.End();) {
3659  Edge edge = it->second;
3660  Station *to = Station::Get((*lg)[it->first].Station());
3661  assert(to->goods[c].node == it->first);
3662  ++it; // Do that before removing the edge. Anything else may crash.
3663  assert(_date >= edge.LastUpdate());
3664  uint timeout = LinkGraph::MIN_TIMEOUT_DISTANCE + (DistanceManhattan(from->xy, to->xy) >> 3);
3665  if ((uint)(_date - edge.LastUpdate()) > timeout) {
3666  bool updated = false;
3667 
3668  if (auto_distributed) {
3669  /* Have all vehicles refresh their next hops before deciding to
3670  * remove the node. */
3671  std::vector<Vehicle *> vehicles;
3672  for (OrderList *l : OrderList::Iterate()) {
3673  bool found_from = false;
3674  bool found_to = false;
3675  for (Order *order = l->GetFirstOrder(); order != nullptr; order = order->next) {
3676  if (!order->IsType(OT_GOTO_STATION) && !order->IsType(OT_IMPLICIT)) continue;
3677  if (order->GetDestination() == from->index) {
3678  found_from = true;
3679  if (found_to) break;
3680  } else if (order->GetDestination() == to->index) {
3681  found_to = true;
3682  if (found_from) break;
3683  }
3684  }
3685  if (!found_to || !found_from) continue;
3686  vehicles.push_back(l->GetFirstSharedVehicle());
3687  }
3688 
3689  auto iter = vehicles.begin();
3690  while (iter != vehicles.end()) {
3691  Vehicle *v = *iter;
3692 
3693  LinkRefresher::Run(v, false); // Don't allow merging. Otherwise lg might get deleted.
3694  if (edge.LastUpdate() == _date) {
3695  updated = true;
3696  break;
3697  }
3698 
3699  Vehicle *next_shared = v->NextShared();
3700  if (next_shared) {
3701  *iter = next_shared;
3702  ++iter;
3703  } else {
3704  iter = vehicles.erase(iter);
3705  }
3706 
3707  if (iter == vehicles.end()) iter = vehicles.begin();
3708  }
3709  }
3710 
3711  if (!updated) {
3712  /* If it's still considered dead remove it. */
3713  node.RemoveEdge(to->goods[c].node);
3714  ge.flows.DeleteFlows(to->index);
3715  RerouteCargo(from, c, to->index, from->index);
3716  }
3717  } else if (edge.LastUnrestrictedUpdate() != INVALID_DATE && (uint)(_date - edge.LastUnrestrictedUpdate()) > timeout) {
3718  edge.Restrict();
3719  ge.flows.RestrictFlows(to->index);
3720  RerouteCargo(from, c, to->index, from->index);
3721  } else if (edge.LastRestrictedUpdate() != INVALID_DATE && (uint)(_date - edge.LastRestrictedUpdate()) > timeout) {
3722  edge.Release();
3723  }
3724  }
3725  assert(_date >= lg->LastCompression());
3726  if ((uint)(_date - lg->LastCompression()) > LinkGraph::COMPRESSION_INTERVAL) {
3727  lg->Compress();
3728  }
3729  }
3730 }
3731 
3741 void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage, EdgeUpdateMode mode)
3742 {
3743  GoodsEntry &ge1 = st->goods[cargo];
3744  Station *st2 = Station::Get(next_station_id);
3745  GoodsEntry &ge2 = st2->goods[cargo];
3746  LinkGraph *lg = nullptr;
3747  if (ge1.link_graph == INVALID_LINK_GRAPH) {
3748  if (ge2.link_graph == INVALID_LINK_GRAPH) {
3750  lg = new LinkGraph(cargo);
3752  ge2.link_graph = lg->index;
3753  ge2.node = lg->AddNode(st2);
3754  } else {
3755  DEBUG(misc, 0, "Can't allocate link graph");
3756  }
3757  } else {
3758  lg = LinkGraph::Get(ge2.link_graph);
3759  }
3760  if (lg) {
3761  ge1.link_graph = lg->index;
3762  ge1.node = lg->AddNode(st);
3763  }
3764  } else if (ge2.link_graph == INVALID_LINK_GRAPH) {
3765  lg = LinkGraph::Get(ge1.link_graph);
3766  ge2.link_graph = lg->index;
3767  ge2.node = lg->AddNode(st2);
3768  } else {
3769  lg = LinkGraph::Get(ge1.link_graph);
3770  if (ge1.link_graph != ge2.link_graph) {
3771  LinkGraph *lg2 = LinkGraph::Get(ge2.link_graph);
3772  if (lg->Size() < lg2->Size()) {
3774  lg2->Merge(lg); // Updates GoodsEntries of lg
3775  lg = lg2;
3776  } else {
3778  lg->Merge(lg2); // Updates GoodsEntries of lg2
3779  }
3780  }
3781  }
3782  if (lg != nullptr) {
3783  (*lg)[ge1.node].UpdateEdge(ge2.node, capacity, usage, mode);
3784  }
3785 }
3786 
3793 void IncreaseStats(Station *st, const Vehicle *front, StationID next_station_id)
3794 {
3795  for (const Vehicle *v = front; v != nullptr; v = v->Next()) {
3796  if (v->refit_cap > 0) {
3797  /* The cargo count can indeed be higher than the refit_cap if
3798  * wagons have been auto-replaced and subsequently auto-
3799  * refitted to a higher capacity. The cargo gets redistributed
3800  * among the wagons in that case.
3801  * As usage is not such an important figure anyway we just
3802  * ignore the additional cargo then.*/
3803  IncreaseStats(st, v->cargo_type, next_station_id, v->refit_cap,
3805  }
3806  }
3807 }
3808 
3809 /* called for every station each tick */
3810 static void StationHandleSmallTick(BaseStation *st)
3811 {
3812  if ((st->facilities & FACIL_WAYPOINT) != 0 || !st->IsInUse()) return;
3813 
3814  byte b = st->delete_ctr + 1;
3815  if (b >= STATION_RATING_TICKS) b = 0;
3816  st->delete_ctr = b;
3817 
3818  if (b == 0) UpdateStationRating(Station::From(st));
3819 }
3820 
3821 void OnTick_Station()
3822 {
3823  if (_game_mode == GM_EDITOR) return;
3824 
3825  for (BaseStation *st : BaseStation::Iterate()) {
3826  StationHandleSmallTick(st);
3827 
3828  /* Clean up the link graph about once a week. */
3829  if (Station::IsExpected(st) && (_tick_counter + st->index) % STATION_LINKGRAPH_TICKS == 0) {
3831  };
3832 
3833  /* Run STATION_ACCEPTANCE_TICKS = 250 tick interval trigger for station animation.
3834  * Station index is included so that triggers are not all done
3835  * at the same time. */
3836  if ((_tick_counter + st->index) % STATION_ACCEPTANCE_TICKS == 0) {
3837  /* Stop processing this station if it was deleted */
3838  if (!StationHandleBigTick(st)) continue;
3839  TriggerStationAnimation(st, st->xy, SAT_250_TICKS);
3840  if (Station::IsExpected(st)) AirportAnimationTrigger(Station::From(st), AAT_STATION_250_TICKS);
3841  }
3842  }
3843 }
3844 
3847 {
3848  for (Station *st : Station::Iterate()) {
3849  for (CargoID i = 0; i < NUM_CARGO; i++) {
3850  GoodsEntry *ge = &st->goods[i];
3853  }
3854  }
3855 }
3856 
3857 
3858 void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius)
3859 {
3860  ForAllStationsRadius(tile, radius, [&](Station *st) {
3861  if (st->owner == owner && DistanceManhattan(tile, st->xy) <= radius) {
3862  for (CargoID i = 0; i < NUM_CARGO; i++) {
3863  GoodsEntry *ge = &st->goods[i];
3864 
3865  if (ge->status != 0) {
3866  ge->rating = Clamp(ge->rating + amount, 0, 255);
3867  }
3868  }
3869  }
3870  });
3871 }
3872 
3873 static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceType source_type, SourceID source_id)
3874 {
3875  /* We can't allocate a CargoPacket? Then don't do anything
3876  * at all; i.e. just discard the incoming cargo. */
3877  if (!CargoPacket::CanAllocateItem()) return 0;
3878 
3879  GoodsEntry &ge = st->goods[type];
3880  amount += ge.amount_fract;
3881  ge.amount_fract = GB(amount, 0, 8);
3882 
3883  amount >>= 8;
3884  /* No new "real" cargo item yet. */
3885  if (amount == 0) return 0;
3886 
3887  StationID next = ge.GetVia(st->index);
3888  ge.cargo.Append(new CargoPacket(st->index, st->xy, amount, source_type, source_id), next);
3889  LinkGraph *lg = nullptr;
3890  if (ge.link_graph == INVALID_LINK_GRAPH) {
3892  lg = new LinkGraph(type);
3894  ge.link_graph = lg->index;
3895  ge.node = lg->AddNode(st);
3896  } else {
3897  DEBUG(misc, 0, "Can't allocate link graph");
3898  }
3899  } else {
3900  lg = LinkGraph::Get(ge.link_graph);
3901  }
3902  if (lg != nullptr) (*lg)[ge.node].UpdateSupply(amount);
3903 
3904  if (!ge.HasRating()) {
3907  }
3908 
3910  TriggerStationAnimation(st, st->xy, SAT_NEW_CARGO, type);
3911  AirportAnimationTrigger(st, AAT_STATION_NEW_CARGO, type);
3912 
3914  st->MarkTilesDirty(true);
3915  return amount;
3916 }
3917 
3918 static bool IsUniqueStationName(const char *name)
3919 {
3920  for (const Station *st : Station::Iterate()) {
3921  if (st->name != nullptr && strcmp(st->name, name) == 0) return false;
3922  }
3923 
3924  return true;
3925 }
3926 
3936 CommandCost CmdRenameStation(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
3937 {
3938  Station *st = Station::GetIfValid(p1);
3939  if (st == nullptr) return CMD_ERROR;
3940 
3941  CommandCost ret = CheckOwnership(st->owner);
3942  if (ret.Failed()) return ret;
3943 
3944  bool reset = StrEmpty(text);
3945 
3946  if (!reset) {
3948  if (!IsUniqueStationName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
3949  }
3950 
3951  if (flags & DC_EXEC) {
3952  st->cached_name.clear();
3953  free(st->name);
3954  st->name = reset ? nullptr : stredup(text);
3955 
3956  st->UpdateVirtCoord();
3958  }
3959 
3960  return CommandCost();
3961 }
3962 
3963 static void AddNearbyStationsByCatchment(TileIndex tile, StationList *stations, StationList &nearby)
3964 {
3965  for (Station *st : nearby) {
3966  if (st->TileIsInCatchment(tile)) stations->insert(st);
3967  }
3968 }
3969 
3977 void FindStationsAroundTiles(const TileArea &location, StationList * const stations, bool use_nearby)
3978 {
3979  if (use_nearby) {
3980  /* Industries and towns maintain a list of nearby stations */
3981  if (IsTileType(location.tile, MP_INDUSTRY)) {
3982  /* Industry nearby stations are already filtered by catchment. */
3983  *stations = Industry::GetByTile(location.tile)->stations_near;
3984  return;
3985  } else if (IsTileType(location.tile, MP_HOUSE)) {
3986  /* Town nearby stations need to be filtered per tile. */
3987  assert(location.w == 1 && location.h == 1);
3988  AddNearbyStationsByCatchment(location.tile, stations, Town::GetByTile(location.tile)->stations_near);
3989  return;
3990  }
3991  }
3992 
3993  /* Not using, or don't have a nearby stations list, so we need to scan. */
3994  std::set<StationID> seen_stations;
3995 
3996  /* Scan an area around the building covering the maximum possible station
3997  * to find the possible nearby stations. */
3999  TileArea ta = TileArea(location).Expand(max_c);
4000  TILE_AREA_LOOP(tile, ta) {
4001  if (IsTileType(tile, MP_STATION)) seen_stations.insert(GetStationIndex(tile));
4002  }
4003 
4004  for (StationID stationid : seen_stations) {
4005  Station *st = Station::GetIfValid(stationid);
4006  if (st == nullptr) continue; /* Waypoint */
4007 
4008  /* Check if station is attached to an industry */
4009  if (!_settings_game.station.serve_neutral_industries && st->industry != nullptr) continue;
4010 
4011  /* Test if the tile is within the station's catchment */
4012  TILE_AREA_LOOP(tile, location) {
4013  if (st->TileIsInCatchment(tile)) {
4014  stations->insert(st);
4015  break;
4016  }
4017  }
4018  }
4019 }
4020 
4026 {
4027  if (this->tile != INVALID_TILE) {
4028  FindStationsAroundTiles(*this, &this->stations);
4029  this->tile = INVALID_TILE;
4030  }
4031  return &this->stations;
4032 }
4033 
4034 static bool CanMoveGoodsToStation(const Station *st, CargoID type)
4035 {
4036  /* Is the station reserved exclusively for somebody else? */
4037  if (st->owner != OWNER_NONE && st->town->exclusive_counter > 0 && st->town->exclusivity != st->owner) return false;
4038 
4039  /* Lowest possible rating, better not to give cargo anymore. */
4040  if (st->goods[type].rating == 0) return false;
4041 
4042  /* Selectively servicing stations, and not this one. */
4043  if (_settings_game.order.selectgoods && !st->goods[type].HasVehicleEverTriedLoading()) return false;
4044 
4045  if (IsCargoInClass(type, CC_PASSENGERS)) {
4046  /* Passengers are never served by just a truck stop. */
4047  if (st->facilities == FACIL_TRUCK_STOP) return false;
4048  } else {
4049  /* Non-passengers are never served by just a bus stop. */
4050  if (st->facilities == FACIL_BUS_STOP) return false;
4051  }
4052  return true;
4053 }
4054 
4055 uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, SourceID source_id, const StationList *all_stations)
4056 {
4057  /* Return if nothing to do. Also the rounding below fails for 0. */
4058  if (all_stations->empty()) return 0;
4059  if (amount == 0) return 0;
4060 
4061  Station *first_station = nullptr;
4062  typedef std::pair<Station *, uint> StationInfo;
4063  std::vector<StationInfo> used_stations;
4064 
4065  for (Station *st : *all_stations) {
4066  if (!CanMoveGoodsToStation(st, type)) continue;
4067 
4068  /* Avoid allocating a vector if there is only one station to significantly
4069  * improve performance in this common case. */
4070  if (first_station == nullptr) {
4071  first_station = st;
4072  continue;
4073  }
4074  if (used_stations.empty()) {
4075  used_stations.reserve(2);
4076  used_stations.emplace_back(std::make_pair(first_station, 0));
4077  }
4078  used_stations.emplace_back(std::make_pair(st, 0));
4079  }
4080 
4081  /* no stations around at all? */
4082  if (first_station == nullptr) return 0;
4083 
4084  if (used_stations.empty()) {
4085  /* only one station around */
4086  amount *= first_station->goods[type].rating + 1;
4087  return UpdateStationWaiting(first_station, type, amount, source_type, source_id);
4088  }
4089 
4090  uint company_best[OWNER_NONE + 1] = {}; // best rating for each company, including OWNER_NONE
4091  uint company_sum[OWNER_NONE + 1] = {}; // sum of ratings for each company
4092  uint best_rating = 0;
4093  uint best_sum = 0; // sum of best ratings for each company
4094 
4095  for (auto &p : used_stations) {
4096  auto owner = p.first->owner;
4097  auto rating = p.first->goods[type].rating;
4098  if (rating > company_best[owner]) {
4099  best_sum += rating - company_best[owner]; // it's usually faster than iterating companies later
4100  company_best[owner] = rating;
4101  if (rating > best_rating) best_rating = rating;
4102  }
4103  company_sum[owner] += rating;
4104  }
4105 
4106  /* From now we'll calculate with fractional cargo amounts.
4107  * First determine how much cargo we really have. */
4108  amount *= best_rating + 1;
4109 
4110  uint moving = 0;
4111  for (auto &p : used_stations) {
4112  uint owner = p.first->owner;
4113  /* Multiply the amount by (company best / sum of best for each company) to get cargo allocated to a company
4114  * and by (station rating / sum of ratings in a company) to get the result for a single station. */
4115  p.second = amount * company_best[owner] * p.first->goods[type].rating / best_sum / company_sum[owner];
4116  moving += p.second;
4117  }
4118 
4119  /* If there is some cargo left due to rounding issues distribute it among the best rated stations. */
4120  if (amount > moving) {
4121  std::sort(used_stations.begin(), used_stations.end(), [type] (const StationInfo &a, const StationInfo &b) {
4122  return b.first->goods[type].rating < a.first->goods[type].rating;
4123  });
4124 
4125  assert(amount - moving <= used_stations.size());
4126  for (uint i = 0; i < amount - moving; i++) {
4127  used_stations[i].second++;
4128  }
4129  }
4130 
4131  uint moved = 0;
4132  for (auto &p : used_stations) {
4133  moved += UpdateStationWaiting(p.first, type, p.second, source_type, source_id);
4134  }
4135 
4136  return moved;
4137 }
4138 
4139 void UpdateStationDockingTiles(Station *st)
4140 {
4141  st->docking_station.Clear();
4142 
4143  /* For neutral stations, start with the industry area instead of dock area */
4144  const TileArea *area = st->industry != nullptr ? &st->industry->location : &st->ship_station;
4145 
4146  if (area->tile == INVALID_TILE) return;
4147 
4148  int x = TileX(area->tile);
4149  int y = TileY(area->tile);
4150 
4151  /* Expand the area by a tile on each side while
4152  * making sure that we remain inside the map. */
4153  int x2 = min(x + area->w + 1, MapSizeX());
4154  int x1 = max(x - 1, 0);
4155 
4156  int y2 = min(y + area->h + 1, MapSizeY());
4157  int y1 = max(y - 1, 0);
4158 
4159  TileArea ta(TileXY(x1, y1), TileXY(x2 - 1, y2 - 1));
4160  TILE_AREA_LOOP(tile, ta) {
4161  if (IsValidTile(tile) && IsPossibleDockingTile(tile)) CheckForDockingTile(tile);
4162  }
4163 }
4164 
4165 void BuildOilRig(TileIndex tile)
4166 {
4167  if (!Station::CanAllocateItem()) {
4168  DEBUG(misc, 0, "Can't allocate station for oilrig at 0x%X, reverting to oilrig only", tile);
4169  return;
4170  }
4171 
4172  Station *st = new Station(tile);
4173  _station_kdtree.Insert(st->index);
4174  st->town = ClosestTownFromTile(tile, UINT_MAX);
4175 
4176  st->string_id = GenerateStationName(st, tile, STATIONNAMING_OILRIG);
4177 
4178  assert(IsTileType(tile, MP_INDUSTRY));
4179  /* Mark industry as associated both ways */
4180  st->industry = Industry::GetByTile(tile);
4181  st->industry->neutral_station = st;
4182  DeleteAnimatedTile(tile);
4183  MakeOilrig(tile, st->index, GetWaterClass(tile));
4184 
4185  st->owner = OWNER_NONE;
4186  st->airport.type = AT_OILRIG;
4187  st->airport.Add(tile);
4188  st->ship_station.Add(tile);
4190  st->build_date = _date;
4191  UpdateStationDockingTiles(st);
4192 
4193  st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE);
4194 
4195  st->UpdateVirtCoord();
4196  st->RecomputeCatchment();
4197  UpdateStationAcceptance(st, false);
4198 }
4199 
4200 void DeleteOilRig(TileIndex tile)
4201 {
4202  Station *st = Station::GetByTile(tile);
4203 
4204  MakeWaterKeepingClass(tile, OWNER_NONE);
4205 
4206  /* The oil rig station is not supposed to be shared with anything else */
4207  assert(st->facilities == (FACIL_AIRPORT | FACIL_DOCK) && st->airport.type == AT_OILRIG);
4208  if (st->industry != nullptr && st->industry->neutral_station == st) {
4209  /* Don't leave dangling neutral station pointer */
4210  st->industry->neutral_station = nullptr;
4211  }
4212  delete st;
4213 }
4214 
4215 static void ChangeTileOwner_Station(TileIndex tile, Owner old_owner, Owner new_owner)
4216 {
4217  if (IsRoadStopTile(tile)) {
4218  FOR_ALL_ROADTRAMTYPES(rtt) {
4219  /* Update all roadtypes, no matter if they are present */
4220  if (GetRoadOwner(tile, rtt) == old_owner) {
4221  RoadType rt = GetRoadType(tile, rtt);
4222  if (rt != INVALID_ROADTYPE) {
4223  /* A drive-through road-stop has always two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */
4224  Company::Get(old_owner)->infrastructure.road[rt] -= 2;
4225  if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += 2;
4226  }
4227  SetRoadOwner(tile, rtt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner);
4228  }
4229  }
4230  }
4231 
4232  if (!IsTileOwner(tile, old_owner)) return;
4233 
4234  if (new_owner != INVALID_OWNER) {
4235  /* Update company infrastructure counts. Only do it here
4236  * if the new owner is valid as otherwise the clear
4237  * command will do it for us. No need to dirty windows
4238  * here, we'll redraw the whole screen anyway.*/
4239  Company *old_company = Company::Get(old_owner);
4240  Company *new_company = Company::Get(new_owner);
4241 
4242  /* Update counts for underlying infrastructure. */
4243  switch (GetStationType(tile)) {
4244  case STATION_RAIL:
4245  case STATION_WAYPOINT:
4246  if (!IsStationTileBlocked(tile)) {
4247  old_company->infrastructure.rail[GetRailType(tile)]--;
4248  new_company->infrastructure.rail[GetRailType(tile)]++;
4249  }
4250  break;
4251 
4252  case STATION_BUS:
4253  case STATION_TRUCK:
4254  /* Road stops were already handled above. */
4255  break;
4256 
4257  case STATION_BUOY:
4258  case STATION_DOCK:
4259  if (GetWaterClass(tile) == WATER_CLASS_CANAL) {
4260  old_company->infrastructure.water--;
4261  new_company->infrastructure.water++;
4262  }
4263  break;
4264 
4265  default:
4266  break;
4267  }
4268 
4269  /* Update station tile count. */
4270  if (!IsBuoy(tile) && !IsAirport(tile)) {
4271  old_company->infrastructure.station--;
4272  new_company->infrastructure.station++;
4273  }
4274 
4275  /* for buoys, owner of tile is owner of water, st->owner == OWNER_NONE */
4276  SetTileOwner(tile, new_owner);
4278  } else {
4279  if (IsDriveThroughStopTile(tile)) {
4280  /* Remove the drive-through road stop */
4281  DoCommand(tile, 1 | 1 << 8, (GetStationType(tile) == STATION_TRUCK) ? ROADSTOP_TRUCK : ROADSTOP_BUS, DC_EXEC | DC_BANKRUPT, CMD_REMOVE_ROAD_STOP);
4282  assert(IsTileType(tile, MP_ROAD));
4283  /* Change owner of tile and all roadtypes */
4284  ChangeTileOwner(tile, old_owner, new_owner);
4285  } else {
4287  /* Set tile owner of water under (now removed) buoy and dock to OWNER_NONE.
4288  * Update owner of buoy if it was not removed (was in orders).
4289  * Do not update when owned by OWNER_WATER (sea and rivers). */
4290  if ((IsTileType(tile, MP_WATER) || IsBuoyTile(tile)) && IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
4291  }
4292  }
4293 }
4294 
4304 {
4305  /* Yeah... water can always remove stops, right? */
4306  if (_current_company == OWNER_WATER) return true;
4307 
4308  if (GetRoadTypeTram(tile) != INVALID_ROADTYPE) {
4309  Owner tram_owner = GetRoadOwner(tile, RTT_TRAM);
4310  if (tram_owner != OWNER_NONE && CheckOwnership(tram_owner).Failed()) return false;
4311  }
4312  if (GetRoadTypeRoad(tile) != INVALID_ROADTYPE) {
4313  Owner road_owner = GetRoadOwner(tile, RTT_ROAD);
4314  if (road_owner != OWNER_TOWN) {
4315  if (road_owner != OWNER_NONE && CheckOwnership(road_owner).Failed()) return false;
4316  } else {
4317  if (CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, RTT_ROAD), OWNER_TOWN, RTT_ROAD, flags).Failed()) return false;
4318  }
4319  }
4320 
4321  return true;
4322 }
4323 
4331 {
4332  if (flags & DC_AUTO) {
4333  switch (GetStationType(tile)) {
4334  default: break;
4335  case STATION_RAIL: return_cmd_error(STR_ERROR_MUST_DEMOLISH_RAILROAD);
4336  case STATION_WAYPOINT: return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
4337  case STATION_AIRPORT: return_cmd_error(STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST);
4338  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);
4339  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);
4340  case STATION_BUOY: return_cmd_error(STR_ERROR_BUOY_IN_THE_WAY);
4341  case STATION_DOCK: return_cmd_error(STR_ERROR_MUST_DEMOLISH_DOCK_FIRST);
4342  case STATION_OILRIG:
4343  SetDParam(1, STR_INDUSTRY_NAME_OIL_RIG);
4344  return_cmd_error(STR_ERROR_GENERIC_OBJECT_IN_THE_WAY);
4345  }
4346  }
4347 
4348  switch (GetStationType(tile)) {
4349  case STATION_RAIL: return RemoveRailStation(tile, flags);
4350  case STATION_WAYPOINT: return RemoveRailWaypoint(tile, flags);
4351  case STATION_AIRPORT: return RemoveAirport(tile, flags);
4352  case STATION_TRUCK:
4353  if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) {
4354  return_cmd_error(STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST);
4355  }
4356  return RemoveRoadStop(tile, flags);
4357  case STATION_BUS:
4358  if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) {
4359  return_cmd_error(STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST);
4360  }
4361  return RemoveRoadStop(tile, flags);
4362  case STATION_BUOY: return RemoveBuoy(tile, flags);
4363  case STATION_DOCK: return RemoveDock(tile, flags);
4364  default: break;
4365  }
4366 
4367  return CMD_ERROR;
4368 }
4369 
4370 static CommandCost TerraformTile_Station(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
4371 {
4373  /* TODO: If you implement newgrf callback 149 'land slope check', you have to decide what to do with it here.
4374  * TTDP does not call it.
4375  */
4376  if (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new)) {
4377  switch (GetStationType(tile)) {
4378  case STATION_WAYPOINT:
4379  case STATION_RAIL: {
4380  DiagDirection direction = AxisToDiagDir(GetRailStationAxis(tile));
4381  if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, direction)) break;
4382  if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, ReverseDiagDir(direction))) break;
4383  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
4384  }
4385 
4386  case STATION_AIRPORT:
4387  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
4388 
4389  case STATION_TRUCK:
4390  case STATION_BUS: {
4391  DiagDirection direction = GetRoadStopDir(tile);
4392  if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, direction)) break;
4393  if (IsDriveThroughStopTile(tile)) {
4394  if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, ReverseDiagDir(direction))) break;
4395  }
4396  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
4397  }
4398 
4399  default: break;
4400  }
4401  }
4402  }
4403  return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
4404 }
4405 
4411 uint FlowStat::GetShare(StationID st) const
4412 {
4413  uint32 prev = 0;
4414  for (SharesMap::const_iterator it = this->shares.begin(); it != this->shares.end(); ++it) {
4415  if (it->second == st) {
4416  return it->first - prev;
4417  } else {
4418  prev = it->first;
4419  }
4420  }
4421  return 0;
4422 }
4423 
4430 StationID FlowStat::GetVia(StationID excluded, StationID excluded2) const
4431 {
4432  if (this->unrestricted == 0) return INVALID_STATION;
4433  assert(!this->shares.empty());
4434  SharesMap::const_iterator it = this->shares.upper_bound(RandomRange(this->unrestricted));
4435  assert(it != this->shares.end() && it->first <= this->unrestricted);
4436  if (it->second != excluded && it->second != excluded2) return it->second;
4437 
4438  /* We've hit one of the excluded stations.
4439  * Draw another share, from outside its range. */
4440 
4441  uint end = it->first;
4442  uint begin = (it == this->shares.begin() ? 0 : (--it)->first);
4443  uint interval = end - begin;
4444  if (interval >= this->unrestricted) return INVALID_STATION; // Only one station in the map.
4445  uint new_max = this->unrestricted - interval;
4446  uint rand = RandomRange(new_max);
4447  SharesMap::const_iterator it2 = (rand < begin) ? this->shares.upper_bound(rand) :
4448  this->shares.upper_bound(rand + interval);
4449  assert(it2 != this->shares.end() && it2->first <= this->unrestricted);
4450  if (it2->second != excluded && it2->second != excluded2) return it2->second;
4451 
4452  /* We've hit the second excluded station.
4453  * Same as before, only a bit more complicated. */
4454 
4455  uint end2 = it2->first;
4456  uint begin2 = (it2 == this->shares.begin() ? 0 : (--it2)->first);
4457  uint interval2 = end2 - begin2;
4458  if (interval2 >= new_max) return INVALID_STATION; // Only the two excluded stations in the map.
4459  new_max -= interval2;
4460  if (begin > begin2) {
4461  Swap(begin, begin2);
4462  Swap(end, end2);
4463  Swap(interval, interval2);
4464  }
4465  rand = RandomRange(new_max);
4466  SharesMap::const_iterator it3 = this->shares.upper_bound(this->unrestricted);
4467  if (rand < begin) {
4468  it3 = this->shares.upper_bound(rand);
4469  } else if (rand < begin2 - interval) {
4470  it3 = this->shares.upper_bound(rand + interval);
4471  } else {
4472  it3 = this->shares.upper_bound(rand + interval + interval2);
4473  }
4474  assert(it3 != this->shares.end() && it3->first <= this->unrestricted);
4475  return it3->second;
4476 }
4477 
4484 {
4485  assert(!this->shares.empty());
4486  SharesMap new_shares;
4487  uint i = 0;
4488  for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) {
4489  new_shares[++i] = it->second;
4490  if (it->first == this->unrestricted) this->unrestricted = i;
4491  }
4492  this->shares.swap(new_shares);
4493  assert(!this->shares.empty() && this->unrestricted <= (--this->shares.end())->first);
4494 }
4495 
4502 void FlowStat::ChangeShare(StationID st, int flow)
4503 {
4504  /* We assert only before changing as afterwards the shares can actually
4505  * be empty. In that case the whole flow stat must be deleted then. */
4506  assert(!this->shares.empty());
4507 
4508  uint removed_shares = 0;
4509  uint added_shares = 0;
4510  uint last_share = 0;
4511  SharesMap new_shares;
4512  for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) {
4513  if (it->second == st) {
4514  if (flow < 0) {
4515  uint share = it->first - last_share;
4516  if (flow == INT_MIN || (uint)(-flow) >= share) {
4517  removed_shares += share;
4518  if (it->first <= this->unrestricted) this->unrestricted -= share;
4519  if (flow != INT_MIN) flow += share;
4520  last_share = it->first;
4521  continue; // remove the whole share
4522  }
4523  removed_shares += (uint)(-flow);
4524  } else {
4525  added_shares += (uint)(flow);
4526  }
4527  if (it->first <= this->unrestricted) this->unrestricted += flow;
4528 
4529  /* If we don't continue above the whole flow has been added or
4530  * removed. */
4531  flow = 0;
4532  }
4533  new_shares[it->first + added_shares - removed_shares] = it->second;
4534  last_share = it->first;
4535  }
4536  if (flow > 0) {
4537  new_shares[last_share + (uint)flow] = st;
4538  if (this->unrestricted < last_share) {
4539  this->ReleaseShare(st);
4540  } else {
4541  this->unrestricted += flow;
4542  }
4543  }
4544  this->shares.swap(new_shares);
4545 }
4546 
4552 void FlowStat::RestrictShare(StationID st)
4553 {
4554  assert(!this->shares.empty());
4555  uint flow = 0;
4556  uint last_share = 0;
4557  SharesMap new_shares;
4558  for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) {
4559  if (flow == 0) {
4560  if (it->first > this->unrestricted) return; // Not present or already restricted.
4561  if (it->second == st) {
4562  flow = it->first - last_share;
4563  this->unrestricted -= flow;
4564  } else {
4565  new_shares[it->first] = it->second;
4566  }
4567  } else {
4568  new_shares[it->first - flow] = it->second;
4569  }
4570  last_share = it->first;
4571  }
4572  if (flow == 0) return;
4573  new_shares[last_share + flow] = st;
4574  this->shares.swap(new_shares);
4575  assert(!this->shares.empty());
4576 }
4577 
4583 void FlowStat::ReleaseShare(StationID st)
4584 {
4585  assert(!this->shares.empty());
4586  uint flow = 0;
4587  uint next_share = 0;
4588  bool found = false;
4589  for (SharesMap::reverse_iterator it(this->shares.rbegin()); it != this->shares.rend(); ++it) {
4590  if (it->first < this->unrestricted) return; // Note: not <= as the share may hit the limit.
4591  if (found) {
4592  flow = next_share - it->first;
4593  this->unrestricted += flow;
4594  break;
4595  } else {
4596  if (it->first == this->unrestricted) return; // !found -> Limit not hit.
4597  if (it->second == st) found = true;
4598  }
4599  next_share = it->first;
4600  }
4601  if (flow == 0) return;
4602  SharesMap new_shares;
4603  new_shares[flow] = st;
4604  for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) {
4605  if (it->second != st) {
4606  new_shares[flow + it->first] = it->second;
4607  } else {
4608  flow = 0;
4609  }
4610  }
4611  this->shares.swap(new_shares);
4612  assert(!this->shares.empty());
4613 }
4614 
4620 void FlowStat::ScaleToMonthly(uint runtime)
4621 {
4622  assert(runtime > 0);
4623  SharesMap new_shares;
4624  uint share = 0;
4625  for (SharesMap::iterator i = this->shares.begin(); i != this->shares.end(); ++i) {
4626  share = max(share + 1, i->first * 30 / runtime);
4627  new_shares[share] = i->second;
4628  if (this->unrestricted == i->first) this->unrestricted = share;
4629  }
4630  this->shares.swap(new_shares);
4631 }
4632 
4639 void FlowStatMap::AddFlow(StationID origin, StationID via, uint flow)
4640 {
4641  FlowStatMap::iterator origin_it = this->find(origin);
4642  if (origin_it == this->end()) {
4643  this->insert(std::make_pair(origin, FlowStat(via, flow)));
4644  } else {
4645  origin_it->second.ChangeShare(via, flow);
4646  assert(!origin_it->second.GetShares()->empty());
4647  }
4648 }
4649 
4658 void FlowStatMap::PassOnFlow(StationID origin, StationID via, uint flow)
4659 {
4660  FlowStatMap::iterator prev_it = this->find(origin);
4661  if (prev_it == this->end()) {
4662  FlowStat fs(via, flow);
4663  fs.AppendShare(INVALID_STATION, flow);
4664  this->insert(std::make_pair(origin, fs));
4665  } else {
4666  prev_it->second.ChangeShare(via, flow);
4667  prev_it->second.ChangeShare(INVALID_STATION, flow);
4668  assert(!prev_it->second.GetShares()->empty());
4669  }
4670 }
4671 
4677 {
4678  for (FlowStatMap::iterator i = this->begin(); i != this->end(); ++i) {
4679  FlowStat &fs = i->second;
4680  uint local = fs.GetShare(INVALID_STATION);
4681  if (local > INT_MAX) { // make sure it fits in an int
4682  fs.ChangeShare(self, -INT_MAX);
4683  fs.ChangeShare(INVALID_STATION, -INT_MAX);
4684  local -= INT_MAX;
4685  }
4686  fs.ChangeShare(self, -(int)local);
4687  fs.ChangeShare(INVALID_STATION, -(int)local);
4688 
4689  /* If the local share is used up there must be a share for some
4690  * remote station. */
4691  assert(!fs.GetShares()->empty());
4692  }
4693 }
4694 
4702 {
4703  StationIDStack ret;
4704  for (FlowStatMap::iterator f_it = this->begin(); f_it != this->end();) {
4705  FlowStat &s_flows = f_it->second;
4706  s_flows.ChangeShare(via, INT_MIN);
4707  if (s_flows.GetShares()->empty()) {
4708  ret.Push(f_it->first);
4709  this->erase(f_it++);
4710  } else {
4711  ++f_it;
4712  }
4713  }
4714  return ret;
4715 }
4716 
4721 void FlowStatMap::RestrictFlows(StationID via)
4722 {
4723  for (FlowStatMap::iterator it = this->begin(); it != this->end(); ++it) {
4724  it->second.RestrictShare(via);
4725  }
4726 }
4727 
4732 void FlowStatMap::ReleaseFlows(StationID via)
4733 {
4734  for (FlowStatMap::iterator it = this->begin(); it != this->end(); ++it) {
4735  it->second.ReleaseShare(via);
4736  }
4737 }
4738 
4744 {
4745  uint ret = 0;
4746  for (FlowStatMap::const_iterator i = this->begin(); i != this->end(); ++i) {
4747  ret += (--(i->second.GetShares()->end()))->first;
4748  }
4749  return ret;
4750 }
4751 
4757 uint FlowStatMap::GetFlowVia(StationID via) const
4758 {
4759  uint ret = 0;
4760  for (FlowStatMap::const_iterator i = this->begin(); i != this->end(); ++i) {
4761  ret += i->second.GetShare(via);
4762  }
4763  return ret;
4764 }
4765 
4771 uint FlowStatMap::GetFlowFrom(StationID from) const
4772 {
4773  FlowStatMap::const_iterator i = this->find(from);
4774  if (i == this->end()) return 0;
4775  return (--(i->second.GetShares()->end()))->first;
4776 }
4777 
4784 uint FlowStatMap::GetFlowFromVia(StationID from, StationID via) const
4785 {
4786  FlowStatMap::const_iterator i = this->find(from);
4787  if (i == this->end()) return 0;
4788  return i->second.GetShare(via);
4789 }
4790 
4791 extern const TileTypeProcs _tile_type_station_procs = {
4792  DrawTile_Station, // draw_tile_proc
4793  GetSlopePixelZ_Station, // get_slope_z_proc
4794  ClearTile_Station, // clear_tile_proc
4795  nullptr, // add_accepted_cargo_proc
4796  GetTileDesc_Station, // get_tile_desc_proc
4797  GetTileTrackStatus_Station, // get_tile_track_status_proc
4798  ClickTile_Station, // click_tile_proc
4799  AnimateTile_Station, // animate_tile_proc
4800  TileLoop_Station, // tile_loop_proc
4801  ChangeTileOwner_Station, // change_tile_owner_proc
4802  nullptr, // add_produced_cargo_proc
4803  VehicleEnter_Station, // vehicle_enter_tile_proc
4804  GetFoundation_Station, // get_foundation_proc
4805  TerraformTile_Station, // terraform_tile_proc
4806 };
Town * AirportGetNearestTown(const AirportSpec *as, const TileIterator &it, uint &mindist)
Finds the town nearest to given airport.
Functions related to OTTD&#39;s strings.
void TriggerStationRandomisation(Station *st, TileIndex tile, StationRandomTrigger trigger, CargoID cargo_type)
Trigger station randomisation.
SourceType
Types of cargo source and destination.
Definition: cargo_type.h:146
Owner
Enum for all companies/owners.
Definition: company_type.h:18
List of scheduled road vehs button.
Road vehicle states.
don&#39;t allow building on structures
Definition: command_type.h:347
Iterator to iterate over all tiles belonging to a bitmaptilearea.
Definition: bitmap_type.h:107
static void MakeRailStation(TileIndex t, Owner o, StationID sid, Axis a, byte section, RailType rt)
Make the given tile a rail station tile.
Definition: station_map.h:557
EdgeIterator Begin()
Get an iterator pointing to the start of the edges array.
Definition: linkgraph.h:395
void ChangeTileOwner(TileIndex tile, Owner old_owner, Owner new_owner)
Change the owner of a tile.
Definition: landscape.cpp:600
static 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:332
Functions/types related to NewGRF debugging.
static void Swap(T &a, T &b)
Type safe swap operation.
Definition: math_func.hpp:275
byte type
Type of this airport,.
Definition: station_base.h:309
uint32 PaletteID
The number of the palette.
Definition: gfx_type.h:18
StationFacility facilities
The facilities that this station has.
static void MakeDock(TileIndex t, Owner o, StationID sid, DiagDirection d, WaterClass wc)
Make the given tile a dock tile.
Definition: station_map.h:653
void AddTrackToSignalBuffer(TileIndex tile, Track track, Owner owner)
Add track to signal update buffer.
Definition: signal.cpp:580
struct RailtypeInfo::@36 base_sprites
Struct containing the main sprites.
VehicleCargoList cargo
The cargo this vehicle is carrying.
Definition: vehicle_base.h:307
static uint MapSizeX()
Get the size of the map along the X.
Definition: map_func.h:72
byte state
Definition: roadveh.h:109
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:80
Definition of stuff that is very close to a company, like the company struct itself.
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 Titem * GetIfValid(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:340
NodeID AddNode(const Station *st)
Add a node to the component and create empty edges associated with it.
Definition: linkgraph.cpp:158
void ShowWaypointWindow(const Waypoint *wp)
Show the window for the given waypoint.
Use callback to select a sprite layout to use.
Increase capacity.
static void SetCustomStationSpecIndex(TileIndex t, byte specindex)
Set the custom station spec for this tile.
Definition: station_map.h:481
bool enabled
entity still available (by default true).newgrf can disable it, though
Definition: industrytype.h:139
bool IsAvailable() const
Check whether this airport is available to build.
static bool FindNearIndustryName(TileIndex tile, void *user_data)
Find a station action 0 property 24 station name, or reduce the free_names if needed.
NewGRF handling of rail types.
static const RailtypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition: rail.h:304
static TropicZone GetTropicZone(TileIndex tile)
Get the tropic zone.
Definition: tile_map.h:238
Select station (when joining stations); Window numbers:
Definition: window_type.h:235
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
No track build.
Definition: track_type.h:102
static void SetAnimationFrame(TileIndex t, byte frame)
Set a new animation frame.
Definition: tile_map.h:262
A standard stop for trucks.
Definition: station_type.h:46
static const uint COMPRESSION_INTERVAL
Minimum number of days between subsequent compressions of a LG.
Definition: linkgraph.h:443
static uint MapSizeY()
Get the size of the map along the Y.
Definition: map_func.h:82
static bool IsCustomStationSpecIndex(TileIndex t)
Is there a custom rail station spec on this tile?
Definition: station_map.h:469
void ClearDockingTilesCheckingNeighbours(TileIndex tile)
Clear docking tile status from tiles around a removed dock, if the tile has no neighbours which would...
Direction direction
facing
Definition: vehicle_base.h:269
Non-existing type of vehicle.
Definition: vehicle_type.h:35
const AirportSpec * GetSpec() const
Get the AirportSpec that from the airport type of this airport.
Definition: station_base.h:320
static void SetTileOwner(TileIndex tile, Owner owner)
Sets the owner of a tile.
Definition: tile_map.h:198
Tile information, used while rendering the tile.
Definition: tile_cmd.h:42
TileArea bus_station
Tile area the bus &#39;station&#39; part covers.
Definition: station_base.h:460
CompanyMask statues
which companies have a statue?
Definition: town.h:69
Definition of link refreshing utility.
Waypoint class.
Direction rotation
How this airport is rotated.
Definition: station_base.h:311
Minimal stack that uses a pool to avoid pointers.
void DeallocateSpecFromStation(BaseStation *st, byte specindex)
Deallocate a StationSpec from a Station.
Some typedefs for the main game.
const AirportFTAClass * GetAirport(const byte airport_type)
Get the finite state machine of an airport type.
Definition: airport.cpp:207
void TileLoop_Water(TileIndex tile)
Let a water tile floods its diagonal adjoining tiles called from tunnelbridge_cmd, and by TileLoop_Industry() and TileLoop_Track()
Definition: water_cmd.cpp:1206
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition: window.cpp:3218
TileArea ship_station
Tile area the ship &#39;station&#39; part covers.
Definition: station_base.h:465
static DiagDirection DirToDiagDir(Direction dir)
Convert a Direction to a DiagDirection.
byte landscape
the landscape we&#39;re currently in
Reference station. Scroll to station when clicking on the news. Delete news when station is deleted...
Definition: news_type.h:53
void AddAnimatedTile(TileIndex tile)
Add the given tile to the animated tile table (if it does not exist on that table yet)...
byte size_y
size of airport in y direction
Iterator to iterate over all tiles belonging to an airport.
Definition: station_base.h:529
company buildings - depots, stations, HQ, ...
Definition: transparency.h:27
Base class for roadstops.
static bool IsReversingRoadTrackdir(Trackdir dir)
Checks whether the trackdir means that we are reversing.
Definition: track_func.h:681
Tile is desert.
Definition: tile_type.h:71
Track along the x-axis (north-east to south-west)
Definition: track_type.h:21
void Queue(LinkGraph *lg)
Queue a link graph for execution.
Date LastUnrestrictedUpdate() const
Get the date of the last update to the edge&#39;s unrestricted capacity.
Definition: linkgraph.h:103
bool HasVehicleEverTriedLoading() const
Reports whether a vehicle has ever tried to load the cargo at this station.
Definition: station_base.h:267
All possible tracks.
Definition: track_type.h:53
An invalid owner.
Definition: company_type.h:29
uint16 triggers
The triggers that trigger animation.
uint GetNumHangars() const
Get the number of hangars on this airport.
Definition: station_base.h:410
static CommandCost CheckFlatLandAirport(AirportTileTableIterator tile_iter, DoCommandFlag flags)
Checks if an airport can be built at the given location and clear the area.
static bool IsRailStation(TileIndex t)
Is this station tile a rail station?
Definition: station_map.h:92
Part of an industry.
Definition: tile_type.h:49
RoadBits GetAnyRoadBits(TileIndex tile, RoadTramType rtt, bool straight_tunnel_bridge_entrance)
Returns the RoadBits on an arbitrary tile Special behaviour:
Definition: road_map.cpp:33
EconomySettings economy
settings to change the economy
static RoadBits GetAllRoadBits(TileIndex tile)
Get all set RoadBits on the given tile.
Definition: road_map.h:140
static RoadStopType GetRoadStopType(TileIndex t)
Get the road stop type of this tile.
Definition: station_map.h:56
CommandCost EnsureNoVehicleOnGround(TileIndex tile)
Ensure there is no vehicle at the ground at the given position.
Definition: vehicle.cpp:537
int32 TileIndexDiff
An offset value between to tiles.
Definition: map_func.h:154
static bool IsWater(TileIndex t)
Is it a plain water tile?
Definition: water_map.h:141
Train vehicle type.
Definition: vehicle_type.h:24
virtual TileIterator * Clone() const =0
Allocate a new iterator that is a copy of this one.
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:329
static Station * GetClosestDeletedStation(TileIndex tile)
Find the closest deleted station of the current company.
static RoadStop ** FindRoadStopSpot(bool truck_station, Station *st)
void Unqueue(LinkGraph *lg)
Remove a link graph from the execution queue.
Functions related to dates.
static WaterClass GetWaterClass(TileIndex t)
Get the water class at a tile.
Definition: water_map.h:106
const char * grf
newGRF used for the tile contents
Definition: tile_cmd.h:61
uint GetSpecCount() const
Get the number of allocated specs within the class.
Definition: newgrf_class.h:44
Northwest.
static const AirportTileSpec * GetByTile(TileIndex tile)
Retrieve airport tile spec for the given airport tile.
West.
static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags)
Remove an airport.
Base for the train class.
The vehicle is in a drive-through road stop.
Definition: roadveh.h:47
CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, CargoTypes *always_accepted)
Get the acceptance of cargoes around the tile in 1/8.
static byte GetAnimationFrame(TileIndex t)
Get the current animation frame.
Definition: tile_map.h:250
static bool HasTileRoadType(TileIndex t, RoadTramType rtt)
Check if a tile has a road or a tram road type.
Definition: road_map.h:210
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.
Left track.
Definition: track_type.h:44
Used for iterations.
Functions related to debugging.
static T SetBit(T &x, const uint8 y)
Set a bit in a variable.
Trackdir
Enumeration for tracks and directions.
Definition: track_type.h:70
void DrawRoadCatenary(const TileInfo *ti)
Draws the catenary for the given tile.
Definition: road_cmd.cpp:1433
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...
Can planes land on this airport type?
Definition: airport.h:147
uint16 cur_speed
current speed
Definition: vehicle_base.h:291
A tile with road (or tram tracks)
Definition: tile_type.h:43
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
Definition: command_func.h:23
bool distant_join_stations
allow to join non-adjacent stations
Ship vehicle type.
Definition: vehicle_type.h:26
static TrackBits AxisToTrackBits(Axis a)
Maps an Axis to the corresponding TrackBits value.
Definition: track_func.h:96
Depot view; Window numbers:
Definition: window_type.h:344
Slope tileh
Slope of the tile.
Definition: tile_cmd.h:45
Maximal number of cargo types in a game.
Definition: cargo_type.h:64
Full road along the x-axis (south-west + north-east)
Definition: road_type.h:56
Set when cargo was delivered for final delivery during the current STATION_ACCEPTANCE_TICKS interval...
Definition: station_base.h:211
Functions used internally by the roads.
A town owns the tile, or a town is expanding.
Definition: company_type.h:24
Flag for invalid railtype.
Definition: rail_type.h:34
Specification of a cargo type.
Definition: cargotype.h:55
SpriteID GetCanalSprite(CanalFeature feature, TileIndex tile)
Lookup the base sprite to use for a canal.
Station specification.
bool IsInUse() const
Check whether the base station currently is in use; in use means that it is not scheduled for deletio...
IndustryLifeType life_type
This is also known as Industry production flag, in newgrf specs.
Definition: industrytype.h:122
TileIndex dest_tile
Heading for this tile.
Definition: vehicle_base.h:235
bool ValParamRailtype(const RailType rail)
Validate functions for rail building.
Definition: rail.cpp:206
void MakeDriveThrough()
Join this road stop to another &#39;base&#39; road stop if possible; fill all necessary data to become an act...
Definition: roadstop.cpp:62
static bool IsRoadStop(TileIndex t)
Is the station at t a road station?
Definition: station_map.h:202
Transport over water.
StringID tramtype
Type of tram on the tile.
Definition: tile_cmd.h:67
X-axis track.
Definition: track_type.h:40
OrthogonalTileArea & Expand(int rad)
Expand a tile area by rad tiles in each direction, keeping within map bounds.
Definition: tilearea.cpp:123
Functions related to vehicles.
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition: aircraft.h:74
Set when cargo was delivered for final delivery this month.
Definition: station_base.h:205
static const uint INVALID_AIRPORTTILE
id for an invalid airport tile
Definition: airport.h:25
static bool HasTileWaterGround(TileIndex t)
Checks whether the tile has water at the ground.
Definition: water_map.h:344
static DiagDirection GetDockDirection(TileIndex t)
Get the direction of a dock.
Definition: station_map.h:429
Trigger tile when built.
Information to handle station action 0 property 24 correctly.
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition: map_func.h:205
A standard stop for buses.
Definition: station_type.h:45
TileArea train_station
Tile area the train &#39;station&#39; part covers.
static bool CMSATree(TileIndex tile)
Check whether the tile is a tree.
Vehicle data structure.
Definition: vehicle_base.h:210
static bool IsExpected(const BaseStation *st)
Helper for checking whether the given station is of this type.
static void MakeOilrig(TileIndex t, StationID sid, WaterClass wc)
Make the given tile an oilrig tile.
Definition: station_map.h:665
byte station_spread
amount a station may spread
static int GetSlopeMaxZ(Slope s)
Returns the height of the highest corner of a slope relative to TileZ (= minimal height) ...
Definition: slope_func.h:160
StationIDStack DeleteFlows(StationID via)
Delete all flows at a station for specific cargo and destination.
uint8 GetAirportNoiseLevelForDistance(const AirportSpec *as, uint distance)
Get a possible noise reduction factor based on distance from town center.
StationRect rect
NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions.
Iterator to iterate over all tiles belonging to an airport spec.
uint GetFlowVia(StationID via) const
Get the sum of flows via a specific station from this FlowStatMap.
Defines the internal data of a functional industry.
Definition: industry.h:40
Tile description for the &#39;land area information&#39; tool.
Definition: tile_cmd.h:51
demolish a tile
Definition: command_type.h:180
DifficultySettings difficulty
settings related to the difficulty
Stores station stats for a single cargo.
Definition: station_base.h:170
Tindex index
Index of this pool item.
Definition: pool_type.hpp:227
Vehicle is flying in the air.
Definition: airport.h:75
flag for invalid roadtype
Definition: road_type.h:27
static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags)
Remove a dock.
static StationGfx GetAirportGfx(TileIndex t)
Get the station graphics of this airport tile.
Definition: station_map.h:244
Manual distribution. No link graph calculations are run.
Draw custom foundations.
void ReleaseFlows(StationID via)
Release all flows at a station for specific cargo and destination.
static bool IsSteepSlope(Slope s)
Checks if a slope is steep.
Definition: slope_func.h:36
Declarations for accessing the k-d tree of stations.
static void FreeTrainReservation(Train *v)
Clear platform reservation during station building/removing.
void RecomputeCatchment()
Recompute tiles covered in our catchment area.
Definition: station.cpp:408
Helper functions to extract data from command parameters.
void PassOnFlow(StationID origin, StationID via, uint amount)
Pass on some flow, remembering it as invalid, for later subtraction from locally consumed flow...
const DrawTileSeqStruct * GetLayout(PalSpriteID *ground) const
Returns the result spritelayout after preprocessing.
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.
Base for aircraft.
void FinalizeLocalConsumption(StationID self)
Subtract invalid flows from locally consumed flow.
Representation of a waypoint.
Definition: waypoint_base.h:16
#define lastof(x)
Get the last element of an fixed size array.
Definition: depend.cpp:48
void MoveSign(TileIndex new_xy) override
Move the station main coordinate somewhere else.
Required: Drive-in stop surface.
Definition: road.h:68
void MarkTilesDirty(bool cargo_change) const
Marks the tiles of the station as dirty.
Definition: station.cpp:218
static 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:74
static Pool::IterateWrapper< Station > Iterate(size_t from=0)
Returns an iterable ensemble of all valid stations of type T.
static Track GetRailStationTrack(TileIndex t)
Get the rail track of a rail station tile.
Definition: station_map.h:349
CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st)
Find a nearby station that joins this station.
Construction costs.
Definition: economy_type.h:149
uint32 station
Count of company owned station tiles.
Definition: company_base.h:34
#define FOR_EACH_SET_BIT(bitpos_var, bitset_value)
Do an operation for each set set bit in a value.
Flag for an invalid DiagDirection.
#define AllocaM(T, num_elements)
alloca() has to be called in the parent function, so define AllocaM() as a macro
Definition: alloc_func.hpp:132
Common return value for all commands.
Definition: command_type.h:23
static bool IsStandardRoadStopTile(TileIndex t)
Is tile t a standard (non-drive through) road stop station?
Definition: station_map.h:223
static bool HasExactlyOneBit(T value)
Test whether value has exactly 1 bit set.
void StartSpriteCombine()
Starts a block of sprites, which are "combined" into a single bounding box.
Definition: viewport.cpp:757
RoadType
The different roadtypes we support.
Definition: road_type.h:22
StationCargoList cargo
The cargo packets of cargo waiting in this station.
Definition: station_base.h:255
static T max(const T a, const T b)
Returns the maximum of two values.
Definition: math_func.hpp:24
uint16 classes
Classes of this cargo type.
Definition: cargotype.h:78
static bool IsDriveThroughStopTile(TileIndex t)
Is tile t a drive through road stop station?
Definition: station_map.h:233
Town * town
The town this station is associated with.
void ForAllStationsRadius(TileIndex center, uint radius, Func func)
Call a function on all stations whose sign is within a radius of a center tile.
bool HasRating() const
Does this cargo have a rating at this station?
Definition: station_base.h:273
byte vehstatus
Status.
Definition: vehicle_base.h:315
uint8 status
Status; 0: no looping, 1: looping, 0xFF: no animation.
static DiagDirection TrackdirToExitdir(Trackdir trackdir)
Maps a trackdir to the (4-way) direction the tile is exited when following that trackdir.
Definition: track_func.h:447
uint GetFlowFrom(StationID from) const
Get the sum of flows from a specific station from this FlowStatMap.
struct RailtypeInfo::@39 strings
Strings associated with the rail type.
uint tiles
Number of tile layouts.
uint StoredCount() const
Returns sum of cargo on board the vehicle (ie not only reserved).
Definition: cargopacket.h:351
uint16 w
The width of the area.
Definition: tilearea_type.h:18
static RoadVehicle * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
Mail.
Definition: cargotype.h:40
bool IsTileFlat(TileIndex tile, int *h)
Check if a given tile is flat.
Definition: tile_map.cpp:100
void Clear()
Clears the &#39;tile area&#39;, i.e.
Definition: tilearea_type.h:38
Determine whether a newstation should be made available to build.
The vehicle entered a station.
Definition: tile_cmd.h:35
static Slope GetFoundationPixelSlope(TileIndex tile, int *z)
Get slope of a tile on top of a (possible) foundation If a tile does not have a foundation, the function returns the same as GetTilePixelSlope.
Definition: landscape.h:66
std::set< Station *, StationCompare > StationList
List of stations.
Definition: station_type.h:94
uint16 noise_reached
level of noise that all the airports are generating
Definition: town.h:67
a flat tile
Definition: slope_type.h:49
uint16 rail_speed
Speed limit of rail (bridges and track)
Definition: tile_cmd.h:64
byte nof_depots
the number of hangar tiles in this airport
int z
Height.
Definition: tile_cmd.h:47
static StationType GetStationType(TileIndex t)
Get the station type of this tile.
Definition: station_map.h:44
StationSettings station
settings related to station management
GoodsEntry goods[NUM_CARGO]
Goods at this station.
Definition: station_base.h:479
static const uint TILE_SIZE
Tile size in world coordinates.
Definition: tile_type.h:13
static CommandCost RemoveRailWaypoint(TileIndex tile, DoCommandFlag flags)
Remove a rail waypoint.
static uint32 RandomRange(uint32 limit)
Pick a random number between 0 and limit - 1, inclusive.
Definition: random_func.hpp:81
RoadStopType
Types of RoadStops.
Definition: station_type.h:44
void DrawFoundation(TileInfo *ti, Foundation f)
Draw foundation f at tile ti.
Definition: landscape.cpp:470
void AddCost(const Money &cost)
Adds the given cost to the cost of the command.
Definition: command_type.h:62
Owner owner[4]
Name of the owner(s)
Definition: tile_cmd.h:53
StringID name
Displayed name of the industry.
Definition: industrytype.h:126
void UpdateStationAcceptance(Station *st, bool show_msg)
Update the acceptance for a station.
static T SB(T &x, const uint8 s, const uint8 n, const U d)
Set n bits in x starting at bit s to d.
static uint GetCustomStationSpecIndex(TileIndex t)
Get the custom station spec for this tile.
Definition: station_map.h:493
StationList stations_near
NOSAVE: List of nearby stations.
Definition: industry.h:64
const DrawTileSeqStruct * seq
Array of child sprites. Terminated with a terminator entry.
Definition: sprite.h:60
const AirportTileTable *const * table
list of the tiles composing the airport
CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Build a bus or truck stop.
void YapfNotifyTrackLayoutChange(TileIndex tile, Track track)
Use this function to notify YAPF that track layout (or signal configuration) has change.
Definition: yapf_rail.cpp:642
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.
static Station * From(BaseStation *st)
Converts a BaseStation to SpecializedStation with type checking.
char * GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index, bool game_script)
Get a parsed string with most special stringcodes replaced by the string parameters.
Definition: strings.cpp:216
static uint ClampU(const uint a, const uint min, const uint max)
Clamp an unsigned integer between an interval.
Definition: math_func.hpp:182
This struct contains all the info that is needed to draw and construct tracks.
Definition: rail.h:124
CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags)
Clear a single tile of a station.
static CargoArray GetAcceptanceAroundStation(const Station *st, CargoTypes *always_accepted)
Get the acceptance of cargoes around the station in.
uint32 free_names
Current bitset of free names (we can remove names).
byte delete_ctr
Delete counter. If greater than 0 then it is decremented until it reaches 0; the waypoint is then is ...
Order * next
Pointer to next order. If nullptr, end of list.
Definition: order_base.h:49
Right track.
Definition: track_type.h:45
bool selectgoods
only send the goods to station if a train has been there
int GetTileZ(TileIndex tile)
Get bottom height of the tile.
Definition: tile_map.cpp:121
company bankrupts, skip money check, skip vehicle on tile check in some cases
Definition: command_type.h:352
Functions related to (drawing on) viewports.
Pseudo random number generator.
void TriggerWatchedCargoCallbacks(Station *st)
Run the watched cargo callback for all houses in the catchment area.
A connected component of a link graph.
Definition: linkgraph.h:38
static bool HasStationRail(TileIndex 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
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:256
CommandCost CanExpandRailStation(const BaseStation *st, TileArea &new_ta, Axis axis)
Check whether we can expand the rail part of the given station.
Invalid cargo type.
Definition: cargo_type.h:68
Set when cargo was delivered for final delivery last month.
Definition: station_base.h:199
Slope GetTileSlope(TileIndex tile, int *h)
Return the slope of a given tile inside the map.
Definition: tile_map.cpp:59
static bool IsValidTile(TileIndex tile)
Checks if a tile is valid.
Definition: tile_map.h:161
SpriteID single_y
single piece of rail in Y direction, without ground
Definition: rail.h:135
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition: viewport.cpp:767
void ScaleToMonthly(uint runtime)
Scale all shares from link graph&#39;s runtime to monthly values.
Triggered in the periodic tile loop.
static bool IsBridgeAbove(TileIndex t)
checks if a bridge is set above the ground of this tile
Definition: bridge_map.h:45
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:3337
static bool IsCompatibleTrainStationTile(TileIndex test_tile, TileIndex station_tile)
Check if a tile is a valid continuation to a railstation tile.
Definition: station_map.h:378
TileArea docking_station
Tile area the docking tiles cover.
Definition: station_base.h:466
Buses, trucks and trams belong to this class.
Definition: roadveh.h:107
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:2241
static bool IsTileOwner(TileIndex tile, Owner owner)
Checks if a tile belongs to the given owner.
Definition: tile_map.h:214
void UpdateAirportsNoise()
Recalculate the noise generated by the airports of each town.
Shared order list linking together the linked list of orders and the list of vehicles sharing this or...
Definition: order_base.h:250
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:3534
static void DrawRailTileSeqInGUI(int x, int y, const DrawTileSprites *dts, int32 total_offset, uint32 newgrf_offset, PaletteID default_palette)
Draw tile sprite sequence in GUI with railroad specifics.
Definition: sprite.h:99
void FindStationsAroundTiles(const TileArea &location, StationList *const stations, bool use_nearby)
Find all stations around a rectangular producer (industry, house, headquarter, ...)
Maximal number of airports in total.
Definition: airport.h:41
Tile animation!
StringID name
Name of this rail type.
Definition: road.h:100
byte noise_level
noise that this airport generates
static const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition: road.h:224
uint GetShare(StationID st) const
Get flow for a station.
static bool CanRemoveRoadWithStop(TileIndex tile, DoCommandFlag flags)
Check if a drive-through road stop tile can be cleared.
void RestrictFlows(StationID via)
Restrict all flows at a station for specific cargo and destination.
Functions related to low-level strings.
byte amount_fract
Fractional part of the amount in the cargo list.
Definition: station_base.h:254
SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg, TileContext context, uint *num_results)
Get the sprite to draw for the given tile.
static const int MAX_CHAR_LENGTH
Max. length of UTF-8 encoded unicode character.
Definition: strings_type.h:18
uint x
X position of the tile in unit coordinates.
Definition: tile_cmd.h:43
SpriteID GetCustomStationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint32 var10)
Resolve sprites for drawing a station tile.
uint Size() const
Get the current size of the component.
Definition: linkgraph.h:497
None of the directions are disallowed.
Definition: road_map.h:286
byte rating
Station rating for this cargo.
Definition: station_base.h:235
The tile has no ownership.
Definition: company_type.h:25
static TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition: map_func.h:341
bool ValParamRoadType(RoadType roadtype)
Validate functions for rail building.
Definition: road.cpp:142
OrthogonalTileArea TileArea
Shorthand for the much more common orthogonal tile area.
Definition: tilearea_type.h:96
EdgeIterator End()
Get an iterator pointing beyond the end of the edges array.
Definition: linkgraph.h:401
Foundation
Enumeration for Foundations.
Definition: slope_type.h:93
TileIndex xy
town center tile
Definition: town.h:54
static void SetStationTileRandomBits(TileIndex t, byte random_bits)
Set the random bits for a station tile.
Definition: station_map.h:505
static bool IsBuoy(TileIndex t)
Is tile t a buoy tile?
Definition: station_map.h:306
static bool IsTileType(TileIndex tile, TileType type)
Checks if a tile is a given tiletype.
Definition: tile_map.h:150
Triggered when the airport is built (for all tiles at the same time).
Southeast.
static void MakeAirport(TileIndex t, Owner o, StationID sid, byte section, WaterClass wc)
Make the given tile an airport tile.
Definition: station_map.h:626
TileIndex tile
Tile index.
Definition: tile_cmd.h:46
AirportClassID cls_id
the class to which this airport type belongs
Updatable node class.
Definition: linkgraph.h:372
static uint ApplyPixelFoundationToSlope(Foundation f, Slope *s)
Applies a foundation to a slope.
Definition: landscape.h:129
static const int GFX_DOCK_BASE_WATER_PART
The offset for the water parts.
Definition: station_map.h:35
CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags)
Shorthand for calling the long DoCommand with a container.
Definition: command.cpp:445
The y axis.
uint32 PrepareLayout(uint32 orig_offset, uint32 newgrf_ground_offset, uint32 newgrf_offset, uint constr_stage, bool separate_ground) const
Prepares a sprite layout before resolving action-1-2-3 chains.
RoadStop * truck_stops
All the truck stops.
Definition: station_base.h:461
This indicates whether a cargo has a rating at the station.
Definition: station_base.h:187
StationID GetVia(StationID source) const
Get the best next hop for a cargo packet from station source.
Definition: station_base.h:283
void Add(TileIndex to_add)
Add a single tile to a tile area; enlarge if needed.
Definition: tilearea.cpp:43
static int CountMapSquareAround(TileIndex tile, CMSAMatcher cmp)
Counts the numbers of tiles matching a specific type in the area around.
bool serve_neutral_industries
company stations can serve industries with attached neutral stations
StringID owner_type[4]
Type of each owner.
Definition: tile_cmd.h:54
static RoadBits GetRoadBits(TileIndex t, RoadTramType rtt)
Get the present road bits for a specific road type.
Definition: road_map.h:127
void ClearDriveThrough()
Prepare for removal of this stop; update other neighbouring stops if needed.
Definition: roadstop.cpp:130
The tile is leveled up to a flat slope.
Definition: slope_type.h:95
LinkGraphID link_graph
Link graph this station belongs to.
Definition: station_base.h:257
Information about GRF, used in the game and (part of it) in savegames.
static bool HasStationReservation(TileIndex t)
Get the reservation state of the rail station.
Definition: station_map.h:393
static bool IsRailStationTile(TileIndex t)
Is this tile a station tile and a rail station?
Definition: station_map.h:102
Ground palette sprite of a tile, together with its sprite layout.
Definition: sprite.h:58
bool road_stop_on_competitor_road
allow building of drive-through road stops on roads owned by competitors
static void SetStationGfx(TileIndex t, StationGfx gfx)
Set the station graphics of this tile.
Definition: station_map.h:80
bool IsTileForestIndustry(TileIndex tile)
Check whether the tile is a forest.
void DirtyCompanyInfrastructureWindows(CompanyID company)
Redraw all windows with company infrastructure counts.
static LinkGraphSchedule instance
Static instance of LinkGraphSchedule.
CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Remove bus or truck stops.
WaterClass
classes of water (for WATER_TILE_CLEAR water tile type).
Definition: water_map.h:47
Images for overlaying track.
Definition: rail.h:48
static bool StationHandleBigTick(BaseStation *st)
This function is called for each station once every 250 ticks.
static bool IsTruckStop(TileIndex t)
Is the station at t a truck stop?
Definition: station_map.h:180
East.
const Direction * rotation
the rotation of each tiletable
static void TruncateCargo(const CargoSpec *cs, GoodsEntry *ge, uint amount=UINT_MAX)
Truncate the cargo by a specific amount.
uint DistanceMax(TileIndex t0, TileIndex t1)
Gets the biggest distance component (x or y) between the two given tiles.
Definition: map.cpp:189
StationID GetVia() const
Get a station a package can be routed to.
Definition: station_base.h:134
static DiagDirection GetRoadStopDir(TileIndex t)
Gets the direction the road stop entrance points towards.
Definition: station_map.h:257
Entry point for OpenTTD to YAPF&#39;s cache.
List of accepted cargoes / rating of cargoes.
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition: order_base.h:61
TileArea truck_station
Tile area the truck &#39;station&#39; part covers.
Definition: station_base.h:462
const StationList * GetStations()
Run a tile loop to find stations around a tile, on demand.
Functions related to NewGRF houses.
static Owner GetTileOwner(TileIndex tile)
Returns the owner of a tile.
Definition: tile_map.h:178
static DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
DoCommandFlag
List of flags for a command.
Definition: command_type.h:344
uint16 tram_speed
Speed limit of tram (bridges and track)
Definition: tile_cmd.h:68
GRFFilePropsBase< NUM_CARGO+3 > grf_prop
Properties related the the grf file.
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:79
byte status
Status of this cargo, see GoodsEntryStatus.
Definition: station_base.h:226
Piece of rail in X direction.
Definition: rail.h:68
bool Succeeded() const
Did this command succeed?
Definition: command_type.h:150
&#39;Close airport&#39; button.
Container for cargo from the same location and time.
Definition: cargopacket.h:42
static bool HasStationTileRail(TileIndex 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
void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage, EdgeUpdateMode mode)
Increase capacity for a link stat given by station cargo and next hop.
const IndustrySpec * GetIndustrySpec(IndustryType thistype)
Accessor for array _industry_specs.
byte layout
Airport layout number.
Definition: station_base.h:310
void DeleteAnimatedTile(TileIndex tile)
Removes the given tile from the animated tile table.
SpriteID GetCustomRoadSprite(const RoadTypeInfo *rti, TileIndex tile, RoadTypeSpriteGroup rtsg, TileContext context, uint *num_results)
Get the sprite to draw for the given tile.
int AllocateSpecToStation(const StationSpec *statspec, BaseStation *st, bool exec)
Allocate a StationSpec to a Station.
#define TILE_AREA_LOOP(var, ta)
A loop which iterates over the tiles of a TileArea.
Definition of base types and functions in a cross-platform compatible way.
static const Date INVALID_DATE
Representation of an invalid date.
Definition: date_type.h:110
Shift the VehicleEnterTileStatus this many bits to the right to get the station ID when VETS_ENTERED_...
Definition: tile_cmd.h:30
static TrackBits GetRailReservationTrackBits(TileIndex t)
Returns the reserved track bits of the tile.
Definition: rail_map.h:194
uint Reroute(uint max_move, VehicleCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge)
Routes packets with station "avoid" as next hop to a different place.
A number of safeguards to prevent using unsafe methods.
StationList stations_near
NOSAVE: List of nearby stations.
Definition: town.h:90
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
Trigger station every 250 ticks.
void WatchedCargoCallback(TileIndex tile, CargoTypes trigger_cargoes)
Run watched cargo accepted callback for a house.
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:258
IndustryType GetIndustryType(TileIndex tile)
Retrieve the type for this industry.
static const uint64 AIRPORT_CLOSED_block
Dummy block for indicating a closed airport.
Definition: airport.h:128
Direction
Defines the 8 directions on the map.
IndustryType type
type of industry.
Definition: industry.h:57
static 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 bool IsDockTile(TileIndex t)
Is tile t a dock tile?
Definition: station_map.h:295
Base of waypoints.
static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags)
Remove a bus station/truck stop.
The vehicle cannot enter the tile.
Definition: tile_cmd.h:37
Water tile.
Definition: tile_type.h:47
static Axis GetRailStationAxis(TileIndex t)
Get the rail direction of a rail station.
Definition: station_map.h:337
uint y
Y position of the tile in unit coordinates.
Definition: tile_cmd.h:44
struct RoadStop * next
Next stop of the given type at this station.
Definition: roadstop_base.h:69
bool HasStationInUse(StationID station, bool include_company, CompanyID company)
Tests whether the company&#39;s vehicles have this station in orders.
Liquids (Oil, Water, Rubber)
Definition: cargotype.h:45
RoadBits
Enumeration for the road parts on a tile.
Definition: road_type.h:50
uint8 callback_mask
Bitmask of cargo callbacks that have to be called.
Definition: cargotype.h:68
void ProcessRegisters(uint8 resolved_var10, uint32 resolved_sprite, bool separate_ground) const
Evaluates the register modifiers and integrates them into the preprocessed sprite layout...
void ShowDepotWindow(TileIndex tile, VehicleType type)
Opens a depot window.
Definition: depot_gui.cpp:1096
void GetTileArea(TileArea *ta, StationType type) const override
Get the tile area for a given station type.
static const uint MIN_TIMEOUT_DISTANCE
Minimum effective distance for timeout calculation.
Definition: linkgraph.h:440
TileArea location
Location of the industry.
Definition: industry.h:41
byte num_table
number of elements in the table
NodeID node
ID of node in link graph referring to this goods entry.
Definition: station_base.h:258
void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec)
Create the station layout for the given number of tracks and platform length.
static bool CMSAMine(TileIndex tile)
Check whether the tile is a mine.
bool IsHangar(TileIndex t)
Check whether the given tile is a hangar.
Definition: station_cmd.cpp:76
CargoID cargo_type
type of cargo this vehicle is carrying
Definition: vehicle_base.h:303
static const uint TILE_HEIGHT
Height of a height level in world coordinate AND in pixels in #ZOOM_LVL_BASE.
Definition: tile_type.h:16
Train * GetTrainForReservation(TileIndex tile, Track track)
Find the train which has reserved a specific path.
Definition: pbs.cpp:331
No road-part is build.
Definition: road_type.h:51
static bool IsBuoyTile(TileIndex t)
Is tile t a buoy tile?
Definition: station_map.h:316
NewGRF handling of road types.
Represents the covered area of e.g.
Definition: tilearea_type.h:16
char * stredup(const char *s, const char *last)
Create a duplicate of the given string.
Definition: string.cpp:136
GUI Functions related to companies.
CargoID produced_cargo[INDUSTRY_NUM_OUTPUTS]
16 production cargo slots
Definition: industry.h:44
PBS support routines.
static bool IsAirport(TileIndex t)
Is this station tile an airport?
Definition: station_map.h:157
TrackBits
Bitfield corresponding to Track.
Definition: track_type.h:38
CommandCost RemoveRailStation(T *st, DoCommandFlag flags, Money removal_cost)
Remove a rail station/waypoint.
StringID name
Tile Subname string, land information on this tile will give you "AirportName (TileSubname)".
Functions related to order backups.
bool IsFrontEngine() const
Check if the vehicle is a front engine.
Definition: vehicle_base.h:881
bool road_stop_on_town_road
allow building of drive-through road stops on town owned roads
Trigger station on new cargo arrival.
void UpdateVirtCoord() override
Update the virtual coords needed to draw the station sign.
uint16 max_speed
Maximum speed for vehicles travelling on this rail type.
Definition: rail.h:228
Map accessor functions for bridges.
void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
Find a vehicle from a specific location.
Definition: vehicle.cpp:496
Set when a sprite originates from an Action 1.
Definition: sprites.h:1524
TileIndex tile
Current tile index.
Definition: vehicle_base.h:228
uint16 max_speed
Maximum speed for vehicles travelling on this road type.
Definition: road.h:139
Owner owner
owner of the industry. Which SHOULD always be (imho) OWNER_NONE
Definition: industry.h:58
Defines the data structure for constructing industry.
Definition: industrytype.h:106
StationSpecList * speclist
List of station specs of this station.
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
static Money RoadBuildCost(RoadType roadtype)
Returns the cost of building the specified roadtype.
Definition: road.h:249
void Push(const Titem &item)
Pushes a new item onto the stack if there is still space in the underlying pool.
Base class for tile iterators.
Definition: tilearea_type.h:99
void UpdateCompanyRoadInfrastructure(RoadType rt, Owner o, int count)
Update road infrastructure counts for a company.
Definition: road_cmd.cpp:194
bool * indtypes
Array of bools telling whether an industry type has been found.
static const int STATION_RATING_TICKS
cycle duration for updating station rating
Definition: date_type.h:32
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:1938
static const AirportSpec * Get(byte type)
Retrieve airport spec for the given airport.
PersistentStorage * psa
Persistent storage for NewGRF airports.
Definition: station_base.h:313
static const AirportTileSpec * Get(StationGfx gfx)
Retrieve airport tile spec for the given airport tile.
Station view; Window numbers:
Definition: window_type.h:338
CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Build a dock/haven.
static void MakeRoadStop(TileIndex 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:590
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:266
Date LastRestrictedUpdate() const
Get the date of the last update to the edge&#39;s restricted capacity.
Definition: linkgraph.h:109
StationRect - used to track station spread out rectangle - cheaper than scanning whole map...
Bit value for coloured news.
Definition: news_type.h:71
SpriteID single_x
single piece of rail in X direction, without ground
Definition: rail.h:134
struct RoadTypeInfo::@42 strings
Strings associated with the rail type.
Called when building a station to customize the tile layout.
virtual TileIndex GetOrderStationLocation(StationID station)
Determine the location for the station where the vehicle goes to next.
Definition: vehicle_base.h:738
static const uint8 ANIM_STATUS_NO_ANIMATION
There is no animation.
void RestrictShare(StationID st)
Restrict a flow by moving it to the end of the map and decreasing the amount of unrestricted flow...
void AddFlow(StationID origin, StationID via, uint amount)
Add some flow from "origin", going via "via".
Owner owner
Which company owns the vehicle?
Definition: vehicle_base.h:271
uint64 flags
stores which blocks on the airport are taken. was 16 bit earlier on, then 32
Definition: station_base.h:308
CommandCost CmdRenameStation(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Rename a station.
static const SharesMap empty_sharesmap
Static instance of FlowStat::SharesMap.
Definition: station_base.h:40
Catchment for all stations with "modified catchment" disabled.
Definition: station_type.h:82
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:40
byte last_speed
Maximum speed (up to 255) of the last vehicle that tried to load this cargo.
Definition: station_base.h:246
uint8 cached_anim_triggers
NOSAVE: Combined animation trigger bitmask, used to determine if trigger processing should happen...
GRFFileProps grf_prop
properties related to the grf file
Definition: industrytype.h:140
static T min(const T a, const T b)
Returns the minimum of two values.
Definition: math_func.hpp:40
Types related to the station widgets.
static Foundation FlatteningFoundation(Slope s)
Returns the foundation needed to flatten a slope.
Definition: slope_func.h:369
static void DrawRailTileSeq(const struct TileInfo *ti, const DrawTileSprites *dts, TransparencyOption to, int32 total_offset, uint32 newgrf_offset, PaletteID default_palette)
Draw tile sprite sequence on tile with railroad specifics.
Definition: sprite.h:89
StringID railtype
Type of rail on the tile.
Definition: tile_cmd.h:63
static bool MayHaveRoad(TileIndex t)
Test whether a tile can have road/tram types.
Definition: road_map.h:32
StringID airport_tile_name
Name of the airport tile.
Definition: tile_cmd.h:60
static bool IsCargoInClass(CargoID c, CargoClass cc)
Does cargo c have cargo class cc?
Definition: cargotype.h:148
Piece of rail in Y direction.
Definition: rail.h:69
uint16 refit_cap
Capacity left over from before last refit.
Definition: vehicle_base.h:306
static DiagDirection GetInclinedSlopeDirection(Slope s)
Returns the direction of an inclined slope.
Definition: slope_func.h:239
Functions related to autoslope.
NewGRF supplied spritelayout.
static bool IsPlainRailTile(TileIndex t)
Checks whether the tile is a rail tile or rail tile with signals.
Definition: rail_map.h:60
An updatable edge class.
Definition: linkgraph.h:291
bool Convert8bitBooleanCallback(const GRFFile *grffile, uint16 cbid, uint16 cb_res)
Converts a callback result into a boolean.
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
static bool AutoslopeEnabled()
Tests if autoslope is enabled for _current_company.
Definition: autoslope.h:44
uint DistanceFromEdge(TileIndex tile)
Param the minimum distance to an edge.
Definition: map.cpp:217
Vehicle * First() const
Get the first vehicle of this vehicle chain.
Definition: vehicle_base.h:592
static TrackStatus CombineTrackStatus(TrackdirBits trackdirbits, TrackdirBits red_signals)
Builds a TrackStatus.
Definition: track_func.h:396
bool build_on_slopes
allow building on slopes
Date LastCompression() const
Get date of last compression.
Definition: linkgraph.h:503
bool Failed() const
Did this command fail?
Definition: command_type.h:159
StringID station_name
Type of station within the class.
Definition: tile_cmd.h:57
byte last_age
Age in years (up to 255) of the last vehicle that tried to load this cargo.
Definition: station_base.h:252
const struct SpriteGroup * spritegroup[Tcnt]
pointer to the different sprites of the entity
TileIndex GetHangarTile(uint hangar_num) const
Get the first tile of the given hangar.
Definition: station_base.h:373
static StationGfx GetStationGfx(TileIndex t)
Get the station graphics of this tile.
Definition: station_map.h:68
static void MakeDriveThroughRoadStop(TileIndex t, Owner station, Owner road, Owner tram, StationID sid, RoadStopType rst, RoadType road_rt, RoadType tram_rt, Axis a)
Make the given tile a drivethrough roadstop tile.
Definition: station_map.h:610
All ships have this type.
Definition: ship.h:26
Date LastUpdate() const
Get the date of the last update to any part of the edge&#39;s capacity.
Definition: linkgraph.h:115
RoadStop * bus_stops
All the road stops.
Definition: station_base.h:459
uint16 MaxTownNoise() const
Calculate the max town noise.
Definition: town.h:124
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:659
static Trackdir ReverseTrackdir(Trackdir trackdir)
Maps a trackdir to the reverse trackdir.
Definition: track_func.h:255
NewGRF handling of airport tiles.
void ShowStationViewWindow(StationID station)
Opens StationViewWindow for given station.
#define return_cmd_error(errcode)
Returns from a function with a specific StringID as error.
Definition: command_func.h:33
static void SetRoadOwner(TileIndex t, RoadTramType rtt, Owner o)
Set the owner of a specific road type.
Definition: road_map.h:250
Station list; Window numbers:
Definition: window_type.h:295
static T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:137
static bool HasSignals(TileIndex t)
Checks if a rail tile has signals.
Definition: rail_map.h:72
FlowStatMap flows
Planned flows through this station.
Definition: station_base.h:259
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:114
CommandCost FindJoiningWaypoint(StationID existing_waypoint, StationID waypoint_to_join, bool adjacent, TileArea ta, Waypoint **wp)
Find a nearby waypoint that joins this waypoint.
uint Truncate(uint max_move=UINT_MAX, StationCargoAmountMap *cargo_per_source=nullptr)
Truncates where each destination loses roughly the same percentage of its cargo.
bool Enter(RoadVehicle *rv)
Enter the road stop.
Definition: roadstop.cpp:233
static void Reset(TileIndex tile=INVALID_TILE, bool from_gui=true)
Reset the OrderBackups from GUI/game logic.
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:35
&#39;Train&#39; is either a loco or a wagon.
Definition: train.h:85
uint8 FindFirstBit(uint32 x)
Search the first set bit in a 32 bit variable.
void ChangeShare(StationID st, int flow)
Change share for specified station.
Functions related to clear (MP_CLEAR) land.
EdgeUpdateMode
Special modes for updating links.
TileIndex tile
The base tile of the area.
Definition: tilearea_type.h:17
byte flags
Bitmask of flags, bit 0: use different sprite set; bit 1: divide cargo about by station size...
uint16 _tick_counter
Ever incrementing (and sometimes wrapping) tick counter for setting off various events.
Definition: date.cpp:29
StationGfx GetStationGfx() const
Get the StationGfx for the current tile.
SpriteID GetCustomStationFoundationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint layout, uint edge_info)
Resolve the sprites for custom station foundations.
A pair-construct of a TileIndexDiff.
Definition: map_type.h:57
static TrackBits GetTrackBits(TileIndex tile)
Gets the track bits of the given tile.
Definition: rail_map.h:136
bool(* CMSAMatcher)(TileIndex tile)
Function to check whether the given tile matches some criterion.
void UpdateAllStationVirtCoords()
Update the virtual coords needed to draw the station sign for all stations.
CompanyInfrastructure infrastructure
NOSAVE: Counts of company owned infrastructure.
Definition: company_base.h:131
The X axis.
uint32 rail[RAILTYPE_END]
Count of company owned track bits for each rail type.
Definition: company_base.h:32
bool IsValidDockingDirectionForDock(TileIndex t, DiagDirection d)
Check if a dock tile can be docked from the given direction.
void DeleteWindowById(WindowClass cls, WindowNumber number, bool force)
Delete a window by its class and window number (if it is open).
Definition: window.cpp:1165
void ReleaseShare(StationID st)
Release ("unrestrict") a flow by moving it to the begin of the map and increasing the amount of unres...
static Axis DiagDirToAxis(DiagDirection d)
Convert a DiagDirection to the axis.
static TileIndexDiff ToTileIndexDiff(TileIndexDiffC tidc)
Return the offset between to tiles from a TileIndexDiffC struct.
Definition: map_func.h:230
Town * CalcClosestTownFromTile(TileIndex tile, uint threshold=UINT_MAX)
Return the town closest to the given tile within threshold.
Definition: town_cmd.cpp:3516
Handling of NewGRF canals.
byte StationGfx
Copy from station_map.h.
CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad)
Get the cargo types being produced around the tile (in a rectangle).
Transport by train.
execute the given command
Definition: command_type.h:346
Station with an airport.
Definition: station_type.h:55
static BaseStation * GetByTile(TileIndex tile)
Get the base station belonging to a specific tile.
static TrackBits TrackToTrackBits(Track track)
Maps a Track to the corresponding TrackBits value.
Definition: track_func.h:85
The tile/execution is done by "water".
Definition: company_type.h:26
uint GetHangarNum(TileIndex tile) const
Get the hangar number of the hangar at a specific tile.
Definition: station_base.h:403
static 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:239
Station with a dock.
Definition: station_type.h:56
CommandCost CheckIfAuthorityAllowsNewStation(TileIndex tile, DoCommandFlag flags)
Checks whether the local authority allows construction of a new station (rail, road, airport, dock) on the given tile.
Definition: town_cmd.cpp:3495
static StationID GetStationIndex(TileIndex t)
Get StationID from a tile.
Definition: station_map.h:28
Tile got trees.
Definition: tile_type.h:45
List of scheduled ships button.
No track.
Definition: track_type.h:39
PalSpriteID ground
Palette and sprite for the ground.
Definition: sprite.h:59
GRFConfig * GetGRFConfig(uint32 grfid, uint32 mask)
Retrieve a NewGRF from the current config by its grfid.
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...
static uint MapSize()
Get the size of the map.
Definition: map_func.h:92
StationType
Station types.
Definition: station_type.h:32
this bit is set when a recolouring process is in action
Definition: sprites.h:1527
void ErrorUnknownCallbackResult(uint32 grfid, uint16 cbid, uint16 cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
Class for storing amounts of cargo.
Definition: cargo_type.h:81
static Owner GetRoadOwner(TileIndex t, RoadTramType rtt)
Get the owner of a specific road type.
Definition: road_map.h:233
static bool IsNormalRoadTile(TileIndex t)
Return whether a tile is a normal road tile.
Definition: road_map.h:73
static 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:26
Header file for NewGRF stations.
Track along the y-axis (north-west to south-east)
Definition: track_type.h:22
RailType
Enumeration for all possible railtypes.
Definition: rail_type.h:27
static T ClrBit(T &x, const uint8 y)
Clears a bit in a variable.
CommandCost CmdOpenCloseAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Open/close an airport to incoming aircraft.
Trackdir GetVehicleTrackdir() const
Get the tracks of the train vehicle.
Definition: train_cmd.cpp:4005
CommandCost GetStationAround(TileArea ta, StationID closest_station, CompanyID company, T **st)
Look for a station owned by the given company around the given tile area.
bool IsStationTileBlocked(TileIndex tile)
Check whether a rail station tile is NOT traversable.
CommandCost PerformStationTileSlopeCheck(TileIndex north_tile, TileIndex cur_tile, const StationSpec *statspec, Axis axis, byte plat_len, byte numtracks)
Check the slope of a tile of a new station.
GUISettings gui
settings related to the GUI
DestinationID GetDestination() const
Gets the destination of this order.
Definition: order_base.h:94
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition: pool_type.hpp:378
Only bits 0 and 3 are used to encode the trackdir for road stops.
Definition: roadveh.h:58
static Track RemoveFirstTrack(TrackBits *tracks)
Removes first Track from TrackBits and returns it.
Definition: track_func.h:139
static TileIndex FindDockLandPart(TileIndex t)
Find the part of a dock that is land-based.
void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_index)
Mark a particular widget in a particular window as dirty (in need of repainting)
Definition: window.cpp:3232
bool station_noise_level
build new airports when the town noise level is still within accepted limits
uint max_waiting_cargo
Max cargo from this station waiting at any station.
Definition: station_base.h:260
StationClassID
bool NeedsPreprocessing() const
Tests whether this spritelayout needs preprocessing by PrepareLayout() and ProcessRegisters(), or whether it can be used directly.
uint32 SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:17
static bool StrEmpty(const char *s)
Check if a string buffer is empty.
Definition: string_func.h:57
void StationMonthlyLoop()
Monthly loop for stations.
int GetTileMaxZ(TileIndex t)
Get top height of the tile inside the map.
Definition: tile_map.cpp:141
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:310
Upper track.
Definition: track_type.h:42
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition: cargotype.h:117
uint16 road_speed
Speed limit of road (bridges and track)
Definition: tile_cmd.h:66
Set of callback functions for performing tile operations of a given tile type.
Definition: tile_cmd.h:145
T * Last()
Get the last vehicle in the chain.
Oilrig airport.
Definition: airport.h:38
size_t MapSize() const
Count the number of ranges with equal keys in this MultiMap.
Definition: multimap.hpp:350
uint32 TileIndex
The index/ID of a Tile.
Definition: tile_type.h:78
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition: sprites.h:1587
Use different sprite set for ground sprites.
Used for iterations.
uint32 GetPlatformInfo(Axis axis, byte tile, int platforms, int length, int x, int y, bool centred)
Evaluate a tile&#39;s position within a station, and return the result in a bit-stuffed format...
virtual bool TileBelongsToRailStation(TileIndex tile) const =0
Check whether a specific tile belongs to this station.
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition: map.cpp:157
Cargo support for NewGRFs.
void RerouteCargo(Station *st, CargoID c, StationID avoid, StationID avoid2)
Reroute cargo of type c at station st or in any vehicles unloading there.
void Invalidate()
Reduce all flows to minimum capacity so that they don&#39;t get in the way of link usage statistics too m...
static size_t GetNumItems()
Returns number of valid items in the pool.
Definition: pool_type.hpp:359
static void ShowRejectOrAcceptNews(const Station *st, uint num_items, CargoID *cargo, StringID msg)
Items contains the two cargo names that are to be accepted or rejected.
Vehicle * Next() const
Get the next vehicle of this vehicle.
Definition: vehicle_base.h:579
bool include(std::vector< T > &vec, const T &item)
Helper function to append an item to a vector if it is not already contained Consider using std::set...
StringID name
name of this airport
Extended foundation block instead of simple.
bool modified_catchment
different-size catchment areas
Trigger station on new cargo arrival.
byte fallback_railtype
Original railtype number to use when drawing non-newgrf railtypes, or when drawing stations...
Definition: rail.h:198
static Money RailBuildCost(RailType railtype)
Returns the cost of building the specified railtype.
Definition: rail.h:372
void Remove(const T &element)
Remove a single element from the tree, if it exists.
Definition: kdtree.hpp:420
OrderSettings order
settings related to orders
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
static IndustryID GetIndustryIndex(TileIndex t)
Get the industry ID of the given tile.
Definition: industry_map.h:63
AnimationInfo animation
Information about the animation.
Track
These are used to specify a single track.
Definition: track_type.h:19
uint16 SourceID
Contains either industry ID, town ID or company ID (or INVALID_SOURCE)
Definition: cargo_type.h:152
const SharesMap * GetShares() const
Get the actual shares as a const pointer so that they can be iterated over.
Definition: station_base.h:92
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition: map_func.h:215
Sprites to use and how to display them for station tiles.
Bit sets of the above specified bits.
Definition: tile_cmd.h:34
byte town_council_tolerance
minimum required town ratings to be allowed to demolish stuff
Definition: settings_type.h:69
Station is a waypoint.
Definition: station_type.h:57
void CDECL error(const char *s,...)
Error handling for fatal non-user errors.
Definition: openttd.cpp:112
bool IsWithinMapBounds(byte table, TileIndex index) const
Check if the airport would be within the map bounds at the given tile.
Availability of station in construction window.
byte size_x
size of airport in x direction
void FreeTrainTrackReservation(const Train *v)
Free the reserved path in front of a vehicle.
Definition: train_cmd.cpp:2229
TileIndex xy
Base tile of the station.
TransportType
Available types of transport.
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
void AppendShare(StationID st, uint flow, bool restricted=false)
Add some flow to the end of the shares map.
Definition: station_base.h:70
StringID airport_name
Name of the airport.
Definition: tile_cmd.h:59
A type of cargo is (no longer) accepted.
Definition: news_type.h:34
static bool IsOilRig(TileIndex t)
Is tile t part of an oilrig?
Definition: station_map.h:274
Slope
Enumeration for the slope-type.
Definition: slope_type.h:48
VehicleType type
Type of vehicle.
Definition: vehicle_type.h:52
Town view; Window numbers:
Definition: window_type.h:326
A tile of a station.
Definition: tile_type.h:46
void DrawRailCatenary(const TileInfo *ti)
Draws overhead wires and pylons for electric railways.
Definition: elrail.cpp:562
BitmapTileArea catchment_tiles
NOSAVE: Set of individual tiles covered by catchment area.
Definition: station_base.h:470
Town data structure.
Definition: town.h:53
static Station * GetByTile(TileIndex tile)
Get the station belonging to a specific tile.
static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, bool is_truck_stop, Axis axis, StationID *station, RoadType rt)
Checks if a road stop can be built at the given tile.
bool show_track_reservation
highlight reserved tracks.
void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool b)
Set the reservation for a complete station platform.
Definition: pbs.cpp:57
Main group of ground images.
Definition: rail.h:49
List of scheduled trains button.
static NewGRFClass * Get(Tid cls_id)
Get a particular class.
uint8 exclusive_counter
months till the exclusivity expires
Definition: town.h:75
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function() ...
Definition: pool_type.hpp:299
Transport by road vehicle.
Flow statistics telling how much flow should be sent along a link.
Definition: station_base.h:36
static const int STATION_LINKGRAPH_TICKS
cycle duration for cleaning dead links
Definition: date_type.h:34
uint GetRailtypeSpriteOffset() const
Offset between the current railtype and normal rail.
Definition: rail.h:292
The vehicle is in a road stop.
Definition: roadveh.h:50
static bool IsRailWaypoint(TileIndex t)
Is this station tile a rail waypoint?
Definition: station_map.h:113
Station * neutral_station
Associated neutral station.
Definition: industry.h:43
void OffsetGroundSprite(int x, int y)
Called when a foundation has been drawn for the current tile.
Definition: viewport.cpp:587
static uint CountBits(T value)
Counts the number of set bits in a variable.
Defines the data structure of each individual tile of an airport.
Functions related to commands.
static bool IsValidID(size_t index)
Tests whether given index is a valid index for station of this type.
CommandCost CmdRemoveFromRailStation(TileIndex start, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Remove a single tile from a rail station.
Coordinates of a point in 2D.
remove a single rail track
Definition: command_type.h:179
A Stop for a Road Vehicle.
Definition: roadstop_base.h:22
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:45
void AddFacility(StationFacility new_facility_bit, TileIndex facil_xy)
Called when new facility is built on the station.
Definition: station.cpp:202
CargoID Index() const
Determines index of this cargospec.
Definition: cargotype.h:88
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:575
Owner owner
The owner of this station.
byte GetSnowLine()
Get the current snow line, either variable or static.
Definition: landscape.cpp:644
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:318
static bool HasRailCatenaryDrawn(RailType rt)
Test if we should draw rail catenary.
Definition: elrail_func.h:30
Date build_date
Date of construction of tile contents.
Definition: tile_cmd.h:55
static bool IsRoadStopTile(TileIndex t)
Is tile t a road stop station?
Definition: station_map.h:213
uint GetFlowFromVia(StationID from, StationID via) const
Get the flow from a specific station via a specific other station.
header file for electrified rail specific functions
Base for ships.
Triggered every 250 ticks (for all tiles at the same time).
static void DeleteStationIfEmpty(BaseStation *st)
This is called right after a station was deleted.
bool adjacent_stations
allow stations to be built directly adjacent to other stations
Station with bus stops.
Definition: station_type.h:54
ConstructionSettings construction
construction of things in-game
Functions that have tunnels and bridges in common.
static TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition: map_func.h:179
Base of all industries.
static DisallowedRoadDirections GetDisallowedRoadDirections(TileIndex t)
Gets the disallowed directions.
Definition: road_map.h:301
const char * GetName() const
Get the name of this grf.
static Pool::IterateWrapper< RoadVehicle > Iterate(size_t from=0)
Returns an iterable ensemble of all valid vehicles of type T.
Functions related to waypoints.
Aircraft vehicle type.
Definition: vehicle_type.h:27
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: depend.cpp:129
Airport airport
Tile area the airport covers.
Definition: station_base.h:464
static 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
StringID name
Name of this rail type.
Definition: rail.h:173
CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Place an Airport.
RailTrackOffset
Offsets for sprites within an overlay/underlay set.
Definition: rail.h:67
CommandCost RemoveBuoy(TileIndex tile, DoCommandFlag flags)
Remove a buoy.
const struct GRFFile * grffile
grf file that introduced this entity
static const uint MAX_LENGTH_STATION_NAME_CHARS
The maximum length of a station name in characters including &#39;\0&#39;.
Definition: station_type.h:87
StringID str
Description of the tile.
Definition: tile_cmd.h:52
StringID station_name
Default name for nearby station.
Definition: industrytype.h:131
static bool IsHangarTile(TileIndex t)
Is tile t an hangar tile?
Definition: station_map.h:326
Passengers.
Definition: cargotype.h:39
const Tcont * Packets() const
Returns a pointer to the cargo packet list (so you can iterate over it etc).
Definition: cargopacket.h:246
remove a (rectangle of) tiles from a rail station
Definition: command_type.h:190
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 ...
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
static bool HasTileWaterClass(TileIndex t)
Checks whether the tile has an waterclass associated.
Definition: water_map.h:95
DiagDirection
Enumeration for diagonal directions.
static TrackdirBits TrackBitsToTrackdirBits(TrackBits bits)
Converts TrackBits to TrackdirBits while allowing both directions.
Definition: track_func.h:327
StringID station_class
Class of station.
Definition: tile_cmd.h:56
void AddNewsItem(StringID string, NewsType type, NewsFlag flags, NewsReferenceType reftype1=NR_NONE, uint32 ref1=UINT32_MAX, NewsReferenceType reftype2=NR_NONE, uint32 ref2=UINT32_MAX, void *free_data=nullptr)
Add a new newsitem to be shown.
Definition: news_gui.cpp:745
byte callback_mask
Bitmask of station callbacks that have to be called.
static const TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:83
byte disallowed_lengths
Bitmask of platform lengths available for the station.
Base of the town class.
StringID roadtype
Type of road on the tile.
Definition: tile_cmd.h:65
void DrawRoadOverlays(const TileInfo *ti, PaletteID pal, const RoadTypeInfo *road_rti, const RoadTypeInfo *tram_rti, uint road_offset, uint tram_offset)
Draw road underlay and overlay sprites.
Definition: road_cmd.cpp:1495
Station with truck stops.
Definition: station_type.h:53
Northeast, upper right on your monitor.
Required: Main group of ground images.
Definition: road.h:60
CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Build rail station.
Choose a sprite layout to draw, instead of the standard 0-7 range.
GameCreationSettings game_creation
settings used during the creation of a game (map)
static const uint NEW_AIRPORTTILE_OFFSET
offset of first newgrf airport tile
Definition: airport.h:24
uint AvailableCount() const
Returns sum of cargo still available for loading at the sation.
Definition: cargopacket.h:507
void UpdateAirplanesOnNewStation(const Station *st)
Updates the status of the Aircraft heading or in the station.
A house by a town.
Definition: tile_type.h:44
Full road along the y-axis (north-west + south-east)
Definition: road_type.h:57
byte CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:20
IndustryType indtype
Industry type to get the name from.
Definition: station_base.h:468
Enum of the default airport tiles.
Check slope of new station tiles.
static Industry * GetByTile(TileIndex tile)
Get the industry of the given tile.
Definition: industry.h:114
NewGRFSpriteLayout * renderdata
Array of tile layouts.
Small news item. (Information window with text and viewport)
Definition: news_type.h:77
Vehicle * NextShared() const
Get the next vehicle of the shared vehicle chain.
Definition: vehicle_base.h:661
void AfterStationTileSetChange(bool adding, StationType type)
After adding/removing tiles to station, update some station-related stuff.
Station with train station.
Definition: station_type.h:52
byte time_since_pickup
Number of rating-intervals (up to 255) since the last vehicle tried to load this cargo.
Definition: station_base.h:233
static CargoTypes GetAcceptanceMask(const Station *st)
Get a mask of the cargo types that the station accepts.
StringID name
Name of this station.
Maximum catchment for airports with "modified catchment" enabled.
Definition: station_type.h:84
Defines the data structure for an airport.
Functions related to water (management)
static DiagDirection AxisToDiagDir(Axis a)
Converts an Axis to a DiagDirection.
static bool CMSAWater(TileIndex tile)
Check whether the tile is water.
An iterator for non-const edges.
Definition: linkgraph.h:322
static bool IsTileOnWater(TileIndex t)
Tests if the tile was built on water.
Definition: water_map.h:130
VehicleEnterTileStatus
The returned bits of VehicleEnterTile.
Definition: tile_cmd.h:20
StationGfx GetTranslatedAirportTileID(StationGfx gfx)
Do airporttile gfx ID translation for NewGRFs.
SpriteID sprite
The &#39;real&#39; sprite.
Definition: gfx_type.h:23
CommandCost CmdRemoveFromRailWaypoint(TileIndex start, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Remove a single tile from a waypoint.
byte disallowed_platforms
Bitmask of number of platforms available for the station.
StringID airport_class
Name of the airport class.
Definition: tile_cmd.h:58
Functions related to news.
static void MakeRoadNormal(TileIndex 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
uint GetFlow() const
Get the sum of all flows from this FlowStatMap.
StationClassID cls_id
The class to which this spec belongs.
Base classes/functions for stations.
void RemoveEdge(NodeID to)
Remove an outgoing edge from this node.
Definition: linkgraph.cpp:227
static bool IsDock(TileIndex t)
Is tile t a dock tile?
Definition: station_map.h:285
static Station * Get(size_t index)
Gets station with given index.
Date _date
Current date in days (day counter)
Definition: date.cpp:27
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:2667
char * name
Custom name.
uint16 h
The height of the area.
Definition: tilearea_type.h:19
void Insert(const T &element)
Insert a single element in the tree.
Definition: kdtree.hpp:401
std::string cached_name
NOSAVE: Cache of the resolved name of the station, if not using a custom name.
static void SetDockingTile(TileIndex t, bool b)
Set the docking tile state of a tile.
Definition: water_map.h:355
Triggered when new cargo arrives at the station (for all tiles at the same time). ...
Industry * industry
NOSAVE: Associated industry for neutral stations. (Rebuilt on load from Industry->st) ...
Definition: station_base.h:483
GRFFileProps grf_prop
properties related the the grf file
static 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:98
CompanyID exclusivity
which company has exclusivity
Definition: town.h:74
StringID string_id
Default name (town area) of station.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:44
remove a (rectangle of) tiles from a rail waypoint
Definition: command_type.h:195
Y-axis track.
Definition: track_type.h:41
void CheckForDockingTile(TileIndex t)
Mark the supplied tile as a docking tile if it is suitable for docking.
Definition: water_cmd.cpp:182
void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
Delete inspect window for a given feature and index.
void Append(CargoPacket *cp, StationID next)
Appends the given cargo packet to the range of packets with the same next station.
void Merge(LinkGraph *other)
Merge a link graph with another one.
Definition: linkgraph.cpp:85
Optional: Images for overlaying track.
Definition: road.h:59
Base class for all station-ish types.
Station data structure.
Definition: station_base.h:450
static const int STATION_ACCEPTANCE_TICKS
cycle duration for updating station acceptance
Definition: date_type.h:33
Axis
Allow incrementing of DiagDirDiff variables.
remove a road stop
Definition: command_type.h:198
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 CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag flags, Axis axis, StationID *station, RailType rt, std::vector< Train *> &affected_vehicles, StationClassID spec_class, byte spec_index, byte plat_len, byte numtracks)
Checks if a rail station can be built at the given area.
struct GRFFileProps grf_prop
Properties related to the grf file.
custom station rating for this cargo type
LinkGraphSettings linkgraph
settings for link graph calculations
Used for industry tiles on land (also for oilrig if newgrf says so).
Definition: water_map.h:51
Road vehicle type.
Definition: vehicle_type.h:25
Set when the station accepts the cargo currently for final deliveries.
Definition: station_base.h:177
static RoadBits AxisToRoadBits(Axis a)
Create the road-part which belongs to the given Axis.
Definition: road_func.h:111
static TileIndex TileXY(uint x, uint y)
Returns the TileIndex of a coordinate.
Definition: map_func.h:163
Train is slowing down.
Definition: vehicle_base.h:34
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:973
static RailType GetRailType(TileIndex t)
Gets the rail type of the given tile.
Definition: rail_map.h:115
Order current_order
The current order (+ status, like: loading)
Definition: vehicle_base.h:316
static RoadStop * GetByTile(TileIndex tile, RoadStopType type)
Find a roadstop at given tile.
Definition: roadstop.cpp:266
Date build_date
Date of construction.
Called to calculate part of a station rating.
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:3319
Southwest.
static void RestoreTrainReservation(Train *v)
Restore platform reservation during station building/removing.
static int GetTileMaxPixelZ(TileIndex tile)
Get top height of the tile.
Definition: tile_map.h:304
static void SetDParam(uint n, uint64 v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings_func.h:199
CargoTypes always_accepted
Bitmask of always accepted cargo types (by houses, HQs, industry tiles when industry doesn&#39;t accept c...
Definition: station_base.h:480
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition: gfx_type.h:24
uint32 water
Count of company owned track bits for canals.
Definition: company_base.h:33
StringID name
Name of this class.
Definition: newgrf_class.h:39
static Station * GetIfValid(size_t index)
Returns station if the index is a valid index for this station type.