OpenTTD Source 20250205-master-gfd85ab1e2c
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"
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
44typedef std::vector<Train *> TrainList;
45
46RailTypeInfo _railtypes[RAILTYPE_END];
47std::vector<RailType> _sorted_railtypes;
48RailTypes _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
75void 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
122static 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 (rti->flags.Test(RailTypeFlag::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
150RailType 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
182static 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 CommandCost(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 CommandCost(STR_ERROR_ALREADY_BUILT);
254 }
255
256 /* Normally, we may overlap and any combination is valid */
257 return CommandCost();
258}
259
260
282
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
392static 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 CommandCost(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 CommandCost(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 */
412static inline bool ValParamTrackOrientation(Track track)
413{
414 return IsValidTrack(track);
415}
416
426CommandCost 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: {
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 CommandCost(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 CommandCost(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 CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
498
501 if (ret.Failed()) return ret;
502 }
503
505 if (ret.Failed()) return ret;
506
507 if (IsNormalRoad(tile)) {
508 if (HasRoadWorks(tile)) return CommandCost(STR_ERROR_ROAD_WORKS_IN_PROGRESS);
509
510 if (GetDisallowedRoadDirections(tile) != DRD_NONE) return CommandCost(STR_ERROR_CROSSING_ON_ONEWAY_ROAD);
511
512 if (RailNoLevelCrossings(railtype)) return CommandCost(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 CommandCost(STR_ERROR_CROSSING_DISALLOWED_ROAD);
518 if (roadtype_tram != INVALID_ROADTYPE && RoadNoLevelCrossing(roadtype_tram)) return CommandCost(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 CommandCost(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) {
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 CommandCost(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
634
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 CommandCost(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
668
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 CommandCost(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);
721 }
722 }
723 break;
724 }
725
726 default: return CommandCost(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
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 != TRACK_BIT_NONE) {
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 == TRACK_BIT_NONE) {
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
807static 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
817static 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
876static 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
932CommandCost 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 CommandCost(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)) {
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 CommandCost(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
1052CommandCost 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 CommandCost(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 CommandCost(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 CommandCost(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)) {
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)) {
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
1199static 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
1258static 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{
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 CommandCost(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
1449CommandCost 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 CommandCost(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
1465 }
1466 if (!HasSignalOnTrack(tile, track)) {
1467 return CommandCost(STR_ERROR_THERE_ARE_NO_SIGNALS);
1468 }
1469
1470 /* Only water can remove signals from anyone */
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;
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
1527CommandCost 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
1533static 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
1553CommandCost 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
1766static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
1767{
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
1800static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
1801{
1803
1804 if (flags & DC_AUTO) {
1805 if (!IsTileOwner(tile, _current_company)) {
1806 return CommandCost(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
1807 }
1808
1809 if (IsPlainRail(tile)) {
1810 return CommandCost(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
1811 } else {
1812 return CommandCost(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
1859static 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
1871static 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
1911static uint32_t _drawtile_track_palette;
1912
1913
1914
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
1951static 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,
1962 4, z);
1963}
1964
1968static 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
1978static 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
1988static 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
1998static 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
2010static 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. */
2059static const int INF = 1000; // big number compared to tilesprite size
2060static 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
2067static 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
2072static 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
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 && rti->flags.Test(RailTypeFlag::NoSpriteCombine);
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
2237static 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
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
2388static 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
2422static 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:
2501 break;
2502 case DIAGDIR_NW:
2503 if (!IsInvisibilitySet(TO_BUILDINGS)) break;
2504 [[fallthrough]];
2505 case DIAGDIR_SE:
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
2543void 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
2570static 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
2577 return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
2578 } else {
2579 return GetTileMaxPixelZ(tile);
2580 }
2581}
2582
2583static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
2584{
2585 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
2586}
2587
2588static 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 LandscapeType::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
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 LandscapeType::Tropic:
2656 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
2657 new_ground = RAIL_GROUND_ICE_DESERT;
2658 goto set_ground;
2659 }
2660 break;
2661
2662 default:
2663 break;
2664 }
2665
2666 new_ground = RAIL_GROUND_GRASS;
2667
2668 if (IsPlainRail(tile) && old_ground != RAIL_GROUND_BARREN) { // wait until bottom is green
2669 /* determine direction of fence */
2670 TrackBits rail = GetTrackBits(tile);
2671
2672 Owner owner = GetTileOwner(tile);
2673 uint8_t fences = 0;
2674
2675 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
2677
2678 /* Track bit on this edge => no fence. */
2679 if ((rail & dir_to_trackbits[d]) != TRACK_BIT_NONE) continue;
2680
2681 TileIndex tile2 = tile + TileOffsByDiagDir(d);
2682
2683 /* Show fences if it's a house, industry, object, road, tunnelbridge or not owned by us. */
2684 if (!IsValidTile(tile2) || IsTileType(tile2, MP_HOUSE) || IsTileType(tile2, MP_INDUSTRY) ||
2685 IsTileType(tile2, MP_ROAD) || (IsTileType(tile2, MP_OBJECT) && !IsObjectType(tile2, OBJECT_OWNED_LAND)) || IsTileType(tile2, MP_TUNNELBRIDGE) || !IsTileOwner(tile2, owner)) {
2686 fences |= 1 << d;
2687 }
2688 }
2689
2690 switch (fences) {
2691 case 0: break;
2692 case (1 << DIAGDIR_NE): new_ground = RAIL_GROUND_FENCE_NE; break;
2693 case (1 << DIAGDIR_SE): new_ground = RAIL_GROUND_FENCE_SE; break;
2694 case (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_SW; break;
2695 case (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_NW; break;
2696 case (1 << DIAGDIR_NE) | (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_NESW; break;
2697 case (1 << DIAGDIR_SE) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_SENW; break;
2698 case (1 << DIAGDIR_NE) | (1 << DIAGDIR_SE): new_ground = RAIL_GROUND_FENCE_VERT1; break;
2699 case (1 << DIAGDIR_NE) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
2700 case (1 << DIAGDIR_SE) | (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
2701 case (1 << DIAGDIR_SW) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_VERT2; break;
2702 default: NOT_REACHED();
2703 }
2704 }
2705
2706set_ground:
2707 if (old_ground != new_ground) {
2708 SetRailGroundType(tile, new_ground);
2709 MarkTileDirtyByTile(tile);
2710 }
2711}
2712
2713
2714static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint, DiagDirection side)
2715{
2716 /* Case of half tile slope with water. */
2717 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(GetTileSlope(tile))) {
2718 TrackBits tb = GetTrackBits(tile);
2719 switch (tb) {
2720 default: NOT_REACHED();
2721 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
2722 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
2723 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
2724 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
2725 }
2727 }
2728
2729 if (mode != TRANSPORT_RAIL) return 0;
2730
2731 TrackBits trackbits = TRACK_BIT_NONE;
2732 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
2733
2734 switch (GetRailTileType(tile)) {
2735 default: NOT_REACHED();
2736 case RAIL_TILE_NORMAL:
2737 trackbits = GetTrackBits(tile);
2738 break;
2739
2740 case RAIL_TILE_SIGNALS: {
2741 trackbits = GetTrackBits(tile);
2742 uint8_t a = GetPresentSignals(tile);
2743 uint b = GetSignalStates(tile);
2744
2745 b &= a;
2746
2747 /* When signals are not present (in neither direction),
2748 * we pretend them to be green. Otherwise, it depends on
2749 * the signal type. For signals that are only active from
2750 * one side, we set the missing signals explicitly to
2751 * `green'. Otherwise, they implicitly become `red'. */
2752 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
2753 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
2754
2755 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
2756 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
2757 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
2758 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
2759
2760 break;
2761 }
2762
2763 case RAIL_TILE_DEPOT: {
2765
2766 if (side != INVALID_DIAGDIR && side != dir) break;
2767
2768 trackbits = DiagDirToDiagTrackBits(dir);
2769 break;
2770 }
2771 }
2772
2773 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
2774}
2775
2776static bool ClickTile_Track(TileIndex tile)
2777{
2778 if (!IsRailDepot(tile)) return false;
2779
2781 return true;
2782}
2783
2784static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
2785{
2786 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
2787 td->rail_speed = rti->max_speed;
2788 td->railtype = rti->strings.name;
2789 td->owner[0] = GetTileOwner(tile);
2790 switch (GetRailTileType(tile)) {
2791 case RAIL_TILE_NORMAL:
2792 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
2793 break;
2794
2795 case RAIL_TILE_SIGNALS: {
2796 static const StringID signal_type[6][6] = {
2797 {
2798 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
2799 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
2800 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
2801 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
2802 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
2803 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
2804 },
2805 {
2806 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
2807 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
2808 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
2809 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
2810 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
2811 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
2812 },
2813 {
2814 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
2815 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
2816 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
2817 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
2818 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
2819 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
2820 },
2821 {
2822 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
2823 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
2824 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
2825 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
2826 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
2827 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
2828 },
2829 {
2830 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
2831 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
2832 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
2833 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
2834 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
2835 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
2836 },
2837 {
2838 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
2839 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
2840 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
2841 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
2842 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
2843 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
2844 }
2845 };
2846
2847 SignalType primary_signal;
2848 SignalType secondary_signal;
2849 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
2850 primary_signal = GetSignalType(tile, TRACK_UPPER);
2851 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
2852 } else {
2853 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
2854 }
2855
2856 td->str = signal_type[secondary_signal][primary_signal];
2857 break;
2858 }
2859
2860 case RAIL_TILE_DEPOT:
2861 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
2862 if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
2863 if (td->rail_speed > 0) {
2864 td->rail_speed = std::min<uint16_t>(td->rail_speed, 61);
2865 } else {
2866 td->rail_speed = 61;
2867 }
2868 }
2869 td->build_date = Depot::GetByTile(tile)->build_date;
2870 break;
2871
2872 default:
2873 NOT_REACHED();
2874 }
2875}
2876
2877static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
2878{
2879 if (!IsTileOwner(tile, old_owner)) return;
2880
2881 if (new_owner != INVALID_OWNER) {
2882 /* Update company infrastructure counts. No need to dirty windows here, we'll redraw the whole screen anyway. */
2883 uint num_pieces = 1;
2884 if (IsPlainRail(tile)) {
2885 TrackBits bits = GetTrackBits(tile);
2886 num_pieces = CountBits(bits);
2887 if (TracksOverlap(bits)) num_pieces *= num_pieces;
2888 }
2889 RailType rt = GetRailType(tile);
2890 Company::Get(old_owner)->infrastructure.rail[rt] -= num_pieces;
2891 Company::Get(new_owner)->infrastructure.rail[rt] += num_pieces;
2892
2893 if (HasSignals(tile)) {
2894 uint num_sigs = CountBits(GetPresentSignals(tile));
2895 Company::Get(old_owner)->infrastructure.signal -= num_sigs;
2896 Company::Get(new_owner)->infrastructure.signal += num_sigs;
2897 }
2898
2899 SetTileOwner(tile, new_owner);
2900 } else {
2902 }
2903}
2904
2905static const uint8_t _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
2906static const uint8_t _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
2907static const int8_t _deltacoord_leaveoffset[8] = {
2908 -1, 0, 1, 0, /* x */
2909 0, 1, 0, -1 /* y */
2910};
2911
2912
2920{
2922 int length = v->CalcNextVehicleOffset();
2923
2924 switch (dir) {
2925 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
2926 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
2927 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
2928 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
2929 default: NOT_REACHED();
2930 }
2931}
2932
2938{
2939 /* This routine applies only to trains in depot tiles. */
2940 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
2941
2942 /* Depot direction. */
2944
2945 uint8_t fract_coord = (x & 0xF) + ((y & 0xF) << 4);
2946
2947 /* Make sure a train is not entering the tile from behind. */
2948 if (_fractcoords_behind[dir] == fract_coord) return VETSB_CANNOT_ENTER;
2949
2950 Train *v = Train::From(u);
2951
2952 /* Leaving depot? */
2953 if (v->direction == DiagDirToDir(dir)) {
2954 /* Calculate the point where the following wagon should be activated. */
2955 int length = v->CalcNextVehicleOffset();
2956
2957 uint8_t fract_coord_leave =
2958 ((_fractcoords_enter[dir] & 0x0F) + // x
2959 (length + 1) * _deltacoord_leaveoffset[dir]) +
2960 (((_fractcoords_enter[dir] >> 4) + // y
2961 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
2962
2963 if (fract_coord_leave == fract_coord) {
2964 /* Leave the depot. */
2965 if ((v = v->Next()) != nullptr) {
2966 v->vehstatus &= ~VS_HIDDEN;
2967 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
2968 }
2969 }
2970 } else if (_fractcoords_enter[dir] == fract_coord) {
2971 /* Entering depot. */
2972 assert(DiagDirToDir(ReverseDiagDir(dir)) == v->direction);
2973 v->track = TRACK_BIT_DEPOT,
2974 v->vehstatus |= VS_HIDDEN;
2976 if (v->Next() == nullptr) VehicleEnterDepot(v->First());
2977 v->tile = tile;
2978
2981 }
2982
2983 return VETSB_CONTINUE;
2984}
2985
2997static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, int z_old, Slope tileh_old, int z_new, Slope tileh_new, TrackBits rail_bits)
2998{
2999 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return CommandCost(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
3000
3001 /* Is the slope-rail_bits combination valid in general? I.e. is it safe to call GetRailFoundation() ? */
3002 if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return CommandCost(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
3003
3004 /* Get the slopes on top of the foundations */
3005 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), tileh_old);
3006 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), tileh_new);
3007
3008 Corner track_corner;
3009 switch (rail_bits) {
3010 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
3011 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
3012 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
3013 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
3014
3015 /* Surface slope must not be changed */
3016 default:
3017 if (z_old != z_new || tileh_old != tileh_new) return CommandCost(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
3018 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
3019 }
3020
3021 /* The height of the track_corner must not be changed. The rest ensures GetRailFoundation() already. */
3022 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
3023 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
3024 if (z_old != z_new) return CommandCost(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
3025
3026 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
3027 /* Make the ground dirty, if surface slope has changed */
3028 if (tileh_old != tileh_new) {
3029 /* If there is flat water on the lower halftile add the cost for clearing it */
3030 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
3031 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
3032 }
3033 return cost;
3034}
3035
3040{
3041 return v->type == VEH_SHIP ? v : nullptr;
3042}
3043
3044static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
3045{
3046 auto [tileh_old, z_old] = GetTileSlopeZ(tile);
3047 if (IsPlainRail(tile)) {
3048 TrackBits rail_bits = GetTrackBits(tile);
3049 /* Is there flat water on the lower halftile that must be cleared expensively? */
3050 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
3051
3052 /* Allow clearing the water only if there is no ship */
3053 if (was_water && HasVehicleOnPos(tile, nullptr, &EnsureNoShipProc)) return CommandCost(STR_ERROR_SHIP_IN_THE_WAY);
3054
3055 /* First test autoslope. However if it succeeds we still have to test the rest, because non-autoslope terraforming is cheaper. */
3056 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
3057
3058 /* When there is only a single horizontal/vertical track, one corner can be terraformed. */
3059 Corner allowed_corner;
3060 switch (rail_bits) {
3061 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
3062 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
3063 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
3064 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
3065 default: return autoslope_result;
3066 }
3067
3068 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
3069
3070 /* Do not allow terraforming if allowed_corner is part of anti-zig-zag foundations */
3071 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
3072
3073 /* Everything is valid, which only changes allowed_corner */
3074 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
3075 if (allowed_corner == corner) continue;
3076 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
3077 }
3078
3079 /* Make the ground dirty */
3080 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
3081
3082 /* allow terraforming */
3083 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
3085 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
3086 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
3087 }
3088 return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
3089}
3090
3091
3092extern const TileTypeProcs _tile_type_rail_procs = {
3093 DrawTile_Track, // draw_tile_proc
3094 GetSlopePixelZ_Track, // get_slope_z_proc
3095 ClearTile_Track, // clear_tile_proc
3096 nullptr, // add_accepted_cargo_proc
3097 GetTileDesc_Track, // get_tile_desc_proc
3098 GetTileTrackStatus_Track, // get_tile_track_status_proc
3099 ClickTile_Track, // click_tile_proc
3100 nullptr, // animate_tile_proc
3101 TileLoop_Track, // tile_loop_proc
3102 ChangeTileOwner_Track, // change_tile_owner_proc
3103 nullptr, // add_produced_cargo_proc
3104 VehicleEnter_Track, // vehicle_enter_tile_proc
3105 GetFoundation_Track, // get_foundation_proc
3106 TerraformTile_Track, // terraform_tile_proc
3107};
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.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr bool HasExactlyOneBit(T value)
Test whether value has exactly 1 bit 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.
bool Succeeded() const
Did this command succeed?
void AddCost(const Money &cost)
Adds the given cost to the cost of the command.
bool Failed() const
Did this command fail?
StringID GetErrorMessage() const
Returns the error message of a command.
void MakeError(StringID message, StringID extra_message=INVALID_STRING_ID)
Makes this CommandCost behave like an error command.
constexpr bool Test(Tenum value) const
Test if the enum value is set.
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:117
SpriteID single_x
single piece of rail in X direction, without ground
Definition rail.h:127
uint16_t max_speed
Maximum speed for vehicles travelling on this rail type.
Definition rail.h:221
SpriteID build_tunnel
button for building a tunnel
Definition rail.h:149
CursorID rail_swne
Cursor for building rail in X direction.
Definition rail.h:156
SpriteID convert_rail
button for converting rail
Definition rail.h:150
CursorID convert
Cursor for converting track.
Definition rail.h:162
CursorID depot
Cursor for building a depot.
Definition rail.h:160
RailTypes powered_railtypes
bitmask to the OTHER railtypes on which an engine of THIS railtype generates power
Definition rail.h:178
RailTypes introduces_railtypes
Bitmask of which other railtypes are introduced when this railtype is introduced.
Definition rail.h:256
SpriteID ground
ground sprite for a 3-way switch
Definition rail.h:126
CursorID rail_nwse
Cursor for building rail in Y direction.
Definition rail.h:158
SpriteID build_x_rail
button for building single rail in X direction
Definition rail.h:144
uint8_t sorting_order
The sorting order of this railtype for the toolbar dropdown.
Definition rail.h:261
RailTypeLabel label
Unique 32 bit rail type identifier.
Definition rail.h:226
SpriteID single_n
single piece of rail in the northern corner
Definition rail.h:129
struct RailTypeInfo::@24 strings
Strings associated with the rail type.
CursorID rail_ew
Cursor for building rail in E-W direction.
Definition rail.h:157
SpriteID auto_rail
button for the autorail construction
Definition rail.h:147
CursorID autorail
Cursor for autorail tool.
Definition rail.h:159
SpriteID single_y
single piece of rail in Y direction, without ground
Definition rail.h:128
StringID name
Name of this rail type.
Definition rail.h:166
RailTypes compatible_railtypes
bitmask to the OTHER railtypes on which an engine of THIS railtype can physically travel
Definition rail.h:181
uint GetRailtypeSpriteOffset() const
Offset between the current railtype and normal rail.
Definition rail.h:285
SpriteID single_s
single piece of rail in the southern corner
Definition rail.h:130
RailTypeFlags flags
Bit mask of rail type flags.
Definition rail.h:201
SpriteID signals[SIGTYPE_END][2][2]
signal GUI sprites (type, variant, state)
Definition rail.h:151
SpriteID build_ew_rail
button for building single rail in E-W direction
Definition rail.h:145
SpriteID build_y_rail
button for building single rail in Y direction
Definition rail.h:146
SpriteID track_ns
two pieces of rail in North and South corner (East-West direction)
Definition rail.h:125
RailTypeLabelList alternate_labels
Rail type labels this type provides in addition to the main label.
Definition rail.h:231
SpriteID snow_offset
sprite number difference between a piece of track on a snowy ground and the corresponding one on norm...
Definition rail.h:175
SpriteID track_y
single piece of rail in Y direction, with ground
Definition rail.h:124
SpriteID build_depot
button for building depots
Definition rail.h:148
struct RailTypeInfo::@23 cursor
Cursors associated with the rail type.
SpriteID single_w
single piece of rail in the western corner
Definition rail.h:132
SpriteID single_e
single piece of rail in the eastern corner
Definition rail.h:131
SpriteID build_ns_rail
button for building single rail in N-S direction
Definition rail.h:143
CursorID rail_ns
Cursor for building rail in N-S direction.
Definition rail.h:155
struct RailTypeInfo::@22 gui_sprites
struct containing the sprites for the rail GUI.
SpriteID tunnel
tunnel sprites base
Definition rail.h:135
SpriteID single_sloped
single piece of rail for slopes
Definition rail.h:133
struct RailTypeInfo::@21 base_sprites
Struct containing the main sprites.
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.
DoCommandFlag
List of flags for a command.
@ DC_AUTO
don't allow building on structures
@ DC_BANKRUPT
company bankrupts, skip money check, skip vehicle on tile check in some cases
@ DC_EXEC
execute the given command
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.
CompanyID _current_company
Company currently doing an action.
void DirtyCompanyInfrastructureWindows(CompanyID company)
Redraw all windows with company infrastructure counts.
GUI Functions related to companies.
Owner
Enum for all companies/owners.
@ INVALID_OWNER
An invalid owner.
@ OWNER_DEITY
The object is owned by a superuser / goal script.
@ OWNER_WATER
The tile/execution is done by "water".
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.
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.
@ EXPENSES_CONSTRUCTION
Construction costs.
static const uint TUNNELBRIDGE_TRACKBIT_FACTOR
Multiplier for how many regular track bits a tunnel/bridge counts.
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:17
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
uint GetPartialPixelZ(int x, int y, Slope corners)
Determines height at given coordinate of a slope.
TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
Returns information about trackdirs and signal states.
void DrawFoundation(TileInfo *ti, Foundation f)
Draw foundation f at tile ti.
int GetSlopeZInCorner(Slope tileh, Corner corner)
Determine the Z height of a corner relative to TileZ.
uint ApplyFoundationToSlope(Foundation f, Slope &s)
Applies a foundation to a slope.
int GetSlopePixelZ(int x, int y, bool ground_vehicle)
Return world Z coordinate of a given point of a tile.
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:515
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:611
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:570
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
@ 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
Train * GetTrainForReservation(TileIndex tile, Track track)
Find the train which has reserved a specific path.
Definition pbs.cpp:330
TrackBits GetReservedTrackbits(TileIndex t)
Get the reserved trackbits for any tile, regardless of type.
Definition pbs.cpp:24
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:393
Money RailClearCost(RailType railtype)
Returns the 'cost' of clearing the specified railtype.
Definition rail.h:376
Money RailBuildCost(RailType railtype)
Returns the cost of building the specified railtype.
Definition rail.h:365
RailFenceOffset
Offsets from base sprite for fence sprites.
Definition rail.h:92
@ RFO_FLAT_RIGHT
Slope FLAT, Track RIGHT, Fence W.
Definition rail.h:103
@ RFO_FLAT_Y_NE
Slope FLAT, Track Y, Fence NE.
Definition rail.h:94
@ RFO_SLOPE_NW_SW
Slope NW, Track Y, Fence SW.
Definition rail.h:108
@ RFO_FLAT_X_SE
Slope FLAT, Track X, Fence SE.
Definition rail.h:101
@ RFO_SLOPE_NW_NE
Slope NW, Track Y, Fence NE.
Definition rail.h:100
@ RFO_SLOPE_SE_SW
Slope SE, Track Y, Fence SW.
Definition rail.h:106
@ RFO_SLOPE_NE_SE
Slope NE, Track X, Fence SE.
Definition rail.h:107
@ RFO_FLAT_LOWER
Slope FLAT, Track LOWER, Fence N.
Definition rail.h:104
@ RFO_SLOPE_SW_SE
Slope SW, Track X, Fence SE.
Definition rail.h:105
@ RFO_FLAT_UPPER
Slope FLAT, Track UPPER, Fence S.
Definition rail.h:96
@ RFO_SLOPE_SE_NE
Slope SE, Track Y, Fence NE.
Definition rail.h:98
@ RFO_FLAT_Y_SW
Slope FLAT, Track Y, Fence SW.
Definition rail.h:102
@ RFO_FLAT_LEFT
Slope FLAT, Track LEFT, Fence E.
Definition rail.h:95
@ RFO_SLOPE_NE_NW
Slope NE, Track X, Fence NW.
Definition rail.h:99
@ RFO_FLAT_X_NW
Slope FLAT, Track X, Fence NW.
Definition rail.h:93
@ RFO_SLOPE_SW_NW
Slope SW, Track X, Fence NW.
Definition rail.h:97
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:312
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:325
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:297
@ Hidden
Bit number for hiding from selection.
@ NoSpriteCombine
Bit number for using non-combined junctions.
@ RTSG_GROUND
Main group of ground images.
Definition rail.h:42
@ RTSG_CURSORS
Cursor and toolbar icon images.
Definition rail.h:40
@ RTSG_GROUND_COMPLETE
Complete ground images.
Definition rail.h:52
@ RTSG_OVERLAY
Images for overlaying track.
Definition rail.h:41
@ RTSG_DEPOT
Depot images.
Definition rail.h:48
@ RTSG_FENCES
Fence images.
Definition rail.h:49
@ RTO_Y
Piece of rail in Y direction.
Definition rail.h:62
@ RTO_S
Piece of rail in southern corner.
Definition rail.h:64
@ RTO_JUNCTION_NE
Ballast for junction 'pointing' NE.
Definition rail.h:73
@ RTO_JUNCTION_NSEW
Ballast for full junction.
Definition rail.h:76
@ RTO_JUNCTION_SW
Ballast for junction 'pointing' SW.
Definition rail.h:72
@ RTO_SLOPE_SE
Piece of rail on slope with south-east raised.
Definition rail.h:68
@ RTO_E
Piece of rail in eastern corner.
Definition rail.h:65
@ RTO_W
Piece of rail in western corner.
Definition rail.h:66
@ RTO_CROSSING_XY
Crossing of X and Y rail, with ballast.
Definition rail.h:71
@ RTO_SLOPE_SW
Piece of rail on slope with south-west raised.
Definition rail.h:69
@ RTO_SLOPE_NW
Piece of rail on slope with north-west raised.
Definition rail.h:70
@ RTO_JUNCTION_NW
Ballast for junction 'pointing' NW.
Definition rail.h:75
@ RTO_JUNCTION_SE
Ballast for junction 'pointing' SE.
Definition rail.h:74
@ RTO_SLOPE_NE
Piece of rail on slope with north-east raised.
Definition rail.h:67
@ RTO_X
Piece of rail in X direction.
Definition rail.h:61
@ RTO_N
Piece of rail in northern corner.
Definition rail.h:63
bool RailNoLevelCrossings(RailType rt)
Test if a RailType disallows build of level crossings.
Definition rail.h:335
int TicksToLeaveDepot(const Train *v)
Compute number of ticks when next wagon will leave a depot.
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.
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,...
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.
CommandCost CmdRemoveSignalTrack(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, Track track, bool autofill)
Remove signals on a stretch of track.
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.
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.
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.
static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image, uint num_sprites)
Draw fence at NE border matching the tile slope.
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
static Vehicle * EnsureNoShipProc(Vehicle *v, void *)
Test-procedure for HasVehicleOnPos to check for a ship.
void InitRailTypes()
Resolve sprites of custom rail types.
Definition rail_cmd.cpp:130
static FenceOffset _fence_offsets[]
Offsets for drawing fences.
static void DrawTrackFence(const TileInfo *ti, SpriteID base_image, uint num_sprites, RailFenceOffset rfo)
Draw a track fence.
CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, TileIndex area_start, RailType totype, bool diagonal)
Convert one rail type to the other.
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.
CommandCost CmdBuildTrainDepot(DoCommandFlag flags, TileIndex tile, RailType railtype, DiagDirection dir)
Build a train depot.
Definition rail_cmd.cpp:963
static Vehicle * UpdateTrainPowerProc(Vehicle *v, void *data)
Update power of train under which is the railtype being converted.
static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image, uint num_sprites)
Draw fence at SW border matching the tile slope.
static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image, uint num_sprites)
Draw fence at SE border matching the tile slope.
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.
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.
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.
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
@ 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
static debug_inline bool IsRailDepotTile(Tile t)
Is this tile rail tile and a rail depot?
Definition rail_map.h:105
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
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
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
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:285
Money RoadBuildCost(RoadType roadtype)
Returns the cost of building the specified roadtype.
Definition road.h:242
void UpdateAdjacentLevelCrossingTilesOnLevelCrossingRemoval(TileIndex tile, Axis road_axis)
Update adjacent level crossing tiles in this multi-track crossing, due to removal of a level crossing...
void MarkDirtyAdjacentLevelCrossingTiles(TileIndex tile, Axis road_axis)
Find adjacent level crossing tiles in this multi-track crossing and mark them dirty.
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).
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
Corner
Enumeration of tile corners.
Definition slope_type.h:22
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
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?
Track GetRailStationTrack(Tile t)
Get the rail track of a rail station tile.
bool IsStationTileBlocked(Tile t)
Is tile t a blocked tile?
bool HasStationRail(Tile t)
Has this station tile a rail? In other words, is this station tile a rail station or rail waypoint?
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:277
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Class to backup a specific variable and restore it later.
void Restore()
Restore the variable.
VehicleType type
Type of vehicle.
GUISettings gui
settings related to the GUI
std::array< uint32_t, RAILTYPE_END > rail
Count of company owned track bits for each rail type.
CompanyInfrastructure infrastructure
NOSAVE: Counts of company owned infrastructure.
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.
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.
int y_offs
Bounding box Y offset.
Corner height_ref
Corner to use height offset from.
int x_offs
Bounding box X offset.
int y_size
Bounding box Y size.
int x_size
Bounding box X size.
bool show_track_reservation
highlight reserved tracks.
LandscapeType 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.
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:23
bool forbid_90_deg
forbid trains to make 90 deg turns
Coordinates of a point in 2D.
Tindex index
Index of this pool item.
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static Titem * Get(size_t index)
Returns Titem with given index.
T * Next() const
Get next vehicle in the chain.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
T * First() const
Get the first vehicle in the chain.
Used to only draw a part of the sprite.
Definition gfx_type.h:265
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.
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.
Direction direction
facing
Order current_order
The current order (+ status, like: loading)
int32_t y_pos
y coordinate.
int32_t x_pos
x coordinate.
uint8_t vehstatus
Status.
uint16_t cur_speed
current speed
TileIndex tile
Current tile index.
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
std::tuple< Slope, int > GetTilePixelSlope(TileIndex tile)
Return the slope of a given tile.
Definition tile_map.h:289
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
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
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
@ TROPICZONE_DESERT
Tile is desert.
Definition tile_type.h:78
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:252
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.
@ CCF_TRACK
Valid changes while vehicle is driving, and possibly changing tracks.
Definition train.h:48
void FreeTrainTrackReservation(const Train *v)
Free the reserved path in front of a vehicle.
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...
@ TO_BUILDINGS
company buildings - depots, stations, HQ, ...
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)
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.
@ VS_HIDDEN
Vehicle is not visible.
Functions related to vehicles.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
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).
Functions related to water (management)
void TileLoop_Water(TileIndex tile)
Let a water tile floods its diagonal adjoining tiles called from tunnelbridge_cmd,...
@ FLOOD_NONE
The tile does not flood neighboured tiles.
Definition water.h:20
FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
Returns the behaviour of a tile during flooding.
void CheckForDockingTile(TileIndex t)
Mark the supplied tile as a docking tile if it is suitable for docking.
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:3217
@ WC_VEHICLE_DEPOT
Depot view; Window numbers:
@ WC_BUILD_VEHICLE
Build vehicle; Window numbers:
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.