OpenTTD Source  20241120-master-g6d3adc6169
rail_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 "viewport_func.h"
12 #include "command_func.h"
13 #include "depot_base.h"
15 #include "newgrf_debug.h"
16 #include "newgrf_railtype.h"
17 #include "train.h"
18 #include "autoslope.h"
19 #include "water.h"
20 #include "tunnelbridge_map.h"
21 #include "vehicle_func.h"
22 #include "sound_func.h"
23 #include "tunnelbridge.h"
24 #include "elrail_func.h"
25 #include "town.h"
26 #include "pbs.h"
27 #include "company_base.h"
28 #include "core/backup_type.hpp"
29 #include "core/container_func.hpp"
31 #include "strings_func.h"
32 #include "company_gui.h"
33 #include "object_map.h"
34 #include "rail_cmd.h"
35 #include "landscape_cmd.h"
36 
37 #include "table/strings.h"
38 #include "table/railtypes.h"
39 #include "table/track_land.h"
40 
41 #include "safeguards.h"
42 
44 typedef std::vector<Train *> TrainList;
45 
46 RailTypeInfo _railtypes[RAILTYPE_END];
47 std::vector<RailType> _sorted_railtypes;
48 RailTypes _railtypes_hidden_mask;
49 
52  SIGNAL_TO_SOUTHWEST,
53  SIGNAL_TO_NORTHEAST,
54  SIGNAL_TO_SOUTHEAST,
55  SIGNAL_TO_NORTHWEST,
56  SIGNAL_TO_EAST,
57  SIGNAL_TO_WEST,
58  SIGNAL_TO_SOUTH,
59  SIGNAL_TO_NORTH,
60 };
61 
66 {
67  static_assert(lengthof(_original_railtypes) <= lengthof(_railtypes));
68 
69  auto insert = std::copy(std::begin(_original_railtypes), std::end(_original_railtypes), std::begin(_railtypes));
70  std::fill(insert, std::end(_railtypes), RailTypeInfo{});
71 
72  _railtypes_hidden_mask = RAILTYPES_NONE;
73 }
74 
75 void ResolveRailTypeGUISprites(RailTypeInfo *rti)
76 {
78  if (cursors_base != 0) {
79  rti->gui_sprites.build_ns_rail = cursors_base + 0;
80  rti->gui_sprites.build_x_rail = cursors_base + 1;
81  rti->gui_sprites.build_ew_rail = cursors_base + 2;
82  rti->gui_sprites.build_y_rail = cursors_base + 3;
83  rti->gui_sprites.auto_rail = cursors_base + 4;
84  rti->gui_sprites.build_depot = cursors_base + 5;
85  rti->gui_sprites.build_tunnel = cursors_base + 6;
86  rti->gui_sprites.convert_rail = cursors_base + 7;
87  rti->cursor.rail_ns = cursors_base + 8;
88  rti->cursor.rail_swne = cursors_base + 9;
89  rti->cursor.rail_ew = cursors_base + 10;
90  rti->cursor.rail_nwse = cursors_base + 11;
91  rti->cursor.autorail = cursors_base + 12;
92  rti->cursor.depot = cursors_base + 13;
93  rti->cursor.tunnel = cursors_base + 14;
94  rti->cursor.convert = cursors_base + 15;
95  }
96 
97  /* Array of default GUI signal sprite numbers. */
98  const SpriteID _signal_lookup[2][SIGTYPE_END] = {
99  {SPR_IMG_SIGNAL_ELECTRIC_NORM, SPR_IMG_SIGNAL_ELECTRIC_ENTRY, SPR_IMG_SIGNAL_ELECTRIC_EXIT,
100  SPR_IMG_SIGNAL_ELECTRIC_COMBO, SPR_IMG_SIGNAL_ELECTRIC_PBS, SPR_IMG_SIGNAL_ELECTRIC_PBS_OWAY},
101 
102  {SPR_IMG_SIGNAL_SEMAPHORE_NORM, SPR_IMG_SIGNAL_SEMAPHORE_ENTRY, SPR_IMG_SIGNAL_SEMAPHORE_EXIT,
103  SPR_IMG_SIGNAL_SEMAPHORE_COMBO, SPR_IMG_SIGNAL_SEMAPHORE_PBS, SPR_IMG_SIGNAL_SEMAPHORE_PBS_OWAY},
104  };
105 
106  for (SignalType type = SIGTYPE_BLOCK; type < SIGTYPE_END; type = (SignalType)(type + 1)) {
107  for (SignalVariant var = SIG_ELECTRIC; var <= SIG_SEMAPHORE; var = (SignalVariant)(var + 1)) {
108  SpriteID red = GetCustomSignalSprite(rti, INVALID_TILE, type, var, SIGNAL_STATE_RED, true);
109  SpriteID green = GetCustomSignalSprite(rti, INVALID_TILE, type, var, SIGNAL_STATE_GREEN, true);
110  rti->gui_sprites.signals[type][var][0] = (red != 0) ? red + SIGNAL_TO_SOUTH : _signal_lookup[var][type];
111  rti->gui_sprites.signals[type][var][1] = (green != 0) ? green + SIGNAL_TO_SOUTH : _signal_lookup[var][type] + 1;
112  }
113  }
114 }
115 
122 static bool CompareRailTypes(const RailType &first, const RailType &second)
123 {
125 }
126 
131 {
132  for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
133  RailTypeInfo *rti = &_railtypes[rt];
134  ResolveRailTypeGUISprites(rti);
135  if (HasBit(rti->flags, RTF_HIDDEN)) SetBit(_railtypes_hidden_mask, rt);
136  }
137 
138  _sorted_railtypes.clear();
139  for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
140  if (_railtypes[rt].label != 0 && !HasBit(_railtypes_hidden_mask, rt)) {
141  _sorted_railtypes.push_back(rt);
142  }
143  }
144  std::sort(_sorted_railtypes.begin(), _sorted_railtypes.end(), CompareRailTypes);
145 }
146 
150 RailType AllocateRailType(RailTypeLabel label)
151 {
152  for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
153  RailTypeInfo *rti = &_railtypes[rt];
154 
155  if (rti->label == 0) {
156  /* Set up new rail type */
158  rti->label = label;
159  rti->alternate_labels.clear();
160 
161  /* Make us compatible with ourself. */
162  rti->powered_railtypes = (RailTypes)(1LL << rt);
163  rti->compatible_railtypes = (RailTypes)(1LL << rt);
164 
165  /* We also introduce ourself. */
166  rti->introduces_railtypes = (RailTypes)(1LL << rt);
167 
168  /* Default sort order; order of allocation, but with some
169  * offsets so it's easier for NewGRF to pick a spot without
170  * changing the order of other (original) rail types.
171  * The << is so you can place other railtypes in between the
172  * other railtypes, the 7 is to be able to place something
173  * before the first (default) rail type. */
174  rti->sorting_order = rt << 4 | 7;
175  return rt;
176  }
177  }
178 
179  return INVALID_RAILTYPE;
180 }
181 
182 static const uint8_t _track_sloped_sprites[14] = {
183  14, 15, 22, 13,
184  0, 21, 17, 12,
185  23, 0, 18, 20,
186  19, 16
187 };
188 
189 
190 /* 4
191  * ---------
192  * |\ /|
193  * | \ 1/ |
194  * | \ / |
195  * | \ / |
196  * 16| \ |32
197  * | / \2 |
198  * | / \ |
199  * | / \ |
200  * |/ \|
201  * ---------
202  * 8
203  */
204 
205 
206 
207 /* MAP2 byte: abcd???? => Signal On? Same coding as map3lo
208  * MAP3LO byte: abcd???? => Signal Exists?
209  * a and b are for diagonals, upper and left,
210  * one for each direction. (ie a == NE->SW, b ==
211  * SW->NE, or v.v., I don't know. b and c are
212  * similar for lower and right.
213  * MAP2 byte: ????abcd => Type of ground.
214  * MAP3LO byte: ????abcd => Type of rail.
215  * MAP5: 00abcdef => rail
216  * 01abcdef => rail w/ signals
217  * 10uuuuuu => unused
218  * 11uuuudd => rail depot
219  */
220 
230 {
231  TrackBits rail_bits = TrackToTrackBits(track);
232  return EnsureNoTrainOnTrackBits(tile, rail_bits);
233 }
234 
242 {
243  if (!IsPlainRail(tile)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
244 
245  /* So, we have a tile with tracks on it (and possibly signals). Let's see
246  * what tracks first */
247  TrackBits current = GetTrackBits(tile); // The current track layout.
248  TrackBits future = current | to_build; // The track layout we want to build.
249 
250  /* Are we really building something new? */
251  if (current == future) {
252  /* Nothing new is being built */
253  return_cmd_error(STR_ERROR_ALREADY_BUILT);
254  }
255 
256  /* Normally, we may overlap and any combination is valid */
257  return CommandCost();
258 }
259 
260 
266  TRACK_BIT_X,
267 
270  TRACK_BIT_Y,
272 
274  TRACK_BIT_Y,
277 
278  TRACK_BIT_X,
281 };
282 
289 
294 
299 
303 };
304 
313 {
314  if (bits == TRACK_BIT_NONE) return FOUNDATION_NONE;
315 
316  if (IsSteepSlope(tileh)) {
317  /* Test for inclined foundations */
318  if (bits == TRACK_BIT_X) return FOUNDATION_INCLINED_X;
319  if (bits == TRACK_BIT_Y) return FOUNDATION_INCLINED_Y;
320 
321  /* Get higher track */
322  Corner highest_corner = GetHighestSlopeCorner(tileh);
323  TrackBits higher_track = CornerToTrackBits(highest_corner);
324 
325  /* Only higher track? */
326  if (bits == higher_track) return HalftileFoundation(highest_corner);
327 
328  /* Overlap with higher track? */
329  if (TracksOverlap(bits | higher_track)) return FOUNDATION_INVALID;
330 
331  /* either lower track or both higher and lower track */
332  return ((bits & higher_track) != 0 ? FOUNDATION_STEEP_BOTH : FOUNDATION_STEEP_LOWER);
333  } else {
334  if ((~_valid_tracks_without_foundation[tileh] & bits) == 0) return FOUNDATION_NONE;
335 
336  bool valid_on_leveled = ((~_valid_tracks_on_leveled_foundation[tileh] & bits) == 0);
337 
338  Corner track_corner;
339  switch (bits) {
340  case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
341  case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
342  case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
343  case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
344 
345  case TRACK_BIT_HORZ:
346  if (tileh == SLOPE_N) return HalftileFoundation(CORNER_N);
347  if (tileh == SLOPE_S) return HalftileFoundation(CORNER_S);
348  return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
349 
350  case TRACK_BIT_VERT:
351  if (tileh == SLOPE_W) return HalftileFoundation(CORNER_W);
352  if (tileh == SLOPE_E) return HalftileFoundation(CORNER_E);
353  return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
354 
355  case TRACK_BIT_X:
357  return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
358 
359  case TRACK_BIT_Y:
361  return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
362 
363  default:
364  return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
365  }
366  /* Single diagonal track */
367 
368  /* Track must be at least valid on leveled foundation */
369  if (!valid_on_leveled) return FOUNDATION_INVALID;
370 
371  /* If slope has three raised corners, build leveled foundation */
373 
374  /* If neighboured corners of track_corner are lowered, build halftile foundation */
375  if ((tileh & SlopeWithThreeCornersRaised(OppositeCorner(track_corner))) == SlopeWithOneCornerRaised(track_corner)) return HalftileFoundation(track_corner);
376 
377  /* else special anti-zig-zag foundation */
378  return SpecialRailFoundation(track_corner);
379  }
380 }
381 
382 
392 static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile)
393 {
394  /* don't allow building on the lower side of a coast */
395  if (GetFloodingBehaviour(tile) != FLOOD_NONE) {
396  if (!IsSteepSlope(tileh) && ((~_valid_tracks_on_leveled_foundation[tileh] & (rail_bits | existing)) != 0)) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
397  }
398 
399  Foundation f_new = GetRailFoundation(tileh, rail_bits | existing);
400 
401  /* check track/slope combination */
402  if ((f_new == FOUNDATION_INVALID) ||
404  return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
405  }
406 
407  Foundation f_old = GetRailFoundation(tileh, existing);
408  return CommandCost(EXPENSES_CONSTRUCTION, f_new != f_old ? _price[PR_BUILD_FOUNDATION] : (Money)0);
409 }
410 
411 /* Validate functions for rail building */
412 static inline bool ValParamTrackOrientation(Track track)
413 {
414  return IsValidTrack(track);
415 }
416 
426 CommandCost CmdBuildSingleRail(DoCommandFlag flags, TileIndex tile, RailType railtype, Track track, bool auto_remove_signals)
427 {
429 
430  if (!ValParamRailType(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
431 
432  Slope tileh = GetTileSlope(tile);
433  TrackBits trackbit = TrackToTrackBits(track);
434 
435  switch (GetTileType(tile)) {
436  case MP_RAILWAY: {
437  CommandCost ret = CheckTileOwnership(tile);
438  if (ret.Failed()) return ret;
439 
440  if (!IsPlainRail(tile)) return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile); // just get appropriate error message
441 
442  if (!IsCompatibleRail(GetRailType(tile), railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
443 
444  ret = CheckTrackCombination(tile, trackbit);
445  if (ret.Succeeded()) ret = EnsureNoTrainOnTrack(tile, track);
446  if (ret.Failed()) return ret;
447 
448  ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile);
449  if (ret.Failed()) return ret;
450  cost.AddCost(ret);
451 
452  if (HasSignals(tile) && TracksOverlap(GetTrackBits(tile) | TrackToTrackBits(track))) {
453  /* If adding the new track causes any overlap, all signals must be removed first */
454  if (!auto_remove_signals) return_cmd_error(STR_ERROR_MUST_REMOVE_SIGNALS_FIRST);
455 
456  for (Track track_it = TRACK_BEGIN; track_it < TRACK_END; track_it++) {
457  if (HasTrack(tile, track_it) && HasSignalOnTrack(tile, track_it)) {
458  CommandCost ret_remove_signals = Command<CMD_REMOVE_SINGLE_SIGNAL>::Do(flags, tile, track_it);
459  if (ret_remove_signals.Failed()) return ret_remove_signals;
460  cost.AddCost(ret_remove_signals);
461  }
462  }
463  }
464 
465  /* If the rail types don't match, try to convert only if engines of
466  * the new rail type are not powered on the present rail type and engines of
467  * the present rail type are powered on the new rail type. */
468  if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) {
469  if (HasPowerOnRail(GetRailType(tile), railtype)) {
470  ret = Command<CMD_CONVERT_RAIL>::Do(flags, tile, tile, railtype, false);
471  if (ret.Failed()) return ret;
472  cost.AddCost(ret);
473  } else {
474  return CMD_ERROR;
475  }
476  }
477 
478  if (flags & DC_EXEC) {
479  SetRailGroundType(tile, RAIL_GROUND_BARREN);
480  TrackBits bits = GetTrackBits(tile);
481  SetTrackBits(tile, bits | trackbit);
482  /* Subtract old infrastructure count. */
483  uint pieces = CountBits(bits);
484  if (TracksOverlap(bits)) pieces *= pieces;
485  Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] -= pieces;
486  /* Add new infrastructure count. */
487  pieces = CountBits(bits | trackbit);
488  if (TracksOverlap(bits | trackbit)) pieces *= pieces;
489  Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] += pieces;
491  }
492  break;
493  }
494 
495  case MP_ROAD: {
496  /* Level crossings may only be built on these slopes */
497  if (!HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
498 
500  CommandCost ret = CheckTileOwnership(tile);
501  if (ret.Failed()) return ret;
502  }
503 
505  if (ret.Failed()) return ret;
506 
507  if (IsNormalRoad(tile)) {
508  if (HasRoadWorks(tile)) return_cmd_error(STR_ERROR_ROAD_WORKS_IN_PROGRESS);
509 
510  if (GetDisallowedRoadDirections(tile) != DRD_NONE) return_cmd_error(STR_ERROR_CROSSING_ON_ONEWAY_ROAD);
511 
512  if (RailNoLevelCrossings(railtype)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED_RAIL);
513 
514  RoadType roadtype_road = GetRoadTypeRoad(tile);
515  RoadType roadtype_tram = GetRoadTypeTram(tile);
516 
517  if (roadtype_road != INVALID_ROADTYPE && RoadNoLevelCrossing(roadtype_road)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED_ROAD);
518  if (roadtype_tram != INVALID_ROADTYPE && RoadNoLevelCrossing(roadtype_tram)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED_ROAD);
519 
520  RoadBits road = GetRoadBits(tile, RTT_ROAD);
521  RoadBits tram = GetRoadBits(tile, RTT_TRAM);
522  if ((track == TRACK_X && ((road | tram) & ROAD_X) == 0) ||
523  (track == TRACK_Y && ((road | tram) & ROAD_Y) == 0)) {
524  Owner road_owner = GetRoadOwner(tile, RTT_ROAD);
525  Owner tram_owner = GetRoadOwner(tile, RTT_TRAM);
526  /* Disallow breaking end-of-line of someone else
527  * so trams can still reverse on this tile. */
528  if (Company::IsValidID(tram_owner) && HasExactlyOneBit(tram)) {
529  ret = CheckOwnership(tram_owner);
530  if (ret.Failed()) return ret;
531  }
532 
533  uint num_new_road_pieces = (road != ROAD_NONE) ? 2 - CountBits(road) : 0;
534  if (num_new_road_pieces > 0) {
535  cost.AddCost(num_new_road_pieces * RoadBuildCost(roadtype_road));
536  }
537 
538  uint num_new_tram_pieces = (tram != ROAD_NONE) ? 2 - CountBits(tram) : 0;
539  if (num_new_tram_pieces > 0) {
540  cost.AddCost(num_new_tram_pieces * RoadBuildCost(roadtype_tram));
541  }
542 
543  if (flags & DC_EXEC) {
544  MakeRoadCrossing(tile, road_owner, tram_owner, _current_company, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtype_road, roadtype_tram, GetTownIndex(tile));
545  UpdateLevelCrossing(tile, false);
547  Company::Get(_current_company)->infrastructure.rail[railtype] += LEVELCROSSING_TRACKBIT_FACTOR;
549  if (num_new_road_pieces > 0 && Company::IsValidID(road_owner)) {
550  Company::Get(road_owner)->infrastructure.road[roadtype_road] += num_new_road_pieces;
552  }
553  if (num_new_tram_pieces > 0 && Company::IsValidID(tram_owner)) {
554  Company::Get(tram_owner)->infrastructure.road[roadtype_tram] += num_new_tram_pieces;
556  }
557  }
558  break;
559  }
560  }
561 
562  if (IsLevelCrossing(tile) && GetCrossingRailBits(tile) == trackbit) {
563  return_cmd_error(STR_ERROR_ALREADY_BUILT);
564  }
565  [[fallthrough]];
566  }
567 
568  default: {
569  /* Will there be flat water on the lower halftile? */
570  bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh);
571 
572  CommandCost ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile);
573  if (ret.Failed()) return ret;
574  cost.AddCost(ret);
575 
576  ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
577  if (ret.Failed()) return ret;
578  cost.AddCost(ret);
579 
580  if (water_ground) {
581  cost.AddCost(-_price[PR_CLEAR_WATER]);
582  cost.AddCost(_price[PR_CLEAR_ROUGH]);
583  }
584 
585  if (flags & DC_EXEC) {
586  MakeRailNormal(tile, _current_company, trackbit, railtype);
587  if (water_ground) {
588  SetRailGroundType(tile, RAIL_GROUND_WATER);
589  if (IsPossibleDockingTile(tile)) CheckForDockingTile(tile);
590  }
591  Company::Get(_current_company)->infrastructure.rail[railtype]++;
593  }
594  break;
595  }
596  }
597 
598  if (flags & DC_EXEC) {
599  MarkTileDirtyByTile(tile);
601  YapfNotifyTrackLayoutChange(tile, track);
602  }
603 
604  cost.AddCost(RailBuildCost(railtype));
605  return cost;
606 }
607 
616 {
618  bool crossing = false;
619 
620  if (!ValParamTrackOrientation(track)) return CMD_ERROR;
621  TrackBits trackbit = TrackToTrackBits(track);
622 
623  /* Need to read tile owner now because it may change when the rail is removed
624  * Also, in case of floods, _current_company != owner
625  * There may be invalid tiletype even in exec run (when removing long track),
626  * so do not call GetTileOwner(tile) in any case here */
627  Owner owner = INVALID_OWNER;
628 
629  Train *v = nullptr;
630 
631  switch (GetTileType(tile)) {
632  case MP_ROAD: {
633  if (!IsLevelCrossing(tile) || GetCrossingRailBits(tile) != trackbit) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
634 
635  if (_current_company != OWNER_WATER) {
636  CommandCost ret = CheckTileOwnership(tile);
637  if (ret.Failed()) return ret;
638  }
639 
640  if (!(flags & DC_BANKRUPT)) {
642  if (ret.Failed()) return ret;
643  }
644 
645  cost.AddCost(RailClearCost(GetRailType(tile)));
646 
647  if (flags & DC_EXEC) {
649 
650  if (HasReservedTracks(tile, trackbit)) {
651  v = GetTrainForReservation(tile, track);
652  if (v != nullptr) FreeTrainTrackReservation(v);
653  }
654 
655  owner = GetTileOwner(tile);
656  Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR;
658  MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypeRoad(tile), GetRoadTypeTram(tile), GetTownIndex(tile), GetRoadOwner(tile, RTT_ROAD), GetRoadOwner(tile, RTT_TRAM));
659  DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile.base());
660  }
661  break;
662  }
663 
664  case MP_RAILWAY: {
665  TrackBits present;
666  /* There are no rails present at depots. */
667  if (!IsPlainRail(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
668 
669  if (_current_company != OWNER_WATER) {
670  CommandCost ret = CheckTileOwnership(tile);
671  if (ret.Failed()) return ret;
672  }
673 
674  CommandCost ret = EnsureNoTrainOnTrack(tile, track);
675  if (ret.Failed()) return ret;
676 
677  present = GetTrackBits(tile);
678  if ((present & trackbit) == 0) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
679  if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
680 
681  cost.AddCost(RailClearCost(GetRailType(tile)));
682 
683  /* Charge extra to remove signals on the track, if they are there */
684  if (HasSignalOnTrack(tile, track)) {
685  cost.AddCost(Command<CMD_REMOVE_SINGLE_SIGNAL>::Do(flags, tile, track));
686  }
687 
688  if (flags & DC_EXEC) {
689  if (HasReservedTracks(tile, trackbit)) {
690  v = GetTrainForReservation(tile, track);
691  if (v != nullptr) FreeTrainTrackReservation(v);
692  }
693 
694  owner = GetTileOwner(tile);
695 
696  /* Subtract old infrastructure count. */
697  uint pieces = CountBits(present);
698  if (TracksOverlap(present)) pieces *= pieces;
699  Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= pieces;
700  /* Add new infrastructure count. */
701  present ^= trackbit;
702  pieces = CountBits(present);
703  if (TracksOverlap(present)) pieces *= pieces;
704  Company::Get(owner)->infrastructure.rail[GetRailType(tile)] += pieces;
706 
707  if (present == 0) {
708  Slope tileh = GetTileSlope(tile);
709  /* If there is flat water on the lower halftile, convert the tile to shore so the water remains */
710  if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) {
711  bool docking = IsDockingTile(tile);
712  MakeShore(tile);
713  SetDockingTile(tile, docking);
714  } else {
715  DoClearSquare(tile);
716  }
717  DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile.base());
718  } else {
719  SetTrackBits(tile, present);
720  SetTrackReservation(tile, GetRailReservationTrackBits(tile) & present);
721  }
722  }
723  break;
724  }
725 
726  default: return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
727  }
728 
729  if (flags & DC_EXEC) {
730  /* if we got that far, 'owner' variable is set correctly */
731  assert(Company::IsValidID(owner));
732 
733  MarkTileDirtyByTile(tile);
734  if (crossing) {
735  /* crossing is set when only TRACK_BIT_X and TRACK_BIT_Y are set. As we
736  * are removing one of these pieces, we'll need to update signals for
737  * both directions explicitly, as after the track is removed it won't
738  * 'connect' with the other piece. */
739  AddTrackToSignalBuffer(tile, TRACK_X, owner);
740  AddTrackToSignalBuffer(tile, TRACK_Y, owner);
743  } else {
744  AddTrackToSignalBuffer(tile, track, owner);
745  YapfNotifyTrackLayoutChange(tile, track);
746  }
747 
748  if (v != nullptr) TryPathReserve(v, true);
749  }
750 
751  return cost;
752 }
753 
754 
763 {
764  assert(IsPlainRailTile(t));
765 
766  bool flooded = false;
767  if (GetRailGroundType(t) == RAIL_GROUND_WATER) return flooded;
768 
769  Slope tileh = GetTileSlope(t);
770  TrackBits rail_bits = GetTrackBits(t);
771 
772  if (IsSlopeWithOneCornerRaised(tileh)) {
774 
775  TrackBits to_remove = lower_track & rail_bits;
776  if (to_remove != 0) {
778  flooded = Command<CMD_REMOVE_SINGLE_RAIL>::Do(DC_EXEC, t, FindFirstTrack(to_remove)).Succeeded();
779  cur_company.Restore();
780  if (!flooded) return flooded; // not yet floodable
781  rail_bits = rail_bits & ~to_remove;
782  if (rail_bits == 0) {
783  MakeShore(t);
785  return flooded;
786  }
787  }
788 
789  if (IsNonContinuousFoundation(GetRailFoundation(tileh, rail_bits))) {
790  flooded = true;
791  SetRailGroundType(t, RAIL_GROUND_WATER);
793  }
794  } else {
795  /* Make shore on steep slopes and 'three-corners-raised'-slopes. */
796  if (ApplyFoundationToSlope(GetRailFoundation(tileh, rail_bits), tileh) == 0) {
797  if (IsSteepSlope(tileh) || IsSlopeWithThreeCornersRaised(tileh)) {
798  flooded = true;
799  SetRailGroundType(t, RAIL_GROUND_WATER);
801  }
802  }
803  }
804  return flooded;
805 }
806 
807 static const TileIndexDiffC _trackdelta[] = {
808  { -1, 0 }, { 0, 1 }, { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, 1 },
809  { 0, 0 },
810  { 0, 0 },
811  { 1, 0 }, { 0, -1 }, { 0, -1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
812  { 0, 0 },
813  { 0, 0 }
814 };
815 
816 
817 static CommandCost ValidateAutoDrag(Trackdir *trackdir, TileIndex start, TileIndex end)
818 {
819  int x = TileX(start);
820  int y = TileY(start);
821  int ex = TileX(end);
822  int ey = TileY(end);
823 
824  if (!ValParamTrackOrientation(TrackdirToTrack(*trackdir))) return CMD_ERROR;
825 
826  /* calculate delta x,y from start to end tile */
827  int dx = ex - x;
828  int dy = ey - y;
829 
830  /* calculate delta x,y for the first direction */
831  int trdx = _trackdelta[*trackdir].x;
832  int trdy = _trackdelta[*trackdir].y;
833 
834  if (!IsDiagonalTrackdir(*trackdir)) {
835  trdx += _trackdelta[*trackdir ^ 1].x;
836  trdy += _trackdelta[*trackdir ^ 1].y;
837  }
838 
839  /* validate the direction */
840  while ((trdx <= 0 && dx > 0) ||
841  (trdx >= 0 && dx < 0) ||
842  (trdy <= 0 && dy > 0) ||
843  (trdy >= 0 && dy < 0)) {
844  if (!HasBit(*trackdir, 3)) { // first direction is invalid, try the other
845  SetBit(*trackdir, 3); // reverse the direction
846  trdx = -trdx;
847  trdy = -trdy;
848  } else { // other direction is invalid too, invalid drag
849  return CMD_ERROR;
850  }
851  }
852 
853  /* (for diagonal tracks, this is already made sure of by above test), but:
854  * for non-diagonal tracks, check if the start and end tile are on 1 line */
855  if (!IsDiagonalTrackdir(*trackdir)) {
856  trdx = _trackdelta[*trackdir].x;
857  trdy = _trackdelta[*trackdir].y;
858  if (abs(dx) != abs(dy) && abs(dx) + abs(trdy) != abs(dy) + abs(trdx)) return CMD_ERROR;
859  }
860 
861  return CommandCost();
862 }
863 
876 static CommandCost CmdRailTrackHelper(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, RailType railtype, Track track, bool remove, bool auto_remove_signals, bool fail_on_obstacle)
877 {
879 
880  if ((!remove && !ValParamRailType(railtype)) || !ValParamTrackOrientation(track)) return CMD_ERROR;
881  if (end_tile >= Map::Size() || tile >= Map::Size()) return CMD_ERROR;
882 
883  Trackdir trackdir = TrackToTrackdir(track);
884 
885  CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
886  if (ret.Failed()) return ret;
887 
888  bool had_success = false;
889  CommandCost last_error = CMD_ERROR;
890  for (;;) {
891  ret = remove ? Command<CMD_REMOVE_SINGLE_RAIL>::Do(flags, tile, TrackdirToTrack(trackdir)) : Command<CMD_BUILD_SINGLE_RAIL>::Do(flags, tile, railtype, TrackdirToTrack(trackdir), auto_remove_signals);
892 
893  if (ret.Failed()) {
894  last_error = ret;
895  if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT && !remove) {
896  if (fail_on_obstacle) return last_error;
897  if (had_success) break; // Keep going if we haven't constructed any rail yet, skipping the start of the drag
898  }
899 
900  /* Ownership errors are more important. */
901  if (last_error.GetErrorMessage() == STR_ERROR_OWNED_BY && remove) break;
902  } else {
903  had_success = true;
904  total_cost.AddCost(ret);
905  }
906 
907  if (tile == end_tile) break;
908 
909  tile += ToTileIndexDiff(_trackdelta[trackdir]);
910 
911  /* toggle railbit for the non-diagonal tracks */
912  if (!IsDiagonalTrackdir(trackdir)) ToggleBit(trackdir, 0);
913  }
914 
915  if (had_success) return total_cost;
916  return last_error;
917 }
918 
932 CommandCost CmdBuildRailroadTrack(DoCommandFlag flags, TileIndex end_tile, TileIndex start_tile, RailType railtype, Track track, bool auto_remove_signals, bool fail_on_obstacle)
933 {
934  return CmdRailTrackHelper(flags, start_tile, end_tile, railtype, track, false, auto_remove_signals, fail_on_obstacle);
935 }
936 
948 {
949  return CmdRailTrackHelper(flags, start_tile, end_tile, INVALID_RAILTYPE, track, true, false, false);
950 }
951 
964 {
965  /* check railtype and valid direction for depot (0 through 3), 4 in total */
966  if (!ValParamRailType(railtype) || !IsValidDiagDirection(dir)) return CMD_ERROR;
967 
968  Slope tileh = GetTileSlope(tile);
969 
971 
972  /* Prohibit construction if
973  * The tile is non-flat AND
974  * 1) build-on-slopes is disabled
975  * 2) the tile is steep i.e. spans two height levels
976  * 3) the exit points in the wrong direction
977  */
978 
979  if (tileh != SLOPE_FLAT) {
981  return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
982  }
983  cost.AddCost(_price[PR_BUILD_FOUNDATION]);
984  }
985 
986  /* Allow the user to rotate the depot instead of having to destroy it and build it again */
987  bool rotate_existing_depot = false;
988  if (IsRailDepotTile(tile) && railtype == GetRailType(tile)) {
989  CommandCost ret = CheckTileOwnership(tile);
990  if (ret.Failed()) return ret;
991 
992  if (dir == GetRailDepotDirection(tile)) return CommandCost();
993 
994  ret = EnsureNoVehicleOnGround(tile);
995  if (ret.Failed()) return ret;
996 
997  rotate_existing_depot = true;
998  }
999 
1000  if (!rotate_existing_depot) {
1001  cost.AddCost(Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile));
1002  if (cost.Failed()) return cost;
1003 
1004  if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
1005 
1006  if (!Depot::CanAllocateItem()) return CMD_ERROR;
1007  }
1008 
1009  if (flags & DC_EXEC) {
1010  if (rotate_existing_depot) {
1011  SetRailDepotExitDirection(tile, dir);
1012  } else {
1013  Depot *d = new Depot(tile);
1015 
1016  MakeRailDepot(tile, _current_company, d->index, dir, railtype);
1017  MakeDefaultName(d);
1018 
1019  Company::Get(_current_company)->infrastructure.rail[railtype]++;
1021  }
1022 
1023  MarkTileDirtyByTile(tile);
1026  }
1027 
1028  cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN]);
1029  cost.AddCost(RailBuildCost(railtype));
1030  return cost;
1031 }
1032 
1052 CommandCost CmdBuildSingleSignal(DoCommandFlag flags, TileIndex tile, Track track, SignalType sigtype, SignalVariant sigvar, bool convert_signal, bool skip_existing_signals, bool ctrl_pressed, SignalType cycle_start, SignalType cycle_stop, uint8_t num_dir_cycle, uint8_t signals_copy)
1053 {
1054  if (sigtype > SIGTYPE_LAST || sigvar > SIG_SEMAPHORE) return CMD_ERROR;
1055  if (cycle_start > cycle_stop || cycle_stop > SIGTYPE_LAST) return CMD_ERROR;
1056 
1057  if (ctrl_pressed) sigvar = (SignalVariant)(sigvar ^ SIG_SEMAPHORE);
1058 
1059  /* You can only build signals on plain rail tiles, and the selected track must exist */
1060  if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) ||
1061  !HasTrack(tile, track)) {
1062  return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
1063  }
1064  /* Protect against invalid signal copying */
1065  if (signals_copy != 0 && (signals_copy & SignalOnTrack(track)) == 0) return CMD_ERROR;
1066 
1067  CommandCost ret = CheckTileOwnership(tile);
1068  if (ret.Failed()) return ret;
1069 
1070  /* See if this is a valid track combination for signals (no overlap) */
1071  if (TracksOverlap(GetTrackBits(tile))) return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
1072 
1073  /* In case we don't want to change an existing signal, return without error. */
1074  if (skip_existing_signals && HasSignalOnTrack(tile, track)) return CommandCost();
1075 
1076  /* you can not convert a signal if no signal is on track */
1077  if (convert_signal && !HasSignalOnTrack(tile, track)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
1078 
1079  CommandCost cost;
1080  if (!HasSignalOnTrack(tile, track)) {
1081  /* build new signals */
1082  cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
1083  } else {
1084  if (signals_copy != 0 && sigvar != GetSignalVariant(tile, track)) {
1085  /* convert signals <-> semaphores */
1086  cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
1087 
1088  } else if (convert_signal) {
1089  /* convert button pressed */
1090  if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
1091  /* it costs money to change signal variant (light or semaphore) */
1092  cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
1093  } else {
1094  /* it is free to change signal type (block, exit, entry, combo, path, etc) */
1095  cost = CommandCost();
1096  }
1097 
1098  } else {
1099  /* it is free to change orientation or number of signals on the tile (for block/presignals which allow signals in both directions) */
1100  cost = CommandCost();
1101  }
1102  }
1103 
1104  if (flags & DC_EXEC) {
1105  Train *v = nullptr;
1106  /* The new/changed signal could block our path. As this can lead to
1107  * stale reservations, we clear the path reservation here and try
1108  * to redo it later on. */
1109  if (HasReservedTracks(tile, TrackToTrackBits(track))) {
1110  v = GetTrainForReservation(tile, track);
1111  if (v != nullptr) FreeTrainTrackReservation(v);
1112  }
1113 
1114  if (!HasSignals(tile)) {
1115  /* there are no signals at all on this tile yet */
1116  SetHasSignals(tile, true);
1117  SetSignalStates(tile, 0xF); // all signals are on
1118  SetPresentSignals(tile, 0); // no signals built by default
1119  SetSignalType(tile, track, sigtype);
1120  SetSignalVariant(tile, track, sigvar);
1121  }
1122 
1123  /* Subtract old signal infrastructure count. */
1124  Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile));
1125 
1126  if (signals_copy == 0) {
1127  if (!HasSignalOnTrack(tile, track)) {
1128  /* build new signals */
1129  SetPresentSignals(tile, GetPresentSignals(tile) | (IsPbsSignal(sigtype) ? KillFirstBit(SignalOnTrack(track)) : SignalOnTrack(track)));
1130  SetSignalType(tile, track, sigtype);
1131  SetSignalVariant(tile, track, sigvar);
1132  while (num_dir_cycle-- > 0) CycleSignalSide(tile, track);
1133  } else {
1134  if (convert_signal) {
1135  /* convert signal button pressed */
1136  if (ctrl_pressed) {
1137  /* toggle the present signal variant: SIG_ELECTRIC <-> SIG_SEMAPHORE */
1138  SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC);
1139  /* Query current signal type so the check for PBS signals below works. */
1140  sigtype = GetSignalType(tile, track);
1141  } else {
1142  /* convert the present signal to the chosen type and variant */
1143  SetSignalType(tile, track, sigtype);
1144  SetSignalVariant(tile, track, sigvar);
1145  if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
1146  SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
1147  }
1148  }
1149 
1150  } else if (ctrl_pressed) {
1151  /* cycle between cycle_start and cycle_end */
1152  sigtype = (SignalType)(GetSignalType(tile, track) + 1);
1153 
1154  if (sigtype < cycle_start || sigtype > cycle_stop) sigtype = cycle_start;
1155 
1156  SetSignalType(tile, track, sigtype);
1157  if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
1158  SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
1159  }
1160  } else {
1161  /* cycle the signal side: both -> left -> right -> both -> ... */
1162  CycleSignalSide(tile, track);
1163  /* Query current signal type so the check for PBS signals below works. */
1164  sigtype = GetSignalType(tile, track);
1165  }
1166  }
1167  } else {
1168  /* If CmdBuildManySignals is called with copying signals, just copy the
1169  * direction of the first signal given as parameter by CmdBuildManySignals */
1170  SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (signals_copy & SignalOnTrack(track)));
1171  SetSignalVariant(tile, track, sigvar);
1172  SetSignalType(tile, track, sigtype);
1173  }
1174 
1175  /* Add new signal infrastructure count. */
1176  Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
1178 
1179  if (IsPbsSignal(sigtype)) {
1180  /* PBS signals should show red unless they are on reserved tiles without a train. */
1181  uint mask = GetPresentSignals(tile) & SignalOnTrack(track);
1182  SetSignalStates(tile, (GetSignalStates(tile) & ~mask) | ((HasBit(GetRailReservationTrackBits(tile), track) && EnsureNoVehicleOnGround(tile).Succeeded() ? UINT_MAX : 0) & mask));
1183  }
1184  MarkTileDirtyByTile(tile);
1186  YapfNotifyTrackLayoutChange(tile, track);
1187  if (v != nullptr && v->track != TRACK_BIT_DEPOT) {
1188  /* Extend the train's path if it's not stopped or loading, or not at a safe position. */
1189  if (!(((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) || v->current_order.IsType(OT_LOADING)) ||
1191  TryPathReserve(v, true);
1192  }
1193  }
1194  }
1195 
1196  return cost;
1197 }
1198 
1199 static bool AdvanceSignalAutoFill(TileIndex &tile, Trackdir &trackdir, bool remove)
1200 {
1201  /* We only process starting tiles of tunnels or bridges so jump to the other end before moving further. */
1202  if (IsTileType(tile, MP_TUNNELBRIDGE)) tile = GetOtherTunnelBridgeEnd(tile);
1203 
1204  tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]);
1205  if (tile == INVALID_TILE) return false;
1206 
1207  /* Check for track bits on the new tile */
1209 
1210  if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
1211  trackdirbits &= TrackdirReachesTrackdirs(trackdir);
1212 
1213  /* No track bits, must stop */
1214  if (trackdirbits == TRACKDIR_BIT_NONE) return false;
1215 
1216  /* Get the first track dir */
1217  trackdir = RemoveFirstTrackdir(&trackdirbits);
1218 
1219  /* Any left? It's a junction so we stop */
1220  if (trackdirbits != TRACKDIR_BIT_NONE) return false;
1221 
1222  switch (GetTileType(tile)) {
1223  case MP_RAILWAY:
1224  if (IsRailDepot(tile)) return false;
1225  if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false;
1226  break;
1227 
1228  case MP_ROAD:
1229  if (!IsLevelCrossing(tile)) return false;
1230  break;
1231 
1232  case MP_TUNNELBRIDGE: {
1233  if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
1234  if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
1235  break;
1236  }
1237 
1238  default: return false;
1239  }
1240  return true;
1241 }
1242 
1258 static CommandCost CmdSignalTrackHelper(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, Track track, SignalType sigtype, SignalVariant sigvar, bool mode, bool remove, bool autofill, bool minimise_gaps, int signal_density)
1259 {
1260  CommandCost total_cost(EXPENSES_CONSTRUCTION);
1261 
1262  if (end_tile >= Map::Size() || !ValParamTrackOrientation(track)) return CMD_ERROR;
1263  if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
1264  if (!remove && (sigtype > SIGTYPE_LAST || sigvar > SIG_SEMAPHORE)) return CMD_ERROR;
1265 
1266  if (!IsPlainRailTile(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
1267  TileIndex start_tile = tile;
1268 
1269  /* Interpret signal_density as the logical length of said amount of tiles in X/Y direction. */
1270  signal_density *= TILE_AXIAL_DISTANCE;
1271 
1272  Trackdir trackdir = TrackToTrackdir(track);
1273  CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
1274  if (ret.Failed()) return ret;
1275 
1276  track = TrackdirToTrack(trackdir); // trackdir might have changed, keep track in sync
1277  Trackdir start_trackdir = trackdir;
1278 
1279  /* Must start on a valid track to be able to avoid loops */
1280  if (!HasTrack(tile, track)) return CMD_ERROR;
1281 
1282  uint8_t signals;
1283  /* copy the signal-style of the first rail-piece if existing */
1284  if (HasSignalOnTrack(tile, track)) {
1285  signals = GetPresentSignals(tile) & SignalOnTrack(track);
1286  assert(signals != 0);
1287 
1288  /* copy signal/semaphores style (independent of CTRL) */
1289  sigvar = GetSignalVariant(tile, track);
1290 
1291  sigtype = GetSignalType(tile, track);
1292  /* Don't but copy entry or exit-signal type */
1293  if (sigtype == SIGTYPE_ENTRY || sigtype == SIGTYPE_EXIT) sigtype = SIGTYPE_BLOCK;
1294  } else { // no signals exist, drag a two-way signal stretch
1295  signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
1296  }
1297 
1298  uint8_t signal_dir = 0;
1299  if (signals & SignalAlongTrackdir(trackdir)) SetBit(signal_dir, 0);
1300  if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1);
1301 
1302  /* signal_ctr - amount of tiles already processed
1303  * last_used_ctr - amount of tiles before previously placed signal
1304  * signals_density - setting to put signal on every Nth tile (double space on |, -- tracks)
1305  * last_suitable_ctr - amount of tiles before last possible signal place
1306  * last_suitable_tile - last tile where it is possible to place a signal
1307  * last_suitable_trackdir - trackdir of the last tile
1308  **********
1309  * trackdir - trackdir to build with autorail
1310  * semaphores - semaphores or signals
1311  * signals - is there a signal/semaphore on the first tile, copy its style (two-way/single-way)
1312  * and convert all others to semaphore/signal
1313  * remove - 1 remove signals, 0 build signals */
1314  int signal_ctr = 0;
1315  int last_used_ctr = -signal_density; // to force signal at first tile
1316  int last_suitable_ctr = 0;
1317  TileIndex last_suitable_tile = INVALID_TILE;
1318  Trackdir last_suitable_trackdir = INVALID_TRACKDIR;
1319  CommandCost last_error = CMD_ERROR;
1320  bool had_success = false;
1321  auto build_signal = [&](TileIndex tile, Trackdir trackdir, bool test_only) {
1322  /* Pick the correct orientation for the track direction */
1323  uint8_t signals = 0;
1324  if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
1325  if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
1326 
1327  DoCommandFlag do_flags = test_only ? flags & ~DC_EXEC : flags;
1328  CommandCost ret = remove ? Command<CMD_REMOVE_SINGLE_SIGNAL>::Do(do_flags, tile, TrackdirToTrack(trackdir)) : Command<CMD_BUILD_SINGLE_SIGNAL>::Do(do_flags, tile, TrackdirToTrack(trackdir), sigtype, sigvar, false, signal_ctr == 0, mode, SIGTYPE_BLOCK, SIGTYPE_BLOCK, 0, signals);
1329 
1330  if (test_only) return ret.Succeeded();
1331 
1332  if (ret.Succeeded()) {
1333  had_success = true;
1334  total_cost.AddCost(ret);
1335  } else {
1336  /* The "No railway" error is the least important one. */
1337  if (ret.GetErrorMessage() != STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ||
1338  last_error.GetErrorMessage() == INVALID_STRING_ID) {
1339  last_error = ret;
1340  }
1341  }
1342  return ret.Succeeded();
1343  };
1344 
1345  for (;;) {
1346  if (remove) {
1347  /* In remove mode last_* stuff doesn't matter, we simply try to clear every tile. */
1348  build_signal(tile, trackdir, false);
1349  } else if (minimise_gaps) {
1350  /* We're trying to minimize gaps wherever possible, so keep track of last suitable
1351  * position and use it if current gap exceeds required signal density. */
1352 
1353  if (signal_ctr > last_used_ctr + signal_density && last_suitable_tile != INVALID_TILE) {
1354  /* We overshot so build a signal in last good location. */
1355  if (build_signal(last_suitable_tile, last_suitable_trackdir, false)) {
1356  last_suitable_tile = INVALID_TILE;
1357  last_used_ctr = last_suitable_ctr;
1358  }
1359  }
1360 
1361  if (signal_ctr == last_used_ctr + signal_density) {
1362  /* Current gap matches the required density, build a signal. */
1363  if (build_signal(tile, trackdir, false)) {
1364  last_used_ctr = signal_ctr;
1365  last_suitable_tile = INVALID_TILE;
1366  }
1367  } else {
1368  /* Test tile for a potential signal spot. */
1369  if (build_signal(tile, trackdir, true)) {
1370  last_suitable_tile = tile;
1371  last_suitable_ctr = signal_ctr;
1372  last_suitable_trackdir = trackdir;
1373  }
1374  }
1375  } else if (signal_ctr >= last_used_ctr + signal_density) {
1376  /* We're always keeping regular interval between signals so doesn't matter whether we succeed or not. */
1377  build_signal(tile, trackdir, false);
1378  last_used_ctr = signal_ctr;
1379  }
1380 
1381  if (autofill) {
1382  switch (GetTileType(tile)) {
1383  case MP_RAILWAY:
1384  signal_ctr += (IsDiagonalTrackdir(trackdir) ? TILE_AXIAL_DISTANCE : TILE_CORNER_DISTANCE);
1385  break;
1386 
1387  case MP_ROAD:
1388  signal_ctr += TILE_AXIAL_DISTANCE;
1389  break;
1390 
1391  case MP_TUNNELBRIDGE: {
1392  uint len = (GetTunnelBridgeLength(tile, GetOtherTunnelBridgeEnd(tile)) + 2) * TILE_AXIAL_DISTANCE;
1393  if (remove || minimise_gaps) {
1394  signal_ctr += len;
1395  } else {
1396  /* To keep regular interval we need to emulate placing signals on a bridge.
1397  * We start with TILE_AXIAL_DISTANCE as one bridge tile gets processed in the main loop. */
1398  signal_ctr += TILE_AXIAL_DISTANCE;
1399  for (uint i = TILE_AXIAL_DISTANCE; i < len; i += TILE_AXIAL_DISTANCE) {
1400  if (signal_ctr >= last_used_ctr + signal_density) last_used_ctr = signal_ctr;
1401  signal_ctr += TILE_AXIAL_DISTANCE;
1402  }
1403  }
1404  break;
1405  }
1406 
1407  default: break;
1408  }
1409 
1410  if (!AdvanceSignalAutoFill(tile, trackdir, remove)) break;
1411 
1412  /* Prevent possible loops */
1413  if (tile == start_tile && trackdir == start_trackdir) break;
1414  } else {
1415  if (tile == end_tile) break;
1416 
1417  signal_ctr += (IsDiagonalTrackdir(trackdir) ? TILE_AXIAL_DISTANCE : TILE_CORNER_DISTANCE);
1418  /* toggle railbit for the non-diagonal tracks (|, -- tracks) */
1419 
1420  tile += ToTileIndexDiff(_trackdelta[trackdir]);
1421  if (!IsDiagonalTrackdir(trackdir)) ToggleBit(trackdir, 0);
1422  }
1423  }
1424 
1425  /* We may end up with the current gap exceeding the signal density so fix that if needed. */
1426  if (!remove && minimise_gaps && signal_ctr > last_used_ctr + signal_density && last_suitable_tile != INVALID_TILE) {
1427  build_signal(last_suitable_tile, last_suitable_trackdir, false);
1428  }
1429 
1430  return had_success ? total_cost : last_error;
1431 }
1432 
1449 CommandCost CmdBuildSignalTrack(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, Track track, SignalType sigtype, SignalVariant sigvar, bool mode, bool autofill, bool minimise_gaps, uint8_t signal_density)
1450 {
1451  return CmdSignalTrackHelper(flags, tile, end_tile, track, sigtype, sigvar, mode, false, autofill, minimise_gaps, signal_density);
1452 }
1453 
1462 {
1463  if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) {
1464  return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
1465  }
1466  if (!HasSignalOnTrack(tile, track)) {
1467  return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
1468  }
1469 
1470  /* Only water can remove signals from anyone */
1471  if (_current_company != OWNER_WATER) {
1472  CommandCost ret = CheckTileOwnership(tile);
1473  if (ret.Failed()) return ret;
1474  }
1475 
1476  /* Do it? */
1477  if (flags & DC_EXEC) {
1478  Train *v = nullptr;
1479  if (HasReservedTracks(tile, TrackToTrackBits(track))) {
1480  v = GetTrainForReservation(tile, track);
1481  } else if (IsPbsSignal(GetSignalType(tile, track))) {
1482  /* PBS signal, might be the end of a path reservation. */
1483  Trackdir td = TrackToTrackdir(track);
1484  for (int i = 0; v == nullptr && i < 2; i++, td = ReverseTrackdir(td)) {
1485  /* Only test the active signal side. */
1486  if (!HasSignalOnTrackdir(tile, ReverseTrackdir(td))) continue;
1487  TileIndex next = TileAddByDiagDir(tile, TrackdirToExitdir(td));
1489  if (HasReservedTracks(next, tracks)) {
1491  }
1492  }
1493  }
1494  Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile));
1495  SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
1496  Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
1498 
1499  /* removed last signal from tile? */
1500  if (GetPresentSignals(tile) == 0) {
1501  SetSignalStates(tile, 0);
1502  SetHasSignals(tile, false);
1503  SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC); // remove any possible semaphores
1504  }
1505 
1506  AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
1507  YapfNotifyTrackLayoutChange(tile, track);
1508  if (v != nullptr) TryPathReserve(v, false);
1509 
1510  MarkTileDirtyByTile(tile);
1511  }
1512 
1513  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_SIGNALS]);
1514 }
1515 
1527 CommandCost CmdRemoveSignalTrack(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, Track track, bool autofill)
1528 {
1529  return CmdSignalTrackHelper(flags, tile, end_tile, track, SIGTYPE_BLOCK, SIG_ELECTRIC, false, true, autofill, false, 1); // bit 5 is remove bit
1530 }
1531 
1533 static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
1534 {
1535  if (v->type != VEH_TRAIN) return nullptr;
1536 
1537  TrainList *affected_trains = static_cast<TrainList*>(data);
1538  include(*affected_trains, Train::From(v)->First());
1539 
1540  return nullptr;
1541 }
1542 
1553 CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, TileIndex area_start, RailType totype, bool diagonal)
1554 {
1555  TileIndex area_end = tile;
1556 
1557  if (!ValParamRailType(totype)) return CMD_ERROR;
1558  if (area_start >= Map::Size()) return CMD_ERROR;
1559 
1560  TrainList affected_trains;
1561 
1563  CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK); // by default, there is no track to convert.
1564  bool found_convertible_track = false; // whether we actually did convert some track (see bug #7633)
1565 
1566  std::unique_ptr<TileIterator> iter = TileIterator::Create(area_start, area_end, diagonal);
1567  for (; (tile = *iter) != INVALID_TILE; ++(*iter)) {
1568  TileType tt = GetTileType(tile);
1569 
1570  /* Check if there is any track on tile */
1571  switch (tt) {
1572  case MP_RAILWAY:
1573  break;
1574  case MP_STATION:
1575  if (!HasStationRail(tile)) continue;
1576  break;
1577  case MP_ROAD:
1578  if (!IsLevelCrossing(tile)) continue;
1579  if (RailNoLevelCrossings(totype)) {
1580  error.MakeError(STR_ERROR_CROSSING_DISALLOWED_RAIL);
1581  continue;
1582  }
1583  break;
1584  case MP_TUNNELBRIDGE:
1585  if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
1586  break;
1587  default: continue;
1588  }
1589 
1590  /* Original railtype we are converting from */
1591  RailType type = GetRailType(tile);
1592 
1593  /* Converting to the same type or converting 'hidden' elrail -> rail */
1594  if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
1595 
1596  /* Trying to convert other's rail */
1597  CommandCost ret = CheckTileOwnership(tile);
1598  if (ret.Failed()) {
1599  error = ret;
1600  continue;
1601  }
1602 
1603  std::vector<Train *> vehicles_affected;
1604 
1605  /* Vehicle on the tile when not converting Rail <-> ElRail
1606  * Tunnels and bridges have special check later */
1607  if (tt != MP_TUNNELBRIDGE) {
1608  if (!IsCompatibleRail(type, totype)) {
1610  if (ret.Failed()) {
1611  error = ret;
1612  continue;
1613  }
1614  }
1615  if (flags & DC_EXEC) { // we can safely convert, too
1616  TrackBits reserved = GetReservedTrackbits(tile);
1617  Track track;
1618  while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
1619  Train *v = GetTrainForReservation(tile, track);
1620  if (v != nullptr && !HasPowerOnRail(v->railtype, totype)) {
1621  /* No power on new rail type, reroute. */
1623  vehicles_affected.push_back(v);
1624  }
1625  }
1626 
1627  /* Update the company infrastructure counters. */
1628  if (!IsRailStationTile(tile) || !IsStationTileBlocked(tile)) {
1629  Company *c = Company::Get(GetTileOwner(tile));
1630  uint num_pieces = IsLevelCrossingTile(tile) ? LEVELCROSSING_TRACKBIT_FACTOR : 1;
1631  if (IsPlainRailTile(tile)) {
1632  TrackBits bits = GetTrackBits(tile);
1633  num_pieces = CountBits(bits);
1634  if (TracksOverlap(bits)) num_pieces *= num_pieces;
1635  }
1636  c->infrastructure.rail[type] -= num_pieces;
1637  c->infrastructure.rail[totype] += num_pieces;
1639  }
1640 
1641  SetRailType(tile, totype);
1642  MarkTileDirtyByTile(tile);
1643  /* update power of train on this tile */
1644  FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
1645  }
1646  }
1647 
1648  switch (tt) {
1649  case MP_RAILWAY:
1650  switch (GetRailTileType(tile)) {
1651  case RAIL_TILE_DEPOT:
1652  if (flags & DC_EXEC) {
1653  /* notify YAPF about the track layout change */
1655 
1656  /* Update build vehicle window related to this depot */
1659  }
1660  found_convertible_track = true;
1661  cost.AddCost(RailConvertCost(type, totype));
1662  break;
1663 
1664  default: // RAIL_TILE_NORMAL, RAIL_TILE_SIGNALS
1665  if (flags & DC_EXEC) {
1666  /* notify YAPF about the track layout change */
1667  TrackBits tracks = GetTrackBits(tile);
1668  while (tracks != TRACK_BIT_NONE) {
1670  }
1671  }
1672  found_convertible_track = true;
1673  cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
1674  break;
1675  }
1676  break;
1677 
1678  case MP_TUNNELBRIDGE: {
1679  TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
1680 
1681  /* If both ends of tunnel/bridge are in the range, do not try to convert twice -
1682  * it would cause assert because of different test and exec runs */
1683  if (endtile < tile) {
1684  if (diagonal) {
1685  if (DiagonalTileArea(area_start, area_end).Contains(endtile)) continue;
1686  } else {
1687  if (OrthogonalTileArea(area_start, area_end).Contains(endtile)) continue;
1688  }
1689  }
1690 
1691  /* When not converting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */
1692  if (!IsCompatibleRail(GetRailType(tile), totype)) {
1693  ret = TunnelBridgeIsFree(tile, endtile);
1694  if (ret.Failed()) {
1695  error = ret;
1696  continue;
1697  }
1698  }
1699 
1700  if (flags & DC_EXEC) {
1702  if (HasTunnelBridgeReservation(tile)) {
1703  Train *v = GetTrainForReservation(tile, track);
1704  if (v != nullptr && !HasPowerOnRail(v->railtype, totype)) {
1705  /* No power on new rail type, reroute. */
1707  vehicles_affected.push_back(v);
1708  }
1709  }
1710 
1711  /* Update the company infrastructure counters. */
1712  uint num_pieces = (GetTunnelBridgeLength(tile, endtile) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
1713  Company *c = Company::Get(GetTileOwner(tile));
1714  c->infrastructure.rail[GetRailType(tile)] -= num_pieces;
1715  c->infrastructure.rail[totype] += num_pieces;
1717 
1718  SetRailType(tile, totype);
1719  SetRailType(endtile, totype);
1720 
1721  FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
1722  FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
1723 
1724  YapfNotifyTrackLayoutChange(tile, track);
1725  YapfNotifyTrackLayoutChange(endtile, track);
1726 
1727  if (IsBridge(tile)) {
1728  MarkBridgeDirty(tile);
1729  } else {
1730  MarkTileDirtyByTile(tile);
1731  MarkTileDirtyByTile(endtile);
1732  }
1733  }
1734 
1735  found_convertible_track = true;
1736  cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
1737  break;
1738  }
1739 
1740  default: // MP_STATION, MP_ROAD
1741  if (flags & DC_EXEC) {
1742  Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
1743  YapfNotifyTrackLayoutChange(tile, track);
1744  }
1745 
1746  found_convertible_track = true;
1747  cost.AddCost(RailConvertCost(type, totype));
1748  break;
1749  }
1750 
1751  for (uint i = 0; i < vehicles_affected.size(); ++i) {
1752  TryPathReserve(vehicles_affected[i], true);
1753  }
1754  }
1755 
1756  if (flags & DC_EXEC) {
1757  /* Railtype changed, update trains as when entering different track */
1758  for (Train *v : affected_trains) {
1759  v->ConsistChanged(CCF_TRACK);
1760  }
1761  }
1762 
1763  return found_convertible_track ? cost : error;
1764 }
1765 
1766 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
1767 {
1768  if (_current_company != OWNER_WATER) {
1769  CommandCost ret = CheckTileOwnership(tile);
1770  if (ret.Failed()) return ret;
1771  }
1772 
1774  if (ret.Failed()) return ret;
1775 
1776  if (flags & DC_EXEC) {
1777  /* read variables before the depot is removed */
1779  Owner owner = GetTileOwner(tile);
1780  Train *v = nullptr;
1781 
1782  if (HasDepotReservation(tile)) {
1784  if (v != nullptr) FreeTrainTrackReservation(v);
1785  }
1786 
1787  Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--;
1789 
1790  delete Depot::GetByTile(tile);
1791  DoClearSquare(tile);
1792  AddSideToSignalBuffer(tile, dir, owner);
1794  if (v != nullptr) TryPathReserve(v, true);
1795  }
1796 
1797  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
1798 }
1799 
1800 static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
1801 {
1803 
1804  if (flags & DC_AUTO) {
1805  if (!IsTileOwner(tile, _current_company)) {
1806  return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
1807  }
1808 
1809  if (IsPlainRail(tile)) {
1810  return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
1811  } else {
1812  return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
1813  }
1814  }
1815 
1816  switch (GetRailTileType(tile)) {
1817  case RAIL_TILE_SIGNALS:
1818  case RAIL_TILE_NORMAL: {
1819  Slope tileh = GetTileSlope(tile);
1820  /* Is there flat water on the lower halftile that gets cleared expensively? */
1821  bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
1822 
1823  TrackBits tracks = GetTrackBits(tile);
1824  while (tracks != TRACK_BIT_NONE) {
1825  Track track = RemoveFirstTrack(&tracks);
1826  CommandCost ret = Command<CMD_REMOVE_SINGLE_RAIL>::Do(flags, tile, track);
1827  if (ret.Failed()) return ret;
1828  cost.AddCost(ret);
1829  }
1830 
1831  /* When bankrupting, don't make water dirty, there could be a ship on lower halftile.
1832  * Same holds for non-companies clearing the tile, e.g. disasters. */
1833  if (water_ground && !(flags & DC_BANKRUPT) && Company::IsValidID(_current_company)) {
1835  if (ret.Failed()) return ret;
1836 
1837  /* The track was removed, and left a coast tile. Now also clear the water. */
1838  if (flags & DC_EXEC) {
1839  DoClearSquare(tile);
1840  }
1841  cost.AddCost(_price[PR_CLEAR_WATER]);
1842  }
1843 
1844  return cost;
1845  }
1846 
1847  case RAIL_TILE_DEPOT:
1848  return RemoveTrainDepot(tile, flags);
1849 
1850  default:
1851  return CMD_ERROR;
1852  }
1853 }
1854 
1859 static uint GetSaveSlopeZ(uint x, uint y, Track track)
1860 {
1861  switch (track) {
1862  case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
1863  case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
1864  case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
1865  case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
1866  default: break;
1867  }
1868  return GetSlopePixelZ(x, y);
1869 }
1870 
1871 static void DrawSingleSignal(TileIndex tile, const RailTypeInfo *rti, Track track, SignalState condition, SignalOffsets image, uint pos)
1872 {
1873  bool side;
1875  case 0: side = false; break; // left
1876  case 2: side = true; break; // right
1877  default: side = _settings_game.vehicle.road_side != 0; break; // driving side
1878  }
1879  static const Point SignalPositions[2][12] = {
1880  { // Signals on the left side
1881  /* LEFT LEFT RIGHT RIGHT UPPER UPPER */
1882  { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
1883  /* LOWER LOWER X X Y Y */
1884  {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
1885  }, { // Signals on the right side
1886  /* LEFT LEFT RIGHT RIGHT UPPER UPPER */
1887  {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
1888  /* LOWER LOWER X X Y Y */
1889  {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
1890  }
1891  };
1892 
1893  uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
1894  uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
1895 
1896  SignalType type = GetSignalType(tile, track);
1897  SignalVariant variant = GetSignalVariant(tile, track);
1898 
1899  SpriteID sprite = GetCustomSignalSprite(rti, tile, type, variant, condition);
1900  if (sprite != 0) {
1901  sprite += image;
1902  } else {
1903  /* Normal electric signals are stored in a different sprite block than all other signals. */
1904  sprite = (type == SIGTYPE_BLOCK && variant == SIG_ELECTRIC) ? SPR_ORIGINAL_SIGNALS_BASE : SPR_SIGNALS_BASE - 16;
1905  sprite += type * 16 + variant * 64 + image * 2 + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
1906  }
1907 
1908  AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
1909 }
1910 
1911 static uint32_t _drawtile_track_palette;
1912 
1913 
1914 
1916 struct FenceOffset {
1918  int x_offs;
1919  int y_offs;
1920  int x_size;
1921  int y_size;
1922 };
1923 
1926  { CORNER_INVALID, 0, 1, 16, 1 }, // RFO_FLAT_X_NW
1927  { CORNER_INVALID, 1, 0, 1, 16 }, // RFO_FLAT_Y_NE
1928  { CORNER_W, 8, 8, 1, 1 }, // RFO_FLAT_LEFT
1929  { CORNER_N, 8, 8, 1, 1 }, // RFO_FLAT_UPPER
1930  { CORNER_INVALID, 0, 1, 16, 1 }, // RFO_SLOPE_SW_NW
1931  { CORNER_INVALID, 1, 0, 1, 16 }, // RFO_SLOPE_SE_NE
1932  { CORNER_INVALID, 0, 1, 16, 1 }, // RFO_SLOPE_NE_NW
1933  { CORNER_INVALID, 1, 0, 1, 16 }, // RFO_SLOPE_NW_NE
1934  { CORNER_INVALID, 0, 15, 16, 1 }, // RFO_FLAT_X_SE
1935  { CORNER_INVALID, 15, 0, 1, 16 }, // RFO_FLAT_Y_SW
1936  { CORNER_E, 8, 8, 1, 1 }, // RFO_FLAT_RIGHT
1937  { CORNER_S, 8, 8, 1, 1 }, // RFO_FLAT_LOWER
1938  { CORNER_INVALID, 0, 15, 16, 1 }, // RFO_SLOPE_SW_SE
1939  { CORNER_INVALID, 15, 0, 1, 16 }, // RFO_SLOPE_SE_SW
1940  { CORNER_INVALID, 0, 15, 16, 1 }, // RFO_SLOPE_NE_SE
1941  { CORNER_INVALID, 15, 0, 1, 16 }, // RFO_SLOPE_NW_SW
1942 };
1943 
1951 static void DrawTrackFence(const TileInfo *ti, SpriteID base_image, uint num_sprites, RailFenceOffset rfo)
1952 {
1953  int z = ti->z;
1954  if (_fence_offsets[rfo].height_ref != CORNER_INVALID) {
1956  }
1957  AddSortableSpriteToDraw(base_image + (rfo % num_sprites), _drawtile_track_palette,
1958  ti->x + _fence_offsets[rfo].x_offs,
1959  ti->y + _fence_offsets[rfo].y_offs,
1960  _fence_offsets[rfo].x_size,
1961  _fence_offsets[rfo].y_size,
1962  4, z);
1963 }
1964 
1968 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image, uint num_sprites)
1969 {
1971  if (ti->tileh & SLOPE_NW) rfo = (ti->tileh & SLOPE_W) ? RFO_SLOPE_SW_NW : RFO_SLOPE_NE_NW;
1972  DrawTrackFence(ti, base_image, num_sprites, rfo);
1973 }
1974 
1978 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image, uint num_sprites)
1979 {
1981  if (ti->tileh & SLOPE_SE) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW_SE : RFO_SLOPE_NE_SE;
1982  DrawTrackFence(ti, base_image, num_sprites, rfo);
1983 }
1984 
1988 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image, uint num_sprites)
1989 {
1991  if (ti->tileh & SLOPE_NE) rfo = (ti->tileh & SLOPE_E) ? RFO_SLOPE_SE_NE : RFO_SLOPE_NW_NE;
1992  DrawTrackFence(ti, base_image, num_sprites, rfo);
1993 }
1994 
1998 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image, uint num_sprites)
1999 {
2001  if (ti->tileh & SLOPE_SW) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE_SW : RFO_SLOPE_NW_SW;
2002  DrawTrackFence(ti, base_image, num_sprites, rfo);
2003 }
2004 
2010 static void DrawTrackDetails(const TileInfo *ti, const RailTypeInfo *rti)
2011 {
2012  /* Base sprite for track fences.
2013  * Note: Halftile slopes only have fences on the upper part. */
2014  uint num_sprites = 0;
2015  SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES, IsHalftileSlope(ti->tileh) ? TCX_UPPER_HALFTILE : TCX_NORMAL, &num_sprites);
2016  if (base_image == 0) {
2017  base_image = SPR_TRACK_FENCE_FLAT_X;
2018  num_sprites = 8;
2019  }
2020 
2021  assert(num_sprites > 0);
2022 
2023  switch (GetRailGroundType(ti->tile)) {
2024  case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image, num_sprites); break;
2025  case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image, num_sprites); break;
2026  case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW(ti, base_image, num_sprites);
2027  DrawTrackFence_SE(ti, base_image, num_sprites); break;
2028  case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image, num_sprites); break;
2029  case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image, num_sprites); break;
2030  case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE(ti, base_image, num_sprites);
2031  DrawTrackFence_SW(ti, base_image, num_sprites); break;
2032  case RAIL_GROUND_FENCE_VERT1: DrawTrackFence(ti, base_image, num_sprites, RFO_FLAT_LEFT); break;
2033  case RAIL_GROUND_FENCE_VERT2: DrawTrackFence(ti, base_image, num_sprites, RFO_FLAT_RIGHT); break;
2034  case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence(ti, base_image, num_sprites, RFO_FLAT_UPPER); break;
2035  case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence(ti, base_image, num_sprites, RFO_FLAT_LOWER); break;
2036  case RAIL_GROUND_WATER: {
2037  Corner track_corner;
2038  if (IsHalftileSlope(ti->tileh)) {
2039  /* Steep slope or one-corner-raised slope with halftile foundation */
2040  track_corner = GetHalftileSlopeCorner(ti->tileh);
2041  } else {
2042  /* Three-corner-raised slope */
2044  }
2045  switch (track_corner) {
2046  case CORNER_W: DrawTrackFence(ti, base_image, num_sprites, RFO_FLAT_LEFT); break;
2047  case CORNER_S: DrawTrackFence(ti, base_image, num_sprites, RFO_FLAT_LOWER); break;
2048  case CORNER_E: DrawTrackFence(ti, base_image, num_sprites, RFO_FLAT_RIGHT); break;
2049  case CORNER_N: DrawTrackFence(ti, base_image, num_sprites, RFO_FLAT_UPPER); break;
2050  default: NOT_REACHED();
2051  }
2052  break;
2053  }
2054  default: break;
2055  }
2056 }
2057 
2058 /* SubSprite for drawing the track halftile of 'three-corners-raised'-sloped rail sprites. */
2059 static const int INF = 1000; // big number compared to tilesprite size
2060 static const SubSprite _halftile_sub_sprite[4] = {
2061  { -INF , -INF , 32 - 33, INF }, // CORNER_W, clip 33 pixels from right
2062  { -INF , 0 + 7, INF , INF }, // CORNER_S, clip 7 pixels from top
2063  { -31 + 33, -INF , INF , INF }, // CORNER_E, clip 33 pixels from left
2064  { -INF , -INF , INF , 30 - 23 } // CORNER_N, clip 23 pixels from bottom
2065 };
2066 
2067 static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s)
2068 {
2069  DrawGroundSprite(sprite, pal, nullptr, 0, (ti->tileh & s) ? -8 : 0);
2070 }
2071 
2072 static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailTypeInfo *rti)
2073 {
2074  RailGroundType rgt = GetRailGroundType(ti->tile);
2075  Foundation f = GetRailFoundation(ti->tileh, track);
2076  Corner halftile_corner = CORNER_INVALID;
2077 
2078  if (IsNonContinuousFoundation(f)) {
2079  /* Save halftile corner */
2081  /* Draw lower part first */
2082  track &= ~CornerToTrackBits(halftile_corner);
2084  }
2085 
2086  DrawFoundation(ti, f);
2087  /* DrawFoundation modifies ti */
2088 
2089  /* Draw ground */
2090  if (rgt == RAIL_GROUND_WATER) {
2091  if (track != TRACK_BIT_NONE || IsSteepSlope(ti->tileh)) {
2092  /* three-corner-raised slope or steep slope with track on upper part */
2093  DrawShoreTile(ti->tileh);
2094  } else {
2095  /* single-corner-raised slope with track on upper part */
2096  DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
2097  }
2098  } else {
2099  SpriteID image;
2100 
2101  switch (rgt) {
2102  case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
2103  case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
2104  default: image = SPR_FLAT_GRASS_TILE; break;
2105  }
2106 
2107  image += SlopeToSpriteOffset(ti->tileh);
2108 
2109  DrawGroundSprite(image, PAL_NONE);
2110  }
2111 
2112  bool no_combine = ti->tileh == SLOPE_FLAT && HasBit(rti->flags, RTF_NO_SPRITE_COMBINE);
2113  SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
2114  SpriteID ground = GetCustomRailSprite(rti, ti->tile, no_combine ? RTSG_GROUND_COMPLETE : RTSG_GROUND);
2116 
2117  if (track == TRACK_BIT_NONE) {
2118  /* Half-tile foundation, no track here? */
2119  } else if (no_combine) {
2120  /* Use trackbits as direct index from ground sprite, subtract 1
2121  * because there is no sprite for no bits. */
2122  DrawGroundSprite(ground + track - 1, PAL_NONE);
2123 
2124  /* Draw reserved track bits */
2125  if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
2126  if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
2127  if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N);
2128  if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S);
2129  if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E);
2130  if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
2131  } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) {
2132  DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE);
2134  } else if (ti->tileh == SLOPE_NE && track == TRACK_BIT_X) {
2135  DrawGroundSprite(ground + RTO_SLOPE_NE, PAL_NONE);
2137  } else if (ti->tileh == SLOPE_SE && track == TRACK_BIT_Y) {
2138  DrawGroundSprite(ground + RTO_SLOPE_SE, PAL_NONE);
2140  } else if (ti->tileh == SLOPE_SW && track == TRACK_BIT_X) {
2141  DrawGroundSprite(ground + RTO_SLOPE_SW, PAL_NONE);
2143  } else {
2144  switch (track) {
2145  /* Draw single ground sprite when not overlapping. No track overlay
2146  * is necessary for these sprites. */
2147  case TRACK_BIT_X: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
2148  case TRACK_BIT_Y: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
2149  case TRACK_BIT_UPPER: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); break;
2150  case TRACK_BIT_LOWER: DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
2151  case TRACK_BIT_RIGHT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); break;
2152  case TRACK_BIT_LEFT: DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
2153  case TRACK_BIT_CROSS: DrawGroundSprite(ground + RTO_CROSSING_XY, PAL_NONE); break;
2154  case TRACK_BIT_HORZ: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N);
2155  DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
2156  case TRACK_BIT_VERT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E);
2157  DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
2158 
2159  default:
2160  /* We're drawing a junction tile */
2161  if ((track & TRACK_BIT_3WAY_NE) == 0) {
2162  DrawGroundSprite(ground + RTO_JUNCTION_SW, PAL_NONE);
2163  } else if ((track & TRACK_BIT_3WAY_SW) == 0) {
2164  DrawGroundSprite(ground + RTO_JUNCTION_NE, PAL_NONE);
2165  } else if ((track & TRACK_BIT_3WAY_NW) == 0) {
2166  DrawGroundSprite(ground + RTO_JUNCTION_SE, PAL_NONE);
2167  } else if ((track & TRACK_BIT_3WAY_SE) == 0) {
2168  DrawGroundSprite(ground + RTO_JUNCTION_NW, PAL_NONE);
2169  } else {
2170  DrawGroundSprite(ground + RTO_JUNCTION_NSEW, PAL_NONE);
2171  }
2172 
2173  /* Mask out PBS bits as we shall draw them afterwards anyway. */
2174  track &= ~pbs;
2175 
2176  /* Draw regular track bits */
2177  if (track & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PAL_NONE);
2178  if (track & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PAL_NONE);
2179  if (track & TRACK_BIT_UPPER) DrawGroundSprite(overlay + RTO_N, PAL_NONE);
2180  if (track & TRACK_BIT_LOWER) DrawGroundSprite(overlay + RTO_S, PAL_NONE);
2181  if (track & TRACK_BIT_RIGHT) DrawGroundSprite(overlay + RTO_E, PAL_NONE);
2182  if (track & TRACK_BIT_LEFT) DrawGroundSprite(overlay + RTO_W, PAL_NONE);
2183  }
2184 
2185  /* Draw reserved track bits */
2186  if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
2187  if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
2188  if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N);
2189  if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S);
2190  if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E);
2191  if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
2192  }
2193 
2194  if (IsValidCorner(halftile_corner)) {
2195  DrawFoundation(ti, HalftileFoundation(halftile_corner));
2198 
2199  /* Draw higher halftile-overlay: Use the sloped sprites with three corners raised. They probably best fit the lightning. */
2200  Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
2201 
2202  SpriteID image;
2203  switch (rgt) {
2204  case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
2206  case RAIL_GROUND_HALF_SNOW: image = SPR_FLAT_SNOW_DESERT_TILE; break;
2207  default: image = SPR_FLAT_GRASS_TILE; break;
2208  }
2209 
2210  image += SlopeToSpriteOffset(fake_slope);
2211 
2212  DrawGroundSprite(image, PAL_NONE, &(_halftile_sub_sprite[halftile_corner]));
2213 
2214  track = CornerToTrackBits(halftile_corner);
2215 
2216  int offset;
2217  switch (track) {
2218  default: NOT_REACHED();
2219  case TRACK_BIT_UPPER: offset = RTO_N; break;
2220  case TRACK_BIT_LOWER: offset = RTO_S; break;
2221  case TRACK_BIT_RIGHT: offset = RTO_E; break;
2222  case TRACK_BIT_LEFT: offset = RTO_W; break;
2223  }
2224 
2225  DrawTrackSprite(ground + offset, PAL_NONE, ti, fake_slope);
2227  DrawTrackSprite(overlay + offset, PALETTE_CRASH, ti, fake_slope);
2228  }
2229  }
2230 }
2231 
2237 static void DrawTrackBits(TileInfo *ti, TrackBits track)
2238 {
2239  const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
2240 
2241  if (rti->UsesOverlay()) {
2242  DrawTrackBitsOverlay(ti, track, rti);
2243  return;
2244  }
2245 
2246  RailGroundType rgt = GetRailGroundType(ti->tile);
2247  Foundation f = GetRailFoundation(ti->tileh, track);
2248  Corner halftile_corner = CORNER_INVALID;
2249 
2250  if (IsNonContinuousFoundation(f)) {
2251  /* Save halftile corner */
2253  /* Draw lower part first */
2254  track &= ~CornerToTrackBits(halftile_corner);
2256  }
2257 
2258  DrawFoundation(ti, f);
2259  /* DrawFoundation modifies ti */
2260 
2261  SpriteID image;
2262  PaletteID pal = PAL_NONE;
2263  const SubSprite *sub = nullptr;
2264  bool junction = false;
2265 
2266  /* Select the sprite to use. */
2267  if (track == 0) {
2268  /* Clear ground (only track on halftile foundation) */
2269  if (rgt == RAIL_GROUND_WATER) {
2270  if (IsSteepSlope(ti->tileh)) {
2271  DrawShoreTile(ti->tileh);
2272  image = 0;
2273  } else {
2274  image = SPR_FLAT_WATER_TILE;
2275  }
2276  } else {
2277  switch (rgt) {
2278  case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
2279  case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
2280  default: image = SPR_FLAT_GRASS_TILE; break;
2281  }
2282  image += SlopeToSpriteOffset(ti->tileh);
2283  }
2284  } else {
2285  if (ti->tileh != SLOPE_FLAT) {
2286  /* track on non-flat ground */
2287  image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
2288  } else {
2289  /* track on flat ground */
2290  switch (track) {
2291  /* single track, select combined track + ground sprite*/
2292  case TRACK_BIT_Y: image = rti->base_sprites.track_y; break;
2293  case TRACK_BIT_X: image = rti->base_sprites.track_y + 1; break;
2294  case TRACK_BIT_UPPER: image = rti->base_sprites.track_y + 2; break;
2295  case TRACK_BIT_LOWER: image = rti->base_sprites.track_y + 3; break;
2296  case TRACK_BIT_RIGHT: image = rti->base_sprites.track_y + 4; break;
2297  case TRACK_BIT_LEFT: image = rti->base_sprites.track_y + 5; break;
2298  case TRACK_BIT_CROSS: image = rti->base_sprites.track_y + 6; break;
2299 
2300  /* double diagonal track, select combined track + ground sprite*/
2301  case TRACK_BIT_HORZ: image = rti->base_sprites.track_ns; break;
2302  case TRACK_BIT_VERT: image = rti->base_sprites.track_ns + 1; break;
2303 
2304  /* junction, select only ground sprite, handle track sprite later */
2305  default:
2306  junction = true;
2307  if ((track & TRACK_BIT_3WAY_NE) == 0) { image = rti->base_sprites.ground; break; }
2308  if ((track & TRACK_BIT_3WAY_SW) == 0) { image = rti->base_sprites.ground + 1; break; }
2309  if ((track & TRACK_BIT_3WAY_NW) == 0) { image = rti->base_sprites.ground + 2; break; }
2310  if ((track & TRACK_BIT_3WAY_SE) == 0) { image = rti->base_sprites.ground + 3; break; }
2311  image = rti->base_sprites.ground + 4;
2312  break;
2313  }
2314  }
2315 
2316  switch (rgt) {
2317  case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
2318  case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
2319  case RAIL_GROUND_WATER: {
2320  /* three-corner-raised slope */
2321  DrawShoreTile(ti->tileh);
2323  sub = &(_halftile_sub_sprite[track_corner]);
2324  break;
2325  }
2326  default: break;
2327  }
2328  }
2329 
2330  if (image != 0) DrawGroundSprite(image, pal, sub);
2331 
2332  /* Draw track pieces individually for junction tiles */
2333  if (junction) {
2334  if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
2335  if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
2336  if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
2337  if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
2338  if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
2339  if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
2340  }
2341 
2342  /* PBS debugging, draw reserved tracks darker */
2343  if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
2344  /* Get reservation, but mask track on halftile slope */
2345  TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
2346  if (pbs & TRACK_BIT_X) {
2347  if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
2349  } else {
2350  DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
2351  }
2352  }
2353  if (pbs & TRACK_BIT_Y) {
2354  if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
2356  } else {
2357  DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
2358  }
2359  }
2360  if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, nullptr, 0, ti->tileh & SLOPE_N ? -(int)TILE_HEIGHT : 0);
2361  if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, nullptr, 0, ti->tileh & SLOPE_S ? -(int)TILE_HEIGHT : 0);
2362  if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, nullptr, 0, ti->tileh & SLOPE_W ? -(int)TILE_HEIGHT : 0);
2363  if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, nullptr, 0, ti->tileh & SLOPE_E ? -(int)TILE_HEIGHT : 0);
2364  }
2365 
2366  if (IsValidCorner(halftile_corner)) {
2367  DrawFoundation(ti, HalftileFoundation(halftile_corner));
2368 
2369  /* Draw higher halftile-overlay: Use the sloped sprites with three corners raised. They probably best fit the lightning. */
2370  Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
2371  image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
2372  pal = PAL_NONE;
2373  switch (rgt) {
2374  case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
2376  case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break; // higher part has snow in this case too
2377  default: break;
2378  }
2379  DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
2380 
2381  if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
2382  static const uint8_t _corner_to_track_sprite[] = {3, 1, 2, 0};
2383  DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, nullptr, 0, -(int)TILE_HEIGHT);
2384  }
2385  }
2386 }
2387 
2388 static void DrawSignals(TileIndex tile, TrackBits rails, const RailTypeInfo *rti)
2389 {
2390  auto MAYBE_DRAW_SIGNAL = [&](uint8_t signalbit, SignalOffsets image, uint pos, Track track) {
2391  if (IsSignalPresent(tile, signalbit)) DrawSingleSignal(tile, rti, track, GetSingleSignalState(tile, signalbit), image, pos);
2392  };
2393 
2394  if (!(rails & TRACK_BIT_Y)) {
2395  if (!(rails & TRACK_BIT_X)) {
2396  if (rails & TRACK_BIT_LEFT) {
2397  MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
2398  MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
2399  }
2400  if (rails & TRACK_BIT_RIGHT) {
2401  MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
2402  MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
2403  }
2404  if (rails & TRACK_BIT_UPPER) {
2405  MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
2406  MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
2407  }
2408  if (rails & TRACK_BIT_LOWER) {
2409  MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
2410  MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
2411  }
2412  } else {
2413  MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
2414  MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
2415  }
2416  } else {
2417  MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
2418  MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
2419  }
2420 }
2421 
2422 static void DrawTile_Track(TileInfo *ti)
2423 {
2424  const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
2425 
2426  _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
2427 
2428  if (IsPlainRail(ti->tile)) {
2429  TrackBits rails = GetTrackBits(ti->tile);
2430 
2431  DrawTrackBits(ti, rails);
2432 
2434 
2436 
2437  if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails, rti);
2438  } else {
2439  /* draw depot */
2440  const DrawTileSprites *dts;
2441  PaletteID pal = PAL_NONE;
2442  SpriteID relocation;
2443 
2445 
2447  /* Draw rail instead of depot */
2448  dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
2449  } else {
2450  dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
2451  }
2452 
2453  SpriteID image;
2454  if (rti->UsesOverlay()) {
2455  image = SPR_FLAT_GRASS_TILE;
2456  } else {
2457  image = dts->ground.sprite;
2458  if (image != SPR_FLAT_GRASS_TILE) image += rti->GetRailtypeSpriteOffset();
2459  }
2460 
2461  /* Adjust ground tile for desert and snow. */
2462  if (IsSnowRailGround(ti->tile)) {
2463  if (image != SPR_FLAT_GRASS_TILE) {
2464  image += rti->snow_offset; // tile with tracks
2465  } else {
2466  image = SPR_FLAT_SNOW_DESERT_TILE; // flat ground
2467  }
2468  }
2469 
2470  DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
2471 
2472  if (rti->UsesOverlay()) {
2473  SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
2474 
2475  switch (GetRailDepotDirection(ti->tile)) {
2476  case DIAGDIR_NE:
2477  if (!IsInvisibilitySet(TO_BUILDINGS)) break;
2478  [[fallthrough]];
2479  case DIAGDIR_SW:
2480  DrawGroundSprite(ground + RTO_X, PAL_NONE);
2481  break;
2482  case DIAGDIR_NW:
2483  if (!IsInvisibilitySet(TO_BUILDINGS)) break;
2484  [[fallthrough]];
2485  case DIAGDIR_SE:
2486  DrawGroundSprite(ground + RTO_Y, PAL_NONE);
2487  break;
2488  default:
2489  break;
2490  }
2491 
2493  SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
2494 
2495  switch (GetRailDepotDirection(ti->tile)) {
2496  case DIAGDIR_NE:
2497  if (!IsInvisibilitySet(TO_BUILDINGS)) break;
2498  [[fallthrough]];
2499  case DIAGDIR_SW:
2500  DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
2501  break;
2502  case DIAGDIR_NW:
2503  if (!IsInvisibilitySet(TO_BUILDINGS)) break;
2504  [[fallthrough]];
2505  case DIAGDIR_SE:
2506  DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
2507  break;
2508  default:
2509  break;
2510  }
2511  }
2512  } else {
2513  /* PBS debugging, draw reserved tracks darker */
2514  if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
2515  switch (GetRailDepotDirection(ti->tile)) {
2516  case DIAGDIR_NE:
2517  if (!IsInvisibilitySet(TO_BUILDINGS)) break;
2518  [[fallthrough]];
2519  case DIAGDIR_SW:
2521  break;
2522  case DIAGDIR_NW:
2523  if (!IsInvisibilitySet(TO_BUILDINGS)) break;
2524  [[fallthrough]];
2525  case DIAGDIR_SE:
2527  break;
2528  default:
2529  break;
2530  }
2531  }
2532  }
2533  int depot_sprite = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT);
2534  relocation = depot_sprite != 0 ? depot_sprite - SPR_RAIL_DEPOT_SE_1 : rti->GetRailtypeSpriteOffset();
2535 
2537 
2538  DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, _drawtile_track_palette);
2539  }
2540  DrawBridgeMiddle(ti);
2541 }
2542 
2543 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
2544 {
2545  const DrawTileSprites *dts = &_depot_gfx_table[dir];
2546  const RailTypeInfo *rti = GetRailTypeInfo(railtype);
2547  SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite;
2548  uint32_t offset = rti->GetRailtypeSpriteOffset();
2549 
2550  if (image != SPR_FLAT_GRASS_TILE) image += offset;
2551  PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
2552 
2553  DrawSprite(image, PAL_NONE, x, y);
2554 
2555  if (rti->UsesOverlay()) {
2557 
2558  switch (dir) {
2559  case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break;
2560  case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break;
2561  default: break;
2562  }
2563  }
2564  int depot_sprite = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
2565  if (depot_sprite != 0) offset = depot_sprite - SPR_RAIL_DEPOT_SE_1;
2566 
2567  DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
2568 }
2569 
2570 static int GetSlopePixelZ_Track(TileIndex tile, uint x, uint y, bool)
2571 {
2572  if (IsPlainRail(tile)) {
2573  auto [tileh, z] = GetTilePixelSlope(tile);
2574  if (tileh == SLOPE_FLAT) return z;
2575 
2576  z += ApplyPixelFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), tileh);
2577  return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
2578  } else {
2579  return GetTileMaxPixelZ(tile);
2580  }
2581 }
2582 
2583 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
2584 {
2585  return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
2586 }
2587 
2588 static void TileLoop_Track(TileIndex tile)
2589 {
2590  RailGroundType old_ground = GetRailGroundType(tile);
2591  RailGroundType new_ground;
2592 
2593  if (old_ground == RAIL_GROUND_WATER) {
2594  TileLoop_Water(tile);
2595  return;
2596  }
2597 
2599  case LT_ARCTIC: {
2600  auto [slope, z] = GetTileSlopeZ(tile);
2601  bool half = false;
2602 
2603  /* for non-flat track, use lower part of track
2604  * in other cases, use the highest part with track */
2605  if (IsPlainRail(tile)) {
2606  TrackBits track = GetTrackBits(tile);
2607  Foundation f = GetRailFoundation(slope, track);
2608 
2609  switch (f) {
2610  case FOUNDATION_NONE:
2611  /* no foundation - is the track on the upper side of three corners raised tile? */
2612  if (IsSlopeWithThreeCornersRaised(slope)) z++;
2613  break;
2614 
2615  case FOUNDATION_INCLINED_X:
2616  case FOUNDATION_INCLINED_Y:
2617  /* sloped track - is it on a steep slope? */
2618  if (IsSteepSlope(slope)) z++;
2619  break;
2620 
2622  /* only lower part of steep slope */
2623  z++;
2624  break;
2625 
2626  default:
2627  /* if it is a steep slope, then there is a track on higher part */
2628  if (IsSteepSlope(slope)) z++;
2629  z++;
2630  break;
2631  }
2632 
2634  } else {
2635  /* is the depot on a non-flat tile? */
2636  if (slope != SLOPE_FLAT) z++;
2637  }
2638 
2639  /* 'z' is now the lowest part of the highest track bit -
2640  * for sloped track, it is 'z' of lower part
2641  * for two track bits, it is 'z' of higher track bit
2642  * For non-continuous foundations (and STEEP_BOTH), 'half' is set */
2643  if (z > GetSnowLine()) {
2644  if (half && z - GetSnowLine() == 1) {
2645  /* track on non-continuous foundation, lower part is not under snow */
2646  new_ground = RAIL_GROUND_HALF_SNOW;
2647  } else {
2648  new_ground = RAIL_GROUND_ICE_DESERT;
2649  }
2650  goto set_ground;
2651  }
2652  break;
2653  }
2654 
2655  case LT_TROPIC:
2656  if (GetTropicZone(tile) == TROPICZONE_DESERT) {
2657  new_ground = RAIL_GROUND_ICE_DESERT;
2658  goto set_ground;
2659  }
2660  break;
2661  }
2662 
2663  new_ground = RAIL_GROUND_GRASS;
2664 
2665  if (IsPlainRail(tile) && old_ground != RAIL_GROUND_BARREN) { // wait until bottom is green
2666  /* determine direction of fence */
2667  TrackBits rail = GetTrackBits(tile);
2668 
2669  Owner owner = GetTileOwner(tile);
2670  uint8_t fences = 0;
2671 
2672  for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
2674 
2675  /* Track bit on this edge => no fence. */
2676  if ((rail & dir_to_trackbits[d]) != TRACK_BIT_NONE) continue;
2677 
2678  TileIndex tile2 = tile + TileOffsByDiagDir(d);
2679 
2680  /* Show fences if it's a house, industry, object, road, tunnelbridge or not owned by us. */
2681  if (!IsValidTile(tile2) || IsTileType(tile2, MP_HOUSE) || IsTileType(tile2, MP_INDUSTRY) ||
2682  IsTileType(tile2, MP_ROAD) || (IsTileType(tile2, MP_OBJECT) && !IsObjectType(tile2, OBJECT_OWNED_LAND)) || IsTileType(tile2, MP_TUNNELBRIDGE) || !IsTileOwner(tile2, owner)) {
2683  fences |= 1 << d;
2684  }
2685  }
2686 
2687  switch (fences) {
2688  case 0: break;
2689  case (1 << DIAGDIR_NE): new_ground = RAIL_GROUND_FENCE_NE; break;
2690  case (1 << DIAGDIR_SE): new_ground = RAIL_GROUND_FENCE_SE; break;
2691  case (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_SW; break;
2692  case (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_NW; break;
2693  case (1 << DIAGDIR_NE) | (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_NESW; break;
2694  case (1 << DIAGDIR_SE) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_SENW; break;
2695  case (1 << DIAGDIR_NE) | (1 << DIAGDIR_SE): new_ground = RAIL_GROUND_FENCE_VERT1; break;
2696  case (1 << DIAGDIR_NE) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
2697  case (1 << DIAGDIR_SE) | (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
2698  case (1 << DIAGDIR_SW) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_VERT2; break;
2699  default: NOT_REACHED();
2700  }
2701  }
2702 
2703 set_ground:
2704  if (old_ground != new_ground) {
2705  SetRailGroundType(tile, new_ground);
2706  MarkTileDirtyByTile(tile);
2707  }
2708 }
2709 
2710 
2711 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint, DiagDirection side)
2712 {
2713  /* Case of half tile slope with water. */
2714  if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(GetTileSlope(tile))) {
2715  TrackBits tb = GetTrackBits(tile);
2716  switch (tb) {
2717  default: NOT_REACHED();
2718  case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
2719  case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
2720  case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
2721  case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
2722  }
2724  }
2725 
2726  if (mode != TRANSPORT_RAIL) return 0;
2727 
2728  TrackBits trackbits = TRACK_BIT_NONE;
2729  TrackdirBits red_signals = TRACKDIR_BIT_NONE;
2730 
2731  switch (GetRailTileType(tile)) {
2732  default: NOT_REACHED();
2733  case RAIL_TILE_NORMAL:
2734  trackbits = GetTrackBits(tile);
2735  break;
2736 
2737  case RAIL_TILE_SIGNALS: {
2738  trackbits = GetTrackBits(tile);
2739  uint8_t a = GetPresentSignals(tile);
2740  uint b = GetSignalStates(tile);
2741 
2742  b &= a;
2743 
2744  /* When signals are not present (in neither direction),
2745  * we pretend them to be green. Otherwise, it depends on
2746  * the signal type. For signals that are only active from
2747  * one side, we set the missing signals explicitly to
2748  * `green'. Otherwise, they implicitly become `red'. */
2749  if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
2750  if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
2751 
2752  if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
2753  if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
2754  if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
2755  if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
2756 
2757  break;
2758  }
2759 
2760  case RAIL_TILE_DEPOT: {
2762 
2763  if (side != INVALID_DIAGDIR && side != dir) break;
2764 
2765  trackbits = DiagDirToDiagTrackBits(dir);
2766  break;
2767  }
2768  }
2769 
2770  return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
2771 }
2772 
2773 static bool ClickTile_Track(TileIndex tile)
2774 {
2775  if (!IsRailDepot(tile)) return false;
2776 
2777  ShowDepotWindow(tile, VEH_TRAIN);
2778  return true;
2779 }
2780 
2781 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
2782 {
2783  const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
2784  td->rail_speed = rti->max_speed;
2785  td->railtype = rti->strings.name;
2786  td->owner[0] = GetTileOwner(tile);
2787  switch (GetRailTileType(tile)) {
2788  case RAIL_TILE_NORMAL:
2789  td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
2790  break;
2791 
2792  case RAIL_TILE_SIGNALS: {
2793  static const StringID signal_type[6][6] = {
2794  {
2795  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
2796  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
2797  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
2798  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
2799  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
2800  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
2801  },
2802  {
2803  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
2804  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
2805  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
2806  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
2807  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
2808  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
2809  },
2810  {
2811  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
2812  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
2813  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
2814  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
2815  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
2816  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
2817  },
2818  {
2819  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
2820  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
2821  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
2822  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
2823  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
2824  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
2825  },
2826  {
2827  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
2828  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
2829  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
2830  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
2831  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
2832  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
2833  },
2834  {
2835  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
2836  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
2837  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
2838  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
2839  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
2840  STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
2841  }
2842  };
2843 
2844  SignalType primary_signal;
2845  SignalType secondary_signal;
2846  if (HasSignalOnTrack(tile, TRACK_UPPER)) {
2847  primary_signal = GetSignalType(tile, TRACK_UPPER);
2848  secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
2849  } else {
2850  secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
2851  }
2852 
2853  td->str = signal_type[secondary_signal][primary_signal];
2854  break;
2855  }
2856 
2857  case RAIL_TILE_DEPOT:
2858  td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
2859  if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
2860  if (td->rail_speed > 0) {
2861  td->rail_speed = std::min<uint16_t>(td->rail_speed, 61);
2862  } else {
2863  td->rail_speed = 61;
2864  }
2865  }
2866  td->build_date = Depot::GetByTile(tile)->build_date;
2867  break;
2868 
2869  default:
2870  NOT_REACHED();
2871  }
2872 }
2873 
2874 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
2875 {
2876  if (!IsTileOwner(tile, old_owner)) return;
2877 
2878  if (new_owner != INVALID_OWNER) {
2879  /* Update company infrastructure counts. No need to dirty windows here, we'll redraw the whole screen anyway. */
2880  uint num_pieces = 1;
2881  if (IsPlainRail(tile)) {
2882  TrackBits bits = GetTrackBits(tile);
2883  num_pieces = CountBits(bits);
2884  if (TracksOverlap(bits)) num_pieces *= num_pieces;
2885  }
2886  RailType rt = GetRailType(tile);
2887  Company::Get(old_owner)->infrastructure.rail[rt] -= num_pieces;
2888  Company::Get(new_owner)->infrastructure.rail[rt] += num_pieces;
2889 
2890  if (HasSignals(tile)) {
2891  uint num_sigs = CountBits(GetPresentSignals(tile));
2892  Company::Get(old_owner)->infrastructure.signal -= num_sigs;
2893  Company::Get(new_owner)->infrastructure.signal += num_sigs;
2894  }
2895 
2896  SetTileOwner(tile, new_owner);
2897  } else {
2899  }
2900 }
2901 
2902 static const uint8_t _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
2903 static const uint8_t _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
2904 static const int8_t _deltacoord_leaveoffset[8] = {
2905  -1, 0, 1, 0, /* x */
2906  0, 1, 0, -1 /* y */
2907 };
2908 
2909 
2917 {
2919  int length = v->CalcNextVehicleOffset();
2920 
2921  switch (dir) {
2922  case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
2923  case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
2924  case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
2925  case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
2926  default: NOT_REACHED();
2927  }
2928 }
2929 
2935 {
2936  /* This routine applies only to trains in depot tiles. */
2937  if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
2938 
2939  /* Depot direction. */
2941 
2942  uint8_t fract_coord = (x & 0xF) + ((y & 0xF) << 4);
2943 
2944  /* Make sure a train is not entering the tile from behind. */
2945  if (_fractcoords_behind[dir] == fract_coord) return VETSB_CANNOT_ENTER;
2946 
2947  Train *v = Train::From(u);
2948 
2949  /* Leaving depot? */
2950  if (v->direction == DiagDirToDir(dir)) {
2951  /* Calculate the point where the following wagon should be activated. */
2952  int length = v->CalcNextVehicleOffset();
2953 
2954  uint8_t fract_coord_leave =
2955  ((_fractcoords_enter[dir] & 0x0F) + // x
2956  (length + 1) * _deltacoord_leaveoffset[dir]) +
2957  (((_fractcoords_enter[dir] >> 4) + // y
2958  ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
2959 
2960  if (fract_coord_leave == fract_coord) {
2961  /* Leave the depot. */
2962  if ((v = v->Next()) != nullptr) {
2963  v->vehstatus &= ~VS_HIDDEN;
2964  v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
2965  }
2966  }
2967  } else if (_fractcoords_enter[dir] == fract_coord) {
2968  /* Entering depot. */
2969  assert(DiagDirToDir(ReverseDiagDir(dir)) == v->direction);
2970  v->track = TRACK_BIT_DEPOT,
2971  v->vehstatus |= VS_HIDDEN;
2972  v->direction = ReverseDir(v->direction);
2973  if (v->Next() == nullptr) VehicleEnterDepot(v->First());
2974  v->tile = tile;
2975 
2977  return VETSB_ENTERED_WORMHOLE;
2978  }
2979 
2980  return VETSB_CONTINUE;
2981 }
2982 
2994 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, int z_old, Slope tileh_old, int z_new, Slope tileh_new, TrackBits rail_bits)
2995 {
2996  if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
2997 
2998  /* Is the slope-rail_bits combination valid in general? I.e. is it safe to call GetRailFoundation() ? */
2999  if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
3000 
3001  /* Get the slopes on top of the foundations */
3002  z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), tileh_old);
3003  z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), tileh_new);
3004 
3005  Corner track_corner;
3006  switch (rail_bits) {
3007  case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
3008  case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
3009  case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
3010  case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
3011 
3012  /* Surface slope must not be changed */
3013  default:
3014  if (z_old != z_new || tileh_old != tileh_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
3015  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
3016  }
3017 
3018  /* The height of the track_corner must not be changed. The rest ensures GetRailFoundation() already. */
3019  z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
3020  z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
3021  if (z_old != z_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
3022 
3023  CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
3024  /* Make the ground dirty, if surface slope has changed */
3025  if (tileh_old != tileh_new) {
3026  /* If there is flat water on the lower halftile add the cost for clearing it */
3027  if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
3028  if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
3029  }
3030  return cost;
3031 }
3032 
3036 static Vehicle *EnsureNoShipProc(Vehicle *v, void *)
3037 {
3038  return v->type == VEH_SHIP ? v : nullptr;
3039 }
3040 
3041 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
3042 {
3043  auto [tileh_old, z_old] = GetTileSlopeZ(tile);
3044  if (IsPlainRail(tile)) {
3045  TrackBits rail_bits = GetTrackBits(tile);
3046  /* Is there flat water on the lower halftile that must be cleared expensively? */
3047  bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
3048 
3049  /* Allow clearing the water only if there is no ship */
3050  if (was_water && HasVehicleOnPos(tile, nullptr, &EnsureNoShipProc)) return_cmd_error(STR_ERROR_SHIP_IN_THE_WAY);
3051 
3052  /* First test autoslope. However if it succeeds we still have to test the rest, because non-autoslope terraforming is cheaper. */
3053  CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
3054 
3055  /* When there is only a single horizontal/vertical track, one corner can be terraformed. */
3056  Corner allowed_corner;
3057  switch (rail_bits) {
3058  case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
3059  case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
3060  case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
3061  case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
3062  default: return autoslope_result;
3063  }
3064 
3065  Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
3066 
3067  /* Do not allow terraforming if allowed_corner is part of anti-zig-zag foundations */
3068  if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
3069 
3070  /* Everything is valid, which only changes allowed_corner */
3071  for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
3072  if (allowed_corner == corner) continue;
3073  if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
3074  }
3075 
3076  /* Make the ground dirty */
3077  if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
3078 
3079  /* allow terraforming */
3080  return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
3082  AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
3083  return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
3084  }
3085  return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
3086 }
3087 
3088 
3089 extern const TileTypeProcs _tile_type_rail_procs = {
3090  DrawTile_Track, // draw_tile_proc
3091  GetSlopePixelZ_Track, // get_slope_z_proc
3092  ClearTile_Track, // clear_tile_proc
3093  nullptr, // add_accepted_cargo_proc
3094  GetTileDesc_Track, // get_tile_desc_proc
3095  GetTileTrackStatus_Track, // get_tile_track_status_proc
3096  ClickTile_Track, // click_tile_proc
3097  nullptr, // animate_tile_proc
3098  TileLoop_Track, // tile_loop_proc
3099  ChangeTileOwner_Track, // change_tile_owner_proc
3100  nullptr, // add_produced_cargo_proc
3101  VehicleEnter_Track, // vehicle_enter_tile_proc
3102  GetFoundation_Track, // get_foundation_proc
3103  TerraformTile_Track, // terraform_tile_proc
3104 };
Functions related to autoslope.
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
bool AutoslopeEnabled()
Tests if autoslope is enabled for _current_company.
Definition: autoslope.h:65
Class for backupping variables and making sure they are restored later.
constexpr bool HasExactlyOneBit(T value)
Test whether value has exactly 1 bit set.
constexpr debug_inline bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr uint CountBits(T value)
Counts the number of set bits in a variable.
constexpr T ToggleBit(T &x, const uint8_t y)
Toggles a bit in a variable.
constexpr T KillFirstBit(T value)
Clear the first bit in an integer.
void DrawBridgeMiddle(const TileInfo *ti)
Draw the middle bits of a bridge.
bool IsBridgeAbove(Tile t)
checks if a bridge is set above the ground of this tile
Definition: bridge_map.h:45
bool IsBridge(Tile t)
Checks if this is a bridge, instead of a tunnel.
Definition: bridge_map.h:24
Common return value for all commands.
Definition: command_type.h:23
bool Succeeded() const
Did this command succeed?
Definition: command_type.h:162
void AddCost(const Money &cost)
Adds the given cost to the cost of the command.
Definition: command_type.h:63
bool Failed() const
Did this command fail?
Definition: command_type.h:171
StringID GetErrorMessage() const
Returns the error message of a command.
Definition: command_type.h:142
void MakeError(StringID message, StringID extra_message=INVALID_STRING_ID)
Makes this CommandCost behave like an error command.
Definition: command_type.h:101
This struct contains all the info that is needed to draw and construct tracks.
Definition: rail.h:127
SpriteID single_x
single piece of rail in X direction, without ground
Definition: rail.h:137
struct RailTypeInfo::@25 cursor
Cursors associated with the rail type.
uint16_t max_speed
Maximum speed for vehicles travelling on this rail type.
Definition: rail.h:231
SpriteID build_tunnel
button for building a tunnel
Definition: rail.h:159
CursorID rail_swne
Cursor for building rail in X direction.
Definition: rail.h:166
SpriteID convert_rail
button for converting rail
Definition: rail.h:160
CursorID convert
Cursor for converting track.
Definition: rail.h:172
struct RailTypeInfo::@23 base_sprites
Struct containing the main sprites.
CursorID depot
Cursor for building a depot.
Definition: rail.h:170
struct RailTypeInfo::@26 strings
Strings associated with the rail type.
RailTypes powered_railtypes
bitmask to the OTHER railtypes on which an engine of THIS railtype generates power
Definition: rail.h:188
RailTypes introduces_railtypes
Bitmask of which other railtypes are introduced when this railtype is introduced.
Definition: rail.h:266
SpriteID ground
ground sprite for a 3-way switch
Definition: rail.h:136
CursorID rail_nwse
Cursor for building rail in Y direction.
Definition: rail.h:168
SpriteID build_x_rail
button for building single rail in X direction
Definition: rail.h:154
uint8_t sorting_order
The sorting order of this railtype for the toolbar dropdown.
Definition: rail.h:271
RailTypeLabel label
Unique 32 bit rail type identifier.
Definition: rail.h:236
SpriteID single_n
single piece of rail in the northern corner
Definition: rail.h:139
CursorID rail_ew
Cursor for building rail in E-W direction.
Definition: rail.h:167
SpriteID auto_rail
button for the autorail construction
Definition: rail.h:157
CursorID autorail
Cursor for autorail tool.
Definition: rail.h:169
SpriteID single_y
single piece of rail in Y direction, without ground
Definition: rail.h:138
StringID name
Name of this rail type.
Definition: rail.h:176
RailTypes compatible_railtypes
bitmask to the OTHER railtypes on which an engine of THIS railtype can physically travel
Definition: rail.h:191
uint GetRailtypeSpriteOffset() const
Offset between the current railtype and normal rail.
Definition: rail.h:295
SpriteID single_s
single piece of rail in the southern corner
Definition: rail.h:140
RailTypeFlags flags
Bit mask of rail type flags.
Definition: rail.h:211
SpriteID signals[SIGTYPE_END][2][2]
signal GUI sprites (type, variant, state)
Definition: rail.h:161
SpriteID build_ew_rail
button for building single rail in E-W direction
Definition: rail.h:155
SpriteID build_y_rail
button for building single rail in Y direction
Definition: rail.h:156
SpriteID track_ns
two pieces of rail in North and South corner (East-West direction)
Definition: rail.h:135
RailTypeLabelList alternate_labels
Rail type labels this type provides in addition to the main label.
Definition: rail.h:241
SpriteID snow_offset
sprite number difference between a piece of track on a snowy ground and the corresponding one on norm...
Definition: rail.h:185
SpriteID track_y
single piece of rail in Y direction, with ground
Definition: rail.h:134
SpriteID build_depot
button for building depots
Definition: rail.h:158
struct RailTypeInfo::@24 gui_sprites
struct containing the sprites for the rail GUI.
SpriteID single_w
single piece of rail in the western corner
Definition: rail.h:142
SpriteID single_e
single piece of rail in the eastern corner
Definition: rail.h:141
SpriteID build_ns_rail
button for building single rail in N-S direction
Definition: rail.h:153
CursorID rail_ns
Cursor for building rail in N-S direction.
Definition: rail.h:165
SpriteID tunnel
tunnel sprites base
Definition: rail.h:145
SpriteID single_sloped
single piece of rail for slopes
Definition: rail.h:143
static std::unique_ptr< TileIterator > Create(TileIndex corner1, TileIndex corner2, bool diagonal)
Create either an OrthogonalTileIterator or DiagonalTileIterator given the diagonal parameter.
Definition: tilearea.cpp:291
static Date date
Current date in days (day counter).
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
Definition: command_func.h:28
#define return_cmd_error(errcode)
Returns from a function with a specific StringID as error.
Definition: command_func.h:38
DoCommandFlag
List of flags for a command.
Definition: command_type.h:374
@ DC_AUTO
don't allow building on structures
Definition: command_type.h:377
@ DC_BANKRUPT
company bankrupts, skip money check, skip vehicle on tile check in some cases
Definition: command_type.h:382
@ DC_EXEC
execute the given command
Definition: command_type.h:376
Definition of stuff that is very close to a company, like the company struct itself.
CommandCost CheckTileOwnership(TileIndex tile)
Check whether the current owner owns the stuff on the given tile.
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:52
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:53
void DirtyCompanyInfrastructureWindows(CompanyID company)
Redraw all windows with company infrastructure counts.
GUI Functions related to companies.
Owner
Enum for all companies/owners.
Definition: company_type.h:18
@ INVALID_OWNER
An invalid owner.
Definition: company_type.h:29
@ OWNER_DEITY
The object is owned by a superuser / goal script.
Definition: company_type.h:27
@ OWNER_WATER
The tile/execution is done by "water".
Definition: company_type.h:26
Some simple functions to help with accessing containers.
bool include(Container &container, typename Container::const_reference &item)
Helper function to append an item to a container if it is not already contained.
Base for all depots (except hangars)
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:27
void ShowDepotWindow(TileIndex tile, VehicleType type)
Opens a depot window.
Definition: depot_gui.cpp:1164
Direction DiagDirToDir(DiagDirection dir)
Convert a DiagDirection to a Direction.
DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
Direction ReverseDir(Direction d)
Return the reverse of a direction.
bool IsValidDiagDirection(DiagDirection d)
Checks if an integer value is a valid DiagDirection.
Axis DiagDirToAxis(DiagDirection d)
Convert a DiagDirection to the axis.
@ AXIS_X
The X axis.
@ AXIS_Y
The y axis.
DiagDirection
Enumeration for diagonal directions.
@ DIAGDIR_NE
Northeast, upper right on your monitor.
@ DIAGDIR_NW
Northwest.
@ DIAGDIR_SE
Southeast.
@ DIAGDIR_END
Used for iterations.
@ DIAGDIR_BEGIN
Used for iterations.
@ INVALID_DIAGDIR
Flag for an invalid DiagDirection.
@ DIAGDIR_SW
Southwest.
static const uint LEVELCROSSING_TRACKBIT_FACTOR
Multiplier for how many regular track bits a level crossing counts.
Definition: economy_type.h:243
@ EXPENSES_CONSTRUCTION
Construction costs.
Definition: economy_type.h:173
static const uint TUNNELBRIDGE_TRACKBIT_FACTOR
Multiplier for how many regular track bits a tunnel/bridge counts.
Definition: economy_type.h:241
void DrawRailCatenary(const TileInfo *ti)
Draws overhead wires and pylons for electric railways.
Definition: elrail.cpp:568
header file for electrified rail specific functions
bool HasRailCatenaryDrawn(RailType rt)
Test if we should draw rail catenary.
Definition: elrail_func.h:30
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:988
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:18
uint32_t PaletteID
The number of the palette.
Definition: gfx_type.h:19
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
Definition: landscape.cpp:609
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:2057
uint GetPartialPixelZ(int x, int y, Slope corners)
Determines height at given coordinate of a slope.
Definition: landscape.cpp:228
TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
Returns information about trackdirs and signal states.
Definition: landscape.cpp:554
void DrawFoundation(TileInfo *ti, Foundation f)
Draw foundation f at tile ti.
Definition: landscape.cpp:425
int GetSlopeZInCorner(Slope tileh, Corner corner)
Determine the Z height of a corner relative to TileZ.
Definition: landscape.cpp:336
uint ApplyFoundationToSlope(Foundation f, Slope &s)
Applies a foundation to a slope.
Definition: landscape.cpp:170
int GetSlopePixelZ(int x, int y, bool ground_vehicle)
Return world Z coordinate of a given point of a tile.
Definition: landscape.cpp:303
uint ApplyPixelFoundationToSlope(Foundation f, Slope &s)
Applies a foundation to a slope.
Definition: landscape.h:126
int GetSlopePixelZInCorner(Slope tileh, Corner corner)
Determine the Z height of a corner relative to TileZ.
Definition: landscape.h:53
Command definitions related to landscape (slopes etc.).
TileIndex AddTileIndexDiffCWrap(TileIndex tile, TileIndexDiffC diff)
Add a TileIndexDiffC to a TileIndex and returns the new one.
Definition: map_func.h:512
TileIndexDiff ToTileIndexDiff(TileIndexDiffC tidc)
Return the offset between two tiles from a TileIndexDiffC struct.
Definition: map_func.h:440
TileIndex TileAddByDiagDir(TileIndex tile, DiagDirection dir)
Adds a DiagDir to a tile.
Definition: map_func.h:608
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition: map_func.h:425
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition: map_func.h:415
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition: map_func.h:567
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition: math_func.hpp:23
constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
Definition: math_func.hpp:268
@ TCX_UPPER_HALFTILE
Querying information about the upper part of a tile with halftile foundation.
@ TCX_NORMAL
Nothing special.
Functions/types related to NewGRF debugging.
void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
Delete inspect window for a given feature and index.
SpriteID GetCustomSignalSprite(const RailTypeInfo *rti, TileIndex tile, SignalType type, SignalVariant var, SignalState state, bool gui)
Get the sprite to draw for a given signal.
SpriteID GetCustomRailSprite(const RailTypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg, TileContext context, uint *num_results)
Get the sprite to draw for the given tile.
NewGRF handling of rail types.
Map accessors for object tiles.
bool IsObjectType(Tile t, ObjectType type)
Check whether the object on a tile is of a specific type.
Definition: object_map.h:25
static const ObjectType OBJECT_OWNED_LAND
Owned land 'flag'.
Definition: object_type.h:19
@ DO_FULL_DETAIL
Also draw details of track and roads.
Definition: openttd.h:50
TrackBits GetReservedTrackbits(TileIndex t)
Get the reserved trackbits for any tile, regardless of type.
Definition: pbs.cpp:24
Train * GetTrainForReservation(TileIndex tile, Track track)
Find the train which has reserved a specific path.
Definition: pbs.cpp:330
bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg)
Determine whether a certain track on a tile is a safe position to end a path.
Definition: pbs.cpp:380
PBS support routines.
bool HasReservedTracks(TileIndex tile, TrackBits tracks)
Check whether some of tracks is reserved on a tile.
Definition: pbs.h:58
bool ValParamRailType(const RailType rail)
Validate functions for rail building.
Definition: rail.cpp:206
Money RailConvertCost(RailType from, RailType to)
Calculates the cost of rail conversion.
Definition: rail.h:403
@ RTSG_GROUND
Main group of ground images.
Definition: rail.h:52
@ RTSG_CURSORS
Cursor and toolbar icon images.
Definition: rail.h:50
@ RTSG_GROUND_COMPLETE
Complete ground images.
Definition: rail.h:62
@ RTSG_OVERLAY
Images for overlaying track.
Definition: rail.h:51
@ RTSG_DEPOT
Depot images.
Definition: rail.h:58
@ RTSG_FENCES
Fence images.
Definition: rail.h:59
Money RailClearCost(RailType railtype)
Returns the 'cost' of clearing the specified railtype.
Definition: rail.h:386
Money RailBuildCost(RailType railtype)
Returns the cost of building the specified railtype.
Definition: rail.h:375
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition: rail.h:307
bool IsCompatibleRail(RailType enginetype, RailType tiletype)
Checks if an engine of the given RailType can drive on a tile with a given RailType.
Definition: rail.h:322
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:335
@ RTO_Y
Piece of rail in Y direction.
Definition: rail.h:72
@ RTO_S
Piece of rail in southern corner.
Definition: rail.h:74
@ RTO_JUNCTION_NE
Ballast for junction 'pointing' NE.
Definition: rail.h:83
@ RTO_JUNCTION_NSEW
Ballast for full junction.
Definition: rail.h:86
@ RTO_JUNCTION_SW
Ballast for junction 'pointing' SW.
Definition: rail.h:82
@ RTO_SLOPE_SE
Piece of rail on slope with south-east raised.
Definition: rail.h:78
@ RTO_E
Piece of rail in eastern corner.
Definition: rail.h:75
@ RTO_W
Piece of rail in western corner.
Definition: rail.h:76
@ RTO_CROSSING_XY
Crossing of X and Y rail, with ballast.
Definition: rail.h:81
@ RTO_SLOPE_SW
Piece of rail on slope with south-west raised.
Definition: rail.h:79
@ RTO_SLOPE_NW
Piece of rail on slope with north-west raised.
Definition: rail.h:80
@ RTO_JUNCTION_NW
Ballast for junction 'pointing' NW.
Definition: rail.h:85
@ RTO_JUNCTION_SE
Ballast for junction 'pointing' SE.
Definition: rail.h:84
@ RTO_SLOPE_NE
Piece of rail on slope with north-east raised.
Definition: rail.h:77
@ RTO_X
Piece of rail in X direction.
Definition: rail.h:71
@ RTO_N
Piece of rail in northern corner.
Definition: rail.h:73
RailFenceOffset
Offsets from base sprite for fence sprites.
Definition: rail.h:102
@ RFO_FLAT_RIGHT
Slope FLAT, Track RIGHT, Fence W.
Definition: rail.h:113
@ RFO_FLAT_Y_NE
Slope FLAT, Track Y, Fence NE.
Definition: rail.h:104
@ RFO_SLOPE_NW_SW
Slope NW, Track Y, Fence SW.
Definition: rail.h:118
@ RFO_FLAT_X_SE
Slope FLAT, Track X, Fence SE.
Definition: rail.h:111
@ RFO_SLOPE_NW_NE
Slope NW, Track Y, Fence NE.
Definition: rail.h:110
@ RFO_SLOPE_SE_SW
Slope SE, Track Y, Fence SW.
Definition: rail.h:116
@ RFO_SLOPE_NE_SE
Slope NE, Track X, Fence SE.
Definition: rail.h:117
@ RFO_FLAT_LOWER
Slope FLAT, Track LOWER, Fence N.
Definition: rail.h:114
@ RFO_SLOPE_SW_SE
Slope SW, Track X, Fence SE.
Definition: rail.h:115
@ RFO_FLAT_UPPER
Slope FLAT, Track UPPER, Fence S.
Definition: rail.h:106
@ RFO_SLOPE_SE_NE
Slope SE, Track Y, Fence NE.
Definition: rail.h:108
@ RFO_FLAT_Y_SW
Slope FLAT, Track Y, Fence SW.
Definition: rail.h:112
@ RFO_FLAT_LEFT
Slope FLAT, Track LEFT, Fence E.
Definition: rail.h:105
@ RFO_SLOPE_NE_NW
Slope NE, Track X, Fence NW.
Definition: rail.h:109
@ RFO_FLAT_X_NW
Slope FLAT, Track X, Fence NW.
Definition: rail.h:103
@ RFO_SLOPE_SW_NW
Slope SW, Track X, Fence NW.
Definition: rail.h:107
@ RTF_HIDDEN
Bit number for hiding from selection.
Definition: rail.h:28
@ RTF_NO_SPRITE_COMBINE
Bit number for using non-combined junctions.
Definition: rail.h:29
bool RailNoLevelCrossings(RailType rt)
Test if a RailType disallows build of level crossings.
Definition: rail.h:345
static Vehicle * UpdateTrainPowerProc(Vehicle *v, void *data)
Update power of train under which is the railtype being converted.
Definition: rail_cmd.cpp:1533
int TicksToLeaveDepot(const Train *v)
Compute number of ticks when next wagon will leave a depot.
Definition: rail_cmd.cpp:2916
static CommandCost CheckTrackCombination(TileIndex tile, TrackBits to_build)
Check that the new track bits may be built.
Definition: rail_cmd.cpp:241
CommandCost CmdRemoveRailroadTrack(DoCommandFlag flags, TileIndex end_tile, TileIndex start_tile, Track track)
Build rail on a stretch of track.
Definition: rail_cmd.cpp:947
CommandCost CmdRemoveSingleSignal(DoCommandFlag flags, TileIndex tile, Track track)
Remove signals.
Definition: rail_cmd.cpp:1461
CommandCost CmdBuildSingleSignal(DoCommandFlag flags, TileIndex tile, Track track, SignalType sigtype, SignalVariant sigvar, bool convert_signal, bool skip_existing_signals, bool ctrl_pressed, SignalType cycle_start, SignalType cycle_stop, uint8_t num_dir_cycle, uint8_t signals_copy)
Build signals, alternate between double/single, signal/semaphore, pre/exit/combo-signals,...
Definition: rail_cmd.cpp:1052
static uint GetSaveSlopeZ(uint x, uint y, Track track)
Get surface height in point (x,y) On tiles with halftile foundations move (x,y) to a safe point wrt.
Definition: rail_cmd.cpp:1859
CommandCost CmdRemoveSignalTrack(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, Track track, bool autofill)
Remove signals on a stretch of track.
Definition: rail_cmd.cpp:1527
bool FloodHalftile(TileIndex t)
Called from water_cmd if a non-flat rail-tile gets flooded and should be converted to shore.
Definition: rail_cmd.cpp:762
RailType AllocateRailType(RailTypeLabel label)
Allocate a new rail type label.
Definition: rail_cmd.cpp:150
static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
Tile callback routine when vehicle enters tile.
Definition: rail_cmd.cpp:2934
static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile)
Tests if a track can be build on a tile.
Definition: rail_cmd.cpp:392
static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image, uint num_sprites)
Draw fence at NW border matching the tile slope.
Definition: rail_cmd.cpp:1968
static const TrackBits _valid_tracks_without_foundation[15]
Valid TrackBits on a specific (non-steep)-slope without foundation.
Definition: rail_cmd.cpp:262
static const TrackBits _valid_tracks_on_leveled_foundation[15]
Valid TrackBits on a specific (non-steep)-slope with leveled foundation.
Definition: rail_cmd.cpp:284
static CommandCost EnsureNoTrainOnTrack(TileIndex tile, Track track)
Tests if a vehicle interacts with the specified track.
Definition: rail_cmd.cpp:229
static void DrawTrackBits(TileInfo *ti, TrackBits track)
Draw ground sprite and track bits.
Definition: rail_cmd.cpp:2237
static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image, uint num_sprites)
Draw fence at NE border matching the tile slope.
Definition: rail_cmd.cpp:1988
CommandCost CmdBuildRailroadTrack(DoCommandFlag flags, TileIndex end_tile, TileIndex start_tile, RailType railtype, Track track, bool auto_remove_signals, bool fail_on_obstacle)
Build rail on a stretch of track.
Definition: rail_cmd.cpp:932
static CommandCost CmdRailTrackHelper(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, RailType railtype, Track track, bool remove, bool auto_remove_signals, bool fail_on_obstacle)
Build or remove a stretch of railroad tracks.
Definition: rail_cmd.cpp:876
SignalOffsets
Enum holding the signal offset in the sprite sheet according to the side it is representing.
Definition: rail_cmd.cpp:51
void InitRailTypes()
Resolve sprites of custom rail types.
Definition: rail_cmd.cpp:130
static FenceOffset _fence_offsets[]
Offsets for drawing fences.
Definition: rail_cmd.cpp:1925
static void DrawTrackFence(const TileInfo *ti, SpriteID base_image, uint num_sprites, RailFenceOffset rfo)
Draw a track fence.
Definition: rail_cmd.cpp:1951
CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, TileIndex area_start, RailType totype, bool diagonal)
Convert one rail type to the other.
Definition: rail_cmd.cpp:1553
void ResetRailTypes()
Reset all rail type information to its default values.
Definition: rail_cmd.cpp:65
static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, int z_old, Slope tileh_old, int z_new, Slope tileh_new, TrackBits rail_bits)
Tests if autoslope is allowed.
Definition: rail_cmd.cpp:2994
CommandCost CmdBuildTrainDepot(DoCommandFlag flags, TileIndex tile, RailType railtype, DiagDirection dir)
Build a train depot.
Definition: rail_cmd.cpp:963
static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image, uint num_sprites)
Draw fence at SW border matching the tile slope.
Definition: rail_cmd.cpp:1998
static Vehicle * EnsureNoShipProc(Vehicle *v, void *)
Test-procedure for HasVehicleOnPos to check for a ship.
Definition: rail_cmd.cpp:3036
static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image, uint num_sprites)
Draw fence at SE border matching the tile slope.
Definition: rail_cmd.cpp:1978
static bool CompareRailTypes(const RailType &first, const RailType &second)
Compare railtypes based on their sorting order.
Definition: rail_cmd.cpp:122
CommandCost CmdBuildSignalTrack(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, Track track, SignalType sigtype, SignalVariant sigvar, bool mode, bool autofill, bool minimise_gaps, uint8_t signal_density)
Build signals on a stretch of track.
Definition: rail_cmd.cpp:1449
CommandCost CmdBuildSingleRail(DoCommandFlag flags, TileIndex tile, RailType railtype, Track track, bool auto_remove_signals)
Build a single piece of rail.
Definition: rail_cmd.cpp:426
Foundation GetRailFoundation(Slope tileh, TrackBits bits)
Checks if a track combination is valid on a specific slope and returns the needed foundation.
Definition: rail_cmd.cpp:312
static CommandCost CmdSignalTrackHelper(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, Track track, SignalType sigtype, SignalVariant sigvar, bool mode, bool remove, bool autofill, bool minimise_gaps, int signal_density)
Build many signals by dragging; AutoSignals.
Definition: rail_cmd.cpp:1258
CommandCost CmdRemoveSingleRail(DoCommandFlag flags, TileIndex tile, Track track)
Remove a single piece of track.
Definition: rail_cmd.cpp:615
std::vector< Train * > TrainList
Helper type for lists/vectors of trains.
Definition: rail_cmd.cpp:44
static void DrawTrackDetails(const TileInfo *ti, const RailTypeInfo *rti)
Draw track fences.
Definition: rail_cmd.cpp:2010
Command definitions for rail.
uint GetSignalStates(Tile tile)
Set the states of the signals (Along/AgainstTrackDir)
Definition: rail_map.h:362
void MakeRailDepot(Tile tile, Owner owner, DepotID depot_id, DiagDirection dir, RailType rail_type)
Make a rail depot.
Definition: rail_map.h:552
RailType GetRailType(Tile t)
Gets the rail type of the given tile.
Definition: rail_map.h:115
bool HasSignalOnTrackdir(Tile tile, Trackdir trackdir)
Checks for the presence of signals along the given trackdir on the given rail tile.
Definition: rail_map.h:426
static debug_inline RailTileType GetRailTileType(Tile t)
Returns the RailTileType (normal with or without signals, waypoint or depot).
Definition: rail_map.h:36
TrackBits GetTrackBits(Tile tile)
Gets the track bits of the given tile.
Definition: rail_map.h:136
static debug_inline bool IsRailDepotTile(Tile t)
Is this tile rail tile and a rail depot?
Definition: rail_map.h:105
RailGroundType
The ground 'under' the rail.
Definition: rail_map.h:485
@ RAIL_GROUND_FENCE_HORIZ1
Grass with a fence at the southern side.
Definition: rail_map.h:496
@ RAIL_GROUND_FENCE_VERT1
Grass with a fence at the eastern side.
Definition: rail_map.h:494
@ RAIL_GROUND_ICE_DESERT
Icy or sandy.
Definition: rail_map.h:498
@ RAIL_GROUND_FENCE_NE
Grass with a fence at the NE edge.
Definition: rail_map.h:491
@ RAIL_GROUND_FENCE_NESW
Grass with a fence at the NE and SW edges.
Definition: rail_map.h:493
@ RAIL_GROUND_FENCE_HORIZ2
Grass with a fence at the northern side.
Definition: rail_map.h:497
@ RAIL_GROUND_FENCE_SW
Grass with a fence at the SW edge.
Definition: rail_map.h:492
@ RAIL_GROUND_FENCE_NW
Grass with a fence at the NW edge.
Definition: rail_map.h:488
@ RAIL_GROUND_WATER
Grass with a fence and shore or water on the free halftile.
Definition: rail_map.h:499
@ RAIL_GROUND_BARREN
Nothing (dirt)
Definition: rail_map.h:486
@ RAIL_GROUND_FENCE_VERT2
Grass with a fence at the western side.
Definition: rail_map.h:495
@ RAIL_GROUND_GRASS
Grassy.
Definition: rail_map.h:487
@ RAIL_GROUND_HALF_SNOW
Snow only on higher part of slope (steep or one corner raised)
Definition: rail_map.h:500
@ RAIL_GROUND_FENCE_SENW
Grass with a fence at the NW and SE edges.
Definition: rail_map.h:490
@ RAIL_GROUND_FENCE_SE
Grass with a fence at the SE edge.
Definition: rail_map.h:489
Track GetRailDepotTrack(Tile t)
Returns the track of a depot, ignoring direction.
Definition: rail_map.h:182
void SetTrackReservation(Tile t, TrackBits b)
Sets the reserved track bits of the tile.
Definition: rail_map.h:209
bool IsSignalPresent(Tile t, uint8_t signalbit)
Checks whether the given signals is present.
Definition: rail_map.h:404
DiagDirection GetRailDepotDirection(Tile t)
Returns the direction the depot is facing to.
Definition: rail_map.h:171
void SetTrackBits(Tile t, TrackBits b)
Sets the track bits of the given tile.
Definition: rail_map.h:147
uint GetPresentSignals(Tile tile)
Get whether the given signals are present (Along/AgainstTrackDir)
Definition: rail_map.h:393
bool HasSignalOnTrack(Tile tile, Track track)
Checks for the presence of signals (either way) on the given track on the given rail tile.
Definition: rail_map.h:413
bool IsOnewaySignal(Tile t, Track track)
One-way signals can't be passed the 'wrong' way.
Definition: rail_map.h:319
void SetPresentSignals(Tile tile, uint signals)
Set whether the given signals are present (Along/AgainstTrackDir)
Definition: rail_map.h:383
static debug_inline bool IsRailDepot(Tile t)
Is this rail tile a rail depot?
Definition: rail_map.h:95
void SetRailDepotExitDirection(Tile tile, DiagDirection dir)
Sets the exit direction of a rail depot.
Definition: rail_map.h:538
static debug_inline bool IsPlainRail(Tile t)
Returns whether this is plain rails, with or without signals.
Definition: rail_map.h:49
TrackBits GetRailReservationTrackBits(Tile t)
Returns the reserved track bits of the tile.
Definition: rail_map.h:194
bool HasDepotReservation(Tile t)
Get the reservation state of the depot.
Definition: rail_map.h:258
void SetHasSignals(Tile tile, bool signals)
Add/remove the 'has signal' bit from the RailTileType.
Definition: rail_map.h:83
@ RAIL_TILE_DEPOT
Depot (one entrance)
Definition: rail_map.h:26
@ RAIL_TILE_NORMAL
Normal rail tile without signals.
Definition: rail_map.h:24
@ RAIL_TILE_SIGNALS
Normal rail tile with signals.
Definition: rail_map.h:25
bool HasSignals(Tile t)
Checks if a rail tile has signals.
Definition: rail_map.h:72
static debug_inline bool IsPlainRailTile(Tile t)
Checks whether the tile is a rail tile or rail tile with signals.
Definition: rail_map.h:60
bool HasTrack(Tile tile, Track track)
Returns whether the given track is present on the given tile.
Definition: rail_map.h:160
SignalState GetSingleSignalState(Tile t, uint8_t signalbit)
Get the state of a single signal.
Definition: rail_map.h:373
void SetSignalStates(Tile tile, uint state)
Set the states of the signals (Along/AgainstTrackDir)
Definition: rail_map.h:352
void SetRailType(Tile t, RailType r)
Sets the rail type of the given tile.
Definition: rail_map.h:125
RailTypes
Allow incrementing of Track variables.
Definition: rail_type.h:44
@ RAILTYPES_NONE
No rail types.
Definition: rail_type.h:45
RailType
Enumeration for all possible railtypes.
Definition: rail_type.h:27
@ RAILTYPE_BEGIN
Used for iterations.
Definition: rail_type.h:28
@ RAILTYPE_END
Used for iterations.
Definition: rail_type.h:33
@ INVALID_RAILTYPE
Flag for invalid railtype.
Definition: rail_type.h:34
@ RAILTYPE_ELECTRIC
Electric rails.
Definition: rail_type.h:30
@ RAILTYPE_RAIL
Standard non-electric rails.
Definition: rail_type.h:29
All the railtype-specific information is stored here.
static const RailTypeInfo _original_railtypes[]
Global Railtype definition.
Definition: railtypes.h:19
bool RoadNoLevelCrossing(RoadType roadtype)
Test if road disallows level crossings.
Definition: road.h:295
Money RoadBuildCost(RoadType roadtype)
Returns the cost of building the specified roadtype.
Definition: road.h:252
void UpdateAdjacentLevelCrossingTilesOnLevelCrossingRemoval(TileIndex tile, Axis road_axis)
Update adjacent level crossing tiles in this multi-track crossing, due to removal of a level crossing...
Definition: train_cmd.cpp:1822
void MarkDirtyAdjacentLevelCrossingTiles(TileIndex tile, Axis road_axis)
Find adjacent level crossing tiles in this multi-track crossing and mark them dirty.
Definition: train_cmd.cpp:1805
void UpdateLevelCrossing(TileIndex tile, bool sound=true, bool force_bar=false)
Update a level crossing to barred or open (crossing may include multiple adjacent tiles).
Definition: train_cmd.cpp:1773
bool IsLevelCrossingTile(Tile t)
Return whether a tile is a level crossing tile.
Definition: road_map.h:95
RoadBits GetRoadBits(Tile t, RoadTramType rtt)
Get the present road bits for a specific road type.
Definition: road_map.h:128
Axis GetCrossingRoadAxis(Tile t)
Get the road axis of a level crossing.
Definition: road_map.h:325
TrackBits GetCrossingRailBits(Tile tile)
Get the rail track bits of a level crossing.
Definition: road_map.h:368
Track GetCrossingRailTrack(Tile tile)
Get the rail track of a level crossing.
Definition: road_map.h:358
DisallowedRoadDirections GetDisallowedRoadDirections(Tile t)
Gets the disallowed directions.
Definition: road_map.h:301
void MakeRoadCrossing(Tile t, Owner road, Owner tram, Owner rail, Axis roaddir, RailType rat, RoadType road_rt, RoadType tram_rt, uint town)
Make a level crossing.
Definition: road_map.h:660
void MakeRoadNormal(Tile 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
RoadBits GetCrossingRoadBits(Tile tile)
Get the road bits of a level crossing.
Definition: road_map.h:348
Owner GetRoadOwner(Tile t, RoadTramType rtt)
Get the owner of a specific road type.
Definition: road_map.h:234
bool IsLevelCrossing(Tile t)
Return whether a tile is a level crossing.
Definition: road_map.h:85
bool HasRoadWorks(Tile t)
Check if a tile has road works.
Definition: road_map.h:513
static debug_inline bool IsNormalRoad(Tile t)
Return whether a tile is a normal road.
Definition: road_map.h:64
RoadBits
Enumeration for the road parts on a tile.
Definition: road_type.h:52
@ ROAD_NONE
No road-part is build.
Definition: road_type.h:53
@ ROAD_Y
Full road along the y-axis (north-west + south-east)
Definition: road_type.h:59
@ ROAD_X
Full road along the x-axis (south-west + north-east)
Definition: road_type.h:58
RoadType
The different roadtypes we support.
Definition: road_type.h:25
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition: road_type.h:30
@ DRD_NONE
None of the directions are disallowed.
Definition: road_type.h:74
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:57
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:56
void AddTrackToSignalBuffer(TileIndex tile, Track track, Owner owner)
Add track to signal update buffer.
Definition: signal.cpp:592
void AddSideToSignalBuffer(TileIndex tile, DiagDirection side, Owner owner)
Add side of tile to signal update buffer.
Definition: signal.cpp:624
uint8_t SignalAgainstTrackdir(Trackdir trackdir)
Maps a trackdir to the bit that stores its status in the map arrays, in the direction against the tra...
Definition: signal_func.h:32
uint8_t SignalAlongTrackdir(Trackdir trackdir)
Maps a trackdir to the bit that stores its status in the map arrays, in the direction along with the ...
Definition: signal_func.h:22
uint8_t SignalOnTrack(Track track)
Maps a Track to the bits that store the status of the two signals that can be present on the given tr...
Definition: signal_func.h:42
SignalType
Type of signal, i.e.
Definition: signal_type.h:23
@ SIGTYPE_ENTRY
presignal block entry
Definition: signal_type.h:25
@ SIGTYPE_EXIT
presignal block exit
Definition: signal_type.h:26
@ SIGTYPE_BLOCK
block signal
Definition: signal_type.h:24
SignalState
These are states in which a signal can be.
Definition: signal_type.h:42
@ SIGNAL_STATE_RED
The signal is red.
Definition: signal_type.h:43
@ SIGNAL_STATE_GREEN
The signal is green.
Definition: signal_type.h:44
SignalVariant
Variant of the signal, i.e.
Definition: signal_type.h:16
@ SIG_SEMAPHORE
Old-fashioned semaphore signal.
Definition: signal_type.h:18
@ SIG_ELECTRIC
Light signal.
Definition: signal_type.h:17
bool IsSpecialRailFoundation(Foundation f)
Tests if a foundation is a special rail foundation for single horizontal/vertical track.
Definition: slope_func.h:345
Slope SlopeWithThreeCornersRaised(Corner corner)
Returns the slope with all except one corner raised.
Definition: slope_func.h:206
Corner OppositeCorner(Corner corner)
Returns the opposite corner.
Definition: slope_func.h:184
static constexpr Corner GetHalftileSlopeCorner(Slope s)
Returns the leveled halftile of a halftile slope.
Definition: slope_func.h:148
static constexpr Slope RemoveHalftileSlope(Slope s)
Removes a halftile slope from a slope.
Definition: slope_func.h:60
bool IsSlopeWithOneCornerRaised(Slope s)
Tests if a specific slope has exactly one corner raised.
Definition: slope_func.h:88
uint SlopeToSpriteOffset(Slope s)
Returns the Sprite offset for a given Slope.
Definition: slope_func.h:415
bool IsNonContinuousFoundation(Foundation f)
Tests if a foundation is a non-continuous foundation, i.e.
Definition: slope_func.h:320
Corner GetHighestSlopeCorner(Slope s)
Returns the highest corner of a slope (one corner raised or a steep slope).
Definition: slope_func.h:126
Corner GetHalftileFoundationCorner(Foundation f)
Returns the halftile corner of a halftile-foundation.
Definition: slope_func.h:333
static constexpr bool IsValidCorner(Corner corner)
Rangecheck for Corner enumeration.
Definition: slope_func.h:24
static constexpr bool IsSteepSlope(Slope s)
Checks if a slope is steep.
Definition: slope_func.h:36
bool IsSlopeWithThreeCornersRaised(Slope s)
Tests if a specific slope has exactly three corners raised.
Definition: slope_func.h:195
Foundation FlatteningFoundation(Slope s)
Returns the foundation needed to flatten a slope.
Definition: slope_func.h:369
static constexpr bool IsHalftileSlope(Slope s)
Checks for non-continuous slope on halftile foundations.
Definition: slope_func.h:47
Foundation HalftileFoundation(Corner corner)
Returns the halftile foundation for single horizontal/vertical track.
Definition: slope_func.h:391
Foundation SpecialRailFoundation(Corner corner)
Returns the special rail foundation for single horizontal/vertical track.
Definition: slope_func.h:403
Slope ComplementSlope(Slope s)
Return the complement of a slope.
Definition: slope_func.h:76
Slope SlopeWithOneCornerRaised(Corner corner)
Returns the slope with a specific corner raised.
Definition: slope_func.h:99
Slope
Enumeration for the slope-type.
Definition: slope_type.h:48
@ SLOPE_W
the west corner of the tile is raised
Definition: slope_type.h:50
@ SLOPE_ELEVATED
bit mask containing all 'simple' slopes
Definition: slope_type.h:61
@ SLOPE_NS
north and south corner are raised
Definition: slope_type.h:60
@ SLOPE_E
the east corner of the tile is raised
Definition: slope_type.h:52
@ SLOPE_S
the south corner of the tile is raised
Definition: slope_type.h:51
@ SLOPE_N
the north corner of the tile is raised
Definition: slope_type.h:53
@ SLOPE_SW
south and west corner are raised
Definition: slope_type.h:56
@ SLOPE_FLAT
a flat tile
Definition: slope_type.h:49
@ SLOPE_NE
north and east corner are raised
Definition: slope_type.h:58
@ SLOPE_SE
south and east corner are raised
Definition: slope_type.h:57
@ SLOPE_NW
north and west corner are raised
Definition: slope_type.h:55
@ SLOPE_EW
east and west corner are raised
Definition: slope_type.h:59
Foundation
Enumeration for Foundations.
Definition: slope_type.h:93
@ FOUNDATION_LEVELED
The tile is leveled up to a flat slope.
Definition: slope_type.h:95
@ FOUNDATION_NONE
The tile has no foundation, the slope remains unchanged.
Definition: slope_type.h:94
@ FOUNDATION_INCLINED_X
The tile has an along X-axis inclined foundation.
Definition: slope_type.h:96
@ FOUNDATION_STEEP_BOTH
The tile has a steep slope. The lowest corner is raised by a foundation and the upper halftile is lev...
Definition: slope_type.h:101
@ FOUNDATION_INCLINED_Y
The tile has an along Y-axis inclined foundation.
Definition: slope_type.h:97
@ FOUNDATION_STEEP_LOWER
The tile has a steep slope. The lowest corner is raised by a foundation to allow building railroad on...
Definition: slope_type.h:98
@ FOUNDATION_HALFTILE_N
Level north halftile non-continuously.
Definition: slope_type.h:105
@ FOUNDATION_INVALID
Used inside "rail_cmd.cpp" to indicate invalid slope/track combination.
Definition: slope_type.h:113
static const uint32_t VALID_LEVEL_CROSSING_SLOPES
Constant bitset with safe slopes for building a level crossing.
Definition: slope_type.h:86
Corner
Enumeration of tile corners.
Definition: slope_type.h:22
Functions related to sound.
void DrawRailTileSeqInGUI(int x, int y, const DrawTileSprites *dts, int32_t total_offset, uint32_t newgrf_offset, PaletteID default_palette)
Draw tile sprite sequence in GUI with railroad specifics.
Definition: sprite.h:99
void DrawRailTileSeq(const struct TileInfo *ti, const DrawTileSprites *dts, TransparencyOption to, int32_t total_offset, uint32_t newgrf_offset, PaletteID default_palette)
Draw tile sprite sequence on tile with railroad specifics.
Definition: sprite.h:89
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 const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition: sprites.h:1605
static const PaletteID PALETTE_TO_BARE_LAND
sets colour to bare land stuff for rail, road and crossings
Definition: sprites.h:1593
bool IsRailStationTile(Tile t)
Is this tile a station tile and a rail station?
Definition: station_map.h:102
Track GetRailStationTrack(Tile t)
Get the rail track of a rail station tile.
Definition: station_map.h:515
bool IsStationTileBlocked(Tile t)
Is tile t a blocked tile?
Definition: station_map.h:431
bool HasStationRail(Tile 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
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition: stdafx.h:280
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:17
Class to backup a specific variable and restore it later.
Definition: backup_type.hpp:21
void Restore()
Restore the variable.
VehicleType type
Type of vehicle.
Definition: vehicle_type.h:51
GUISettings gui
settings related to the GUI
std::array< uint32_t, RAILTYPE_END > rail
Count of company owned track bits for each rail type.
Definition: company_base.h:33
CompanyInfrastructure infrastructure
NOSAVE: Counts of company owned infrastructure.
Definition: company_base.h:147
bool build_on_slopes
allow building on slopes
bool crossing_with_competitor
allow building of level crossings with competitor roads or rails
uint8_t train_signal_side
show signals on left / driving / right side
TimerGameCalendar::Date build_date
Date of construction.
Definition: depot_base.h:26
Represents a diagonal tile area.
Definition: tilearea_type.h:70
Ground palette sprite of a tile, together with its sprite layout.
Definition: sprite.h:58
PalSpriteID ground
Palette and sprite for the ground.
Definition: sprite.h:59
Offsets for drawing fences.
Definition: rail_cmd.cpp:1916
int y_offs
Bounding box Y offset.
Definition: rail_cmd.cpp:1919
Corner height_ref
Corner to use height offset from.
Definition: rail_cmd.cpp:1917
int x_offs
Bounding box X offset.
Definition: rail_cmd.cpp:1918
int y_size
Bounding box Y size.
Definition: rail_cmd.cpp:1921
int x_size
Bounding box X size.
Definition: rail_cmd.cpp:1920
bool show_track_reservation
highlight reserved tracks.
uint8_t landscape
the landscape we're currently in
PathfinderSettings pf
settings for all pathfinders
ConstructionSettings construction
construction of things in-game
GameCreationSettings game_creation
settings used during the creation of a game (map)
VehicleSettings vehicle
options for vehicles
static debug_inline uint Size()
Get the size of the map.
Definition: map_func.h:288
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition: order_base.h:70
Represents the covered area of e.g.
Definition: tilearea_type.h:18
SpriteID sprite
The 'real' sprite.
Definition: gfx_type.h:24
bool forbid_90_deg
forbid trains to make 90 deg turns
Coordinates of a point in 2D.
Tindex index
Index of this pool item.
Definition: pool_type.hpp:238
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:339
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:328
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
Definition: pool_type.hpp:309
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
T * Next() const
Get next vehicle in the chain.
T * First() const
Get the first vehicle in the chain.
Used to only draw a part of the sprite.
Definition: gfx_type.h:231
Tile description for the 'land area information' tool.
Definition: tile_cmd.h:52
uint16_t rail_speed
Speed limit of rail (bridges and track)
Definition: tile_cmd.h:65
StringID str
Description of the tile.
Definition: tile_cmd.h:53
TimerGameCalendar::Date build_date
Date of construction of tile contents.
Definition: tile_cmd.h:57
StringID railtype
Type of rail on the tile.
Definition: tile_cmd.h:64
Owner owner[4]
Name of the owner(s)
Definition: tile_cmd.h:55
A pair-construct of a TileIndexDiff.
Definition: map_type.h:31
int16_t x
The x value of the coordinate.
Definition: map_type.h:32
int16_t y
The y value of the coordinate.
Definition: map_type.h:33
Tile information, used while rendering the tile.
Definition: tile_cmd.h:43
int z
Height.
Definition: tile_cmd.h:48
int x
X position of the tile in unit coordinates.
Definition: tile_cmd.h:44
Slope tileh
Slope of the tile.
Definition: tile_cmd.h:46
TileIndex tile
Tile index.
Definition: tile_cmd.h:47
int y
Y position of the tile in unit coordinates.
Definition: tile_cmd.h:45
Set of callback functions for performing tile operations of a given tile type.
Definition: tile_cmd.h:158
'Train' is either a loco or a wagon.
Definition: train.h:89
Trackdir GetVehicleTrackdir() const override
Get the tracks of the train vehicle.
Definition: train_cmd.cpp:4220
int CalcNextVehicleOffset() const
Calculate the offset from this vehicle's center to the following center taking the vehicle lengths in...
Definition: train.h:172
uint8_t train_acceleration_model
realistic acceleration for trains
uint8_t road_side
the side of the road vehicles drive on
bool disable_elrails
when true, the elrails are disabled
Vehicle data structure.
Definition: vehicle_base.h:244
Direction direction
facing
Definition: vehicle_base.h:307
Order current_order
The current order (+ status, like: loading)
Definition: vehicle_base.h:356
int32_t y_pos
y coordinate.
Definition: vehicle_base.h:305
int32_t x_pos
x coordinate.
Definition: vehicle_base.h:304
uint8_t vehstatus
Status.
Definition: vehicle_base.h:354
uint16_t cur_speed
current speed
Definition: vehicle_base.h:328
TileIndex tile
Current tile index.
Definition: vehicle_base.h:264
VehicleEnterTileStatus
The returned bits of VehicleEnterTile.
Definition: tile_cmd.h:21
@ VETSB_ENTERED_WORMHOLE
The vehicle either entered a bridge, tunnel or depot tile (this includes the last tile of the bridge/...
Definition: tile_cmd.h:37
@ VETSB_CANNOT_ENTER
The vehicle cannot enter the tile.
Definition: tile_cmd.h:38
@ VETSB_CONTINUE
Bit sets of the above specified bits.
Definition: tile_cmd.h:35
std::tuple< Slope, int > GetTileSlopeZ(TileIndex tile)
Return the slope of a given tile inside the map.
Definition: tile_map.cpp:55
bool IsTileOwner(Tile tile, Owner owner)
Checks if a tile belongs to the given owner.
Definition: tile_map.h:214
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition: tile_map.h:178
void SetTileOwner(Tile tile, Owner owner)
Sets the owner of a tile.
Definition: tile_map.h:198
int GetTileMaxPixelZ(TileIndex tile)
Get top height of the tile.
Definition: tile_map.h:312
static debug_inline TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition: tile_map.h:96
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition: tile_map.h:161
TropicZone GetTropicZone(Tile tile)
Get the tropic zone.
Definition: tile_map.h:238
std::tuple< Slope, int > GetTilePixelSlope(TileIndex tile)
Return the slope of a given tile.
Definition: tile_map.h:289
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition: tile_map.h:150
Slope GetTileSlope(TileIndex tile)
Return the slope of a given tile inside the map.
Definition: tile_map.h:279
@ TROPICZONE_DESERT
Tile is desert.
Definition: tile_type.h:78
static const uint TILE_HEIGHT
Height of a height level in world coordinate AND in pixels in #ZOOM_BASE.
Definition: tile_type.h:18
static const uint TILE_SIZE
Tile size in world coordinates.
Definition: tile_type.h:15
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:95
TileType
The different types of tiles.
Definition: tile_type.h:47
@ MP_ROAD
A tile with road (or tram tracks)
Definition: tile_type.h:50
@ MP_STATION
A tile of a station.
Definition: tile_type.h:53
@ MP_TUNNELBRIDGE
Tunnel entry/exit and bridge heads.
Definition: tile_type.h:57
@ MP_HOUSE
A house by a town.
Definition: tile_type.h:51
@ MP_WATER
Water tile.
Definition: tile_type.h:54
@ MP_RAILWAY
A railway.
Definition: tile_type.h:49
@ MP_INDUSTRY
Part of an industry.
Definition: tile_type.h:56
@ MP_OBJECT
Contains objects such as transmitters and owned land.
Definition: tile_type.h:58
Definition of the game-calendar-timer.
Base of the town class.
void MakeDefaultName(T *obj)
Set the default name for a depot/waypoint.
Definition: town.h:253
TownID GetTownIndex(Tile t)
Get the index of which town this house/street is attached to.
Definition: town_map.h:23
Trackdir TrackToTrackdir(Track track)
Returns a Trackdir for the given Track.
Definition: track_func.h:279
Trackdir RemoveFirstTrackdir(TrackdirBits *trackdirs)
Removes first Trackdir from TrackdirBits and returns it.
Definition: track_func.h:156
Track TrackdirToTrack(Trackdir trackdir)
Returns the Track that a given Trackdir represents.
Definition: track_func.h:262
TrackBits CornerToTrackBits(Corner corner)
Returns a single horizontal/vertical trackbit that is in a specific tile corner.
Definition: track_func.h:99
TrackBits TrackToTrackBits(Track track)
Maps a Track to the corresponding TrackBits value.
Definition: track_func.h:77
TrackdirBits TrackBitsToTrackdirBits(TrackBits bits)
Converts TrackBits to TrackdirBits while allowing both directions.
Definition: track_func.h:319
TrackdirBits TrackStatusToTrackdirBits(TrackStatus ts)
Returns the present-trackdir-information of a TrackStatus.
Definition: track_func.h:352
Track TrackBitsToTrack(TrackBits tracks)
Converts TrackBits to Track.
Definition: track_func.h:193
Trackdir ReverseTrackdir(Trackdir trackdir)
Maps a trackdir to the reverse trackdir.
Definition: track_func.h:247
TrackStatus CombineTrackStatus(TrackdirBits trackdirbits, TrackdirBits red_signals)
Builds a TrackStatus.
Definition: track_func.h:388
bool TracksOverlap(TrackBits bits)
Checks if the given tracks overlap, ie form a crossing.
Definition: track_func.h:645
TrackdirBits TrackdirReachesTrackdirs(Trackdir trackdir)
Maps a trackdir to the trackdirs that can be reached from it (ie, when entering the next tile.
Definition: track_func.h:584
bool IsValidTrack(Track track)
Checks if a Track is valid.
Definition: track_func.h:28
Track FindFirstTrack(TrackBits tracks)
Returns first Track from TrackBits or INVALID_TRACK.
Definition: track_func.h:177
bool IsDiagonalTrackdir(Trackdir trackdir)
Checks if a given Trackdir is diagonal.
Definition: track_func.h:631
TrackBits DiagDirToDiagTrackBits(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal track bits incidating with that diagdir.
Definition: track_func.h:524
Track RemoveFirstTrack(TrackBits *tracks)
Removes first Track from TrackBits and returns it.
Definition: track_func.h:131
DiagDirection TrackdirToExitdir(Trackdir trackdir)
Maps a trackdir to the (4-way) direction the tile is exited when following that trackdir.
Definition: track_func.h:439
Track DiagDirToDiagTrack(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal track incidating with that diagdir.
Definition: track_func.h:512
TrackBits TrackdirBitsToTrackBits(TrackdirBits bits)
Discards all directional information from a TrackdirBits value.
Definition: track_func.h:308
Sprites to use and how to display them for train depot tiles.
TrackBits
Allow incrementing of Track variables.
Definition: track_type.h:35
@ TRACK_BIT_UPPER
Upper track.
Definition: track_type.h:39
@ TRACK_BIT_DEPOT
Bitflag for a depot.
Definition: track_type.h:53
@ TRACK_BIT_LEFT
Left track.
Definition: track_type.h:41
@ TRACK_BIT_Y
Y-axis track.
Definition: track_type.h:38
@ TRACK_BIT_CROSS
X-Y-axis cross.
Definition: track_type.h:43
@ TRACK_BIT_HORZ
Upper and lower track.
Definition: track_type.h:44
@ TRACK_BIT_NONE
No track.
Definition: track_type.h:36
@ TRACK_BIT_3WAY_NW
"Arrow" to the north-west
Definition: track_type.h:49
@ TRACK_BIT_X
X-axis track.
Definition: track_type.h:37
@ TRACK_BIT_LOWER
Lower track.
Definition: track_type.h:40
@ TRACK_BIT_ALL
All possible tracks.
Definition: track_type.h:50
@ TRACK_BIT_3WAY_NE
"Arrow" to the north-east
Definition: track_type.h:46
@ TRACK_BIT_RIGHT
Right track.
Definition: track_type.h:42
@ TRACK_BIT_3WAY_SW
"Arrow" to the south-west
Definition: track_type.h:48
@ TRACK_BIT_VERT
Left and right track.
Definition: track_type.h:45
@ TRACK_BIT_3WAY_SE
"Arrow" to the south-east
Definition: track_type.h:47
Trackdir
Enumeration for tracks and directions.
Definition: track_type.h:67
@ INVALID_TRACKDIR
Flag for an invalid trackdir.
Definition: track_type.h:86
TrackdirBits
Allow incrementing of Trackdir variables.
Definition: track_type.h:98
@ TRACKDIR_BIT_LEFT_S
Track left, direction south.
Definition: track_type.h:104
@ TRACKDIR_BIT_Y_NW
Track y-axis, direction north-west.
Definition: track_type.h:108
@ TRACKDIR_BIT_UPPER_E
Track upper, direction east.
Definition: track_type.h:102
@ TRACKDIR_BIT_X_NE
Track x-axis, direction north-east.
Definition: track_type.h:100
@ TRACKDIR_BIT_LOWER_E
Track lower, direction east.
Definition: track_type.h:103
@ TRACKDIR_BIT_LEFT_N
Track left, direction north.
Definition: track_type.h:111
@ TRACKDIR_BIT_RIGHT_S
Track right, direction south.
Definition: track_type.h:105
@ TRACKDIR_BIT_Y_SE
Track y-axis, direction south-east.
Definition: track_type.h:101
@ TRACKDIR_BIT_NONE
No track build.
Definition: track_type.h:99
@ TRACKDIR_BIT_RIGHT_N
Track right, direction north.
Definition: track_type.h:112
@ TRACKDIR_BIT_UPPER_W
Track upper, direction west.
Definition: track_type.h:109
@ TRACKDIR_BIT_LOWER_W
Track lower, direction west.
Definition: track_type.h:110
@ TRACKDIR_BIT_X_SW
Track x-axis, direction south-west.
Definition: track_type.h:107
Track
These are used to specify a single track.
Definition: track_type.h:19
@ INVALID_TRACK
Flag for an invalid track.
Definition: track_type.h:28
@ TRACK_Y
Track along the y-axis (north-west to south-east)
Definition: track_type.h:22
@ TRACK_LOWER
Track in the lower corner of the tile (south)
Definition: track_type.h:24
@ TRACK_END
Used for iterations.
Definition: track_type.h:27
@ TRACK_LEFT
Track in the left corner of the tile (west)
Definition: track_type.h:25
@ TRACK_RIGHT
Track in the right corner of the tile (east)
Definition: track_type.h:26
@ TRACK_BEGIN
Used for iterations.
Definition: track_type.h:20
@ TRACK_X
Track along the x-axis (north-east to south-west)
Definition: track_type.h:21
@ TRACK_UPPER
Track in the upper corner of the tile (north)
Definition: track_type.h:23
Base for the train class.
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:2866
void FreeTrainTrackReservation(const Train *v)
Free the reserved path in front of a vehicle.
Definition: train_cmd.cpp:2386
@ CCF_TRACK
Valid changes while vehicle is driving, and possibly changing tracks.
Definition: train.h:48
@ TO_BUILDINGS
company buildings - depots, stations, HQ, ...
Definition: transparency.h:27
uint8_t _display_opt
What do we want to draw/do?
bool IsInvisibilitySet(TransparencyOption to)
Check if the invisibility option bit is set and if we aren't in the game menu (there's never transpar...
Definition: transparency.h:59
TransportType
Available types of transport.
@ TRANSPORT_RAIL
Transport by train.
@ TRANSPORT_WATER
Transport over water.
Header file for things common for tunnels and bridges.
void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height)
Mark bridge tiles dirty.
uint GetTunnelBridgeLength(TileIndex begin, TileIndex end)
Calculates the length of a tunnel or a bridge (without end tiles)
Definition: tunnelbridge.h:25
Functions that have tunnels and bridges in common.
DiagDirection GetTunnelBridgeDirection(Tile t)
Get the direction pointing to the other end.
bool HasTunnelBridgeReservation(Tile t)
Get the reservation state of the rail tunnel/bridge.
TransportType GetTunnelBridgeTransportType(Tile t)
Tunnel: Get the transport type of the tunnel (road or rail) Bridge: Get the transport type of the bri...
TileIndex GetOtherTunnelBridgeEnd(Tile t)
Determines type of the wormhole and returns its other end.
CommandCost EnsureNoVehicleOnGround(TileIndex tile)
Ensure there is no vehicle at the ground at the given position.
Definition: vehicle.cpp:546
void VehicleEnterDepot(Vehicle *v)
Vehicle entirely entered the depot, update its status, orders, vehicle windows, service it,...
Definition: vehicle.cpp:1552
CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits)
Tests if a vehicle interacts with the specified track bits.
Definition: vehicle.cpp:608
bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
Checks whether a vehicle is on a specific location.
Definition: vehicle.cpp:520
void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
Find a vehicle from a specific location.
Definition: vehicle.cpp:505
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
Finds vehicle in tunnel / bridge.
Definition: vehicle.cpp:575
@ VS_STOPPED
Vehicle is stopped by the player.
Definition: vehicle_base.h:34
@ VS_HIDDEN
Vehicle is not visible.
Definition: vehicle_base.h:33
Functions related to vehicles.
@ VEH_SHIP
Ship vehicle type.
Definition: vehicle_type.h:26
@ VEH_TRAIN
Train vehicle type.
Definition: vehicle_type.h:24
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:671
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:587
Functions related to (drawing on) viewports.
static const uint BB_HEIGHT_UNDER_BRIDGE
Some values for constructing bounding boxes (BB).
Definition: viewport_type.h:88
Functions related to water (management)
void TileLoop_Water(TileIndex tile)
Let a water tile floods its diagonal adjoining tiles called from tunnelbridge_cmd,...
Definition: water_cmd.cpp:1245
FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
Returns the behaviour of a tile during flooding.
Definition: water_cmd.cpp:1092
void CheckForDockingTile(TileIndex t)
Mark the supplied tile as a docking tile if it is suitable for docking.
Definition: water_cmd.cpp:195
@ FLOOD_NONE
The tile does not flood neighboured tiles.
Definition: water.h:20
void MakeShore(Tile t)
Helper function to make a coast tile.
Definition: water_map.h:381
bool IsDockingTile(Tile t)
Checks whether the tile is marked as a dockling tile.
Definition: water_map.h:371
void SetDockingTile(Tile t, bool b)
Set the docking tile state of a tile.
Definition: water_map.h:361
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:3211
@ WC_VEHICLE_DEPOT
Depot view; Window numbers:
Definition: window_type.h:351
@ WC_BUILD_VEHICLE
Build vehicle; Window numbers:
Definition: window_type.h:389
Entry point for OpenTTD to YAPF's cache.
void YapfNotifyTrackLayoutChange(TileIndex tile, Track track)
Use this function to notify YAPF that track layout (or signal configuration) has change.
Definition: yapf_rail.cpp:635