mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-15 17:34:09 +01:00
feat: lock field shunting at zero and on resistive positions
New optional Cntrl. key ScndCtrlResistiveLock=Yes: IncScndCtrl() refuses to step the shunt controller up while the master controller is at its no-power position or on a resistive RList position (R >= 0.01), as the interlock of the ET21, ET22 and EP09 does. Decreasing the shunt stays allowed so it can't get stuck. The AI doesn't choose field shunting while the lock applies. Without the key nothing changes. Game data: the key is to be added to the Cntrl. line of the ET21 (et21_v2), ET22 (et22_v3, et22-2000_v2) and EP09 (ep09_v1, ep09_v2) .fiz files that define it; until then they behave as before. (eu07/maszyna#402)
This commit is contained in:
@@ -1943,6 +1943,7 @@ class TMoverParameters
|
||||
double MirrorVelClose{5.0};
|
||||
bool MirrorForbidden{false}; /*czy jest pozwolenie na otworzenie lusterek (przycisk)*/
|
||||
bool ScndS = false; /*Czy jest bocznikowanie na szeregowej*/
|
||||
bool ScndCtrlResistiveLock{false}; // the shunt controller can't be moved up while the master controller is at zero or on a resistive position (ScndCtrlResistiveLock=Yes in Cntrl.)
|
||||
bool SpeedCtrl = false; /*czy jest tempomat*/
|
||||
speed_control SpeedCtrlUnit; /*parametry tempomatu*/
|
||||
double SpeedCtrlButtons[10]{30, 40, 50, 60, 70, 80, 90, 100, 110, 120}; /*przyciski prędkości*/
|
||||
@@ -2372,6 +2373,8 @@ class TMoverParameters
|
||||
bool IncScndCtrl(int CtrlSpeed);
|
||||
bool DecScndCtrl(int CtrlSpeed);
|
||||
int GetVirtualScndPos() const;
|
||||
// whether ScndCtrlResistiveLock keeps the shunt controller from being moved up at the current master controller position
|
||||
bool IsScndCtrlLockedByMainCtrl() const;
|
||||
bool IsScndCtrlNoPowerPos() const;
|
||||
bool IsScndCtrlMaxPowerPos() const;
|
||||
|
||||
|
||||
@@ -2751,7 +2751,7 @@ bool TMoverParameters::IncScndCtrl(int CtrlSpeed)
|
||||
{
|
||||
// if (RList[MainCtrlPos].R=0) and (MainCtrlPos>0) and (ScndCtrlPos<ScndCtrlPosNo) and
|
||||
// (not CoupledCtrl) then
|
||||
if (ScndCtrlPos < ScndCtrlPosNo && !CoupledCtrl)
|
||||
if (ScndCtrlPos < ScndCtrlPosNo && !CoupledCtrl && !IsScndCtrlLockedByMainCtrl())
|
||||
{
|
||||
// TBD, TODO: refactor this validation as part of relay check routine (currently in tractionforce()
|
||||
// TBD, TODO: diesel electric engine utilize scndctrlactualpos like the other types?
|
||||
@@ -2872,6 +2872,12 @@ bool TMoverParameters::DecScndCtrl(int CtrlSpeed)
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool TMoverParameters::IsScndCtrlLockedByMainCtrl() const
|
||||
{
|
||||
// ET21, ET22, EP09: the field shunting engages only on the resistance-free positions of the master controller (eu07/maszyna#402)
|
||||
return ScndCtrlResistiveLock && (IsMainCtrlNoPowerPos() || RList[MainCtrlPos].R >= 0.01);
|
||||
}
|
||||
|
||||
int TMoverParameters::GetVirtualScndPos() const
|
||||
{
|
||||
if (TrainType == dt_ET42 && DynamicBrakeFlag && !ScndCtrlPos)
|
||||
@@ -10897,6 +10903,7 @@ void TMoverParameters::LoadFIZ_Cntrl(std::string const &line)
|
||||
extract_value(EIMCtrlEmergency, "EIMCtrlEmergency", line, "");
|
||||
|
||||
extract_value(ScndS, "ScndS", line, ""); // brak pozycji rownoleglej przy niskiej nastawie PSR
|
||||
extract_value(ScndCtrlResistiveLock, "ScndCtrlResistiveLock", line, ""); // bocznikowanie tylko na pozycjach bezoporowych
|
||||
|
||||
extract_value(InitialCtrlDelay, "IniCDelay", line, "");
|
||||
extract_value(CtrlDelay, "SCDelay", line, "");
|
||||
|
||||
@@ -37,3 +37,83 @@ TEST_CASE("cntrl: the relays of a multiple unit start on their own, of other veh
|
||||
CHECK(unit->ConverterOverloadRelayStart == start_t::automatic);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// the first position of the master controller after Position without the starting resistors in the circuit
|
||||
int resistance_free_position(TMoverParameters const &Vehicle, int Position = 0) {
|
||||
for (auto position{Position + 1}; position <= Vehicle.MainCtrlPosNo; ++position) {
|
||||
if (Vehicle.RList[position].R < 0.01) {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// the vehicle with its cab occupied, the master controller set to Position and the shunt controller off
|
||||
void controllers_at(vehicle &Vehicle, int Position) {
|
||||
Vehicle->CabActive = 1;
|
||||
Vehicle->MainCtrlPos = Position;
|
||||
Vehicle->ScndCtrlPos = 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("cntrl: ScndCtrlResistiveLock keeps the field shunting off at zero and on the resistive positions (eu07/maszyna#402)") {
|
||||
for (auto const *path : {"et22_v3/201e-rn", "ep09_v2/104e"}) {
|
||||
CAPTURE(path);
|
||||
vehicle locked{definition::fiz(path).set("Cntrl", "ScndCtrlResistiveLock", "Yes"), 0.0, "test", 1};
|
||||
REQUIRE(locked->ScndCtrlResistiveLock);
|
||||
REQUIRE(locked->ScndCtrlPosNo > 0);
|
||||
auto const resistancefree{resistance_free_position(locked.mover())};
|
||||
REQUIRE(resistancefree > 1);
|
||||
REQUIRE(locked->RList[resistancefree - 1].R >= 0.01);
|
||||
|
||||
SUBCASE("zero") {
|
||||
controllers_at(locked, 0);
|
||||
CHECK(locked->IsScndCtrlLockedByMainCtrl());
|
||||
CHECK_FALSE(locked->IncScndCtrl(1));
|
||||
CHECK_FALSE(locked->IncScndCtrl(2));
|
||||
CHECK(locked->ScndCtrlPos == 0);
|
||||
}
|
||||
SUBCASE("resistive positions") {
|
||||
for (auto position{1}; position < resistancefree; ++position) {
|
||||
CAPTURE(position);
|
||||
controllers_at(locked, position);
|
||||
CHECK_FALSE(locked->IncScndCtrl(1));
|
||||
CHECK(locked->ScndCtrlPos == 0);
|
||||
}
|
||||
}
|
||||
SUBCASE("every resistance-free position") {
|
||||
for (auto position{resistancefree}; position > 0; position = resistance_free_position(locked.mover(), position)) {
|
||||
CAPTURE(position);
|
||||
controllers_at(locked, position);
|
||||
CHECK_FALSE(locked->IsScndCtrlLockedByMainCtrl());
|
||||
CHECK(locked->IncScndCtrl(1));
|
||||
CHECK(locked->ScndCtrlPos == 1);
|
||||
}
|
||||
}
|
||||
SUBCASE("the shunting still goes off on a resistive position") {
|
||||
controllers_at(locked, resistancefree);
|
||||
REQUIRE(locked->IncScndCtrl(1));
|
||||
locked->MainCtrlPos = resistancefree - 1;
|
||||
CHECK(locked->DecScndCtrl(1));
|
||||
CHECK(locked->ScndCtrlPos == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("cntrl: without ScndCtrlResistiveLock the field shunting engages on any position, as before") {
|
||||
for (auto const *path : {"et22_v3/201e-rn", "ep09_v2/104e"}) {
|
||||
CAPTURE(path);
|
||||
vehicle unlocked{definition::fiz(path), 0.0, "test", 1};
|
||||
CHECK_FALSE(unlocked->ScndCtrlResistiveLock);
|
||||
for (auto const position : {0, 1}) {
|
||||
CAPTURE(position);
|
||||
controllers_at(unlocked, position);
|
||||
CHECK_FALSE(unlocked->IsScndCtrlLockedByMainCtrl());
|
||||
CHECK(unlocked->IncScndCtrl(1));
|
||||
CHECK(unlocked->ScndCtrlPos == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3364,7 +3364,7 @@ bool TController::IncSpeed()
|
||||
mvOccupied->Vel <= (IsCargoTrain ? 40 : 30) + (seriesmodefieldshunting ? 5 : 0) - (fAccGravity < -0.025 ? 10 : 0));
|
||||
// when not in series mode use the first available parallel mode configuration until 50/60 km/h for passenger/cargo train
|
||||
// (if there's only one parallel mode configuration it'll be used regardless of current speed)
|
||||
auto const usefieldshunting = mvControlling->StLinFlag && mvControlling->RList[mvControlling->MainCtrlPos].R < 0.01 &&
|
||||
auto const usefieldshunting = mvControlling->StLinFlag && mvControlling->RList[mvControlling->MainCtrlPos].R < 0.01 && false == mvControlling->IsScndCtrlLockedByMainCtrl() &&
|
||||
(useseriesmode ? mvControlling->RList[mvControlling->MainCtrlPos].Bn == 1 :
|
||||
true == sufficientacceleration && true == sufficienttractionforce && mvOccupied->Vel <= (IsCargoTrain ? 60 : 50) + (parallelmodefieldshunting ? 5 : 0) ?
|
||||
mvControlling->RList[mvControlling->MainCtrlPos].Bn > 1 :
|
||||
|
||||
Reference in New Issue
Block a user