Implement train speed adaptation on signalled tunnels/bridges

See: #373
pull/374/head
Jonathan G Rennison 2 years ago
parent cf25a0c80a
commit 909b20ee68

@ -156,7 +156,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_MORE_HOUSES, XSCF_NULL, 2, 2, "more_houses", nullptr, nullptr, nullptr }, { XSLFI_MORE_HOUSES, XSCF_NULL, 2, 2, "more_houses", nullptr, nullptr, nullptr },
{ XSLFI_CUSTOM_TOWN_ZONE, XSCF_IGNORABLE_UNKNOWN, 1, 1, "custom_town_zone", nullptr, nullptr, nullptr }, { XSLFI_CUSTOM_TOWN_ZONE, XSCF_IGNORABLE_UNKNOWN, 1, 1, "custom_town_zone", nullptr, nullptr, nullptr },
{ XSLFI_STATION_CARGO_HISTORY, XSCF_NULL, 1, 1, "station_cargo_history", nullptr, nullptr, nullptr }, { XSLFI_STATION_CARGO_HISTORY, XSCF_NULL, 1, 1, "station_cargo_history", nullptr, nullptr, nullptr },
{ XSLFI_TRAIN_SPEED_ADAPTATION, XSCF_NULL, 1, 1, "train_speed_adaptation", nullptr, nullptr, "TSAS" }, { XSLFI_TRAIN_SPEED_ADAPTATION, XSCF_NULL, 2, 2, "train_speed_adaptation", nullptr, nullptr, "TSAS" },
{ XSLFI_EXTRA_STATION_NAMES, XSCF_NULL, 1, 1, "extra_station_names", nullptr, nullptr, nullptr }, { XSLFI_EXTRA_STATION_NAMES, XSCF_NULL, 1, 1, "extra_station_names", nullptr, nullptr, nullptr },
{ XSLFI_DEPOT_ORDER_EXTRA_FLAGS,XSCF_IGNORABLE_UNKNOWN, 1, 1, "depot_order_extra_flags", nullptr, nullptr, nullptr }, { XSLFI_DEPOT_ORDER_EXTRA_FLAGS,XSCF_IGNORABLE_UNKNOWN, 1, 1, "depot_order_extra_flags", nullptr, nullptr, nullptr },
{ XSLFI_EXTRA_SIGNAL_TYPES, XSCF_NULL, 1, 1, "extra_signal_types", nullptr, nullptr, nullptr }, { XSLFI_EXTRA_SIGNAL_TYPES, XSCF_NULL, 1, 1, "extra_signal_types", nullptr, nullptr, nullptr },

