src/signal.cpp
changeset 8238 d47a86c79603
child 8246 4469741c1f70
equal deleted inserted replaced
8237:6f925c9cf836 8238:d47a86c79603
       
     1 /* $Id$ */
       
     2 
       
     3 /** @file signal.cpp functions related to rail signals updating */
       
     4 
       
     5 #include "stdafx.h"
       
     6 #include "openttd.h"
       
     7 #include "debug.h"
       
     8 #include "tile_cmd.h"
       
     9 #include "rail_map.h"
       
    10 #include "road_map.h"
       
    11 #include "station_map.h"
       
    12 #include "tunnelbridge_map.h"
       
    13 #include "vehicle_func.h"
       
    14 #include "train.h"
       
    15 #include "newgrf_station.h"
       
    16 #include "functions.h"
       
    17 #include "track_type.h"
       
    18 #include "track_func.h"
       
    19 #include "signal_func.h"
       
    20 #include "player.h"
       
    21 
       
    22 
       
    23 /** these are the maximums used for updating signal blocks */
       
    24 enum {
       
    25 	SIG_TBU_SIZE  =  64, ///< number of signals entering to block
       
    26 	SIG_TBD_SIZE  = 256, ///< number of intersections - open nodes in current block
       
    27 	SIG_GLOB_SIZE =  64, ///< number of open blocks (block can be opened more times until detected)
       
    28 };
       
    29 
       
    30 /** incidating trackbits with given enterdir */
       
    31 static const TrackBitsByte _enterdir_to_trackbits[DIAGDIR_END] = {
       
    32 	{TRACK_BIT_3WAY_NE},
       
    33 	{TRACK_BIT_3WAY_SE},
       
    34 	{TRACK_BIT_3WAY_SW},
       
    35 	{TRACK_BIT_3WAY_NW}
       
    36 };
       
    37 
       
    38 /** incidating trackdirbits with given enterdir */
       
    39 static const TrackdirBitsShort _enterdir_to_trackdirbits[DIAGDIR_END] = {
       
    40 	{TRACKDIR_BIT_X_SW | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_RIGHT_S},
       
    41 	{TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_RIGHT_N},
       
    42 	{TRACKDIR_BIT_X_NE | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_LEFT_N},
       
    43 	{TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_LEFT_S}
       
    44 };
       
    45 
       
    46 /**
       
    47  * Set containing 'items' items of 'tile and Tdir'
       
    48  * No tree structure is used because it would cause
       
    49  * slowdowns in most usual cases
       
    50  */
       
    51 template <typename Tdir, uint items>
       
    52 struct SmallSet {
       
    53 private:
       
    54 	uint n;           // actual number of units
       
    55 	bool overflowed;  // did we try to oveflow the set?
       
    56 	const char *name; // name, used for debugging purposes...
       
    57 
       
    58 	/** Element of set */
       
    59 	struct SSdata {
       
    60 		TileIndex tile;
       
    61 		Tdir dir;
       
    62 	} data[items];
       
    63 
       
    64 public:
       
    65 	/** Constructor - just set default values and 'name' */
       
    66 	SmallSet(const char *name) : n(0), overflowed(false), name(name) { }
       
    67 
       
    68 	/** Reset variables to default values */
       
    69 	void Reset()
       
    70 	{
       
    71 		this->n = 0;
       
    72 		this->overflowed = false;
       
    73 	}
       
    74 
       
    75 	/**
       
    76 	 * Returns value of 'oveflowed'
       
    77 	 * @return did we try to overflow the set?
       
    78 	 */
       
    79 	bool Overflowed()
       
    80 	{
       
    81 		return this->overflowed;
       
    82 	}
       
    83 
       
    84 	/**
       
    85 	 * Checks for empty set
       
    86 	 * @return is the set empty?
       
    87 	 */
       
    88 	bool IsEmpty()
       
    89 	{
       
    90 		return this->n == 0;
       
    91 	}
       
    92 
       
    93 	/**
       
    94 	 * Checks for full set
       
    95 	 * @return is the set full?
       
    96 	 */
       
    97 	bool IsFull()
       
    98 	{
       
    99 		return this->n == lengthof(data);
       
   100 	}
       
   101 
       
   102 	/**
       
   103 	 * Tries to remove first instance of given tile and dir
       
   104 	 * @param tile tile
       
   105 	 * @param dir and dir to remove
       
   106 	 * @return element was found and removed
       
   107 	 */
       
   108 	bool Remove(TileIndex tile, Tdir dir)
       
   109 	{
       
   110 		for (uint i = 0; i < this->n; i++) {
       
   111 			if (this->data[i].tile == tile && this->data[i].dir == dir) {
       
   112 				this->data[i] = this->data[--this->n];
       
   113 				return true;
       
   114 			}
       
   115 		}
       
   116 
       
   117 		return false;
       
   118 	}
       
   119 
       
   120 	/**
       
   121 	 * Tries to find given tile and dir in the set
       
   122 	 * @param tile tile
       
   123 	 * @param dir and dir to find
       
   124 	 * @return true iff the tile & dir elemnt was found
       
   125 	 */
       
   126 	bool IsIn(TileIndex tile, Tdir dir)
       
   127 	{
       
   128 		for (uint i = 0; i < this->n; i++) {
       
   129 			if (this->data[i].tile == tile && this->data[i].dir == dir) return true;
       
   130 		}
       
   131 
       
   132 		return false;
       
   133 	}
       
   134 
       
   135 	/**
       
   136 	 * Adds tile & dir into the set, checks for full set
       
   137 	 * Sets the 'overflowed' flag if the set was full
       
   138 	 * @param tile tile
       
   139 	 * @param dir and dir to add
       
   140 	 * @return true iff the item could be added (set wasn't full)
       
   141 	 */
       
   142 	bool Add(TileIndex tile, Tdir dir)
       
   143 	{
       
   144 		if (this->IsFull()) {
       
   145 			overflowed = true;
       
   146 			DEBUG(misc, 0, "SignalSegment too complex. Set %s is full (maximum %d)", name, items);
       
   147 			return false; // set is full
       
   148 		}
       
   149 
       
   150 		this->data[this->n].tile = tile;
       
   151 		this->data[this->n].dir = dir;
       
   152 		this->n++;
       
   153 
       
   154 		return true;
       
   155 	}
       
   156 
       
   157 	/**
       
   158 	 * Reads the last added element into the set
       
   159 	 * @param tile pointer where tile is written to
       
   160 	 * @param dir pointer where dir is written to
       
   161 	 * @return false iff the set was empty
       
   162 	 */
       
   163 	bool Get(TileIndex *tile, Tdir *dir)
       
   164 	{
       
   165 		if (this->n == 0) return false;
       
   166 
       
   167 		this->n--;
       
   168 		*tile = this->data[this->n].tile;
       
   169 		*dir = this->data[this->n].dir;
       
   170 
       
   171 		return true;
       
   172 	}
       
   173 };
       
   174 
       
   175 static SmallSet<Trackdir, SIG_TBU_SIZE> _tbuset("_tbuset");         ///< set of signals that will be updated
       
   176 static SmallSet<DiagDirection, SIG_TBD_SIZE> _tbdset("_tbdset");    ///< set of open nodes in current signal block
       
   177 static SmallSet<DiagDirection, SIG_GLOB_SIZE> _globset("_globset"); ///< set of places to be updated in following runs
       
   178 
       
   179 
       
   180 /** Check whether there is a train on rail, not in a depot */
       
   181 static void *TrainOnTileEnum(Vehicle *v, void *)
       
   182 {
       
   183 	if (v->type != VEH_TRAIN || v->u.rail.track == TRACK_BIT_DEPOT) return NULL;
       
   184 
       
   185 	return v;
       
   186 }
       
   187 
       
   188 
       
   189 /**
       
   190  * Perform some operations before adding data into Todo set
       
   191  * The new and reverse direction is removed from _globset, because we are sure
       
   192  * it doesn't need to be checked again
       
   193  * Also, remove reverse direction from _tbdset
       
   194  * This is the 'core' part so the graph seaching won't enter any tile twice
       
   195  *
       
   196  * @param t1 tile we are entering
       
   197  * @param d1 direction (tile side) we are entering
       
   198  * @param t2 tile we are leaving
       
   199  * @param d2 direction (tile side) we are leaving
       
   200  * @return false iff reverse direction was in Todo set
       
   201  */
       
   202 static inline bool CheckAddToTodoSet(TileIndex t1, DiagDirection d1, TileIndex t2, DiagDirection d2)
       
   203 {
       
   204 	_globset.Remove(t1, d1); // it can be in Global but not in Todo
       
   205 	_globset.Remove(t2, d2); // remove in all cases
       
   206 
       
   207 	assert(!_tbdset.IsIn(t1, d1)); // it really shouldn't be there already
       
   208 
       
   209 	if (_tbdset.Remove(t2, d2)) return false;
       
   210 
       
   211 	return true;
       
   212 }
       
   213 
       
   214 
       
   215 /**
       
   216  * Perform some operations before adding data into Todo set
       
   217  * The new and reverse direction is removed from Global set, because we are sure
       
   218  * it doesn't need to be checked again
       
   219  * Also, remove reverse direction from Todo set
       
   220  * This is the 'core' part so the graph seaching won't enter any tile twice
       
   221  *
       
   222  * @param t1 tile we are entering
       
   223  * @param d1 direction (tile side) we are entering
       
   224  * @param t2 tile we are leaving
       
   225  * @param d2 direction (tile side) we are leaving
       
   226  * @return false iff the Todo buffer would be overrun
       
   227  */
       
   228 static inline bool MaybeAddToTodoSet(TileIndex t1, DiagDirection d1, TileIndex t2, DiagDirection d2)
       
   229 {
       
   230 	if (!CheckAddToTodoSet(t1, d1, t2, d2)) return true;
       
   231 
       
   232 	return _tbdset.Add(t1, d1);
       
   233 }
       
   234 
       
   235 
       
   236 /** Current signal block state flags */
       
   237 enum SigFlags {
       
   238 	SF_NONE   = 0,
       
   239 	SF_TRAIN  = 1 << 0, ///< train found in segment
       
   240 	SF_EXIT   = 1 << 1, ///< exitsignal found
       
   241 	SF_EXIT2  = 1 << 2, ///< two or more exits found
       
   242 	SF_GREEN  = 1 << 3, ///< green exitsignal found
       
   243 	SF_GREEN2 = 1 << 4, ///< two or more green exits found
       
   244 	SF_FULL   = 1 << 5, ///< some of buffers was full, do not continue
       
   245 };
       
   246 
       
   247 DECLARE_ENUM_AS_BIT_SET(SigFlags)
       
   248 
       
   249 
       
   250 /**
       
   251  * Search signal block
       
   252  *
       
   253  * @param owner owner whose signals we are updating
       
   254  * @return SigFlags
       
   255  */
       
   256 static SigFlags ExploreSegment(Owner owner)
       
   257 {
       
   258 	SigFlags flags = SF_NONE;
       
   259 
       
   260 	while (!_tbdset.IsEmpty()) {
       
   261 		TileIndex tile;
       
   262 		DiagDirection enterdir;
       
   263 
       
   264 		_tbdset.Get(&tile, &enterdir);
       
   265 
       
   266 		TileIndex oldtile = tile; // tile we are leaving
       
   267 		DiagDirection exitdir = enterdir == INVALID_DIAGDIR ? INVALID_DIAGDIR : ReverseDiagDir(enterdir); // expected new exit direction (for straight line)
       
   268 
       
   269 		switch (GetTileType(tile)) {
       
   270 			case MP_RAILWAY: {
       
   271 				if (GetTileOwner(tile) != owner) continue; // do not propagate signals on others' tiles (remove for tracksharing)
       
   272 
       
   273 				if (IsRailDepot(tile)) {
       
   274 					if (enterdir == INVALID_DIAGDIR) { // from 'inside' - train just entered or left the depot
       
   275 						if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
       
   276 						exitdir = GetRailDepotDirection(tile);
       
   277 						tile += TileOffsByDiagDir(exitdir);
       
   278 						enterdir = ReverseDiagDir(exitdir);
       
   279 						break;
       
   280 					} else if (enterdir == GetRailDepotDirection(tile)) { // entered a depot
       
   281 						if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
       
   282 						continue;
       
   283 					} else {
       
   284 						continue;
       
   285 					}
       
   286 				}
       
   287 
       
   288 				if (GetRailTileType(tile) == RAIL_TILE_WAYPOINT) {
       
   289 					if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
       
   290 					tile += TileOffsByDiagDir(exitdir);
       
   291 					/* enterdir and exitdir stay the same */
       
   292 					break;
       
   293 				}
       
   294 
       
   295 				TrackBits tracks = GetTrackBits(tile); // trackbits of tile
       
   296 				TrackBits tracks_masked = (TrackBits)(tracks & _enterdir_to_trackbits[enterdir]); // only incidating trackbits
       
   297 
       
   298 				if (tracks == TRACK_BIT_HORZ || tracks == TRACK_BIT_VERT) { // there is exactly one incidating track, no need to check
       
   299 					tracks = tracks_masked;
       
   300 					if (!(flags & SF_TRAIN) && VehicleFromPos(tile, &tracks, &EnsureNoTrainOnTrackProc)) flags |= SF_TRAIN;
       
   301 				} else {
       
   302 					if (tracks_masked == TRACK_BIT_NONE) continue; // no incidating track
       
   303 					if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
       
   304 				}
       
   305 
       
   306 				if (HasSignals(tile)) { // there is exactly one track - not zero, because there is exit from this tile
       
   307 					Track track = TrackBitsToTrack(tracks_masked); // mask TRACK_BIT_X and Y too
       
   308 					if (HasSignalOnTrack(tile, track)) { // now check whole track, not trackdir
       
   309 						SignalType sig = GetSignalType(tile, track);
       
   310 						Trackdir trackdir = (Trackdir)FindFirstBit((tracks * 0x101) & _enterdir_to_trackdirbits[enterdir]);
       
   311 						Trackdir reversedir = ReverseTrackdir(trackdir);
       
   312 						/* add (tile, reversetrackdir) to 'to-be-updated' set when there is
       
   313 						 * ANY signal in REVERSE direction
       
   314 						 * (if it is a presignal EXIT and it changes, it will be added to 'to-be-done' set later) */
       
   315 						if (HasSignalOnTrackdir(tile, reversedir)) {
       
   316 							if (!_tbuset.Add(tile, reversedir)) return flags | SF_FULL;
       
   317 						}
       
   318 						/* if it is a presignal EXIT in OUR direction and we haven't found 2 green exits yes, do special check */
       
   319 						if (!(flags & SF_GREEN2) && (sig & SIGTYPE_EXIT) && HasSignalOnTrackdir(tile, trackdir)) { // found presignal exit
       
   320 							if (flags & SF_EXIT) flags |= SF_EXIT2; // found two (or more) exits
       
   321 							flags |= SF_EXIT; // found at least one exit - allow for compiler optimizations
       
   322 							if (GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_GREEN) { // found green presignal exit
       
   323 								if (flags & SF_GREEN) flags |= SF_GREEN2;
       
   324 								flags |= SF_GREEN;
       
   325 							}
       
   326 						}
       
   327 						continue;
       
   328 					}
       
   329 				}
       
   330 
       
   331 				for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { // test all possible exit directions
       
   332 					if (dir != enterdir && tracks & _enterdir_to_trackbits[dir]) { // any track incidating?
       
   333 						TileIndex newtile = tile + TileOffsByDiagDir(dir);  // new tile to check
       
   334 						DiagDirection newdir = ReverseDiagDir(dir); // direction we are entering from
       
   335 						if (!MaybeAddToTodoSet(newtile, newdir, tile, dir)) return flags | SF_FULL;
       
   336 					}
       
   337 				}
       
   338 
       
   339 				continue; // continue the while() loop
       
   340 				}
       
   341 
       
   342 			case MP_STATION:
       
   343 				if (!IsRailwayStation(tile)) continue;
       
   344 				if (GetTileOwner(tile) != owner) continue;
       
   345 				if (DiagDirToAxis(enterdir) != GetRailStationAxis(tile)) continue; // different axis
       
   346 				if (IsStationTileBlocked(tile)) continue; // 'eye-candy' station tile
       
   347 
       
   348 				if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
       
   349 				tile += TileOffsByDiagDir(exitdir);
       
   350 				break;
       
   351 
       
   352 			case MP_ROAD:
       
   353 				if (!IsLevelCrossing(tile)) continue;
       
   354 				if (GetTileOwner(tile) != owner) continue;
       
   355 				if (DiagDirToAxis(enterdir) == GetCrossingRoadAxis(tile)) continue; // different axis
       
   356 
       
   357 				if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
       
   358 				tile += TileOffsByDiagDir(exitdir);
       
   359 				break;
       
   360 
       
   361 			case MP_TUNNELBRIDGE: {
       
   362 				if (GetTileOwner(tile) != owner) continue;
       
   363 				if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
       
   364 				DiagDirection dir = GetTunnelBridgeDirection(tile);
       
   365 
       
   366 				if (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole
       
   367 					if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
       
   368 					enterdir = dir;
       
   369 					exitdir = ReverseDiagDir(dir);
       
   370 					tile += TileOffsByDiagDir(exitdir); // just skip to next tile
       
   371 				} else { // NOT incoming from the wormhole!
       
   372 					if (ReverseDiagDir(enterdir) != dir) continue;
       
   373 					if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
       
   374 					tile = GetOtherTunnelBridgeEnd(tile); // just skip to exit tile
       
   375 					enterdir = INVALID_DIAGDIR;
       
   376 					exitdir = INVALID_DIAGDIR;
       
   377 				}
       
   378 				}
       
   379 				break;
       
   380 
       
   381 			default:
       
   382 				continue; // continue the while() loop
       
   383 		}
       
   384 
       
   385 		if (!MaybeAddToTodoSet(tile, enterdir, oldtile, exitdir)) return flags | SF_FULL;
       
   386 	}
       
   387 
       
   388 	return flags;
       
   389 }
       
   390 
       
   391 
       
   392 /**
       
   393  * Update signals around segment in _tbuset
       
   394  *
       
   395  * @param flags info about segment
       
   396  */
       
   397 static void UpdateSignalsAroundSegment(SigFlags flags)
       
   398 {
       
   399 	while (!_tbuset.IsEmpty()) {
       
   400 		TileIndex tile;
       
   401 		Trackdir trackdir;
       
   402 		_tbuset.Get(&tile, &trackdir);
       
   403 
       
   404 		assert(HasSignalOnTrackdir(tile, trackdir));
       
   405 
       
   406 		SignalType sig = GetSignalType(tile, TrackdirToTrack(trackdir));
       
   407 		SignalState newstate = SIGNAL_STATE_GREEN;
       
   408 
       
   409 		/* determine whether the new state is red */
       
   410 		if (flags & SF_TRAIN) {
       
   411 			/* train in the segment */
       
   412 			newstate = SIGNAL_STATE_RED;
       
   413 		} else {
       
   414  			/* is it a bidir combo? - then do not count its other signal direction as exit */
       
   415 			if (sig == SIGTYPE_COMBO && HasSignalOnTrackdir(tile, ReverseTrackdir(trackdir))) {
       
   416 				/* at least one more exit */
       
   417 				if (flags & SF_EXIT2 &&
       
   418  						/* no green exit */
       
   419 						(!(flags & SF_GREEN) ||
       
   420 						/* only one green exit, and it is this one - so all other exits are red */
       
   421 						(!(flags & SF_GREEN2) && GetSignalStateByTrackdir(tile, ReverseTrackdir(trackdir)) == SIGNAL_STATE_GREEN))) {
       
   422 					newstate = SIGNAL_STATE_RED;
       
   423 				}
       
   424 			} else { // entry, at least one exit, no green exit
       
   425 				if (sig & SIGTYPE_ENTRY && (flags & SF_EXIT && !(flags & SF_GREEN))) newstate = SIGNAL_STATE_RED;
       
   426 			}
       
   427 		}
       
   428 
       
   429 		/* only when the state changes */
       
   430 		if (newstate != GetSignalStateByTrackdir(tile, trackdir)) {
       
   431 			if (sig & SIGTYPE_EXIT) {
       
   432 				/* for pre-signal exits, add block to the global set */
       
   433 				DiagDirection exitdir = TrackdirToExitdir(ReverseTrackdir(trackdir));
       
   434 				_globset.Add(tile, exitdir); // do not check for full global set, first update all signals
       
   435 			}
       
   436 			SetSignalStateByTrackdir(tile, trackdir, newstate);
       
   437 			MarkTileDirtyByTile(tile);
       
   438 		}
       
   439 	}
       
   440 
       
   441 }
       
   442 
       
   443 
       
   444 /** Reset all sets after one set overflowed */
       
   445 static inline void ResetSets()
       
   446 {
       
   447 	_tbuset.Reset();
       
   448 	_tbdset.Reset();
       
   449 	_globset.Reset();
       
   450 }
       
   451 
       
   452 
       
   453 /**
       
   454  * Updates blocks in _globset buffer
       
   455  *
       
   456  * @return false iff presignal entry would be green (needed for trains leaving depot)
       
   457  */
       
   458 static bool UpdateSignalsInBuffer()
       
   459 {
       
   460 	bool first = true;  // first block?
       
   461 	bool state = false; // value to return
       
   462 
       
   463 	Owner owner = OWNER_NONE; // owner whose signals we are updating
       
   464 
       
   465 	while (!_globset.IsEmpty()) {
       
   466 		assert(_tbuset.IsEmpty());
       
   467 		assert(_tbdset.IsEmpty());
       
   468 
       
   469 		TileIndex tile;
       
   470 		DiagDirection dir;
       
   471 
       
   472 		_globset.Get(&tile, &dir);
       
   473 
       
   474 		/* After updating signal, data stored are always MP_RAILWAY with signals.
       
   475 		 * Other situations happen when data are from outside functions -
       
   476 		 * modification of railbits (including both rail building and removal),
       
   477 		 * train entering/leaving block, train leaving depot...
       
   478 		 */
       
   479 		switch (GetTileType(tile)) {
       
   480 			case MP_TUNNELBRIDGE:
       
   481 				/* 'optimization assert' - do not try to update signals when it is not needed */
       
   482 				assert(GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL);
       
   483 				assert(dir == INVALID_DIAGDIR || dir == ReverseDiagDir(GetTunnelBridgeDirection(tile)));
       
   484 				if (first) owner = GetTileOwner(tile);
       
   485 				_tbdset.Add(tile, INVALID_DIAGDIR);  // we can safely start from wormhole centre
       
   486 				_tbdset.Add(GetOtherTunnelBridgeEnd(tile), INVALID_DIAGDIR);
       
   487 				break;
       
   488 
       
   489 			case MP_RAILWAY:
       
   490 				if (IsRailDepot(tile)) {
       
   491 					/* 'optimization assert' do not try to update signals in other cases */
       
   492 					assert(dir == INVALID_DIAGDIR || dir == GetRailDepotDirection(tile));
       
   493 					if (first) owner = GetTileOwner(tile);
       
   494 					_tbdset.Add(tile, INVALID_DIAGDIR); // start from depot inside
       
   495 					break;
       
   496 				}
       
   497 				/* FALLTHROUGH */
       
   498 			case MP_STATION:
       
   499 			case MP_ROAD:
       
   500 				if ((TrackBits)(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & _enterdir_to_trackbits[dir]) != TRACK_BIT_NONE) {
       
   501  					/* only add to set when there is some 'interesting' track */
       
   502 					if (first) owner = GetTileOwner(tile);
       
   503 					_tbdset.Add(tile, dir);
       
   504 					_tbdset.Add(tile + TileOffsByDiagDir(dir), ReverseDiagDir(dir));
       
   505 					break;
       
   506 				}
       
   507 				/* FALLTHROUGH */
       
   508 			default:
       
   509 				/* jump to next tile */
       
   510 				tile = tile + TileOffsByDiagDir(dir);
       
   511 				dir = ReverseDiagDir(dir);
       
   512 				if ((TrackBits)(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & _enterdir_to_trackbits[dir]) != TRACK_BIT_NONE) {
       
   513 					if (first) owner = GetTileOwner(tile);
       
   514 					_tbdset.Add(tile, dir);
       
   515 					break;
       
   516 				}
       
   517 				/* happens when removing a rail that wasn't connected at one or both sides */
       
   518 				continue; // continue the while() loop
       
   519 		}
       
   520 
       
   521 		assert(IsValidPlayer(owner));
       
   522 		assert(!_tbdset.Overflowed()); // it really shouldn't overflow by these one or two items
       
   523 		assert(!_tbdset.IsEmpty()); // it wouldn't hurt anyone, but shouldn't happen too
       
   524 
       
   525 		SigFlags flags = ExploreSegment(owner);
       
   526 
       
   527 		if (first) {
       
   528 			first = false;
       
   529 			state = (flags & SF_TRAIN) || (flags & SF_EXIT && !(flags & SF_GREEN)) || (flags & SF_FULL); // true iff train CAN'T leave the depot
       
   530 		}
       
   531 
       
   532 		/* do not do anything when some buffer was full */
       
   533 		if (flags & SF_FULL) break;
       
   534 
       
   535 		UpdateSignalsAroundSegment(flags);
       
   536 	}
       
   537 
       
   538 	return state;
       
   539 }
       
   540 
       
   541 
       
   542 /**
       
   543  * Update signals, starting at one side of a tile
       
   544  * Will check tile next to this at opposite side too
       
   545  *
       
   546  * @see UpdateSignalsInBuffer()
       
   547  * @param tile tile where we start
       
   548  * @param side side of tile
       
   549  * @return false iff train can leave depot
       
   550  */
       
   551 bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection side)
       
   552 {
       
   553 	assert(_globset.IsEmpty());
       
   554 	_globset.Add(tile, side);
       
   555 
       
   556 	return UpdateSignalsInBuffer();
       
   557 }
       
   558 
       
   559 
       
   560 /**
       
   561  * Update signals at segments that are at both ends of
       
   562  * given (existent or non-existent) track
       
   563  *
       
   564  * @see UpdateSignalsInBuffer()
       
   565  * @param tile tile where we start
       
   566  * @param track track at which ends we will update signals
       
   567  */
       
   568 void SetSignalsOnBothDir(TileIndex tile, Track track)
       
   569 {
       
   570 	static const DiagDirection _search_dir_1[] = {
       
   571 		DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE
       
   572 	};
       
   573 	static const DiagDirection _search_dir_2[] = {
       
   574 		DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE
       
   575 	};
       
   576 
       
   577 	assert(_globset.IsEmpty());
       
   578 
       
   579 	_globset.Add(tile, _search_dir_1[track]);
       
   580 	_globset.Add(tile, _search_dir_2[track]);
       
   581 	UpdateSignalsInBuffer();
       
   582 }