Codechange: Rename and return AyStarStatus instead of int (#13125)
[openttd-github.git] / src / signal.cpp
blob315d59ab9844c97089d7d0ece976921cea5917d4
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 */
8 /** @file signal.cpp functions related to rail signals updating */
10 #include "stdafx.h"
11 #include "debug.h"
12 #include "station_map.h"
13 #include "tunnelbridge_map.h"
14 #include "vehicle_func.h"
15 #include "viewport_func.h"
16 #include "train.h"
17 #include "company_base.h"
18 #include "pbs.h"
20 #include "safeguards.h"
23 /** these are the maximums used for updating signal blocks */
24 static const uint SIG_TBU_SIZE = 64; ///< number of signals entering to block
25 static const uint SIG_TBD_SIZE = 256; ///< number of intersections - open nodes in current block
26 static const uint SIG_GLOB_SIZE = 128; ///< number of open blocks (block can be opened more times until detected)
27 static const uint SIG_GLOB_UPDATE = 64; ///< how many items need to be in _globset to force update
29 static_assert(SIG_GLOB_UPDATE <= SIG_GLOB_SIZE);
31 /** incidating trackbits with given enterdir */
32 static const TrackBits _enterdir_to_trackbits[DIAGDIR_END] = {
33 TRACK_BIT_3WAY_NE,
34 TRACK_BIT_3WAY_SE,
35 TRACK_BIT_3WAY_SW,
36 TRACK_BIT_3WAY_NW
39 /** incidating trackdirbits with given enterdir */
40 static const TrackdirBits _enterdir_to_trackdirbits[DIAGDIR_END] = {
41 TRACKDIR_BIT_X_SW | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_RIGHT_S,
42 TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_RIGHT_N,
43 TRACKDIR_BIT_X_NE | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_LEFT_N,
44 TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_LEFT_S
47 /**
48 * Set containing 'items' items of 'tile and Tdir'
49 * No tree structure is used because it would cause
50 * slowdowns in most usual cases
52 template <typename Tdir, uint items>
53 struct SmallSet {
54 private:
55 uint n; // actual number of units
56 bool overflowed; // did we try to overflow the set?
57 const char *name; // name, used for debugging purposes...
59 /** Element of set */
60 struct SSdata {
61 TileIndex tile;
62 Tdir dir;
63 } data[items];
65 public:
66 /** Constructor - just set default values and 'name' */
67 SmallSet(const char *name) : n(0), overflowed(false), name(name) { }
69 /** Reset variables to default values */
70 void Reset()
72 this->n = 0;
73 this->overflowed = false;
76 /**
77 * Returns value of 'overflowed'
78 * @return did we try to overflow the set?
80 bool Overflowed()
82 return this->overflowed;
85 /**
86 * Checks for empty set
87 * @return is the set empty?
89 bool IsEmpty()
91 return this->n == 0;
94 /**
95 * Checks for full set
96 * @return is the set full?
98 bool IsFull()
100 return this->n == lengthof(data);
104 * Reads the number of items
105 * @return current number of items
107 uint Items()
109 return this->n;
114 * Tries to remove first instance of given tile and dir
115 * @param tile tile
116 * @param dir and dir to remove
117 * @return element was found and removed
119 bool Remove(TileIndex tile, Tdir dir)
121 for (uint i = 0; i < this->n; i++) {
122 if (this->data[i].tile == tile && this->data[i].dir == dir) {
123 this->data[i] = this->data[--this->n];
124 return true;
128 return false;
132 * Tries to find given tile and dir in the set
133 * @param tile tile
134 * @param dir and dir to find
135 * @return true iff the tile & dir element was found
137 bool IsIn(TileIndex tile, Tdir dir)
139 for (uint i = 0; i < this->n; i++) {
140 if (this->data[i].tile == tile && this->data[i].dir == dir) return true;
143 return false;
147 * Adds tile & dir into the set, checks for full set
148 * Sets the 'overflowed' flag if the set was full
149 * @param tile tile
150 * @param dir and dir to add
151 * @return true iff the item could be added (set wasn't full)
153 bool Add(TileIndex tile, Tdir dir)
155 if (this->IsFull()) {
156 overflowed = true;
157 Debug(misc, 0, "SignalSegment too complex. Set {} is full (maximum {})", name, items);
158 return false; // set is full
161 this->data[this->n].tile = tile;
162 this->data[this->n].dir = dir;
163 this->n++;
165 return true;
169 * Reads the last added element into the set
170 * @param tile pointer where tile is written to
171 * @param dir pointer where dir is written to
172 * @return false iff the set was empty
174 bool Get(TileIndex *tile, Tdir *dir)
176 if (this->n == 0) return false;
178 this->n--;
179 *tile = this->data[this->n].tile;
180 *dir = this->data[this->n].dir;
182 return true;
186 static SmallSet<Trackdir, SIG_TBU_SIZE> _tbuset("_tbuset"); ///< set of signals that will be updated
187 static SmallSet<DiagDirection, SIG_TBD_SIZE> _tbdset("_tbdset"); ///< set of open nodes in current signal block
188 static SmallSet<DiagDirection, SIG_GLOB_SIZE> _globset("_globset"); ///< set of places to be updated in following runs
191 /** Check whether there is a train on rail, not in a depot */
192 static Vehicle *TrainOnTileEnum(Vehicle *v, void *)
194 if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return nullptr;
196 return v;
201 * Perform some operations before adding data into Todo set
202 * The new and reverse direction is removed from _globset, because we are sure
203 * it doesn't need to be checked again
204 * Also, remove reverse direction from _tbdset
205 * This is the 'core' part so the graph searching won't enter any tile twice
207 * @param t1 tile we are entering
208 * @param d1 direction (tile side) we are entering
209 * @param t2 tile we are leaving
210 * @param d2 direction (tile side) we are leaving
211 * @return false iff reverse direction was in Todo set
213 static inline bool CheckAddToTodoSet(TileIndex t1, DiagDirection d1, TileIndex t2, DiagDirection d2)
215 _globset.Remove(t1, d1); // it can be in Global but not in Todo
216 _globset.Remove(t2, d2); // remove in all cases
218 assert(!_tbdset.IsIn(t1, d1)); // it really shouldn't be there already
220 return !_tbdset.Remove(t2, d2);
225 * Perform some operations before adding data into Todo set
226 * The new and reverse direction is removed from Global set, because we are sure
227 * it doesn't need to be checked again
228 * Also, remove reverse direction from Todo set
229 * This is the 'core' part so the graph searching won't enter any tile twice
231 * @param t1 tile we are entering
232 * @param d1 direction (tile side) we are entering
233 * @param t2 tile we are leaving
234 * @param d2 direction (tile side) we are leaving
235 * @return false iff the Todo buffer would be overrun
237 static inline bool MaybeAddToTodoSet(TileIndex t1, DiagDirection d1, TileIndex t2, DiagDirection d2)
239 if (!CheckAddToTodoSet(t1, d1, t2, d2)) return true;
241 return _tbdset.Add(t1, d1);
245 /** Current signal block state flags */
246 enum SigFlags {
247 SF_NONE = 0,
248 SF_TRAIN = 1 << 0, ///< train found in segment
249 SF_EXIT = 1 << 1, ///< exitsignal found
250 SF_EXIT2 = 1 << 2, ///< two or more exits found
251 SF_GREEN = 1 << 3, ///< green exitsignal found
252 SF_GREEN2 = 1 << 4, ///< two or more green exits found
253 SF_FULL = 1 << 5, ///< some of buffers was full, do not continue
254 SF_PBS = 1 << 6, ///< pbs signal found
255 SF_SPLIT = 1 << 7, ///< track merge/split found
256 SF_ENTER = 1 << 8, ///< signal entering the block found
257 SF_ENTER2 = 1 << 9, ///< two or more signals entering the block found
260 DECLARE_ENUM_AS_BIT_SET(SigFlags)
264 * Search signal block
266 * @param owner owner whose signals we are updating
267 * @return SigFlags
269 static SigFlags ExploreSegment(Owner owner)
271 SigFlags flags = SF_NONE;
273 TileIndex tile = INVALID_TILE; // Stop GCC from complaining about a possibly uninitialized variable (issue #8280).
274 DiagDirection enterdir = INVALID_DIAGDIR;
276 while (_tbdset.Get(&tile, &enterdir)) { // tile and enterdir are initialized here, unless I'm mistaken.
277 TileIndex oldtile = tile; // tile we are leaving
278 DiagDirection exitdir = enterdir == INVALID_DIAGDIR ? INVALID_DIAGDIR : ReverseDiagDir(enterdir); // expected new exit direction (for straight line)
280 switch (GetTileType(tile)) {
281 case MP_RAILWAY: {
282 if (GetTileOwner(tile) != owner) continue; // do not propagate signals on others' tiles (remove for tracksharing)
284 if (IsRailDepot(tile)) {
285 if (enterdir == INVALID_DIAGDIR) { // from 'inside' - train just entered or left the depot
286 if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags |= SF_TRAIN;
287 exitdir = GetRailDepotDirection(tile);
288 tile += TileOffsByDiagDir(exitdir);
289 enterdir = ReverseDiagDir(exitdir);
290 break;
291 } else if (enterdir == GetRailDepotDirection(tile)) { // entered a depot
292 if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags |= SF_TRAIN;
293 continue;
294 } else {
295 continue;
299 assert(IsValidDiagDirection(enterdir));
300 TrackBits tracks = GetTrackBits(tile); // trackbits of tile
301 TrackBits tracks_masked = (TrackBits)(tracks & _enterdir_to_trackbits[enterdir]); // only incidating trackbits
303 if (tracks == TRACK_BIT_HORZ || tracks == TRACK_BIT_VERT) { // there is exactly one incidating track, no need to check
304 tracks = tracks_masked;
305 /* If no train detected yet, and there is not no train -> there is a train -> set the flag */
306 if (!(flags & SF_TRAIN) && EnsureNoTrainOnTrackBits(tile, tracks).Failed()) flags |= SF_TRAIN;
307 } else {
308 if (tracks_masked == TRACK_BIT_NONE) continue; // no incidating track
309 if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags |= SF_TRAIN;
312 /* Is this a track merge or split? */
313 if (!HasAtMostOneBit(tracks)) flags |= SF_SPLIT;
315 if (HasSignals(tile)) { // there is exactly one track - not zero, because there is exit from this tile
316 Track track = TrackBitsToTrack(tracks_masked); // mask TRACK_BIT_X and Y too
317 if (HasSignalOnTrack(tile, track)) { // now check whole track, not trackdir
318 SignalType sig = GetSignalType(tile, track);
319 Trackdir trackdir = (Trackdir)FindFirstBit((tracks * 0x101U) & _enterdir_to_trackdirbits[enterdir]);
320 Trackdir reversedir = ReverseTrackdir(trackdir);
321 /* add (tile, reversetrackdir) to 'to-be-updated' set when there is
322 * ANY conventional signal in REVERSE direction
323 * (if it is a presignal EXIT and it changes, it will be added to 'to-be-done' set later) */
324 if (HasSignalOnTrackdir(tile, reversedir)) {
325 if (IsPbsSignal(sig)) flags |= SF_PBS;
326 if (flags & SF_ENTER) flags |= SF_ENTER2;
327 flags |= SF_ENTER;
329 if (!_tbuset.Add(tile, reversedir)) return flags | SF_FULL;
331 if (HasSignalOnTrackdir(tile, trackdir) && !IsOnewaySignal(tile, track)) flags |= SF_PBS;
333 /* if it is a presignal EXIT in OUR direction and we haven't found 2 green exits yes, do special check */
334 if (!(flags & SF_GREEN2) && IsPresignalExit(tile, track) && HasSignalOnTrackdir(tile, trackdir)) { // found presignal exit
335 if (flags & SF_EXIT) flags |= SF_EXIT2; // found two (or more) exits
336 flags |= SF_EXIT; // found at least one exit - allow for compiler optimizations
337 if (GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_GREEN) { // found green presignal exit
338 if (flags & SF_GREEN) flags |= SF_GREEN2;
339 flags |= SF_GREEN;
343 continue;
347 for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { // test all possible exit directions
348 if (dir != enterdir && (tracks & _enterdir_to_trackbits[dir])) { // any track incidating?
349 TileIndex newtile = tile + TileOffsByDiagDir(dir); // new tile to check
350 DiagDirection newdir = ReverseDiagDir(dir); // direction we are entering from
351 if (!MaybeAddToTodoSet(newtile, newdir, tile, dir)) return flags | SF_FULL;
355 continue; // continue the while() loop
358 case MP_STATION:
359 if (!HasStationRail(tile)) continue;
360 if (GetTileOwner(tile) != owner) continue;
361 if (DiagDirToAxis(enterdir) != GetRailStationAxis(tile)) continue; // different axis
362 if (IsStationTileBlocked(tile)) continue; // 'eye-candy' station tile
364 if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags |= SF_TRAIN;
365 tile += TileOffsByDiagDir(exitdir);
366 break;
368 case MP_ROAD:
369 if (!IsLevelCrossing(tile)) continue;
370 if (GetTileOwner(tile) != owner) continue;
371 if (DiagDirToAxis(enterdir) == GetCrossingRoadAxis(tile)) continue; // different axis
373 if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags |= SF_TRAIN;
374 tile += TileOffsByDiagDir(exitdir);
375 break;
377 case MP_TUNNELBRIDGE: {
378 if (GetTileOwner(tile) != owner) continue;
379 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
380 DiagDirection dir = GetTunnelBridgeDirection(tile);
382 if (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole
383 if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags |= SF_TRAIN;
384 enterdir = dir;
385 exitdir = ReverseDiagDir(dir);
386 tile += TileOffsByDiagDir(exitdir); // just skip to next tile
387 } else { // NOT incoming from the wormhole!
388 if (ReverseDiagDir(enterdir) != dir) continue;
389 if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags |= SF_TRAIN;
390 tile = GetOtherTunnelBridgeEnd(tile); // just skip to exit tile
391 enterdir = INVALID_DIAGDIR;
392 exitdir = INVALID_DIAGDIR;
395 break;
397 default:
398 continue; // continue the while() loop
401 if (!MaybeAddToTodoSet(tile, enterdir, oldtile, exitdir)) return flags | SF_FULL;
404 return flags;
409 * Update signals around segment in _tbuset
411 * @param flags info about segment
413 static void UpdateSignalsAroundSegment(SigFlags flags)
415 TileIndex tile = INVALID_TILE; // Stop GCC from complaining about a possibly uninitialized variable (issue #8280).
416 Trackdir trackdir = INVALID_TRACKDIR;
418 while (_tbuset.Get(&tile, &trackdir)) {
419 assert(HasSignalOnTrackdir(tile, trackdir));
421 Track track = TrackdirToTrack(trackdir);
422 SignalType sig = GetSignalType(tile, track);
423 SignalState newstate = SIGNAL_STATE_GREEN;
425 /* Signal state of reserved path signals is handled by the reserve/unreserve process. */
426 if (IsPbsSignal(sig) && (GetRailReservationTrackBits(tile) & TrackToTrackBits(track)) != TRACK_BIT_NONE) continue;
428 /* determine whether the new state is red */
429 if (flags & SF_TRAIN) {
430 /* train in the segment */
431 newstate = SIGNAL_STATE_RED;
432 } else if (IsPbsSignal(sig) && (flags & (SF_SPLIT | SF_ENTER2))) {
433 /* Turn path signals red if the segment has a junction or more than one way in. */
434 newstate = SIGNAL_STATE_RED;
435 } else {
436 /* is it a bidir combo? - then do not count its other signal direction as exit */
437 if (sig == SIGTYPE_COMBO && HasSignalOnTrackdir(tile, ReverseTrackdir(trackdir))) {
438 /* at least one more exit */
439 if ((flags & SF_EXIT2) &&
440 /* no green exit */
441 (!(flags & SF_GREEN) ||
442 /* only one green exit, and it is this one - so all other exits are red */
443 (!(flags & SF_GREEN2) && GetSignalStateByTrackdir(tile, ReverseTrackdir(trackdir)) == SIGNAL_STATE_GREEN))) {
444 newstate = SIGNAL_STATE_RED;
446 } else { // entry, at least one exit, no green exit
447 if (IsPresignalEntry(tile, TrackdirToTrack(trackdir)) && (flags & SF_EXIT) && !(flags & SF_GREEN)) newstate = SIGNAL_STATE_RED;
451 /* only when the state changes */
452 if (newstate != GetSignalStateByTrackdir(tile, trackdir)) {
453 if (IsPresignalExit(tile, TrackdirToTrack(trackdir))) {
454 /* for pre-signal exits, add block to the global set */
455 DiagDirection exitdir = TrackdirToExitdir(ReverseTrackdir(trackdir));
456 _globset.Add(tile, exitdir); // do not check for full global set, first update all signals
458 SetSignalStateByTrackdir(tile, trackdir, newstate);
459 MarkTileDirtyByTile(tile);
466 /** Reset all sets after one set overflowed */
467 static inline void ResetSets()
469 _tbuset.Reset();
470 _tbdset.Reset();
471 _globset.Reset();
476 * Updates blocks in _globset buffer
478 * @param owner company whose signals we are updating
479 * @return state of the first block from _globset
480 * @pre Company::IsValidID(owner)
482 static SigSegState UpdateSignalsInBuffer(Owner owner)
484 assert(Company::IsValidID(owner));
486 bool first = true; // first block?
487 SigSegState state = SIGSEG_FREE; // value to return
489 TileIndex tile = INVALID_TILE; // Stop GCC from complaining about a possibly uninitialized variable (issue #8280).
490 DiagDirection dir = INVALID_DIAGDIR;
492 while (_globset.Get(&tile, &dir)) {
493 assert(_tbuset.IsEmpty());
494 assert(_tbdset.IsEmpty());
496 /* After updating signal, data stored are always MP_RAILWAY with signals.
497 * Other situations happen when data are from outside functions -
498 * modification of railbits (including both rail building and removal),
499 * train entering/leaving block, train leaving depot...
501 switch (GetTileType(tile)) {
502 case MP_TUNNELBRIDGE:
503 /* 'optimization assert' - do not try to update signals when it is not needed */
504 assert(GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL);
505 assert(dir == INVALID_DIAGDIR || dir == ReverseDiagDir(GetTunnelBridgeDirection(tile)));
506 _tbdset.Add(tile, INVALID_DIAGDIR); // we can safely start from wormhole centre
507 _tbdset.Add(GetOtherTunnelBridgeEnd(tile), INVALID_DIAGDIR);
508 break;
510 case MP_RAILWAY:
511 if (IsRailDepot(tile)) {
512 /* 'optimization assert' do not try to update signals in other cases */
513 assert(dir == INVALID_DIAGDIR || dir == GetRailDepotDirection(tile));
514 _tbdset.Add(tile, INVALID_DIAGDIR); // start from depot inside
515 break;
517 [[fallthrough]];
519 case MP_STATION:
520 case MP_ROAD:
521 if ((TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)) & _enterdir_to_trackbits[dir]) != TRACK_BIT_NONE) {
522 /* only add to set when there is some 'interesting' track */
523 _tbdset.Add(tile, dir);
524 _tbdset.Add(tile + TileOffsByDiagDir(dir), ReverseDiagDir(dir));
525 break;
527 [[fallthrough]];
529 default:
530 /* jump to next tile */
531 tile = tile + TileOffsByDiagDir(dir);
532 dir = ReverseDiagDir(dir);
533 if ((TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)) & _enterdir_to_trackbits[dir]) != TRACK_BIT_NONE) {
534 _tbdset.Add(tile, dir);
535 break;
537 /* happens when removing a rail that wasn't connected at one or both sides */
538 continue; // continue the while() loop
541 assert(!_tbdset.Overflowed()); // it really shouldn't overflow by these one or two items
542 assert(!_tbdset.IsEmpty()); // it wouldn't hurt anyone, but shouldn't happen too
544 SigFlags flags = ExploreSegment(owner);
546 if (first) {
547 first = false;
548 /* SIGSEG_FREE is set by default */
549 if (flags & SF_PBS) {
550 state = SIGSEG_PBS;
551 } else if ((flags & SF_TRAIN) || ((flags & SF_EXIT) && !(flags & SF_GREEN)) || (flags & SF_FULL)) {
552 state = SIGSEG_FULL;
556 /* do not do anything when some buffer was full */
557 if (flags & SF_FULL) {
558 ResetSets(); // free all sets
559 break;
562 UpdateSignalsAroundSegment(flags);
565 return state;
569 static Owner _last_owner = INVALID_OWNER; ///< last owner whose track was put into _globset
573 * Update signals in buffer
574 * Called from 'outside'
576 void UpdateSignalsInBuffer()
578 if (!_globset.IsEmpty()) {
579 UpdateSignalsInBuffer(_last_owner);
580 _last_owner = INVALID_OWNER; // invalidate
586 * Add track to signal update buffer
588 * @param tile tile where we start
589 * @param track track at which ends we will update signals
590 * @param owner owner whose signals we will update
592 void AddTrackToSignalBuffer(TileIndex tile, Track track, Owner owner)
594 static const DiagDirection _search_dir_1[] = {
595 DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE
597 static const DiagDirection _search_dir_2[] = {
598 DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE
601 /* do not allow signal updates for two companies in one run */
602 assert(_globset.IsEmpty() || owner == _last_owner);
604 _last_owner = owner;
606 _globset.Add(tile, _search_dir_1[track]);
607 _globset.Add(tile, _search_dir_2[track]);
609 if (_globset.Items() >= SIG_GLOB_UPDATE) {
610 /* too many items, force update */
611 UpdateSignalsInBuffer(_last_owner);
612 _last_owner = INVALID_OWNER;
618 * Add side of tile to signal update buffer
620 * @param tile tile where we start
621 * @param side side of tile
622 * @param owner owner whose signals we will update
624 void AddSideToSignalBuffer(TileIndex tile, DiagDirection side, Owner owner)
626 /* do not allow signal updates for two companies in one run */
627 assert(_globset.IsEmpty() || owner == _last_owner);
629 _last_owner = owner;
631 _globset.Add(tile, side);
633 if (_globset.Items() >= SIG_GLOB_UPDATE) {
634 /* too many items, force update */
635 UpdateSignalsInBuffer(_last_owner);
636 _last_owner = INVALID_OWNER;
641 * Update signals, starting at one side of a tile
642 * Will check tile next to this at opposite side too
644 * @see UpdateSignalsInBuffer()
645 * @param tile tile where we start
646 * @param side side of tile
647 * @param owner owner whose signals we will update
648 * @return the state of the signal segment
650 SigSegState UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner)
652 assert(_globset.IsEmpty());
653 _globset.Add(tile, side);
655 return UpdateSignalsInBuffer(owner);
660 * Update signals at segments that are at both ends of
661 * given (existent or non-existent) track
663 * @see UpdateSignalsInBuffer()
664 * @param tile tile where we start
665 * @param track track at which ends we will update signals
666 * @param owner owner whose signals we will update
668 void SetSignalsOnBothDir(TileIndex tile, Track track, Owner owner)
670 assert(_globset.IsEmpty());
672 AddTrackToSignalBuffer(tile, track, owner);
673 UpdateSignalsInBuffer(owner);