Implement train speed adaptation on signalled tunnels/bridges

See: #373
This commit is contained in:
Jonathan G Rennison
2022-02-21 18:30:43 +00:00
parent cf25a0c80a
commit 909b20ee68
4 changed files with 106 additions and 58 deletions

View File

@@ -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;
}
}