OpenTTD
station_cmd.cpp
Go to the documentation of this file.
1 /* $Id: station_cmd.cpp 27893 2017-08-13 18:38:42Z frosch $ */
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 "command_func.h"
18 #include "town.h"
19 #include "news_func.h"
20 #include "train.h"
21 #include "ship.h"
22 #include "roadveh.h"
23 #include "industry.h"
24 #include "newgrf_cargo.h"
25 #include "newgrf_debug.h"
26 #include "newgrf_station.h"
27 #include "newgrf_canal.h" /* For the buoy */
29 #include "road_internal.h" /* For drawing catenary/checking road removal */
30 #include "autoslope.h"
31 #include "water.h"
32 #include "strings_func.h"
33 #include "clear_func.h"
34 #include "date_func.h"
35 #include "vehicle_func.h"
36 #include "string_func.h"
37 #include "animated_tile_func.h"
38 #include "elrail_func.h"
39 #include "station_base.h"
40 #include "roadstop_base.h"
41 #include "newgrf_railtype.h"
42 #include "waypoint_base.h"
43 #include "waypoint_func.h"
44 #include "pbs.h"
45 #include "debug.h"
46 #include "core/random_func.hpp"
47 #include "company_base.h"
48 #include "table/airporttile_ids.h"
49 #include "newgrf_airporttiles.h"
50 #include "order_backup.h"
51 #include "newgrf_house.h"
52 #include "company_gui.h"
54 #include "linkgraph/refresh.h"
55 #include "widgets/station_widget.h"
56 
57 #include "table/strings.h"
58 
59 #include "safeguards.h"
60 
66 /* static */ const FlowStat::SharesMap FlowStat::empty_sharesmap;
67 
75 {
76  assert(IsTileType(t, MP_STATION));
77 
78  /* If the tile isn't an airport there's no chance it's a hangar. */
79  if (!IsAirport(t)) return false;
80 
81  const Station *st = Station::GetByTile(t);
82  const AirportSpec *as = st->airport.GetSpec();
83 
84  for (uint i = 0; i < as->nof_depots; i++) {
85  if (st->airport.GetHangarTile(i) == t) return true;
86  }
87 
88  return false;
89 }
90 
98 template <class T>
99 CommandCost GetStationAround(TileArea ta, StationID closest_station, T **st)
100 {
101  ta.tile -= TileDiffXY(1, 1);
102  ta.w += 2;
103  ta.h += 2;
104 
105  /* check around to see if there's any stations there */
106  TILE_AREA_LOOP(tile_cur, ta) {
107  if (IsTileType(tile_cur, MP_STATION)) {
108  StationID t = GetStationIndex(tile_cur);
109  if (!T::IsValidID(t)) continue;
110 
111  if (closest_station == INVALID_STATION) {
112  closest_station = t;
113  } else if (closest_station != t) {
114  return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
115  }
116  }
117  }
118  *st = (closest_station == INVALID_STATION) ? NULL : T::Get(closest_station);
119  return CommandCost();
120 }
121 
127 typedef bool (*CMSAMatcher)(TileIndex tile);
128 
136 {
137  int num = 0;
138 
139  for (int dx = -3; dx <= 3; dx++) {
140  for (int dy = -3; dy <= 3; dy++) {
141  TileIndex t = TileAddWrap(tile, dx, dy);
142  if (t != INVALID_TILE && cmp(t)) num++;
143  }
144  }
145 
146  return num;
147 }
148 
154 static bool CMSAMine(TileIndex tile)
155 {
156  /* No industry */
157  if (!IsTileType(tile, MP_INDUSTRY)) return false;
158 
159  const Industry *ind = Industry::GetByTile(tile);
160 
161  /* No extractive industry */
162  if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_EXTRACTIVE) == 0) return false;
163 
164  for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
165  /* The industry extracts something non-liquid, i.e. no oil or plastic, so it is a mine.
166  * Also the production of passengers and mail is ignored. */
167  if (ind->produced_cargo[i] != CT_INVALID &&
169  return true;
170  }
171  }
172 
173  return false;
174 }
175 
181 static bool CMSAWater(TileIndex tile)
182 {
183  return IsTileType(tile, MP_WATER) && IsWater(tile);
184 }
185 
191 static bool CMSATree(TileIndex tile)
192 {
193  return IsTileType(tile, MP_TREES);
194 }
195 
196 #define M(x) ((x) - STR_SV_STNAME)
197 
198 enum StationNaming {
199  STATIONNAMING_RAIL,
200  STATIONNAMING_ROAD,
201  STATIONNAMING_AIRPORT,
202  STATIONNAMING_OILRIG,
203  STATIONNAMING_DOCK,
204  STATIONNAMING_HELIPORT,
205 };
206 
209  uint32 free_names;
210  bool *indtypes;
211 };
212 
221 static bool FindNearIndustryName(TileIndex tile, void *user_data)
222 {
223  /* All already found industry types */
225  if (!IsTileType(tile, MP_INDUSTRY)) return false;
226 
227  /* If the station name is undefined it means that it doesn't name a station */
228  IndustryType indtype = GetIndustryType(tile);
229  if (GetIndustrySpec(indtype)->station_name == STR_UNDEFINED) return false;
230 
231  /* In all cases if an industry that provides a name is found two of
232  * the standard names will be disabled. */
233  sni->free_names &= ~(1 << M(STR_SV_STNAME_OILFIELD) | 1 << M(STR_SV_STNAME_MINES));
234  return !sni->indtypes[indtype];
235 }
236 
237 static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming name_class)
238 {
239  static const uint32 _gen_station_name_bits[] = {
240  0, // STATIONNAMING_RAIL
241  0, // STATIONNAMING_ROAD
242  1U << M(STR_SV_STNAME_AIRPORT), // STATIONNAMING_AIRPORT
243  1U << M(STR_SV_STNAME_OILFIELD), // STATIONNAMING_OILRIG
244  1U << M(STR_SV_STNAME_DOCKS), // STATIONNAMING_DOCK
245  1U << M(STR_SV_STNAME_HELIPORT), // STATIONNAMING_HELIPORT
246  };
247 
248  const Town *t = st->town;
249  uint32 free_names = UINT32_MAX;
250 
252  memset(indtypes, 0, sizeof(indtypes));
253 
254  const Station *s;
255  FOR_ALL_STATIONS(s) {
256  if (s != st && s->town == t) {
257  if (s->indtype != IT_INVALID) {
258  indtypes[s->indtype] = true;
260  if (name != STR_UNDEFINED) {
261  /* Filter for other industrytypes with the same name */
262  for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
263  const IndustrySpec *indsp = GetIndustrySpec(it);
264  if (indsp->enabled && indsp->station_name == name) indtypes[it] = true;
265  }
266  }
267  continue;
268  }
269  uint str = M(s->string_id);
270  if (str <= 0x20) {
271  if (str == M(STR_SV_STNAME_FOREST)) {
272  str = M(STR_SV_STNAME_WOODS);
273  }
274  ClrBit(free_names, str);
275  }
276  }
277  }
278 
279  TileIndex indtile = tile;
280  StationNameInformation sni = { free_names, indtypes };
281  if (CircularTileSearch(&indtile, 7, FindNearIndustryName, &sni)) {
282  /* An industry has been found nearby */
283  IndustryType indtype = GetIndustryType(indtile);
284  const IndustrySpec *indsp = GetIndustrySpec(indtype);
285  /* STR_NULL means it only disables oil rig/mines */
286  if (indsp->station_name != STR_NULL) {
287  st->indtype = indtype;
288  return STR_SV_STNAME_FALLBACK;
289  }
290  }
291 
292  /* Oil rigs/mines name could be marked not free by looking for a near by industry. */
293  free_names = sni.free_names;
294 
295  /* check default names */
296  uint32 tmp = free_names & _gen_station_name_bits[name_class];
297  if (tmp != 0) return STR_SV_STNAME + FindFirstBit(tmp);
298 
299  /* check mine? */
300  if (HasBit(free_names, M(STR_SV_STNAME_MINES))) {
301  if (CountMapSquareAround(tile, CMSAMine) >= 2) {
302  return STR_SV_STNAME_MINES;
303  }
304  }
305 
306  /* check close enough to town to get central as name? */
307  if (DistanceMax(tile, t->xy) < 8) {
308  if (HasBit(free_names, M(STR_SV_STNAME))) return STR_SV_STNAME;
309 
310  if (HasBit(free_names, M(STR_SV_STNAME_CENTRAL))) return STR_SV_STNAME_CENTRAL;
311  }
312 
313  /* Check lakeside */
314  if (HasBit(free_names, M(STR_SV_STNAME_LAKESIDE)) &&
315  DistanceFromEdge(tile) < 20 &&
316  CountMapSquareAround(tile, CMSAWater) >= 5) {
317  return STR_SV_STNAME_LAKESIDE;
318  }
319 
320  /* Check woods */
321  if (HasBit(free_names, M(STR_SV_STNAME_WOODS)) && (
322  CountMapSquareAround(tile, CMSATree) >= 8 ||
324  ) {
325  return _settings_game.game_creation.landscape == LT_TROPIC ? STR_SV_STNAME_FOREST : STR_SV_STNAME_WOODS;
326  }
327 
328  /* check elevation compared to town */
329  int z = GetTileZ(tile);
330  int z2 = GetTileZ(t->xy);
331  if (z < z2) {
332  if (HasBit(free_names, M(STR_SV_STNAME_VALLEY))) return STR_SV_STNAME_VALLEY;
333  } else if (z > z2) {
334  if (HasBit(free_names, M(STR_SV_STNAME_HEIGHTS))) return STR_SV_STNAME_HEIGHTS;
335  }
336 
337  /* check direction compared to town */
338  static const int8 _direction_and_table[] = {
339  ~( (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_EAST)) | (1 << M(STR_SV_STNAME_NORTH)) ),
340  ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_NORTH)) ),
341  ~( (1 << M(STR_SV_STNAME_SOUTH)) | (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_EAST)) ),
343  };
344 
345  free_names &= _direction_and_table[
346  (TileX(tile) < TileX(t->xy)) +
347  (TileY(tile) < TileY(t->xy)) * 2];
348 
349  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));
350  return (tmp == 0) ? STR_SV_STNAME_FALLBACK : (STR_SV_STNAME + FindFirstBit(tmp));
351 }
352 #undef M
353 
360 {
361  uint threshold = 8;
362  Station *best_station = NULL;
363  Station *st;
364 
365  FOR_ALL_STATIONS(st) {
366  if (!st->IsInUse() && st->owner == _current_company) {
367  uint cur_dist = DistanceManhattan(tile, st->xy);
368 
369  if (cur_dist < threshold) {
370  threshold = cur_dist;
371  best_station = st;
372  }
373  }
374  }
375 
376  return best_station;
377 }
378 
379 
381 {
382  switch (type) {
383  case STATION_RAIL:
384  *ta = this->train_station;
385  return;
386 
387  case STATION_AIRPORT:
388  *ta = this->airport;
389  return;
390 
391  case STATION_TRUCK:
392  *ta = this->truck_station;
393  return;
394 
395  case STATION_BUS:
396  *ta = this->bus_station;
397  return;
398 
399  case STATION_DOCK:
400  case STATION_OILRIG:
401  ta->tile = this->dock_tile;
402  break;
403 
404  default: NOT_REACHED();
405  }
406 
407  ta->w = 1;
408  ta->h = 1;
409 }
410 
415 {
416  Point pt = RemapCoords2(TileX(this->xy) * TILE_SIZE, TileY(this->xy) * TILE_SIZE);
417 
418  pt.y -= 32 * ZOOM_LVL_BASE;
419  if ((this->facilities & FACIL_AIRPORT) && this->airport.type == AT_OILRIG) pt.y -= 16 * ZOOM_LVL_BASE;
420 
421  SetDParam(0, this->index);
422  SetDParam(1, this->facilities);
423  this->sign.UpdatePosition(pt.x, pt.y, STR_VIEWPORT_STATION);
424 
425  SetWindowDirty(WC_STATION_VIEW, this->index);
426 }
427 
430 {
431  BaseStation *st;
432 
433  FOR_ALL_BASE_STATIONS(st) {
434  st->UpdateVirtCoord();
435  }
436 }
437 
443 static uint GetAcceptanceMask(const Station *st)
444 {
445  uint mask = 0;
446 
447  for (CargoID i = 0; i < NUM_CARGO; i++) {
448  if (HasBit(st->goods[i].status, GoodsEntry::GES_ACCEPTANCE)) mask |= 1 << i;
449  }
450  return mask;
451 }
452 
457 static void ShowRejectOrAcceptNews(const Station *st, uint num_items, CargoID *cargo, StringID msg)
458 {
459  for (uint i = 0; i < num_items; i++) {
460  SetDParam(i + 1, CargoSpec::Get(cargo[i])->name);
461  }
462 
463  SetDParam(0, st->index);
465 }
466 
474 CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad)
475 {
476  CargoArray produced;
477 
478  int x = TileX(tile);
479  int y = TileY(tile);
480 
481  /* expand the region by rad tiles on each side
482  * while making sure that we remain inside the board. */
483  int x2 = min(x + w + rad, MapSizeX());
484  int x1 = max(x - rad, 0);
485 
486  int y2 = min(y + h + rad, MapSizeY());
487  int y1 = max(y - rad, 0);
488 
489  assert(x1 < x2);
490  assert(y1 < y2);
491  assert(w > 0);
492  assert(h > 0);
493 
494  TileArea ta(TileXY(x1, y1), TileXY(x2 - 1, y2 - 1));
495 
496  /* Loop over all tiles to get the produced cargo of
497  * everything except industries */
498  TILE_AREA_LOOP(tile, ta) AddProducedCargo(tile, produced);
499 
500  /* Loop over the industries. They produce cargo for
501  * anything that is within 'rad' from their bounding
502  * box. As such if you have e.g. a oil well the tile
503  * area loop might not hit an industry tile while
504  * the industry would produce cargo for the station.
505  */
506  const Industry *i;
507  FOR_ALL_INDUSTRIES(i) {
508  if (!ta.Intersects(i->location)) continue;
509 
510  for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
511  CargoID cargo = i->produced_cargo[j];
512  if (cargo != CT_INVALID) produced[cargo]++;
513  }
514  }
515 
516  return produced;
517 }
518 
527 CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, uint32 *always_accepted)
528 {
529  CargoArray acceptance;
530  if (always_accepted != NULL) *always_accepted = 0;
531 
532  int x = TileX(tile);
533  int y = TileY(tile);
534 
535  /* expand the region by rad tiles on each side
536  * while making sure that we remain inside the board. */
537  int x2 = min(x + w + rad, MapSizeX());
538  int y2 = min(y + h + rad, MapSizeY());
539  int x1 = max(x - rad, 0);
540  int y1 = max(y - rad, 0);
541 
542  assert(x1 < x2);
543  assert(y1 < y2);
544  assert(w > 0);
545  assert(h > 0);
546 
547  for (int yc = y1; yc != y2; yc++) {
548  for (int xc = x1; xc != x2; xc++) {
549  TileIndex tile = TileXY(xc, yc);
550  AddAcceptedCargo(tile, acceptance, always_accepted);
551  }
552  }
553 
554  return acceptance;
555 }
556 
562 void UpdateStationAcceptance(Station *st, bool show_msg)
563 {
564  /* old accepted goods types */
565  uint old_acc = GetAcceptanceMask(st);
566 
567  /* And retrieve the acceptance. */
568  CargoArray acceptance;
569  if (!st->rect.IsEmpty()) {
570  acceptance = GetAcceptanceAroundTiles(
571  TileXY(st->rect.left, st->rect.top),
572  st->rect.right - st->rect.left + 1,
573  st->rect.bottom - st->rect.top + 1,
574  st->GetCatchmentRadius(),
575  &st->always_accepted
576  );
577  }
578 
579  /* Adjust in case our station only accepts fewer kinds of goods */
580  for (CargoID i = 0; i < NUM_CARGO; i++) {
581  uint amt = acceptance[i];
582 
583  /* Make sure the station can accept the goods type. */
584  bool is_passengers = IsCargoInClass(i, CC_PASSENGERS);
585  if ((!is_passengers && !(st->facilities & ~FACIL_BUS_STOP)) ||
586  (is_passengers && !(st->facilities & ~FACIL_TRUCK_STOP))) {
587  amt = 0;
588  }
589 
590  GoodsEntry &ge = st->goods[i];
591  SB(ge.status, GoodsEntry::GES_ACCEPTANCE, 1, amt >= 8);
593  (*LinkGraph::Get(ge.link_graph))[ge.node].SetDemand(amt / 8);
594  }
595  }
596 
597  /* Only show a message in case the acceptance was actually changed. */
598  uint new_acc = GetAcceptanceMask(st);
599  if (old_acc == new_acc) return;
600 
601  /* show a message to report that the acceptance was changed? */
602  if (show_msg && st->owner == _local_company && st->IsInUse()) {
603  /* List of accept and reject strings for different number of
604  * cargo types */
605  static const StringID accept_msg[] = {
606  STR_NEWS_STATION_NOW_ACCEPTS_CARGO,
607  STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO,
608  };
609  static const StringID reject_msg[] = {
610  STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO,
611  STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO,
612  };
613 
614  /* Array of accepted and rejected cargo types */
615  CargoID accepts[2] = { CT_INVALID, CT_INVALID };
616  CargoID rejects[2] = { CT_INVALID, CT_INVALID };
617  uint num_acc = 0;
618  uint num_rej = 0;
619 
620  /* Test each cargo type to see if its acceptance has changed */
621  for (CargoID i = 0; i < NUM_CARGO; i++) {
622  if (HasBit(new_acc, i)) {
623  if (!HasBit(old_acc, i) && num_acc < lengthof(accepts)) {
624  /* New cargo is accepted */
625  accepts[num_acc++] = i;
626  }
627  } else {
628  if (HasBit(old_acc, i) && num_rej < lengthof(rejects)) {
629  /* Old cargo is no longer accepted */
630  rejects[num_rej++] = i;
631  }
632  }
633  }
634 
635  /* Show news message if there are any changes */
636  if (num_acc > 0) ShowRejectOrAcceptNews(st, num_acc, accepts, accept_msg[num_acc - 1]);
637  if (num_rej > 0) ShowRejectOrAcceptNews(st, num_rej, rejects, reject_msg[num_rej - 1]);
638  }
639 
640  /* redraw the station view since acceptance changed */
642 }
643 
644 static void UpdateStationSignCoord(BaseStation *st)
645 {
646  const StationRect *r = &st->rect;
647 
648  if (r->IsEmpty()) return; // no tiles belong to this station
649 
650  /* clamp sign coord to be inside the station rect */
651  st->xy = TileXY(ClampU(TileX(st->xy), r->left, r->right), ClampU(TileY(st->xy), r->top, r->bottom));
652  st->UpdateVirtCoord();
653 
654  if (!Station::IsExpected(st)) return;
655  Station *full_station = Station::From(st);
656  for (CargoID c = 0; c < NUM_CARGO; ++c) {
657  LinkGraphID lg = full_station->goods[c].link_graph;
658  if (!LinkGraph::IsValidID(lg)) continue;
659  (*LinkGraph::Get(lg))[full_station->goods[c].node].UpdateLocation(st->xy);
660  }
661 }
662 
672 static CommandCost BuildStationPart(Station **st, DoCommandFlag flags, bool reuse, TileArea area, StationNaming name_class)
673 {
674  /* Find a deleted station close to us */
675  if (*st == NULL && reuse) *st = GetClosestDeletedStation(area.tile);
676 
677  if (*st != NULL) {
678  if ((*st)->owner != _current_company) {
679  return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION);
680  }
681 
682  CommandCost ret = (*st)->rect.BeforeAddRect(area.tile, area.w, area.h, StationRect::ADD_TEST);
683  if (ret.Failed()) return ret;
684  } else {
685  /* allocate and initialize new station */
686  if (!Station::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);
687 
688  if (flags & DC_EXEC) {
689  *st = new Station(area.tile);
690 
691  (*st)->town = ClosestTownFromTile(area.tile, UINT_MAX);
692  (*st)->string_id = GenerateStationName(*st, area.tile, name_class);
693 
695  SetBit((*st)->town->have_ratings, _current_company);
696  }
697  }
698  }
699  return CommandCost();
700 }
701 
709 {
710  if (!st->IsInUse()) {
711  st->delete_ctr = 0;
713  }
714  /* station remains but it probably lost some parts - station sign should stay in the station boundaries */
715  UpdateStationSignCoord(st);
716 }
717 
719 
729 CommandCost CheckBuildableTile(TileIndex tile, uint invalid_dirs, int &allowed_z, bool allow_steep, bool check_bridge = true)
730 {
731  if (check_bridge && IsBridgeAbove(tile)) {
732  return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
733  }
734 
736  if (ret.Failed()) return ret;
737 
738  int z;
739  Slope tileh = GetTileSlope(tile, &z);
740 
741  /* Prohibit building if
742  * 1) The tile is "steep" (i.e. stretches two height levels).
743  * 2) The tile is non-flat and the build_on_slopes switch is disabled.
744  */
745  if ((!allow_steep && IsSteepSlope(tileh)) ||
747  return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
748  }
749 
751  int flat_z = z + GetSlopeMaxZ(tileh);
752  if (tileh != SLOPE_FLAT) {
753  /* Forbid building if the tile faces a slope in a invalid direction. */
754  for (DiagDirection dir = DIAGDIR_BEGIN; dir != DIAGDIR_END; dir++) {
755  if (HasBit(invalid_dirs, dir) && !CanBuildDepotByTileh(dir, tileh)) {
756  return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
757  }
758  }
759  cost.AddCost(_price[PR_BUILD_FOUNDATION]);
760  }
761 
762  /* The level of this tile must be equal to allowed_z. */
763  if (allowed_z < 0) {
764  /* First tile. */
765  allowed_z = flat_z;
766  } else if (allowed_z != flat_z) {
767  return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
768  }
769 
770  return cost;
771 }
772 
780 {
782  int allowed_z = -1;
783 
784  TILE_AREA_LOOP(tile_cur, tile_area) {
785  CommandCost ret = CheckBuildableTile(tile_cur, 0, allowed_z, true);
786  if (ret.Failed()) return ret;
787  cost.AddCost(ret);
788 
789  ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
790  if (ret.Failed()) return ret;
791  cost.AddCost(ret);
792  }
793 
794  return cost;
795 }
796 
811 static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag flags, Axis axis, StationID *station, RailType rt, SmallVector<Train *, 4> &affected_vehicles, StationClassID spec_class, byte spec_index, byte plat_len, byte numtracks)
812 {
814  int allowed_z = -1;
815  uint invalid_dirs = 5 << axis;
816 
817  const StationSpec *statspec = StationClass::Get(spec_class)->GetSpec(spec_index);
818  bool slope_cb = statspec != NULL && HasBit(statspec->callback_mask, CBM_STATION_SLOPE_CHECK);
819 
820  TILE_AREA_LOOP(tile_cur, tile_area) {
821  CommandCost ret = CheckBuildableTile(tile_cur, invalid_dirs, allowed_z, false);
822  if (ret.Failed()) return ret;
823  cost.AddCost(ret);
824 
825  if (slope_cb) {
826  /* Do slope check if requested. */
827  ret = PerformStationTileSlopeCheck(tile_area.tile, tile_cur, statspec, axis, plat_len, numtracks);
828  if (ret.Failed()) return ret;
829  }
830 
831  /* if station is set, then we have special handling to allow building on top of already existing stations.
832  * so station points to INVALID_STATION if we can build on any station.
833  * Or it points to a station if we're only allowed to build on exactly that station. */
834  if (station != NULL && IsTileType(tile_cur, MP_STATION)) {
835  if (!IsRailStation(tile_cur)) {
836  return ClearTile_Station(tile_cur, DC_AUTO); // get error message
837  } else {
838  StationID st = GetStationIndex(tile_cur);
839  if (*station == INVALID_STATION) {
840  *station = st;
841  } else if (*station != st) {
842  return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
843  }
844  }
845  } else {
846  /* Rail type is only valid when building a railway station; if station to
847  * build isn't a rail station it's INVALID_RAILTYPE. */
848  if (rt != INVALID_RAILTYPE &&
849  IsPlainRailTile(tile_cur) && !HasSignals(tile_cur) &&
850  HasPowerOnRail(GetRailType(tile_cur), rt)) {
851  /* Allow overbuilding if the tile:
852  * - has rail, but no signals
853  * - it has exactly one track
854  * - the track is in line with the station
855  * - the current rail type has power on the to-be-built type (e.g. convert normal rail to el rail)
856  */
857  TrackBits tracks = GetTrackBits(tile_cur);
858  Track track = RemoveFirstTrack(&tracks);
859  Track expected_track = HasBit(invalid_dirs, DIAGDIR_NE) ? TRACK_X : TRACK_Y;
860 
861  if (tracks == TRACK_BIT_NONE && track == expected_track) {
862  /* Check for trains having a reservation for this tile. */
863  if (HasBit(GetRailReservationTrackBits(tile_cur), track)) {
864  Train *v = GetTrainForReservation(tile_cur, track);
865  if (v != NULL) {
866  *affected_vehicles.Append() = v;
867  }
868  }
869  CommandCost ret = DoCommand(tile_cur, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
870  if (ret.Failed()) return ret;
871  cost.AddCost(ret);
872  /* With flags & ~DC_EXEC CmdLandscapeClear would fail since the rail still exists */
873  continue;
874  }
875  }
876  ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
877  if (ret.Failed()) return ret;
878  cost.AddCost(ret);
879  }
880  }
881 
882  return cost;
883 }
884 
897 static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, bool is_truck_stop, Axis axis, StationID *station, RoadTypes rts)
898 {
900  int allowed_z = -1;
901 
902  TILE_AREA_LOOP(cur_tile, tile_area) {
903  CommandCost ret = CheckBuildableTile(cur_tile, invalid_dirs, allowed_z, !is_drive_through);
904  if (ret.Failed()) return ret;
905  cost.AddCost(ret);
906 
907  /* If station is set, then we have special handling to allow building on top of already existing stations.
908  * Station points to INVALID_STATION if we can build on any station.
909  * Or it points to a station if we're only allowed to build on exactly that station. */
910  if (station != NULL && IsTileType(cur_tile, MP_STATION)) {
911  if (!IsRoadStop(cur_tile)) {
912  return ClearTile_Station(cur_tile, DC_AUTO); // Get error message.
913  } else {
914  if (is_truck_stop != IsTruckStop(cur_tile) ||
915  is_drive_through != IsDriveThroughStopTile(cur_tile)) {
916  return ClearTile_Station(cur_tile, DC_AUTO); // Get error message.
917  }
918  /* Drive-through station in the wrong direction. */
919  if (is_drive_through && IsDriveThroughStopTile(cur_tile) && DiagDirToAxis(GetRoadStopDir(cur_tile)) != axis){
920  return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION);
921  }
922  StationID st = GetStationIndex(cur_tile);
923  if (*station == INVALID_STATION) {
924  *station = st;
925  } else if (*station != st) {
926  return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
927  }
928  }
929  } else {
930  bool build_over_road = is_drive_through && IsNormalRoadTile(cur_tile);
931  /* Road bits in the wrong direction. */
932  RoadBits rb = IsNormalRoadTile(cur_tile) ? GetAllRoadBits(cur_tile) : ROAD_NONE;
933  if (build_over_road && (rb & (axis == AXIS_X ? ROAD_Y : ROAD_X)) != 0) {
934  /* Someone was pedantic and *NEEDED* three fracking different error messages. */
935  switch (CountBits(rb)) {
936  case 1:
937  return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION);
938 
939  case 2:
940  if (rb == ROAD_X || rb == ROAD_Y) return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION);
941  return_cmd_error(STR_ERROR_DRIVE_THROUGH_CORNER);
942 
943  default: // 3 or 4
944  return_cmd_error(STR_ERROR_DRIVE_THROUGH_JUNCTION);
945  }
946  }
947 
948  RoadTypes cur_rts = IsNormalRoadTile(cur_tile) ? GetRoadTypes(cur_tile) : ROADTYPES_NONE;
949  uint num_roadbits = 0;
950  if (build_over_road) {
951  /* There is a road, check if we can build road+tram stop over it. */
952  if (HasBit(cur_rts, ROADTYPE_ROAD)) {
953  Owner road_owner = GetRoadOwner(cur_tile, ROADTYPE_ROAD);
954  if (road_owner == OWNER_TOWN) {
955  if (!_settings_game.construction.road_stop_on_town_road) return_cmd_error(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD);
957  CommandCost ret = CheckOwnership(road_owner);
958  if (ret.Failed()) return ret;
959  }
960  num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_ROAD));
961  }
962 
963  /* There is a tram, check if we can build road+tram stop over it. */
964  if (HasBit(cur_rts, ROADTYPE_TRAM)) {
965  Owner tram_owner = GetRoadOwner(cur_tile, ROADTYPE_TRAM);
966  if (Company::IsValidID(tram_owner) &&
968  /* Disallow breaking end-of-line of someone else
969  * so trams can still reverse on this tile. */
971  CommandCost ret = CheckOwnership(tram_owner);
972  if (ret.Failed()) return ret;
973  }
974  num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_TRAM));
975  }
976 
977  /* Take into account existing roadbits. */
978  rts |= cur_rts;
979  } else {
980  ret = DoCommand(cur_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
981  if (ret.Failed()) return ret;
982  cost.AddCost(ret);
983  }
984 
985  uint roadbits_to_build = CountBits(rts) * 2 - num_roadbits;
986  cost.AddCost(_price[PR_BUILD_ROAD] * roadbits_to_build);
987  }
988  }
989 
990  return cost;
991 }
992 
1001 {
1002  TileArea cur_ta = st->train_station;
1003 
1004  /* determine new size of train station region.. */
1005  int x = min(TileX(cur_ta.tile), TileX(new_ta.tile));
1006  int y = min(TileY(cur_ta.tile), TileY(new_ta.tile));
1007  new_ta.w = max(TileX(cur_ta.tile) + cur_ta.w, TileX(new_ta.tile) + new_ta.w) - x;
1008  new_ta.h = max(TileY(cur_ta.tile) + cur_ta.h, TileY(new_ta.tile) + new_ta.h) - y;
1009  new_ta.tile = TileXY(x, y);
1010 
1011  /* make sure the final size is not too big. */
1013  return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
1014  }
1015 
1016  return CommandCost();
1017 }
1018 
1019 static inline byte *CreateSingle(byte *layout, int n)
1020 {
1021  int i = n;
1022  do *layout++ = 0; while (--i);
1023  layout[((n - 1) >> 1) - n] = 2;
1024  return layout;
1025 }
1026 
1027 static inline byte *CreateMulti(byte *layout, int n, byte b)
1028 {
1029  int i = n;
1030  do *layout++ = b; while (--i);
1031  if (n > 4) {
1032  layout[0 - n] = 0;
1033  layout[n - 1 - n] = 0;
1034  }
1035  return layout;
1036 }
1037 
1045 void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec)
1046 {
1047  if (statspec != NULL && statspec->lengths >= plat_len &&
1048  statspec->platforms[plat_len - 1] >= numtracks &&
1049  statspec->layouts[plat_len - 1][numtracks - 1]) {
1050  /* Custom layout defined, follow it. */
1051  memcpy(layout, statspec->layouts[plat_len - 1][numtracks - 1],
1052  plat_len * numtracks);
1053  return;
1054  }
1055 
1056  if (plat_len == 1) {
1057  CreateSingle(layout, numtracks);
1058  } else {
1059  if (numtracks & 1) layout = CreateSingle(layout, plat_len);
1060  numtracks >>= 1;
1061 
1062  while (--numtracks >= 0) {
1063  layout = CreateMulti(layout, plat_len, 4);
1064  layout = CreateMulti(layout, plat_len, 6);
1065  }
1066  }
1067 }
1068 
1080 template <class T, StringID error_message>
1081 CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st)
1082 {
1083  assert(*st == NULL);
1084  bool check_surrounding = true;
1085 
1087  if (existing_station != INVALID_STATION) {
1088  if (adjacent && existing_station != station_to_join) {
1089  /* You can't build an adjacent station over the top of one that
1090  * already exists. */
1091  return_cmd_error(error_message);
1092  } else {
1093  /* Extend the current station, and don't check whether it will
1094  * be near any other stations. */
1095  *st = T::GetIfValid(existing_station);
1096  check_surrounding = (*st == NULL);
1097  }
1098  } else {
1099  /* There's no station here. Don't check the tiles surrounding this
1100  * one if the company wanted to build an adjacent station. */
1101  if (adjacent) check_surrounding = false;
1102  }
1103  }
1104 
1105  if (check_surrounding) {
1106  /* Make sure there are no similar stations around us. */
1107  CommandCost ret = GetStationAround(ta, existing_station, st);
1108  if (ret.Failed()) return ret;
1109  }
1110 
1111  /* Distant join */
1112  if (*st == NULL && station_to_join != INVALID_STATION) *st = T::GetIfValid(station_to_join);
1113 
1114  return CommandCost();
1115 }
1116 
1126 static CommandCost FindJoiningStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
1127 {
1128  return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST>(existing_station, station_to_join, adjacent, ta, st);
1129 }
1130 
1140 CommandCost FindJoiningWaypoint(StationID existing_waypoint, StationID waypoint_to_join, bool adjacent, TileArea ta, Waypoint **wp)
1141 {
1142  return FindJoiningBaseStation<Waypoint, STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST>(existing_waypoint, waypoint_to_join, adjacent, ta, wp);
1143 }
1144 
1150 {
1153  v = v->Last();
1155 }
1156 
1162 {
1164  TryPathReserve(v, true, true);
1165  v = v->Last();
1167 }
1168 
1186 CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1187 {
1188  /* Unpack parameters */
1189  RailType rt = Extract<RailType, 0, 4>(p1);
1190  Axis axis = Extract<Axis, 4, 1>(p1);
1191  byte numtracks = GB(p1, 8, 8);
1192  byte plat_len = GB(p1, 16, 8);
1193  bool adjacent = HasBit(p1, 24);
1194 
1195  StationClassID spec_class = Extract<StationClassID, 0, 8>(p2);
1196  byte spec_index = GB(p2, 8, 8);
1197  StationID station_to_join = GB(p2, 16, 16);
1198 
1199  /* Does the authority allow this? */
1200  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile_org, flags);
1201  if (ret.Failed()) return ret;
1202 
1203  if (!ValParamRailtype(rt)) return CMD_ERROR;
1204 
1205  /* Check if the given station class is valid */
1206  if ((uint)spec_class >= StationClass::GetClassCount() || spec_class == STAT_CLASS_WAYP) return CMD_ERROR;
1207  if (spec_index >= StationClass::Get(spec_class)->GetSpecCount()) return CMD_ERROR;
1208  if (plat_len == 0 || numtracks == 0) return CMD_ERROR;
1209 
1210  int w_org, h_org;
1211  if (axis == AXIS_X) {
1212  w_org = plat_len;
1213  h_org = numtracks;
1214  } else {
1215  h_org = plat_len;
1216  w_org = numtracks;
1217  }
1218 
1219  bool reuse = (station_to_join != NEW_STATION);
1220  if (!reuse) station_to_join = INVALID_STATION;
1221  bool distant_join = (station_to_join != INVALID_STATION);
1222 
1223  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
1224 
1226 
1227  /* these values are those that will be stored in train_tile and station_platforms */
1228  TileArea new_location(tile_org, w_org, h_org);
1229 
1230  /* Make sure the area below consists of clear tiles. (OR tiles belonging to a certain rail station) */
1231  StationID est = INVALID_STATION;
1232  SmallVector<Train *, 4> affected_vehicles;
1233  /* Clear the land below the station. */
1234  CommandCost cost = CheckFlatLandRailStation(new_location, flags, axis, &est, rt, affected_vehicles, spec_class, spec_index, plat_len, numtracks);
1235  if (cost.Failed()) return cost;
1236  /* Add construction expenses. */
1237  cost.AddCost((numtracks * _price[PR_BUILD_STATION_RAIL] + _price[PR_BUILD_STATION_RAIL_LENGTH]) * plat_len);
1238  cost.AddCost(numtracks * plat_len * RailBuildCost(rt));
1239 
1240  Station *st = NULL;
1241  ret = FindJoiningStation(est, station_to_join, adjacent, new_location, &st);
1242  if (ret.Failed()) return ret;
1243 
1244  ret = BuildStationPart(&st, flags, reuse, new_location, STATIONNAMING_RAIL);
1245  if (ret.Failed()) return ret;
1246 
1247  if (st != NULL && st->train_station.tile != INVALID_TILE) {
1248  CommandCost ret = CanExpandRailStation(st, new_location, axis);
1249  if (ret.Failed()) return ret;
1250  }
1251 
1252  /* Check if we can allocate a custom stationspec to this station */
1253  const StationSpec *statspec = StationClass::Get(spec_class)->GetSpec(spec_index);
1254  int specindex = AllocateSpecToStation(statspec, st, (flags & DC_EXEC) != 0);
1255  if (specindex == -1) return_cmd_error(STR_ERROR_TOO_MANY_STATION_SPECS);
1256 
1257  if (statspec != NULL) {
1258  /* Perform NewStation checks */
1259 
1260  /* Check if the station size is permitted */
1261  if (HasBit(statspec->disallowed_platforms, min(numtracks - 1, 7)) || HasBit(statspec->disallowed_lengths, min(plat_len - 1, 7))) {
1262  return CMD_ERROR;
1263  }
1264 
1265  /* Check if the station is buildable */
1266  if (HasBit(statspec->callback_mask, CBM_STATION_AVAIL)) {
1267  uint16 cb_res = GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE);
1268  if (cb_res != CALLBACK_FAILED && !Convert8bitBooleanCallback(statspec->grf_prop.grffile, CBID_STATION_AVAILABILITY, cb_res)) return CMD_ERROR;
1269  }
1270  }
1271 
1272  if (flags & DC_EXEC) {
1273  TileIndexDiff tile_delta;
1274  byte *layout_ptr;
1275  byte numtracks_orig;
1276  Track track;
1277 
1278  st->train_station = new_location;
1279  st->AddFacility(FACIL_TRAIN, new_location.tile);
1280 
1281  st->rect.BeforeAddRect(tile_org, w_org, h_org, StationRect::ADD_TRY);
1282 
1283  if (statspec != NULL) {
1284  /* Include this station spec's animation trigger bitmask
1285  * in the station's cached copy. */
1286  st->cached_anim_triggers |= statspec->animation.triggers;
1287  }
1288 
1289  tile_delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
1290  track = AxisToTrack(axis);
1291 
1292  layout_ptr = AllocaM(byte, numtracks * plat_len);
1293  GetStationLayout(layout_ptr, numtracks, plat_len, statspec);
1294 
1295  numtracks_orig = numtracks;
1296 
1297  Company *c = Company::Get(st->owner);
1298  TileIndex tile_track = tile_org;
1299  do {
1300  TileIndex tile = tile_track;
1301  int w = plat_len;
1302  do {
1303  byte layout = *layout_ptr++;
1304  if (IsRailStationTile(tile) && HasStationReservation(tile)) {
1305  /* Check for trains having a reservation for this tile. */
1307  if (v != NULL) {
1308  *affected_vehicles.Append() = v;
1310  }
1311  }
1312 
1313  /* Railtype can change when overbuilding. */
1314  if (IsRailStationTile(tile)) {
1315  if (!IsStationTileBlocked(tile)) c->infrastructure.rail[GetRailType(tile)]--;
1316  c->infrastructure.station--;
1317  }
1318 
1319  /* Remove animation if overbuilding */
1320  DeleteAnimatedTile(tile);
1321  byte old_specindex = HasStationTileRail(tile) ? GetCustomStationSpecIndex(tile) : 0;
1322  MakeRailStation(tile, st->owner, st->index, axis, layout & ~1, rt);
1323  /* Free the spec if we overbuild something */
1324  DeallocateSpecFromStation(st, old_specindex);
1325 
1326  SetCustomStationSpecIndex(tile, specindex);
1327  SetStationTileRandomBits(tile, GB(Random(), 0, 4));
1328  SetAnimationFrame(tile, 0);
1329 
1330  if (!IsStationTileBlocked(tile)) c->infrastructure.rail[rt]++;
1331  c->infrastructure.station++;
1332 
1333  if (statspec != NULL) {
1334  /* Use a fixed axis for GetPlatformInfo as our platforms / numtracks are always the right way around */
1335  uint32 platinfo = GetPlatformInfo(AXIS_X, GetStationGfx(tile), plat_len, numtracks_orig, plat_len - w, numtracks_orig - numtracks, false);
1336 
1337  /* As the station is not yet completely finished, the station does not yet exist. */
1338  uint16 callback = GetStationCallback(CBID_STATION_TILE_LAYOUT, platinfo, 0, statspec, NULL, tile);
1339  if (callback != CALLBACK_FAILED) {
1340  if (callback < 8) {
1341  SetStationGfx(tile, (callback & ~1) + axis);
1342  } else {
1344  }
1345  }
1346 
1347  /* Trigger station animation -- after building? */
1348  TriggerStationAnimation(st, tile, SAT_BUILT);
1349  }
1350 
1351  tile += tile_delta;
1352  } while (--w);
1353  AddTrackToSignalBuffer(tile_track, track, _current_company);
1354  YapfNotifyTrackLayoutChange(tile_track, track);
1355  tile_track += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta
1356  } while (--numtracks);
1357 
1358  for (uint i = 0; i < affected_vehicles.Length(); ++i) {
1359  /* Restore reservations of trains. */
1360  RestoreTrainReservation(affected_vehicles[i]);
1361  }
1362 
1363  /* Check whether we need to expand the reservation of trains already on the station. */
1364  TileArea update_reservation_area;
1365  if (axis == AXIS_X) {
1366  update_reservation_area = TileArea(tile_org, 1, numtracks_orig);
1367  } else {
1368  update_reservation_area = TileArea(tile_org, numtracks_orig, 1);
1369  }
1370 
1371  TILE_AREA_LOOP(tile, update_reservation_area) {
1372  /* Don't even try to make eye candy parts reserved. */
1373  if (IsStationTileBlocked(tile)) continue;
1374 
1375  DiagDirection dir = AxisToDiagDir(axis);
1376  TileIndexDiff tile_offset = TileOffsByDiagDir(dir);
1377  TileIndex platform_begin = tile;
1378  TileIndex platform_end = tile;
1379 
1380  /* We can only account for tiles that are reachable from this tile, so ignore primarily blocked tiles while finding the platform begin and end. */
1381  for (TileIndex next_tile = platform_begin - tile_offset; IsCompatibleTrainStationTile(next_tile, platform_begin); next_tile -= tile_offset) {
1382  platform_begin = next_tile;
1383  }
1384  for (TileIndex next_tile = platform_end + tile_offset; IsCompatibleTrainStationTile(next_tile, platform_end); next_tile += tile_offset) {
1385  platform_end = next_tile;
1386  }
1387 
1388  /* If there is at least on reservation on the platform, we reserve the whole platform. */
1389  bool reservation = false;
1390  for (TileIndex t = platform_begin; !reservation && t <= platform_end; t += tile_offset) {
1391  reservation = HasStationReservation(t);
1392  }
1393 
1394  if (reservation) {
1395  SetRailStationPlatformReservation(platform_begin, dir, true);
1396  }
1397  }
1398 
1399  st->MarkTilesDirty(false);
1400  st->UpdateVirtCoord();
1401  UpdateStationAcceptance(st, false);
1407  }
1408 
1409  return cost;
1410 }
1411 
1412 static void MakeRailStationAreaSmaller(BaseStation *st)
1413 {
1414  TileArea ta = st->train_station;
1415 
1416 restart:
1417 
1418  /* too small? */
1419  if (ta.w != 0 && ta.h != 0) {
1420  /* check the left side, x = constant, y changes */
1421  for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(0, i));) {
1422  /* the left side is unused? */
1423  if (++i == ta.h) {
1424  ta.tile += TileDiffXY(1, 0);
1425  ta.w--;
1426  goto restart;
1427  }
1428  }
1429 
1430  /* check the right side, x = constant, y changes */
1431  for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(ta.w - 1, i));) {
1432  /* the right side is unused? */
1433  if (++i == ta.h) {
1434  ta.w--;
1435  goto restart;
1436  }
1437  }
1438 
1439  /* check the upper side, y = constant, x changes */
1440  for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(i, 0));) {
1441  /* the left side is unused? */
1442  if (++i == ta.w) {
1443  ta.tile += TileDiffXY(0, 1);
1444  ta.h--;
1445  goto restart;
1446  }
1447  }
1448 
1449  /* check the lower side, y = constant, x changes */
1450  for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(i, ta.h - 1));) {
1451  /* the left side is unused? */
1452  if (++i == ta.w) {
1453  ta.h--;
1454  goto restart;
1455  }
1456  }
1457  } else {
1458  ta.Clear();
1459  }
1460 
1461  st->train_station = ta;
1462 }
1463 
1474 template <class T>
1475 CommandCost RemoveFromRailBaseStation(TileArea ta, SmallVector<T *, 4> &affected_stations, DoCommandFlag flags, Money removal_cost, bool keep_rail)
1476 {
1477  /* Count of the number of tiles removed */
1478  int quantity = 0;
1479  CommandCost total_cost(EXPENSES_CONSTRUCTION);
1480  /* Accumulator for the errors seen during clearing. If no errors happen,
1481  * and the quantity is 0 there is no station. Otherwise it will be one
1482  * of the other error that got accumulated. */
1484 
1485  /* Do the action for every tile into the area */
1486  TILE_AREA_LOOP(tile, ta) {
1487  /* Make sure the specified tile is a rail station */
1488  if (!HasStationTileRail(tile)) continue;
1489 
1490  /* If there is a vehicle on ground, do not allow to remove (flood) the tile */
1492  error.AddCost(ret);
1493  if (ret.Failed()) continue;
1494 
1495  /* Check ownership of station */
1496  T *st = T::GetByTile(tile);
1497  if (st == NULL) continue;
1498 
1499  if (_current_company != OWNER_WATER) {
1500  CommandCost ret = CheckOwnership(st->owner);
1501  error.AddCost(ret);
1502  if (ret.Failed()) continue;
1503  }
1504 
1505  /* If we reached here, the tile is valid so increase the quantity of tiles we will remove */
1506  quantity++;
1507 
1508  if (keep_rail || IsStationTileBlocked(tile)) {
1509  /* Don't refund the 'steel' of the track when we keep the
1510  * rail, or when the tile didn't have any rail at all. */
1511  total_cost.AddCost(-_price[PR_CLEAR_RAIL]);
1512  }
1513 
1514  if (flags & DC_EXEC) {
1515  /* read variables before the station tile is removed */
1516  uint specindex = GetCustomStationSpecIndex(tile);
1517  Track track = GetRailStationTrack(tile);
1518  Owner owner = GetTileOwner(tile);
1519  RailType rt = GetRailType(tile);
1520  Train *v = NULL;
1521 
1522  if (HasStationReservation(tile)) {
1523  v = GetTrainForReservation(tile, track);
1524  if (v != NULL) FreeTrainReservation(v);
1525  }
1526 
1527  bool build_rail = keep_rail && !IsStationTileBlocked(tile);
1528  if (!build_rail && !IsStationTileBlocked(tile)) Company::Get(owner)->infrastructure.rail[rt]--;
1529 
1530  DoClearSquare(tile);
1531  DeleteNewGRFInspectWindow(GSF_STATIONS, tile);
1532  if (build_rail) MakeRailNormal(tile, owner, TrackToTrackBits(track), rt);
1533  Company::Get(owner)->infrastructure.station--;
1535 
1536  st->rect.AfterRemoveTile(st, tile);
1537  AddTrackToSignalBuffer(tile, track, owner);
1538  YapfNotifyTrackLayoutChange(tile, track);
1539 
1540  DeallocateSpecFromStation(st, specindex);
1541 
1542  affected_stations.Include(st);
1543 
1544  if (v != NULL) RestoreTrainReservation(v);
1545  }
1546  }
1547 
1548  if (quantity == 0) return error.Failed() ? error : CommandCost(STR_ERROR_THERE_IS_NO_STATION);
1549 
1550  for (T **stp = affected_stations.Begin(); stp != affected_stations.End(); stp++) {
1551  T *st = *stp;
1552 
1553  /* now we need to make the "spanned" area of the railway station smaller
1554  * if we deleted something at the edges.
1555  * we also need to adjust train_tile. */
1556  MakeRailStationAreaSmaller(st);
1557  UpdateStationSignCoord(st);
1558 
1559  /* if we deleted the whole station, delete the train facility. */
1560  if (st->train_station.tile == INVALID_TILE) {
1561  st->facilities &= ~FACIL_TRAIN;
1563  st->UpdateVirtCoord();
1565  }
1566  }
1567 
1568  total_cost.AddCost(quantity * removal_cost);
1569  return total_cost;
1570 }
1571 
1583 CommandCost CmdRemoveFromRailStation(TileIndex start, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1584 {
1585  TileIndex end = p1 == 0 ? start : p1;
1586  if (start >= MapSize() || end >= MapSize()) return CMD_ERROR;
1587 
1588  TileArea ta(start, end);
1589  SmallVector<Station *, 4> affected_stations;
1590 
1591  CommandCost ret = RemoveFromRailBaseStation(ta, affected_stations, flags, _price[PR_CLEAR_STATION_RAIL], HasBit(p2, 0));
1592  if (ret.Failed()) return ret;
1593 
1594  /* Do all station specific functions here. */
1595  for (Station **stp = affected_stations.Begin(); stp != affected_stations.End(); stp++) {
1596  Station *st = *stp;
1597 
1599  st->MarkTilesDirty(false);
1601  }
1602 
1603  /* Now apply the rail cost to the number that we deleted */
1604  return ret;
1605 }
1606 
1618 CommandCost CmdRemoveFromRailWaypoint(TileIndex start, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1619 {
1620  TileIndex end = p1 == 0 ? start : p1;
1621  if (start >= MapSize() || end >= MapSize()) return CMD_ERROR;
1622 
1623  TileArea ta(start, end);
1624  SmallVector<Waypoint *, 4> affected_stations;
1625 
1626  return RemoveFromRailBaseStation(ta, affected_stations, flags, _price[PR_CLEAR_WAYPOINT_RAIL], HasBit(p2, 0));
1627 }
1628 
1629 
1638 template <class T>
1640 {
1641  /* Current company owns the station? */
1642  if (_current_company != OWNER_WATER) {
1643  CommandCost ret = CheckOwnership(st->owner);
1644  if (ret.Failed()) return ret;
1645  }
1646 
1647  /* determine width and height of platforms */
1648  TileArea ta = st->train_station;
1649 
1650  assert(ta.w != 0 && ta.h != 0);
1651 
1653  /* clear all areas of the station */
1654  TILE_AREA_LOOP(tile, ta) {
1655  /* only remove tiles that are actually train station tiles */
1656  if (st->TileBelongsToRailStation(tile)) {
1657  SmallVector<T*, 4> affected_stations; // dummy
1658  CommandCost ret = RemoveFromRailBaseStation(TileArea(tile, 1, 1), affected_stations, flags, removal_cost, false);
1659  if (ret.Failed()) return ret;
1660  cost.AddCost(ret);
1661  }
1662  }
1663 
1664  return cost;
1665 }
1666 
1674 {
1675  /* if there is flooding, remove platforms tile by tile */
1676  if (_current_company == OWNER_WATER) {
1677  return DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAIL_STATION);
1678  }
1679 
1680  Station *st = Station::GetByTile(tile);
1681  CommandCost cost = RemoveRailStation(st, flags, _price[PR_CLEAR_STATION_RAIL]);
1682 
1683  if (flags & DC_EXEC) st->RecomputeIndustriesNear();
1684 
1685  return cost;
1686 }
1687 
1695 {
1696  /* if there is flooding, remove waypoints tile by tile */
1697  if (_current_company == OWNER_WATER) {
1698  return DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAIL_WAYPOINT);
1699  }
1700 
1701  return RemoveRailStation(Waypoint::GetByTile(tile), flags, _price[PR_CLEAR_WAYPOINT_RAIL]);
1702 }
1703 
1704 
1710 static RoadStop **FindRoadStopSpot(bool truck_station, Station *st)
1711 {
1712  RoadStop **primary_stop = (truck_station) ? &st->truck_stops : &st->bus_stops;
1713 
1714  if (*primary_stop == NULL) {
1715  /* we have no roadstop of the type yet, so write a "primary stop" */
1716  return primary_stop;
1717  } else {
1718  /* there are stops already, so append to the end of the list */
1719  RoadStop *stop = *primary_stop;
1720  while (stop->next != NULL) stop = stop->next;
1721  return &stop->next;
1722  }
1723 }
1724 
1726 
1736 static CommandCost FindJoiningRoadStop(StationID existing_stop, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
1737 {
1738  return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST>(existing_stop, station_to_join, adjacent, ta, st);
1739 }
1740 
1757 CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1758 {
1759  bool type = HasBit(p2, 0);
1760  bool is_drive_through = HasBit(p2, 1);
1761  RoadTypes rts = Extract<RoadTypes, 2, 2>(p2);
1762  StationID station_to_join = GB(p2, 16, 16);
1763  bool reuse = (station_to_join != NEW_STATION);
1764  if (!reuse) station_to_join = INVALID_STATION;
1765  bool distant_join = (station_to_join != INVALID_STATION);
1766 
1767  uint8 width = (uint8)GB(p1, 0, 8);
1768  uint8 lenght = (uint8)GB(p1, 8, 8);
1769 
1770  /* Check if the requested road stop is too big */
1771  if (width > _settings_game.station.station_spread || lenght > _settings_game.station.station_spread) return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
1772  /* Check for incorrect width / length. */
1773  if (width == 0 || lenght == 0) return CMD_ERROR;
1774  /* Check if the first tile and the last tile are valid */
1775  if (!IsValidTile(tile) || TileAddWrap(tile, width - 1, lenght - 1) == INVALID_TILE) return CMD_ERROR;
1776 
1777  TileArea roadstop_area(tile, width, lenght);
1778 
1779  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
1780 
1781  if (!HasExactlyOneBit(rts) || !HasRoadTypesAvail(_current_company, rts)) return CMD_ERROR;
1782 
1783  /* Trams only have drive through stops */
1784  if (!is_drive_through && HasBit(rts, ROADTYPE_TRAM)) return CMD_ERROR;
1785 
1786  DiagDirection ddir;
1787  Axis axis;
1788  if (is_drive_through) {
1789  /* By definition axis is valid, due to there being 2 axes and reading 1 bit. */
1790  axis = Extract<Axis, 6, 1>(p2);
1791  ddir = AxisToDiagDir(axis);
1792  } else {
1793  /* By definition ddir is valid, due to there being 4 diagonal directions and reading 2 bits. */
1794  ddir = Extract<DiagDirection, 6, 2>(p2);
1795  axis = DiagDirToAxis(ddir);
1796  }
1797 
1798  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags);
1799  if (ret.Failed()) return ret;
1800 
1801  /* Total road stop cost. */
1802  CommandCost cost(EXPENSES_CONSTRUCTION, roadstop_area.w * roadstop_area.h * _price[type ? PR_BUILD_STATION_TRUCK : PR_BUILD_STATION_BUS]);
1803  StationID est = INVALID_STATION;
1804  ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 5 << axis : 1 << ddir, is_drive_through, type, axis, &est, rts);
1805  if (ret.Failed()) return ret;
1806  cost.AddCost(ret);
1807 
1808  Station *st = NULL;
1809  ret = FindJoiningRoadStop(est, station_to_join, HasBit(p2, 5), roadstop_area, &st);
1810  if (ret.Failed()) return ret;
1811 
1812  /* Check if this number of road stops can be allocated. */
1813  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);
1814 
1815  ret = BuildStationPart(&st, flags, reuse, roadstop_area, STATIONNAMING_ROAD);
1816  if (ret.Failed()) return ret;
1817 
1818  if (flags & DC_EXEC) {
1819  /* Check every tile in the area. */
1820  TILE_AREA_LOOP(cur_tile, roadstop_area) {
1821  RoadTypes cur_rts = GetRoadTypes(cur_tile);
1822  Owner road_owner = HasBit(cur_rts, ROADTYPE_ROAD) ? GetRoadOwner(cur_tile, ROADTYPE_ROAD) : _current_company;
1823  Owner tram_owner = HasBit(cur_rts, ROADTYPE_TRAM) ? GetRoadOwner(cur_tile, ROADTYPE_TRAM) : _current_company;
1824 
1825  if (IsTileType(cur_tile, MP_STATION) && IsRoadStop(cur_tile)) {
1826  RemoveRoadStop(cur_tile, flags);
1827  }
1828 
1829  RoadStop *road_stop = new RoadStop(cur_tile);
1830  /* Insert into linked list of RoadStops. */
1831  RoadStop **currstop = FindRoadStopSpot(type, st);
1832  *currstop = road_stop;
1833 
1834  if (type) {
1835  st->truck_station.Add(cur_tile);
1836  } else {
1837  st->bus_station.Add(cur_tile);
1838  }
1839 
1840  /* Initialize an empty station. */
1841  st->AddFacility((type) ? FACIL_TRUCK_STOP : FACIL_BUS_STOP, cur_tile);
1842 
1843  st->rect.BeforeAddTile(cur_tile, StationRect::ADD_TRY);
1844 
1845  RoadStopType rs_type = type ? ROADSTOP_TRUCK : ROADSTOP_BUS;
1846  if (is_drive_through) {
1847  /* Update company infrastructure counts. If the current tile is a normal
1848  * road tile, count only the new road bits needed to get a full diagonal road. */
1849  RoadType rt;
1850  FOR_EACH_SET_ROADTYPE(rt, cur_rts | rts) {
1851  Company *c = Company::GetIfValid(rt == ROADTYPE_ROAD ? road_owner : tram_owner);
1852  if (c != NULL) {
1853  c->infrastructure.road[rt] += 2 - (IsNormalRoadTile(cur_tile) && HasBit(cur_rts, rt) ? CountBits(GetRoadBits(cur_tile, rt)) : 0);
1855  }
1856  }
1857 
1858  MakeDriveThroughRoadStop(cur_tile, st->owner, road_owner, tram_owner, st->index, rs_type, rts | cur_rts, axis);
1859  road_stop->MakeDriveThrough();
1860  } else {
1861  /* Non-drive-through stop never overbuild and always count as two road bits. */
1862  Company::Get(st->owner)->infrastructure.road[FIND_FIRST_BIT(rts)] += 2;
1863  MakeRoadStop(cur_tile, st->owner, st->index, rs_type, rts, ddir);
1864  }
1865  Company::Get(st->owner)->infrastructure.station++;
1867 
1868  MarkTileDirtyByTile(cur_tile);
1869  }
1870  }
1871 
1872  if (st != NULL) {
1873  st->UpdateVirtCoord();
1874  UpdateStationAcceptance(st, false);
1879  }
1880  return cost;
1881 }
1882 
1883 
1884 static Vehicle *ClearRoadStopStatusEnum(Vehicle *v, void *)
1885 {
1886  if (v->type == VEH_ROAD) {
1887  /* Okay... we are a road vehicle on a drive through road stop.
1888  * But that road stop has just been removed, so we need to make
1889  * sure we are in a valid state... however, vehicles can also
1890  * turn on road stop tiles, so only clear the 'road stop' state
1891  * bits and only when the state was 'in road stop', otherwise
1892  * we'll end up clearing the turn around bits. */
1893  RoadVehicle *rv = RoadVehicle::From(v);
1895  }
1896 
1897  return NULL;
1898 }
1899 
1900 
1908 {
1909  Station *st = Station::GetByTile(tile);
1910 
1911  if (_current_company != OWNER_WATER) {
1912  CommandCost ret = CheckOwnership(st->owner);
1913  if (ret.Failed()) return ret;
1914  }
1915 
1916  bool is_truck = IsTruckStop(tile);
1917 
1918  RoadStop **primary_stop;
1919  RoadStop *cur_stop;
1920  if (is_truck) { // truck stop
1921  primary_stop = &st->truck_stops;
1922  cur_stop = RoadStop::GetByTile(tile, ROADSTOP_TRUCK);
1923  } else {
1924  primary_stop = &st->bus_stops;
1925  cur_stop = RoadStop::GetByTile(tile, ROADSTOP_BUS);
1926  }
1927 
1928  assert(cur_stop != NULL);
1929 
1930  /* don't do the check for drive-through road stops when company bankrupts */
1931  if (IsDriveThroughStopTile(tile) && (flags & DC_BANKRUPT)) {
1932  /* remove the 'going through road stop' status from all vehicles on that tile */
1933  if (flags & DC_EXEC) FindVehicleOnPos(tile, NULL, &ClearRoadStopStatusEnum);
1934  } else {
1936  if (ret.Failed()) return ret;
1937  }
1938 
1939  if (flags & DC_EXEC) {
1940  if (*primary_stop == cur_stop) {
1941  /* removed the first stop in the list */
1942  *primary_stop = cur_stop->next;
1943  /* removed the only stop? */
1944  if (*primary_stop == NULL) {
1945  st->facilities &= (is_truck ? ~FACIL_TRUCK_STOP : ~FACIL_BUS_STOP);
1946  }
1947  } else {
1948  /* tell the predecessor in the list to skip this stop */
1949  RoadStop *pred = *primary_stop;
1950  while (pred->next != cur_stop) pred = pred->next;
1951  pred->next = cur_stop->next;
1952  }
1953 
1954  /* Update company infrastructure counts. */
1955  RoadType rt;
1956  FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) {
1957  Company *c = Company::GetIfValid(GetRoadOwner(tile, rt));
1958  if (c != NULL) {
1959  c->infrastructure.road[rt] -= 2;
1961  }
1962  }
1963  Company::Get(st->owner)->infrastructure.station--;
1965 
1966  if (IsDriveThroughStopTile(tile)) {
1967  /* Clears the tile for us */
1968  cur_stop->ClearDriveThrough();
1969  } else {
1970  DoClearSquare(tile);
1971  }
1972 
1974  delete cur_stop;
1975 
1976  /* Make sure no vehicle is going to the old roadstop */
1977  RoadVehicle *v;
1978  FOR_ALL_ROADVEHICLES(v) {
1979  if (v->First() == v && v->current_order.IsType(OT_GOTO_STATION) &&
1980  v->dest_tile == tile) {
1982  }
1983  }
1984 
1985  st->rect.AfterRemoveTile(st, tile);
1986 
1987  st->UpdateVirtCoord();
1990 
1991  /* Update the tile area of the truck/bus stop */
1992  if (is_truck) {
1993  st->truck_station.Clear();
1994  for (const RoadStop *rs = st->truck_stops; rs != NULL; rs = rs->next) st->truck_station.Add(rs->xy);
1995  } else {
1996  st->bus_station.Clear();
1997  for (const RoadStop *rs = st->bus_stops; rs != NULL; rs = rs->next) st->bus_station.Add(rs->xy);
1998  }
1999  }
2000 
2001  return CommandCost(EXPENSES_CONSTRUCTION, _price[is_truck ? PR_CLEAR_STATION_TRUCK : PR_CLEAR_STATION_BUS]);
2002 }
2003 
2015 CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
2016 {
2017  uint8 width = (uint8)GB(p1, 0, 8);
2018  uint8 height = (uint8)GB(p1, 8, 8);
2019  bool keep_drive_through_roads = !HasBit(p2, 1);
2020 
2021  /* Check for incorrect width / height. */
2022  if (width == 0 || height == 0) return CMD_ERROR;
2023  /* Check if the first tile and the last tile are valid */
2024  if (!IsValidTile(tile) || TileAddWrap(tile, width - 1, height - 1) == INVALID_TILE) return CMD_ERROR;
2025  /* Bankrupting company is not supposed to remove roads, there may be road vehicles. */
2026  if (!keep_drive_through_roads && (flags & DC_BANKRUPT)) return CMD_ERROR;
2027 
2028  TileArea roadstop_area(tile, width, height);
2029 
2031  CommandCost last_error(STR_ERROR_THERE_IS_NO_STATION);
2032  bool had_success = false;
2033 
2034  TILE_AREA_LOOP(cur_tile, roadstop_area) {
2035  /* Make sure the specified tile is a road stop of the correct type */
2036  if (!IsTileType(cur_tile, MP_STATION) || !IsRoadStop(cur_tile) || (uint32)GetRoadStopType(cur_tile) != GB(p2, 0, 1)) continue;
2037 
2038  /* Save information on to-be-restored roads before the stop is removed. */
2039  RoadTypes rts = ROADTYPES_NONE;
2040  RoadBits road_bits = ROAD_NONE;
2041  Owner road_owner[] = { OWNER_NONE, OWNER_NONE };
2042  assert_compile(lengthof(road_owner) == ROADTYPE_END);
2043  if (IsDriveThroughStopTile(cur_tile)) {
2044  RoadType rt;
2045  FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(cur_tile)) {
2046  road_owner[rt] = GetRoadOwner(cur_tile, rt);
2047  /* If we don't want to preserve our roads then restore only roads of others. */
2048  if (keep_drive_through_roads || road_owner[rt] != _current_company) SetBit(rts, rt);
2049  }
2050  road_bits = AxisToRoadBits(DiagDirToAxis(GetRoadStopDir(cur_tile)));
2051  }
2052 
2053  CommandCost ret = RemoveRoadStop(cur_tile, flags);
2054  if (ret.Failed()) {
2055  last_error = ret;
2056  continue;
2057  }
2058  cost.AddCost(ret);
2059  had_success = true;
2060 
2061  /* Restore roads. */
2062  if ((flags & DC_EXEC) && rts != ROADTYPES_NONE) {
2063  MakeRoadNormal(cur_tile, road_bits, rts, ClosestTownFromTile(cur_tile, UINT_MAX)->index,
2064  road_owner[ROADTYPE_ROAD], road_owner[ROADTYPE_TRAM]);
2065 
2066  /* Update company infrastructure counts. */
2067  RoadType rt;
2068  FOR_EACH_SET_ROADTYPE(rt, rts) {
2069  Company *c = Company::GetIfValid(GetRoadOwner(cur_tile, rt));
2070  if (c != NULL) {
2071  c->infrastructure.road[rt] += CountBits(road_bits);
2073  }
2074  }
2075  }
2076  }
2077 
2078  return had_success ? cost : last_error;
2079 }
2080 
2088 {
2089  uint mindist = UINT_MAX;
2090 
2091  for (TileIndex cur_tile = it; cur_tile != INVALID_TILE; cur_tile = ++it) {
2092  mindist = min(mindist, DistanceManhattan(town_tile, cur_tile));
2093  }
2094 
2095  return mindist;
2096 }
2097 
2108 {
2109  /* 0 cannot be accounted, and 1 is the lowest that can be reduced from town.
2110  * So no need to go any further*/
2111  if (as->noise_level < 2) return as->noise_level;
2112 
2113  uint distance = GetMinimalAirportDistanceToTile(it, town_tile);
2114 
2115  /* The steps for measuring noise reduction are based on the "magical" (and arbitrary) 8 base distance
2116  * adding the town_council_tolerance 4 times, as a way to graduate, depending of the tolerance.
2117  * Basically, it says that the less tolerant a town is, the bigger the distance before
2118  * an actual decrease can be granted */
2119  uint8 town_tolerance_distance = 8 + (_settings_game.difficulty.town_council_tolerance * 4);
2120 
2121  /* now, we want to have the distance segmented using the distance judged bareable by town
2122  * This will give us the coefficient of reduction the distance provides. */
2123  uint noise_reduction = distance / town_tolerance_distance;
2124 
2125  /* If the noise reduction equals the airport noise itself, don't give it for free.
2126  * Otherwise, simply reduce the airport's level. */
2127  return noise_reduction >= as->noise_level ? 1 : as->noise_level - noise_reduction;
2128 }
2129 
2138 {
2139  Town *t, *nearest = NULL;
2140  uint add = as->size_x + as->size_y - 2; // GetMinimalAirportDistanceToTile can differ from DistanceManhattan by this much
2141  uint mindist = UINT_MAX - add; // prevent overflow
2142  FOR_ALL_TOWNS(t) {
2143  if (DistanceManhattan(t->xy, it) < mindist + add) { // avoid calling GetMinimalAirportDistanceToTile too often
2144  TileIterator *copy = it.Clone();
2145  uint dist = GetMinimalAirportDistanceToTile(*copy, t->xy);
2146  delete copy;
2147  if (dist < mindist) {
2148  nearest = t;
2149  mindist = dist;
2150  }
2151  }
2152  }
2153 
2154  return nearest;
2155 }
2156 
2157 
2160 {
2161  Town *t;
2162  const Station *st;
2163 
2164  FOR_ALL_TOWNS(t) t->noise_reached = 0;
2165 
2166  FOR_ALL_STATIONS(st) {
2167  if (st->airport.tile != INVALID_TILE && st->airport.type != AT_OILRIG) {
2168  const AirportSpec *as = st->airport.GetSpec();
2169  AirportTileIterator it(st);
2170  Town *nearest = AirportGetNearestTown(as, it);
2171  nearest->noise_reached += GetAirportNoiseLevelForTown(as, it, nearest->xy);
2172  }
2173  }
2174 }
2175 
2189 CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
2190 {
2191  StationID station_to_join = GB(p2, 16, 16);
2192  bool reuse = (station_to_join != NEW_STATION);
2193  if (!reuse) station_to_join = INVALID_STATION;
2194  bool distant_join = (station_to_join != INVALID_STATION);
2195  byte airport_type = GB(p1, 0, 8);
2196  byte layout = GB(p1, 8, 8);
2197 
2198  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
2199 
2200  if (airport_type >= NUM_AIRPORTS) return CMD_ERROR;
2201 
2202  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags);
2203  if (ret.Failed()) return ret;
2204 
2205  /* Check if a valid, buildable airport was chosen for construction */
2206  const AirportSpec *as = AirportSpec::Get(airport_type);
2207  if (!as->IsAvailable() || layout >= as->num_table) return CMD_ERROR;
2208 
2209  Direction rotation = as->rotation[layout];
2210  int w = as->size_x;
2211  int h = as->size_y;
2212  if (rotation == DIR_E || rotation == DIR_W) Swap(w, h);
2213  TileArea airport_area = TileArea(tile, w, h);
2214 
2216  return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
2217  }
2218 
2219  CommandCost cost = CheckFlatLand(airport_area, flags);
2220  if (cost.Failed()) return cost;
2221 
2222  /* The noise level is the noise from the airport and reduce it to account for the distance to the town center. */
2223  AirportTileTableIterator iter(as->table[layout], tile);
2224  Town *nearest = AirportGetNearestTown(as, iter);
2225  uint newnoise_level = GetAirportNoiseLevelForTown(as, iter, nearest->xy);
2226 
2227  /* Check if local auth would allow a new airport */
2228  StringID authority_refuse_message = STR_NULL;
2229  Town *authority_refuse_town = NULL;
2230 
2232  /* do not allow to build a new airport if this raise the town noise over the maximum allowed by town */
2233  if ((nearest->noise_reached + newnoise_level) > nearest->MaxTownNoise()) {
2234  authority_refuse_message = STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE;
2235  authority_refuse_town = nearest;
2236  }
2237  } else {
2238  Town *t = ClosestTownFromTile(tile, UINT_MAX);
2239  uint num = 0;
2240  const Station *st;
2241  FOR_ALL_STATIONS(st) {
2242  if (st->town == t && (st->facilities & FACIL_AIRPORT) && st->airport.type != AT_OILRIG) num++;
2243  }
2244  if (num >= 2) {
2245  authority_refuse_message = STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT;
2246  authority_refuse_town = t;
2247  }
2248  }
2249 
2250  if (authority_refuse_message != STR_NULL) {
2251  SetDParam(0, authority_refuse_town->index);
2252  return_cmd_error(authority_refuse_message);
2253  }
2254 
2255  Station *st = NULL;
2256  ret = FindJoiningStation(INVALID_STATION, station_to_join, HasBit(p2, 0), airport_area, &st);
2257  if (ret.Failed()) return ret;
2258 
2259  /* Distant join */
2260  if (st == NULL && distant_join) st = Station::GetIfValid(station_to_join);
2261 
2262  ret = BuildStationPart(&st, flags, reuse, airport_area, (GetAirport(airport_type)->flags & AirportFTAClass::AIRPLANES) ? STATIONNAMING_AIRPORT : STATIONNAMING_HELIPORT);
2263  if (ret.Failed()) return ret;
2264 
2265  if (st != NULL && st->airport.tile != INVALID_TILE) {
2266  return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT);
2267  }
2268 
2269  for (AirportTileTableIterator iter(as->table[layout], tile); iter != INVALID_TILE; ++iter) {
2270  cost.AddCost(_price[PR_BUILD_STATION_AIRPORT]);
2271  }
2272 
2273  if (flags & DC_EXEC) {
2274  /* Always add the noise, so there will be no need to recalculate when option toggles */
2275  nearest->noise_reached += newnoise_level;
2276 
2277  st->AddFacility(FACIL_AIRPORT, tile);
2278  st->airport.type = airport_type;
2279  st->airport.layout = layout;
2280  st->airport.flags = 0;
2281  st->airport.rotation = rotation;
2282 
2283  st->rect.BeforeAddRect(tile, w, h, StationRect::ADD_TRY);
2284 
2285  for (AirportTileTableIterator iter(as->table[layout], tile); iter != INVALID_TILE; ++iter) {
2286  MakeAirport(iter, st->owner, st->index, iter.GetStationGfx(), WATER_CLASS_INVALID);
2287  SetStationTileRandomBits(iter, GB(Random(), 0, 4));
2288  st->airport.Add(iter);
2289 
2291  }
2292 
2293  /* Only call the animation trigger after all tiles have been built */
2294  for (AirportTileTableIterator iter(as->table[layout], tile); iter != INVALID_TILE; ++iter) {
2295  AirportTileAnimationTrigger(st, iter, AAT_BUILT);
2296  }
2297 
2299 
2300  Company::Get(st->owner)->infrastructure.airport++;
2302 
2303  st->UpdateVirtCoord();
2304  UpdateStationAcceptance(st, false);
2309 
2312  }
2313  }
2314 
2315  return cost;
2316 }
2317 
2325 {
2326  Station *st = Station::GetByTile(tile);
2327 
2328  if (_current_company != OWNER_WATER) {
2329  CommandCost ret = CheckOwnership(st->owner);
2330  if (ret.Failed()) return ret;
2331  }
2332 
2333  tile = st->airport.tile;
2334 
2336 
2337  const Aircraft *a;
2338  FOR_ALL_AIRCRAFT(a) {
2339  if (!a->IsNormalAircraft()) continue;
2340  if (a->targetairport == st->index && a->state != FLYING) return CMD_ERROR;
2341  }
2342 
2343  if (flags & DC_EXEC) {
2344  const AirportSpec *as = st->airport.GetSpec();
2345  /* The noise level is the noise from the airport and reduce it to account for the distance to the town center.
2346  * And as for construction, always remove it, even if the setting is not set, in order to avoid the
2347  * need of recalculation */
2348  AirportTileIterator it(st);
2349  Town *nearest = AirportGetNearestTown(as, it);
2350  nearest->noise_reached -= GetAirportNoiseLevelForTown(as, it, nearest->xy);
2351  }
2352 
2353  TILE_AREA_LOOP(tile_cur, st->airport) {
2354  if (!st->TileBelongsToAirport(tile_cur)) continue;
2355 
2356  CommandCost ret = EnsureNoVehicleOnGround(tile_cur);
2357  if (ret.Failed()) return ret;
2358 
2359  cost.AddCost(_price[PR_CLEAR_STATION_AIRPORT]);
2360 
2361  if (flags & DC_EXEC) {
2362  if (IsHangarTile(tile_cur)) OrderBackup::Reset(tile_cur, false);
2363  DeleteAnimatedTile(tile_cur);
2364  DoClearSquare(tile_cur);
2365  DeleteNewGRFInspectWindow(GSF_AIRPORTTILES, tile_cur);
2366  }
2367  }
2368 
2369  if (flags & DC_EXEC) {
2370  /* Clear the persistent storage. */
2371  delete st->airport.psa;
2372 
2373  for (uint i = 0; i < st->airport.GetNumHangars(); ++i) {
2376  );
2377  }
2378 
2379  st->rect.AfterRemoveRect(st, st->airport);
2380 
2381  st->airport.Clear();
2382  st->facilities &= ~FACIL_AIRPORT;
2383 
2385 
2388  }
2389 
2390  Company::Get(st->owner)->infrastructure.airport--;
2392 
2393  st->UpdateVirtCoord();
2396  DeleteNewGRFInspectWindow(GSF_AIRPORTS, st->index);
2397  }
2398 
2399  return cost;
2400 }
2401 
2411 CommandCost CmdOpenCloseAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
2412 {
2413  if (!Station::IsValidID(p1)) return CMD_ERROR;
2414  Station *st = Station::Get(p1);
2415 
2416  if (!(st->facilities & FACIL_AIRPORT) || st->owner == OWNER_NONE) return CMD_ERROR;
2417 
2418  CommandCost ret = CheckOwnership(st->owner);
2419  if (ret.Failed()) return ret;
2420 
2421  if (flags & DC_EXEC) {
2424  }
2425  return CommandCost();
2426 }
2427 
2434 bool HasStationInUse(StationID station, bool include_company, CompanyID company)
2435 {
2436  const Vehicle *v;
2437  FOR_ALL_VEHICLES(v) {
2438  if ((v->owner == company) == include_company) {
2439  const Order *order;
2440  FOR_VEHICLE_ORDERS(v, order) {
2441  if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station) {
2442  return true;
2443  }
2444  }
2445  }
2446  }
2447  return false;
2448 }
2449 
2450 static const TileIndexDiffC _dock_tileoffs_chkaround[] = {
2451  {-1, 0},
2452  { 0, 0},
2453  { 0, 0},
2454  { 0, -1}
2455 };
2456 static const byte _dock_w_chk[4] = { 2, 1, 2, 1 };
2457 static const byte _dock_h_chk[4] = { 1, 2, 1, 2 };
2458 
2468 CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
2469 {
2470  StationID station_to_join = GB(p2, 16, 16);
2471  bool reuse = (station_to_join != NEW_STATION);
2472  if (!reuse) station_to_join = INVALID_STATION;
2473  bool distant_join = (station_to_join != INVALID_STATION);
2474 
2475  if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
2476 
2478  if (direction == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2479  direction = ReverseDiagDir(direction);
2480 
2481  /* Docks cannot be placed on rapids */
2482  if (HasTileWaterGround(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2483 
2484  CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags);
2485  if (ret.Failed()) return ret;
2486 
2487  if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
2488 
2489  ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
2490  if (ret.Failed()) return ret;
2491 
2492  TileIndex tile_cur = tile + TileOffsByDiagDir(direction);
2493 
2494  if (!IsTileType(tile_cur, MP_WATER) || !IsTileFlat(tile_cur)) {
2495  return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2496  }
2497 
2498  if (IsBridgeAbove(tile_cur)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
2499 
2500  /* Get the water class of the water tile before it is cleared.*/
2501  WaterClass wc = GetWaterClass(tile_cur);
2502 
2503  ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
2504  if (ret.Failed()) return ret;
2505 
2506  tile_cur += TileOffsByDiagDir(direction);
2507  if (!IsTileType(tile_cur, MP_WATER) || !IsTileFlat(tile_cur)) {
2508  return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
2509  }
2510 
2511  TileArea dock_area = TileArea(tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]),
2512  _dock_w_chk[direction], _dock_h_chk[direction]);
2513 
2514  /* middle */
2515  Station *st = NULL;
2516  ret = FindJoiningStation(INVALID_STATION, station_to_join, HasBit(p1, 0), dock_area, &st);
2517  if (ret.Failed()) return ret;
2518 
2519  /* Distant join */
2520  if (st == NULL && distant_join) st = Station::GetIfValid(station_to_join);
2521 
2522  ret = BuildStationPart(&st, flags, reuse, dock_area, STATIONNAMING_DOCK);
2523  if (ret.Failed()) return ret;
2524 
2525  if (st != NULL && st->dock_tile != INVALID_TILE) return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK);
2526 
2527  if (flags & DC_EXEC) {
2528  st->dock_tile = tile;
2529  st->AddFacility(FACIL_DOCK, tile);
2530 
2531  st->rect.BeforeAddRect(dock_area.tile, dock_area.w, dock_area.h, StationRect::ADD_TRY);
2532 
2533  /* If the water part of the dock is on a canal, update infrastructure counts.
2534  * This is needed as we've unconditionally cleared that tile before. */
2535  if (wc == WATER_CLASS_CANAL) {
2536  Company::Get(st->owner)->infrastructure.water++;
2537  }
2538  Company::Get(st->owner)->infrastructure.station += 2;
2540 
2541  MakeDock(tile, st->owner, st->index, direction, wc);
2542 
2543  st->UpdateVirtCoord();
2544  UpdateStationAcceptance(st, false);
2549  }
2550 
2551  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_STATION_DOCK]);
2552 }
2553 
2561 {
2562  Station *st = Station::GetByTile(tile);
2563  CommandCost ret = CheckOwnership(st->owner);
2564  if (ret.Failed()) return ret;
2565 
2566  TileIndex docking_location = TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile)));
2567 
2568  TileIndex tile1 = st->dock_tile;
2569  TileIndex tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1));
2570 
2571  ret = EnsureNoVehicleOnGround(tile1);
2572  if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2);
2573  if (ret.Failed()) return ret;
2574 
2575  if (flags & DC_EXEC) {
2576  DoClearSquare(tile1);
2577  MarkTileDirtyByTile(tile1);
2578  MakeWaterKeepingClass(tile2, st->owner);
2579 
2580  st->rect.AfterRemoveTile(st, tile1);
2581  st->rect.AfterRemoveTile(st, tile2);
2582 
2583  st->dock_tile = INVALID_TILE;
2584  st->facilities &= ~FACIL_DOCK;
2585 
2586  Company::Get(st->owner)->infrastructure.station -= 2;
2588 
2590  st->UpdateVirtCoord();
2593 
2594  /* All ships that were going to our station, can't go to it anymore.
2595  * Just clear the order, then automatically the next appropriate order
2596  * will be selected and in case of no appropriate order it will just
2597  * wander around the world. */
2598  Ship *s;
2599  FOR_ALL_SHIPS(s) {
2600  if (s->current_order.IsType(OT_LOADING) && s->tile == docking_location) {
2601  s->LeaveStation();
2602  }
2603 
2604  if (s->dest_tile == docking_location) {
2605  s->dest_tile = 0;
2606  s->current_order.Free();
2607  }
2608  }
2609  }
2610 
2611  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_STATION_DOCK]);
2612 }
2613 
2614 #include "table/station_land.h"
2615 
2616 const DrawTileSprites *GetStationTileLayout(StationType st, byte gfx)
2617 {
2618  return &_station_display_datas[st][gfx];
2619 }
2620 
2630 bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrackOffset *overlay_offset)
2631 {
2632  bool snow_desert;
2633  switch (*ground) {
2634  case SPR_RAIL_TRACK_X:
2635  snow_desert = false;
2636  *overlay_offset = RTO_X;
2637  break;
2638 
2639  case SPR_RAIL_TRACK_Y:
2640  snow_desert = false;
2641  *overlay_offset = RTO_Y;
2642  break;
2643 
2644  case SPR_RAIL_TRACK_X_SNOW:
2645  snow_desert = true;
2646  *overlay_offset = RTO_X;
2647  break;
2648 
2649  case SPR_RAIL_TRACK_Y_SNOW:
2650  snow_desert = true;
2651  *overlay_offset = RTO_Y;
2652  break;
2653 
2654  default:
2655  return false;
2656  }
2657 
2658  if (ti != NULL) {
2659  /* Decide snow/desert from tile */
2661  case LT_ARCTIC:
2662  snow_desert = (uint)ti->z > GetSnowLine() * TILE_HEIGHT;
2663  break;
2664 
2665  case LT_TROPIC:
2666  snow_desert = GetTropicZone(ti->tile) == TROPICZONE_DESERT;
2667  break;
2668 
2669  default:
2670  break;
2671  }
2672  }
2673 
2674  *ground = snow_desert ? SPR_FLAT_SNOW_DESERT_TILE : SPR_FLAT_GRASS_TILE;
2675  return true;
2676 }
2677 
2678 static void DrawTile_Station(TileInfo *ti)
2679 {
2680  const NewGRFSpriteLayout *layout = NULL;
2681  DrawTileSprites tmp_rail_layout;
2682  const DrawTileSprites *t = NULL;
2683  RoadTypes roadtypes;
2684  int32 total_offset;
2685  const RailtypeInfo *rti = NULL;
2686  uint32 relocation = 0;
2687  uint32 ground_relocation = 0;
2688  BaseStation *st = NULL;
2689  const StationSpec *statspec = NULL;
2690  uint tile_layout = 0;
2691 
2692  if (HasStationRail(ti->tile)) {
2693  rti = GetRailTypeInfo(GetRailType(ti->tile));
2694  roadtypes = ROADTYPES_NONE;
2695  total_offset = rti->GetRailtypeSpriteOffset();
2696 
2697  if (IsCustomStationSpecIndex(ti->tile)) {
2698  /* look for customization */
2699  st = BaseStation::GetByTile(ti->tile);
2700  statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec;
2701 
2702  if (statspec != NULL) {
2703  tile_layout = GetStationGfx(ti->tile);
2704 
2706  uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile);
2707  if (callback != CALLBACK_FAILED) tile_layout = (callback & ~1) + GetRailStationAxis(ti->tile);
2708  }
2709 
2710  /* Ensure the chosen tile layout is valid for this custom station */
2711  if (statspec->renderdata != NULL) {
2712  layout = &statspec->renderdata[tile_layout < statspec->tiles ? tile_layout : (uint)GetRailStationAxis(ti->tile)];
2713  if (!layout->NeedsPreprocessing()) {
2714  t = layout;
2715  layout = NULL;
2716  }
2717  }
2718  }
2719  }
2720  } else {
2721  roadtypes = IsRoadStop(ti->tile) ? GetRoadTypes(ti->tile) : ROADTYPES_NONE;
2722  total_offset = 0;
2723  }
2724 
2725  StationGfx gfx = GetStationGfx(ti->tile);
2726  if (IsAirport(ti->tile)) {
2727  gfx = GetAirportGfx(ti->tile);
2728  if (gfx >= NEW_AIRPORTTILE_OFFSET) {
2729  const AirportTileSpec *ats = AirportTileSpec::Get(gfx);
2730  if (ats->grf_prop.spritegroup[0] != NULL && DrawNewAirportTile(ti, Station::GetByTile(ti->tile), gfx, ats)) {
2731  return;
2732  }
2733  /* No sprite group (or no valid one) found, meaning no graphics associated.
2734  * Use the substitute one instead */
2735  assert(ats->grf_prop.subst_id != INVALID_AIRPORTTILE);
2736  gfx = ats->grf_prop.subst_id;
2737  }
2738  switch (gfx) {
2739  case APT_RADAR_GRASS_FENCE_SW:
2740  t = &_station_display_datas_airport_radar_grass_fence_sw[GetAnimationFrame(ti->tile)];
2741  break;
2742  case APT_GRASS_FENCE_NE_FLAG:
2743  t = &_station_display_datas_airport_flag_grass_fence_ne[GetAnimationFrame(ti->tile)];
2744  break;
2745  case APT_RADAR_FENCE_SW:
2746  t = &_station_display_datas_airport_radar_fence_sw[GetAnimationFrame(ti->tile)];
2747  break;
2748  case APT_RADAR_FENCE_NE:
2749  t = &_station_display_datas_airport_radar_fence_ne[GetAnimationFrame(ti->tile)];
2750  break;
2751  case APT_GRASS_FENCE_NE_FLAG_2:
2752  t = &_station_display_datas_airport_flag_grass_fence_ne_2[GetAnimationFrame(ti->tile)];
2753  break;
2754  }
2755  }
2756 
2757  Owner owner = GetTileOwner(ti->tile);
2758 
2759  PaletteID palette;
2760  if (Company::IsValidID(owner)) {
2761  palette = COMPANY_SPRITE_COLOUR(owner);
2762  } else {
2763  /* Some stations are not owner by a company, namely oil rigs */
2764  palette = PALETTE_TO_GREY;
2765  }
2766 
2767  if (layout == NULL && (t == NULL || t->seq == NULL)) t = GetStationTileLayout(GetStationType(ti->tile), gfx);
2768 
2769  /* don't show foundation for docks */
2770  if (ti->tileh != SLOPE_FLAT && !IsDock(ti->tile)) {
2771  if (statspec != NULL && HasBit(statspec->flags, SSF_CUSTOM_FOUNDATIONS)) {
2772  /* Station has custom foundations.
2773  * Check whether the foundation continues beyond the tile's upper sides. */
2774  uint edge_info = 0;
2775  int z;
2776  Slope slope = GetFoundationPixelSlope(ti->tile, &z);
2777  if (!HasFoundationNW(ti->tile, slope, z)) SetBit(edge_info, 0);
2778  if (!HasFoundationNE(ti->tile, slope, z)) SetBit(edge_info, 1);
2779  SpriteID image = GetCustomStationFoundationRelocation(statspec, st, ti->tile, tile_layout, edge_info);
2780  if (image == 0) goto draw_default_foundation;
2781 
2782  if (HasBit(statspec->flags, SSF_EXTENDED_FOUNDATIONS)) {
2783  /* Station provides extended foundations. */
2784 
2785  static const uint8 foundation_parts[] = {
2786  0, 0, 0, 0, // Invalid, Invalid, Invalid, SLOPE_SW
2787  0, 1, 2, 3, // Invalid, SLOPE_EW, SLOPE_SE, SLOPE_WSE
2788  0, 4, 5, 6, // Invalid, SLOPE_NW, SLOPE_NS, SLOPE_NWS
2789  7, 8, 9 // SLOPE_NE, SLOPE_ENW, SLOPE_SEN
2790  };
2791 
2792  AddSortableSpriteToDraw(image + foundation_parts[ti->tileh], PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
2793  } else {
2794  /* Draw simple foundations, built up from 8 possible foundation sprites. */
2795 
2796  /* Each set bit represents one of the eight composite sprites to be drawn.
2797  * 'Invalid' entries will not drawn but are included for completeness. */
2798  static const uint8 composite_foundation_parts[] = {
2799  /* Invalid (00000000), Invalid (11010001), Invalid (11100100), SLOPE_SW (11100000) */
2800  0x00, 0xD1, 0xE4, 0xE0,
2801  /* Invalid (11001010), SLOPE_EW (11001001), SLOPE_SE (11000100), SLOPE_WSE (11000000) */
2802  0xCA, 0xC9, 0xC4, 0xC0,
2803  /* Invalid (11010010), SLOPE_NW (10010001), SLOPE_NS (11100100), SLOPE_NWS (10100000) */
2804  0xD2, 0x91, 0xE4, 0xA0,
2805  /* SLOPE_NE (01001010), SLOPE_ENW (00001001), SLOPE_SEN (01000100) */
2806  0x4A, 0x09, 0x44
2807  };
2808 
2809  uint8 parts = composite_foundation_parts[ti->tileh];
2810 
2811  /* If foundations continue beyond the tile's upper sides then
2812  * mask out the last two pieces. */
2813  if (HasBit(edge_info, 0)) ClrBit(parts, 6);
2814  if (HasBit(edge_info, 1)) ClrBit(parts, 7);
2815 
2816  if (parts == 0) {
2817  /* We always have to draw at least one sprite to make sure there is a boundingbox and a sprite with the
2818  * correct offset for the childsprites.
2819  * So, draw the (completely empty) sprite of the default foundations. */
2820  goto draw_default_foundation;
2821  }
2822 
2824  for (int i = 0; i < 8; i++) {
2825  if (HasBit(parts, i)) {
2826  AddSortableSpriteToDraw(image + i, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
2827  }
2828  }
2829  EndSpriteCombine();
2830  }
2831 
2832  OffsetGroundSprite(31, 1);
2834  } else {
2835 draw_default_foundation:
2837  }
2838  }
2839 
2840  if (IsBuoy(ti->tile)) {
2841  DrawWaterClassGround(ti);
2842  SpriteID sprite = GetCanalSprite(CF_BUOY, ti->tile);
2843  if (sprite != 0) total_offset = sprite - SPR_IMG_BUOY;
2844  } else if (IsDock(ti->tile) || (IsOilRig(ti->tile) && IsTileOnWater(ti->tile))) {
2845  if (ti->tileh == SLOPE_FLAT) {
2846  DrawWaterClassGround(ti);
2847  } else {
2848  assert(IsDock(ti->tile));
2849  TileIndex water_tile = ti->tile + TileOffsByDiagDir(GetDockDirection(ti->tile));
2850  WaterClass wc = GetWaterClass(water_tile);
2851  if (wc == WATER_CLASS_SEA) {
2852  DrawShoreTile(ti->tileh);
2853  } else {
2854  DrawClearLandTile(ti, 3);
2855  }
2856  }
2857  } else {
2858  if (layout != NULL) {
2859  /* Sprite layout which needs preprocessing */
2860  bool separate_ground = HasBit(statspec->flags, SSF_SEPARATE_GROUND);
2861  uint32 var10_values = layout->PrepareLayout(total_offset, rti->fallback_railtype, 0, 0, separate_ground);
2862  uint8 var10;
2863  FOR_EACH_SET_BIT(var10, var10_values) {
2864  uint32 var10_relocation = GetCustomStationRelocation(statspec, st, ti->tile, var10);
2865  layout->ProcessRegisters(var10, var10_relocation, separate_ground);
2866  }
2867  tmp_rail_layout.seq = layout->GetLayout(&tmp_rail_layout.ground);
2868  t = &tmp_rail_layout;
2869  total_offset = 0;
2870  } else if (statspec != NULL) {
2871  /* Simple sprite layout */
2872  ground_relocation = relocation = GetCustomStationRelocation(statspec, st, ti->tile, 0);
2873  if (HasBit(statspec->flags, SSF_SEPARATE_GROUND)) {
2874  ground_relocation = GetCustomStationRelocation(statspec, st, ti->tile, 1);
2875  }
2876  ground_relocation += rti->fallback_railtype;
2877  }
2878 
2879  SpriteID image = t->ground.sprite;
2880  PaletteID pal = t->ground.pal;
2881  RailTrackOffset overlay_offset;
2882  if (rti != NULL && rti->UsesOverlay() && SplitGroundSpriteForOverlay(ti, &image, &overlay_offset)) {
2883  SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
2884  DrawGroundSprite(image, PAL_NONE);
2885  DrawGroundSprite(ground + overlay_offset, PAL_NONE);
2886 
2887  if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasStationReservation(ti->tile)) {
2888  SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
2889  DrawGroundSprite(overlay + overlay_offset, PALETTE_CRASH);
2890  }
2891  } else {
2892  image += HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE) ? ground_relocation : total_offset;
2893  if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += ground_relocation;
2894  DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette));
2895 
2896  /* PBS debugging, draw reserved tracks darker */
2897  if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasStationRail(ti->tile) && HasStationReservation(ti->tile)) {
2898  const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
2900  }
2901  }
2902  }
2903 
2905 
2906  if (HasBit(roadtypes, ROADTYPE_TRAM)) {
2907  Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y;
2908  DrawGroundSprite((HasBit(roadtypes, ROADTYPE_ROAD) ? SPR_TRAMWAY_OVERLAY : SPR_TRAMWAY_TRAM) + (axis ^ 1), PAL_NONE);
2909  DrawRoadCatenary(ti, axis == AXIS_X ? ROAD_X : ROAD_Y);
2910  }
2911 
2912  if (IsRailWaypoint(ti->tile)) {
2913  /* Don't offset the waypoint graphics; they're always the same. */
2914  total_offset = 0;
2915  }
2916 
2917  DrawRailTileSeq(ti, t, TO_BUILDINGS, total_offset, relocation, palette);
2918 }
2919 
2920 void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, RoadType roadtype, int image)
2921 {
2922  int32 total_offset = 0;
2923  PaletteID pal = COMPANY_SPRITE_COLOUR(_local_company);
2924  const DrawTileSprites *t = GetStationTileLayout(st, image);
2925  const RailtypeInfo *rti = NULL;
2926 
2927  if (railtype != INVALID_RAILTYPE) {
2928  rti = GetRailTypeInfo(railtype);
2929  total_offset = rti->GetRailtypeSpriteOffset();
2930  }
2931 
2932  SpriteID img = t->ground.sprite;
2933  RailTrackOffset overlay_offset;
2934  if (rti != NULL && rti->UsesOverlay() && SplitGroundSpriteForOverlay(NULL, &img, &overlay_offset)) {
2936  DrawSprite(img, PAL_NONE, x, y);
2937  DrawSprite(ground + overlay_offset, PAL_NONE, x, y);
2938  } else {
2939  DrawSprite(img + total_offset, HasBit(img, PALETTE_MODIFIER_COLOUR) ? pal : PAL_NONE, x, y);
2940  }
2941 
2942  if (roadtype == ROADTYPE_TRAM) {
2943  DrawSprite(SPR_TRAMWAY_TRAM + (t->ground.sprite == SPR_ROAD_PAVED_STRAIGHT_X ? 1 : 0), PAL_NONE, x, y);
2944  }
2945 
2946  /* Default waypoint has no railtype specific sprites */
2947  DrawRailTileSeqInGUI(x, y, t, st == STATION_WAYPOINT ? 0 : total_offset, 0, pal);
2948 }
2949 
2950 static int GetSlopePixelZ_Station(TileIndex tile, uint x, uint y)
2951 {
2952  return GetTileMaxPixelZ(tile);
2953 }
2954 
2955 static Foundation GetFoundation_Station(TileIndex tile, Slope tileh)
2956 {
2957  return FlatteningFoundation(tileh);
2958 }
2959 
2960 static void GetTileDesc_Station(TileIndex tile, TileDesc *td)
2961 {
2962  td->owner[0] = GetTileOwner(tile);
2963  if (IsDriveThroughStopTile(tile)) {
2964  Owner road_owner = INVALID_OWNER;
2965  Owner tram_owner = INVALID_OWNER;
2966  RoadTypes rts = GetRoadTypes(tile);
2967  if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD);
2968  if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM);
2969 
2970  /* Is there a mix of owners? */
2971  if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) ||
2972  (road_owner != INVALID_OWNER && road_owner != td->owner[0])) {
2973  uint i = 1;
2974  if (road_owner != INVALID_OWNER) {
2975  td->owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER;
2976  td->owner[i] = road_owner;
2977  i++;
2978  }
2979  if (tram_owner != INVALID_OWNER) {
2980  td->owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER;
2981  td->owner[i] = tram_owner;
2982  }
2983  }
2984  }
2986 
2987  if (HasStationTileRail(tile)) {
2988  const StationSpec *spec = GetStationSpec(tile);
2989 
2990  if (spec != NULL) {
2992  td->station_name = spec->name;
2993 
2994  if (spec->grf_prop.grffile != NULL) {
2995  const GRFConfig *gc = GetGRFConfig(spec->grf_prop.grffile->grfid);
2996  td->grf = gc->GetName();
2997  }
2998  }
2999 
3000  const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
3001  td->rail_speed = rti->max_speed;
3002  td->railtype = rti->strings.name;
3003  }
3004 
3005  if (IsAirport(tile)) {
3006  const AirportSpec *as = Station::GetByTile(tile)->airport.GetSpec();
3008  td->airport_name = as->name;
3009 
3010  const AirportTileSpec *ats = AirportTileSpec::GetByTile(tile);
3011  td->airport_tile_name = ats->name;
3012 
3013  if (as->grf_prop.grffile != NULL) {
3014  const GRFConfig *gc = GetGRFConfig(as->grf_prop.grffile->grfid);
3015  td->grf = gc->GetName();
3016  } else if (ats->grf_prop.grffile != NULL) {
3017  const GRFConfig *gc = GetGRFConfig(ats->grf_prop.grffile->grfid);
3018  td->grf = gc->GetName();
3019  }
3020  }
3021 
3022  StringID str;
3023  switch (GetStationType(tile)) {
3024  default: NOT_REACHED();
3025  case STATION_RAIL: str = STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION; break;
3026  case STATION_AIRPORT:
3027  str = (IsHangar(tile) ? STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR : STR_LAI_STATION_DESCRIPTION_AIRPORT);
3028  break;
3029  case STATION_TRUCK: str = STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA; break;
3030  case STATION_BUS: str = STR_LAI_STATION_DESCRIPTION_BUS_STATION; break;
3031  case STATION_OILRIG: str = STR_INDUSTRY_NAME_OIL_RIG; break;
3032  case STATION_DOCK: str = STR_LAI_STATION_DESCRIPTION_SHIP_DOCK; break;
3033  case STATION_BUOY: str = STR_LAI_STATION_DESCRIPTION_BUOY; break;
3034  case STATION_WAYPOINT: str = STR_LAI_STATION_DESCRIPTION_WAYPOINT; break;
3035  }
3036  td->str = str;
3037 }
3038 
3039 
3040 static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
3041 {
3042  TrackBits trackbits = TRACK_BIT_NONE;
3043 
3044  switch (mode) {
3045  case TRANSPORT_RAIL:
3046  if (HasStationRail(tile) && !IsStationTileBlocked(tile)) {
3047  trackbits = TrackToTrackBits(GetRailStationTrack(tile));
3048  }
3049  break;
3050 
3051  case TRANSPORT_WATER:
3052  /* buoy is coded as a station, it is always on open water */
3053  if (IsBuoy(tile)) {
3054  trackbits = TRACK_BIT_ALL;
3055  /* remove tracks that connect NE map edge */
3056  if (TileX(tile) == 0) trackbits &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
3057  /* remove tracks that connect NW map edge */
3058  if (TileY(tile) == 0) trackbits &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
3059  }
3060  break;
3061 
3062  case TRANSPORT_ROAD:
3063  if ((GetRoadTypes(tile) & sub_mode) != 0 && IsRoadStop(tile)) {
3064  DiagDirection dir = GetRoadStopDir(tile);
3065  Axis axis = DiagDirToAxis(dir);
3066 
3067  if (side != INVALID_DIAGDIR) {
3068  if (axis != DiagDirToAxis(side) || (IsStandardRoadStopTile(tile) && dir != side)) break;
3069  }
3070 
3071  trackbits = AxisToTrackBits(axis);
3072  }
3073  break;
3074 
3075  default:
3076  break;
3077  }
3078 
3080 }
3081 
3082 
3083 static void TileLoop_Station(TileIndex tile)
3084 {
3085  /* FIXME -- GetTileTrackStatus_Station -> animated stationtiles
3086  * hardcoded.....not good */
3087  switch (GetStationType(tile)) {
3088  case STATION_AIRPORT:
3089  AirportTileAnimationTrigger(Station::GetByTile(tile), tile, AAT_TILELOOP);
3090  break;
3091 
3092  case STATION_DOCK:
3093  if (!IsTileFlat(tile)) break; // only handle water part
3094  FALLTHROUGH;
3095 
3096  case STATION_OILRIG: //(station part)
3097  case STATION_BUOY:
3098  TileLoop_Water(tile);
3099  break;
3100 
3101  default: break;
3102  }
3103 }
3104 
3105 
3106 static void AnimateTile_Station(TileIndex tile)
3107 {
3108  if (HasStationRail(tile)) {
3109  AnimateStationTile(tile);
3110  return;
3111  }
3112 
3113  if (IsAirport(tile)) {
3114  AnimateAirportTile(tile);
3115  }
3116 }
3117 
3118 
3119 static bool ClickTile_Station(TileIndex tile)
3120 {
3121  const BaseStation *bst = BaseStation::GetByTile(tile);
3122 
3123  if (bst->facilities & FACIL_WAYPOINT) {
3125  } else if (IsHangar(tile)) {
3126  const Station *st = Station::From(bst);
3128  } else {
3130  }
3131  return true;
3132 }
3133 
3134 static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, int x, int y)
3135 {
3136  if (v->type == VEH_TRAIN) {
3137  StationID station_id = GetStationIndex(tile);
3138  if (!v->current_order.ShouldStopAtStation(v, station_id)) return VETSB_CONTINUE;
3139  if (!IsRailStation(tile) || !v->IsFrontEngine()) return VETSB_CONTINUE;
3140 
3141  int station_ahead;
3142  int station_length;
3143  int stop = GetTrainStopLocation(station_id, tile, Train::From(v), &station_ahead, &station_length);
3144 
3145  /* Stop whenever that amount of station ahead + the distance from the
3146  * begin of the platform to the stop location is longer than the length
3147  * of the platform. Station ahead 'includes' the current tile where the
3148  * vehicle is on, so we need to subtract that. */
3149  if (stop + station_ahead - (int)TILE_SIZE >= station_length) return VETSB_CONTINUE;
3150 
3152 
3153  x &= 0xF;
3154  y &= 0xF;
3155 
3156  if (DiagDirToAxis(dir) != AXIS_X) Swap(x, y);
3157  if (y == TILE_SIZE / 2) {
3158  if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x;
3159  stop &= TILE_SIZE - 1;
3160 
3161  if (x == stop) {
3162  return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station
3163  } else if (x < stop) {
3165  uint16 spd = max(0, (stop - x) * 20 - 15);
3166  if (spd < v->cur_speed) v->cur_speed = spd;
3167  }
3168  }
3169  } else if (v->type == VEH_ROAD) {
3170  RoadVehicle *rv = RoadVehicle::From(v);
3171  if (rv->state < RVSB_IN_ROAD_STOP && !IsReversingRoadTrackdir((Trackdir)rv->state) && rv->frame == 0) {
3172  if (IsRoadStop(tile) && rv->IsFrontEngine()) {
3173  /* Attempt to allocate a parking bay in a road stop */
3175  }
3176  }
3177  }
3178 
3179  return VETSB_CONTINUE;
3180 }
3181 
3187 {
3188  /* Collect cargoes accepted since the last big tick. */
3189  uint cargoes = 0;
3190  for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
3191  if (HasBit(st->goods[cid].status, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(cargoes, cid);
3192  }
3193 
3194  /* Anything to do? */
3195  if (cargoes == 0) return;
3196 
3197  /* Loop over all houses in the catchment. */
3198  Rect r = st->GetCatchmentRect();
3199  TileArea ta(TileXY(r.left, r.top), TileXY(r.right, r.bottom));
3200  TILE_AREA_LOOP(tile, ta) {
3201  if (IsTileType(tile, MP_HOUSE)) {
3202  WatchedCargoCallback(tile, cargoes);
3203  }
3204  }
3205 }
3206 
3214 {
3215  if (!st->IsInUse()) {
3216  if (++st->delete_ctr >= 8) delete st;
3217  return false;
3218  }
3219 
3220  if (Station::IsExpected(st)) {
3222 
3223  for (CargoID i = 0; i < NUM_CARGO; i++) {
3224  ClrBit(Station::From(st)->goods[i].status, GoodsEntry::GES_ACCEPTED_BIGTICK);
3225  }
3226  }
3227 
3228 
3229  if ((st->facilities & FACIL_WAYPOINT) == 0) UpdateStationAcceptance(Station::From(st), true);
3230 
3231  return true;
3232 }
3233 
3234 static inline void byte_inc_sat(byte *p)
3235 {
3236  byte b = *p + 1;
3237  if (b != 0) *p = b;
3238 }
3239 
3246 static void TruncateCargo(const CargoSpec *cs, GoodsEntry *ge, uint amount = UINT_MAX)
3247 {
3248  /* If truncating also punish the source stations' ratings to
3249  * decrease the flow of incoming cargo. */
3250 
3251  StationCargoAmountMap waiting_per_source;
3252  ge->cargo.Truncate(amount, &waiting_per_source);
3253  for (StationCargoAmountMap::iterator i(waiting_per_source.begin()); i != waiting_per_source.end(); ++i) {
3254  Station *source_station = Station::GetIfValid(i->first);
3255  if (source_station == NULL) continue;
3256 
3257  GoodsEntry &source_ge = source_station->goods[cs->Index()];
3258  source_ge.max_waiting_cargo = max(source_ge.max_waiting_cargo, i->second);
3259  }
3260 }
3261 
3262 static void UpdateStationRating(Station *st)
3263 {
3264  bool waiting_changed = false;
3265 
3266  byte_inc_sat(&st->time_since_load);
3267  byte_inc_sat(&st->time_since_unload);
3268 
3269  const CargoSpec *cs;
3270  FOR_ALL_CARGOSPECS(cs) {
3271  GoodsEntry *ge = &st->goods[cs->Index()];
3272  /* Slowly increase the rating back to his original level in the case we
3273  * didn't deliver cargo yet to this station. This happens when a bribe
3274  * failed while you didn't moved that cargo yet to a station. */
3275  if (!ge->HasRating() && ge->rating < INITIAL_STATION_RATING) {
3276  ge->rating++;
3277  }
3278 
3279  /* Only change the rating if we are moving this cargo */
3280  if (ge->HasRating()) {
3281  byte_inc_sat(&ge->time_since_pickup);
3282  if (ge->time_since_pickup == 255 && _settings_game.order.selectgoods) {
3284  ge->last_speed = 0;
3285  TruncateCargo(cs, ge);
3286  waiting_changed = true;
3287  continue;
3288  }
3289 
3290  bool skip = false;
3291  int rating = 0;
3292  uint waiting = ge->cargo.AvailableCount();
3293 
3294  /* num_dests is at least 1 if there is any cargo as
3295  * INVALID_STATION is also a destination.
3296  */
3297  uint num_dests = (uint)ge->cargo.Packets()->MapSize();
3298 
3299  /* Average amount of cargo per next hop, but prefer solitary stations
3300  * with only one or two next hops. They are allowed to have more
3301  * cargo waiting per next hop.
3302  * With manual cargo distribution waiting_avg = waiting / 2 as then
3303  * INVALID_STATION is the only destination.
3304  */
3305  uint waiting_avg = waiting / (num_dests + 1);
3306 
3308  /* Perform custom station rating. If it succeeds the speed, days in transit and
3309  * waiting cargo ratings must not be executed. */
3310 
3311  /* NewGRFs expect last speed to be 0xFF when no vehicle has arrived yet. */
3312  uint last_speed = ge->HasVehicleEverTriedLoading() ? ge->last_speed : 0xFF;
3313 
3314  uint32 var18 = min(ge->time_since_pickup, 0xFF) | (min(ge->max_waiting_cargo, 0xFFFF) << 8) | (min(last_speed, 0xFF) << 24);
3315  /* Convert to the 'old' vehicle types */
3316  uint32 var10 = (st->last_vehicle_type == VEH_INVALID) ? 0x0 : (st->last_vehicle_type + 0x10);
3317  uint16 callback = GetCargoCallback(CBID_CARGO_STATION_RATING_CALC, var10, var18, cs);
3318  if (callback != CALLBACK_FAILED) {
3319  skip = true;
3320  rating = GB(callback, 0, 14);
3321 
3322  /* Simulate a 15 bit signed value */
3323  if (HasBit(callback, 14)) rating -= 0x4000;
3324  }
3325  }
3326 
3327  if (!skip) {
3328  int b = ge->last_speed - 85;
3329  if (b >= 0) rating += b >> 2;
3330 
3331  byte waittime = ge->time_since_pickup;
3332  if (st->last_vehicle_type == VEH_SHIP) waittime >>= 2;
3333  (waittime > 21) ||
3334  (rating += 25, waittime > 12) ||
3335  (rating += 25, waittime > 6) ||
3336  (rating += 45, waittime > 3) ||
3337  (rating += 35, true);
3338 
3339  (rating -= 90, ge->max_waiting_cargo > 1500) ||
3340  (rating += 55, ge->max_waiting_cargo > 1000) ||
3341  (rating += 35, ge->max_waiting_cargo > 600) ||
3342  (rating += 10, ge->max_waiting_cargo > 300) ||
3343  (rating += 20, ge->max_waiting_cargo > 100) ||
3344  (rating += 10, true);
3345  }
3346 
3347  if (Company::IsValidID(st->owner) && HasBit(st->town->statues, st->owner)) rating += 26;
3348 
3349  byte age = ge->last_age;
3350  (age >= 3) ||
3351  (rating += 10, age >= 2) ||
3352  (rating += 10, age >= 1) ||
3353  (rating += 13, true);
3354 
3355  {
3356  int or_ = ge->rating; // old rating
3357 
3358  /* only modify rating in steps of -2, -1, 0, 1 or 2 */
3359  ge->rating = rating = or_ + Clamp(Clamp(rating, 0, 255) - or_, -2, 2);
3360 
3361  /* if rating is <= 64 and more than 100 items waiting on average per destination,
3362  * remove some random amount of goods from the station */
3363  if (rating <= 64 && waiting_avg >= 100) {
3364  int dec = Random() & 0x1F;
3365  if (waiting_avg < 200) dec &= 7;
3366  waiting -= (dec + 1) * num_dests;
3367  waiting_changed = true;
3368  }
3369 
3370  /* if rating is <= 127 and there are any items waiting, maybe remove some goods. */
3371  if (rating <= 127 && waiting != 0) {
3372  uint32 r = Random();
3373  if (rating <= (int)GB(r, 0, 7)) {
3374  /* Need to have int, otherwise it will just overflow etc. */
3375  waiting = max((int)waiting - (int)((GB(r, 8, 2) - 1) * num_dests), 0);
3376  waiting_changed = true;
3377  }
3378  }
3379 
3380  /* At some point we really must cap the cargo. Previously this
3381  * was a strict 4095, but now we'll have a less strict, but
3382  * increasingly aggressive truncation of the amount of cargo. */
3383  static const uint WAITING_CARGO_THRESHOLD = 1 << 12;
3384  static const uint WAITING_CARGO_CUT_FACTOR = 1 << 6;
3385  static const uint MAX_WAITING_CARGO = 1 << 15;
3386 
3387  if (waiting > WAITING_CARGO_THRESHOLD) {
3388  uint difference = waiting - WAITING_CARGO_THRESHOLD;
3389  waiting -= (difference / WAITING_CARGO_CUT_FACTOR);
3390 
3391  waiting = min(waiting, MAX_WAITING_CARGO);
3392  waiting_changed = true;
3393  }
3394 
3395  /* We can't truncate cargo that's already reserved for loading.
3396  * Thus StoredCount() here. */
3397  if (waiting_changed && waiting < ge->cargo.AvailableCount()) {
3398  /* Feed back the exact own waiting cargo at this station for the
3399  * next rating calculation. */
3400  ge->max_waiting_cargo = 0;
3401 
3402  TruncateCargo(cs, ge, ge->cargo.AvailableCount() - waiting);
3403  } else {
3404  /* If the average number per next hop is low, be more forgiving. */
3405  ge->max_waiting_cargo = waiting_avg;
3406  }
3407  }
3408  }
3409  }
3410 
3411  StationID index = st->index;
3412  if (waiting_changed) {
3413  SetWindowDirty(WC_STATION_VIEW, index); // update whole window
3414  } else {
3415  SetWindowWidgetDirty(WC_STATION_VIEW, index, WID_SV_ACCEPT_RATING_LIST); // update only ratings list
3416  }
3417 }
3418 
3427 void RerouteCargo(Station *st, CargoID c, StationID avoid, StationID avoid2)
3428 {
3429  GoodsEntry &ge = st->goods[c];
3430 
3431  /* Reroute cargo in station. */
3432  ge.cargo.Reroute(UINT_MAX, &ge.cargo, avoid, avoid2, &ge);
3433 
3434  /* Reroute cargo staged to be transfered. */
3435  for (std::list<Vehicle *>::iterator it(st->loading_vehicles.begin()); it != st->loading_vehicles.end(); ++it) {
3436  for (Vehicle *v = *it; v != NULL; v = v->Next()) {
3437  if (v->cargo_type != c) continue;
3438  v->cargo.Reroute(UINT_MAX, &v->cargo, avoid, avoid2, &ge);
3439  }
3440  }
3441 }
3442 
3452 {
3453  for (CargoID c = 0; c < NUM_CARGO; ++c) {
3454  const bool auto_distributed = (_settings_game.linkgraph.GetDistributionType(c) != DT_MANUAL);
3455  GoodsEntry &ge = from->goods[c];
3457  if (lg == NULL) continue;
3458  Node node = (*lg)[ge.node];
3459  for (EdgeIterator it(node.Begin()); it != node.End();) {
3460  Edge edge = it->second;
3461  Station *to = Station::Get((*lg)[it->first].Station());
3462  assert(to->goods[c].node == it->first);
3463  ++it; // Do that before removing the edge. Anything else may crash.
3464  assert(_date >= edge.LastUpdate());
3465  uint timeout = LinkGraph::MIN_TIMEOUT_DISTANCE + (DistanceManhattan(from->xy, to->xy) >> 3);
3466  if ((uint)(_date - edge.LastUpdate()) > timeout) {
3467  bool updated = false;
3468 
3469  if (auto_distributed) {
3470  /* Have all vehicles refresh their next hops before deciding to
3471  * remove the node. */
3472  OrderList *l;
3473  SmallVector<Vehicle *, 32> vehicles;
3474  FOR_ALL_ORDER_LISTS(l) {
3475  bool found_from = false;
3476  bool found_to = false;
3477  for (Order *order = l->GetFirstOrder(); order != NULL; order = order->next) {
3478  if (!order->IsType(OT_GOTO_STATION) && !order->IsType(OT_IMPLICIT)) continue;
3479  if (order->GetDestination() == from->index) {
3480  found_from = true;
3481  if (found_to) break;
3482  } else if (order->GetDestination() == to->index) {
3483  found_to = true;
3484  if (found_from) break;
3485  }
3486  }
3487  if (!found_to || !found_from) continue;
3488  *(vehicles.Append()) = l->GetFirstSharedVehicle();
3489  }
3490 
3491  Vehicle **iter = vehicles.Begin();
3492  while (iter != vehicles.End()) {
3493  Vehicle *v = *iter;
3494 
3495  LinkRefresher::Run(v, false); // Don't allow merging. Otherwise lg might get deleted.
3496  if (edge.LastUpdate() == _date) {
3497  updated = true;
3498  break;
3499  }
3500 
3501  Vehicle *next_shared = v->NextShared();
3502  if (next_shared) {
3503  *iter = next_shared;
3504  ++iter;
3505  } else {
3506  vehicles.Erase(iter);
3507  }
3508 
3509  if (iter == vehicles.End()) iter = vehicles.Begin();
3510  }
3511  }
3512 
3513  if (!updated) {
3514  /* If it's still considered dead remove it. */
3515  node.RemoveEdge(to->goods[c].node);
3516  ge.flows.DeleteFlows(to->index);
3517  RerouteCargo(from, c, to->index, from->index);
3518  }
3519  } else if (edge.LastUnrestrictedUpdate() != INVALID_DATE && (uint)(_date - edge.LastUnrestrictedUpdate()) > timeout) {
3520  edge.Restrict();
3521  ge.flows.RestrictFlows(to->index);
3522  RerouteCargo(from, c, to->index, from->index);
3523  } else if (edge.LastRestrictedUpdate() != INVALID_DATE && (uint)(_date - edge.LastRestrictedUpdate()) > timeout) {
3524  edge.Release();
3525  }
3526  }
3527  assert(_date >= lg->LastCompression());
3528  if ((uint)(_date - lg->LastCompression()) > LinkGraph::COMPRESSION_INTERVAL) {
3529  lg->Compress();
3530  }
3531  }
3532 }
3533 
3543 void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage, EdgeUpdateMode mode)
3544 {
3545  GoodsEntry &ge1 = st->goods[cargo];
3546  Station *st2 = Station::Get(next_station_id);
3547  GoodsEntry &ge2 = st2->goods[cargo];
3548  LinkGraph *lg = NULL;
3549  if (ge1.link_graph == INVALID_LINK_GRAPH) {
3550  if (ge2.link_graph == INVALID_LINK_GRAPH) {
3552  lg = new LinkGraph(cargo);
3554  ge2.link_graph = lg->index;
3555  ge2.node = lg->AddNode(st2);
3556  } else {
3557  DEBUG(misc, 0, "Can't allocate link graph");
3558  }
3559  } else {
3560  lg = LinkGraph::Get(ge2.link_graph);
3561  }
3562  if (lg) {
3563  ge1.link_graph = lg->index;
3564  ge1.node = lg->AddNode(st);
3565  }
3566  } else if (ge2.link_graph == INVALID_LINK_GRAPH) {
3567  lg = LinkGraph::Get(ge1.link_graph);
3568  ge2.link_graph = lg->index;
3569  ge2.node = lg->AddNode(st2);
3570  } else {
3571  lg = LinkGraph::Get(ge1.link_graph);
3572  if (ge1.link_graph != ge2.link_graph) {
3573  LinkGraph *lg2 = LinkGraph::Get(ge2.link_graph);
3574  if (lg->Size() < lg2->Size()) {
3576  lg2->Merge(lg); // Updates GoodsEntries of lg
3577  lg = lg2;
3578  } else {
3580  lg->Merge(lg2); // Updates GoodsEntries of lg2
3581  }
3582  }
3583  }
3584  if (lg != NULL) {
3585  (*lg)[ge1.node].UpdateEdge(ge2.node, capacity, usage, mode);
3586  }
3587 }
3588 
3595 void IncreaseStats(Station *st, const Vehicle *front, StationID next_station_id)
3596 {
3597  for (const Vehicle *v = front; v != NULL; v = v->Next()) {
3598  if (v->refit_cap > 0) {
3599  /* The cargo count can indeed be higher than the refit_cap if
3600  * wagons have been auto-replaced and subsequently auto-
3601  * refitted to a higher capacity. The cargo gets redistributed
3602  * among the wagons in that case.
3603  * As usage is not such an important figure anyway we just
3604  * ignore the additional cargo then.*/
3605  IncreaseStats(st, v->cargo_type, next_station_id, v->refit_cap,
3607  }
3608  }
3609 }
3610 
3611 /* called for every station each tick */
3612 static void StationHandleSmallTick(BaseStation *st)
3613 {
3614  if ((st->facilities & FACIL_WAYPOINT) != 0 || !st->IsInUse()) return;
3615 
3616  byte b = st->delete_ctr + 1;
3617  if (b >= STATION_RATING_TICKS) b = 0;
3618  st->delete_ctr = b;
3619 
3620  if (b == 0) UpdateStationRating(Station::From(st));
3621 }
3622 
3623 void OnTick_Station()
3624 {
3625  if (_game_mode == GM_EDITOR) return;
3626 
3627  BaseStation *st;
3628  FOR_ALL_BASE_STATIONS(st) {
3629  StationHandleSmallTick(st);
3630 
3631  /* Clean up the link graph about once a week. */
3632  if (Station::IsExpected(st) && (_tick_counter + st->index) % STATION_LINKGRAPH_TICKS == 0) {
3634  };
3635 
3636  /* Run STATION_ACCEPTANCE_TICKS = 250 tick interval trigger for station animation.
3637  * Station index is included so that triggers are not all done
3638  * at the same time. */
3639  if ((_tick_counter + st->index) % STATION_ACCEPTANCE_TICKS == 0) {
3640  /* Stop processing this station if it was deleted */
3641  if (!StationHandleBigTick(st)) continue;
3642  TriggerStationAnimation(st, st->xy, SAT_250_TICKS);
3643  if (Station::IsExpected(st)) AirportAnimationTrigger(Station::From(st), AAT_STATION_250_TICKS);
3644  }
3645  }
3646 }
3647 
3650 {
3651  Station *st;
3652 
3653  FOR_ALL_STATIONS(st) {
3654  for (CargoID i = 0; i < NUM_CARGO; i++) {
3655  GoodsEntry *ge = &st->goods[i];
3658  }
3659  }
3660 }
3661 
3662 
3663 void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius)
3664 {
3665  Station *st;
3666 
3667  FOR_ALL_STATIONS(st) {
3668  if (st->owner == owner &&
3669  DistanceManhattan(tile, st->xy) <= radius) {
3670  for (CargoID i = 0; i < NUM_CARGO; i++) {
3671  GoodsEntry *ge = &st->goods[i];
3672 
3673  if (ge->status != 0) {
3674  ge->rating = Clamp(ge->rating + amount, 0, 255);
3675  }
3676  }
3677  }
3678  }
3679 }
3680 
3681 static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceType source_type, SourceID source_id)
3682 {
3683  /* We can't allocate a CargoPacket? Then don't do anything
3684  * at all; i.e. just discard the incoming cargo. */
3685  if (!CargoPacket::CanAllocateItem()) return 0;
3686 
3687  GoodsEntry &ge = st->goods[type];
3688  amount += ge.amount_fract;
3689  ge.amount_fract = GB(amount, 0, 8);
3690 
3691  amount >>= 8;
3692  /* No new "real" cargo item yet. */
3693  if (amount == 0) return 0;
3694 
3695  StationID next = ge.GetVia(st->index);
3696  ge.cargo.Append(new CargoPacket(st->index, st->xy, amount, source_type, source_id), next);
3697  LinkGraph *lg = NULL;
3698  if (ge.link_graph == INVALID_LINK_GRAPH) {
3700  lg = new LinkGraph(type);
3702  ge.link_graph = lg->index;
3703  ge.node = lg->AddNode(st);
3704  } else {
3705  DEBUG(misc, 0, "Can't allocate link graph");
3706  }
3707  } else {
3708  lg = LinkGraph::Get(ge.link_graph);
3709  }
3710  if (lg != NULL) (*lg)[ge.node].UpdateSupply(amount);
3711 
3712  if (!ge.HasRating()) {
3715  }
3716 
3718  TriggerStationAnimation(st, st->xy, SAT_NEW_CARGO, type);
3719  AirportAnimationTrigger(st, AAT_STATION_NEW_CARGO, type);
3720 
3722  st->MarkTilesDirty(true);
3723  return amount;
3724 }
3725 
3726 static bool IsUniqueStationName(const char *name)
3727 {
3728  const Station *st;
3729 
3730  FOR_ALL_STATIONS(st) {
3731  if (st->name != NULL && strcmp(st->name, name) == 0) return false;
3732  }
3733 
3734  return true;
3735 }
3736 
3746 CommandCost CmdRenameStation(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
3747 {
3748  Station *st = Station::GetIfValid(p1);
3749  if (st == NULL) return CMD_ERROR;
3750 
3751  CommandCost ret = CheckOwnership(st->owner);
3752  if (ret.Failed()) return ret;
3753 
3754  bool reset = StrEmpty(text);
3755 
3756  if (!reset) {
3758  if (!IsUniqueStationName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
3759  }
3760 
3761  if (flags & DC_EXEC) {
3762  free(st->name);
3763  st->name = reset ? NULL : stredup(text);
3764 
3765  st->UpdateVirtCoord();
3767  }
3768 
3769  return CommandCost();
3770 }
3771 
3778 void FindStationsAroundTiles(const TileArea &location, StationList *stations)
3779 {
3780  /* area to search = producer plus station catchment radius */
3782 
3783  uint x = TileX(location.tile);
3784  uint y = TileY(location.tile);
3785 
3786  uint min_x = (x > max_rad) ? x - max_rad : 0;
3787  uint max_x = x + location.w + max_rad;
3788  uint min_y = (y > max_rad) ? y - max_rad : 0;
3789  uint max_y = y + location.h + max_rad;
3790 
3791  if (min_x == 0 && _settings_game.construction.freeform_edges) min_x = 1;
3792  if (min_y == 0 && _settings_game.construction.freeform_edges) min_y = 1;
3793  if (max_x >= MapSizeX()) max_x = MapSizeX() - 1;
3794  if (max_y >= MapSizeY()) max_y = MapSizeY() - 1;
3795 
3796  for (uint cy = min_y; cy < max_y; cy++) {
3797  for (uint cx = min_x; cx < max_x; cx++) {
3798  TileIndex cur_tile = TileXY(cx, cy);
3799  if (!IsTileType(cur_tile, MP_STATION)) continue;
3800 
3801  Station *st = Station::GetByTile(cur_tile);
3802  /* st can be NULL in case of waypoints */
3803  if (st == NULL) continue;
3804 
3806  int rad = st->GetCatchmentRadius();
3807  int rad_x = cx - x;
3808  int rad_y = cy - y;
3809 
3810  if (rad_x < -rad || rad_x >= rad + location.w) continue;
3811  if (rad_y < -rad || rad_y >= rad + location.h) continue;
3812  }
3813 
3814  /* Insert the station in the set. This will fail if it has
3815  * already been added.
3816  */
3817  stations->Include(st);
3818  }
3819  }
3820 }
3821 
3827 {
3828  if (this->tile != INVALID_TILE) {
3829  FindStationsAroundTiles(*this, &this->stations);
3830  this->tile = INVALID_TILE;
3831  }
3832  return &this->stations;
3833 }
3834 
3835 uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, SourceID source_id, const StationList *all_stations)
3836 {
3837  /* Return if nothing to do. Also the rounding below fails for 0. */
3838  if (amount == 0) return 0;
3839 
3840  Station *st1 = NULL; // Station with best rating
3841  Station *st2 = NULL; // Second best station
3842  uint best_rating1 = 0; // rating of st1
3843  uint best_rating2 = 0; // rating of st2
3844 
3845  for (Station * const *st_iter = all_stations->Begin(); st_iter != all_stations->End(); ++st_iter) {
3846  Station *st = *st_iter;
3847 
3848  /* Is the station reserved exclusively for somebody else? */
3849  if (st->town->exclusive_counter > 0 && st->town->exclusivity != st->owner) continue;
3850 
3851  if (st->goods[type].rating == 0) continue; // Lowest possible rating, better not to give cargo anymore
3852 
3853  if (_settings_game.order.selectgoods && !st->goods[type].HasVehicleEverTriedLoading()) continue; // Selectively servicing stations, and not this one
3854 
3855  if (IsCargoInClass(type, CC_PASSENGERS)) {
3856  if (st->facilities == FACIL_TRUCK_STOP) continue; // passengers are never served by just a truck stop
3857  } else {
3858  if (st->facilities == FACIL_BUS_STOP) continue; // non-passengers are never served by just a bus stop
3859  }
3860 
3861  /* This station can be used, add it to st1/st2 */
3862  if (st1 == NULL || st->goods[type].rating >= best_rating1) {
3863  st2 = st1; best_rating2 = best_rating1; st1 = st; best_rating1 = st->goods[type].rating;
3864  } else if (st2 == NULL || st->goods[type].rating >= best_rating2) {
3865  st2 = st; best_rating2 = st->goods[type].rating;
3866  }
3867  }
3868 
3869  /* no stations around at all? */
3870  if (st1 == NULL) return 0;
3871 
3872  /* From now we'll calculate with fractal cargo amounts.
3873  * First determine how much cargo we really have. */
3874  amount *= best_rating1 + 1;
3875 
3876  if (st2 == NULL) {
3877  /* only one station around */
3878  return UpdateStationWaiting(st1, type, amount, source_type, source_id);
3879  }
3880 
3881  /* several stations around, the best two (highest rating) are in st1 and st2 */
3882  assert(st1 != NULL);
3883  assert(st2 != NULL);
3884  assert(best_rating1 != 0 || best_rating2 != 0);
3885 
3886  /* Then determine the amount the worst station gets. We do it this way as the
3887  * best should get a bonus, which in this case is the rounding difference from
3888  * this calculation. In reality that will mean the bonus will be pretty low.
3889  * Nevertheless, the best station should always get the most cargo regardless
3890  * of rounding issues. */
3891  uint worst_cargo = amount * best_rating2 / (best_rating1 + best_rating2);
3892  assert(worst_cargo <= (amount - worst_cargo));
3893 
3894  /* And then send the cargo to the stations! */
3895  uint moved = UpdateStationWaiting(st1, type, amount - worst_cargo, source_type, source_id);
3896  /* These two UpdateStationWaiting's can't be in the statement as then the order
3897  * of execution would be undefined and that could cause desyncs with callbacks. */
3898  return moved + UpdateStationWaiting(st2, type, worst_cargo, source_type, source_id);
3899 }
3900 
3901 void BuildOilRig(TileIndex tile)
3902 {
3903  if (!Station::CanAllocateItem()) {
3904  DEBUG(misc, 0, "Can't allocate station for oilrig at 0x%X, reverting to oilrig only", tile);
3905  return;
3906  }
3907 
3908  Station *st = new Station(tile);
3909  st->town = ClosestTownFromTile(tile, UINT_MAX);
3910 
3911  st->string_id = GenerateStationName(st, tile, STATIONNAMING_OILRIG);
3912 
3913  assert(IsTileType(tile, MP_INDUSTRY));
3914  DeleteAnimatedTile(tile);
3915  MakeOilrig(tile, st->index, GetWaterClass(tile));
3916 
3917  st->owner = OWNER_NONE;
3918  st->airport.type = AT_OILRIG;
3919  st->airport.Add(tile);
3920  st->dock_tile = tile;
3922  st->build_date = _date;
3923 
3924  st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE);
3925 
3926  st->UpdateVirtCoord();
3927  UpdateStationAcceptance(st, false);
3929 }
3930 
3931 void DeleteOilRig(TileIndex tile)
3932 {
3933  Station *st = Station::GetByTile(tile);
3934 
3935  MakeWaterKeepingClass(tile, OWNER_NONE);
3936 
3937  st->dock_tile = INVALID_TILE;
3938  st->airport.Clear();
3939  st->facilities &= ~(FACIL_AIRPORT | FACIL_DOCK);
3940  st->airport.flags = 0;
3941 
3942  st->rect.AfterRemoveTile(st, tile);
3943 
3944  st->UpdateVirtCoord();
3946  if (!st->IsInUse()) delete st;
3947 }
3948 
3949 static void ChangeTileOwner_Station(TileIndex tile, Owner old_owner, Owner new_owner)
3950 {
3951  if (IsRoadStopTile(tile)) {
3952  for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) {
3953  /* Update all roadtypes, no matter if they are present */
3954  if (GetRoadOwner(tile, rt) == old_owner) {
3955  if (HasTileRoadType(tile, rt)) {
3956  /* A drive-through road-stop has always two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */
3957  Company::Get(old_owner)->infrastructure.road[rt] -= 2;
3958  if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += 2;
3959  }
3960  SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner);
3961  }
3962  }
3963  }
3964 
3965  if (!IsTileOwner(tile, old_owner)) return;
3966 
3967  if (new_owner != INVALID_OWNER) {
3968  /* Update company infrastructure counts. Only do it here
3969  * if the new owner is valid as otherwise the clear
3970  * command will do it for us. No need to dirty windows
3971  * here, we'll redraw the whole screen anyway.*/
3972  Company *old_company = Company::Get(old_owner);
3973  Company *new_company = Company::Get(new_owner);
3974 
3975  /* Update counts for underlying infrastructure. */
3976  switch (GetStationType(tile)) {
3977  case STATION_RAIL:
3978  case STATION_WAYPOINT:
3979  if (!IsStationTileBlocked(tile)) {
3980  old_company->infrastructure.rail[GetRailType(tile)]--;
3981  new_company->infrastructure.rail[GetRailType(tile)]++;
3982  }
3983  break;
3984 
3985  case STATION_BUS:
3986  case STATION_TRUCK:
3987  /* Road stops were already handled above. */
3988  break;
3989 
3990  case STATION_BUOY:
3991  case STATION_DOCK:
3992  if (GetWaterClass(tile) == WATER_CLASS_CANAL) {
3993  old_company->infrastructure.water--;
3994  new_company->infrastructure.water++;
3995  }
3996  break;
3997 
3998  default:
3999  break;
4000  }
4001 
4002  /* Update station tile count. */
4003  if (!IsBuoy(tile) && !IsAirport(tile)) {
4004  old_company->infrastructure.station--;
4005  new_company->infrastructure.station++;
4006  }
4007 
4008  /* for buoys, owner of tile is owner of water, st->owner == OWNER_NONE */
4009  SetTileOwner(tile, new_owner);
4011  } else {
4012  if (IsDriveThroughStopTile(tile)) {
4013  /* Remove the drive-through road stop */
4014  DoCommand(tile, 1 | 1 << 8, (GetStationType(tile) == STATION_TRUCK) ? ROADSTOP_TRUCK : ROADSTOP_BUS, DC_EXEC | DC_BANKRUPT, CMD_REMOVE_ROAD_STOP);
4015  assert(IsTileType(tile, MP_ROAD));
4016  /* Change owner of tile and all roadtypes */
4017  ChangeTileOwner(tile, old_owner, new_owner);
4018  } else {
4020  /* Set tile owner of water under (now removed) buoy and dock to OWNER_NONE.
4021  * Update owner of buoy if it was not removed (was in orders).
4022  * Do not update when owned by OWNER_WATER (sea and rivers). */
4023  if ((IsTileType(tile, MP_WATER) || IsBuoyTile(tile)) && IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
4024  }
4025  }
4026 }
4027 
4037 {
4038  /* Yeah... water can always remove stops, right? */
4039  if (_current_company == OWNER_WATER) return true;
4040 
4041  RoadTypes rts = GetRoadTypes(tile);
4042  if (HasBit(rts, ROADTYPE_TRAM)) {
4043  Owner tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM);
4044  if (tram_owner != OWNER_NONE && CheckOwnership(tram_owner).Failed()) return false;
4045  }
4046  if (HasBit(rts, ROADTYPE_ROAD)) {
4047  Owner road_owner = GetRoadOwner(tile, ROADTYPE_ROAD);
4048  if (road_owner != OWNER_TOWN) {
4049  if (road_owner != OWNER_NONE && CheckOwnership(road_owner).Failed()) return false;
4050  } else {
4051  if (CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, ROADTYPE_ROAD), OWNER_TOWN, ROADTYPE_ROAD, flags).Failed()) return false;
4052  }
4053  }
4054 
4055  return true;
4056 }
4057 
4065 {
4066  if (flags & DC_AUTO) {
4067  switch (GetStationType(tile)) {
4068  default: break;
4069  case STATION_RAIL: return_cmd_error(STR_ERROR_MUST_DEMOLISH_RAILROAD);
4070  case STATION_WAYPOINT: return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
4071  case STATION_AIRPORT: return_cmd_error(STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST);
4072  case STATION_TRUCK: return_cmd_error(HasTileRoadType(tile, ROADTYPE_TRAM) ? STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST);
4073  case STATION_BUS: return_cmd_error(HasTileRoadType(tile, ROADTYPE_TRAM) ? STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST);
4074  case STATION_BUOY: return_cmd_error(STR_ERROR_BUOY_IN_THE_WAY);
4075  case STATION_DOCK: return_cmd_error(STR_ERROR_MUST_DEMOLISH_DOCK_FIRST);
4076  case STATION_OILRIG:
4077  SetDParam(1, STR_INDUSTRY_NAME_OIL_RIG);
4078  return_cmd_error(STR_ERROR_GENERIC_OBJECT_IN_THE_WAY);
4079  }
4080  }
4081 
4082  switch (GetStationType(tile)) {
4083  case STATION_RAIL: return RemoveRailStation(tile, flags);
4084  case STATION_WAYPOINT: return RemoveRailWaypoint(tile, flags);
4085  case STATION_AIRPORT: return RemoveAirport(tile, flags);
4086  case STATION_TRUCK:
4087  if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) {
4088  return_cmd_error(STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST);
4089  }
4090  return RemoveRoadStop(tile, flags);
4091  case STATION_BUS:
4092  if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) {
4093  return_cmd_error(STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST);
4094  }
4095  return RemoveRoadStop(tile, flags);
4096  case STATION_BUOY: return RemoveBuoy(tile, flags);
4097  case STATION_DOCK: return RemoveDock(tile, flags);
4098  default: break;
4099  }
4100 
4101  return CMD_ERROR;
4102 }
4103 
4104 static CommandCost TerraformTile_Station(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
4105 {
4107  /* TODO: If you implement newgrf callback 149 'land slope check', you have to decide what to do with it here.
4108  * TTDP does not call it.
4109  */
4110  if (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new)) {
4111  switch (GetStationType(tile)) {
4112  case STATION_WAYPOINT:
4113  case STATION_RAIL: {
4114  DiagDirection direction = AxisToDiagDir(GetRailStationAxis(tile));
4115  if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, direction)) break;
4116  if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, ReverseDiagDir(direction))) break;
4117  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
4118  }
4119 
4120  case STATION_AIRPORT:
4121  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
4122 
4123  case STATION_TRUCK:
4124  case STATION_BUS: {
4125  DiagDirection direction = GetRoadStopDir(tile);
4126  if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, direction)) break;
4127  if (IsDriveThroughStopTile(tile)) {
4128  if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, ReverseDiagDir(direction))) break;
4129  }
4130  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
4131  }
4132 
4133  default: break;
4134  }
4135  }
4136  }
4137  return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
4138 }
4139 
4145 uint FlowStat::GetShare(StationID st) const
4146 {
4147  uint32 prev = 0;
4148  for (SharesMap::const_iterator it = this->shares.begin(); it != this->shares.end(); ++it) {
4149  if (it->second == st) {
4150  return it->first - prev;
4151  } else {
4152  prev = it->first;
4153  }
4154  }
4155  return 0;
4156 }
4157 
4164 StationID FlowStat::GetVia(StationID excluded, StationID excluded2) const
4165 {
4166  if (this->unrestricted == 0) return INVALID_STATION;
4167  assert(!this->shares.empty());
4168  SharesMap::const_iterator it = this->shares.upper_bound(RandomRange(this->unrestricted));
4169  assert(it != this->shares.end() && it->first <= this->unrestricted);
4170  if (it->second != excluded && it->second != excluded2) return it->second;
4171 
4172  /* We've hit one of the excluded stations.
4173  * Draw another share, from outside its range. */
4174 
4175  uint end = it->first;
4176  uint begin = (it == this->shares.begin() ? 0 : (--it)->first);
4177  uint interval = end - begin;
4178  if (interval >= this->unrestricted) return INVALID_STATION; // Only one station in the map.
4179  uint new_max = this->unrestricted - interval;
4180  uint rand = RandomRange(new_max);
4181  SharesMap::const_iterator it2 = (rand < begin) ? this->shares.upper_bound(rand) :
4182  this->shares.upper_bound(rand + interval);
4183  assert(it2 != this->shares.end() && it2->first <= this->unrestricted);
4184  if (it2->second != excluded && it2->second != excluded2) return it2->second;
4185 
4186  /* We've hit the second excluded station.
4187  * Same as before, only a bit more complicated. */
4188 
4189  uint end2 = it2->first;
4190  uint begin2 = (it2 == this->shares.begin() ? 0 : (--it2)->first);
4191  uint interval2 = end2 - begin2;
4192  if (interval2 >= new_max) return INVALID_STATION; // Only the two excluded stations in the map.
4193  new_max -= interval2;
4194  if (begin > begin2) {
4195  Swap(begin, begin2);
4196  Swap(end, end2);
4197  Swap(interval, interval2);
4198  }
4199  rand = RandomRange(new_max);
4200  SharesMap::const_iterator it3 = this->shares.upper_bound(this->unrestricted);
4201  if (rand < begin) {
4202  it3 = this->shares.upper_bound(rand);
4203  } else if (rand < begin2 - interval) {
4204  it3 = this->shares.upper_bound(rand + interval);
4205  } else {
4206  it3 = this->shares.upper_bound(rand + interval + interval2);
4207  }
4208  assert(it3 != this->shares.end() && it3->first <= this->unrestricted);
4209  return it3->second;
4210 }
4211 
4218 {
4219  assert(!this->shares.empty());
4220  SharesMap new_shares;
4221  uint i = 0;
4222  for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) {
4223  new_shares[++i] = it->second;
4224  if (it->first == this->unrestricted) this->unrestricted = i;
4225  }
4226  this->shares.swap(new_shares);
4227  assert(!this->shares.empty() && this->unrestricted <= (--this->shares.end())->first);
4228 }
4229 
4236 void FlowStat::ChangeShare(StationID st, int flow)
4237 {
4238  /* We assert only before changing as afterwards the shares can actually
4239  * be empty. In that case the whole flow stat must be deleted then. */
4240  assert(!this->shares.empty());
4241 
4242  uint removed_shares = 0;
4243  uint added_shares = 0;
4244  uint last_share = 0;
4245  SharesMap new_shares;
4246  for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) {
4247  if (it->second == st) {
4248  if (flow < 0) {
4249  uint share = it->first - last_share;
4250  if (flow == INT_MIN || (uint)(-flow) >= share) {
4251  removed_shares += share;
4252  if (it->first <= this->unrestricted) this->unrestricted -= share;
4253  if (flow != INT_MIN) flow += share;
4254  last_share = it->first;
4255  continue; // remove the whole share
4256  }
4257  removed_shares += (uint)(-flow);
4258  } else {
4259  added_shares += (uint)(flow);
4260  }
4261  if (it->first <= this->unrestricted) this->unrestricted += flow;
4262 
4263  /* If we don't continue above the whole flow has been added or
4264  * removed. */
4265  flow = 0;
4266  }
4267  new_shares[it->first + added_shares - removed_shares] = it->second;
4268  last_share = it->first;
4269  }
4270  if (flow > 0) {
4271  new_shares[last_share + (uint)flow] = st;
4272  if (this->unrestricted < last_share) {
4273  this->ReleaseShare(st);
4274  } else {
4275  this->unrestricted += flow;
4276  }
4277  }
4278  this->shares.swap(new_shares);
4279 }
4280 
4286 void FlowStat::RestrictShare(StationID st)
4287 {
4288  assert(!this->shares.empty());
4289  uint flow = 0;
4290  uint last_share = 0;
4291  SharesMap new_shares;
4292  for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) {
4293  if (flow == 0) {
4294  if (it->first > this->unrestricted) return; // Not present or already restricted.
4295  if (it->second == st) {
4296  flow = it->first - last_share;
4297  this->unrestricted -= flow;
4298  } else {
4299  new_shares[it->first] = it->second;
4300  }
4301  } else {
4302  new_shares[it->first - flow] = it->second;
4303  }
4304  last_share = it->first;
4305  }
4306  if (flow == 0) return;
4307  new_shares[last_share + flow] = st;
4308  this->shares.swap(new_shares);
4309  assert(!this->shares.empty());
4310 }
4311 
4317 void FlowStat::ReleaseShare(StationID st)
4318 {
4319  assert(!this->shares.empty());
4320  uint flow = 0;
4321  uint next_share = 0;
4322  bool found = false;
4323  for (SharesMap::reverse_iterator it(this->shares.rbegin()); it != this->shares.rend(); ++it) {
4324  if (it->first < this->unrestricted) return; // Note: not <= as the share may hit the limit.
4325  if (found) {
4326  flow = next_share - it->first;
4327  this->unrestricted += flow;
4328  break;
4329  } else {
4330  if (it->first == this->unrestricted) return; // !found -> Limit not hit.
4331  if (it->second == st) found = true;
4332  }
4333  next_share = it->first;
4334  }
4335  if (flow == 0) return;
4336  SharesMap new_shares;
4337  new_shares[flow] = st;
4338  for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) {
4339  if (it->second != st) {
4340  new_shares[flow + it->first] = it->second;
4341  } else {
4342  flow = 0;
4343  }
4344  }
4345  this->shares.swap(new_shares);
4346  assert(!this->shares.empty());
4347 }
4348 
4354 void FlowStat::ScaleToMonthly(uint runtime)
4355 {
4356  assert(runtime > 0);
4357  SharesMap new_shares;
4358  uint share = 0;
4359  for (SharesMap::iterator i = this->shares.begin(); i != this->shares.end(); ++i) {
4360  share = max(share + 1, i->first * 30 / runtime);
4361  new_shares[share] = i->second;
4362  if (this->unrestricted == i->first) this->unrestricted = share;
4363  }
4364  this->shares.swap(new_shares);
4365 }
4366 
4373 void FlowStatMap::AddFlow(StationID origin, StationID via, uint flow)
4374 {
4375  FlowStatMap::iterator origin_it = this->find(origin);
4376  if (origin_it == this->end()) {
4377  this->insert(std::make_pair(origin, FlowStat(via, flow)));
4378  } else {
4379  origin_it->second.ChangeShare(via, flow);
4380  assert(!origin_it->second.GetShares()->empty());
4381  }
4382 }
4383 
4392 void FlowStatMap::PassOnFlow(StationID origin, StationID via, uint flow)
4393 {
4394  FlowStatMap::iterator prev_it = this->find(origin);
4395  if (prev_it == this->end()) {
4396  FlowStat fs(via, flow);
4397  fs.AppendShare(INVALID_STATION, flow);
4398  this->insert(std::make_pair(origin, fs));
4399  } else {
4400  prev_it->second.ChangeShare(via, flow);
4401  prev_it->second.ChangeShare(INVALID_STATION, flow);
4402  assert(!prev_it->second.GetShares()->empty());
4403  }
4404 }
4405 
4411 {
4412  for (FlowStatMap::iterator i = this->begin(); i != this->end(); ++i) {
4413  FlowStat &fs = i->second;
4414  uint local = fs.GetShare(INVALID_STATION);
4415  if (local > INT_MAX) { // make sure it fits in an int
4416  fs.ChangeShare(self, -INT_MAX);
4417  fs.ChangeShare(INVALID_STATION, -INT_MAX);
4418  local -= INT_MAX;
4419  }
4420  fs.ChangeShare(self, -(int)local);
4421  fs.ChangeShare(INVALID_STATION, -(int)local);
4422 
4423  /* If the local share is used up there must be a share for some
4424  * remote station. */
4425  assert(!fs.GetShares()->empty());
4426  }
4427 }
4428 
4436 {
4437  StationIDStack ret;
4438  for (FlowStatMap::iterator f_it = this->begin(); f_it != this->end();) {
4439  FlowStat &s_flows = f_it->second;
4440  s_flows.ChangeShare(via, INT_MIN);
4441  if (s_flows.GetShares()->empty()) {
4442  ret.Push(f_it->first);
4443  this->erase(f_it++);
4444  } else {
4445  ++f_it;
4446  }
4447  }
4448  return ret;
4449 }
4450 
4455 void FlowStatMap::RestrictFlows(StationID via)
4456 {
4457  for (FlowStatMap::iterator it = this->begin(); it != this->end(); ++it) {
4458  it->second.RestrictShare(via);
4459  }
4460 }
4461 
4466 void FlowStatMap::ReleaseFlows(StationID via)
4467 {
4468  for (FlowStatMap::iterator it = this->begin(); it != this->end(); ++it) {
4469  it->second.ReleaseShare(via);
4470  }
4471 }
4472 
4478 {
4479  uint ret = 0;
4480  for (FlowStatMap::const_iterator i = this->begin(); i != this->end(); ++i) {
4481  ret += (--(i->second.GetShares()->end()))->first;
4482  }
4483  return ret;
4484 }
4485 
4491 uint FlowStatMap::GetFlowVia(StationID via) const
4492 {
4493  uint ret = 0;
4494  for (FlowStatMap::const_iterator i = this->begin(); i != this->end(); ++i) {
4495  ret += i->second.GetShare(via);
4496  }
4497  return ret;
4498 }
4499 
4505 uint FlowStatMap::GetFlowFrom(StationID from) const
4506 {
4507  FlowStatMap::const_iterator i = this->find(from);
4508  if (i == this->end()) return 0;
4509  return (--(i->second.GetShares()->end()))->first;
4510 }
4511 
4518 uint FlowStatMap::GetFlowFromVia(StationID from, StationID via) const
4519 {
4520  FlowStatMap::const_iterator i = this->find(from);
4521  if (i == this->end()) return 0;
4522  return i->second.GetShare(via);
4523 }
4524 
4525 extern const TileTypeProcs _tile_type_station_procs = {
4526  DrawTile_Station, // draw_tile_proc
4527  GetSlopePixelZ_Station, // get_slope_z_proc
4528  ClearTile_Station, // clear_tile_proc
4529  NULL, // add_accepted_cargo_proc
4530  GetTileDesc_Station, // get_tile_desc_proc
4531  GetTileTrackStatus_Station, // get_tile_track_status_proc
4532  ClickTile_Station, // click_tile_proc
4533  AnimateTile_Station, // animate_tile_proc
4534  TileLoop_Station, // tile_loop_proc
4535  ChangeTileOwner_Station, // change_tile_owner_proc
4536  NULL, // add_produced_cargo_proc
4537  VehicleEnter_Station, // vehicle_enter_tile_proc
4538  GetFoundation_Station, // get_foundation_proc
4539  TerraformTile_Station, // terraform_tile_proc
4540 };
Functions related to OTTD&#39;s strings.
void TriggerStationRandomisation(Station *st, TileIndex tile, StationRandomTrigger trigger, CargoID cargo_type)
Trigger station randomisation.
List of scheduled road vehs button.
Road vehicle states.
don&#39;t allow building on structures
Definition: command_type.h:343
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:556
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:520
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:324
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:309
uint32 PaletteID
The number of the palette.
Definition: gfx_type.h:20
static void MakeDock(TileIndex t, Owner o, StationID sid, DiagDirection d, WaterClass wc)
Make the given tile a dock tile.
Definition: station_map.h:650
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
byte state
Definition: roadveh.h:89
static uint MapSizeX()
Get the size of the map along the X.
Definition: map_func.h:74
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:77
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:157
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:482
bool enabled
entity still available (by default true).newgrf can disable it, though
Definition: industrytype.h:135
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:296
static TropicZone GetTropicZone(TileIndex tile)
Get the tropic zone.
Definition: tile_map.h:231
Select station (when joining stations); Window numbers:
Definition: window_type.h:237
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
static void SetAnimationFrame(TileIndex t, byte frame)
Set a new animation frame.
Definition: tile_map.h:255
A standard stop for trucks.
Definition: station_type.h:49
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:470
Rect GetCatchmentRect() const
Determines catchment rectangle of this station.
Definition: station.cpp:294
const AirportSpec * GetSpec() const
Get the AirportSpec that from the airport type of this airport.
Definition: station_base.h:320
static void SetTileOwner(TileIndex tile, Owner owner)
Sets the owner of a tile.
Definition: tile_map.h:191
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:456
CompanyMask statues
which companies have a statue?
Definition: town.h:70
Definition of link refreshing utility.
StationID targetairport
Airport to go to next.
Definition: aircraft.h:78
CommandCost GetStationAround(TileArea ta, StationID closest_station, T **st)
Look for a station around the given tile area.
Definition: station_cmd.cpp:99
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.
CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, RoadType rt, DoCommandFlag flags, bool town_check)
Is it allowed to remove the given road bits from the given tile?
Definition: road_cmd.cpp:116
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:1153
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition: window.cpp:3120
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:68
void AddAnimatedTile(TileIndex tile)
Add the given tile to the animated tile table (if it does not exist on that table yet)...
DirectionByte direction
facing
Definition: vehicle_base.h:271
byte size_y
size of airport in y direction
Iterator to iterate over all tiles belonging to an airport.
Definition: station_base.h:512
company buildings - depots, stations, HQ, ...
Definition: transparency.h:29
RailType
Enumeration for all possible railtypes.
Definition: rail_type.h:29
Base class for roadstops.
Non-existing type of vehicle.
Definition: vehicle_type.h:35
static bool IsReversingRoadTrackdir(Trackdir dir)
Checks whether the trackdir means that we are reversing.
Definition: track_func.h:661
Tile is desert.
Definition: tile_type.h:73
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:267
uint16 triggers
The triggers that trigger animation.
East.
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:410
static bool IsRailStation(TileIndex t)
Is this station tile a rail station?
Definition: station_map.h:93
Part of an industry.
Definition: tile_type.h:51
EconomySettings economy
settings to change the economy
static RoadBits GetAllRoadBits(TileIndex tile)
Get all set RoadBits on the given tile.
Definition: road_map.h:139
static RoadStopType GetRoadStopType(TileIndex t)
Get the road stop type of this tile.
Definition: station_map.h:57
CommandCost EnsureNoVehicleOnGround(TileIndex tile)
Ensure there is no vehicle at the ground at the given position.
Definition: vehicle.cpp:538
Flag for an invalid DiagDirection.
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:141
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:106
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
CompanyByte exclusivity
which company has exclusivity
Definition: town.h:75
static const AirportTileSpec * GetByTile(TileIndex tile)
Retrieve airport tile spec for the given airport tile.
Basic road type.
Definition: road_type.h:24
static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags)
Remove an airport.
Base for the train class.
The vehicle is in a drive-through road stop.
Definition: roadveh.h:47
static byte GetAnimationFrame(TileIndex t)
Get the current animation frame.
Definition: tile_map.h:243
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.
Functions related to debugging.
static T SetBit(T &x, const uint8 y)
Set a bit in a variable.
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...
Track
These are used to specify a single track.
Definition: track_type.h:21
Can planes land on this airport type?
Definition: airport.h:148
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
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
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:211
Functions used internally by the roads.
Used for iterations.
Definition: road_type.h:26
Specification of a cargo type.
Definition: cargotype.h:56
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...
TileIndex dock_tile
The location of the dock.
Definition: station_base.h:461
IndustryLifeType life_type
This is also known as Industry production flag, in newgrf specs.
Definition: industrytype.h:118
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:198
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:203
Transport over water.
Functions related to vehicles.
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition: aircraft.h:74
Set when cargo was delivered for final delivery this month.
Definition: station_base.h:205
Manual distribution. No link graph calculations are run.
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:344
static DiagDirection GetDockDirection(TileIndex t)
Get the direction of a dock.
Definition: station_map.h:430
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:48
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:662
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.
static bool HasTileRoadType(TileIndex t, RoadType rt)
Check if a tile has a specific road type.
Definition: road_map.h:188
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:39
const T * Begin() const
Get the pointer to the first item (const)
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:2152
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:170
Tindex index
Index of this pool item.
Definition: pool_type.hpp:147
Vehicle is flying in the air.
Definition: airport.h:77
static RoadBits GetRoadBits(TileIndex t, RoadType rt)
Get the present road bits for a specific road type.
Definition: road_map.h:111
#define FOR_EACH_SET_ROADTYPE(var, road_types)
Iterate through each set RoadType in a RoadTypes value.
Definition: road_func.h:28
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:245
Northeast, upper right on your monitor.
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
T * First() const
Get the first vehicle in the chain.
static void FreeTrainReservation(Train *v)
Clear platform reservation during station building/removing.
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
Simple vector template class.
void MarkTilesDirty(bool cargo_change) const
Marks the tiles of the station as dirty.
Definition: station.cpp:203
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:350
CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st)
Find a nearby station that joins this station.
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.
#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:224
Used for iterations.
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:785
RoadType
The different roadtypes we support.
Definition: road_type.h:22
StationCargoList cargo
The cargo packets of cargo waiting in this station.
Definition: station_base.h:255
static T max(const T a, const T b)
Returns the maximum of two values.
Definition: math_func.hpp:26
uint16 classes
Classes of this cargo type.
Definition: cargotype.h:79
static bool IsDriveThroughStopTile(TileIndex t)
Is tile t a drive through road stop station?
Definition: station_map.h:234
Town * town
The town this station is associated with.
bool HasRating() const
Does this cargo have a rating at this station?
Definition: station_base.h:273
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:427
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:41
bool IsTileFlat(TileIndex tile, int *h)
Check if a given tile is flat.
Definition: tile_map.cpp:159
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:67
const T * End() const
Get the pointer behind the last valid item (const)
Waypoint class.
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:121
int z
Height.
Definition: tile_cmd.h:49
static StationType GetStationType(TileIndex t)
Get the station type of this tile.
Definition: station_map.h:45
StationSettings station
settings related to station management
GoodsEntry goods[NUM_CARGO]
Goods at this station.
Definition: station_base.h:472
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:47
void DrawFoundation(TileInfo *ti, Foundation f)
Draw foundation f at tile ti.
Definition: landscape.cpp:390
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
Direction
Defines the 8 directions on the map.
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:494
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:642
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:116
CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags)
Clear a single tile of a station.
uint32 free_names
Current bitset of free names (we can remove names).
T * Append(uint to_add=1)
Append an item and return it.
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 NULL, end of list.
Definition: order_base.h:51
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:182
CompanyByte _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:46
company bankrupts, skip money check, skip vehicle on tile check in some cases
Definition: command_type.h:348
Functions related to (drawing on) viewports.
Pseudo random number generator.
uint32 always_accepted
Bitmask of always accepted cargo types (by houses, HQs, industry tiles when industry doesn&#39;t accept c...
Definition: station_base.h:473
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:136
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:279
Right track.
Definition: track_type.h:48
bool freeform_edges
allow terraforming the tiles at the map edges
CommandCost CanExpandRailStation(const BaseStation *st, TileArea &new_ta, Axis axis)
Check whether we can expand the rail part of the given station.
Set when cargo was delivered for final delivery last month.
Definition: station_base.h:199
Slope GetTileSlope(TileIndex tile, int *h)
Return the slope of a given tile inside the map.
Definition: tile_map.cpp:115
static bool IsValidTile(TileIndex tile)
Checks if a tile is valid.
Definition: tile_map.h:154
SpriteID single_y
single piece of rail in Y direction, without ground
Definition: rail.h:127
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition: viewport.cpp:795
void ScaleToMonthly(uint runtime)
Scale all shares from link graph&#39;s runtime to monthly values.
Triggered in the periodic tile loop.
static bool IsBridgeAbove(TileIndex t)
checks if a bridge is set above the ground of this tile
Definition: bridge_map.h:45
void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
Mark window data of all windows of a given class as invalid (in need of re-computing) Note that by de...
Definition: window.cpp:3238
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:379
Station is a waypoint.
Definition: station_type.h:60
TrackBits
Bitfield corresponding to Track.
Definition: track_type.h:41
Buses, trucks and trams belong to this class.
Definition: roadveh.h:88
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:2259
static bool IsTileOwner(TileIndex tile, Owner owner)
Checks if a tile belongs to the given owner.
Definition: tile_map.h:207
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:3239
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
Maximal number of airports in total.
Definition: airport.h:43
Aircraft vehicle type.
Definition: vehicle_type.h:27
Tile animation!
byte noise_level
noise that this airport generates
uint GetShare(StationID st) const
Get flow for a station.
static bool CanRemoveRoadWithStop(TileIndex tile, DoCommandFlag flags)
Check if a drive-through road stop tile can be cleared.
void RestrictFlows(StationID via)
Restrict all flows at a station for specific cargo and destination.
Functions related to low-level strings.
byte amount_fract
Fractional part of the amount in the cargo list.
Definition: station_base.h:254
SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg, TileContext context, uint *num_results)
Get the sprite to draw for the given tile.
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
byte rating
Station rating for this cargo.
Definition: station_base.h:235
static TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition: map_func.h:343
OrthogonalTileArea TileArea
Shorthand for the much more common orthogonal tile area.
Definition: tilearea_type.h:96
EdgeIterator End()
Get an iterator pointing beyond the end of the edges array.
Definition: linkgraph.h: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:506
static bool IsBuoy(TileIndex t)
Is tile t a buoy tile?
Definition: station_map.h:307
static bool IsTileType(TileIndex tile, TileType type)
Checks if a tile is a give tiletype.
Definition: tile_map.h:143
All possible tracks.
Definition: track_type.h:56
Triggered when the airport is built (for all tiles at the same time).
CommandCost RemoveFromRailBaseStation(TileArea ta, SmallVector< T *, 4 > &affected_stations, DoCommandFlag flags, Money removal_cost, bool keep_rail)
Remove a number of tiles from any rail station within the area.
static void MakeAirport(TileIndex t, Owner o, StationID sid, byte section, WaterClass wc)
Make the given tile an airport tile.
Definition: station_map.h:623
void UpdateVirtCoord()
Update the virtual coords needed to draw the station sign.
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:127
Track along the y-axis (north-west to south-east)
Definition: track_type.h:24
CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags)
Shorthand for calling the long DoCommand with a container.
Definition: command.cpp:436
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:457
This indicates whether a cargo has a rating at the station.
Definition: station_base.h:187
uint Length() const
Get the number of items in the list.
StationID GetVia(StationID source) const
Get the best next hop for a cargo packet from station source.
Definition: station_base.h:283
void Add(TileIndex to_add)
Add a single tile to a tile area; enlarge if needed.
Definition: tilearea.cpp:45
static int CountMapSquareAround(TileIndex tile, CMSAMatcher cmp)
Counts the numbers of tiles matching a specific type in the area around.
static Owner GetRoadOwner(TileIndex t, RoadType rt)
Get the owner of a specific road type.
Definition: road_map.h:199
StringID owner_type[4]
Type of each owner.
Definition: tile_cmd.h:56
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:257
West.
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:394
static bool IsRailStationTile(TileIndex t)
Is this tile a station tile and a rail station?
Definition: station_map.h:103
X-axis track.
Definition: track_type.h:43
Ground palette sprite of a tile, together with its sprite layout.
Definition: sprite.h:60
#define FIND_FIRST_BIT(x)
Returns the first non-zero bit in a 6-bit value (from right).
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:81
static void SetRoadOwner(TileIndex t, RoadType rt, Owner o)
Set the owner of a specific road type.
Definition: road_map.h:220
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:41
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:181
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:134
static DiagDirection GetRoadStopDir(TileIndex t)
Gets the direction the road stop entrance points towards.
Definition: station_map.h:258
bool HasRoadTypesAvail(const CompanyID company, const RoadTypes rts)
Finds out, whether given company has all given RoadTypes available.
Definition: road.cpp:110
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:458
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:171
static DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
DoCommandFlag
List of flags for a command.
Definition: command_type.h:340
bool Intersects(const OrthogonalTileArea &ta) const
Does this tile area intersect with another?
Definition: tilearea.cpp:77
Southeast.
Southwest.
GRFFilePropsBase< NUM_CARGO+3 > grf_prop
Properties related the the grf file.
Station with truck stops.
Definition: station_type.h:56
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:76
byte status
Status of this cargo, see GoodsEntryStatus.
Definition: station_base.h:226
Piece of rail in X direction.
Definition: rail.h:60
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:147
void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage, EdgeUpdateMode mode)
Increase capacity for a link stat given by station cargo and next hop.
const IndustrySpec * GetIndustrySpec(IndustryType thistype)
Accessor for array _industry_specs.
byte layout
Airport layout number.
Definition: station_base.h:310
void DeleteAnimatedTile(TileIndex tile)
Removes the given tile from the animated tile table.
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
CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, uint32 *always_accepted)
Get the acceptance of cargoes around the tile in 1/8.
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:195
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.
uint32 road[ROADTYPE_END]
Count of company owned track bits for each road type.
Definition: company_base.h:32
A number of safeguards to prevent using unsafe methods.
Trams.
Definition: road_type.h:25
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.
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:129
IndustryType type
type of industry.
Definition: industry.h:55
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
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:338
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:46
uint8 GetAirportNoiseLevelForTown(const AirportSpec *as, TileIterator &it, TileIndex town_tile)
Get a possible noise reduction factor based on distance from town center.
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:69
Trackdir
Enumeration for tracks and directions.
Definition: track_type.h:74
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:1092
uint GetCatchmentRadius() const
Determines the catchment radius of the station.
Definition: station.cpp:271
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:40
byte num_table
number of elements in the table
Used for iterations.
NodeID node
ID of node in link graph referring to this goods entry.
Definition: station_base.h:258
void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec)
Create the station layout for the given number of tracks and platform length.
static bool CMSAMine(TileIndex tile)
Check whether the tile is a mine.
CommandCost CheckFlatLand(TileArea tile_area, DoCommandFlag flags)
Tries to clear the given area.
bool IsHangar(TileIndex t)
Check whether the given tile is a hangar.
Definition: station_cmd.cpp:74
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:317
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:126
GUI Functions related to companies.
PBS support routines.
static bool IsAirport(TileIndex t)
Is this station tile an airport?
Definition: station_map.h:158
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:882
bool road_stop_on_town_road
allow building of drive-through road stops on town owned roads
Trigger station on new cargo arrival.
void RecomputeIndustriesNear()
Recomputes Station::industries_near, list of industries possibly accepting cargo in station&#39;s catchme...
Definition: station.cpp:357
uint16 max_speed
Maximum speed for vehicles travelling on this rail type.
Definition: rail.h:220
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:497
Set when a sprite originates from an Action 1.
Definition: sprites.h:1506
TileIndex tile
Current tile index.
Definition: vehicle_base.h:230
Defines the data structure for constructing industry.
Definition: industrytype.h:101
StationSpecList * speclist
List of station specs of this station.
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
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.
Definition: tilearea_type.h:99
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
The tile has no ownership.
Definition: company_type.h:27
static const AirportSpec * Get(byte type)
Retrieve airport spec for the given airport.
PersistentStorage * psa
Persistent storage for NewGRF airports.
Definition: station_base.h:313
CargoID produced_cargo[2]
2 production cargo slots
Definition: industry.h:42
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.
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:86
SpriteID single_x
single piece of rail in X direction, without ground
Definition: rail.h:126
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...
StationFacilityByte facilities
The facilities that this station has.
void AddFlow(StationID origin, StationID via, uint amount)
Add some flow from "origin", going via "via".
uint64 flags
stores which blocks on the airport are taken. was 16 bit earlier on, then 32
Definition: station_base.h:308
CommandCost CmdRenameStation(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Rename a station.
static const SharesMap empty_sharesmap
Static instance of FlowStat::SharesMap.
Definition: station_base.h:40
DiagDirection
Enumeration for diagonal directions.
Catchment for all stations with "modified catchment" disabled.
Definition: station_type.h:87
#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:246
Road vehicle type.
Definition: vehicle_type.h:25
Invalid cargo type.
Definition: cargo_type.h:70
uint8 cached_anim_triggers
NOSAVE: Combined animation trigger bitmask, used to determine if trigger processing should happen...
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
StringID airport_tile_name
Name of the airport tile.
Definition: tile_cmd.h:62
RoadBits GetAnyRoadBits(TileIndex tile, RoadType rt, bool straight_tunnel_bridge_entrance)
Returns the RoadBits on an arbitrary tile Special behaviour:
Definition: road_map.cpp:35
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:61
Station with a dock.
Definition: station_type.h:59
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:61
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:376
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:252
const struct SpriteGroup * spritegroup[Tcnt]
pointer to the different sprites of the entity
TileIndex GetHangarTile(uint hangar_num) const
Get the first tile of the given hangar.
Definition: station_base.h:373
static StationGfx GetStationGfx(TileIndex t)
Get the station graphics of this tile.
Definition: station_map.h:69
DirectionByte rotation
How this airport is rotated.
Definition: station_base.h:311
All ships have this type.
Definition: ship.h:24
RoadTypes
The different roadtypes we support, but then a bitmask of them.
Definition: road_type.h:36
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:455
uint16 MaxTownNoise() const
Calculate the max town noise.
Definition: town.h:122
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:688
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:79
uint Truncate(uint max_move=UINT_MAX, StationCargoAmountMap *cargo_per_source=NULL)
Truncates where each destination loses roughly the same percentage of its cargo.
#define FOR_ALL_SHIPS(var)
Iterate over all ships.
Definition: ship.h:55
void DrawRoadCatenary(const TileInfo *ti, RoadBits tram)
Draws the catenary for the given tile.
Definition: road_cmd.cpp:1194
Station list; Window numbers:
Definition: window_type.h:297
Ship vehicle type.
Definition: vehicle_type.h:26
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:73
FlowStatMap flows
Planned flows through this station.
Definition: station_base.h:259
TileIndex TileAddWrap(TileIndex tile, int addx, int addy)
This function checks if we add addx/addy to tile, if we do wrap around the edges. ...
Definition: map.cpp:116
CommandCost FindJoiningWaypoint(StationID existing_waypoint, StationID waypoint_to_join, bool adjacent, TileArea ta, Waypoint **wp)
Find a nearby waypoint that joins this waypoint.
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:39
&#39;Train&#39; is either a loco or a wagon.
Definition: train.h:88
uint8 FindFirstBit(uint32 x)
Search the first set bit in a 32 bit variable.
SourceType
Types of cargo source and destination.
Definition: cargo_type.h:139
void ChangeShare(StationID st, int flow)
Change share for specified station.
Maximal number of cargo types in a game.
Definition: cargo_type.h:66
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...
OwnerByte owner
The owner of this station.
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset)
Mark a tile given by its index dirty for repaint.
Definition: viewport.cpp:1904
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:58
static TrackBits GetTrackBits(TileIndex tile)
Gets the track bits of the given tile.
Definition: rail_map.h:137
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:125
The X axis.
uint32 rail[RAILTYPE_END]
Count of company owned track bits for each rail type.
Definition: company_base.h:34
void DeleteWindowById(WindowClass cls, WindowNumber number, bool force)
Delete a window by its class and window number (if it is open).
Definition: window.cpp:1137
void ReleaseShare(StationID st)
Release ("unrestrict") a flow by moving it to the begin of the map and increasing the amount of unres...
Construction costs.
Definition: economy_type.h:151
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:342
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
uint GetHangarNum(TileIndex tile) const
Get the hangar number of the hangar at a specific tile.
Definition: station_base.h:403
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:3193
static StationID GetStationIndex(TileIndex t)
Get StationID from a tile.
Definition: station_map.h:29
Tile got trees.
Definition: tile_type.h:47
List of scheduled ships button.
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:35
this bit is set when a recolouring process is in action
Definition: sprites.h:1509
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:74
static bool IsNormalRoadTile(TileIndex t)
Return whether a tile is a normal road tile.
Definition: road_map.h:57
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.
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:4032
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