Add road/tram type flag to disallow collisions with trains

pull/491/head
Jonathan G Rennison 1 year ago
parent 663a3969a0
commit f7d62a1767

@ -177,6 +177,8 @@
<dd>Towns may not modify tiles of this roadtype in any way whatsoever</dd>
<dt>NO_TUNNELS</dt>
<dd>Disallow tunnels for this roadtype</dd>
<dt>NO_TRAIN_COLLISION</dt>
<dd>Disallow collisions with trains for vehicles of this roadtype</dd>
</dl>
</td>
</tr>
@ -206,6 +208,8 @@
<dd>Towns may not modify tiles of this tramtype in any way whatsoever</dd>
<dt>NO_TUNNELS</dt>
<dd>Disallow tunnels for this tramtype</dd>
<dt>NO_TRAIN_COLLISION</dt>
<dd>Disallow collisions with trains for vehicles of this tramtype</dd>
</dl>
</td>
</tr>

@ -329,6 +329,8 @@
<tr><td>1</td><td>2</td><td>Towns may not modify tiles of this road/tram type in any way whatsoever</td></tr>
<tr><td>2</td><td>4</td><td>Disallow tunnels for this road/tram type<br />
Support for this bit is indicated by the feature name: <font face="monospace">action0_roadtype_extra_flags</font>, version 2.</td></tr>
<tr><td>3</td><td>8</td><td>Disallow collisions with trains for vehicles of this road/tram type<br />
Support for this bit is indicated by the feature name: <font face="monospace">action0_roadtype_extra_flags</font>, version 2.</td></tr>
</table>
</p>
<p>This is indicated by the feature name: <font face="monospace">action0_roadtype_extra_flags</font>, version 1</p>

@ -56,6 +56,7 @@ enum RoadTypeExtraFlags {
RXTF_NOT_AVAILABLE_AI_GS = 0, ///< Bit number for unavailable for AI/GS
RXTF_NO_TOWN_MODIFICATION, ///< Bit number for no town modification
RXTF_NO_TUNNELS, ///< Bit number for no tunnels
RXTF_NO_TRAIN_COLLISION, ///< Bit number for no train collision
RXTFB_NONE = 0, ///< All flags cleared.
};
@ -346,5 +347,6 @@ bool HasAnyRoadTypesAvail(CompanyID company, RoadTramType rtt);
extern std::vector<RoadType> _sorted_roadtypes;
extern RoadTypes _roadtypes_hidden_mask;
extern std::array<RoadTypes, RTCM_END> _collision_mode_roadtypes;
extern RoadTypes _roadtypes_non_train_colliding;
#endif /* ROAD_H */

