Safer level crossings: add setting to improve RV level crossing safety.
This commit is contained in:
@@ -650,6 +650,7 @@
|
||||
<li>m5 bit 5: set if crossing lights are on</li>
|
||||
<li>m7 bits 4..0: <a href="#OwnershipInfo">owner</a> of the road type 0 (normal road)</li>
|
||||
<li>m5 bit 4: pbs reservation state</li>
|
||||
<li style="color: blue">m5 bit 1: set if crossing is possibly occupied by a road vehicle</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
@@ -150,7 +150,7 @@ the array so you can quickly see what is used and what is not.
|
||||
<td class="bits">-inherit-</td>
|
||||
<td class="bits">XXXX XXXX</td>
|
||||
<td class="bits">-inherit-</td>
|
||||
<td class="bits">XXXX<span class="free"> OOO</span>X</td>
|
||||
<td class="bits">XXXX<span class="free"> OO</span><span class="used_p">P</span>X</td>
|
||||
<td class="bits"><span class="free">OO</span>XX X<span class="free">OOO</span></td>
|
||||
<td class="bits">XXXX XXXX</td>
|
||||
</tr>
|
||||
|
@@ -1850,6 +1850,8 @@ STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}Change s
|
||||
|
||||
STR_CONFIG_SETTING_ADJACENT_CROSSINGS :Close adjacent level crossings: {STRING2}
|
||||
STR_CONFIG_SETTING_ADJACENT_CROSSINGS_HELPTEXT :Closes all adjacent level crossings on parallel tracks whenever one or more is occupied
|
||||
STR_CONFIG_SETTING_SAFER_CROSSINGS :Safer level crossings: {STRING2}
|
||||
STR_CONFIG_SETTING_SAFER_CROSSINGS_HELPTEXT :Changes to level crossings to improve road vehicle safety
|
||||
|
||||
STR_CONFIG_SETTING_PAY_FOR_REPAIR_VEHICLE :Pay for repairing vehicles: {STRING2}
|
||||
STR_CONFIG_SETTING_PAY_FOR_REPAIR_VEHICLE_HELPTEXT :Pay for repairing vehicles which have broken down
|
||||
|
12
src/pbs.cpp
12
src/pbs.cpp
@@ -125,6 +125,18 @@ bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
|
||||
|
||||
case MP_ROAD:
|
||||
if (IsLevelCrossing(tile) && !HasCrossingReservation(tile)) {
|
||||
if (_settings_game.vehicle.safer_crossings) {
|
||||
if (IsCrossingOccupiedByRoadVehicle(tile)) return false;
|
||||
if (_settings_game.vehicle.adjacent_crossings) {
|
||||
const Axis axis = GetCrossingRoadAxis(tile);
|
||||
for (TileIndex t = tile; IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == axis; t = TileAddByDiagDir(t, AxisToDiagDir(GetCrossingRoadAxis(t)))) {
|
||||
if (IsCrossingOccupiedByRoadVehicle(t)) return false;
|
||||
}
|
||||
for (TileIndex t = tile; IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == axis; t = TileAddByDiagDir(t, ReverseDiagDir(AxisToDiagDir(GetCrossingRoadAxis(t))))) {
|
||||
if (IsCrossingOccupiedByRoadVehicle(t)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
SetCrossingReservation(tile, true);
|
||||
UpdateLevelCrossing(tile, false);
|
||||
return true;
|
||||
|
@@ -1887,6 +1887,12 @@ static VehicleEnterTileStatus VehicleEnter_Road(Vehicle *v, TileIndex tile, int
|
||||
break;
|
||||
}
|
||||
|
||||
case ROAD_TILE_CROSSING: {
|
||||
if (v->type != VEH_ROAD) break;
|
||||
SetCrossingOccupiedByRoadVehicle(tile, true);
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
return VETSB_CONTINUE;
|
||||
|
@@ -180,5 +180,6 @@ bool ValParamRoadType(const RoadType rt);
|
||||
RoadTypes GetCompanyRoadtypes(const CompanyID company);
|
||||
|
||||
void UpdateLevelCrossing(TileIndex tile, bool sound = true);
|
||||
bool IsCrossingOccupiedByRoadVehicle(TileIndex t);
|
||||
|
||||
#endif /* ROAD_FUNC_H */
|
||||
|
@@ -402,21 +402,27 @@ static inline void SetCrossingBarred(TileIndex t, bool barred)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbar a level crossing.
|
||||
* @param t The tile to change.
|
||||
* Check if the level crossing is possibly occupied by road vehicle(s).
|
||||
* @param t The tile to query.
|
||||
* @pre IsLevelCrossing(t)
|
||||
* @return True if the level crossing is marked as occupied. This may return false positives.
|
||||
*/
|
||||
static inline void UnbarCrossing(TileIndex t)
|
||||
static inline bool IsCrossingPossiblyOccupiedByRoadVehicle(TileIndex t)
|
||||
{
|
||||
SetCrossingBarred(t, false);
|
||||
assert(IsLevelCrossing(t));
|
||||
return HasBit(_m[t].m5, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bar a level crossing.
|
||||
* @param t The tile to change.
|
||||
* Set whether the level crossing is occupied by road vehicle(s).
|
||||
* @param t The tile to modify.
|
||||
* @param barred True if the crossing should be marked as occupied, false otherwise.
|
||||
* @pre IsLevelCrossing(t)
|
||||
*/
|
||||
static inline void BarCrossing(TileIndex t)
|
||||
static inline void SetCrossingOccupiedByRoadVehicle(TileIndex t, bool occupied)
|
||||
{
|
||||
SetCrossingBarred(t, true);
|
||||
assert(IsLevelCrossing(t));
|
||||
SB(_m[t].m5, 1, 1, occupied ? 1 : 0);
|
||||
}
|
||||
|
||||
/** Check if a road tile has snow/desert. */
|
||||
|
@@ -3386,6 +3386,14 @@ bool AfterLoadGame()
|
||||
_settings_game.economy.day_length_factor = 1;
|
||||
}
|
||||
|
||||
if (SlXvIsFeatureMissing(XSLFI_SAFER_CROSSINGS)) {
|
||||
for (TileIndex t = 0; t < map_size; t++) {
|
||||
if (IsLevelCrossingTile(t)) {
|
||||
SetCrossingOccupiedByRoadVehicle(t, EnsureNoRoadVehicleOnGround(t).Failed());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Road stops is 'only' updating some caches */
|
||||
AfterLoadRoadStops();
|
||||
AfterLoadLabelMaps();
|
||||
|
@@ -51,6 +51,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
||||
{ XSLFI_TRACE_RESTRICT_OWNER, XSCF_NULL, 1, 1, "tracerestrict_owner", NULL, NULL, NULL },
|
||||
{ XSLFI_PROG_SIGS, XSCF_NULL, 1, 1, "programmable_signals", NULL, NULL, "SPRG" },
|
||||
{ XSLFI_ADJACENT_CROSSINGS, XSCF_NULL, 1, 1, "adjacent_crossings", NULL, NULL, NULL },
|
||||
{ XSLFI_SAFER_CROSSINGS, XSCF_NULL, 1, 1, "safer_crossings", NULL, NULL, NULL },
|
||||
{ XSLFI_DEPARTURE_BOARDS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "departure_boards", NULL, NULL, NULL },
|
||||
{ XSLFI_TIMETABLES_START_TICKS, XSCF_NULL, 2, 2, "timetable_start_ticks", NULL, NULL, NULL },
|
||||
{ XSLFI_TOWN_CARGO_ADJ, XSCF_IGNORABLE_UNKNOWN, 2, 2, "town_cargo_adj", NULL, NULL, NULL },
|
||||
|
@@ -25,6 +25,7 @@ enum SlXvFeatureIndex {
|
||||
XSLFI_TRACE_RESTRICT_OWNER, ///< Trace restrict: train owner test
|
||||
XSLFI_PROG_SIGS, ///< programmable signals patch
|
||||
XSLFI_ADJACENT_CROSSINGS, ///< Adjacent level crossings closure patch
|
||||
XSLFI_SAFER_CROSSINGS, ///< Safer level crossings
|
||||
XSLFI_DEPARTURE_BOARDS, ///< Departure boards patch, in ticks mode
|
||||
XSLFI_TIMETABLES_START_TICKS, ///< Timetable start time is in ticks, instead of days (from departure boards patch)
|
||||
XSLFI_TOWN_CARGO_ADJ, ///< Town cargo adjustment patch
|
||||
|
@@ -1694,6 +1694,7 @@ static SettingsContainer &GetSettingsTree()
|
||||
vehicles->Add(new SettingEntry("order.no_servicing_if_no_breakdowns"));
|
||||
vehicles->Add(new SettingEntry("order.serviceathelipad"));
|
||||
vehicles->Add(new SettingEntry("vehicle.adjacent_crossings"));
|
||||
vehicles->Add(new SettingEntry("vehicle.safer_crossings"));
|
||||
}
|
||||
|
||||
SettingsPage *limitations = main->Add(new SettingsPage(STR_CONFIG_SETTING_LIMITATIONS));
|
||||
|
@@ -515,6 +515,7 @@ struct VehicleSettings {
|
||||
byte road_side; ///< the side of the road vehicles drive on
|
||||
uint8 plane_crashes; ///< number of plane crashes, 0 = none, 1 = reduced, 2 = normal
|
||||
bool adjacent_crossings; ///< enable closing of adjacent level crossings
|
||||
bool safer_crossings; ///< enable safer level crossings
|
||||
bool improved_breakdowns; ///< different types, chances and severities of breakdowns
|
||||
bool pay_for_repair; ///< pay for repairing vehicle
|
||||
uint8 repair_cost; ///< cost of repairing vehicle
|
||||
|
@@ -400,6 +400,7 @@ static SigInfo ExploreSegment(Owner owner)
|
||||
if (DiagDirToAxis(enterdir) == GetCrossingRoadAxis(tile)) continue; // different axis
|
||||
|
||||
if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) info.flags |= SF_TRAIN;
|
||||
if (_settings_game.vehicle.safer_crossings) info.flags |= SF_PBS;
|
||||
tile += TileOffsByDiagDir(exitdir);
|
||||
break;
|
||||
|
||||
|
@@ -3057,6 +3057,15 @@ strhelp = STR_CONFIG_SETTING_ADJACENT_CROSSINGS_HELPTEXT
|
||||
cat = SC_BASIC
|
||||
patxname = ""adjacent_crossings.vehicle.adjacent_crossings""
|
||||
|
||||
[SDT_BOOL]
|
||||
base = GameSettings
|
||||
var = vehicle.safer_crossings
|
||||
def = false
|
||||
str = STR_CONFIG_SETTING_SAFER_CROSSINGS
|
||||
strhelp = STR_CONFIG_SETTING_SAFER_CROSSINGS_HELPTEXT
|
||||
cat = SC_BASIC
|
||||
patxname = ""safer_crossings.vehicle.safer_crossings""
|
||||
|
||||
|
||||
;***************************************************************************
|
||||
; Unsaved setting variables.
|
||||
|
@@ -1866,6 +1866,20 @@ void UpdateLevelCrossing(TileIndex tile, bool sound)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the level crossing is occupied by road vehicle(s).
|
||||
* @param t The tile to query.
|
||||
* @pre IsLevelCrossing(t)
|
||||
* @return True if the level crossing is marked as occupied.
|
||||
*/
|
||||
bool IsCrossingOccupiedByRoadVehicle(TileIndex t)
|
||||
{
|
||||
if (!IsCrossingPossiblyOccupiedByRoadVehicle(t)) return false;
|
||||
const bool occupied = EnsureNoRoadVehicleOnGround(t).Failed();
|
||||
SetCrossingOccupiedByRoadVehicle(t, occupied);
|
||||
return occupied;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Bars crossing and plays ding-ding sound if not barred already
|
||||
|
@@ -575,6 +575,40 @@ CommandCost EnsureNoVehicleOnGround(TileIndex tile)
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback that returns 'real' vehicles lower or at height \c *(int*)data, for road vehicles.
|
||||
* @param v Vehicle to examine.
|
||||
* @param data Pointer to height data.
|
||||
* @return \a v if conditions are met, else \c NULL.
|
||||
*/
|
||||
static Vehicle *EnsureNoRoadVehicleProcZ(Vehicle *v, void *data)
|
||||
{
|
||||
int z = *(int*)data;
|
||||
|
||||
if (v->type != VEH_ROAD) return NULL;
|
||||
if (v->z_pos > z) return NULL;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure there is no road vehicle at the ground at the given position.
|
||||
* @param tile Position to examine.
|
||||
* @return Succeeded command (ground is free) or failed command (a vehicle is found).
|
||||
*/
|
||||
CommandCost EnsureNoRoadVehicleOnGround(TileIndex tile)
|
||||
{
|
||||
int z = GetTileMaxPixelZ(tile);
|
||||
|
||||
/* Value v is not safe in MP games, however, it is used to generate a local
|
||||
* error message only (which may be different for different machines).
|
||||
* Such a message does not affect MP synchronisation.
|
||||
*/
|
||||
Vehicle *v = VehicleFromPos(tile, &z, &EnsureNoRoadVehicleProcZ, true);
|
||||
if (v != NULL) return_cmd_error(STR_ERROR_ROAD_VEHICLE_IN_THE_WAY);
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/** Procedure called for every vehicle found in tunnel/bridge in the hash map */
|
||||
static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
|
||||
{
|
||||
|
@@ -165,6 +165,7 @@ static inline uint32 GetCmdSendToDepot(const BaseVehicle *v)
|
||||
}
|
||||
|
||||
CommandCost EnsureNoVehicleOnGround(TileIndex tile);
|
||||
CommandCost EnsureNoRoadVehicleOnGround(TileIndex tile);
|
||||
CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits);
|
||||
|
||||
extern VehicleID _new_vehicle_id;
|
||||
|
Reference in New Issue
Block a user