Initial support for one-way side road junctions
This commit is contained in:
@@ -373,9 +373,78 @@ bool RoadVehicle::FindClosestDepot(TileIndex *location, DestinationID *destinati
|
||||
return true;
|
||||
}
|
||||
|
||||
static DisallowedRoadDirections GetOneWayRoadTileDisallowedRoadDirections(TileIndex tile)
|
||||
{
|
||||
if (IsNormalRoadTile(tile)) return GetDisallowedRoadDirections(tile);
|
||||
if (IsDriveThroughStopTile(tile)) return GetDriveThroughStopDisallowedRoadDirections(tile);
|
||||
return DRD_NONE;
|
||||
}
|
||||
|
||||
static DiagDirection OneWaySideJunctionRoadRoadBitsToDiagDir(RoadBits bits)
|
||||
{
|
||||
/*
|
||||
* Drive on left missing bit:
|
||||
* ROAD_SE (bit 2) -> DIAGDIR_NE (0)
|
||||
* ROAD_SW (bit 1) -> DIAGDIR_SE (1)
|
||||
* ROAD_NW (bit 0) -> DIAGDIR_SW (2)
|
||||
* ROAD_NE (bit 3) -> DIAGDIR_NW (3)
|
||||
*/
|
||||
uint8 bit = FIND_FIRST_BIT(bits ^ ROAD_ALL);
|
||||
bit ^= 3;
|
||||
return (DiagDirection)((bit + 3 + (_settings_game.vehicle.road_side * 2)) % 4);
|
||||
}
|
||||
|
||||
inline bool IsOneWaySideJunctionRoadDRDsPresent(TileIndex tile, DiagDirection dir)
|
||||
{
|
||||
const DisallowedRoadDirections diagdir_to_drd[DIAGDIR_END] = { DRD_NORTHBOUND, DRD_NORTHBOUND, DRD_SOUTHBOUND, DRD_SOUTHBOUND };
|
||||
|
||||
TileIndexDiffC ti = TileIndexDiffCByDiagDir(dir);
|
||||
TileIndex ahead = AddTileIndexDiffCWrap(tile, ti);
|
||||
if (ahead == INVALID_TILE || GetOneWayRoadTileDisallowedRoadDirections(ahead) != diagdir_to_drd[dir]) return false;
|
||||
TileIndex behind = AddTileIndexDiffCWrap(tile, { (int16)(-ti.x), (int16)(-ti.y) });
|
||||
if (behind == INVALID_TILE || GetOneWayRoadTileDisallowedRoadDirections(behind) != diagdir_to_drd[dir]) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsOneWaySideJunctionRoad(TileIndex tile)
|
||||
{
|
||||
RoadBits bits = GetRoadBits(tile, RTT_ROAD);
|
||||
if (!HasExactlyOneBit(bits ^ ROAD_ALL)) return false;
|
||||
DiagDirection dir = OneWaySideJunctionRoadRoadBitsToDiagDir(bits);
|
||||
return IsOneWaySideJunctionRoadDRDsPresent(tile, dir);
|
||||
}
|
||||
|
||||
TrackdirBits MaskOneWaySideJunctionRoad(TileIndex tile, RoadBits bits)
|
||||
{
|
||||
DiagDirection dir = OneWaySideJunctionRoadRoadBitsToDiagDir(bits);
|
||||
if (!IsOneWaySideJunctionRoadDRDsPresent(tile, dir)) return ~TRACKDIR_BIT_NONE;
|
||||
|
||||
const TrackdirBits left_turns = TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_RIGHT_S;
|
||||
const TrackdirBits right_turns = TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_RIGHT_N;
|
||||
TrackdirBits remove = (_settings_game.vehicle.road_side ? left_turns : right_turns);
|
||||
|
||||
DiagDirection side_dir = (DiagDirection)((dir + 3 + (_settings_game.vehicle.road_side * 2)) % 4);
|
||||
TileIndexDiffC ti = TileIndexDiffCByDiagDir(side_dir);
|
||||
TileIndex side = AddTileIndexDiffCWrap(tile, ti);
|
||||
|
||||
const DisallowedRoadDirections diagdir_to_drd[DIAGDIR_END] = { DRD_SOUTHBOUND, DRD_SOUTHBOUND, DRD_NORTHBOUND, DRD_NORTHBOUND };
|
||||
const TrackdirBits remove_side_trackdirs[] = {
|
||||
TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_UPPER_E, // DIAGDIR_NE
|
||||
TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_E, // DIAGDIR_SE
|
||||
TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_LOWER_W, // DIAGDIR_SW
|
||||
TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_UPPER_W // DIAGDIR_NW
|
||||
};
|
||||
if (side != INVALID_TILE && GetOneWayRoadTileDisallowedRoadDirections(side) & diagdir_to_drd[side_dir]) remove |= remove_side_trackdirs[side_dir];
|
||||
|
||||
return ~remove;
|
||||
}
|
||||
|
||||
static bool IsOneWayRoadTile(TileIndex tile)
|
||||
{
|
||||
if (IsNormalRoadTile(tile) && GetDisallowedRoadDirections(tile) != DRD_NONE) return true;
|
||||
if (IsNormalRoadTile(tile)) {
|
||||
if (GetDisallowedRoadDirections(tile) != DRD_NONE) return true;
|
||||
if (IsOneWaySideJunctionRoad(tile)) return true;
|
||||
}
|
||||
if (IsDriveThroughStopTile(tile) && GetDriveThroughStopDisallowedRoadDirections(tile) != DRD_NONE) return true;
|
||||
return false;
|
||||
}
|
||||
@@ -863,8 +932,20 @@ static bool CheckRoadInfraUnsuitableForOvertaking(OvertakeData *od)
|
||||
TrackdirBits red_signals = TrackStatusToRedSignals(ts); // barred level crossing
|
||||
TrackBits trackbits = TrackdirBitsToTrackBits(trackdirbits);
|
||||
|
||||
/* Track does not continue along overtaking direction || track has junction || levelcrossing is barred */
|
||||
if (!HasBit(trackdirbits, od->trackdir) || (trackbits & ~TRACK_BIT_CROSS) || (red_signals != TRACKDIR_BIT_NONE)) return true;
|
||||
/* Track does not continue along overtaking direction || levelcrossing is barred */
|
||||
if (!HasBit(trackdirbits, od->trackdir) || (red_signals != TRACKDIR_BIT_NONE)) return true;
|
||||
/* Track has junction */
|
||||
if (trackbits & ~TRACK_BIT_CROSS) {
|
||||
if (IsNormalRoadTile(od->tile) && IsOneWaySideJunctionRoad(od->tile)) {
|
||||
const RoadVehPathCache &pc = od->v->path;
|
||||
if (!pc.empty() && pc.tile.front() == od->tile && !IsStraightRoadTrackdir(pc.td.front())) {
|
||||
/* cached path indicates that we are turning here, do not overtake */
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1404,6 +1485,9 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
|
||||
} else if (v->HasArticulatedPart() && IsBridgeTile(v->tile) && (IsRoadCustomBridgeHeadTile(v->tile) || IsRoadCustomBridgeHeadTile(GetOtherBridgeEnd(v->tile)))) {
|
||||
/* Articulated RVs may not overtake on custom bridge heads */
|
||||
v->SetRoadVehicleOvertaking(0);
|
||||
} else if (v->state < RVSB_IN_ROAD_STOP && !IsStraightRoadTrackdir((Trackdir)v->state) && IsOneWaySideJunctionRoad(v->tile)) {
|
||||
/* No turning to/from overtaking lane on one way side road junctions */
|
||||
v->SetRoadVehicleOvertaking(0);
|
||||
} else if (++v->overtaking_ctr >= RV_OVERTAKE_TIMEOUT) {
|
||||
/* If overtaking just aborts at a random moment, we can have a out-of-bound problem,
|
||||
* if the vehicle started a corner. To protect that, only allow an abort of
|
||||
|
Reference in New Issue
Block a user