Initial support for one-way side road junctions

pull/203/head
Jonathan G Rennison 4 years ago
parent 569d715cfc
commit 750417af10

@ -2265,6 +2265,9 @@ static TrackStatus GetTileTrackStatus_Road(TileIndex tile, TransportType mode, u
uint multiplier = drd_to_multiplier[(rtt == RTT_TRAM) ? DRD_NONE : GetDisallowedRoadDirections(tile)];
if (!HasRoadWorks(tile)) trackdirbits = (TrackdirBits)(_road_trackbits[bits] * multiplier);
extern TrackdirBits MaskOneWaySideJunctionRoad(TileIndex tile, RoadBits bits);
if (rtt == RTT_ROAD && HasExactlyOneBit(bits ^ ROAD_ALL)) trackdirbits &= MaskOneWaySideJunctionRoad(tile, bits);
break;
}

@ -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

Loading…
Cancel
Save