diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index c6c85659..77ac72dd 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -2352,6 +2352,9 @@ class TMoverParameters plc::basic_controller m_plc; int AIHintPantstate{0}; // suggested pantograph setup + // suggested pantograph setup in shunting (AI: ShuntPantstate=, eu07/maszyna#461), the bits as in Pantstate: 1 front, + // 2 rear, 3 both; 0 (the default) shunts with the pantographs handled as in train mode + int AIHintShuntPantstate{0}; bool AIHintPantUpIfIdle{true}; // whether raise both pantographs if idling for a while double AIHintLocalBrakeAccFactor{1.05}; // suggested acceleration weight for local brake operation diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index e707ede2..8b1eee98 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -11616,6 +11616,7 @@ void TMoverParameters::LoadFIZ_AI(std::string const &Input) { extract_value(AIHintPantstate, "Pantstate", Input, ""); + extract_value(AIHintShuntPantstate, "ShuntPantstate", Input, ""); extract_value(AIHintPantUpIfIdle, "IdlePantUp", Input, ""); extract_value(AIHintLocalBrakeAccFactor, "LocalBrakeAccFactor", Input, ""); } diff --git a/tests/unit/test_ai_hints.cpp b/tests/unit/test_ai_hints.cpp new file mode 100644 index 00000000..d01e421c --- /dev/null +++ b/tests/unit/test_ai_hints.cpp @@ -0,0 +1,31 @@ +#include "stdafx.h" +#include "doctest.h" +#include "vehicle.h" + +using test::definition; +using test::vehicle; + +// the hints for the AI driver from the AI section of the .fiz + +TEST_CASE("ai hints: without the AI section the pantographs follow the built-in logic") { + vehicle wagon{definition::load("wagon")}; + + CHECK(wagon->AIHintPantstate == 0); + CHECK(wagon->AIHintShuntPantstate == 0); + CHECK(wagon->AIHintPantUpIfIdle); +} + +TEST_CASE("ai hints: the suggested pantograph setup for shunting is read apart from the one for train mode") { + // eu07/maszyna#461: so the ET41 doesn't shunt with all of its four pantographs up + vehicle shunting{definition::load("wagon").set("AI", "Pantstate", 1).set("AI", "ShuntPantstate", 2)}; + + CHECK(shunting->AIHintPantstate == 1); + CHECK(shunting->AIHintShuntPantstate == 2); +} + +TEST_CASE("ai hints: a .fiz with the setup for train mode only has none for shunting") { + vehicle train{definition::load("wagon").set("AI", "Pantstate", 3)}; + + CHECK(train->AIHintPantstate == 3); + CHECK(train->AIHintShuntPantstate == 0); +} diff --git a/vehicle/Driver.cpp b/vehicle/Driver.cpp index 384c1b30..0e72198a 100644 --- a/vehicle/Driver.cpp +++ b/vehicle/Driver.cpp @@ -6229,6 +6229,13 @@ TController::control_pantographs() { fActionTime = -2.0 - Random(10); } + // the pantograph setup the .fiz suggests for shunting (AI: ShuntPantstate=, eu07/maszyna#461), 0 when there's none + // or the vehicle isn't shunting + auto const shuntpantographsetup { + ( OrderCurrentGet() & ( Shunt | Loose_shunt ) ) != 0 ? + mvOccupied->AIHintShuntPantstate : + 0 }; + // raise/lower pantographs as needed auto const useregularpantographlayout { pVehicle->Next(coupling::control) == nullptr // standalone @@ -6255,7 +6262,11 @@ TController::control_pantographs() { // jeśli nie trzeba opuszczać pantografów // TODO: check if faction alone reduces frequency enough if( fActionTime > 0.0 ) { - if( mvOccupied->AIHintPantstate == 0 ) { + if( shuntpantographsetup != 0 ) { + // shunting with the pantograph setup the .fiz suggests for it + control_pantographs_setup( shuntpantographsetup ); + } + else if( mvOccupied->AIHintPantstate == 0 ) { // jazda na tylnym if( iDirection >= 0 && useregularpantographlayout ) { // jak jedzie w kierunku sprzęgu 0 @@ -6308,6 +6319,12 @@ TController::control_pantographs() { } } } + else if( shuntpantographsetup != 0 ) { + // shunting with the suggested setup, also while standing, and without raising more pantographs when idling + if( fOverhead2 <= 0.0 && iOverheadDown == 0 ) { + control_pantographs_setup( shuntpantographsetup ); + } + } else { if( !mvOccupied->AIHintPantUpIfIdle || IdleTime <= 45.0 || std::abs(fStopTime) <= 15.0 || mvPantographUnit->EnginePowerSource.CollectorParameters.CollectorsNo <= 1 ) { @@ -6334,6 +6351,31 @@ TController::control_pantographs() { } } +// raises the pantographs of the suggested setup (bit 0: front, bit 1: rear) and lowers the others, these only once +// a pantograph of the setup collects the voltage, so the vehicle doesn't lose its power on the way +void +TController::control_pantographs_setup( int const Setup ) { + + auto const front { ( Setup & 1 << 0 ) != 0 }; + auto const rear { ( Setup & 1 << 1 ) != 0 }; + if( front ) { + cue_action( driver_hint::frontpantographvalveon ); + } + if( rear ) { + cue_action( driver_hint::rearpantographvalveon ); + } + if( auto const setuplive { ( front && mvPantographUnit->PantFrontVolt != 0.0 ) || ( rear && mvPantographUnit->PantRearVolt != 0.0 ) }; + false == setuplive ) { + return; + } + if( false == front ) { + cue_action( driver_hint::frontpantographvalveoff ); + } + if( false == rear ) { + cue_action( driver_hint::rearpantographvalveoff ); + } +} + void TController::control_horns( double const Timedelta ) { // horn control diff --git a/vehicle/Driver.h b/vehicle/Driver.h index 38b4c9e2..570a893f 100644 --- a/vehicle/Driver.h +++ b/vehicle/Driver.h @@ -323,6 +323,7 @@ private: void scan_obstacles( double const Range ); void control_wheelslip(); void control_pantographs(); + void control_pantographs_setup( int const Setup ); void control_horns( double const Timedelta ); void control_security_system( double const Timedelta ); void control_handles();