示例#1
0
/* static */ ScriptRail::SignalType ScriptRail::GetSignalType(TileIndex tile, TileIndex front)
{
	if (ScriptMap::DistanceManhattan(tile, front) != 1) return SIGNALTYPE_NONE;
	if (!::IsTileType(tile, MP_RAILWAY) || !::HasSignals(tile)) return SIGNALTYPE_NONE;

	int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile));

	for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) {
		const Track &track = _possible_trackdirs[data_index][i].track;
		if (!(::TrackToTrackBits(track) & GetRailTracks(tile))) continue;
		if (!HasSignalOnTrack(tile, track)) continue;
		if (!HasSignalOnTrackdir(tile, _possible_trackdirs[data_index][i].trackdir)) continue;
		SignalType st = (SignalType)::GetSignalType(tile, track);
		if (HasSignalOnTrackdir(tile, ::ReverseTrackdir(_possible_trackdirs[data_index][i].trackdir))) st = (SignalType)(st | SIGNALTYPE_TWOWAY);
		return st;
	}

	return SIGNALTYPE_NONE;
}
/**
 * Search signal block
 *
 * @param owner owner whose signals we are updating
 * @return SigFlags
 */
static SigFlags ExploreSegment(Owner owner)
{
	SigFlags flags = SF_NONE;

	TileIndex tile;
	DiagDirection enterdir;

	while (_tbdset.Get(&tile, &enterdir)) {
		TileIndex oldtile = tile; // tile we are leaving
		DiagDirection exitdir = enterdir == INVALID_DIAGDIR ? INVALID_DIAGDIR : ReverseDiagDir(enterdir); // expected new exit direction (for straight line)

		switch (GetTileType(tile)) {
			case MP_RAILWAY: {
				if (GetTileOwner(tile) != owner) continue; // do not propagate signals on others' tiles (remove for tracksharing)

				if (IsRailDepot(tile)) {
					if (enterdir == INVALID_DIAGDIR) { // from 'inside' - train just entered or left the depot
						if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
						exitdir = GetRailDepotDirection(tile);
						tile += TileOffsByDiagDir(exitdir);
						enterdir = ReverseDiagDir(exitdir);
						break;
					} else if (enterdir == GetRailDepotDirection(tile)) { // entered a depot
						if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
						continue;
					} else {
						continue;
					}
				}

				TrackBits tracks = GetTrackBits(tile); // trackbits of tile
				TrackBits tracks_masked = (TrackBits)(tracks & _enterdir_to_trackbits[enterdir]); // only incidating trackbits

				if (tracks == TRACK_BIT_HORZ || tracks == TRACK_BIT_VERT) { // there is exactly one incidating track, no need to check
					tracks = tracks_masked;
					/* If no train detected yet, and there is not no train -> there is a train -> set the flag */
					if (!(flags & SF_TRAIN) && EnsureNoTrainOnTrackBits(tile, tracks).Failed()) flags |= SF_TRAIN;
				} else {
					if (tracks_masked == TRACK_BIT_NONE) continue; // no incidating track
					if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
				}

				if (HasSignals(tile)) { // there is exactly one track - not zero, because there is exit from this tile
					Track track = TrackBitsToTrack(tracks_masked); // mask TRACK_BIT_X and Y too
					if (HasSignalOnTrack(tile, track)) { // now check whole track, not trackdir
						SignalType sig = GetSignalType(tile, track);
						Trackdir trackdir = (Trackdir)FindFirstBit((tracks * 0x101) & _enterdir_to_trackdirbits[enterdir]);
						Trackdir reversedir = ReverseTrackdir(trackdir);
						/* add (tile, reversetrackdir) to 'to-be-updated' set when there is
						 * ANY conventional signal in REVERSE direction
						 * (if it is a presignal EXIT and it changes, it will be added to 'to-be-done' set later) */
						if (HasSignalOnTrackdir(tile, reversedir)) {
							if (IsPbsSignal(sig)) {
								flags |= SF_PBS;
							} else if (!_tbuset.Add(tile, reversedir)) {
								return flags | SF_FULL;
							}
						}
						if (HasSignalOnTrackdir(tile, trackdir) && !IsOnewaySignal(tile, track)) flags |= SF_PBS;

						/* if it is a presignal EXIT in OUR direction and we haven't found 2 green exits yes, do special check */
						if (!(flags & SF_GREEN2) && IsPresignalExit(tile, track) && HasSignalOnTrackdir(tile, trackdir)) { // found presignal exit
							if (flags & SF_EXIT) flags |= SF_EXIT2; // found two (or more) exits
							flags |= SF_EXIT; // found at least one exit - allow for compiler optimizations
							if (GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_GREEN) { // found green presignal exit
								if (flags & SF_GREEN) flags |= SF_GREEN2;
								flags |= SF_GREEN;
							}
						}

						continue;
					}
				}

				for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { // test all possible exit directions
					if (dir != enterdir && (tracks & _enterdir_to_trackbits[dir])) { // any track incidating?
						TileIndex newtile = tile + TileOffsByDiagDir(dir);  // new tile to check
						DiagDirection newdir = ReverseDiagDir(dir); // direction we are entering from
						if (!MaybeAddToTodoSet(newtile, newdir, tile, dir)) return flags | SF_FULL;
					}
				}

				continue; // continue the while() loop
				}

			case MP_STATION:
				if (!HasStationRail(tile)) continue;
				if (GetTileOwner(tile) != owner) continue;
				if (DiagDirToAxis(enterdir) != GetRailStationAxis(tile)) continue; // different axis
				if (IsStationTileBlocked(tile)) continue; // 'eye-candy' station tile

				if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
				tile += TileOffsByDiagDir(exitdir);
				break;

			case MP_ROAD:
				if (!IsLevelCrossing(tile)) continue;
				if (GetTileOwner(tile) != owner) continue;
				if (DiagDirToAxis(enterdir) == GetCrossingRoadAxis(tile)) continue; // different axis

				if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
				tile += TileOffsByDiagDir(exitdir);
				break;

			case MP_TUNNELBRIDGE: {
				if (GetTileOwner(tile) != owner) continue;
				if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
				DiagDirection dir = GetTunnelBridgeDirection(tile);

				if (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole
					if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
					enterdir = dir;
					exitdir = ReverseDiagDir(dir);
					tile += TileOffsByDiagDir(exitdir); // just skip to next tile
				} else { // NOT incoming from the wormhole!
					if (ReverseDiagDir(enterdir) != dir) continue;
					if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
					tile = GetOtherTunnelBridgeEnd(tile); // just skip to exit tile
					enterdir = INVALID_DIAGDIR;
					exitdir = INVALID_DIAGDIR;
				}
				}
				break;

			default:
				continue; // continue the while() loop
		}

		if (!MaybeAddToTodoSet(tile, enterdir, oldtile, exitdir)) return flags | SF_FULL;
	}

	return flags;
}