@ -14,35 +14,42 @@
using SignalSpeedType = std::pair<const SignalSpeedKey, SignalSpeedValue>; using SignalSpeedType = std::pair<const SignalSpeedKey, SignalSpeedValue>;
static const SaveLoad _train_speed_adaptation_map_desc[] = { static const SaveLoad _train_speed_adaptation_map_desc[] = {
SLE_VAR(SignalSpeedType, first.signal_track, SLE_UINT8), SLE_CONDVAR_X(SignalSpeedType, first.signal_track, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TRAIN_SPEED_ADAPTATION, 1, 1)),
SLE_CONDVAR_X(SignalSpeedType, first.signal_track, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TRAIN_SPEED_ADAPTATION, 2)),
SLE_VAR(SignalSpeedType, first.last_passing_train_dir, SLE_UINT8), SLE_VAR(SignalSpeedType, first.last_passing_train_dir, SLE_UINT8),
SLE_VAR(SignalSpeedType, second.train_speed, SLE_UINT16), SLE_VAR(SignalSpeedType, second.train_speed, SLE_UINT16),
SLE_VAR(SignalSpeedType, second.time_stamp, SLE_UINT64), SLE_VAR(SignalSpeedType, second.time_stamp, SLE_UINT64),
}; };
static std::vector<SaveLoad> _filtered_train_speed_adaptation_map_desc = SlFilterObject(_train_speed_adaptation_map_desc);
static void Load_TSAS() static void Load_TSAS()
{ {
_filtered_train_speed_adaptation_map_desc = SlFilterObject(_train_speed_adaptation_map_desc);
int index; int index;
SignalSpeedType data; SignalSpeedType data;
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
const_cast<SignalSpeedKey &>(data.first).signal_tile = index; const_cast<SignalSpeedKey &>(data.first).signal_tile = index;
SlObject(&data, _train_speed_adaptation_map_desc); SlObjectLoadFiltered(&data, _filtered_train_speed_adaptation_map_desc);
_signal_speeds.insert(data); _signal_speeds.insert(data);
} }
_filtered_train_speed_adaptation_map_desc.clear();
} }
static void RealSave_TSAS(SignalSpeedType *data) static void RealSave_TSAS(SignalSpeedType *data)
{ {
SlObject(data, _train_speed_adaptation_map_desc); SlObjectSaveFiltered(data, _filtered_train_speed_adaptation_map_desc);
} }
static void Save_TSAS() static void Save_TSAS()
{ {
_filtered_train_speed_adaptation_map_desc = SlFilterObject(_train_speed_adaptation_map_desc);
for (auto &it : _signal_speeds) { for (auto &it : _signal_speeds) {
SlSetArrayIndex(it.first.signal_tile); SlSetArrayIndex(it.first.signal_tile);
SignalSpeedType *data = &it; SignalSpeedType *data = &it;
SlAutolength((AutolengthProc*) RealSave_TSAS, data); SlAutolength((AutolengthProc*) RealSave_TSAS, data);
} }
_filtered_train_speed_adaptation_map_desc.clear();
} }
extern const ChunkHandler train_speed_adaptation_chunk_handlers[] = { extern const ChunkHandler train_speed_adaptation_chunk_handlers[] = {

@ -133,7 +133,7 @@ void AdjustAllSignalSpeedRestrictionTickValues(DateTicksScaled delta)
/** Removes all speed restrictions which have passed their timeout from all signals */ /** Removes all speed restrictions which have passed their timeout from all signals */
void ClearOutOfDateSignalSpeedRestrictions() void ClearOutOfDateSignalSpeedRestrictions()
{ {
for(auto key_value_pair = _signal_speeds.begin(); key_value_pair != _signal_speeds.end(); ) { for (auto key_value_pair = _signal_speeds.begin(); key_value_pair != _signal_speeds.end(); ) {
if (IsOutOfDate(key_value_pair->second)) { if (IsOutOfDate(key_value_pair->second)) {
key_value_pair = _signal_speeds.erase(key_value_pair); key_value_pair = _signal_speeds.erase(key_value_pair);
} else { } else {
@ -5610,28 +5610,38 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
v->wait_counter = (TILE_SIZE * simulated_wormhole_signals) - TILE_SIZE; v->wait_counter = (TILE_SIZE * simulated_wormhole_signals) - TILE_SIZE;
v->tunnel_bridge_signal_num = 0; v->tunnel_bridge_signal_num = 0;
if (v->IsFrontEngine() && IsTunnelBridgeSignalSimulationEntrance(old_tile) && IsTunnelBridgeRestrictedSignal(old_tile)) { if (v->IsFrontEngine() && IsTunnelBridgeSignalSimulationEntrance(old_tile) && (IsTunnelBridgeRestrictedSignal(old_tile) || _settings_game.vehicle.train_speed_adaptation)) {
const Trackdir trackdir = GetTunnelBridgeEntranceTrackdir(old_tile); const Trackdir trackdir = GetTunnelBridgeEntranceTrackdir(old_tile);
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, TrackdirToTrack(trackdir)); if (IsTunnelBridgeRestrictedSignal(old_tile)) {
if (prog && prog->actions_used_flags & (TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_RELEASE_FRONT | TRPAUF_SPEED_RESTRICTION | TRPAUF_CHANGE_COUNTER)) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, TrackdirToTrack(trackdir));
TraceRestrictProgramResult out; if (prog && prog->actions_used_flags & (TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_RELEASE_FRONT | TRPAUF_SPEED_RESTRICTION | TRPAUF_CHANGE_COUNTER)) {
TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr); TraceRestrictProgramResult out;
input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_RELEASE_FRONT | TRPISP_CHANGE_COUNTER; TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr);
prog->Execute(v, input, out); input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_RELEASE_FRONT | TRPISP_CHANGE_COUNTER;
HandleTraceRestrictSpeedRestrictionAction(out, v, trackdir); prog->Execute(v, input, out);
HandleTraceRestrictSpeedRestrictionAction(out, v, trackdir);
}
}
if (_settings_game.vehicle.train_speed_adaptation) {
SetSignalTrainAdaptationSpeed(v, old_tile, TrackdirToTrack(trackdir));
} }
} }
if (v->Next() == nullptr && IsTunnelBridgeSignalSimulationEntrance(old_tile) && IsTunnelBridgeRestrictedSignal(old_tile)) { if (v->Next() == nullptr && IsTunnelBridgeSignalSimulationEntrance(old_tile) && (IsTunnelBridgeRestrictedSignal(old_tile) || _settings_game.vehicle.train_speed_adaptation)) {
const Trackdir trackdir = GetTunnelBridgeEntranceTrackdir(old_tile); const Trackdir trackdir = GetTunnelBridgeEntranceTrackdir(old_tile);
const Track track = TrackdirToTrack(trackdir); const Track track = TrackdirToTrack(trackdir);
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, track); if (IsTunnelBridgeRestrictedSignal(old_tile)) {
if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, track);
TraceRestrictProgramResult out; if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) {
TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr); TraceRestrictProgramResult out;
input.permitted_slot_operations = TRPISP_RELEASE_BACK; TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr);
prog->Execute(first, input, out); input.permitted_slot_operations = TRPISP_RELEASE_BACK;
prog->Execute(first, input, out);
}
}
if (_settings_game.vehicle.train_speed_adaptation) {
ApplySignalTrainAdaptationSpeed(v, old_tile, track);
} }
} }
} }
@ -5672,10 +5682,18 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
SetBridgeEntranceSimulatedSignalState(v->tile, v->tunnel_bridge_signal_num, SIGNAL_STATE_RED); SetBridgeEntranceSimulatedSignalState(v->tile, v->tunnel_bridge_signal_num, SIGNAL_STATE_RED);
MarkSingleBridgeSignalDirty(gp.new_tile, v->tile); MarkSingleBridgeSignalDirty(gp.new_tile, v->tile);
} }
if (_settings_game.vehicle.train_speed_adaptation && distance == 0 && IsTunnelBridgeSignalSimulationEntrance(v->tile)) {
ApplySignalTrainAdaptationSpeed(v, v->tile, 0x100 + v->tunnel_bridge_signal_num);
}
} }
} }
if (v->Next() == nullptr) { if (v->Next() == nullptr) {
if (v->tunnel_bridge_signal_num > 0 && distance == (TILE_SIZE * simulated_wormhole_signals) - TILE_SIZE) HandleSignalBehindTrain(v, v->tunnel_bridge_signal_num - 2); if (v->tunnel_bridge_signal_num > 0 && distance == (TILE_SIZE * simulated_wormhole_signals) - TILE_SIZE) {
HandleSignalBehindTrain(v, v->tunnel_bridge_signal_num - 2);
if (_settings_game.vehicle.train_speed_adaptation) {
SetSignalTrainAdaptationSpeed(v, v->tile, 0x100 + v->tunnel_bridge_signal_num - 1);
}
}
DiagDirection tunnel_bridge_dir = GetTunnelBridgeDirection(v->tile); DiagDirection tunnel_bridge_dir = GetTunnelBridgeDirection(v->tile);
Axis axis = DiagDirToAxis(tunnel_bridge_dir); Axis axis = DiagDirToAxis(tunnel_bridge_dir);
DiagDirection axial_dir = DirToDiagDirAlongAxis(v->direction, axis); DiagDirection axial_dir = DirToDiagDirAlongAxis(v->direction, axis);
@ -5803,26 +5821,14 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir)); const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir));
const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks); const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks);
if (HasSignalOnTrackdir(gp.old_tile, ReverseTrackdir(rev_trackdir))) { if (HasSignalOnTrackdir(gp.old_tile, ReverseTrackdir(rev_trackdir))) {
const Track track = TrackdirToTrack(rev_trackdir); ApplySignalTrainAdaptationSpeed(v, gp.old_tile, TrackdirToTrack(rev_trackdir));
SignalSpeedKey speed_key = {
speed_key.signal_tile = gp.old_tile,
speed_key.signal_track = track,
speed_key.last_passing_train_dir = v->GetVehicleTrackdir()
};
const auto found_speed_restriction = _signal_speeds.find(speed_key);
if (found_speed_restriction != _signal_speeds.end()) {
if (IsOutOfDate(found_speed_restriction->second)) {
_signal_speeds.erase(found_speed_restriction);
v->signal_speed_restriction = 0;
} else {
v->signal_speed_restriction = std::max<uint16>(25, found_speed_restriction->second.train_speed);
}
} else {
v->signal_speed_restriction = 0;
}
} }
} }
if (_settings_game.vehicle.train_speed_adaptation && IsTileType(gp.old_tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(gp.old_tile)) {
const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTunnelBridgeTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir));
const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks);
ApplySignalTrainAdaptationSpeed(v, gp.old_tile, TrackdirToTrack(rev_trackdir));
}
switch (TrainMovedChangeSignal(v, gp.new_tile, enterdir, true)) { switch (TrainMovedChangeSignal(v, gp.new_tile, enterdir, true)) {
case CHANGED_NORMAL_TO_PBS_BLOCK: case CHANGED_NORMAL_TO_PBS_BLOCK:
@ -5867,16 +5873,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
const Track track = TrackdirToTrack(rev_trackdir); const Track track = TrackdirToTrack(rev_trackdir);
if (_settings_game.vehicle.train_speed_adaptation && HasSignalOnTrackdir(gp.old_tile, ReverseTrackdir(rev_trackdir))) { if (_settings_game.vehicle.train_speed_adaptation && HasSignalOnTrackdir(gp.old_tile, ReverseTrackdir(rev_trackdir))) {
SignalSpeedKey speed_key = { SetSignalTrainAdaptationSpeed(v, gp.old_tile, track);
speed_key.signal_tile = gp.old_tile,
speed_key.signal_track = track,
speed_key.last_passing_train_dir = v->GetVehicleTrackdir()
};
SignalSpeedValue speed_value = {
speed_value.train_speed = v->First()->cur_speed,
speed_value.time_stamp = GetSpeedRestrictionTimeout(v->First())
};
_signal_speeds[speed_key] = speed_value;
} }
if (HasSignalOnTrack(gp.old_tile, track)) { if (HasSignalOnTrack(gp.old_tile, track)) {
@ -5892,18 +5889,23 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
} }
} }
if (IsTileType(gp.old_tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(gp.old_tile) && IsTunnelBridgeRestrictedSignal(gp.old_tile)) { if (IsTileType(gp.old_tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(gp.old_tile) && (IsTunnelBridgeRestrictedSignal(gp.old_tile) || _settings_game.vehicle.train_speed_adaptation)) {
const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTunnelBridgeTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir)); const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTunnelBridgeTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir));
const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks); const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks);
const Track track = TrackdirToTrack(rev_trackdir); const Track track = TrackdirToTrack(rev_trackdir);
if (TrackdirEntersTunnelBridge(gp.old_tile, rev_trackdir)) { if (TrackdirEntersTunnelBridge(gp.old_tile, rev_trackdir)) {
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.old_tile, track); if (IsTunnelBridgeRestrictedSignal(gp.old_tile)) {
if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.old_tile, track);
TraceRestrictProgramResult out; if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) {
TraceRestrictProgramInput input(gp.old_tile, ReverseTrackdir(rev_trackdir), nullptr, nullptr); TraceRestrictProgramResult out;
input.permitted_slot_operations = TRPISP_RELEASE_BACK; TraceRestrictProgramInput input(gp.old_tile, ReverseTrackdir(rev_trackdir), nullptr, nullptr);
prog->Execute(first, input, out); input.permitted_slot_operations = TRPISP_RELEASE_BACK;
prog->Execute(first, input, out);
}
}
if (_settings_game.vehicle.train_speed_adaptation) {
SetSignalTrainAdaptationSpeed(v, gp.old_tile, track);
} }
} }
} }
@ -7271,3 +7273,38 @@ int GetTrainEstimatedMaxAchievableSpeed(const Train *train, const int mass, cons
return max_speed; return max_speed;
} }
void SetSignalTrainAdaptationSpeed(const Train *v, TileIndex tile, uint16 track)
{
SignalSpeedKey speed_key = {
speed_key.signal_tile = tile,
speed_key.signal_track = track,
speed_key.last_passing_train_dir = v->GetVehicleTrackdir()
};
SignalSpeedValue speed_value = {
speed_value.train_speed = v->First()->cur_speed,
speed_value.time_stamp = GetSpeedRestrictionTimeout(v->First())
};
_signal_speeds[speed_key] = speed_value;
}
void ApplySignalTrainAdaptationSpeed(Train *v, TileIndex tile, uint16 track)
{
SignalSpeedKey speed_key = {
speed_key.signal_tile = tile,
speed_key.signal_track = track,
speed_key.last_passing_train_dir = v->GetVehicleTrackdir()
};
const auto found_speed_restriction = _signal_speeds.find(speed_key);
if (found_speed_restriction != _signal_speeds.end()) {
if (IsOutOfDate(found_speed_restriction->second)) {
_signal_speeds.erase(found_speed_restriction);
v->signal_speed_restriction = 0;
} else {
v->signal_speed_restriction = std::max<uint16>(25, found_speed_restriction->second.train_speed);
}
} else {
v->signal_speed_restriction = 0;
}
}

