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_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_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_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 },

@ -14,35 +14,42 @@
using SignalSpeedType = std::pair<const SignalSpeedKey, SignalSpeedValue>;
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, second.train_speed, SLE_UINT16),
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()
{
_filtered_train_speed_adaptation_map_desc = SlFilterObject(_train_speed_adaptation_map_desc);
int index;
SignalSpeedType data;
while ((index = SlIterateArray()) != -1) {
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);
}
_filtered_train_speed_adaptation_map_desc.clear();
}
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()
{
_filtered_train_speed_adaptation_map_desc = SlFilterObject(_train_speed_adaptation_map_desc);
for (auto &it : _signal_speeds) {
SlSetArrayIndex(it.first.signal_tile);
SignalSpeedType *data = &it;
SlAutolength((AutolengthProc*) RealSave_TSAS, data);
}
_filtered_train_speed_adaptation_map_desc.clear();
}
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 */
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)) {
key_value_pair = _signal_speeds.erase(key_value_pair);
} else {
@ -5610,28 +5610,38 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
v->wait_counter = (TILE_SIZE * simulated_wormhole_signals) - TILE_SIZE;
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 TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, TrackdirToTrack(trackdir));
if (prog && prog->actions_used_flags & (TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_RELEASE_FRONT | TRPAUF_SPEED_RESTRICTION | TRPAUF_CHANGE_COUNTER)) {
TraceRestrictProgramResult out;
TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr);
input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_RELEASE_FRONT | TRPISP_CHANGE_COUNTER;
prog->Execute(v, input, out);
HandleTraceRestrictSpeedRestrictionAction(out, v, trackdir);
if (IsTunnelBridgeRestrictedSignal(old_tile)) {
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, TrackdirToTrack(trackdir));
if (prog && prog->actions_used_flags & (TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_RELEASE_FRONT | TRPAUF_SPEED_RESTRICTION | TRPAUF_CHANGE_COUNTER)) {
TraceRestrictProgramResult out;
TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr);
input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_RELEASE_FRONT | TRPISP_CHANGE_COUNTER;
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 Track track = TrackdirToTrack(trackdir);
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, track);
if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) {
TraceRestrictProgramResult out;
TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr);
input.permitted_slot_operations = TRPISP_RELEASE_BACK;
prog->Execute(first, input, out);
if (IsTunnelBridgeRestrictedSignal(old_tile)) {
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, track);
if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) {
TraceRestrictProgramResult out;
TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr);
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);
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->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);
Axis axis = DiagDirToAxis(tunnel_bridge_dir);
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 Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks);
if (HasSignalOnTrackdir(gp.old_tile, ReverseTrackdir(rev_trackdir))) {
const Track track = 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;
}
ApplySignalTrainAdaptationSpeed(v, gp.old_tile, TrackdirToTrack(rev_trackdir));
}
}
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)) {
case CHANGED_NORMAL_TO_PBS_BLOCK:
@ -5867,16 +5873,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
const Track track = TrackdirToTrack(rev_trackdir);
if (_settings_game.vehicle.train_speed_adaptation && HasSignalOnTrackdir(gp.old_tile, ReverseTrackdir(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()
};
SignalSpeedValue speed_value = {
speed_value.train_speed = v->First()->cur_speed,
speed_value.time_stamp = GetSpeedRestrictionTimeout(v->First())
};
_signal_speeds[speed_key] = speed_value;
SetSignalTrainAdaptationSpeed(v, 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 Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks);
const Track track = TrackdirToTrack(rev_trackdir);
if (TrackdirEntersTunnelBridge(gp.old_tile, rev_trackdir)) {
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.old_tile, track);
if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) {
TraceRestrictProgramResult out;
TraceRestrictProgramInput input(gp.old_tile, ReverseTrackdir(rev_trackdir), nullptr, nullptr);
input.permitted_slot_operations = TRPISP_RELEASE_BACK;
prog->Execute(first, input, out);
if (IsTunnelBridgeRestrictedSignal(gp.old_tile)) {
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.old_tile, track);
if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) {
TraceRestrictProgramResult out;
TraceRestrictProgramInput input(gp.old_tile, ReverseTrackdir(rev_trackdir), nullptr, nullptr);
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;
}
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
{
TileIndex signal_tile;
Track signal_track;
uint16 signal_track;
Trackdir last_passing_train_dir;
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 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;
}
@ -50,4 +50,8 @@ struct SignalSpeedKeyHashFunc
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 */

Loading…
Cancel
Save