Feature: Multi-track level crossings (#9931)

This commit is contained in:
Tyler Trahan
2022-11-01 14:51:23 -06:00
committed by GitHub
parent c65a2799c9
commit c19abebf8d
10 changed files with 217 additions and 22 deletions

View File

@@ -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);
}
}