@ -52,6 +52,7 @@ RoadTypeInfo _roadtypes[ROADTYPE_END];
std::vector<RoadType> _sorted_roadtypes;
RoadTypes _roadtypes_hidden_mask;
std::array<RoadTypes, RTCM_END> _collision_mode_roadtypes;
RoadTypes _roadtypes_non_train_colliding;
/**
* Bitmap of road/tram types.
@ -138,10 +139,12 @@ void InitRoadTypes()
void InitRoadTypesCaches()
{
std::fill(_collision_mode_roadtypes.begin(), _collision_mode_roadtypes.end(), ROADTYPES_NONE);
_roadtypes_non_train_colliding = ROADTYPES_NONE;
for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
const RoadTypeInfo &rti = _roadtypes[rt];
SetBit(_collision_mode_roadtypes[rti.collision_mode], rt);
if (HasBit(rti.extra_flags, RXTF_NO_TRAIN_COLLISION)) SetBit(_roadtypes_non_train_colliding, rt);
}
}
@ -2300,15 +2303,22 @@ static void DrawTile_Road(TileInfo *ti, DrawTileProcParams params)
SpriteID rail = GetCustomRailSprite(rti, ti->tile, RTSG_CROSSING) + axis;
DrawGroundSprite(rail, pal);
auto is_usable_crossing = [&](TileIndex t) -> bool {
if (HasRoadTypeRoad(t) && !HasBit(_roadtypes_non_train_colliding, GetRoadTypeRoad(t))) return true;
if (HasRoadTypeTram(t) && !HasBit(_roadtypes_non_train_colliding, GetRoadTypeTram(t))) return true;
return false;
};
if (_settings_game.vehicle.adjacent_crossings) {
if (!is_usable_crossing(ti->tile)) {
/* Do not draw crossing overlays */
} else if (_settings_game.vehicle.adjacent_crossings) {
const Axis axis = GetCrossingRoadAxis(ti->tile);
const DiagDirection dir1 = AxisToDiagDir(axis);
const DiagDirection dir2 = ReverseDiagDir(dir1);
uint adjacent_diagdirs = 0;
for (DiagDirection dir : { dir1, dir2 }) {
const TileIndex t = TileAddByDiagDir(ti->tile, dir);
if (t < MapSize() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == axis) {
if (t < MapSize() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == axis && is_usable_crossing(t)) {
SetBit(adjacent_diagdirs, dir);
}
}
@ -2656,7 +2666,7 @@ static TrackStatus GetTileTrackStatus_Road(TileIndex tile, TransportType mode, u
break;
case TRANSPORT_ROAD: {
RoadTramType rtt = (RoadTramType)sub_mode;
RoadTramType rtt = (RoadTramType)GB(sub_mode, 0, 8);
if (!HasTileRoadType(tile, rtt)) break;
switch (GetRoadTileType(tile)) {
case ROAD_TILE_NORMAL: {
@ -2704,7 +2714,13 @@ static TrackStatus GetTileTrackStatus_Road(TileIndex tile, TransportType mode, u
if (side != INVALID_DIAGDIR && axis != DiagDirToAxis(side)) break;
trackdirbits = TrackBitsToTrackdirBits(AxisToTrackBits(axis));
if (IsCrossingBarred(tile)) {
auto is_non_colliding = [&]() -> bool {
uint8 rtfield = GB(sub_mode, 8, 8);
if (rtfield == 0) return false;
RoadType rt = (RoadType)(rtfield - 1);
return HasBit(_roadtypes_non_train_colliding, rt);
};
if (IsCrossingBarred(tile) && !is_non_colliding()) {
red_signals = trackdirbits;
auto mask_red_signal_bits_if_crossing_barred = [&](TileIndex t, TrackdirBits mask) {
if (IsLevelCrossingTile(t) && IsCrossingBarred(t)) red_signals &= mask;

@ -155,6 +155,7 @@ struct RoadVehicle FINAL : public GroundVehicle<RoadVehicle, VEH_ROAD> {
inline bool IsRoadVehicleOnLevelCrossing() const
{
if (HasBit(_roadtypes_non_train_colliding, this->roadtype)) return false;
for (const RoadVehicle *u = this; u != nullptr; u = u->Next()) {
if (IsLevelCrossingTile(u->tile)) return true;
}

@ -631,6 +631,8 @@ static void RoadVehCrash(RoadVehicle *v)
static bool RoadVehCheckTrainCrash(RoadVehicle *v)
{
if (HasBit(_roadtypes_non_train_colliding, v->roadtype)) return false;
for (RoadVehicle *u = v; u != nullptr; u = u->Next()) {
if (u->state == RVSB_WORMHOLE) continue;
@ -911,7 +913,7 @@ static Vehicle *EnumFindVehBlockingOvertakeBehind(Vehicle *v, void *data)
static bool CheckRoadInfraUnsuitableForOvertaking(OvertakeData *od)
{
if (!HasTileAnyRoadType(od->tile, od->v->compatible_roadtypes)) return true;
TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, GetRoadTramType(od->v->roadtype));
TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, ((od->v->roadtype + 1) << 8) | GetRoadTramType(od->v->roadtype));
TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts);
TrackdirBits red_signals = TrackStatusToRedSignals(ts); // barred level crossing
TrackBits trackbits = TrackdirBitsToTrackBits(trackdirbits);
@ -1167,7 +1169,7 @@ static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection
Trackdir best_track;
bool path_found = true;
TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, GetRoadTramType(v->roadtype));
TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, ((v->roadtype + 1) << 8) | GetRoadTramType(v->roadtype));
TrackdirBits red_signals = TrackStatusToRedSignals(ts); // crossing
TrackdirBits trackdirs = TrackStatusToTrackdirBits(ts);

@ -3877,7 +3877,7 @@ bool AfterLoadGame()
if (SlXvIsFeatureMissing(XSLFI_SAFER_CROSSINGS)) {
for (TileIndex t = 0; t < map_size; t++) {
if (IsLevelCrossingTile(t)) {
SetCrossingOccupiedByRoadVehicle(t, EnsureNoRoadVehicleOnGround(t).Failed());
SetCrossingOccupiedByRoadVehicle(t, IsTrainCollidableRoadVehicleOnGround(t));
}
}
}

@ -3792,7 +3792,7 @@ static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode
case TRANSPORT_ROAD:
if (IsAnyRoadStop(tile)) {
RoadTramType rtt = (RoadTramType)sub_mode;
RoadTramType rtt = (RoadTramType)GB(sub_mode, 0, 8);
if (!HasTileRoadType(tile, rtt)) break;
DiagDirection dir = GetRoadStopDir(tile);

@ -1791,10 +1791,11 @@ class NIHRoadType : public NIHelper {
HasBit(rti->flags, ROTF_HIDDEN) ? 'h' : '-',
HasBit(rti->flags, ROTF_TOWN_BUILD) ? 'T' : '-');
output.print(buffer);
seprintf(buffer, lastof(buffer), " Extra Flags: %c%c%c",
seprintf(buffer, lastof(buffer), " Extra Flags: %c%c%c%c",
HasBit(rti->extra_flags, RXTF_NOT_AVAILABLE_AI_GS) ? 's' : '-',
HasBit(rti->extra_flags, RXTF_NO_TOWN_MODIFICATION) ? 't' : '-',
HasBit(rti->extra_flags, RXTF_NO_TUNNELS) ? 'T' : '-');
HasBit(rti->extra_flags, RXTF_NO_TUNNELS) ? 'T' : '-',
HasBit(rti->extra_flags, RXTF_NO_TRAIN_COLLISION) ? 'c' : '-');
output.print(buffer);
seprintf(buffer, lastof(buffer), " Collision mode: %u", rti->collision_mode);
output.print(buffer);

@ -2729,7 +2729,7 @@ void MarkDirtyAdjacentLevelCrossingTilesOnAddRemove(TileIndex tile, Axis road_ax
bool IsCrossingOccupiedByRoadVehicle(TileIndex t)
{
if (!IsCrossingPossiblyOccupiedByRoadVehicle(t)) return false;
const bool occupied = EnsureNoRoadVehicleOnGround(t).Failed();
const bool occupied = IsTrainCollidableRoadVehicleOnGround(t);
SetCrossingOccupiedByRoadVehicle(t, occupied);
return occupied;
}

@ -2857,13 +2857,13 @@ extern const TrackBits _road_trackbits[16];
static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
{
TransportType transport_type = GetTunnelBridgeTransportType(tile);
if (transport_type != mode || (transport_type == TRANSPORT_ROAD && !HasTileRoadType(tile, (RoadTramType)sub_mode))) return 0;
if (transport_type != mode || (transport_type == TRANSPORT_ROAD && !HasTileRoadType(tile, (RoadTramType)GB(sub_mode, 0, 8)))) return 0;
DiagDirection dir = GetTunnelBridgeDirection(tile);
if (side != INVALID_DIAGDIR && side == dir) return 0;
if (mode == TRANSPORT_ROAD && IsRoadCustomBridgeHeadTile(tile)) {
TrackBits bits = _road_trackbits[GetCustomBridgeHeadRoadBits(tile, (RoadTramType)sub_mode)];
TrackBits bits = _road_trackbits[GetCustomBridgeHeadRoadBits(tile, (RoadTramType)GB(sub_mode, 0, 8))];
return CombineTrackStatus(TrackBitsToTrackdirBits(bits), TRACKDIR_BIT_NONE);
}
return CombineTrackStatus(TrackBitsToTrackdirBits(mode == TRANSPORT_RAIL ? GetTunnelBridgeTrackBits(tile) : DiagDirToDiagTrackBits(dir)), TRACKDIR_BIT_NONE);

@ -561,6 +561,22 @@ static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
return v;
}
/**
* Callback that returns 'real' train-collidable road vehicles lower or at height \c *(int*)data .
* @param v Vehicle to examine.
* @param data Pointer to height data.
* @return \a v if conditions are met, else \c nullptr.
*/
static Vehicle *EnsureNoTrainCollidableRoadVehicleProcZ(Vehicle *v, void *data)
{
int z = static_cast<int>(reinterpret_cast<intptr_t>(data));
if (v->z_pos > z) return nullptr;
if (HasBit(_roadtypes_non_train_colliding, RoadVehicle::From(v)->roadtype)) return nullptr;
return v;
}
/**
* Callback that returns 'real' vehicles lower or at height \c *(int*)data .
* @param v Vehicle to examine.
@ -623,6 +639,13 @@ CommandCost EnsureNoRoadVehicleOnGround(TileIndex tile)
return CommandCost();
}
bool IsTrainCollidableRoadVehicleOnGround(TileIndex tile)
{
int z = GetTileMaxPixelZ(tile);
return VehicleFromPos(tile, VEH_ROAD, reinterpret_cast<void *>(static_cast<intptr_t>(z)), &EnsureNoTrainCollidableRoadVehicleProcZ, true) != nullptr;
}
struct GetVehicleTunnelBridgeProcData {
const Vehicle *v;
TileIndex t;

@ -241,6 +241,7 @@ static inline uint32 GetCmdSendToDepot(const BaseVehicle *v)
CommandCost EnsureNoVehicleOnGround(TileIndex tile);
CommandCost EnsureNoRoadVehicleOnGround(TileIndex tile);
bool IsTrainCollidableRoadVehicleOnGround(TileIndex tile);
CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits);
extern VehicleID _new_vehicle_id;

Loading…
Cancel
Save