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