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