Add road/tram type flag to disallow collisions with trains
This commit is contained in:
@@ -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;
|
||||
|
Reference in New Issue
Block a user