Feature: Multi-track level crossings (#9931)
This commit is contained in:
@@ -1674,29 +1674,88 @@ static bool TrainApproachingCrossing(TileIndex tile)
|
||||
return HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a level crossing should be barred.
|
||||
* @param tile The tile to check.
|
||||
* @return True if the crossing should be barred, else false.
|
||||
*/
|
||||
static inline bool CheckLevelCrossing(TileIndex tile)
|
||||
{
|
||||
/* reserved || train on crossing || train approaching crossing */
|
||||
return HasCrossingReservation(tile) || HasVehicleOnPos(tile, NULL, &TrainOnTileEnum) || TrainApproachingCrossing(tile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets correct crossing state
|
||||
* @param tile tile to update
|
||||
* @param sound should we play sound?
|
||||
* @pre tile is a rail-road crossing
|
||||
* Sets a level crossing tile to the correct state.
|
||||
* @param tile Tile to update.
|
||||
* @param sound Should we play sound?
|
||||
* @param force_barred Should we set the crossing to barred?
|
||||
* @pre tile is a rail-road crossing.
|
||||
*/
|
||||
void UpdateLevelCrossing(TileIndex tile, bool sound)
|
||||
static void UpdateLevelCrossingTile(TileIndex tile, bool sound, bool force_barred)
|
||||
{
|
||||
assert(IsLevelCrossingTile(tile));
|
||||
bool set_barred;
|
||||
|
||||
/* reserved || train on crossing || train approaching crossing */
|
||||
bool new_state = HasCrossingReservation(tile) || HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum) || TrainApproachingCrossing(tile);
|
||||
/* We force the crossing to be barred when an adjacent crossing is barred, otherwise let it decide for itself. */
|
||||
set_barred = force_barred || CheckLevelCrossing(tile);
|
||||
|
||||
if (new_state != IsCrossingBarred(tile)) {
|
||||
if (new_state && sound) {
|
||||
if (_settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
|
||||
}
|
||||
SetCrossingBarred(tile, new_state);
|
||||
/* The state has changed */
|
||||
if (set_barred != IsCrossingBarred(tile)) {
|
||||
if (set_barred && sound && _settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
|
||||
SetCrossingBarred(tile, set_barred);
|
||||
MarkTileDirtyByTile(tile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a level crossing to barred or open (crossing may include multiple adjacent tiles).
|
||||
* @param tile Tile which causes the update.
|
||||
* @param sound Should we play sound?
|
||||
* @param force_bar Should we force the crossing to be barred?
|
||||
*/
|
||||
void UpdateLevelCrossing(TileIndex tile, bool sound, bool force_bar)
|
||||
{
|
||||
if (!IsLevelCrossingTile(tile)) return;
|
||||
|
||||
bool forced_state = force_bar;
|
||||
|
||||
const Axis axis = GetCrossingRoadAxis(tile);
|
||||
const DiagDirection dir1 = AxisToDiagDir(axis);
|
||||
const DiagDirection dir2 = ReverseDiagDir(dir1);
|
||||
|
||||
/* Check if an adjacent crossing is barred. */
|
||||
for (DiagDirection dir : { dir1, dir2 }) {
|
||||
for (TileIndex t = tile; !forced_state && t < MapSize() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == axis; t = TileAddByDiagDir(t, dir)) {
|
||||
forced_state |= CheckLevelCrossing(t);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now that we know whether all tiles in this crossing should be barred or open,
|
||||
* we need to update those tiles. We start with the tile itself, then look along the road axis. */
|
||||
UpdateLevelCrossingTile(tile, sound, forced_state);
|
||||
for (DiagDirection dir : { dir1, dir2 }) {
|
||||
for (TileIndex t = TileAddByDiagDir(tile, dir); t < MapSize() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == axis; t = TileAddByDiagDir(t, dir)) {
|
||||
UpdateLevelCrossingTile(t, sound, forced_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find adjacent level crossing tiles in this multi-track crossing and mark them dirty.
|
||||
* @param The tile which causes the update.
|
||||
*/
|
||||
void MarkDirtyAdjacentLevelCrossingTiles(TileIndex tile, Axis road_axis)
|
||||
{
|
||||
const DiagDirection dir1 = AxisToDiagDir(road_axis);
|
||||
const DiagDirection dir2 = ReverseDiagDir(dir1);
|
||||
for (DiagDirection dir : { dir1, dir2 }) {
|
||||
const TileIndex t = TileAddByDiagDir(tile, dir);
|
||||
if (t < MapSize() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == road_axis) {
|
||||
MarkTileDirtyByTile(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bars crossing and plays ding-ding sound if not barred already
|
||||
@@ -1706,9 +1765,8 @@ void UpdateLevelCrossing(TileIndex tile, bool sound)
|
||||
static inline void MaybeBarCrossingWithSound(TileIndex tile)
|
||||
{
|
||||
if (!IsCrossingBarred(tile)) {
|
||||
BarCrossing(tile);
|
||||
if (_settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
|
||||
MarkTileDirtyByTile(tile);
|
||||
SetCrossingReservation(tile, true);
|
||||
UpdateLevelCrossing(tile, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user