From 30bdc3da6139d0e3896aabe61bbb2980c06c7582 Mon Sep 17 00:00:00 2001 From: jerrrrycho Date: Sat, 7 Nov 2026 21:33:28 +0100 Subject: [PATCH 1/2] feat: radio fuse, a cut-off in the radio's power supply (eu07/maszyna#438) TMoverParameters::RadioFuse, closed by default, stands for a fuse in the cabinet, a lever on the desk or the switch on the radio's power supply. RadioPowered() needs it closed, so with it open the radio's buttons, calls, messages and the radio-stop stop working; opening it at a standstill resets the radio-stop as switching the radio off does, and the radio and radio-stop lamps go out. New commands radiofusetoggle/radiofuseenable/radiofusedisable (no default keys), cab controls radiofuse_sw: (follows the fuse state), radiofuseon_sw: and radiofuseoff_sw:, and radio_fuse for the Python screens. The AI turning the radio back on closes the fuse too. Existing vehicles don't change: the fuse starts closed and opens only from a new cab control or a bound key. SVN data, optional: cabs that have such a fuse or lever get one of the new controls in their .mmd, in the form of radio_sw: (e.g. "radiofuse_sw: { rot 0 0 0 }"); lang/*.po can translate "radio fuse". (eu07/maszyna#438) --- McZapkie/MOVER.h | 7 ++++-- McZapkie/Mover.cpp | 2 +- application/driverhints.cpp | 3 ++- input/command.cpp | 6 +++++ input/command.h | 3 +++ input/driverkeyboardinput.cpp | 3 +++ input/drivermouseinput.cpp | 9 +++++++ tests/unit/test_radio.cpp | 30 ++++++++++++++++++++++++ utilities/translation.cpp | 3 +++ vehicle/Driver.cpp | 2 +- vehicle/DynObj.cpp | 3 ++- vehicle/Train.cpp | 44 +++++++++++++++++++++++++++++++++-- vehicle/Train.h | 3 +++ vr/openvr_imp.cpp | 9 +++++++ 14 files changed, 119 insertions(+), 8 deletions(-) diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 199c65a0..b976174e 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1590,6 +1590,9 @@ class TMoverParameters double EpForce = 0.0; /*Poziom zadanej sily EP*/ bool Signalling = false; /*Czy jest zalaczona sygnalizacja hamowania ostatniego wagonu*/ bool Radio = false; /*Czy jest zalaczony radiotelefon*/ + // the cut-off in the radio's power supply: a fuse in the cabinet, a lever on the desk or the switch on the radio's power + // supply (eu07/maszyna#438). Closed unless the driver opens it, so vehicles without such a switch work as before + bool RadioFuse = true; float NominalBatteryVoltage = 0.f; /*Winger - baterie w elektrykach*/ TDimension Dim; /*wymiary*/ double Cx = 0.0; /*wsp. op. aerodyn.*/ @@ -2473,10 +2476,10 @@ class TMoverParameters auto const oilmanual{OilPump.start_type != start_t::automatic}; return (fuelmanual || oilmanual) && (false == fuelmanual || FuelPump.is_enabled) && (false == oilmanual || OilPump.is_enabled); } - // whether the radio is switched on and has the low voltage to work + // whether the radio is switched on, its power supply isn't cut off and it has the low voltage to work bool RadioPowered() const { - return Radio && (Power24vIsAvailable || Power110vIsAvailable); + return Radio && RadioFuse && (Power24vIsAvailable || Power110vIsAvailable); } /*obrot kol uwzgledniajacy poslizg*/ double ComputeRotatingWheel(double WForce, double dt, double n) const; diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 330e8eb8..dae4996a 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -3145,7 +3145,7 @@ void TMoverParameters::SecuritySystemCheck(double dt) bool isPower = Power24vIsAvailable || Power110vIsAvailable; SecuritySystem.update(dt, Vel, isPower, CabActive); - if (!Battery || !Radio) + if (!Battery || !Radio || !RadioFuse) { // wyłączenie baterii deaktywuje sprzęt RadiostopSwitch(false); } diff --git a/application/driverhints.cpp b/application/driverhints.cpp index bcfd7dbd..cd1a43b9 100644 --- a/application/driverhints.cpp +++ b/application/driverhints.cpp @@ -130,12 +130,13 @@ TController::cue_action( driver_hint const Action, float const Actionparameter ) case driver_hint::radioon: { if( AIControllFlag ) { mvOccupied->Radio = true; + mvOccupied->RadioFuse = true; } remove_hint( driver_hint::radiooff ); hint( Action, [this](float const /*Parameter*/) { - return mvOccupied->Radio == true; } ); + return mvOccupied->Radio && mvOccupied->RadioFuse; } ); break; } case driver_hint::radiochannel: { diff --git a/input/command.cpp b/input/command.cpp index 0ae67cfa..574d4dca 100644 --- a/input/command.cpp +++ b/input/command.cpp @@ -158,6 +158,9 @@ commanddescription_sequence Commands_descriptions = { {"radiovolumeincrease", command_target::vehicle, command_mode::oneoff}, {"radiovolumedecrease", command_target::vehicle, command_mode::oneoff}, {"radiovolumeset", command_target::vehicle, command_mode::oneoff}, + {"radiofusetoggle", command_target::vehicle, command_mode::oneoff}, + {"radiofuseenable", command_target::vehicle, command_mode::oneoff}, + {"radiofusedisable", command_target::vehicle, command_mode::oneoff}, {"cabchangeforward", command_target::vehicle, command_mode::oneoff}, {"cabchangebackward", command_target::vehicle, command_mode::oneoff}, {"modernlightdimmerdecrease", command_target::vehicle, command_mode::oneoff}, @@ -544,6 +547,9 @@ std::unordered_map const commandMap = { {"radiovolumeincrease", user_command::radiovolumeincrease}, {"radiovolumedecrease", user_command::radiovolumedecrease}, {"radiovolumeset", user_command::radiovolumeset}, + {"radiofusetoggle", user_command::radiofusetoggle}, + {"radiofuseenable", user_command::radiofuseenable}, + {"radiofusedisable", user_command::radiofusedisable}, {"cabchangeforward", user_command::cabchangeforward}, {"cabchangebackward", user_command::cabchangebackward}, {"viewturn", user_command::viewturn}, diff --git a/input/command.h b/input/command.h index ddacef4a..540bfc8f 100644 --- a/input/command.h +++ b/input/command.h @@ -151,6 +151,9 @@ enum class user_command radiovolumeincrease, radiovolumedecrease, radiovolumeset, + radiofusetoggle, + radiofuseenable, + radiofusedisable, cabchangeforward, cabchangebackward, diff --git a/input/driverkeyboardinput.cpp b/input/driverkeyboardinput.cpp index e7e636b3..047f3678 100644 --- a/input/driverkeyboardinput.cpp +++ b/input/driverkeyboardinput.cpp @@ -160,6 +160,9 @@ driverkeyboard_input::default_bindings() { // radiovolumeincrease, // radiovolumedecrease, // radiovolumeset, + // radiofusetoggle, + // radiofuseenable, + // radiofusedisable, { cabchangeforward, {GLFW_KEY_HOME, ""} }, { cabchangebackward, {GLFW_KEY_END, ""} }, // viewturn, diff --git a/input/drivermouseinput.cpp b/input/drivermouseinput.cpp index 22562b85..8c9763bf 100644 --- a/input/drivermouseinput.cpp +++ b/input/drivermouseinput.cpp @@ -783,6 +783,15 @@ drivermouse_input::default_bindings() { { "radiooff_sw:", { radiodisable, none } }, + { "radiofuse_sw:", { + radiofusetoggle, + none } }, + { "radiofuseon_sw:", { + radiofuseenable, + none } }, + { "radiofuseoff_sw:", { + radiofusedisable, + none } }, { "radiochannel_sw:", { radiochannelincrease, radiochanneldecrease } }, diff --git a/tests/unit/test_radio.cpp b/tests/unit/test_radio.cpp index 33a12f72..b65cc2ce 100644 --- a/tests/unit/test_radio.cpp +++ b/tests/unit/test_radio.cpp @@ -26,3 +26,33 @@ TEST_CASE("radio: a radio switched off or without the low voltage doesn't") { } CHECK_FALSE(vehicle->RadioPowered()); } + +// the cut-off in the radio's power supply (eu07/maszyna#438): a fuse, a desk lever or the switch on the radio's +// power supply, closed unless the driver opens it + +TEST_CASE("radio: the radio fuse is closed by default") { + test::vehicle vehicle{test::definition::load("wagon")}; + CHECK(vehicle->RadioFuse); +} + +TEST_CASE("radio: an opened radio fuse cuts the radio off") { + test::vehicle vehicle{test::definition::load("wagon")}; + vehicle->Radio = true; + vehicle->Power24vIsAvailable = true; + vehicle->RadioFuse = false; + CHECK_FALSE(vehicle->RadioPowered()); + vehicle->RadioFuse = true; + CHECK(vehicle->RadioPowered()); +} + +TEST_CASE("radio: opening the radio fuse at a standstill resets the radio-stop, as switching the radio off does") { + test::vehicle loco{test::definition::fiz("4e_v1/4e")}; + loco->Battery = true; + loco->Radio = true; + REQUIRE(loco->RadiostopSwitch(true)); + loco->SecuritySystemCheck(0.1); + CHECK(loco->RadioStopFlag); + loco->RadioFuse = false; + loco->SecuritySystemCheck(0.1); + CHECK_FALSE(loco->RadioStopFlag); +} diff --git a/utilities/translation.cpp b/utilities/translation.cpp index c0dbeb1a..16e07d01 100644 --- a/utilities/translation.cpp +++ b/utilities/translation.cpp @@ -271,6 +271,9 @@ std::string locale::label_cab_control(std::string const &Label) { "converteroff_sw:", STRN("converter") }, { "main_sw:", STRN("line breaker") }, { "radio_sw:", STRN("radio") }, + { "radiofuse_sw:", STRN("radio fuse") }, + { "radiofuseon_sw:", STRN("radio fuse") }, + { "radiofuseoff_sw:", STRN("radio fuse") }, { "radiochannel_sw:", STRN("radio channel") }, { "radiochannelprev_sw:", STRN("radio channel") }, { "radiochannelnext_sw:", STRN("radio channel") }, diff --git a/vehicle/Driver.cpp b/vehicle/Driver.cpp index 08f0c0d2..0de55551 100644 --- a/vehicle/Driver.cpp +++ b/vehicle/Driver.cpp @@ -6294,7 +6294,7 @@ TController::control_security_system( double const Timedelta ) { } } if( iEngineActive - && false == mvOccupied->Radio + && ( false == mvOccupied->Radio || false == mvOccupied->RadioFuse ) && false == mvOccupied->RadioStopFlag ) { // otherwise if it's safe to do so, turn the radio back on // arbitrary 5 sec delay before switching radio back on diff --git a/vehicle/DynObj.cpp b/vehicle/DynObj.cpp index d5f60e33..89359fc3 100644 --- a/vehicle/DynObj.cpp +++ b/vehicle/DynObj.cpp @@ -7197,7 +7197,8 @@ void TDynamicObject::RadioStop() if( Mechanik ) { // o ile ktoś go prowadzi if( MoverParameters->SecuritySystem.radiostop_available() - && MoverParameters->Radio ) { + && MoverParameters->Radio + && MoverParameters->RadioFuse ) { // jeśli pojazd ma RadioStop i jest on aktywny // HACK cast until math types unification glm::dvec3 pos = static_cast(vPosition); diff --git a/vehicle/Train.cpp b/vehicle/Train.cpp index 201b8972..bc0924ce 100644 --- a/vehicle/Train.cpp +++ b/vehicle/Train.cpp @@ -485,6 +485,9 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { {user_command::radiovolumeincrease, &TTrain::OnCommand_radiovolumeincrease}, {user_command::radiovolumedecrease, &TTrain::OnCommand_radiovolumedecrease}, {user_command::radiovolumeset, &TTrain::OnCommand_radiovolumeset}, + {user_command::radiofusetoggle, &TTrain::OnCommand_radiofusetoggle}, + {user_command::radiofuseenable, &TTrain::OnCommand_radiofuseenable}, + {user_command::radiofusedisable, &TTrain::OnCommand_radiofusedisable}, {user_command::cabchangeforward, &TTrain::OnCommand_cabchangeforward}, {user_command::cabchangebackward, &TTrain::OnCommand_cabchangebackward}, {user_command::generictoggle0, &TTrain::OnCommand_generictoggle}, @@ -785,6 +788,7 @@ std::shared_ptr TTrain::GetTrainState(dictionary_source const } } dict->insert("radio", mvOccupied->Radio); + dict->insert("radio_fuse", mvOccupied->RadioFuse); dict->insert("radio_channel", RadioChannel()); dict->insert("radio_volume", m_radiovolume); dict->insert("door_lock", mvOccupied->Doors.lock_enabled); @@ -8032,6 +8036,41 @@ void TTrain::OnCommand_radiodisable(TTrain *Train, command_data const &Command) } } +// the cut-off in the radio's power supply (eu07/maszyna#438); opening it works like switching the radio off, the +// radio-stop flag included +void TTrain::OnCommand_radiofusetoggle(TTrain *Train, command_data const &Command) +{ + if (Command.action != GLFW_PRESS) + { + return; + } + + if (Train->mvOccupied->RadioFuse) + { + OnCommand_radiofusedisable(Train, Command); + } + else + { + OnCommand_radiofuseenable(Train, Command); + } +} + +void TTrain::OnCommand_radiofuseenable(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + Train->mvOccupied->RadioFuse = true; + } +} + +void TTrain::OnCommand_radiofusedisable(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + Train->mvOccupied->RadioFuse = false; + } +} + void TTrain::OnCommand_radiochannelincrease(TTrain *Train, command_data const &Command) { @@ -9053,9 +9092,9 @@ bool TTrain::Update(double const Deltatime) // KURS90 btLampkaMaxSila.Turn(abs(mvControlled->Im) >= 350); btLampkaPrzekrMaxSila.Turn(abs(mvControlled->Im) >= 450); - btLampkaRadio.Turn(mvOccupied->Radio); + btLampkaRadio.Turn(mvOccupied->Radio && mvOccupied->RadioFuse); btLampkaRadioMessage.Turn(radio_message_played); - btLampkaRadioStop.Turn(mvOccupied->Radio && mvOccupied->RadioStopFlag); + btLampkaRadioStop.Turn(mvOccupied->Radio && mvOccupied->RadioFuse && mvOccupied->RadioStopFlag); btLampkaHamulecReczny.Turn(mvOccupied->ManualBrakePos > 0); // NBMX wrzesien 2003 - drzwi oraz sygnał odjazdu if (DynamicObject->Mechanik != nullptr) @@ -11962,6 +12001,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con {"pantfrontoff_sw:", &mvPantographUnit->Pantographs[end::front].valve.is_disabled}, {"pantrearoff_sw:", &mvPantographUnit->Pantographs[end::rear].valve.is_disabled}, {"radio_sw:", &mvOccupied->Radio}, + {"radiofuse_sw:", &mvOccupied->RadioFuse}, {"cablight_sw:", &Cabine[iCabn].bLight}, {"springbraketoggle_bt:", &mvOccupied->SpringBrake.Activate}, {"couplingdisconnect_sw:", &m_couplingdisconnect}, diff --git a/vehicle/Train.h b/vehicle/Train.h index 009b349b..7071bf21 100644 --- a/vehicle/Train.h +++ b/vehicle/Train.h @@ -489,6 +489,9 @@ class TTrain { static void OnCommand_radiovolumeincrease(TTrain *Train, command_data const &Command); static void OnCommand_radiovolumedecrease(TTrain *Train, command_data const &Command); static void OnCommand_radiovolumeset(TTrain *Train, command_data const &Command); + static void OnCommand_radiofusetoggle(TTrain *Train, command_data const &Command); + static void OnCommand_radiofuseenable(TTrain *Train, command_data const &Command); + static void OnCommand_radiofusedisable(TTrain *Train, command_data const &Command); static void OnCommand_cabchangeforward( TTrain *Train, command_data const &Command ); static void OnCommand_cabchangebackward( TTrain *Train, command_data const &Command ); static void OnCommand_generictoggle( TTrain *Train, command_data const &Command ); diff --git a/vr/openvr_imp.cpp b/vr/openvr_imp.cpp index 15467d00..14f901f5 100644 --- a/vr/openvr_imp.cpp +++ b/vr/openvr_imp.cpp @@ -669,6 +669,15 @@ std::unordered_map vr_openvr::m_buttonb { "radiooff_sw:", { user_command::radiodisable, user_command::none } }, + { "radiofuse_sw:", { + user_command::radiofusetoggle, + user_command::none } }, + { "radiofuseon_sw:", { + user_command::radiofuseenable, + user_command::none } }, + { "radiofuseoff_sw:", { + user_command::radiofusedisable, + user_command::none } }, { "radiochannel_sw:", { user_command::radiochannelincrease, user_command::radiochanneldecrease } }, From 43fc80f45244b891c322e5ce11e5ad6649fdd934 Mon Sep 17 00:00:00 2001 From: jerrrrycho Date: Sun, 8 Nov 2026 17:52:39 +0100 Subject: [PATCH 2/2] fix: radio fuse review: working push buttons, own hint, HUD - radioon_sw:/radiooff_sw:/radiofuseon_sw:/radiofuseoff_sw: are now loaded as push-button gauges in initialize_gauge, so they can be clicked; the enable/disable commands press them while held. radiotoggle and radiofusetoggle flip the state directly, so they don't move them. - New driver hint "Close radio fuse" (radiofuseon); "Switch on radio" is given only when the radio's own switch is off. - The HUD shows the radio channel only with the fuse closed. (eu07/maszyna#438) --- application/driverhints.cpp | 13 ++++- application/driverhints_def.h | 1 + application/driveruipanels.cpp | 2 +- utilities/translation.cpp | 2 + vehicle/Driver.cpp | 9 +++- vehicle/Train.cpp | 97 +++++++++++++++++++++++----------- vehicle/Train.h | 4 ++ 7 files changed, 94 insertions(+), 34 deletions(-) diff --git a/application/driverhints.cpp b/application/driverhints.cpp index cd1a43b9..ae39ede7 100644 --- a/application/driverhints.cpp +++ b/application/driverhints.cpp @@ -130,13 +130,22 @@ TController::cue_action( driver_hint const Action, float const Actionparameter ) case driver_hint::radioon: { if( AIControllFlag ) { mvOccupied->Radio = true; - mvOccupied->RadioFuse = true; } remove_hint( driver_hint::radiooff ); hint( Action, [this](float const /*Parameter*/) { - return mvOccupied->Radio && mvOccupied->RadioFuse; } ); + return mvOccupied->Radio == true; } ); + break; + } + case driver_hint::radiofuseon: { + if( AIControllFlag ) { + mvOccupied->RadioFuse = true; + } + hint( + Action, + [this](float const /*Parameter*/) { + return mvOccupied->RadioFuse == true; } ); break; } case driver_hint::radiochannel: { diff --git a/application/driverhints_def.h b/application/driverhints_def.h index f59ed734..2ce89667 100644 --- a/application/driverhints_def.h +++ b/application/driverhints_def.h @@ -2,6 +2,7 @@ DRIVER_HINT_DEF(batteryon, STRN("Switch on battery")) DRIVER_HINT_DEF(batteryoff, STRN("Switch off battery")) DRIVER_HINT_DEF(radioon, STRN("Switch on radio")) DRIVER_HINT_DEF(radiooff, STRN("Switch off radio")) +DRIVER_HINT_DEF(radiofuseon, STRN("Close radio fuse")) DRIVER_HINT_DEF(radiochannel, STRN("Tune into channel %.0f")) DRIVER_HINT_DEF(oilpumpon, STRN("Switch on oil pump")) DRIVER_HINT_DEF(oilpumpoff, STRN("Switch off oil pump")) diff --git a/application/driveruipanels.cpp b/application/driveruipanels.cpp index e318d356..8186b82c 100644 --- a/application/driveruipanels.cpp +++ b/application/driveruipanels.cpp @@ -810,7 +810,7 @@ debug_panel::update_section_vehicle( std::vector &Output ) { mover.HeatingAllow ? 'h' : '.', mover.Hamulec->Releaser() ? '^' : '.', - std::string( m_input.mechanik ? STR(" R") + ( mover.Radio ? std::to_string( m_input.mechanik->iRadioChannel ) : "-" ) : "" ).c_str(), + std::string( m_input.mechanik ? STR(" R") + ( mover.Radio && mover.RadioFuse ? std::to_string( m_input.mechanik->iRadioChannel ) : "-" ) : "" ).c_str(), std::string( isdieselenginepowered ? STR(" oil pressure: ") + to_string( mover.OilPump.pressure, 2 ) : "" ).c_str(), // power transfers // 3000v diff --git a/utilities/translation.cpp b/utilities/translation.cpp index 16e07d01..14fd709f 100644 --- a/utilities/translation.cpp +++ b/utilities/translation.cpp @@ -271,6 +271,8 @@ std::string locale::label_cab_control(std::string const &Label) { "converteroff_sw:", STRN("converter") }, { "main_sw:", STRN("line breaker") }, { "radio_sw:", STRN("radio") }, + { "radioon_sw:", STRN("radio") }, + { "radiooff_sw:", STRN("radio") }, { "radiofuse_sw:", STRN("radio fuse") }, { "radiofuseon_sw:", STRN("radio fuse") }, { "radiofuseoff_sw:", STRN("radio fuse") }, diff --git a/vehicle/Driver.cpp b/vehicle/Driver.cpp index 0de55551..9eb3b3b5 100644 --- a/vehicle/Driver.cpp +++ b/vehicle/Driver.cpp @@ -2689,6 +2689,7 @@ bool TController::PrepareEngine() cue_action( driver_hint::batteryon ); cue_action( driver_hint::cabactivation); + cue_action( driver_hint::radiofuseon ); cue_action( driver_hint::radioon ); if( has_diesel_engine() ) { @@ -6300,7 +6301,13 @@ TController::control_security_system( double const Timedelta ) { // arbitrary 5 sec delay before switching radio back on m_radiocontroltime = std::min( m_radiocontroltime, 5.0 ); if( m_radiocontroltime < 0.0 ) { - cue_action( driver_hint::radioon ); + // hint at whichever of the two is open, the radio's switch or the cut-off in its power supply + if( false == mvOccupied->RadioFuse ) { + cue_action( driver_hint::radiofuseon ); + } + if( false == mvOccupied->Radio ) { + cue_action( driver_hint::radioon ); + } } else { m_radiocontroltime -= Timedelta; diff --git a/vehicle/Train.cpp b/vehicle/Train.cpp index bc0924ce..1b10f755 100644 --- a/vehicle/Train.cpp +++ b/vehicle/Train.cpp @@ -7998,41 +7998,47 @@ void TTrain::OnCommand_radiotoggle(TTrain *Train, command_data const &Command) // NOTE: works without the switch in the 3d model too, to allow system reset after receiving radio-stop signal // only reacting to press, so the sound can loop uninterrupted - if (false == Train->mvOccupied->Radio) - { - // turn on - OnCommand_radioenable(Train, Command); - } - else - { - // turn off - OnCommand_radiodisable(Train, Command); - } + // NOTE: flips the state directly rather than through radioenable/radiodisable, so it doesn't move the radioon_sw:/radiooff_sw: buttons + Train->mvOccupied->Radio = (false == Train->mvOccupied->Radio); } void TTrain::OnCommand_radioenable(TTrain *Train, command_data const &Command) { - if (Command.action != GLFW_PRESS) - { - return; - } - - if (false == Train->mvOccupied->Radio) + if (Command.action == GLFW_PRESS) { Train->mvOccupied->Radio = true; + // visual feedback + if (Train->m_controlmapper.contains("radioon_sw:")) + { + Train->ggRadioOnButton.UpdateValue(1.0f, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + if (Train->m_controlmapper.contains("radioon_sw:")) + { + Train->ggRadioOnButton.UpdateValue(0.0f, Train->dsbSwitch); + } } } void TTrain::OnCommand_radiodisable(TTrain *Train, command_data const &Command) { - if (Command.action != GLFW_PRESS) - { - return; - } - - if (Train->mvOccupied->Radio) + if (Command.action == GLFW_PRESS) { Train->mvOccupied->Radio = false; + // visual feedback + if (Train->m_controlmapper.contains("radiooff_sw:")) + { + Train->ggRadioOffButton.UpdateValue(1.0f, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + if (Train->m_controlmapper.contains("radiooff_sw:")) + { + Train->ggRadioOffButton.UpdateValue(0.0f, Train->dsbSwitch); + } } } @@ -8045,14 +8051,9 @@ void TTrain::OnCommand_radiofusetoggle(TTrain *Train, command_data const &Comman return; } - if (Train->mvOccupied->RadioFuse) - { - OnCommand_radiofusedisable(Train, Command); - } - else - { - OnCommand_radiofuseenable(Train, Command); - } + // NOTE: flips the state directly rather than through radiofuseenable/radiofusedisable, so it doesn't move the + // radiofuseon_sw:/radiofuseoff_sw: buttons + Train->mvOccupied->RadioFuse = (false == Train->mvOccupied->RadioFuse); } void TTrain::OnCommand_radiofuseenable(TTrain *Train, command_data const &Command) @@ -8060,6 +8061,18 @@ void TTrain::OnCommand_radiofuseenable(TTrain *Train, command_data const &Comman if (Command.action == GLFW_PRESS) { Train->mvOccupied->RadioFuse = true; + // visual feedback + if (Train->m_controlmapper.contains("radiofuseon_sw:")) + { + Train->ggRadioFuseOnButton.UpdateValue(1.0f, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + if (Train->m_controlmapper.contains("radiofuseon_sw:")) + { + Train->ggRadioFuseOnButton.UpdateValue(0.0f, Train->dsbSwitch); + } } } @@ -8068,6 +8081,18 @@ void TTrain::OnCommand_radiofusedisable(TTrain *Train, command_data const &Comma if (Command.action == GLFW_PRESS) { Train->mvOccupied->RadioFuse = false; + // visual feedback + if (Train->m_controlmapper.contains("radiofuseoff_sw:")) + { + Train->ggRadioFuseOffButton.UpdateValue(1.0f, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + if (Train->m_controlmapper.contains("radiofuseoff_sw:")) + { + Train->ggRadioFuseOffButton.UpdateValue(0.0f, Train->dsbSwitch); + } } } @@ -9562,6 +9587,10 @@ bool TTrain::Update(double const Deltatime) ggRadioVolumeSelector.Update(); ggRadioVolumePrevious.Update(); ggRadioVolumeNext.Update(); + ggRadioOnButton.Update(); + ggRadioOffButton.Update(); + ggRadioFuseOnButton.Update(); + ggRadioFuseOffButton.Update(); ggDepartureSignalButton.Update(); /* ggPantFrontButton.Update(); @@ -11102,6 +11131,10 @@ void TTrain::clear_cab_controls() ggRadioVolumeSelector.Clear(); ggRadioVolumePrevious.Clear(); ggRadioVolumeNext.Clear(); + ggRadioOnButton.Clear(); + ggRadioOffButton.Clear(); + ggRadioFuseOnButton.Clear(); + ggRadioFuseOffButton.Clear(); ggDoorLeftPermitButton.Clear(); ggDoorRightPermitButton.Clear(); ggDoorPermitPresetButton.Clear(); @@ -11844,6 +11877,10 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con {"radiovolume_sw:", ggRadioVolumeSelector}, {"radiovolumeprev_sw:", ggRadioVolumePrevious}, {"radiovolumenext_sw:", ggRadioVolumeNext}, + {"radioon_sw:", ggRadioOnButton}, + {"radiooff_sw:", ggRadioOffButton}, + {"radiofuseon_sw:", ggRadioFuseOnButton}, + {"radiofuseoff_sw:", ggRadioFuseOffButton}, /* { "pantfront_sw:", ggPantFrontButton }, { "pantrear_sw:", ggPantRearButton }, diff --git a/vehicle/Train.h b/vehicle/Train.h index 7071bf21..9deacc9b 100644 --- a/vehicle/Train.h +++ b/vehicle/Train.h @@ -598,6 +598,10 @@ public: // reszta może by?publiczna TGauge ggRadioVolumeSelector; TGauge ggRadioVolumePrevious; TGauge ggRadioVolumeNext; + TGauge ggRadioOnButton; + TGauge ggRadioOffButton; + TGauge ggRadioFuseOnButton; + TGauge ggRadioFuseOffButton; TGauge ggUpperLightButton; TGauge ggLeftLightButton; TGauge ggRightLightButton;