OpenTTD Source  1.10.1
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  return;
404 
405  default: NOT_REACHED();
406  }
407 }
408 
413 {
414  Point pt = RemapCoords2(TileX(this->xy) * TILE_SIZE, TileY(this->xy) * TILE_SIZE);
415 
416  pt.y -= 32 * ZOOM_LVL_BASE;
417  if ((this->facilities & FACIL_AIRPORT) && this->airport.type == AT_OILRIG) pt.y -= 16 * ZOOM_LVL_BASE;
418 
419  if (this->sign.kdtree_valid) _viewport_sign_kdtree.Remove(ViewportSignKdtreeItem::MakeStation(this->index));
420 
421  SetDParam(0, this->index);
422  SetDParam(1, this->facilities);
423  this->sign.UpdatePosition(pt.x, pt.y, STR_VIEWPORT_STATION);
424 
425  _viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeStation(this->index));
426 
427  SetWindowDirty(WC_STATION_VIEW, this->index);
428 }
429 
435 {
436  if (this->xy == new_xy) return;
437 
438  _station_kdtree.Remove(this->index);
439 
440  this->BaseStation::MoveSign(new_xy);
441 
442  _station_kdtree.Insert(this->index);
443 }
444 
447 {
448  for (BaseStation *st : BaseStation::Iterate()) {
449  st->UpdateVirtCoord();
450  }
451 }
452 
453 void BaseStation::FillCachedName() const
454 {
456  int64 args_array[] = { this->index };
457  StringParameters tmp_params(args_array);
458  char *end = GetStringWithArgs(buf, Waypoint::IsExpected(this) ? STR_WAYPOINT_NAME : STR_STATION_NAME, &tmp_params, lastof(buf));
459  this->cached_name.assign(buf, end);
460 }
461 
462 void ClearAllStationCachedNames()
463 {
464  for (BaseStation *st : BaseStation::Iterate()) {
465  st->cached_name.clear();
466  }
467 }
468 
474 static CargoTypes GetAcceptanceMask(const Station *st)
475 {
476  CargoTypes mask = 0;
477 
478  for (CargoID i = 0; i < NUM_CARGO; i++) {
479  if (HasBit(st->goods[i].status, GoodsEntry::GES_ACCEPTANCE)) SetBit(mask, i);
480  }
481  return mask;
482 }
483 
488 static void ShowRejectOrAcceptNews(const Station *st, uint num_items, CargoID *cargo, StringID msg)
489 {
490  for (uint i = 0; i < num_items; i++) {
491  SetDParam(i + 1, CargoSpec::Get(cargo[i])->name);
492  }
493 
494  SetDParam(0, st->index);
496 }
497 
505 CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad)
506 {
507  CargoArray produced;
508  std::set<IndustryID> industries;
509  TileArea ta = TileArea(tile, w, h).Expand(rad);
510 
511  /* Loop over all tiles to get the produced cargo of
512  * everything except industries */
513  TILE_AREA_LOOP(tile, ta) {
514  if (IsTileType(tile, MP_INDUSTRY)) industries.insert(GetIndustryIndex(tile));
515  AddProducedCargo(tile, produced);
516  }
517 
518  /* Loop over the seen industries. They produce cargo for
519  * anything that is within 'rad' of any one of their tiles.
520  */
521  for (IndustryID industry : industries) {
522  const Industry *i = Industry::Get(industry);
523  /* Skip industry with neutral station */
524  if (i->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) continue;
525 
526  for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
527  CargoID cargo = i->produced_cargo[j];
528  if (cargo != CT_INVALID) produced[cargo]++;
529  }
530  }
531 
532  return produced;
533 }
534 
544 CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, CargoTypes *always_accepted)
545 {
546  CargoArray acceptance;
547  if (always_accepted != nullptr) *always_accepted = 0;
548 
549  TileArea ta = TileArea(tile, w, h).Expand(rad);
550 
551  TILE_AREA_LOOP(tile, ta) {
552  /* Ignore industry if it has a neutral station. */
553  if (!_settings_game.station.serve_neutral_industries && IsTileType(tile, MP_INDUSTRY) && Industry::GetByTile(tile)->neutral_station != nullptr) continue;
554 
555  AddAcceptedCargo(tile, acceptance, always_accepted);
556  }
557 
558  return acceptance;
559 }
560 
566 static CargoArray GetAcceptanceAroundStation(const Station *st, CargoTypes *always_accepted)
567 {
568  CargoArray acceptance;
569  if (always_accepted != nullptr) *always_accepted = 0;
570 
572  for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
573  AddAcceptedCargo(tile, acceptance, always_accepted);
574  }
575 
576  return acceptance;
577 }
578 
584 void UpdateStationAcceptance(Station *st, bool show_msg)
585 {
586  /* old accepted goods types */
587  CargoTypes old_acc = GetAcceptanceMask(st);
588 
589  /* And retrieve the acceptance. */
590  CargoArray acceptance;
591  if (!st->rect.IsEmpty()) {
592  acceptance = GetAcceptanceAroundStation(st, &st->always_accepted);
593  }
594 
595  /* Adjust in case our station only accepts fewer kinds of goods */
596  for (CargoID i = 0; i < NUM_CARGO; i++) {
597  uint amt = acceptance[i];
598 
599  /* Make sure the station can accept the goods type. */
600  bool is_passengers = IsCargoInClass(i, CC_PASSENGERS);
601  if ((!is_passengers && !(st->facilities & ~FACIL_BUS_STOP)) ||
602  (is_passengers && !(st->facilities & ~FACIL_TRUCK_STOP))) {
603  amt = 0;
604  }
605 
606  GoodsEntry &ge = st->goods[i];
607  SB(ge.status, GoodsEntry::GES_ACCEPTANCE, 1, amt >= 8);
609  (*LinkGraph::Get(ge.link_graph))[ge.node].SetDemand(amt / 8);
610  }
611  }
612 
613  /* Only show a message in case the acceptance was actually changed. */
614  CargoTypes new_acc = GetAcceptanceMask(st);
615  if (old_acc == new_acc) return;
616 
617  /* show a message to report that the acceptance was changed? */
618  if (show_msg && st->owner == _local_company && st->IsInUse()) {
619  /* List of accept and reject strings for different number of
620  * cargo types */
621  static const StringID accept_msg[] = {
622  STR_NEWS_STATION_NOW_ACCEPTS_CARGO,
623  STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO,
624  };
625  static const StringID reject_msg[] = {
626  STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO,
627  STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO,
628  };
629 
630  /* Array of accepted and rejected cargo types */
631  CargoID accepts[2] = { CT_INVALID, CT_INVALID };
632  CargoID rejects[2] = { CT_INVALID, CT_INVALID };
633  uint num_acc = 0;
634  uint num_rej = 0;
635 
636  /* Test each cargo type to see if its acceptance has changed */
637  for (CargoID i = 0; i < NUM_CARGO; i++) {
638  if (HasBit(new_acc, i)) {
639  if (!HasBit(old_acc, i) && num_acc < lengthof(accepts)) {
640  /* New cargo is accepted */
641  accepts[num_acc++] = i;
642  }
643  } else {
644  if (HasBit(old_acc, i) && num_rej < lengthof(rejects)) {
645  /* Old cargo is no longer accepted */
646  rejects[num_rej++] = i;
647  }
648  }
649  }
650 
651  /* Show news message if there are any changes */
652  if (num_acc > 0) ShowRejectOrAcceptNews(st, num_acc, accepts, accept_msg[num_acc - 1]);
653  if (num_rej > 0) ShowRejectOrAcceptNews(st, num_rej, rejects, reject_msg[num_rej - 1]);
654  }
655 
656  /* redraw the station view since acceptance changed */
658 }
659 
660 static void UpdateStationSignCoord(BaseStation *st)
661 {
662  const StationRect *r = &st->rect;
663 
664  if (r->IsEmpty()) return; // no tiles belong to this station
665 
666  /* clamp sign coord to be inside the station rect */
667  TileIndex new_xy = TileXY(ClampU(TileX(st->xy), r->left, r->right), ClampU(TileY(st->xy), r->top, r->bottom));
668  st->MoveSign(new_xy);
669 
670  if (!Station::IsExpected(st)) return;
671  Station *full_station = Station::From(st);
672  for (CargoID c = 0; c < NUM_CARGO; ++c) {
673  LinkGraphID lg = full_station->goods[c].link_graph;
674  if (!LinkGraph::IsValidID(lg)) continue;
675  (*LinkGraph::Get(lg))[full_station->goods[c].node].UpdateLocation(st->xy);
676  }
677 }
678 
688 static CommandCost BuildStationPart(Station **st, DoCommandFlag flags, bool reuse, TileArea area, StationNaming name_class)
689 {
690  /* Find a deleted station close to us */
691  if (*st == nullptr && reuse) *st = GetClosestDeletedStation(area.tile);
692 
693  if (*st != nullptr) {
694  if ((*st)->owner != _current_company) {
696  }
697 
698  CommandCost ret = (*st)->rect.BeforeAddRect(area.tile, area.w, area.h, StationRect::ADD_TEST);
699  if (ret.Failed()) return ret;
700  } else {
701  /* allocate and initialize new station */
702  if (!Station::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);
703 
704  if (flags & DC_EXEC) {
705  *st = new Station(area.tile);
706  _station_kdtree.Insert((*st)->index);
707 
708  (*st)->town = ClosestTownFromTile(area.tile, UINT_MAX);
709  (*st)->string_id = GenerateStationName(*st, area.tile, name_class);
710 
712  SetBit((*st)->town->have_ratings, _current_company);
713  }
714  }
715  }
716  return CommandCost();
717 }
718 
726 {
727  if (!st->IsInUse()) {
728  st->delete_ctr = 0;
730  }
731  /* station remains but it probably lost some parts - station sign should stay in the station boundaries */
732  UpdateStationSignCoord(st);
733 }
734 
741 {
742  this->UpdateVirtCoord();
743  this->RecomputeCatchment();
745  if (adding) InvalidateWindowData(WC_STATION_LIST, this->owner, 0);
746 
747  switch (type) {
748  case STATION_RAIL:
750  break;
751  case STATION_AIRPORT:
752  break;
753  case STATION_TRUCK:
754  case STATION_BUS:
756  break;
757  case STATION_DOCK:
759  break;
760  default: NOT_REACHED();
761  }
762 
763  if (adding) {
764  UpdateStationAcceptance(this, false);
766  } else {
767  DeleteStationIfEmpty(this);
768  }
769 
770 }
771 
773 
783 CommandCost CheckBuildableTile(TileIndex tile, uint invalid_dirs, int &allowed_z, bool allow_steep, bool check_bridge = true)
784 {
785  if (check_bridge && IsBridgeAbove(tile)) {
786  return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
787  }
788 
790  if (ret.Failed()) return ret;
791 
792  int z;
793  Slope tileh = GetTileSlope(tile, &z);
794 
795  /* Prohibit building if
796  * 1) The tile is "steep" (i.e. stretches two height levels).
797  * 2) The tile is non-flat and the build_on_slopes switch is disabled.
798  */
799  if ((!allow_steep && IsSteepSlope(tileh)) ||
801  return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
802  }
803 
805  int flat_z = z + GetSlopeMaxZ(tileh);
806  if (tileh != SLOPE_FLAT) {
807  /* Forbid building if the tile faces a slope in a invalid direction. */
808  for (DiagDirection dir = DIAGDIR_BEGIN; dir != DIAGDIR_END; dir++) {
809  if (HasBit(invalid_dirs, dir) && !CanBuildDepotByTileh(dir, tileh)) {
810  return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
811  }
812  }
813  cost.AddCost(_price[PR_BUILD_FOUNDATION]);
814  }
815 
816  /* The level of this tile must be equal to allowed_z. */
817  if (allowed_z < 0) {
818  /* First tile. */
819  allowed_z = flat_z;
820  } else if (allowed_z != flat_z) {
821  return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
822  }
823 
824  return cost;
825 }
826 
834 {
836  int allowed_z = -1;
837 
838  for (; tile_iter != INVALID_TILE; ++tile_iter) {
839  CommandCost ret = CheckBuildableTile(tile_iter, 0, allowed_z, true);
840  if (ret.Failed()) return ret;
841  cost.AddCost(ret);
842 
843  ret = DoCommand(tile_iter, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
844  if (ret.Failed()) return ret;
845  cost.AddCost(ret);
846  }
847 
848  return cost;
849 }
850 
865 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)
866 {
868  int allowed_z = -1;
869  uint invalid_dirs = 5 << axis;
870 
871  const StationSpec *statspec = StationClass::Get(spec_class)->GetSpec(spec_index);
872  bool slope_cb = statspec != nullptr && HasBit(statspec->callback_mask, CBM_STATION_SLOPE_CHECK);
873 
874  TILE_AREA_LOOP(tile_cur, tile_area) {
875  CommandCost ret = CheckBuildableTile(tile_cur, invalid_dirs, allowed_z, false);
876  if (ret.Failed()) return ret;
877  cost.AddCost(ret);
878 
879  if (slope_cb) {
880  /* Do slope check if requested. */
881  ret = PerformStationTileSlopeCheck(tile_area.tile, tile_cur, statspec, axis, plat_len, numtracks);
882  if (ret.Failed()) return ret;
883  }
884 
885  /* if station is set, then we have special handling to allow building on top of already existing stations.
886  * so station points to INVALID_STATION if we can build on any station.
887  * Or it points to a station if we're only allowed to build on exactly that station. */
888  if (station != nullptr && IsTileType(tile_cur, MP_STATION)) {
889  if (!IsRailStation(tile_cur)) {
890  return ClearTile_Station(tile_cur, DC_AUTO); // get error message
891  } else {
892  StationID st = GetStationIndex(tile_cur);
893  if (*station == INVALID_STATION) {
894  *station = st;
895  } else if (*station != st) {
896  return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
897  }
898  }
899  } else {
900  /* Rail type is only valid when building a railway station; if station to
901  * build isn't a rail station it's INVALID_RAILTYPE. */
902  if (rt != INVALID_RAILTYPE &&
903  IsPlainRailTile(tile_cur) && !HasSignals(tile_cur) &&
904  HasPowerOnRail(GetRailType(tile_cur), rt)) {
905  /* Allow overbuilding if the tile:
906  * - has rail, but no signals
907  * - it has exactly one track
908  * - the track is in line with the station
909  * - the current rail type has power on the to-be-built type (e.g. convert normal rail to el rail)
910  */
911  TrackBits tracks = GetTrackBits(tile_cur);
912  Track track = RemoveFirstTrack(&tracks);
913  Track expected_track = HasBit(invalid_dirs, DIAGDIR_NE) ? TRACK_X : TRACK_Y;
914 
915  if (tracks == TRACK_BIT_NONE && track == expected_track) {
916  /* Check for trains having a reservation for this tile. */
917  if (HasBit(GetRailReservationTrackBits(tile_cur), track)) {
918  Train *v = GetTrainForReservation(tile_cur, track);
919  if (v != nullptr) {
920  affected_vehicles.push_back(v);
921  }
922  }
923  CommandCost ret = DoCommand(tile_cur, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
924  if (ret.Failed()) return ret;
925  cost.AddCost(ret);
926  /* With flags & ~DC_EXEC CmdLandscapeClear would fail since the rail still exists */
927  continue;
928  }
929  }
930  ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
931  if (ret.Failed()) return ret;
932  cost.AddCost(ret);
933  }
934  }
935 
936  return cost;
937 }
938 
951 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)
952 {
954  int allowed_z = -1;
955 
956  TILE_AREA_LOOP(cur_tile, tile_area) {
957  CommandCost ret = CheckBuildableTile(cur_tile, invalid_dirs, allowed_z, !is_drive_through);
958  if (ret.Failed()) return ret;
959  cost.AddCost(ret);
960 
961  /* If station is set, then we have special handling to allow building on top of already existing stations.
962  * Station points to INVALID_STATION if we can build on any station.
963  * Or it points to a station if we're only allowed to build on exactly that station. */
964  if (station != nullptr && IsTileType(cur_tile, MP_STATION)) {
965  if (!IsRoadStop(cur_tile)) {
966  return ClearTile_Station(cur_tile, DC_AUTO); // Get error message.
967  } else {
968  if (is_truck_stop != IsTruckStop(cur_tile) ||
969  is_drive_through != IsDriveThroughStopTile(cur_tile)) {
970  return ClearTile_Station(cur_tile, DC_AUTO); // Get error message.
971  }
972  /* Drive-through station in the wrong direction. */
973  if (is_drive_through && IsDriveThroughStopTile(cur_tile) && DiagDirToAxis(GetRoadStopDir(cur_tile)) != axis){
974  return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION);
975  }
976  StationID st = GetStationIndex(cur_tile);
977  if (*station == INVALID_STATION) {
978  *station = st;
979  } else if (*station != st) {
980  return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
981  }
982  }
983  } else {
984  bool build_over_road = is_drive_through && IsNormalRoadTile(cur_tile);
985  /* Road bits in the wrong direction. */
986  RoadBits rb = IsNormalRoadTile(cur_tile) ? GetAllRoadBits(cur_tile) : ROAD_NONE;
987  if (build_over_road && (rb & (axis == AXIS_X ? ROAD_Y : ROAD_X)) != 0) {
988  /* Someone was pedantic and *NEEDED* three fracking different error messages. */
989  switch (CountBits(rb)) {
990  case 1:
991  return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION);
992 
993  case 2:
994  if (rb == ROAD_X || rb == ROAD_Y) return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION);
995  return_cmd_error(STR_ERROR_DRIVE_THROUGH_CORNER);
996 
997  default: // 3 or 4
998  return_cmd_error(STR_ERROR_DRIVE_THROUGH_JUNCTION);
999  }
1000  }
1001 
1002  if (build_over_road) {
1003  /* There is a road, check if we can build road+tram stop over it. */
1004  RoadType road_rt = GetRoadType(cur_tile, RTT_ROAD);
1005  if (road_rt != INVALID_ROADTYPE) {
1006  Owner road_owner = GetRoadOwner(cur_tile, RTT_ROAD);
1007  if (road_owner == OWNER_TOWN) {
1008  if (!_settings_game.construction.road_stop_on_town_road) return_cmd_error(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD);
1009  } else if (!_settings_game.construction.road_stop_on_competitor_road && road_owner != OWNER_NONE) {
1010  CommandCost ret = CheckOwnership(road_owner);
1011  if (ret.Failed()) return ret;
1012  }
1013  uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_ROAD));
1014 
1015  if (RoadTypeIsRoad(rt) && !HasPowerOnRoad(rt, road_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD);
1016 
1017  if (GetDisallowedRoadDirections(cur_tile) != DRD_NONE && road_owner != OWNER_TOWN) {
1018  CommandCost ret = CheckOwnership(road_owner);
1019  if (ret.Failed()) return ret;
1020  }
1021 
1022  cost.AddCost(RoadBuildCost(road_rt) * (2 - num_pieces));
1023  } else if (RoadTypeIsRoad(rt)) {
1024  cost.AddCost(RoadBuildCost(rt) * 2);
1025  }
1026 
1027  /* There is a tram, check if we can build road+tram stop over it. */
1028  RoadType tram_rt = GetRoadType(cur_tile, RTT_TRAM);
1029  if (tram_rt != INVALID_ROADTYPE) {
1030  Owner tram_owner = GetRoadOwner(cur_tile, RTT_TRAM);
1031  if (Company::IsValidID(tram_owner) &&
1033  /* Disallow breaking end-of-line of someone else
1034  * so trams can still reverse on this tile. */
1035  HasExactlyOneBit(GetRoadBits(cur_tile, RTT_TRAM)))) {
1036  CommandCost ret = CheckOwnership(tram_owner);
1037  if (ret.Failed()) return ret;
1038  }
1039  uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_TRAM));
1040 
1041  if (RoadTypeIsTram(rt) && !HasPowerOnRoad(rt, tram_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD);
1042 
1043  cost.AddCost(RoadBuildCost(tram_rt) * (2 - num_pieces));
1044  } else if (RoadTypeIsTram(rt)) {
1045  cost.AddCost(RoadBuildCost(rt) * 2);
1046  }
1047  } else {
1048  ret = DoCommand(cur_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
1049  if (ret.Failed()) return ret;
1050  cost.AddCost(ret);
1051  cost.AddCost(RoadBuildCost(rt) * 2);
1052  }
1053  }
1054  }
1055 
1056  return cost;
1057 }
1058 
1067 {
1068  TileArea cur_ta = st->train_station;
1069 
1070  /* determine new size of train station region.. */
1071  int x = min(TileX(cur_ta.tile), TileX(new_ta.tile));
1072  int y = min(TileY(cur_ta.tile), TileY(new_ta.tile));
1073  new_ta.w = max(TileX(cur_ta.tile) + cur_ta.w, TileX(new_ta.tile) + new_ta.w) - x;
1074  new_ta.h = max(TileY(cur_ta.tile) + cur_ta.h, TileY(new_ta.tile) + new_ta.h) - y;
1075  new_ta.tile = TileXY(x, y);
1076 
1077  /* make sure the final size is not too big. */
1079  return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
1080  }
1081 
1082  return CommandCost();
1083 }
1084 
1085 static inline byte *CreateSingle(byte *layout, int n)
1086 {
1087  int i = n;
1088  do *layout++ = 0; while (--i);
1089  layout[((n - 1) >> 1) - n] = 2;
1090  return layout;
1091 }
1092 
1093 static inline byte *CreateMulti(byte *layout, int n, byte b)
1094 {
1095  int i = n;
1096  do *layout++ = b; while (--i);
1097  if (n > 4) {
1098  layout[0 - n] = 0;
1099  layout[n - 1 - n] = 0;
1100  }
1101  return layout;
1102 }
1103 
1111 void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec)
1112 {
1113  if (statspec != nullptr && statspec->lengths >= plat_len &&
1114  statspec->platforms[plat_len - 1] >= numtracks &&
1115  statspec->layouts[plat_len - 1][numtracks - 1]) {
1116  /* Custom layout defined, follow it. */
1117  memcpy(layout, statspec->layouts[plat_len - 1][numtracks - 1],
1118  plat_len * numtracks);
1119  return;
1120  }
1121 
1122  if (plat_len == 1) {
1123  CreateSingle(layout, numtracks);
1124  } else {
1125  if (numtracks & 1) layout = CreateSingle(layout, plat_len);
1126  numtracks >>= 1;
1127 
1128  while (--numtracks >= 0) {
1129  layout = CreateMulti(layout, plat_len, 4);
1130  layout = CreateMulti(layout, plat_len, 6);
1131  }
1132  }
1133 }
1134 
1146 template <class T, StringID error_message>
1147 CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st)
1148 {
1149  assert(*st == nullptr);
1150  bool check_surrounding = true;
1151 
1153  if (existing_station != INVALID_STATION) {
1154  if (adjacent && existing_station != station_to_join) {
1155  /* You can't build an adjacent station over the top of one that
1156  * already exists. */
1157  return_cmd_error(error_message);
1158  } else {
1159  /* Extend the current station, and don't check whether it will
1160  * be near any other stations. */
1161  *st = T::GetIfValid(existing_station);
1162  check_surrounding = (*st == nullptr);
1163  }
1164  } else {
1165  /* There's no station here. Don't check the tiles surrounding this
1166  * one if the company wanted to build an adjacent station. */
1167  if (adjacent) check_surrounding = false;
1168  }
1169  }
1170 
1171  if (check_surrounding) {
1172  /* Make sure there is no more than one other station around us that is owned by us. */
1173  CommandCost ret = GetStationAround(ta, existing_station, _current_company, st);
1174  if (ret.Failed()) return ret;
1175  }
1176 
1177  /* Distant join */
1178  if (*st == nullptr && station_to_join != INVALID_STATION) *st = T::GetIfValid(station_to_join);
1179 
1180  return CommandCost();
1181 }
1182 
1192 static CommandCost FindJoiningStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
1193 {
1194  return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST>(existing_station, station_to_join, adjacent, ta, st);
1195 }
1196 
1206 CommandCost FindJoiningWaypoint(StationID existing_waypoint, StationID waypoint_to_join, bool adjacent, TileArea ta, Waypoint **wp)
1207 {
1208  return FindJoiningBaseStation<Waypoint, STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST>(existing_waypoint, waypoint_to_join, adjacent, ta, wp);
1209 }
1210 
1216 {
1219  v = v->Last();
1221 }
1222 
1228 {
1230  TryPathReserve(v, true, true);
1231  v = v->Last();
1233 }
1234 
1252 CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1253 {
1254  /* Unpack parameters */
1255  RailType rt = Extract<RailType, 0, 6>(p1);
1256  Axis axis = Extract<Axis, 6, 1>(p1);
1257  byte numtracks = GB(p1, 8, 8);
1258  byte plat_len = GB(p1, 16, 8);
1259  bool adjacent = HasBit(p1, 24);
1260 
1261  StationClassID spec_class = Extract<StationClassID, 0, 8>(p2);
1262  byte spec_index = GB(p2, 8, 8);
1263  StationID station_to_join = GB(p2, 16, 16);
1264 
1265  /* Does the authority allow this? */
1266  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile_org, flags);
1267  if (ret.Failed()) return ret;
1268 
1269  if (!ValParamRailtype(rt)) return CMD_ERROR;
1270 
1271  /* Check if the given station class is valid */
1272  if ((uint)spec_class >= StationClass::GetClassCount() || spec_class == STAT_CLASS_WAYP) return CMD_ERROR;
1273  if (spec_index >= StationClass::Get(spec_class)->GetSpecCount()) return CMD_ERROR;
1274  if (plat_len == 0 || numtracks == 0) return CMD_ERROR;
1275 
1276  int w_org, h_org;
1277  if (axis == AXIS_X) {
1278  w_org = plat_len;
1279  h_org = numtracks;
1280  } else {
1281  h_org = plat_len;
1282  w_org = numtracks;
1283  }
1284 
1285  bool reuse = (station_to_join != NEW_STATION);
1286  if (!reuse) station_to_join = INVALID_STATION;
1287  bool distant_join = (station_to_join != INVALID_STATION);
1288 
1289  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
1290 
1292 
1293  /* these values are those that will be stored in train_tile and station_platforms */
1294  TileArea new_location(tile_org, w_org, h_org);
1295 
1296  /* Make sure the area below consists of clear tiles. (OR tiles belonging to a certain rail station) */
1297  StationID est = INVALID_STATION;
1298  std::vector<Train *> affected_vehicles;
1299  /* Clear the land below the station. */
1300  CommandCost cost = CheckFlatLandRailStation(new_location, flags, axis, &est, rt, affected_vehicles, spec_class, spec_index, plat_len, numtracks);
1301  if (cost.Failed()) return cost;
1302  /* Add construction expenses. */
1303  cost.AddCost((numtracks * _price[PR_BUILD_STATION_RAIL] + _price[PR_BUILD_STATION_RAIL_LENGTH]) * plat_len);
1304  cost.AddCost(numtracks * plat_len * RailBuildCost(rt));
1305 
1306  Station *st = nullptr;
1307  ret = FindJoiningStation(est, station_to_join, adjacent, new_location, &st);
1308  if (ret.Failed()) return ret;
1309 
1310  ret = BuildStationPart(&st, flags, reuse, new_location, STATIONNAMING_RAIL);
1311  if (ret.Failed()) return ret;
1312 
1313  if (st != nullptr && st->train_station.tile != INVALID_TILE) {
1314  CommandCost ret = CanExpandRailStation(st, new_location, axis);
1315  if (ret.Failed()) return ret;
1316  }
1317 
1318  /* Check if we can allocate a custom stationspec to this station */
1319  const StationSpec *statspec = StationClass::Get(spec_class)->GetSpec(spec_index);
1320  int specindex = AllocateSpecToStation(statspec, st, (flags & DC_EXEC) != 0);
1321  if (specindex == -1) return_cmd_error(STR_ERROR_TOO_MANY_STATION_SPECS);
1322 
1323  if (statspec != nullptr) {
1324  /* Perform NewStation checks */
1325 
1326  /* Check if the station size is permitted */
1327  if (HasBit(statspec->disallowed_platforms, min(numtracks - 1, 7)) || HasBit(statspec->disallowed_lengths, min(plat_len - 1, 7))) {
1328  return CMD_ERROR;
1329  }
1330 
1331  /* Check if the station is buildable */
1332  if (HasBit(statspec->callback_mask, CBM_STATION_AVAIL)) {
1333  uint16 cb_res = GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, nullptr, INVALID_TILE);
1334  if (cb_res != CALLBACK_FAILED && !Convert8bitBooleanCallback(statspec->grf_prop.grffile, CBID_STATION_AVAILABILITY, cb_res)) return CMD_ERROR;
1335  }
1336  }
1337 
1338  if (flags & DC_EXEC) {
1339  TileIndexDiff tile_delta;
1340  byte *layout_ptr;
1341  byte numtracks_orig;
1342  Track track;
1343 
1344  st->train_station = new_location;
1345  st->AddFacility(FACIL_TRAIN, new_location.tile);
1346 
1347  st->rect.BeforeAddRect(tile_org, w_org, h_org, StationRect::ADD_TRY);
1348 
1349  if (statspec != nullptr) {
1350  /* Include this station spec's animation trigger bitmask
1351  * in the station's cached copy. */
1352  st->cached_anim_triggers |= statspec->animation.triggers;
1353  }
1354 
1355  tile_delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
1356  track = AxisToTrack(axis);
1357 
1358  layout_ptr = AllocaM(byte, numtracks * plat_len);
1359  GetStationLayout(layout_ptr, numtracks, plat_len, statspec);
1360 
1361  numtracks_orig = numtracks;
1362 
1363  Company *c = Company::Get(st->owner);
1364  TileIndex tile_track = tile_org;
1365  do {
1366  TileIndex tile = tile_track;
1367  int w = plat_len;
1368  do {
1369  byte layout = *layout_ptr++;
1370  if (IsRailStationTile(tile) && HasStationReservation(tile)) {
1371  /* Check for trains having a reservation for this tile. */
1373  if (v != nullptr) {
1374  affected_vehicles.push_back(v);
1376  }
1377  }
1378 
1379  /* Railtype can change when overbuilding. */
1380  if (IsRailStationTile(tile)) {
1381  if (!IsStationTileBlocked(tile)) c->infrastructure.rail[GetRailType(tile)]--;
1382  c->infrastructure.station--;
1383  }
1384 
1385  /* Remove animation if overbuilding */
1386  DeleteAnimatedTile(tile);
1387  byte old_specindex = HasStationTileRail(tile) ? GetCustomStationSpecIndex(tile) : 0;
1388  MakeRailStation(tile, st->owner, st->index, axis, layout & ~1, rt);
1389  /* Free the spec if we overbuild something */
1390  DeallocateSpecFromStation(st, old_specindex);
1391 
1392  SetCustomStationSpecIndex(tile, specindex);
1393  SetStationTileRandomBits(tile, GB(Random(), 0, 4));
1394  SetAnimationFrame(tile, 0);
1395 
1396  if (!IsStationTileBlocked(tile)) c->infrastructure.rail[rt]++;
1397  c->infrastructure.station++;
1398 
1399  if (statspec != nullptr) {
1400  /* Use a fixed axis for GetPlatformInfo as our platforms / numtracks are always the right way around */
1401  uint32 platinfo = GetPlatformInfo(AXIS_X, GetStationGfx(tile), plat_len, numtracks_orig, plat_len - w, numtracks_orig - numtracks, false);
1402 
1403  /* As the station is not yet completely finished, the station does not yet exist. */
1404  uint16 callback = GetStationCallback(CBID_STATION_TILE_LAYOUT, platinfo, 0, statspec, nullptr, tile);
1405  if (callback != CALLBACK_FAILED) {
1406  if (callback < 8) {
1407  SetStationGfx(tile, (callback & ~1) + axis);
1408  } else {
1410  }
1411  }
1412 
1413  /* Trigger station animation -- after building? */
1414  TriggerStationAnimation(st, tile, SAT_BUILT);
1415  }
1416 
1417  tile += tile_delta;
1418  } while (--w);
1419  AddTrackToSignalBuffer(tile_track, track, _current_company);
1420  YapfNotifyTrackLayoutChange(tile_track, track);
1421  tile_track += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta
1422  } while (--numtracks);
1423 
1424  for (uint i = 0; i < affected_vehicles.size(); ++i) {
1425  /* Restore reservations of trains. */
1426  RestoreTrainReservation(affected_vehicles[i]);
1427  }
1428 
1429  /* Check whether we need to expand the reservation of trains already on the station. */
1430  TileArea update_reservation_area;
1431  if (axis == AXIS_X) {
1432  update_reservation_area = TileArea(tile_org, 1, numtracks_orig);
1433  } else {
1434  update_reservation_area = TileArea(tile_org, numtracks_orig, 1);
1435  }
1436 
1437  TILE_AREA_LOOP(tile, update_reservation_area) {
1438  /* Don't even try to make eye candy parts reserved. */
1439  if (IsStationTileBlocked(tile)) continue;
1440 
1441  DiagDirection dir = AxisToDiagDir(axis);
1442  TileIndexDiff tile_offset = TileOffsByDiagDir(dir);
1443  TileIndex platform_begin = tile;
1444  TileIndex platform_end = tile;
1445 
1446  /* We can only account for tiles that are reachable from this tile, so ignore primarily blocked tiles while finding the platform begin and end. */
1447  for (TileIndex next_tile = platform_begin - tile_offset; IsCompatibleTrainStationTile(next_tile, platform_begin); next_tile -= tile_offset) {
1448  platform_begin = next_tile;
1449  }
1450  for (TileIndex next_tile = platform_end + tile_offset; IsCompatibleTrainStationTile(next_tile, platform_end); next_tile += tile_offset) {
1451  platform_end = next_tile;
1452  }
1453 
1454  /* If there is at least on reservation on the platform, we reserve the whole platform. */
1455  bool reservation = false;
1456  for (TileIndex t = platform_begin; !reservation && t <= platform_end; t += tile_offset) {
1457  reservation = HasStationReservation(t);
1458  }
1459 
1460  if (reservation) {
1461  SetRailStationPlatformReservation(platform_begin, dir, true);
1462  }
1463  }
1464 
1465  st->MarkTilesDirty(false);
1466  st->AfterStationTileSetChange(true, STATION_RAIL);
1467  }
1468 
1469  return cost;
1470 }
1471 
1472 static TileArea MakeStationAreaSmaller(BaseStation *st, TileArea ta, bool (*func)(BaseStation *, TileIndex))
1473 {
1474 restart:
1475 
1476  /* too small? */
1477  if (ta.w != 0 && ta.h != 0) {
1478  /* check the left side, x = constant, y changes */
1479  for (uint i = 0; !func(st, ta.tile + TileDiffXY(0, i));) {
1480  /* the left side is unused? */
1481  if (++i == ta.h) {
1482  ta.tile += TileDiffXY(1, 0);
1483  ta.w--;
1484  goto restart;
1485  }
1486  }
1487 
1488  /* check the right side, x = constant, y changes */
1489  for (uint i = 0; !func(st, ta.tile + TileDiffXY(ta.w - 1, i));) {
1490  /* the right side is unused? */
1491  if (++i == ta.h) {
1492  ta.w--;
1493  goto restart;
1494  }
1495  }
1496 
1497  /* check the upper side, y = constant, x changes */
1498  for (uint i = 0; !func(st, ta.tile + TileDiffXY(i, 0));) {
1499  /* the left side is unused? */
1500  if (++i == ta.w) {
1501  ta.tile += TileDiffXY(0, 1);
1502  ta.h--;
1503  goto restart;
1504  }
1505  }
1506 
1507  /* check the lower side, y = constant, x changes */
1508  for (uint i = 0; !func(st, ta.tile + TileDiffXY(i, ta.h - 1));) {
1509  /* the left side is unused? */
1510  if (++i == ta.w) {
1511  ta.h--;
1512  goto restart;
1513  }
1514  }
1515  } else {
1516  ta.Clear();
1517  }
1518 
1519  return ta;
1520 }
1521 
1522 static bool TileBelongsToRailStation(BaseStation *st, TileIndex tile)
1523 {
1524  return st->TileBelongsToRailStation(tile);
1525 }
1526 
1527 static void MakeRailStationAreaSmaller(BaseStation *st)
1528 {
1529  st->train_station = MakeStationAreaSmaller(st, st->train_station, TileBelongsToRailStation);
1530 }
1531 
1532 static bool TileBelongsToShipStation(BaseStation *st, TileIndex tile)
1533 {
1534  return IsDockTile(tile) && GetStationIndex(tile) == st->index;
1535 }
1536 
1537 static void MakeShipStationAreaSmaller(Station *st)
1538 {
1539  st->ship_station = MakeStationAreaSmaller(st, st->ship_station, TileBelongsToShipStation);
1540  UpdateStationDockingTiles(st);
1541 }
1542 
1553 template <class T>
1554 CommandCost RemoveFromRailBaseStation(TileArea ta, std::vector<T *> &affected_stations, DoCommandFlag flags, Money removal_cost, bool keep_rail)
1555 {
1556  /* Count of the number of tiles removed */
1557  int quantity = 0;
1558  CommandCost total_cost(EXPENSES_CONSTRUCTION);
1559  /* Accumulator for the errors seen during clearing. If no errors happen,
1560  * and the quantity is 0 there is no station. Otherwise it will be one
1561  * of the other error that got accumulated. */
1563 
1564  /* Do the action for every tile into the area */
1565  TILE_AREA_LOOP(tile, ta) {
1566  /* Make sure the specified tile is a rail station */
1567  if (!HasStationTileRail(tile)) continue;
1568 
1569  /* If there is a vehicle on ground, do not allow to remove (flood) the tile */
1571  error.AddCost(ret);
1572  if (ret.Failed()) continue;
1573 
1574  /* Check ownership of station */
1575  T *st = T::GetByTile(tile);
1576  if (st == nullptr) continue;
1577 
1578  if (_current_company != OWNER_WATER) {
1579  CommandCost ret = CheckOwnership(st->owner);
1580  error.AddCost(ret);
1581  if (ret.Failed()) continue;
1582  }
1583 
1584  /* If we reached here, the tile is valid so increase the quantity of tiles we will remove */
1585  quantity++;
1586 
1587  if (keep_rail || IsStationTileBlocked(tile)) {
1588  /* Don't refund the 'steel' of the track when we keep the
1589  * rail, or when the tile didn't have any rail at all. */
1590  total_cost.AddCost(-_price[PR_CLEAR_RAIL]);
1591  }
1592 
1593  if (flags & DC_EXEC) {
1594  /* read variables before the station tile is removed */
1595  uint specindex = GetCustomStationSpecIndex(tile);
1596  Track track = GetRailStationTrack(tile);
1597  Owner owner = GetTileOwner(tile);
1598  RailType rt = GetRailType(tile);
1599  Train *v = nullptr;
1600 
1601  if (HasStationReservation(tile)) {
1602  v = GetTrainForReservation(tile, track);
1603  if (v != nullptr) FreeTrainReservation(v);
1604  }
1605 
1606  bool build_rail = keep_rail && !IsStationTileBlocked(tile);
1607  if (!build_rail && !IsStationTileBlocked(tile)) Company::Get(owner)->infrastructure.rail[rt]--;
1608 
1609  DoClearSquare(tile);
1610  DeleteNewGRFInspectWindow(GSF_STATIONS, tile);
1611  if (build_rail) MakeRailNormal(tile, owner, TrackToTrackBits(track), rt);
1612  Company::Get(owner)->infrastructure.station--;
1614 
1615  st->rect.AfterRemoveTile(st, tile);
1616  AddTrackToSignalBuffer(tile, track, owner);
1617  YapfNotifyTrackLayoutChange(tile, track);
1618 
1619  DeallocateSpecFromStation(st, specindex);
1620 
1621  include(affected_stations, st);
1622 
1623  if (v != nullptr) RestoreTrainReservation(v);
1624  }
1625  }
1626 
1627  if (quantity == 0) return error.Failed() ? error : CommandCost(STR_ERROR_THERE_IS_NO_STATION);
1628 
1629  for (T *st : affected_stations) {
1630 
1631  /* now we need to make the "spanned" area of the railway station smaller
1632  * if we deleted something at the edges.
1633  * we also need to adjust train_tile. */
1634  MakeRailStationAreaSmaller(st);
1635  UpdateStationSignCoord(st);
1636 
1637  /* if we deleted the whole station, delete the train facility. */
1638  if (st->train_station.tile == INVALID_TILE) {
1639  st->facilities &= ~FACIL_TRAIN;
1641  st->UpdateVirtCoord();
1643  }
1644  }
1645 
1646  total_cost.AddCost(quantity * removal_cost);
1647  return total_cost;
1648 }
1649 
1661 CommandCost CmdRemoveFromRailStation(TileIndex start, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1662 {
1663  TileIndex end = p1 == 0 ? start : p1;
1664  if (start >= MapSize() || end >= MapSize()) return CMD_ERROR;
1665 
1666  TileArea ta(start, end);
1667  std::vector<Station *> affected_stations;
1668 
1669  CommandCost ret = RemoveFromRailBaseStation(ta, affected_stations, flags, _price[PR_CLEAR_STATION_RAIL], HasBit(p2, 0));
1670  if (ret.Failed()) return ret;
1671 
1672  /* Do all station specific functions here. */
1673  for (Station *st : affected_stations) {
1674 
1676  st->MarkTilesDirty(false);
1677  st->RecomputeCatchment();
1678  }
1679 
1680  /* Now apply the rail cost to the number that we deleted */
1681  return ret;
1682 }
1683 
1695 CommandCost CmdRemoveFromRailWaypoint(TileIndex start, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1696 {
1697  TileIndex end = p1 == 0 ? start : p1;
1698  if (start >= MapSize() || end >= MapSize()) return CMD_ERROR;
1699 
1700  TileArea ta(start, end);
1701  std::vector<Waypoint *> affected_stations;
1702 
1703  return RemoveFromRailBaseStation(ta, affected_stations, flags, _price[PR_CLEAR_WAYPOINT_RAIL], HasBit(p2, 0));
1704 }
1705 
1706 
1715 template <class T>
1717 {
1718  /* Current company owns the station? */
1719  if (_current_company != OWNER_WATER) {
1720  CommandCost ret = CheckOwnership(st->owner);
1721  if (ret.Failed()) return ret;
1722  }
1723 
1724  /* determine width and height of platforms */
1725  TileArea ta = st->train_station;
1726 
1727  assert(ta.w != 0 && ta.h != 0);
1728 
1730  /* clear all areas of the station */
1731  TILE_AREA_LOOP(tile, ta) {
1732  /* only remove tiles that are actually train station tiles */
1733  if (st->TileBelongsToRailStation(tile)) {
1734  std::vector<T*> affected_stations; // dummy
1735  CommandCost ret = RemoveFromRailBaseStation(TileArea(tile, 1, 1), affected_stations, flags, removal_cost, false);
1736  if (ret.Failed()) return ret;
1737  cost.AddCost(ret);
1738  }
1739  }
1740 
1741  return cost;
1742 }
1743 
1751 {
1752  /* if there is flooding, remove platforms tile by tile */
1753  if (_current_company == OWNER_WATER) {
1754  return DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAIL_STATION);
1755  }
1756 
1757  Station *st = Station::GetByTile(tile);
1758  CommandCost cost = RemoveRailStation(st, flags, _price[PR_CLEAR_STATION_RAIL]);
1759 
1760  if (flags & DC_EXEC) st->RecomputeCatchment();
1761 
1762  return cost;
1763 }
1764 
1772 {
1773  /* if there is flooding, remove waypoints tile by tile */
1774  if (_current_company == OWNER_WATER) {
1775  return DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAIL_WAYPOINT);
1776  }
1777 
1778  return RemoveRailStation(Waypoint::GetByTile(tile), flags, _price[PR_CLEAR_WAYPOINT_RAIL]);
1779 }
1780 
1781 
1787 static RoadStop **FindRoadStopSpot(bool truck_station, Station *st)
1788 {
1789  RoadStop **primary_stop = (truck_station) ? &st->truck_stops : &st->bus_stops;
1790 
1791  if (*primary_stop == nullptr) {
1792  /* we have no roadstop of the type yet, so write a "primary stop" */
1793  return primary_stop;
1794  } else {
1795  /* there are stops already, so append to the end of the list */
1796  RoadStop *stop = *primary_stop;
1797  while (stop->next != nullptr) stop = stop->next;
1798  return &stop->next;
1799  }
1800 }
1801 
1803 
1813 static CommandCost FindJoiningRoadStop(StationID existing_stop, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
1814 {
1815  return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST>(existing_stop, station_to_join, adjacent, ta, st);
1816 }
1817 
1834 CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1835 {
1836  bool type = HasBit(p2, 0);
1837  bool is_drive_through = HasBit(p2, 1);
1838  RoadType rt = Extract<RoadType, 5, 6>(p2);
1839  if (!ValParamRoadType(rt)) return CMD_ERROR;
1840  StationID station_to_join = GB(p2, 16, 16);
1841  bool reuse = (station_to_join != NEW_STATION);
1842  if (!reuse) station_to_join = INVALID_STATION;
1843  bool distant_join = (station_to_join != INVALID_STATION);
1844 
1845  uint8 width = (uint8)GB(p1, 0, 8);
1846  uint8 length = (uint8)GB(p1, 8, 8);
1847 
1848  /* Check if the requested road stop is too big */
1849  if (width > _settings_game.station.station_spread || length > _settings_game.station.station_spread) return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
1850  /* Check for incorrect width / length. */
1851  if (width == 0 || length == 0) return CMD_ERROR;
1852  /* Check if the first tile and the last tile are valid */
1853  if (!IsValidTile(tile) || TileAddWrap(tile, width - 1, length - 1) == INVALID_TILE) return CMD_ERROR;
1854 
1855  TileArea roadstop_area(tile, width, length);
1856 
1857  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
1858 
1859  /* Trams only have drive through stops */
1860  if (!is_drive_through && RoadTypeIsTram(rt)) return CMD_ERROR;
1861 
1862  DiagDirection ddir;
1863  Axis axis;
1864  if (is_drive_through) {
1865  /* By definition axis is valid, due to there being 2 axes and reading 1 bit. */
1866  axis = Extract<Axis, 3, 1>(p2);
1867  ddir = AxisToDiagDir(axis);
1868  } else {
1869  /* By definition ddir is valid, due to there being 4 diagonal directions and reading 2 bits. */
1870  ddir = Extract<DiagDirection, 3, 2>(p2);
1871  axis = DiagDirToAxis(ddir);
1872  }
1873 
1874  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags);
1875  if (ret.Failed()) return ret;
1876 
1877  /* Total road stop cost. */
1878  CommandCost cost(EXPENSES_CONSTRUCTION, roadstop_area.w * roadstop_area.h * _price[type ? PR_BUILD_STATION_TRUCK : PR_BUILD_STATION_BUS]);
1879  StationID est = INVALID_STATION;
1880  ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 5 << axis : 1 << ddir, is_drive_through, type, axis, &est, rt);
1881  if (ret.Failed()) return ret;
1882  cost.AddCost(ret);
1883 
1884  Station *st = nullptr;
1885  ret = FindJoiningRoadStop(est, station_to_join, HasBit(p2, 2), roadstop_area, &st);
1886  if (ret.Failed()) return ret;
1887 
1888  /* Check if this number of road stops can be allocated. */
1889  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);
1890 
1891  ret = BuildStationPart(&st, flags, reuse, roadstop_area, STATIONNAMING_ROAD);
1892  if (ret.Failed()) return ret;
1893 
1894  if (flags & DC_EXEC) {
1895  /* Check every tile in the area. */
1896  TILE_AREA_LOOP(cur_tile, roadstop_area) {
1897  /* Get existing road types and owners before any tile clearing */
1898  RoadType road_rt = MayHaveRoad(cur_tile) ? GetRoadType(cur_tile, RTT_ROAD) : INVALID_ROADTYPE;
1899  RoadType tram_rt = MayHaveRoad(cur_tile) ? GetRoadType(cur_tile, RTT_TRAM) : INVALID_ROADTYPE;
1900  Owner road_owner = road_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_ROAD) : _current_company;
1901  Owner tram_owner = tram_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_TRAM) : _current_company;
1902 
1903  if (IsTileType(cur_tile, MP_STATION) && IsRoadStop(cur_tile)) {
1904  RemoveRoadStop(cur_tile, flags);
1905  }
1906 
1907  RoadStop *road_stop = new RoadStop(cur_tile);
1908  /* Insert into linked list of RoadStops. */
1909  RoadStop **currstop = FindRoadStopSpot(type, st);
1910  *currstop = road_stop;
1911 
1912  if (type) {
1913  st->truck_station.Add(cur_tile);
1914  } else {
1915  st->bus_station.Add(cur_tile);
1916  }
1917 
1918  /* Initialize an empty station. */
1919  st->AddFacility((type) ? FACIL_TRUCK_STOP : FACIL_BUS_STOP, cur_tile);
1920 
1921  st->rect.BeforeAddTile(cur_tile, StationRect::ADD_TRY);
1922 
1923  RoadStopType rs_type = type ? ROADSTOP_TRUCK : ROADSTOP_BUS;
1924  if (is_drive_through) {
1925  /* Update company infrastructure counts. If the current tile is a normal road tile, remove the old
1926  * bits first. */
1927  if (IsNormalRoadTile(cur_tile)) {
1928  UpdateCompanyRoadInfrastructure(road_rt, road_owner, -(int)CountBits(GetRoadBits(cur_tile, RTT_ROAD)));
1929  UpdateCompanyRoadInfrastructure(tram_rt, tram_owner, -(int)CountBits(GetRoadBits(cur_tile, RTT_TRAM)));
1930  }
1931 
1932  if (road_rt == INVALID_ROADTYPE && RoadTypeIsRoad(rt)) road_rt = rt;
1933  if (tram_rt == INVALID_ROADTYPE && RoadTypeIsTram(rt)) tram_rt = rt;
1934 
1935  UpdateCompanyRoadInfrastructure(road_rt, road_owner, 2);
1936  UpdateCompanyRoadInfrastructure(tram_rt, tram_owner, 2);
1937 
1938  MakeDriveThroughRoadStop(cur_tile, st->owner, road_owner, tram_owner, st->index, rs_type, road_rt, tram_rt, axis);
1939  road_stop->MakeDriveThrough();
1940  } else {
1941  if (road_rt == INVALID_ROADTYPE && RoadTypeIsRoad(rt)) road_rt = rt;
1942  if (tram_rt == INVALID_ROADTYPE && RoadTypeIsTram(rt)) tram_rt = rt;
1943  /* Non-drive-through stop never overbuild and always count as two road bits. */
1944  Company::Get(st->owner)->infrastructure.road[rt] += 2;
1945  MakeRoadStop(cur_tile, st->owner, st->index, rs_type, road_rt, tram_rt, ddir);
1946  }
1947  Company::Get(st->owner)->infrastructure.station++;
1948 
1949  MarkTileDirtyByTile(cur_tile);
1950  }
1951  }
1952 
1953  if (st != nullptr) {
1954  st->AfterStationTileSetChange(true, type ? STATION_TRUCK: STATION_BUS);
1955  }
1956  return cost;
1957 }
1958 
1959 
1960 static Vehicle *ClearRoadStopStatusEnum(Vehicle *v, void *)
1961 {
1962  if (v->type == VEH_ROAD) {
1963  /* Okay... we are a road vehicle on a drive through road stop.
1964  * But that road stop has just been removed, so we need to make
1965  * sure we are in a valid state... however, vehicles can also
1966  * turn on road stop tiles, so only clear the 'road stop' state
1967  * bits and only when the state was 'in road stop', otherwise
1968  * we'll end up clearing the turn around bits. */
1969  RoadVehicle *rv = RoadVehicle::From(v);
1971  }
1972 
1973  return nullptr;
1974 }
1975 
1976 
1984 {
1985  Station *st = Station::GetByTile(tile);
1986 
1987  if (_current_company != OWNER_WATER) {
1988  CommandCost ret = CheckOwnership(st->owner);
1989  if (ret.Failed()) return ret;
1990  }
1991 
1992  bool is_truck = IsTruckStop(tile);
1993 
1994  RoadStop **primary_stop;
1995  RoadStop *cur_stop;
1996  if (is_truck) { // truck stop
1997  primary_stop = &st->truck_stops;
1998  cur_stop = RoadStop::GetByTile(tile, ROADSTOP_TRUCK);
1999  } else {
2000  primary_stop = &st->bus_stops;
2001  cur_stop = RoadStop::GetByTile(tile, ROADSTOP_BUS);
2002  }
2003 
2004  assert(cur_stop != nullptr);
2005 
2006  /* don't do the check for drive-through road stops when company bankrupts */
2007  if (IsDriveThroughStopTile(tile) && (flags & DC_BANKRUPT)) {
2008  /* remove the 'going through road stop' status from all vehicles on that tile */
2009  if (flags & DC_EXEC) FindVehicleOnPos(tile, nullptr, &ClearRoadStopStatusEnum);
2010  } else {
2012  if (ret.Failed()) return ret;
2013  }
2014 
2015  if (flags & DC_EXEC) {
2016  if (*primary_stop == cur_stop) {
2017  /* removed the first stop in the list */
2018  *primary_stop = cur_stop->next;
2019  /* removed the only stop? */
2020  if (*primary_stop == nullptr) {
2021  st->facilities &= (is_truck ? ~FACIL_TRUCK_STOP : ~FACIL_BUS_STOP);
2022  }
2023  } else {
2024  /* tell the predecessor in the list to skip this stop */
2025  RoadStop *pred = *primary_stop;
2026  while (pred->next != cur_stop) pred = pred->next;
2027  pred->next = cur_stop->next;
2028  }
2029 
2030  /* Update company infrastructure counts. */
2031  FOR_ALL_ROADTRAMTYPES(rtt) {
2032  RoadType rt = GetRoadType(tile, rtt);
2033  UpdateCompanyRoadInfrastructure(rt, GetRoadOwner(tile, rtt), -2);
2034  }
2035 
2036  Company::Get(st->owner)->infrastructure.station--;
2038 
2039  if (IsDriveThroughStopTile(tile)) {
2040  /* Clears the tile for us */
2041  cur_stop->ClearDriveThrough();
2042  } else {
2043  DoClearSquare(tile);
2044  }
2045 
2046  delete cur_stop;
2047 
2048  /* Make sure no vehicle is going to the old roadstop */
2049  for (RoadVehicle *v : RoadVehicle::Iterate()) {
2050  if (v->First() == v && v->current_order.IsType(OT_GOTO_STATION) &&
2051  v->dest_tile == tile) {
2052  v->SetDestTile(v->GetOrderStationLocation(st->index));
2053  }
2054  }
2055 
2056  st->rect.AfterRemoveTile(st, tile);
2057 
2058  st->AfterStationTileSetChange(false, is_truck ? STATION_TRUCK: STATION_BUS);
2059 
2060  /* Update the tile area of the truck/bus stop */
2061  if (is_truck) {
2062  st->truck_station.Clear();
2063  for (const RoadStop *rs = st->truck_stops; rs != nullptr; rs = rs->next) st->truck_station.Add(rs->xy);
2064  } else {
2065  st->bus_station.Clear();
2066  for (const RoadStop *rs = st->bus_stops; rs != nullptr; rs = rs->next) st->bus_station.Add(rs->xy);
2067  }
2068  }
2069 
2070  return CommandCost(EXPENSES_CONSTRUCTION, _price[is_truck ? PR_CLEAR_STATION_TRUCK : PR_CLEAR_STATION_BUS]);
2071 }
2072 
2084 CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
2085 {
2086  uint8 width = (uint8)GB(p1, 0, 8);
2087  uint8 height = (uint8)GB(p1, 8, 8);
2088  bool keep_drive_through_roads = !HasBit(p2, 1);
2089 
2090  /* Check for incorrect width / height. */
2091  if (width == 0 || height == 0) return CMD_ERROR;
2092  /* Check if the first tile and the last tile are valid */
2093  if (!IsValidTile(tile) || TileAddWrap(tile, width - 1, height - 1) == INVALID_TILE) return CMD_ERROR;
2094  /* Bankrupting company is not supposed to remove roads, there may be road vehicles. */
2095  if (!keep_drive_through_roads && (flags & DC_BANKRUPT)) return CMD_ERROR;
2096 
2097  TileArea roadstop_area(tile, width, height);
2098 
2100  CommandCost last_error(STR_ERROR_THERE_IS_NO_STATION);
2101  bool had_success = false;
2102 
2103  TILE_AREA_LOOP(cur_tile, roadstop_area) {
2104  /* Make sure the specified tile is a road stop of the correct type */
2105  if (!IsTileType(cur_tile, MP_STATION) || !IsRoadStop(cur_tile) || (uint32)GetRoadStopType(cur_tile) != GB(p2, 0, 1)) continue;
2106 
2107  /* Save information on to-be-restored roads before the stop is removed. */
2108  RoadBits road_bits = ROAD_NONE;
2109  RoadType road_type[] = { INVALID_ROADTYPE, INVALID_ROADTYPE };
2110  Owner road_owner[] = { OWNER_NONE, OWNER_NONE };
2111  if (IsDriveThroughStopTile(cur_tile)) {
2112  FOR_ALL_ROADTRAMTYPES(rtt) {
2113  road_type[rtt] = GetRoadType(cur_tile, rtt);
2114  if (road_type[rtt] == INVALID_ROADTYPE) continue;
2115  road_owner[rtt] = GetRoadOwner(cur_tile, rtt);
2116  /* If we don't want to preserve our roads then restore only roads of others. */
2117  if (!keep_drive_through_roads && road_owner[rtt] == _current_company) road_type[rtt] = INVALID_ROADTYPE;
2118  }
2119  road_bits = AxisToRoadBits(DiagDirToAxis(GetRoadStopDir(cur_tile)));
2120  }
2121 
2122  CommandCost ret = RemoveRoadStop(cur_tile, flags);
2123  if (ret.Failed()) {
2124  last_error = ret;
2125  continue;
2126  }
2127  cost.AddCost(ret);
2128  had_success = true;
2129 
2130  /* Restore roads. */
2131  if ((flags & DC_EXEC) && (road_type[RTT_ROAD] != INVALID_ROADTYPE || road_type[RTT_TRAM] != INVALID_ROADTYPE)) {
2132  MakeRoadNormal(cur_tile, road_bits, road_type[RTT_ROAD], road_type[RTT_TRAM], ClosestTownFromTile(cur_tile, UINT_MAX)->index,
2133  road_owner[RTT_ROAD], road_owner[RTT_TRAM]);
2134 
2135  /* Update company infrastructure counts. */
2136  int count = CountBits(road_bits);
2137  UpdateCompanyRoadInfrastructure(road_type[RTT_ROAD], road_owner[RTT_ROAD], count);
2138  UpdateCompanyRoadInfrastructure(road_type[RTT_TRAM], road_owner[RTT_TRAM], count);
2139  }
2140  }
2141 
2142  return had_success ? cost : last_error;
2143 }
2144 
2153 uint8 GetAirportNoiseLevelForDistance(const AirportSpec *as, uint distance)
2154 {
2155  /* 0 cannot be accounted, and 1 is the lowest that can be reduced from town.
2156  * So no need to go any further*/
2157  if (as->noise_level < 2) return as->noise_level;
2158 
2159  /* The steps for measuring noise reduction are based on the "magical" (and arbitrary) 8 base distance
2160  * adding the town_council_tolerance 4 times, as a way to graduate, depending of the tolerance.
2161  * Basically, it says that the less tolerant a town is, the bigger the distance before
2162  * an actual decrease can be granted */
2163  uint8 town_tolerance_distance = 8 + (_settings_game.difficulty.town_council_tolerance * 4);
2164 
2165  /* now, we want to have the distance segmented using the distance judged bareable by town
2166  * This will give us the coefficient of reduction the distance provides. */
2167  uint noise_reduction = distance / town_tolerance_distance;
2168 
2169  /* If the noise reduction equals the airport noise itself, don't give it for free.
2170  * Otherwise, simply reduce the airport's level. */
2171  return noise_reduction >= as->noise_level ? 1 : as->noise_level - noise_reduction;
2172 }
2173 
2182 Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it, uint &mindist)
2183 {
2184  assert(Town::GetNumItems() > 0);
2185 
2186  Town *nearest = nullptr;
2187 
2188  uint perimeter_min_x = TileX(it);
2189  uint perimeter_min_y = TileY(it);
2190  uint perimeter_max_x = perimeter_min_x + as->size_x - 1;
2191  uint perimeter_max_y = perimeter_min_y + as->size_y - 1;
2192 
2193  mindist = UINT_MAX - 1; // prevent overflow
2194 
2195  std::unique_ptr<TileIterator> copy(it.Clone());
2196  for (TileIndex cur_tile = *copy; cur_tile != INVALID_TILE; cur_tile = ++*copy) {
2197  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) {
2198  Town *t = CalcClosestTownFromTile(cur_tile, mindist + 1);
2199  if (t == nullptr) continue;
2200 
2201  uint dist = DistanceManhattan(t->xy, cur_tile);
2202  if (dist == mindist && t->index < nearest->index) nearest = t;
2203  if (dist < mindist) {
2204  nearest = t;
2205  mindist = dist;
2206  }
2207  }
2208  }
2209 
2210  return nearest;
2211 }
2212 
2213 
2216 {
2217  for (Town *t : Town::Iterate()) t->noise_reached = 0;
2218 
2219  for (const Station *st : Station::Iterate()) {
2220  if (st->airport.tile != INVALID_TILE && st->airport.type != AT_OILRIG) {
2221  const AirportSpec *as = st->airport.GetSpec();
2222  AirportTileIterator it(st);
2223  uint dist;
2224  Town *nearest = AirportGetNearestTown(as, it, dist);
2225  nearest->noise_reached += GetAirportNoiseLevelForDistance(as, dist);
2226  }
2227  }
2228 }
2229 
2243 CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
2244 {
2245  StationID station_to_join = GB(p2, 16, 16);
2246  bool reuse = (station_to_join != NEW_STATION);
2247  if (!reuse) station_to_join = INVALID_STATION;
2248  bool distant_join = (station_to_join != INVALID_STATION);
2249  byte airport_type = GB(p1, 0, 8);
2250  byte layout = GB(p1, 8, 8);
2251 
2252  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
2253 
2254  if (airport_type >= NUM_AIRPORTS) return CMD_ERROR;
2255 
2256  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags);
2257  if (ret.Failed()) return ret;
2258 
2259  /* Check if a valid, buildable airport was chosen for construction */
2260  const AirportSpec *as = AirportSpec::Get(airport_type);
2261  if (!as->IsAvailable() || layout >= as->num_table) return CMD_ERROR;
2262  if (!as->IsWithinMapBounds(layout, tile)) return CMD_ERROR;
2263 
2264  Direction rotation = as->rotation[layout];
2265  int w = as->size_x;
2266  int h = as->size_y;
2267  if (rotation == DIR_E || rotation == DIR_W) Swap(w, h);
2268  TileArea airport_area = TileArea(tile, w, h);
2269 
2271  return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
2272  }
2273 
2274  AirportTileTableIterator iter(as->table[layout], tile);
2275  CommandCost cost = CheckFlatLandAirport(iter, flags);
2276  if (cost.Failed()) return cost;
2277 
2278  /* The noise level is the noise from the airport and reduce it to account for the distance to the town center. */
2279  uint dist;
2280  Town *nearest = AirportGetNearestTown(as, iter, dist);
2281  uint newnoise_level = GetAirportNoiseLevelForDistance(as, dist);
2282 
2283  /* Check if local auth would allow a new airport */
2284  StringID authority_refuse_message = STR_NULL;
2285  Town *authority_refuse_town = nullptr;
2286 
2288  /* do not allow to build a new airport if this raise the town noise over the maximum allowed by town */
2289  if ((nearest->noise_reached + newnoise_level) > nearest->MaxTownNoise()) {
2290  authority_refuse_message = STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE;
2291  authority_refuse_town = nearest;
2292  }
2293  } else {
2294  Town *t = ClosestTownFromTile(tile, UINT_MAX);
2295  uint num = 0;
2296  for (const Station *st : Station::Iterate()) {
2297  if (st->town == t && (st->facilities & FACIL_AIRPORT) && st->airport.type != AT_OILRIG) num++;
2298  }
2299  if (num >= 2) {
2300  authority_refuse_message = STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT;
2301  authority_refuse_town = t;
2302  }
2303  }
2304 
2305  if (authority_refuse_message != STR_NULL) {
2306  SetDParam(0, authority_refuse_town->index);
2307  return_cmd_error(authority_refuse_message);
2308  }
2309 
2310  Station *st = nullptr;
2311  ret = FindJoiningStation(INVALID_STATION, station_to_join, HasBit(p2, 0), airport_area, &st);
2312  if (ret.Failed()) return ret;
2313 
2314  /* Distant join */
2315  if (st == nullptr && distant_join) st = Station::GetIfValid(station_to_join);
2316 
2317  ret = BuildStationPart(&st, flags, reuse, airport_area, (GetAirport(airport_type)->flags & AirportFTAClass::AIRPLANES) ? STATIONNAMING_AIRPORT : STATIONNAMING_HELIPORT);
2318  if (ret.Failed()) return ret;
2319 
2320  if (st != nullptr && st->airport.tile != INVALID_TILE) {
2321  return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT);
2322  }
2323 
2324  for (AirportTileTableIterator iter(as->table[layout], tile); iter != INVALID_TILE; ++iter) {
2325  cost.AddCost(_price[PR_BUILD_STATION_AIRPORT]);
2326  }
2327 
2328  if (flags & DC_EXEC) {
2329  /* Always add the noise, so there will be no need to recalculate when option toggles */
2330  nearest->noise_reached += newnoise_level;
2331 
2332  st->AddFacility(FACIL_AIRPORT, tile);
2333  st->airport.type = airport_type;
2334  st->airport.layout = layout;
2335  st->airport.flags = 0;
2336  st->airport.rotation = rotation;
2337 
2338  st->rect.BeforeAddRect(tile, w, h, StationRect::ADD_TRY);
2339 
2340  for (AirportTileTableIterator iter(as->table[layout], tile); iter != INVALID_TILE; ++iter) {
2341  MakeAirport(iter, st->owner, st->index, iter.GetStationGfx(), WATER_CLASS_INVALID);
2342  SetStationTileRandomBits(iter, GB(Random(), 0, 4));
2343  st->airport.Add(iter);
2344 
2346  }
2347 
2348  /* Only call the animation trigger after all tiles have been built */
2349  for (AirportTileTableIterator iter(as->table[layout], tile); iter != INVALID_TILE; ++iter) {
2350  AirportTileAnimationTrigger(st, iter, AAT_BUILT);
2351  }
2352 
2354 
2355  Company::Get(st->owner)->infrastructure.airport++;
2356 
2357  st->AfterStationTileSetChange(true, STATION_AIRPORT);
2359 
2362  }
2363  }
2364 
2365  return cost;
2366 }
2367 
2375 {
2376  Station *st = Station::GetByTile(tile);
2377 
2378  if (_current_company != OWNER_WATER) {
2379  CommandCost ret = CheckOwnership(st->owner);
2380  if (ret.Failed()) return ret;
2381  }
2382 
2383  tile = st->airport.tile;
2384 
2386 
2387  for (const Aircraft *a : Aircraft::Iterate()) {
2388  if (!a->IsNormalAircraft()) continue;
2389  if (a->targetairport == st->index && a->state != FLYING) {
2390  return_cmd_error(STR_ERROR_AIRCRAFT_IN_THE_WAY);
2391  }
2392  }
2393 
2394  if (flags & DC_EXEC) {
2395  const AirportSpec *as = st->airport.GetSpec();
2396  /* The noise level is the noise from the airport and reduce it to account for the distance to the town center.
2397  * And as for construction, always remove it, even if the setting is not set, in order to avoid the
2398  * need of recalculation */
2399  AirportTileIterator it(st);
2400  uint dist;
2401  Town *nearest = AirportGetNearestTown(as, it, dist);
2402  nearest->noise_reached -= GetAirportNoiseLevelForDistance(as, dist);
2403  }
2404 
2405  TILE_AREA_LOOP(tile_cur, st->airport) {
2406  if (!st->TileBelongsToAirport(tile_cur)) continue;
2407 
2408  CommandCost ret = EnsureNoVehicleOnGround(tile_cur);
2409  if (ret.Failed()) return ret;
2410 
2411  cost.AddCost(_price[PR_CLEAR_STATION_AIRPORT]);
2412 
2413  if (flags & DC_EXEC) {
2414  if (IsHangarTile(tile_cur)) OrderBackup::Reset(tile_cur, false);
2415  DeleteAnimatedTile(tile_cur);
2416  DoClearSquare(tile_cur);
2417  DeleteNewGRFInspectWindow(GSF_AIRPORTTILES, tile_cur);
2418  }
2419  }
2420 
2421  if (flags & DC_EXEC) {
2422  /* Clear the persistent storage. */
2423  delete st->airport.psa;
2424 
2425  for (uint i = 0; i < st->airport.GetNumHangars(); ++i) {
2428  );
2429  }
2430 
2431  st->rect.AfterRemoveRect(st, st->airport);
2432 
2433  st->airport.Clear();
2434  st->facilities &= ~FACIL_AIRPORT;
2435 
2437 
2440  }
2441 
2442  Company::Get(st->owner)->infrastructure.airport--;
2443 
2444  st->AfterStationTileSetChange(false, STATION_AIRPORT);
2445 
2446  DeleteNewGRFInspectWindow(GSF_AIRPORTS, st->index);
2447  }
2448 
2449  return cost;
2450 }
2451 
2461 CommandCost CmdOpenCloseAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
2462 {
2463  if (!Station::IsValidID(p1)) return CMD_ERROR;
2464  Station *st = Station::Get(p1);
2465 
2466  if (!(st->facilities & FACIL_AIRPORT) || st->owner == OWNER_NONE) return CMD_ERROR;
2467 
2468  CommandCost ret = CheckOwnership(st->owner);
2469  if (ret.Failed()) return ret;
2470 
2471  if (flags & DC_EXEC) {
2474  }
2475  return CommandCost();
2476 }
2477 
2484 bool HasStationInUse(StationID station, bool include_company, CompanyID company)
2485 {
2486  for (const Vehicle *v : Vehicle::Iterate()) {
2487  if ((v->owner == company) == include_company) {
2488  const Order *order;
2489  FOR_VEHICLE_ORDERS(v, order) {
2490  if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station) {
2491  return true;
2492  }
2493  }
2494  }
2495  }
2496  return false;
2497 }
2498 
2499 static const TileIndexDiffC _dock_tileoffs_chkaround[] = {
2500  {-1, 0},
2501  { 0, 0},
2502  { 0, 0},
2503  { 0, -1}
2504 };
2505 static const byte _dock_w_chk[4] = { 2, 1, 2, 1 };
2506 static const byte _dock_h_chk[4] = { 1, 2, 1, 2 };
2507 
2517 CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
2518 {
2519  StationID station_to_join = GB(p2, 16, 16);
2520  bool reuse = (station_to_join != NEW_STATION);
2521  if (!reuse) station_to_join = INVALID_STATION;
2522  bool distant_join = (station_to_join != INVALID_STATION);
2523 
2524  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
2525 
2527  if (direction == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2528  direction = ReverseDiagDir(direction);
2529 
2530  /* Docks cannot be placed on rapids */
2531  if (HasTileWaterGround(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2532 
2533  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags);
2534  if (ret.Failed()) return ret;
2535 
2536  if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
2537 
2538  ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
2539  if (ret.Failed()) return ret;
2540 
2541  TileIndex tile_cur = tile + TileOffsByDiagDir(direction);
2542 
2543  if (!IsTileType(tile_cur, MP_WATER) || !IsTileFlat(tile_cur)) {
2544  return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2545  }
2546 
2547  if (IsBridgeAbove(tile_cur)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
2548 
2549  /* Get the water class of the water tile before it is cleared.*/
2550  WaterClass wc = GetWaterClass(tile_cur);
2551 
2552  ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
2553  if (ret.Failed()) return ret;
2554 
2555  tile_cur += TileOffsByDiagDir(direction);
2556  if (!IsTileType(tile_cur, MP_WATER) || !IsTileFlat(tile_cur)) {
2557  return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2558  }
2559 
2560  TileArea dock_area = TileArea(tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]),
2561  _dock_w_chk[direction], _dock_h_chk[direction]);
2562 
2563  /* middle */
2564  Station *st = nullptr;
2565  ret = FindJoiningStation(INVALID_STATION, station_to_join, HasBit(p1, 0), dock_area, &st);
2566  if (ret.Failed()) return ret;
2567 
2568  /* Distant join */
2569  if (st == nullptr && distant_join) st = Station::GetIfValid(station_to_join);
2570 
2571  ret = BuildStationPart(&st, flags, reuse, dock_area, STATIONNAMING_DOCK);
2572  if (ret.Failed()) return ret;
2573 
2574  if (flags & DC_EXEC) {
2575  st->ship_station.Add(tile);
2576  st->ship_station.Add(tile + TileOffsByDiagDir(direction));
2577  st->AddFacility(FACIL_DOCK, tile);
2578 
2579  st->rect.BeforeAddRect(dock_area.tile, dock_area.w, dock_area.h, StationRect::ADD_TRY);
2580 
2581  /* If the water part of the dock is on a canal, update infrastructure counts.
2582  * This is needed as we've unconditionally cleared that tile before. */
2583  if (wc == WATER_CLASS_CANAL) {
2584  Company::Get(st->owner)->infrastructure.water++;
2585  }
2586  Company::Get(st->owner)->infrastructure.station += 2;
2587 
2588  MakeDock(tile, st->owner, st->index, direction, wc);
2589  UpdateStationDockingTiles(st);
2590 
2591  st->AfterStationTileSetChange(true, STATION_DOCK);
2592  }
2593 
2594  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_STATION_DOCK]);
2595 }
2596 
2597 void RemoveDockingTile(TileIndex t)
2598 {
2599  for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
2600  TileIndex tile = t + TileOffsByDiagDir(d);
2601  if (!IsValidTile(tile)) continue;
2602 
2603  if (IsTileType(tile, MP_STATION)) {
2604  Station *st = Station::GetByTile(tile);
2605  if (st != nullptr) UpdateStationDockingTiles(st);
2606  } else if (IsTileType(tile, MP_INDUSTRY)) {
2607  Station *neutral = Industry::GetByTile(tile)->neutral_station;
2608  if (neutral != nullptr) UpdateStationDockingTiles(neutral);
2609  }
2610  }
2611 }
2612 
2619 {
2620  assert(IsValidTile(tile));
2621 
2622  /* Clear and maybe re-set docking tile */
2623  for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
2624  TileIndex docking_tile = tile + TileOffsByDiagDir(d);
2625  if (!IsValidTile(docking_tile)) continue;
2626 
2627  if (IsPossibleDockingTile(docking_tile)) {
2628  SetDockingTile(docking_tile, false);
2629  CheckForDockingTile(docking_tile);
2630  }
2631  }
2632 }
2633 
2641 {
2642  assert(IsDockTile(t));
2643 
2645  static const uint8 _valid_docking_tile[] = {
2646  0, 0, 0, 0, // No docking against the slope part.
2647  1 << DIAGDIR_NE | 1 << DIAGDIR_SW, // Docking permitted at the end
2648  1 << DIAGDIR_NW | 1 << DIAGDIR_SE, // of the flat piers.
2649  };
2650 
2651  StationGfx gfx = GetStationGfx(t);
2652  assert(gfx < lengthof(_valid_docking_tile));
2653  return HasBit(_valid_docking_tile[gfx], d);
2654 }
2655 
2662 {
2663  assert(IsDockTile(t));
2664 
2665  StationGfx gfx = GetStationGfx(t);
2666  if (gfx < GFX_DOCK_BASE_WATER_PART) return t;
2667 
2668  for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
2669  TileIndex tile = t + TileOffsByDiagDir(d);
2670  if (!IsValidTile(tile)) continue;
2671  if (!IsDockTile(tile)) continue;
2672  if (GetStationGfx(tile) < GFX_DOCK_BASE_WATER_PART && tile + TileOffsByDiagDir(GetDockDirection(tile)) == t) return tile;
2673  }
2674 
2675  return INVALID_TILE;
2676 }
2677 
2685 {
2686  Station *st = Station::GetByTile(tile);
2687  CommandCost ret = CheckOwnership(st->owner);
2688  if (ret.Failed()) return ret;
2689 
2690  if (!IsDockTile(tile)) return CMD_ERROR;
2691 
2692  TileIndex tile1 = FindDockLandPart(tile);
2693  if (tile1 == INVALID_TILE) return CMD_ERROR;
2694  TileIndex tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1));
2695 
2696  ret = EnsureNoVehicleOnGround(tile1);
2697  if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2);
2698  if (ret.Failed()) return ret;
2699 
2700  if (flags & DC_EXEC) {
2701  DoClearSquare(tile1);
2702  MarkTileDirtyByTile(tile1);
2703  MakeWaterKeepingClass(tile2, st->owner);
2704 
2705  st->rect.AfterRemoveTile(st, tile1);
2706  st->rect.AfterRemoveTile(st, tile2);
2707 
2708  MakeShipStationAreaSmaller(st);
2709  if (st->ship_station.tile == INVALID_TILE) {
2710  st->ship_station.Clear();
2711  st->docking_station.Clear();
2712  st->facilities &= ~FACIL_DOCK;
2713  }
2714 
2715  Company::Get(st->owner)->infrastructure.station -= 2;
2716 
2717  st->AfterStationTileSetChange(false, STATION_DOCK);
2718 
2721 
2722  /* All ships that were going to our station, can't go to it anymore.
2723  * Just clear the order, then automatically the next appropriate order
2724  * will be selected and in case of no appropriate order it will just
2725  * wander around the world. */
2726  if (!(st->facilities & FACIL_DOCK)) {
2727  for (Ship *s : Ship::Iterate()) {
2728  if (s->current_order.IsType(OT_LOADING) && s->current_order.GetDestination() == st->index) {
2729  s->LeaveStation();
2730  }
2731 
2732  if (s->current_order.IsType(OT_GOTO_STATION) && s->current_order.GetDestination() == st->index) {
2733  s->SetDestTile(s->GetOrderStationLocation(st->index));
2734  }
2735  }
2736  }
2737  }
2738 
2739  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_STATION_DOCK]);
2740 }
2741 
2742 #include "table/station_land.h"
2743 
2744 const DrawTileSprites *GetStationTileLayout(StationType st, byte gfx)
2745 {
2746  return &_station_display_datas[st][gfx];
2747 }
2748 
2758 bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrackOffset *overlay_offset)
2759 {
2760  bool snow_desert;
2761  switch (*ground) {
2762  case SPR_RAIL_TRACK_X:
2763  case SPR_MONO_TRACK_X:
2764  case SPR_MGLV_TRACK_X:
2765  snow_desert = false;
2766  *overlay_offset = RTO_X;
2767  break;
2768 
2769  case SPR_RAIL_TRACK_Y:
2770  case SPR_MONO_TRACK_Y:
2771  case SPR_MGLV_TRACK_Y:
2772  snow_desert = false;
2773  *overlay_offset = RTO_Y;
2774  break;
2775 
2776  case SPR_RAIL_TRACK_X_SNOW:
2777  case SPR_MONO_TRACK_X_SNOW:
2778  case SPR_MGLV_TRACK_X_SNOW:
2779  snow_desert = true;
2780  *overlay_offset = RTO_X;
2781  break;
2782 
2783  case SPR_RAIL_TRACK_Y_SNOW:
2784  case SPR_MONO_TRACK_Y_SNOW:
2785  case SPR_MGLV_TRACK_Y_SNOW:
2786  snow_desert = true;
2787  *overlay_offset = RTO_Y;
2788  break;
2789 
2790  default:
2791  return false;
2792  }
2793 
2794  if (ti != nullptr) {
2795  /* Decide snow/desert from tile */
2797  case LT_ARCTIC:
2798  snow_desert = (uint)ti->z > GetSnowLine() * TILE_HEIGHT;
2799  break;
2800 
2801  case LT_TROPIC:
2802  snow_desert = GetTropicZone(ti->tile) == TROPICZONE_DESERT;
2803  break;
2804 
2805  default:
2806  break;
2807  }
2808  }
2809 
2810  *ground = snow_desert ? SPR_FLAT_SNOW_DESERT_TILE : SPR_FLAT_GRASS_TILE;
2811  return true;
2812 }
2813 
2814 static void DrawTile_Station(TileInfo *ti)
2815 {
2816  const NewGRFSpriteLayout *layout = nullptr;
2817  DrawTileSprites tmp_rail_layout;
2818  const DrawTileSprites *t = nullptr;
2819  int32 total_offset;
2820  const RailtypeInfo *rti = nullptr;
2821  uint32 relocation = 0;
2822  uint32 ground_relocation = 0;
2823  BaseStation *st = nullptr;
2824  const StationSpec *statspec = nullptr;
2825  uint tile_layout = 0;
2826 
2827  if (HasStationRail(ti->tile)) {
2828  rti = GetRailTypeInfo(GetRailType(ti->tile));
2829  total_offset = rti->GetRailtypeSpriteOffset();
2830 
2831  if (IsCustomStationSpecIndex(ti->tile)) {
2832  /* look for customization */
2833  st = BaseStation::GetByTile(ti->tile);
2834  statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec;
2835 
2836  if (statspec != nullptr) {
2837  tile_layout = GetStationGfx(ti->tile);
2838 
2840  uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile);
2841  if (callback != CALLBACK_FAILED) tile_layout = (callback & ~1) + GetRailStationAxis(ti->tile);
2842  }
2843 
2844  /* Ensure the chosen tile layout is valid for this custom station */
2845  if (statspec->renderdata != nullptr) {
2846  layout = &statspec->renderdata[tile_layout < statspec->tiles ? tile_layout : (uint)GetRailStationAxis(ti->tile)];
2847  if (!layout->NeedsPreprocessing()) {
2848  t = layout;
2849  layout = nullptr;
2850  }
2851  }
2852  }
2853  }
2854  } else {
2855  total_offset = 0;
2856  }
2857 
2858  StationGfx gfx = GetStationGfx(ti->tile);
2859  if (IsAirport(ti->tile)) {
2860  gfx = GetAirportGfx(ti->tile);
2861  if (gfx >= NEW_AIRPORTTILE_OFFSET) {
2862  const AirportTileSpec *ats = AirportTileSpec::Get(gfx);
2863  if (ats->grf_prop.spritegroup[0] != nullptr && DrawNewAirportTile(ti, Station::GetByTile(ti->tile), gfx, ats)) {
2864  return;
2865  }
2866  /* No sprite group (or no valid one) found, meaning no graphics associated.
2867  * Use the substitute one instead */
2868  assert(ats->grf_prop.subst_id != INVALID_AIRPORTTILE);
2869  gfx = ats->grf_prop.subst_id;
2870  }
2871  switch (gfx) {
2872  case APT_RADAR_GRASS_FENCE_SW:
2873  t = &_station_display_datas_airport_radar_grass_fence_sw[GetAnimationFrame(ti->tile)];
2874  break;
2875  case APT_GRASS_FENCE_NE_FLAG:
2876  t = &_station_display_datas_airport_flag_grass_fence_ne[GetAnimationFrame(ti->tile)];
2877  break;
2878  case APT_RADAR_FENCE_SW:
2879  t = &_station_display_datas_airport_radar_fence_sw[GetAnimationFrame(ti->tile)];
2880  break;
2881  case APT_RADAR_FENCE_NE:
2882  t = &_station_display_datas_airport_radar_fence_ne[GetAnimationFrame(ti->tile)];
2883  break;
2884  case APT_GRASS_FENCE_NE_FLAG_2:
2885  t = &_station_display_datas_airport_flag_grass_fence_ne_2[GetAnimationFrame(ti->tile)];
2886  break;
2887  }
2888  }
2889 
2890  Owner owner = GetTileOwner(ti->tile);
2891 
2892  PaletteID palette;
2893  if (Company::IsValidID(owner)) {
2894  palette = COMPANY_SPRITE_COLOUR(owner);
2895  } else {
2896  /* Some stations are not owner by a company, namely oil rigs */
2897  palette = PALETTE_TO_GREY;
2898  }
2899 
2900  if (layout == nullptr && (t == nullptr || t->seq == nullptr)) t = GetStationTileLayout(GetStationType(ti->tile), gfx);
2901 
2902  /* don't show foundation for docks */
2903  if (ti->tileh != SLOPE_FLAT && !IsDock(ti->tile)) {
2904  if (statspec != nullptr && HasBit(statspec->flags, SSF_CUSTOM_FOUNDATIONS)) {
2905  /* Station has custom foundations.
2906  * Check whether the foundation continues beyond the tile's upper sides. */
2907  uint edge_info = 0;
2908  int z;
2909  Slope slope = GetFoundationPixelSlope(ti->tile, &z);
2910  if (!HasFoundationNW(ti->tile, slope, z)) SetBit(edge_info, 0);
2911  if (!HasFoundationNE(ti->tile, slope, z)) SetBit(edge_info, 1);
2912  SpriteID image = GetCustomStationFoundationRelocation(statspec, st, ti->tile, tile_layout, edge_info);
2913  if (image == 0) goto draw_default_foundation;
2914 
2915  if (HasBit(statspec->flags, SSF_EXTENDED_FOUNDATIONS)) {
2916  /* Station provides extended foundations. */
2917 
2918  static const uint8 foundation_parts[] = {
2919  0, 0, 0, 0, // Invalid, Invalid, Invalid, SLOPE_SW
2920  0, 1, 2, 3, // Invalid, SLOPE_EW, SLOPE_SE, SLOPE_WSE
2921  0, 4, 5, 6, // Invalid, SLOPE_NW, SLOPE_NS, SLOPE_NWS
2922  7, 8, 9 // SLOPE_NE, SLOPE_ENW, SLOPE_SEN
2923  };
2924 
2925  AddSortableSpriteToDraw(image + foundation_parts[ti->tileh], PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
2926  } else {
2927  /* Draw simple foundations, built up from 8 possible foundation sprites. */
2928 
2929  /* Each set bit represents one of the eight composite sprites to be drawn.
2930  * 'Invalid' entries will not drawn but are included for completeness. */
2931  static const uint8 composite_foundation_parts[] = {
2932  /* Invalid (00000000), Invalid (11010001), Invalid (11100100), SLOPE_SW (11100000) */
2933  0x00, 0xD1, 0xE4, 0xE0,
2934  /* Invalid (11001010), SLOPE_EW (11001001), SLOPE_SE (11000100), SLOPE_WSE (11000000) */
2935  0xCA, 0xC9, 0xC4, 0xC0,
2936  /* Invalid (11010010), SLOPE_NW (10010001), SLOPE_NS (11100100), SLOPE_NWS (10100000) */
2937  0xD2, 0x91, 0xE4, 0xA0,
2938  /* SLOPE_NE (01001010), SLOPE_ENW (00001001), SLOPE_SEN (01000100) */
2939  0x4A, 0x09, 0x44
2940  };
2941 
2942  uint8 parts = composite_foundation_parts[ti->tileh];
2943 
2944  /* If foundations continue beyond the tile's upper sides then
2945  * mask out the last two pieces. */
2946  if (HasBit(edge_info, 0)) ClrBit(parts, 6);
2947  if (HasBit(edge_info, 1)) ClrBit(parts, 7);
2948 
2949  if (parts == 0) {
2950  /* We always have to draw at least one sprite to make sure there is a boundingbox and a sprite with the
2951  * correct offset for the childsprites.
2952  * So, draw the (completely empty) sprite of the default foundations. */
2953  goto draw_default_foundation;
2954  }
2955 
2957  for (int i = 0; i < 8; i++) {
2958  if (HasBit(parts, i)) {
2959  AddSortableSpriteToDraw(image + i, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
2960  }
2961  }
2962  EndSpriteCombine();
2963  }
2964 
2965  OffsetGroundSprite(31, 1);
2967  } else {
2968 draw_default_foundation:
2970  }
2971  }
2972 
2973  if (IsBuoy(ti->tile)) {
2974  DrawWaterClassGround(ti);
2975  SpriteID sprite = GetCanalSprite(CF_BUOY, ti->tile);
2976  if (sprite != 0) total_offset = sprite - SPR_IMG_BUOY;
2977  } else if (IsDock(ti->tile) || (IsOilRig(ti->tile) && IsTileOnWater(ti->tile))) {
2978  if (ti->tileh == SLOPE_FLAT) {
2979  DrawWaterClassGround(ti);
2980  } else {
2981  assert(IsDock(ti->tile));
2982  TileIndex water_tile = ti->tile + TileOffsByDiagDir(GetDockDirection(ti->tile));
2983  WaterClass wc = HasTileWaterClass(water_tile) ? GetWaterClass(water_tile) : WATER_CLASS_INVALID;
2984  if (wc == WATER_CLASS_SEA) {
2985  DrawShoreTile(ti->tileh);
2986  } else {
2987  DrawClearLandTile(ti, 3);
2988  }
2989  }
2990  } else {
2991  if (layout != nullptr) {
2992  /* Sprite layout which needs preprocessing */
2993  bool separate_ground = HasBit(statspec->flags, SSF_SEPARATE_GROUND);
2994  uint32 var10_values = layout->PrepareLayout(total_offset, rti->fallback_railtype, 0, 0, separate_ground);
2995  uint8 var10;
2996  FOR_EACH_SET_BIT(var10, var10_values) {
2997  uint32 var10_relocation = GetCustomStationRelocation(statspec, st, ti->tile, var10);
2998  layout->ProcessRegisters(var10, var10_relocation, separate_ground);
2999  }
3000  tmp_rail_layout.seq = layout->GetLayout(&tmp_rail_layout.ground);
3001  t = &tmp_rail_layout;
3002  total_offset = 0;
3003  } else if (statspec != nullptr) {
3004  /* Simple sprite layout */
3005  ground_relocation = relocation = GetCustomStationRelocation(statspec, st, ti->tile, 0);
3006  if (HasBit(statspec->flags, SSF_SEPARATE_GROUND)) {
3007  ground_relocation = GetCustomStationRelocation(statspec, st, ti->tile, 1);
3008  }
3009  ground_relocation += rti->fallback_railtype;
3010  }
3011 
3012  SpriteID image = t->ground.sprite;
3013  PaletteID pal = t->ground.pal;
3014  RailTrackOffset overlay_offset;
3015  if (rti != nullptr && rti->UsesOverlay() && SplitGroundSpriteForOverlay(ti, &image, &overlay_offset)) {
3016  SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
3017  DrawGroundSprite(image, PAL_NONE);
3018  DrawGroundSprite(ground + overlay_offset, PAL_NONE);
3019 
3020  if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasStationReservation(ti->tile)) {
3021  SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
3022  DrawGroundSprite(overlay + overlay_offset, PALETTE_CRASH);
3023  }
3024  } else {
3025  image += HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE) ? ground_relocation : total_offset;
3026  if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += ground_relocation;
3027  DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette));
3028 
3029  /* PBS debugging, draw reserved tracks darker */
3030  if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasStationRail(ti->tile) && HasStationReservation(ti->tile)) {
3031  const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
3033  }
3034  }
3035  }
3036 
3038 
3039  if (IsRoadStop(ti->tile)) {
3040  RoadType road_rt = GetRoadTypeRoad(ti->tile);
3041  RoadType tram_rt = GetRoadTypeTram(ti->tile);
3042  const RoadTypeInfo* road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt);
3043  const RoadTypeInfo* tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt);
3044 
3045  if (IsDriveThroughStopTile(ti->tile)) {
3046  Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y;
3047  uint sprite_offset = axis == AXIS_X ? 1 : 0;
3048 
3049  DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset);
3050  } else {
3051  /* Non-drivethrough road stops are only valid for roads. */
3052  assert(road_rt != INVALID_ROADTYPE && tram_rt == INVALID_ROADTYPE);
3053 
3054  if (road_rti->UsesOverlay()) {
3055  DiagDirection dir = GetRoadStopDir(ti->tile);
3056  SpriteID ground = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_ROADSTOP);
3057  DrawGroundSprite(ground + dir, PAL_NONE);
3058  }
3059  }
3060 
3061  /* Draw road, tram catenary */
3062  DrawRoadCatenary(ti);
3063  }
3064 
3065  if (IsRailWaypoint(ti->tile)) {
3066  /* Don't offset the waypoint graphics; they're always the same. */
3067  total_offset = 0;
3068  }
3069 
3070  DrawRailTileSeq(ti, t, TO_BUILDINGS, total_offset, relocation, palette);
3071 }
3072 
3073 void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, RoadType roadtype, int image)
3074 {
3075  int32 total_offset = 0;
3076  PaletteID pal = COMPANY_SPRITE_COLOUR(_local_company);
3077  const DrawTileSprites *t = GetStationTileLayout(st, image);
3078  const RailtypeInfo *rti = nullptr;
3079 
3080  if (railtype != INVALID_RAILTYPE) {
3081  rti = GetRailTypeInfo(railtype);
3082  total_offset = rti->GetRailtypeSpriteOffset();
3083  }
3084 
3085  SpriteID img = t->ground.sprite;
3086  RailTrackOffset overlay_offset;
3087  if (rti != nullptr && rti->UsesOverlay() && SplitGroundSpriteForOverlay(nullptr, &img, &overlay_offset)) {
3089  DrawSprite(img, PAL_NONE, x, y);
3090  DrawSprite(ground + overlay_offset, PAL_NONE, x, y);
3091  } else {
3092  DrawSprite(img + total_offset, HasBit(img, PALETTE_MODIFIER_COLOUR) ? pal : PAL_NONE, x, y);
3093  }
3094 
3095  if (roadtype != INVALID_ROADTYPE) {
3096  const RoadTypeInfo* rti = GetRoadTypeInfo(roadtype);
3097  if (image >= 4) {
3098  /* Drive-through stop */
3099  uint sprite_offset = 5 - image;
3100 
3101  /* Road underlay takes precedence over tram */
3102  if (rti->UsesOverlay()) {
3104  DrawSprite(ground + sprite_offset, PAL_NONE, x, y);
3105 
3107  if (overlay) DrawSprite(overlay + sprite_offset, PAL_NONE, x, y);
3108  } else if (RoadTypeIsTram(roadtype)) {
3109  DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y);
3110  }
3111  } else {
3112  /* Drive-in stop */
3113  if (RoadTypeIsRoad(roadtype) && rti->UsesOverlay()) {
3115  DrawSprite(ground + image, PAL_NONE, x, y);
3116  }
3117  }
3118  }
3119 
3120  /* Default waypoint has no railtype specific sprites */
3121  DrawRailTileSeqInGUI(x, y, t, st == STATION_WAYPOINT ? 0 : total_offset, 0, pal);
3122 }
3123 
3124 static int GetSlopePixelZ_Station(TileIndex tile, uint x, uint y)
3125 {
3126  return GetTileMaxPixelZ(tile);
3127 }
3128 
3129 static Foundation GetFoundation_Station(TileIndex tile, Slope tileh)
3130 {
3131  return FlatteningFoundation(tileh);
3132 }
3133 
3134 static void GetTileDesc_Station(TileIndex tile, TileDesc *td)
3135 {
3136  td->owner[0] = GetTileOwner(tile);
3137 
3138  if (IsRoadStopTile(tile)) {
3139  RoadType road_rt = GetRoadTypeRoad(tile);
3140  RoadType tram_rt = GetRoadTypeTram(tile);
3141  Owner road_owner = INVALID_OWNER;
3142  Owner tram_owner = INVALID_OWNER;
3143  if (road_rt != INVALID_ROADTYPE) {
3144  const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt);
3145  td->roadtype = rti->strings.name;
3146  td->road_speed = rti->max_speed / 2;
3147  road_owner = GetRoadOwner(tile, RTT_ROAD);
3148  }
3149 
3150  if (tram_rt != INVALID_ROADTYPE) {
3151  const RoadTypeInfo *rti = GetRoadTypeInfo(tram_rt);
3152  td->tramtype = rti->strings.name;
3153  td->tram_speed = rti->max_speed / 2;
3154  tram_owner = GetRoadOwner(tile, RTT_TRAM);
3155  }
3156 
3157  if (IsDriveThroughStopTile(tile)) {
3158  /* Is there a mix of owners? */
3159  if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) ||
3160  (road_owner != INVALID_OWNER && road_owner != td->owner[0])) {
3161  uint i = 1;
3162  if (road_owner != INVALID_OWNER) {
3163  td->owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER;
3164  td->owner[i] = road_owner;
3165  i++;
3166  }
3167  if (tram_owner != INVALID_OWNER) {
3168  td->owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER;
3169  td->owner[i] = tram_owner;
3170  }
3171  }
3172  }
3173  }
3174 
3176 
3177  if (HasStationTileRail(tile)) {
3178  const StationSpec *spec = GetStationSpec(tile);
3179 
3180  if (spec != nullptr) {
3182  td->station_name = spec->name;
3183 
3184  if (spec->grf_prop.grffile != nullptr) {
3185  const GRFConfig *gc = GetGRFConfig(spec->grf_prop.grffile->grfid);
3186  td->grf = gc->GetName();
3187  }
3188  }
3189 
3190  const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
3191  td->rail_speed = rti->max_speed;
3192  td->railtype = rti->strings.name;
3193  }
3194 
3195  if (IsAirport(tile)) {
3196  const AirportSpec *as = Station::GetByTile(tile)->airport.GetSpec();
3198  td->airport_name = as->name;
3199 
3200  const AirportTileSpec *ats = AirportTileSpec::GetByTile(tile);
3201  td->airport_tile_name = ats->name;
3202 
3203  if (as->grf_prop.grffile != nullptr) {
3204  const GRFConfig *gc = GetGRFConfig(as->grf_prop.grffile->grfid);
3205  td->grf = gc->GetName();
3206  } else if (ats->grf_prop.grffile != nullptr) {
3207  const GRFConfig *gc = GetGRFConfig(ats->grf_prop.grffile->grfid);
3208  td->grf = gc->GetName();
3209  }
3210  }
3211 
3212  StringID str;
3213  switch (GetStationType(tile)) {
3214  default: NOT_REACHED();
3215  case STATION_RAIL: str = STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION; break;
3216  case STATION_AIRPORT:
3217  str = (IsHangar(tile) ? STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR : STR_LAI_STATION_DESCRIPTION_AIRPORT);
3218  break;
3219  case STATION_TRUCK: str = STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA; break;
3220  case STATION_BUS: str = STR_LAI_STATION_DESCRIPTION_BUS_STATION; break;
3221  case STATION_OILRIG: {
3222  const Industry *i = Station::GetByTile(tile)->industry;
3223  const IndustrySpec *is = GetIndustrySpec(i->type);
3224  td->owner[0] = i->owner;
3225  str = is->name;
3226  if (is->grf_prop.grffile != nullptr) td->grf = GetGRFConfig(is->grf_prop.grffile->grfid)->GetName();
3227  break;
3228  }
3229  case STATION_DOCK: str = STR_LAI_STATION_DESCRIPTION_SHIP_DOCK; break;
3230  case STATION_BUOY: str = STR_LAI_STATION_DESCRIPTION_BUOY; break;
3231  case STATION_WAYPOINT: str = STR_LAI_STATION_DESCRIPTION_WAYPOINT; break;
3232  }
3233  td->str = str;
3234 }
3235 
3236 
3237 static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
3238 {
3239  TrackBits trackbits = TRACK_BIT_NONE;
3240 
3241  switch (mode) {
3242  case TRANSPORT_RAIL:
3243  if (HasStationRail(tile) && !IsStationTileBlocked(tile)) {
3244  trackbits = TrackToTrackBits(GetRailStationTrack(tile));
3245  }
3246  break;
3247 
3248  case TRANSPORT_WATER:
3249  /* buoy is coded as a station, it is always on open water */
3250  if (IsBuoy(tile)) {
3251  trackbits = TRACK_BIT_ALL;
3252  /* remove tracks that connect NE map edge */
3253  if (TileX(tile) == 0) trackbits &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
3254  /* remove tracks that connect NW map edge */
3255  if (TileY(tile) == 0) trackbits &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
3256  }
3257  break;
3258 
3259  case TRANSPORT_ROAD:
3260  if (IsRoadStop(tile)) {
3261  RoadTramType rtt = (RoadTramType)sub_mode;
3262  if (!HasTileRoadType(tile, rtt)) break;
3263 
3264  DiagDirection dir = GetRoadStopDir(tile);
3265  Axis axis = DiagDirToAxis(dir);
3266 
3267  if (side != INVALID_DIAGDIR) {
3268  if (axis != DiagDirToAxis(side) || (IsStandardRoadStopTile(tile) && dir != side)) break;
3269  }
3270 
3271  trackbits = AxisToTrackBits(axis);
3272  }
3273  break;
3274 
3275  default:
3276  break;
3277  }
3278 
3280 }
3281 
3282 
3283 static void TileLoop_Station(TileIndex tile)
3284 {
3285  /* FIXME -- GetTileTrackStatus_Station -> animated stationtiles
3286  * hardcoded.....not good */
3287  switch (GetStationType(tile)) {
3288  case STATION_AIRPORT:
3289  AirportTileAnimationTrigger(Station::GetByTile(tile), tile, AAT_TILELOOP);
3290  break;
3291 
3292  case STATION_DOCK:
3293  if (!IsTileFlat(tile)) break; // only handle water part
3294  FALLTHROUGH;
3295 
3296  case STATION_OILRIG: //(station part)
3297  case STATION_BUOY:
3298  TileLoop_Water(tile);
3299  break;
3300 
3301  default: break;
3302  }
3303 }
3304 
3305 
3306 static void AnimateTile_Station(TileIndex tile)
3307 {
3308  if (HasStationRail(tile)) {
3309  AnimateStationTile(tile);
3310  return;
3311  }
3312 
3313  if (IsAirport(tile)) {
3314  AnimateAirportTile(tile);
3315  }
3316 }
3317 
3318 
3319 static bool ClickTile_Station(TileIndex tile)
3320 {
3321  const BaseStation *bst = BaseStation::GetByTile(tile);
3322 
3323  if (bst->facilities & FACIL_WAYPOINT) {
3325  } else if (IsHangar(tile)) {
3326  const Station *st = Station::From(bst);
3328  } else {
3330  }
3331  return true;
3332 }
3333 
3334 static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, int x, int y)
3335 {
3336  if (v->type == VEH_TRAIN) {
3337  StationID station_id = GetStationIndex(tile);
3338  if (!v->current_order.ShouldStopAtStation(v, station_id)) return VETSB_CONTINUE;
3339  if (!IsRailStation(tile) || !v->IsFrontEngine()) return VETSB_CONTINUE;
3340 
3341  int station_ahead;
3342  int station_length;
3343  int stop = GetTrainStopLocation(station_id, tile, Train::From(v), &station_ahead, &station_length);
3344 
3345  /* Stop whenever that amount of station ahead + the distance from the
3346  * begin of the platform to the stop location is longer than the length
3347  * of the platform. Station ahead 'includes' the current tile where the
3348  * vehicle is on, so we need to subtract that. */
3349  if (stop + station_ahead - (int)TILE_SIZE >= station_length) return VETSB_CONTINUE;
3350 
3352 
3353  x &= 0xF;
3354  y &= 0xF;
3355 
3356  if (DiagDirToAxis(dir) != AXIS_X) Swap(x, y);
3357  if (y == TILE_SIZE / 2) {
3358  if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x;
3359  stop &= TILE_SIZE - 1;
3360 
3361  if (x == stop) {
3362  return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station
3363  } else if (x < stop) {
3365  uint16 spd = max(0, (stop - x) * 20 - 15);
3366  if (spd < v->cur_speed) v->cur_speed = spd;
3367  }
3368  }
3369  } else if (v->type == VEH_ROAD) {
3370  RoadVehicle *rv = RoadVehicle::From(v);
3371  if (rv->state < RVSB_IN_ROAD_STOP && !IsReversingRoadTrackdir((Trackdir)rv->state) && rv->frame == 0) {
3372  if (IsRoadStop(tile) && rv->IsFrontEngine()) {
3373  /* Attempt to allocate a parking bay in a road stop */
3375  }
3376  }
3377  }
3378 
3379  return VETSB_CONTINUE;
3380 }
3381 
3387 {
3388  /* Collect cargoes accepted since the last big tick. */
3389  CargoTypes cargoes = 0;
3390  for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
3391  if (HasBit(st->goods[cid].status, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(cargoes, cid);
3392  }
3393 
3394  /* Anything to do? */
3395  if (cargoes == 0) return;
3396 
3397  /* Loop over all houses in the catchment. */
3399  for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
3400  if (IsTileType(tile, MP_HOUSE)) {
3401  WatchedCargoCallback(tile, cargoes);
3402  }
3403  }
3404 }
3405 
3413 {
3414  if (!st->IsInUse()) {
3415  if (++st->delete_ctr >= 8) delete st;
3416  return false;
3417  }
3418 
3419  if (Station::IsExpected(st)) {
3421 
3422  for (CargoID i = 0; i < NUM_CARGO; i++) {
3423  ClrBit(Station::From(st)->goods[i].status, GoodsEntry::GES_ACCEPTED_BIGTICK);
3424  }
3425  }
3426 
3427 
3428  if ((st->facilities & FACIL_WAYPOINT) == 0) UpdateStationAcceptance(Station::From(st), true);
3429 
3430  return true;
3431 }
3432 
3433 static inline void byte_inc_sat(byte *p)
3434 {
3435  byte b = *p + 1;
3436  if (b != 0) *p = b;
3437 }
3438 
3445 static void TruncateCargo(const CargoSpec *cs, GoodsEntry *ge, uint amount = UINT_MAX)
3446 {
3447  /* If truncating also punish the source stations' ratings to
3448  * decrease the flow of incoming cargo. */
3449 
3450  StationCargoAmountMap waiting_per_source;
3451  ge->cargo.Truncate(amount, &waiting_per_source);
3452  for (StationCargoAmountMap::iterator i(waiting_per_source.begin()); i != waiting_per_source.end(); ++i) {
3453  Station *source_station = Station::GetIfValid(i->first);
3454  if (source_station == nullptr) continue;
3455 
3456  GoodsEntry &source_ge = source_station->goods[cs->Index()];
3457  source_ge.max_waiting_cargo = max(source_ge.max_waiting_cargo, i->second);
3458  }
3459 }
3460 
3461 static void UpdateStationRating(Station *st)
3462 {
3463  bool waiting_changed = false;
3464 
3465  byte_inc_sat(&st->time_since_load);
3466  byte_inc_sat(&st->time_since_unload);
3467 
3468  const CargoSpec *cs;
3469  FOR_ALL_CARGOSPECS(cs) {
3470  GoodsEntry *ge = &st->goods[cs->Index()];
3471  /* Slowly increase the rating back to his original level in the case we
3472  * didn't deliver cargo yet to this station. This happens when a bribe
3473  * failed while you didn't moved that cargo yet to a station. */
3474  if (!ge->HasRating() && ge->rating < INITIAL_STATION_RATING) {
3475  ge->rating++;
3476  }
3477 
3478  /* Only change the rating if we are moving this cargo */
3479  if (ge->HasRating()) {
3480  byte_inc_sat(&ge->time_since_pickup);
3481  if (ge->time_since_pickup == 255 && _settings_game.order.selectgoods) {
3483  ge->last_speed = 0;
3484  TruncateCargo(cs, ge);
3485  waiting_changed = true;
3486  continue;
3487  }
3488 
3489  bool skip = false;
3490  int rating = 0;
3491  uint waiting = ge->cargo.AvailableCount();
3492 
3493  /* num_dests is at least 1 if there is any cargo as
3494  * INVALID_STATION is also a destination.
3495  */
3496  uint num_dests = (uint)ge->cargo.Packets()->MapSize();
3497 
3498  /* Average amount of cargo per next hop, but prefer solitary stations
3499  * with only one or two next hops. They are allowed to have more
3500  * cargo waiting per next hop.
3501  * With manual cargo distribution waiting_avg = waiting / 2 as then
3502  * INVALID_STATION is the only destination.
3503  */
3504  uint waiting_avg = waiting / (num_dests + 1);
3505 
3507  /* Perform custom station rating. If it succeeds the speed, days in transit and
3508  * waiting cargo ratings must not be executed. */
3509 
3510  /* NewGRFs expect last speed to be 0xFF when no vehicle has arrived yet. */
3511  uint last_speed = ge->HasVehicleEverTriedLoading() ? ge->last_speed : 0xFF;
3512 
3513  uint32 var18 = min(ge->time_since_pickup, 0xFF) | (min(ge->max_waiting_cargo, 0xFFFF) << 8) | (min(last_speed, 0xFF) << 24);
3514  /* Convert to the 'old' vehicle types */
3515  uint32 var10 = (st->last_vehicle_type == VEH_INVALID) ? 0x0 : (st->last_vehicle_type + 0x10);
3516  uint16 callback = GetCargoCallback(CBID_CARGO_STATION_RATING_CALC, var10, var18, cs);
3517  if (callback != CALLBACK_FAILED) {
3518  skip = true;
3519  rating = GB(callback, 0, 14);
3520 
3521  /* Simulate a 15 bit signed value */
3522  if (HasBit(callback, 14)) rating -= 0x4000;
3523  }
3524  }
3525 
3526  if (!skip) {
3527  int b = ge->last_speed - 85;
3528  if (b >= 0) rating += b >> 2;
3529 
3530  byte waittime = ge->time_since_pickup;
3531  if (st->last_vehicle_type == VEH_SHIP) waittime >>= 2;
3532  if (waittime <= 21) rating += 25;
3533  if (waittime <= 12) rating += 25;
3534  if (waittime <= 6) rating += 45;
3535  if (waittime <= 3) rating += 35;
3536 
3537  rating -= 90;
3538  if (ge->max_waiting_cargo <= 1500) rating += 55;
3539  if (ge->max_waiting_cargo <= 1000) rating += 35;
3540  if (ge->max_waiting_cargo <= 600) rating += 10;
3541  if (ge->max_waiting_cargo <= 300) rating += 20;
3542  if (ge->max_waiting_cargo <= 100) rating += 10;
3543  }
3544 
3545  if (Company::IsValidID(st->owner) && HasBit(st->town->statues, st->owner)) rating += 26;
3546 
3547  byte age = ge->last_age;
3548  if (age < 3) rating += 10;
3549  if (age < 2) rating += 10;
3550  if (age < 1) rating += 13;
3551 
3552  {
3553  int or_ = ge->rating; // old rating
3554 
3555  /* only modify rating in steps of -2, -1, 0, 1 or 2 */
3556  ge->rating = rating = or_ + Clamp(Clamp(rating, 0, 255) - or_, -2, 2);
3557 
3558  /* if rating is <= 64 and more than 100 items waiting on average per destination,
3559  * remove some random amount of goods from the station */
3560  if (rating <= 64 && waiting_avg >= 100) {
3561  int dec = Random() & 0x1F;
3562  if (waiting_avg < 200) dec &= 7;
3563  waiting -= (dec + 1) * num_dests;
3564  waiting_changed = true;
3565  }
3566 
3567  /* if rating is <= 127 and there are any items waiting, maybe remove some goods. */
3568  if (rating <= 127 && waiting != 0) {
3569  uint32 r = Random();
3570  if (rating <= (int)GB(r, 0, 7)) {
3571  /* Need to have int, otherwise it will just overflow etc. */
3572  waiting = max((int)waiting - (int)((GB(r, 8, 2) - 1) * num_dests), 0);
3573  waiting_changed = true;
3574  }
3575  }
3576 
3577  /* At some point we really must cap the cargo. Previously this
3578  * was a strict 4095, but now we'll have a less strict, but
3579  * increasingly aggressive truncation of the amount of cargo. */
3580  static const uint WAITING_CARGO_THRESHOLD = 1 << 12;
3581  static const uint WAITING_CARGO_CUT_FACTOR = 1 << 6;
3582  static const uint MAX_WAITING_CARGO = 1 << 15;
3583 
3584  if (waiting > WAITING_CARGO_THRESHOLD) {
3585  uint difference = waiting - WAITING_CARGO_THRESHOLD;
3586  waiting -= (difference / WAITING_CARGO_CUT_FACTOR);
3587 
3588  waiting = min(waiting, MAX_WAITING_CARGO);
3589  waiting_changed = true;
3590  }
3591 
3592  /* We can't truncate cargo that's already reserved for loading.
3593  * Thus StoredCount() here. */
3594  if (waiting_changed && waiting < ge->cargo.AvailableCount()) {
3595  /* Feed back the exact own waiting cargo at this station for the
3596  * next rating calculation. */
3597  ge->max_waiting_cargo = 0;
3598 
3599  TruncateCargo(cs, ge, ge->cargo.AvailableCount() - waiting);
3600  } else {
3601  /* If the average number per next hop is low, be more forgiving. */
3602  ge->max_waiting_cargo = waiting_avg;
3603  }
3604  }
3605  }
3606  }
3607 
3608  StationID index = st->index;
3609  if (waiting_changed) {
3610  SetWindowDirty(WC_STATION_VIEW, index); // update whole window
3611  } else {
3612  SetWindowWidgetDirty(WC_STATION_VIEW, index, WID_SV_ACCEPT_RATING_LIST); // update only ratings list
3613  }
3614 }
3615 
3624 void RerouteCargo(Station *st, CargoID c, StationID avoid, StationID avoid2)
3625 {
3626  GoodsEntry &ge = st->goods[c];
3627 
3628  /* Reroute cargo in station. */
3629  ge.cargo.Reroute(UINT_MAX, &ge.cargo, avoid, avoid2, &ge);
3630 
3631  /* Reroute cargo staged to be transferred. */
3632  for (std::list<Vehicle *>::iterator it(st->loading_vehicles.begin()); it != st->loading_vehicles.end(); ++it) {
3633  for (Vehicle *v = *it; v != nullptr; v = v->Next()) {
3634  if (v->cargo_type != c) continue;
3635  v->cargo.Reroute(UINT_MAX, &v->cargo, avoid, avoid2, &ge);
3636  }
3637  }
3638 }
3639 
3649 {
3650  for (CargoID c = 0; c < NUM_CARGO; ++c) {
3651  const bool auto_distributed = (_settings_game.linkgraph.GetDistributionType(c) != DT_MANUAL);
3652  GoodsEntry &ge = from->goods[c];
3654  if (lg == nullptr) continue;
3655  Node node = (*lg)[ge.node];
3656  for (EdgeIterator it(node.Begin()); it != node.End();) {
3657  Edge edge = it->second;
3658  Station *to = Station::Get((*lg)[it->first].Station());
3659  assert(to->goods[c].node == it->first);
3660  ++it; // Do that before removing the edge. Anything else may crash.
3661  assert(_date >= edge.LastUpdate());
3662  uint timeout = LinkGraph::MIN_TIMEOUT_DISTANCE + (DistanceManhattan(from->xy, to->xy) >> 3);
3663  if ((uint)(_date - edge.LastUpdate()) > timeout) {
3664  bool updated = false;
3665 
3666  if (auto_distributed) {
3667  /* Have all vehicles refresh their next hops before deciding to
3668  * remove the node. */
3669  std::vector<Vehicle *> vehicles;
3670  for (OrderList *l : OrderList::Iterate()) {
3671  bool found_from = false;
3672  bool found_to = false;
3673  for (Order *order = l->GetFirstOrder(); order != nullptr; order = order->next) {
3674  if (!order->IsType(OT_GOTO_STATION) && !order->IsType(OT_IMPLICIT)) continue;
3675  if (order->GetDestination() == from->index) {
3676  found_from = true;
3677  if (found_to) break;
3678  } else if (order->GetDestination() == to->index) {
3679  found_to = true;
3680  if (found_from) break;
3681  }
3682  }
3683  if (!found_to || !found_from) continue;
3684  vehicles.push_back(l->GetFirstSharedVehicle());
3685  }
3686 
3687  auto iter = vehicles.begin();
3688  while (iter != vehicles.end()) {
3689  Vehicle *v = *iter;
3690 
3691  LinkRefresher::Run(v, false); // Don't allow merging. Otherwise lg might get deleted.
3692  if (edge.LastUpdate() == _date) {
3693  updated = true;
3694  break;
3695  }
3696 
3697  Vehicle *next_shared = v->NextShared();
3698  if (next_shared) {
3699  *iter = next_shared;
3700  ++iter;
3701  } else {
3702  iter = vehicles.erase(iter);
3703  }
3704 
3705  if (iter == vehicles.end()) iter = vehicles.begin();
3706  }
3707  }
3708 
3709  if (!updated) {
3710  /* If it's still considered dead remove it. */
3711  node.RemoveEdge(to->goods[c].node);
3712  ge.flows.DeleteFlows(to->index);
3713  RerouteCargo(from, c, to->index, from->index);
3714  }
3715  } else if (edge.LastUnrestrictedUpdate() != INVALID_DATE && (uint)(_date - edge.LastUnrestrictedUpdate()) > timeout) {
3716  edge.Restrict();
3717  ge.flows.RestrictFlows(to->index);
3718  RerouteCargo(from, c, to->index, from->index);
3719  } else if (edge.LastRestrictedUpdate() != INVALID_DATE && (uint)(_date - edge.LastRestrictedUpdate()) > timeout) {
3720  edge.Release();
3721  }
3722  }
3723  assert(_date >= lg->LastCompression());
3724  if ((uint)(_date - lg->LastCompression()) > LinkGraph::COMPRESSION_INTERVAL) {
3725  lg->Compress();
3726  }
3727  }
3728 }
3729 
3739 void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage, EdgeUpdateMode mode)
3740 {
3741  GoodsEntry &ge1 = st->goods[cargo];
3742  Station *st2 = Station::Get(next_station_id);
3743  GoodsEntry &ge2 = st2->goods[cargo];
3744  LinkGraph *lg = nullptr;
3745  if (ge1.link_graph == INVALID_LINK_GRAPH) {
3746  if (ge2.link_graph == INVALID_LINK_GRAPH) {
3748  lg = new LinkGraph(cargo);
3750  ge2.link_graph = lg->index;
3751  ge2.node = lg->AddNode(st2);
3752  } else {
3753  DEBUG(misc, 0, "Can't allocate link graph");
3754  }
3755  } else {
3756  lg = LinkGraph::Get(ge2.link_graph);
3757  }
3758  if (lg) {
3759  ge1.link_graph = lg->index;
3760  ge1.node = lg->AddNode(st);
3761  }
3762  } else if (ge2.link_graph == INVALID_LINK_GRAPH) {
3763  lg = LinkGraph::Get(ge1.link_graph);
3764  ge2.link_graph = lg->index;
3765  ge2.node = lg->AddNode(st2);
3766  } else {
3767  lg = LinkGraph::Get(ge1.link_graph);
3768  if (ge1.link_graph != ge2.link_graph) {
3769  LinkGraph *lg2 = LinkGraph::Get(ge2.link_graph);
3770  if (lg->Size() < lg2->Size()) {
3772  lg2->Merge(lg); // Updates GoodsEntries of lg
3773  lg = lg2;
3774  } else {
3776  lg->Merge(lg2); // Updates GoodsEntries of lg2
3777  }
3778  }
3779  }
3780  if (lg != nullptr) {
3781  (*lg)[ge1.node].UpdateEdge(ge2.node, capacity, usage, mode);
3782  }
3783 }
3784 
3791 void IncreaseStats(Station *st, const Vehicle *front, StationID next_station_id)
3792 {
3793  for (const Vehicle *v = front; v != nullptr; v = v->Next()) {
3794  if (v->refit_cap > 0) {
3795  /* The cargo count can indeed be higher than the refit_cap if
3796  * wagons have been auto-replaced and subsequently auto-
3797  * refitted to a higher capacity. The cargo gets redistributed
3798  * among the wagons in that case.
3799  * As usage is not such an important figure anyway we just
3800  * ignore the additional cargo then.*/
3801  IncreaseStats(st, v->cargo_type, next_station_id, v->refit_cap,
3803  }
3804  }
3805 }
3806 
3807 /* called for every station each tick */
3808 static void StationHandleSmallTick(BaseStation *st)
3809 {
3810  if ((st->facilities & FACIL_WAYPOINT) != 0 || !st->IsInUse()) return;
3811 
3812  byte b = st->delete_ctr + 1;
3813  if (b >= STATION_RATING_TICKS) b = 0;
3814  st->delete_ctr = b;
3815 
3816  if (b == 0) UpdateStationRating(Station::From(st));
3817 }
3818 
3819 void OnTick_Station()
3820 {
3821  if (_game_mode == GM_EDITOR) return;
3822 
3823  for (BaseStation *st : BaseStation::Iterate()) {
3824  StationHandleSmallTick(st);
3825 
3826  /* Clean up the link graph about once a week. */
3827  if (Station::IsExpected(st) && (_tick_counter + st->index) % STATION_LINKGRAPH_TICKS == 0) {
3829  };
3830 
3831  /* Run STATION_ACCEPTANCE_TICKS = 250 tick interval trigger for station animation.
3832  * Station index is included so that triggers are not all done
3833  * at the same time. */
3834  if ((_tick_counter + st->index) % STATION_ACCEPTANCE_TICKS == 0) {
3835  /* Stop processing this station if it was deleted */
3836  if (!StationHandleBigTick(st)) continue;
3837  TriggerStationAnimation(st, st->xy, SAT_250_TICKS);
3838  if (Station::IsExpected(st)) AirportAnimationTrigger(Station::From(st), AAT_STATION_250_TICKS);
3839  }
3840  }
3841 }
3842 
3845 {
3846  for (Station *st : Station::Iterate()) {
3847  for (CargoID i = 0; i < NUM_CARGO; i++) {
3848  GoodsEntry *ge = &st->goods[i];
3851  }
3852  }
3853 }
3854 
3855 
3856 void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius)
3857 {
3858  ForAllStationsRadius(tile, radius, [&](Station *st) {
3859  if (st->owner == owner && DistanceManhattan(tile, st->xy) <= radius) {
3860  for (CargoID i = 0; i < NUM_CARGO; i++) {
3861  GoodsEntry *ge = &st->goods[i];
3862 
3863  if (ge->status != 0) {
3864  ge->rating = Clamp(ge->rating + amount, 0, 255);
3865  }
3866  }
3867  }
3868  });
3869 }
3870 
3871 static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceType source_type, SourceID source_id)
3872 {
3873  /* We can't allocate a CargoPacket? Then don't do anything
3874  * at all; i.e. just discard the incoming cargo. */
3875  if (!CargoPacket::CanAllocateItem()) return 0;
3876 
3877  GoodsEntry &ge = st->goods[type];
3878  amount += ge.amount_fract;
3879  ge.amount_fract = GB(amount, 0, 8);
3880 
3881  amount >>= 8;
3882  /* No new "real" cargo item yet. */
3883  if (amount == 0) return 0;
3884 
3885  StationID next = ge.GetVia(st->index);
3886  ge.cargo.Append(new CargoPacket(st->index, st->xy, amount, source_type, source_id), next);
3887  LinkGraph *lg = nullptr;
3888  if (ge.link_graph == INVALID_LINK_GRAPH) {
3890  lg = new LinkGraph(type);
3892  ge.link_graph = lg->index;
3893  ge.node = lg->AddNode(st);
3894  } else {
3895  DEBUG(misc, 0, "Can't allocate link graph");
3896  }
3897  } else {
3898  lg = LinkGraph::Get(ge.link_graph);
3899  }
3900  if (lg != nullptr) (*lg)[ge.node].UpdateSupply(amount);
3901 
3902  if (!ge.HasRating()) {
3905  }
3906 
3908  TriggerStationAnimation(st, st->xy, SAT_NEW_CARGO, type);
3909  AirportAnimationTrigger(st, AAT_STATION_NEW_CARGO, type);
3910 
3912  st->MarkTilesDirty(true);
3913  return amount;
3914 }
3915 
3916 static bool IsUniqueStationName(const char *name)
3917 {
3918  for (const Station *st : Station::Iterate()) {
3919  if (st->name != nullptr && strcmp(st->name, name) == 0) return false;
3920  }
3921 
3922  return true;
3923 }
3924 
3934 CommandCost CmdRenameStation(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
3935 {
3936  Station *st = Station::GetIfValid(p1);
3937  if (st == nullptr) return CMD_ERROR;
3938 
3939  CommandCost ret = CheckOwnership(st->owner);
3940  if (ret.Failed()) return ret;
3941 
3942  bool reset = StrEmpty(text);
3943 
3944  if (!reset) {
3946  if (!IsUniqueStationName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
3947  }
3948 
3949  if (flags & DC_EXEC) {
3950  st->cached_name.clear();
3951  free(st->name);
3952  st->name = reset ? nullptr : stredup(text);
3953 
3954  st->UpdateVirtCoord();
3956  }
3957 
3958  return CommandCost();
3959 }
3960 
3961 static void AddNearbyStationsByCatchment(TileIndex tile, StationList *stations, StationList &nearby)
3962 {
3963  for (Station *st : nearby) {
3964  if (st->TileIsInCatchment(tile)) stations->insert(st);
3965  }
3966 }
3967 
3975 void FindStationsAroundTiles(const TileArea &location, StationList * const stations, bool use_nearby)
3976 {
3977  if (use_nearby) {
3978  /* Industries and towns maintain a list of nearby stations */
3979  if (IsTileType(location.tile, MP_INDUSTRY)) {
3980  /* Industry nearby stations are already filtered by catchment. */
3981  *stations = Industry::GetByTile(location.tile)->stations_near;
3982  return;
3983  } else if (IsTileType(location.tile, MP_HOUSE)) {
3984  /* Town nearby stations need to be filtered per tile. */
3985  assert(location.w == 1 && location.h == 1);
3986  AddNearbyStationsByCatchment(location.tile, stations, Town::GetByTile(location.tile)->stations_near);
3987  return;
3988  }
3989  }
3990 
3991  /* Not using, or don't have a nearby stations list, so we need to scan. */
3992  std::set<StationID> seen_stations;
3993 
3994  /* Scan an area around the building covering the maximum possible station
3995  * to find the possible nearby stations. */
3997  TileArea ta = TileArea(location).Expand(max_c);
3998  TILE_AREA_LOOP(tile, ta) {
3999  if (IsTileType(tile, MP_STATION)) seen_stations.insert(GetStationIndex(tile));
4000  }
4001 
4002  for (StationID stationid : seen_stations) {
4003  Station *st = Station::GetIfValid(stationid);
4004  if (st == nullptr) continue; /* Waypoint */
4005 
4006  /* Check if station is attached to an industry */
4007  if (!_settings_game.station.serve_neutral_industries && st->industry != nullptr) continue;
4008 
4009  /* Test if the tile is within the station's catchment */
4010  TILE_AREA_LOOP(tile, location) {
4011  if (st->TileIsInCatchment(tile)) {
4012  stations->insert(st);
4013  break;
4014  }
4015  }
4016  }
4017 }
4018 
4024 {
4025  if (this->tile != INVALID_TILE) {
4026  FindStationsAroundTiles(*this, &this->stations);
4027  this->tile = INVALID_TILE;
4028  }
4029  return &this->stations;
4030 }
4031 
4032 static bool CanMoveGoodsToStation(const Station *st, CargoID type)
4033 {
4034  /* Is the station reserved exclusively for somebody else? */
4035  if (st->owner != OWNER_NONE && st->town->exclusive_counter > 0 && st->town->exclusivity != st->owner) return false;
4036 
4037  /* Lowest possible rating, better not to give cargo anymore. */
4038  if (st->goods[type].rating == 0) return false;
4039 
4040  /* Selectively servicing stations, and not this one. */
4041  if (_settings_game.order.selectgoods && !st->goods[type].HasVehicleEverTriedLoading()) return false;
4042 
4043  if (IsCargoInClass(type, CC_PASSENGERS)) {
4044  /* Passengers are never served by just a truck stop. */
4045  if (st->facilities == FACIL_TRUCK_STOP) return false;
4046  } else {
4047  /* Non-passengers are never served by just a bus stop. */
4048  if (st->facilities == FACIL_BUS_STOP) return false;
4049  }
4050  return true;
4051 }
4052 
4053 uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, SourceID source_id, const StationList *all_stations)
4054 {
4055  /* Return if nothing to do. Also the rounding below fails for 0. */
4056  if (all_stations->empty()) return 0;
4057  if (amount == 0) return 0;
4058 
4059  Station *first_station = nullptr;
4060  typedef std::pair<Station *, uint> StationInfo;
4061  std::vector<StationInfo> used_stations;
4062 
4063  for (Station *st : *all_stations) {
4064  if (!CanMoveGoodsToStation(st, type)) continue;
4065 
4066  /* Avoid allocating a vector if there is only one station to significantly
4067  * improve performance in this common case. */
4068  if (first_station == nullptr) {
4069  first_station = st;
4070  continue;
4071  }
4072  if (used_stations.empty()) {
4073  used_stations.reserve(2);
4074  used_stations.emplace_back(std::make_pair(first_station, 0));
4075  }
4076  used_stations.emplace_back(std::make_pair(st, 0));
4077  }
4078 
4079  /* no stations around at all? */
4080  if (first_station == nullptr) return 0;
4081 
4082  if (used_stations.empty()) {
4083  /* only one station around */
4084  amount *= first_station->goods[type].rating + 1;
4085  return UpdateStationWaiting(first_station, type, amount, source_type, source_id);
4086  }
4087 
4088  uint company_best[OWNER_NONE + 1] = {}; // best rating for each company, including OWNER_NONE
4089  uint company_sum[OWNER_NONE + 1] = {}; // sum of ratings for each company
4090  uint best_rating = 0;
4091  uint best_sum = 0; // sum of best ratings for each company
4092 
4093  for (auto &p : used_stations) {
4094  auto owner = p.first->owner;
4095  auto rating = p.first->goods[type].rating;
4096  if (rating > company_best[owner]) {
4097  best_sum += rating - company_best[owner]; // it's usually faster than iterating companies later
4098  company_best[owner] = rating;
4099  if (rating > best_rating) best_rating = rating;
4100  }
4101  company_sum[owner] += rating;
4102  }
4103 
4104  /* From now we'll calculate with fractional cargo amounts.
4105  * First determine how much cargo we really have. */
4106  amount *= best_rating + 1;
4107 
4108  uint moving = 0;
4109  for (auto &p : used_stations) {
4110  uint owner = p.first->owner;
4111  /* Multiply the amount by (company best / sum of best for each company) to get cargo allocated to a company
4112  * and by (station rating / sum of ratings in a company) to get the result for a single station. */
4113  p.second = amount * company_best[owner] * p.first->goods[type].rating / best_sum / company_sum[owner];
4114  moving += p.second;
4115  }
4116 
4117  /* If there is some cargo left due to rounding issues distribute it among the best rated stations. */
4118  if (amount > moving) {
4119  std::sort(used_stations.begin(), used_stations.end(), [type] (const StationInfo &a, const StationInfo &b) {
4120  return b.first->goods[type].rating < a.first->goods[type].rating;
4121  });
4122 
4123  assert(amount - moving <= used_stations.size());
4124  for (uint i = 0; i < amount - moving; i++) {
4125  used_stations[i].second++;
4126  }
4127  }
4128 
4129  uint moved = 0;
4130  for (auto &p : used_stations) {
4131  moved += UpdateStationWaiting(p.first, type, p.second, source_type, source_id);
4132  }
4133 
4134  return moved;
4135 }
4136 
4137 void UpdateStationDockingTiles(Station *st)
4138 {
4139  st->docking_station.Clear();
4140 
4141  /* For neutral stations, start with the industry area instead of dock area */
4142  const TileArea *area = st->industry != nullptr ? &st->industry->location : &st->ship_station;
4143 
4144  if (area->tile == INVALID_TILE) return;
4145 
4146  int x = TileX(area->tile);
4147  int y = TileY(area->tile);
4148 
4149  /* Expand the area by a tile on each side while
4150  * making sure that we remain inside the map. */
4151  int x2 = min(x + area->w + 1, MapSizeX());
4152  int x1 = max(x - 1, 0);
4153 
4154  int y2 = min(y + area->h + 1, MapSizeY());
4155  int y1 = max(y - 1, 0);
4156 
4157  TileArea ta(TileXY(x1, y1), TileXY(x2 - 1, y2 - 1));
4158  TILE_AREA_LOOP(tile, ta) {
4159  if (IsValidTile(tile) && IsPossibleDockingTile(tile)) CheckForDockingTile(tile);
4160  }
4161 }
4162 
4163 void BuildOilRig(TileIndex tile)
4164 {
4165  if (!Station::CanAllocateItem()) {
4166  DEBUG(misc, 0, "Can't allocate station for oilrig at 0x%X, reverting to oilrig only", tile);
4167  return;
4168  }
4169 
4170  Station *st = new Station(tile);
4171  _station_kdtree.Insert(st->index);
4172  st->town = ClosestTownFromTile(tile, UINT_MAX);
4173 
4174  st->string_id = GenerateStationName(st, tile, STATIONNAMING_OILRIG);
4175 
4176  assert(IsTileType(tile, MP_INDUSTRY));
4177  /* Mark industry as associated both ways */
4178  st->industry = Industry::GetByTile(tile);
4179  st->industry->neutral_station = st;
4180  DeleteAnimatedTile(tile);
4181  MakeOilrig(tile, st->index, GetWaterClass(tile));
4182 
4183  st->owner = OWNER_NONE;
4184  st->airport.type = AT_OILRIG;
4185  st->airport.Add(tile);
4186  st->ship_station.Add(tile);
4188  st->build_date = _date;
4189  UpdateStationDockingTiles(st);
4190 
4191  st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE);
4192 
4193  st->UpdateVirtCoord();
4194  st->RecomputeCatchment();
4195  UpdateStationAcceptance(st, false);
4196 }
4197 
4198 void DeleteOilRig(TileIndex tile)
4199 {
4200  Station *st = Station::GetByTile(tile);
4201 
4202  MakeWaterKeepingClass(tile, OWNER_NONE);
4203 
4204  /* The oil rig station is not supposed to be shared with anything else */
4205  assert(st->facilities == (FACIL_AIRPORT | FACIL_DOCK) && st->airport.type == AT_OILRIG);
4206  if (st->industry != nullptr && st->industry->neutral_station == st) {
4207  /* Don't leave dangling neutral station pointer */
4208  st->industry->neutral_station = nullptr;
4209  }
4210  delete st;
4211 }
4212 
4213 static void ChangeTileOwner_Station(TileIndex tile, Owner old_owner, Owner new_owner)
4214 {
4215  if (IsRoadStopTile(tile)) {
4216  FOR_ALL_ROADTRAMTYPES(rtt) {
4217  /* Update all roadtypes, no matter if they are present */
4218  if (GetRoadOwner(tile, rtt) == old_owner) {
4219  RoadType rt = GetRoadType(tile, rtt);
4220  if (rt != INVALID_ROADTYPE) {
4221  /* A drive-through road-stop has always two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */
4222  Company::Get(old_owner)->infrastructure.road[rt] -= 2;
4223  if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += 2;
4224  }
4225  SetRoadOwner(tile, rtt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner);
4226  }
4227  }
4228  }
4229 
4230  if (!IsTileOwner(tile, old_owner)) return;
4231 
4232  if (new_owner != INVALID_OWNER) {
4233  /* Update company infrastructure counts. Only do it here
4234  * if the new owner is valid as otherwise the clear
4235  * command will do it for us. No need to dirty windows
4236  * here, we'll redraw the whole screen anyway.*/
4237  Company *old_company = Company::Get(old_owner);
4238  Company *new_company = Company::Get(new_owner);
4239 
4240  /* Update counts for underlying infrastructure. */
4241  switch (GetStationType(tile)) {
4242  case STATION_RAIL:
4243  case STATION_WAYPOINT:
4244  if (!IsStationTileBlocked(tile)) {
4245  old_company->infrastructure.rail[GetRailType(tile)]--;
4246  new_company->infrastructure.rail[GetRailType(tile)]++;
4247  }
4248  break;
4249 
4250  case STATION_BUS:
4251  case STATION_TRUCK:
4252  /* Road stops were already handled above. */
4253  break;
4254 
4255  case STATION_BUOY:
4256  case STATION_DOCK:
4257  if (GetWaterClass(tile) == WATER_CLASS_CANAL) {
4258  old_company->infrastructure.water--;
4259  new_company->infrastructure.water++;
4260  }
4261  break;
4262 
4263  default:
4264  break;
4265  }
4266 
4267  /* Update station tile count. */
4268  if (!IsBuoy(tile) && !IsAirport(tile)) {
4269  old_company->infrastructure.station--;
4270  new_company->infrastructure.station++;
4271  }
4272 
4273  /* for buoys, owner of tile is owner of water, st->owner == OWNER_NONE */
4274  SetTileOwner(tile, new_owner);
4276  } else {
4277  if (IsDriveThroughStopTile(tile)) {
4278  /* Remove the drive-through road stop */
4279  DoCommand(tile, 1 | 1 << 8, (GetStationType(tile) == STATION_TRUCK) ? ROADSTOP_TRUCK : ROADSTOP_BUS, DC_EXEC | DC_BANKRUPT, CMD_REMOVE_ROAD_STOP);
4280  assert(IsTileType(tile, MP_ROAD));
4281  /* Change owner of tile and all roadtypes */
4282  ChangeTileOwner(tile, old_owner, new_owner);
4283  } else {
4285  /* Set tile owner of water under (now removed) buoy and dock to OWNER_NONE.
4286  * Update owner of buoy if it was not removed (was in orders).
4287  * Do not update when owned by OWNER_WATER (sea and rivers). */
4288  if ((IsTileType(tile, MP_WATER) || IsBuoyTile(tile)) && IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
4289  }
4290  }
4291 }
4292 
4302 {
4303  /* Yeah... water can always remove stops, right? */
4304  if (_current_company == OWNER_WATER) return true;
4305 
4306  if (GetRoadTypeTram(tile) != INVALID_ROADTYPE) {
4307  Owner tram_owner = GetRoadOwner(tile, RTT_TRAM);
4308  if (tram_owner != OWNER_NONE && CheckOwnership(tram_owner).Failed()) return false;
4309  }
4310  if (GetRoadTypeRoad(tile) != INVALID_ROADTYPE) {
4311  Owner road_owner = GetRoadOwner(tile, RTT_ROAD);
4312  if (road_owner != OWNER_TOWN) {
4313  if (road_owner != OWNER_NONE && CheckOwnership(road_owner).Failed()) return false;
4314  } else {
4315  if (CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, RTT_ROAD), OWNER_TOWN, RTT_ROAD, flags).Failed()) return false;
4316  }
4317  }
4318 
4319  return true;
4320 }
4321 
4329 {
4330  if (flags & DC_AUTO) {
4331  switch (GetStationType(tile)) {
4332  default: break;
4333  case STATION_RAIL: return_cmd_error(STR_ERROR_MUST_DEMOLISH_RAILROAD);
4334  case STATION_WAYPOINT: return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
4335  case STATION_AIRPORT: return_cmd_error(STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST);
4336  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);
4337  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);
4338  case STATION_BUOY: return_cmd_error(STR_ERROR_BUOY_IN_THE_WAY);
4339  case STATION_DOCK: return_cmd_error(STR_ERROR_MUST_DEMOLISH_DOCK_FIRST);
4340  case STATION_OILRIG:
4341  SetDParam(1, STR_INDUSTRY_NAME_OIL_RIG);
4342  return_cmd_error(STR_ERROR_GENERIC_OBJECT_IN_THE_WAY);
4343  }
4344  }
4345 
4346  switch (GetStationType(tile)) {
4347  case STATION_RAIL: return RemoveRailStation(tile, flags);
4348  case STATION_WAYPOINT: return RemoveRailWaypoint(tile, flags);
4349  case STATION_AIRPORT: return RemoveAirport(tile, flags);
4350  case STATION_TRUCK:
4351  if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) {
4352  return_cmd_error(STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST);
4353  }
4354  return RemoveRoadStop(tile, flags);
4355  case STATION_BUS:
4356  if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) {
4357  return_cmd_error(STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST);
4358  }
4359  return RemoveRoadStop(tile, flags);
4360  case STATION_BUOY: return RemoveBuoy(tile, flags);
4361  case STATION_DOCK: return RemoveDock(tile, flags);
4362  default: break;
4363  }
4364 
4365  return CMD_ERROR;
4366 }
4367 
4368 static CommandCost TerraformTile_Station(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
4369 {
4371  /* TODO: If you implement newgrf callback 149 'land slope check', you have to decide what to do with it here.
4372  * TTDP does not call it.
4373  */
4374  if (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new)) {
4375  switch (GetStationType(tile)) {
4376  case STATION_WAYPOINT:
4377  case STATION_RAIL: {
4378  DiagDirection direction = AxisToDiagDir(GetRailStationAxis(tile));
4379  if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, direction)) break;
4380  if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, ReverseDiagDir(direction))) break;
4381  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
4382  }
4383 
4384  case STATION_AIRPORT:
4385  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
4386 
4387  case STATION_TRUCK:
4388  case STATION_BUS: {
4389  DiagDirection direction = GetRoadStopDir(tile);
4390  if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, direction)) break;
4391  if (IsDriveThroughStopTile(tile)) {
4392  if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, ReverseDiagDir(direction))) break;
4393  }
4394  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
4395  }
4396 
4397  default: break;
4398  }
4399  }
4400  }
4401  return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
4402 }
4403 
4409 uint FlowStat::GetShare(StationID st) const
4410 {
4411  uint32 prev = 0;
4412  for (SharesMap::const_iterator it = this->shares.begin(); it != this->shares.end(); ++it) {
4413  if (it->second == st) {
4414  return it->first - prev;
4415  } else {
4416  prev = it->first;
4417  }
4418  }
4419  return 0;
4420 }
4421 
4428 StationID FlowStat::GetVia(StationID excluded, StationID excluded2) const
4429 {
4430  if (this->unrestricted == 0) return INVALID_STATION;
4431  assert(!this->shares.empty());
4432  SharesMap::const_iterator it = this->shares.upper_bound(RandomRange(this->unrestricted));
4433  assert(it != this->shares.end() && it->first <= this->unrestricted);
4434  if (it->second != excluded && it->second != excluded2) return it->second;
4435 
4436  /* We've hit one of the excluded stations.
4437  * Draw another share, from outside its range. */
4438 
4439  uint end = it->first;
4440  uint begin = (it == this->shares.begin() ? 0 : (--it)->first);
4441  uint interval = end - begin;
4442  if (interval >= this->unrestricted) return INVALID_STATION; // Only one station in the map.
4443  uint new_max = this->unrestricted - interval;
4444  uint rand = RandomRange(new_max);
4445  SharesMap::const_iterator it2 = (rand < begin) ? this->shares.upper_bound(rand) :
4446  this->shares.upper_bound(rand + interval);
4447  assert(it2 != this->shares.end() && it2->first <= this->unrestricted);
4448  if (it2->second != excluded && it2->second != excluded2) return it2->second;
4449 
4450  /* We've hit the second excluded station.
4451  * Same as before, only a bit more complicated. */
4452 
4453  uint end2 = it2->first;
4454  uint begin2 = (it2 == this->shares.begin() ? 0 : (--it2)->first);
4455  uint interval2 = end2 - begin2;
4456  if (interval2 >= new_max) return INVALID_STATION; // Only the two excluded stations in the map.
4457  new_max -= interval2;
4458  if (begin > begin2) {
4459  Swap(begin, begin2);
4460  Swap(end, end2);
4461  Swap(interval, interval2);
4462  }
4463  rand = RandomRange(new_max);
4464  SharesMap::const_iterator it3 = this->shares.upper_bound(this->unrestricted);
4465  if (rand < begin) {
4466  it3 = this->shares.upper_bound(rand);
4467  } else if (rand < begin2 - interval) {
4468  it3 = this->shares.upper_bound(rand + interval);
4469  } else {
4470  it3 = this->shares.upper_bound(rand + interval + interval2);
4471  }
4472  assert(it3 != this->shares.end() && it3->first <= this->unrestricted);
4473  return it3->second;
4474 }
4475 
4482 {
4483  assert(!this->shares.empty());
4484  SharesMap new_shares;
4485  uint i = 0;
4486  for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) {
4487  new_shares[++i] = it->second;
4488  if (it->first == this->unrestricted) this->unrestricted = i;
4489  }
4490  this->shares.swap(new_shares);
4491  assert(!this->shares.empty() && this->unrestricted <= (--this->shares.end())->first);
4492 }
4493 
4500 void FlowStat::ChangeShare(StationID st, int flow)
4501 {
4502  /* We assert only before changing as afterwards the shares can actually
4503  * be empty. In that case the whole flow stat must be deleted then. */
4504  assert(!this->shares.empty());
4505 
4506  uint removed_shares = 0;
4507  uint added_shares = 0;
4508  uint last_share = 0;
4509  SharesMap new_shares;
4510  for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) {
4511  if (it->second == st) {
4512  if (flow < 0) {
4513  uint share = it->first - last_share;
4514  if (flow == INT_MIN || (uint)(-flow) >= share) {
4515  removed_shares += share;
4516  if (it->first <= this->unrestricted) this->unrestricted -= share;
4517  if (flow != INT_MIN) flow += share;
4518  last_share = it->first;
4519  continue; // remove the whole share
4520  }
4521  removed_shares += (uint)(-flow);
4522  } else {
4523  added_shares += (uint)(flow);
4524  }
4525  if (it->first <= this->unrestricted) this->unrestricted += flow;
4526 
4527  /* If we don't continue above the whole flow has been added or
4528  * removed. */
4529  flow = 0;
4530  }
4531  new_shares[it->first + added_shares - removed_shares] = it->second;
4532  last_share = it->first;
4533  }
4534  if (flow > 0) {
4535  new_shares[last_share + (uint)flow] = st;
4536  if (this->unrestricted < last_share) {
4537  this->ReleaseShare(st);
4538  } else {
4539  this->unrestricted += flow;
4540  }
4541  }
4542  this->shares.swap(new_shares);
4543 }
4544 
4550 void FlowStat::RestrictShare(StationID st)
4551 {
4552  assert(!this->shares.empty());
4553  uint flow = 0;
4554  uint last_share = 0;
4555  SharesMap new_shares;
4556  for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) {
4557  if (flow == 0) {
4558  if (it->first > this->unrestricted) return; // Not present or already restricted.
4559  if (it->second == st) {
4560  flow = it->first - last_share;
4561  this->unrestricted -= flow;
4562  } else {
4563  new_shares[it->first] = it->second;
4564  }
4565  } else {
4566  new_shares[it->first - flow] = it->second;
4567  }
4568  last_share = it->first;
4569  }
4570  if (flow == 0) return;
4571  new_shares[last_share + flow] = st;
4572  this->shares.swap(new_shares);
4573  assert(!this->shares.empty());
4574 }
4575 
4581 void FlowStat::ReleaseShare(StationID st)
4582 {
4583  assert(!this->shares.empty());
4584  uint flow = 0;
4585  uint next_share = 0;
4586  bool found = false;
4587  for (SharesMap::reverse_iterator it(this->shares.rbegin()); it != this->shares.rend(); ++it) {
4588  if (it->first < this->unrestricted) return; // Note: not <= as the share may hit the limit.
4589  if (found) {
4590  flow = next_share - it->first;
4591  this->unrestricted += flow;
4592  break;
4593  } else {
4594  if (it->first == this->unrestricted) return; // !found -> Limit not hit.
4595  if (it->second == st) found = true;
4596  }
4597  next_share = it->first;
4598  }
4599  if (flow == 0) return;
4600  SharesMap new_shares;
4601  new_shares[flow] = st;
4602  for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) {
4603  if (it->second != st) {
4604  new_shares[flow + it->first] = it->second;
4605  } else {
4606  flow = 0;
4607  }
4608  }
4609  this->shares.swap(new_shares);
4610  assert(!this->shares.empty());
4611 }
4612 
4618 void FlowStat::ScaleToMonthly(uint runtime)
4619 {
4620  assert(runtime > 0);
4621  SharesMap new_shares;
4622  uint share = 0;
4623  for (SharesMap::iterator i = this->shares.begin(); i != this->shares.end(); ++i) {
4624  share = max(share + 1, i->first * 30 / runtime);
4625  new_shares[share] = i->second;
4626  if (this->unrestricted == i->first) this->unrestricted = share;
4627  }
4628  this->shares.swap(new_shares);
4629 }
4630 
4637 void FlowStatMap::AddFlow(StationID origin, StationID via, uint flow)
4638 {
4639  FlowStatMap::iterator origin_it = this->find(origin);
4640  if (origin_it == this->end()) {
4641  this->insert(std::make_pair(origin, FlowStat(via, flow)));
4642  } else {
4643  origin_it->second.ChangeShare(via, flow);
4644  assert(!origin_it->second.GetShares()->empty());
4645  }
4646 }
4647 
4656 void FlowStatMap::PassOnFlow(StationID origin, StationID via, uint flow)
4657 {
4658  FlowStatMap::iterator prev_it = this->find(origin);
4659  if (prev_it == this->end()) {
4660  FlowStat fs(via, flow);
4661  fs.AppendShare(INVALID_STATION, flow);
4662  this->insert(std::make_pair(origin, fs));
4663  } else {
4664  prev_it->second.ChangeShare(via, flow);
4665  prev_it->second.ChangeShare(INVALID_STATION, flow);
4666  assert(!prev_it->second.GetShares()->empty());
4667  }
4668 }
4669 
4675 {
4676  for (FlowStatMap::iterator i = this->begin(); i != this->end(); ++i) {
4677  FlowStat &fs = i->second;
4678  uint local = fs.GetShare(INVALID_STATION);
4679  if (local > INT_MAX) { // make sure it fits in an int
4680  fs.ChangeShare(self, -INT_MAX);
4681  fs.ChangeShare(INVALID_STATION, -INT_MAX);
4682  local -= INT_MAX;
4683  }
4684  fs.ChangeShare(self, -(int)local);
4685  fs.ChangeShare(INVALID_STATION, -(int)local);
4686 
4687  /* If the local share is used up there must be a share for some
4688  * remote station. */
4689  assert(!fs.GetShares()->empty());
4690  }
4691 }
4692 
4700 {
4701  StationIDStack ret;
4702  for (FlowStatMap::iterator f_it = this->begin(); f_it != this->end();) {
4703  FlowStat &s_flows = f_it->second;
4704  s_flows.ChangeShare(via, INT_MIN);
4705  if (s_flows.GetShares()->empty()) {
4706  ret.Push(f_it->first);
4707  this->erase(f_it++);
4708  } else {
4709  ++f_it;
4710  }
4711  }
4712  return ret;
4713 }
4714 
4719 void FlowStatMap::RestrictFlows(StationID via)
4720 {
4721  for (FlowStatMap::iterator it = this->begin(); it != this->end(); ++it) {
4722  it->second.RestrictShare(via);
4723  }
4724 }
4725 
4730 void FlowStatMap::ReleaseFlows(StationID via)
4731 {
4732  for (FlowStatMap::iterator it = this->begin(); it != this->end(); ++it) {
4733  it->second.ReleaseShare(via);
4734  }
4735 }
4736 
4742 {
4743  uint ret = 0;
4744  for (FlowStatMap::const_iterator i = this->begin(); i != this->end(); ++i) {
4745  ret += (--(i->second.GetShares()->end()))->first;
4746  }
4747  return ret;
4748 }
4749 
4755 uint FlowStatMap::GetFlowVia(StationID via) const
4756 {
4757  uint ret = 0;
4758  for (FlowStatMap::const_iterator i = this->begin(); i != this->end(); ++i) {
4759  ret += i->second.GetShare(via);
4760  }
4761  return ret;
4762 }
4763 
4769 uint FlowStatMap::GetFlowFrom(StationID from) const
4770 {
4771  FlowStatMap::const_iterator i = this->find(from);
4772  if (i == this->end()) return 0;
4773  return (--(i->second.GetShares()->end()))->first;
4774 }
4775 
4782 uint FlowStatMap::GetFlowFromVia(StationID from, StationID via) const
4783 {
4784  FlowStatMap::const_iterator i = this->find(from);
4785  if (i == this->end()) return 0;
4786  return i->second.GetShare(via);
4787 }
4788 
4789 extern const TileTypeProcs _tile_type_station_procs = {
4790  DrawTile_Station, // draw_tile_proc
4791  GetSlopePixelZ_Station, // get_slope_z_proc
4792  ClearTile_Station, // clear_tile_proc
4793  nullptr, // add_accepted_cargo_proc
4794  GetTileDesc_Station, // get_tile_desc_proc
4795  GetTileTrackStatus_Station, // get_tile_track_status_proc
4796  ClickTile_Station, // click_tile_proc
4797  AnimateTile_Station, // animate_tile_proc
4798  TileLoop_Station, // tile_loop_proc
4799  ChangeTileOwner_Station, // change_tile_owner_proc
4800  nullptr, // add_produced_cargo_proc
4801  VehicleEnter_Station, // vehicle_enter_tile_proc
4802  GetFoundation_Station, // get_foundation_proc
4803  TerraformTile_Station, // terraform_tile_proc
4804 };
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:1210
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:790
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.