@ -19,7 +19,7 @@
struct SignalSpeedKey struct SignalSpeedKey
{ {
TileIndex signal_tile; TileIndex signal_tile;
Track signal_track; uint16 signal_track;
Trackdir last_passing_train_dir; Trackdir last_passing_train_dir;
bool operator==(const SignalSpeedKey& other) const bool operator==(const SignalSpeedKey& other) const
@ -42,7 +42,7 @@ struct SignalSpeedKeyHashFunc
{ {
const std::size_t h1 = std::hash<TileIndex>()(key.signal_tile); const std::size_t h1 = std::hash<TileIndex>()(key.signal_tile);
const std::size_t h2 = std::hash<Trackdir>()(key.last_passing_train_dir); const std::size_t h2 = std::hash<Trackdir>()(key.last_passing_train_dir);
const std::size_t h3 = std::hash<Track>()(key.signal_track); const std::size_t h3 = std::hash<uint16>()(key.signal_track);
return (h1 ^ h2) ^ h3; return (h1 ^ h2) ^ h3;
} }
@ -50,4 +50,8 @@ struct SignalSpeedKeyHashFunc
extern std::unordered_map<SignalSpeedKey, SignalSpeedValue, SignalSpeedKeyHashFunc> _signal_speeds; extern std::unordered_map<SignalSpeedKey, SignalSpeedValue, SignalSpeedKeyHashFunc> _signal_speeds;
struct Train;
void SetSignalTrainAdaptationSpeed(const Train *v, TileIndex tile, uint16 track);
void ApplySignalTrainAdaptationSpeed(Train *v, TileIndex tile, uint16 track);
#endif /* TRAIN_SPEED_ADAPTATION_H */ #endif /* TRAIN_SPEED_ADAPTATION_H */

Loading…
Cancel
Save