diff --git a/CMakeLists.txt b/CMakeLists.txt index 56cf1bce..c2c2e090 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,6 +98,14 @@ set(SOURCES "world/Traction.cpp" "world/TractionPower.cpp" "vehicle/Train.cpp" +"vehicle/Train_Commands_Auxiliary.cpp" +"vehicle/Train_Commands_Brakes.cpp" +"vehicle/Train_Commands_Controls.cpp" +"vehicle/Train_Commands_Doors.cpp" +"vehicle/Train_Commands_Electrical.cpp" +"vehicle/Train_Commands_Lights.cpp" +"vehicle/Train_Commands_Misc.cpp" +"vehicle/Train_Commands_Radio.cpp" "world/TrkFoll.cpp" "vehicle/AirCoupler.cpp" "model/AnimModel.cpp" diff --git a/vehicle/AirCoupler.cpp b/vehicle/AirCoupler.cpp index 81253d60..4d913461 100644 --- a/vehicle/AirCoupler.cpp +++ b/vehicle/AirCoupler.cpp @@ -7,7 +7,6 @@ obtain one at http://mozilla.org/MPL/2.0/. */ -#include "stdafx.h" #include "vehicle/AirCoupler.h" #include "model/Model3d.h" diff --git a/vehicle/Button.cpp b/vehicle/Button.cpp index d4d31877..fd981c02 100644 --- a/vehicle/Button.cpp +++ b/vehicle/Button.cpp @@ -14,7 +14,6 @@ http://mozilla.org/MPL/2.0/. #include "vehicle/DynObj.h" #include "Console.h" #include "utilities/Logs.h" -#include "rendering/renderer.h" void TButton::Clear(int i) { diff --git a/vehicle/Driver.h b/vehicle/Driver.h index e7c4fac0..3524c3f5 100644 --- a/vehicle/Driver.h +++ b/vehicle/Driver.h @@ -16,7 +16,6 @@ http://mozilla.org/MPL/2.0/. #include "audio/sound.h" #include "vehicle/DynObj.h" #include "world/mtable.h" -#include "utilities/translation.h" #include "application/driverhints.h" auto const EU07_AI_ACCELERATION = 0.05; diff --git a/vehicle/DynObj.cpp b/vehicle/DynObj.cpp index 184d432a..5fedf2d1 100644 --- a/vehicle/DynObj.cpp +++ b/vehicle/DynObj.cpp @@ -17,7 +17,6 @@ http://mozilla.org/MPL/2.0/. #include "simulation/simulation.h" #include "rendering/lightarray.h" -#include "vehicle/Camera.h" #include "vehicle/Train.h" #include "vehicle/Driver.h" #include "utilities/Globals.h" @@ -32,7 +31,6 @@ http://mozilla.org/MPL/2.0/. #include "rendering/renderer.h" #include "application/uitranscripts.h" #include "input/messaging.h" -#include "vehicle/Driver.h" // Ra: taki zapis funkcjonuje lepiej, ale może nie jest optymalny #define vWorldFront glm::vec3(0, 0, 1) diff --git a/vehicle/Train.cpp b/vehicle/Train.cpp index 45f020b6..942a2fbe 100644 --- a/vehicle/Train.cpp +++ b/vehicle/Train.cpp @@ -40,6 +40,10 @@ extern user_command command; } */ + +auto const EU07_CONTROLLER_BASERETURNDELAY{0.5f}; +auto const EU07_CONTROLLER_KEYBOARDETURNDELAY{1.5f}; + void control_mapper::clear() { @@ -1084,7315 +1088,6 @@ TDynamicObject *TTrain::find_nearest_consist_vehicle(bool freefly, glm::vec3 pos return vehicle; } -// command handlers -void TTrain::OnCommand_aidriverenable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // on press - if (Train->DynamicObject->Mechanik == nullptr) - { - return; - } - - if (true == Train->DynamicObject->Mechanik->AIControllFlag) - { - // żeby nie trzeba było rozłączać dla zresetowania - Train->DynamicObject->Mechanik->TakeControl(false); - } - Train->DynamicObject->Mechanik->TakeControl(true); - } -} - -void TTrain::OnCommand_aidriverdisable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // on press - - if (Train->DynamicObject->Mechanik) - Train->DynamicObject->Mechanik->TakeControl(false); - } -} - -auto const EU07_CONTROLLER_BASERETURNDELAY{0.5f}; -auto const EU07_CONTROLLER_KEYBOARDETURNDELAY{1.5f}; - -void TTrain::OnCommand_jointcontrollerset(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - // on press or hold - // value controls brake in range 0-0.5, master controller in range 0.5-1.0 - if (Command.param1 >= 0.5) - { - Train->set_master_controller((Command.param1 * 2 - 1) * - (Train->mvControlled->CoupledCtrl ? Train->mvControlled->MainCtrlPosNo + Train->mvControlled->ScndCtrlPosNo : Train->mvControlled->MainCtrlPosNo)); - Train->m_mastercontrollerinuse = true; - // when SplitEDPneumaticBrake is active the joint controller's negative range - // commands the dedicated dynamic-brake lever instead of the local pneumatic brake - if (Train->mvControlled->SplitEDPneumaticBrake) - { - Train->mvControlled->DynamicBrakeLevelSet(0.0); - } - else - { - Train->mvOccupied->LocalBrakePosA = 0; - } - } - else - { - auto const negativeRange{std::clamp(1.0 - Command.param1 * 2, 0.0, 1.0)}; - if (Train->mvControlled->SplitEDPneumaticBrake) - { - // negative range of jointctrl drives only ED braking, local pneumatic brake stays untouched. - // snap to DBPN discrete stops so the lever animates step-by-step - auto const stepCount{std::max(1, Train->mvControlled->DynamicBrakeCtrlPosNo)}; - auto const snapped{std::round(negativeRange * stepCount) / stepCount}; - Train->mvControlled->DynamicBrakeLevelSet(snapped); - } - else - { - Train->mvOccupied->LocalBrakePosA = negativeRange; - } - if (Train->mvControlled->MainCtrlPowerPos() > 0) - { - Train->set_master_controller(Train->mvControlled->MainCtrlNoPowerPos()); - } - } - } - else - { - // release - Train->m_mastercontrollerinuse = false; - Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_BASERETURNDELAY; // NOTE: keyboard return delay is omitted for other input sources - } -} - -void TTrain::OnCommand_mastercontrollerincrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - // on press or hold - auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; - // when SplitEDPneumaticBrake is true the joint controller's negative range maps - // to the dedicated dynamic-brake lever (DynamicBrakeCtrl) rather than to LocalBrake - auto const negativeRangeActive{splitMode ? Train->mvControlled->DynamicBrakeCtrlPos > 0.0 : Train->mvOccupied->LocalBrakePosA > 0.0}; - if (Train->ggJointCtrl.SubModel != nullptr && negativeRangeActive) - { - if (splitMode) - { - OnCommand_DynamicBrakeControllerDecrease(Train, Command); - Train->m_mastercontrollerinuse = true; - } - else - { - OnCommand_independentbrakedecrease(Train, Command); - } - } - else - { - Train->mvControlled->IncMainCtrl(1); - Train->m_mastercontrollerinuse = true; - } - } - else if (Command.action == GLFW_RELEASE) - { - // release - Train->m_mastercontrollerinuse = false; - Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_KEYBOARDETURNDELAY + EU07_CONTROLLER_BASERETURNDELAY; - } -} - -void TTrain::OnCommand_mastercontrollerincreasefast(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - // on press or hold - auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; - auto const negativeRangeActive{splitMode ? Train->mvControlled->DynamicBrakeCtrlPos > 0.0 : Train->mvOccupied->LocalBrakePosA > 0.0}; - if (Train->ggJointCtrl.SubModel != nullptr && negativeRangeActive) - { - if (splitMode) - { - OnCommand_DynamicBrakeControllerDecreaseFast(Train, Command); - Train->m_mastercontrollerinuse = true; - } - else - { - OnCommand_independentbrakedecreasefast(Train, Command); - } - } - else - { - Train->mvControlled->IncMainCtrl(Train->mvControlled->MainCtrlPosNo); - Train->m_mastercontrollerinuse = true; - } - } - else - { - // release - Train->m_mastercontrollerinuse = false; - Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_KEYBOARDETURNDELAY + EU07_CONTROLLER_BASERETURNDELAY; - } -} - -void TTrain::OnCommand_mastercontrollerdecrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - // on press or hold - auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; - if (Train->ggJointCtrl.SubModel != nullptr && Train->mvControlled->IsMainCtrlNoPowerPos()) - { - // negative range of jointctrl: ED brake when split, otherwise pneumatic local brake - if (splitMode) - { - OnCommand_DynamicBrakeControllerIncrease(Train, Command); - Train->m_mastercontrollerinuse = true; - } - else - { - OnCommand_independentbrakeincrease(Train, Command); - } - } - else - { - Train->mvControlled->DecMainCtrl(1); - Train->m_mastercontrollerinuse = true; - } - } - else if (Command.action == GLFW_RELEASE) - { - // release - Train->m_mastercontrollerinuse = false; - Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_KEYBOARDETURNDELAY + EU07_CONTROLLER_BASERETURNDELAY; - } -} - -void TTrain::OnCommand_mastercontrollerdecreasefast(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - // on press or hold - auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; - if (Train->ggJointCtrl.SubModel != nullptr && Train->mvControlled->IsMainCtrlNoPowerPos()) - { - if (splitMode) - { - OnCommand_DynamicBrakeControllerIncreaseFast(Train, Command); - Train->m_mastercontrollerinuse = true; - } - else - { - OnCommand_independentbrakeincreasefast(Train, Command); - } - } - else - { - Train->mvControlled->DecMainCtrl(Train->mvControlled->MainCtrlPowerPos()); - Train->m_mastercontrollerinuse = true; - } - } - else - { - // release - Train->m_mastercontrollerinuse = false; - Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_KEYBOARDETURNDELAY + EU07_CONTROLLER_BASERETURNDELAY; - } -} - -void TTrain::OnCommand_mastercontrollerset(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - // on press or hold - Train->set_master_controller(Command.param1); - Train->m_mastercontrollerinuse = true; - } - else - { - // release - Train->m_mastercontrollerinuse = false; - Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_BASERETURNDELAY; // NOTE: keyboard return delay is omitted for other input sources - } -} -void TTrain::OnCommand_DynamicBrakeControllerIncrease(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_RELEASE) - { - return; - } - if (false == Train->mvControlled->SplitEDPneumaticBrake) - { - return; - } - - // step exactly one stop (1 / DBPN) per command, matching the discrete behaviour of jointctrl - Train->mvControlled->IncDynamicBrakeLevel(1.0f); -} - -void TTrain::OnCommand_DynamicBrakeControllerIncreaseFast(TTrain *Train, command_data const &Command) -{ - if (Command.action != GLFW_PRESS) - { - return; - } - if (false == Train->mvControlled->SplitEDPneumaticBrake) - { - return; - } - - Train->mvControlled->IncDynamicBrakeLevel(static_cast(Train->mvControlled->DynamicBrakeCtrlPosNo)); -} - -void TTrain::OnCommand_DynamicBrakeControllerDecrease(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_RELEASE) - { - return; - } - if (false == Train->mvControlled->SplitEDPneumaticBrake) - { - return; - } - - // step exactly one stop (1 / DBPN) per command, matching the discrete behaviour of jointctrl - Train->mvControlled->DecDynamicBrakeLevel(1.0f); -} - -void TTrain::OnCommand_DynamicBrakeControllerDecreaseFast(TTrain *Train, command_data const &Command) -{ - if (Command.action != GLFW_PRESS) - { - return; - } - if (false == Train->mvControlled->SplitEDPneumaticBrake) - { - return; - } - - Train->mvControlled->DecDynamicBrakeLevel(static_cast(Train->mvControlled->DynamicBrakeCtrlPosNo)); -} - -void TTrain::OnCommand_DynamicBrakeControllerSet(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_RELEASE) - { - return; - } - if (false == Train->mvControlled->SplitEDPneumaticBrake) - { - return; - } - - // when input source uses raw 0..1 value, snap to nearest DBPN step - auto const target{std::clamp(Command.param1, 0.0, 1.0)}; - auto const stepCount{std::max(1, Train->mvControlled->DynamicBrakeCtrlPosNo)}; - auto const snapped{std::round(target * stepCount) / stepCount}; - Train->mvControlled->DynamicBrakeLevelSet(snapped); -} - -void TTrain::OnCommand_secondcontrollerincrease(TTrain *Train, command_data const &Command) -{ - - if (Train->mvControlled->EngineType == TEngineType::DieselElectric && true == Train->mvControlled->ShuntModeAllow && true == Train->mvControlled->ShuntMode) - { - if (Command.action != GLFW_RELEASE) - { - Train->mvControlled->AnPos = std::clamp(Train->mvControlled->AnPos + 0.025, 0.0, 1.0); - } - } - else - { - // regular mode - // push or pushtoggle control type - if (Train->ggScndCtrl.is_push()) - { - if (Command.action == GLFW_PRESS) - { - // activate on press - Train->mvControlled->IncScndCtrl(1); - } - } - // toggle control type - else - { - if (Command.action != GLFW_RELEASE) - { - Train->mvControlled->IncScndCtrl(1); - } - } - // HACK: potentially animate push or pushtoggle control - if (Train->ggScndCtrl.is_push()) - { - auto const activeposition{Train->ggScndCtrl.is_toggle() ? 1.f : 1.f}; - auto const neutralposition{Train->ggScndCtrl.is_toggle() ? 0.5f : 0.f}; - Train->ggScndCtrl.UpdateValue(Command.action == GLFW_RELEASE ? neutralposition : activeposition, Train->dsbSwitch); - } - // potentially animate tempomat button - if (Train->ggScndCtrlButton.is_push() && Train->mvControlled->ScndCtrlPos <= 1) - { - Train->ggScndCtrlButton.UpdateValue(Command.action == GLFW_RELEASE ? 0.f : 1.f, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_secondcontrollerincreasefast(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - // on press or hold - if (Train->mvControlled->EngineType == TEngineType::DieselElectric && true == Train->mvControlled->ShuntMode) - { - Train->mvControlled->AnPos = 1.0; - } - else - { - Train->mvControlled->IncScndCtrl(2); - } - } -} - -void TTrain::OnCommand_notchingrelaytoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->mvOccupied->AutoRelayFlag) - { - // turn on - Train->mvOccupied->AutoRelaySwitch(true); - } - else - { - // turn off - Train->mvOccupied->AutoRelaySwitch(false); - } - } -} - -void TTrain::OnCommand_tempomattoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggScndCtrlButton.is_push()) - { - // impulse switch - if (Command.action == GLFW_RELEASE) - { - // just move the button(s) back to default position - // visual feedback - Train->ggScndCtrlButton.UpdateValue(0.0, Train->dsbSwitch); - Train->ggScndCtrlOffButton.UpdateValue(0.0, Train->dsbSwitch); - return; - } - // glfw_press - if (Train->mvControlled->ScndCtrlPos == 0) - { - // turn on if it's not active - Train->mvControlled->IncScndCtrl(1); - // visual feedback - Train->ggScndCtrlButton.UpdateValue(1.0, Train->dsbSwitch); - } - else - { - // otherwise turn off - Train->mvControlled->DecScndCtrl(2); - // visual feedback - if (Train->m_controlmapper.contains("tempomatoff_sw:")) - { - Train->ggScndCtrlOffButton.UpdateValue(1.0, Train->dsbSwitch); - } - else - { - Train->ggScndCtrlButton.UpdateValue(1.0, Train->dsbSwitch); - } - } - } - else - { - // two-state switch - if (Command.action == GLFW_RELEASE) - { - return; - } - - if (Train->mvControlled->ScndCtrlPos == 0) - { - // turn on - Train->mvControlled->IncScndCtrl(1); - // visual feedback - Train->ggScndCtrlButton.UpdateValue(1.0, Train->dsbSwitch); - } - else - { - // turn off - Train->mvControlled->DecScndCtrl(2); - // visual feedback - Train->ggScndCtrlButton.UpdateValue(0.0, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_distancecounteractivate(TTrain *Train, command_data const &Command) -{ - // NOTE: distance meter activation button is presumed to be of impulse type - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggDistanceCounterButton.UpdateValue(1.0, Train->dsbSwitch); - // activate or start anew - if (Train->mvOccupied->isDoubleClickForMeasureNeeded) - { - // handler tempomatu dla podwojnego kliku - if (Train->trainLenghtMeasureTimer >= 0.f) // jesli zdazylismy w czasie sekundy - Train->m_distancecounter = 0.f; // rozpoczynamy pomiar - else - Train->trainLenghtMeasureTimer = Train->mvOccupied->DistanceCounterDoublePressPeriod; // odpalamy zegarek od nowa - } - else - { - // dla pojedynczego kliku - Train->m_distancecounter = 0.f; - } - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggDistanceCounterButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_mucurrentindicatorothersourceactivate(TTrain *Train, command_data const &Command) -{ - - if (Train->ggNextCurrentButton.SubModel == nullptr) - { - if (Command.action == GLFW_PRESS) - { - WriteLog("Current Indicator Source switch is missing, or wasn't defined"); - } - return; - } - - if (Command.action == GLFW_PRESS) - { - // turn on - Train->ShowNextCurrent = true; - // visual feedback - Train->ggNextCurrentButton.UpdateValue(1.0, Train->dsbSwitch); - } - else if (Command.action == GLFW_RELEASE) - { - // turn off - Train->ShowNextCurrent = false; - // visual feedback - Train->ggNextCurrentButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_secondcontrollerdecrease(TTrain *Train, command_data const &Command) -{ - - if (Train->mvControlled->EngineType == TEngineType::DieselElectric && true == Train->mvControlled->ShuntMode) - { - if (Command.action != GLFW_RELEASE) - { - Train->mvControlled->AnPos = std::clamp(Train->mvControlled->AnPos - 0.025, 0.0, 1.0); - } - } - else - { - // regular mode - // push or pushtoggle control type - if (Train->ggScndCtrl.is_push()) - { - // basic push control can't decrease state, but pushtoggle can - if (true == Train->ggScndCtrl.is_toggle()) - { - if (Command.action == GLFW_PRESS) - { - // activate on press - Train->mvControlled->DecScndCtrl(1); - } - } - } - // toggle control type - else - { - if (Command.action != GLFW_RELEASE) - { - Train->mvControlled->DecScndCtrl(1); - } - } - // HACK: potentially animate push or pushtoggle control - if (Train->ggScndCtrl.is_push()) - { - auto const activeposition{Train->ggScndCtrl.is_toggle() ? 0.f : 1.f}; - auto const neutralposition{Train->ggScndCtrl.is_toggle() ? 0.5f : 0.f}; - Train->ggScndCtrl.UpdateValue(Command.action == GLFW_RELEASE ? neutralposition : activeposition, Train->dsbSwitch); - } - // potentially animate tempomat button - if (Train->ggScndCtrlButton.is_push() && Train->mvControlled->ScndCtrlPos <= 1) - { - if (Train->m_controlmapper.contains("tempomatoff_sw:")) - { - Train->ggScndCtrlOffButton.UpdateValue(Command.action == GLFW_RELEASE ? 0.f : 1.f, Train->dsbSwitch); - } - else - { - Train->ggScndCtrlButton.UpdateValue(Command.action == GLFW_RELEASE ? 0.f : 1.f, Train->dsbSwitch); - } - } - } -} - -void TTrain::OnCommand_secondcontrollerdecreasefast(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - // on press or hold - if (Train->mvControlled->EngineType == TEngineType::DieselElectric && true == Train->mvControlled->ShuntMode) - { - Train->mvControlled->AnPos = 0.0; - } - else - { - Train->mvControlled->DecScndCtrl(2); - } - } -} - -void TTrain::OnCommand_secondcontrollerset(TTrain *Train, command_data const &Command) -{ - - auto const targetposition{std::min(Command.param1, Train->mvControlled->ScndCtrlPosNo)}; - // HACK: potentially animate push or pushtoggle control - if (Train->ggScndCtrl.is_push()) - { - auto const activeposition{Train->ggScndCtrl.is_toggle() ? - (targetposition < Train->mvControlled->ScndCtrlPos ? 0.f : - targetposition > Train->mvControlled->ScndCtrlPos ? 1.f : - Train->ggScndCtrl.GetDesiredValue()) : // leave the control in its current position if it hits the limit - targetposition == 0 ? 0.f : - 1.f}; - auto const neutralposition{Train->ggScndCtrl.is_toggle() ? 0.5f : 0.f}; - Train->ggScndCtrl.UpdateValue(Command.action == GLFW_RELEASE ? neutralposition : activeposition, Train->dsbSwitch); - } - // update control value - if (Command.action != GLFW_RELEASE) - { - // on press or hold - while (targetposition < Train->mvControlled->GetVirtualScndPos() && true == Train->mvControlled->DecScndCtrl(1)) - { - // all work is done in the header - ; - } - while (targetposition > Train->mvControlled->GetVirtualScndPos() && true == Train->mvControlled->IncScndCtrl(1)) - { - // all work is done in the header - ; - } - } -} - -void TTrain::OnCommand_independentbrakeincrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - - // when SplitEDPneumaticBrake is active the local brake key always operates - // the pneumatic local brake directly, never piggy-backing on the joint controller - auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; - auto const useStepped{Train->ggJointCtrl.SubModel != nullptr && !splitMode}; - if (Train->mvOccupied->LocalBrake != TLocalBrake::ManualBrake) - { - if (false == splitMode && Train->ggJointCtrl.SubModel != nullptr && Train->mvOccupied->MainCtrlPos > 0) - { - OnCommand_mastercontrollerdecrease(Train, Command); - } - else - { - Train->mvOccupied->IncLocalBrakeLevel(useStepped ? 1 : Global.brake_speed * Command.time_delta * LocalBrakePosNo); - if (useStepped) - { - Train->m_mastercontrollerinuse = true; - } - } - } - } -} - -void TTrain::OnCommand_independentbrakeincreasefast(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - - auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; - auto const useJointAnim{Train->ggJointCtrl.SubModel != nullptr && !splitMode}; - if (Train->mvOccupied->LocalBrake != TLocalBrake::ManualBrake) - { - if (false == splitMode && Train->ggJointCtrl.SubModel != nullptr && Train->mvOccupied->MainCtrlPos > 0) - { - OnCommand_mastercontrollerdecreasefast(Train, Command); - } - else - { - Train->mvOccupied->IncLocalBrakeLevel(LocalBrakePosNo); - if (useJointAnim) - { - Train->m_mastercontrollerinuse = true; - } - } - } - } -} - -void TTrain::OnCommand_independentbrakedecrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - - auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; - auto const useStepped{Train->ggJointCtrl.SubModel != nullptr && !splitMode}; - if (Train->mvOccupied->LocalBrake != TLocalBrake::ManualBrake - // Ra 1014-06: AI potrafi zahamować pomocniczym mimo jego braku - odhamować jakoś trzeba - // TODO: sort AI out so it doesn't do things it doesn't have equipment for - || Train->mvOccupied->LocalBrakePosA > 0) - { - if (false == splitMode && Train->ggJointCtrl.SubModel != nullptr && Train->mvOccupied->LocalBrakePosA == 0.0) - { - OnCommand_mastercontrollerincrease(Train, Command); - } - else - { - Train->mvOccupied->DecLocalBrakeLevel(useStepped ? 1 : Global.brake_speed * Command.time_delta * LocalBrakePosNo); - if (useStepped) - { - Train->m_mastercontrollerinuse = true; - } - } - } - } -} - -void TTrain::OnCommand_independentbrakedecreasefast(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - - auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; - auto const useJointAnim{Train->ggJointCtrl.SubModel != nullptr && !splitMode}; - if (Train->mvOccupied->LocalBrake != TLocalBrake::ManualBrake - // Ra 1014-06: AI potrafi zahamować pomocniczym mimo jego braku - odhamować jakoś trzeba - // TODO: sort AI out so it doesn't do things it doesn't have equipment for - || Train->mvOccupied->LocalBrakePosA > 0) - { - if (false == splitMode && Train->ggJointCtrl.SubModel != nullptr && Train->mvOccupied->LocalBrakePosA == 0.0) - { - OnCommand_mastercontrollerincreasefast(Train, Command); - } - else - { - Train->mvOccupied->DecLocalBrakeLevel(LocalBrakePosNo); - if (useJointAnim) - { - Train->m_mastercontrollerinuse = true; - } - } - } - } -} - -void TTrain::OnCommand_independentbrakeset(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - - Train->mvOccupied->LocalBrakePosA = std::clamp(Command.param1, 0.0, 1.0); - } - /* - Train->mvControlled->LocalBrakePos = ( - std::round( - interpolate( - 0.0, - LocalBrakePosNo, - clamp( - Command.param1, - 0.0, 1.0 ) ) ) ); - */ -} - -void TTrain::OnCommand_independentbrakebailoff(TTrain *Train, command_data const &Command) -{ - - if (false == Command.freefly) - { - // TODO: check if this set of conditions can be simplified. - // it'd be more flexible to have an attribute indicating whether bail off position is supported - if (Train->mvControlled->TrainType != dt_EZT && - (Train->mvControlled->EngineType == TEngineType::ElectricSeriesMotor || Train->mvControlled->EngineType == TEngineType::DieselElectric || - Train->mvControlled->EngineType == TEngineType::ElectricInductionMotor) && - Train->mvOccupied->BrakeCtrlPosNo > 0) - { - - if (Command.action == GLFW_PRESS) - { - // press or hold - // visual feedback - Train->ggReleaserButton.UpdateValue(1.0, Train->dsbSwitch); - - Train->mvOccupied->BrakeReleaser(1); - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - Train->ggReleaserButton.UpdateValue(0.0, Train->dsbSwitch); - - Train->mvOccupied->BrakeReleaser(0); - } - } - } - else - { - // car brake handling, while in walk mode - auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; - if (vehicle != nullptr) - { - if (Command.action == GLFW_PRESS) - { - // press or hold - vehicle->MoverParameters->BrakeReleaser(1); - } - else if (Command.action == GLFW_RELEASE) - { - // release - vehicle->MoverParameters->BrakeReleaser(0); - } - } - } -} - -void TTrain::OnCommand_universalbrakebutton1(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // press or hold - // visual feedback - Train->ggUniveralBrakeButton1.UpdateValue(1.0, Train->dsbSwitch); - - Train->mvOccupied->UniversalBrakeButton(0, 1); - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - Train->ggUniveralBrakeButton1.UpdateValue(0.0, Train->dsbSwitch); - - Train->mvOccupied->UniversalBrakeButton(0, 0); - } -} - -void TTrain::OnCommand_universalbrakebutton2(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // press or hold - // visual feedback - Train->ggUniveralBrakeButton2.UpdateValue(1.0, Train->dsbSwitch); - - Train->mvOccupied->UniversalBrakeButton(1, 1); - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - Train->ggUniveralBrakeButton2.UpdateValue(0.0, Train->dsbSwitch); - - Train->mvOccupied->UniversalBrakeButton(1, 0); - } -} - -void TTrain::OnCommand_universalbrakebutton3(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // press or hold - // visual feedback - Train->ggUniveralBrakeButton3.UpdateValue(1.0, Train->dsbSwitch); - - Train->mvOccupied->UniversalBrakeButton(2, 1); - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - Train->ggUniveralBrakeButton3.UpdateValue(0.0, Train->dsbSwitch); - - Train->mvOccupied->UniversalBrakeButton(2, 0); - } -} - -void TTrain::OnCommand_trainbrakeincrease(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_REPEAT && Train->mvOccupied->BrakeHandle == TBrakeHandle::FV4a) - Train->mvOccupied->BrakeLevelAdd(Global.brake_speed * Command.time_delta * Train->mvOccupied->BrakeCtrlPosNo); - else if (Command.action == GLFW_PRESS && Train->mvOccupied->BrakeHandle != TBrakeHandle::FV4a) - Train->set_train_brake(Train->mvOccupied->fBrakeCtrlPos + Global.fBrakeStep); -} - -void TTrain::OnCommand_trainbrakedecrease(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_REPEAT && Train->mvOccupied->BrakeHandle == TBrakeHandle::FV4a) - Train->mvOccupied->BrakeLevelAdd(-Global.brake_speed * Command.time_delta * Train->mvOccupied->BrakeCtrlPosNo); - else if (Command.action == GLFW_PRESS && Train->mvOccupied->BrakeHandle != TBrakeHandle::FV4a) - Train->set_train_brake(Train->mvOccupied->fBrakeCtrlPos - Global.fBrakeStep); - else if (Command.action == GLFW_RELEASE) - { - // release - Train->zero_charging_train_brake(); - } -} - -void TTrain::OnCommand_trainbrakeset(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - // press or hold - Train->mvOccupied->BrakeLevelSet(std::lerp(Train->mvOccupied->Handle->GetPos(bh_MIN), Train->mvOccupied->Handle->GetPos(bh_MAX), std::clamp(Command.param1, 0.0, 1.0))); - } - else - { - // release - Train->zero_charging_train_brake(); - } -} - -void TTrain::OnCommand_trainbrakecharging(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - // press or hold - Train->set_train_brake(-1); - } - else - { - // release - Train->zero_charging_train_brake(); - } -} - -void TTrain::OnCommand_trainbrakerelease(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - Train->set_train_brake(0); - } -} - -void TTrain::OnCommand_trainbrakefirstservice(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - Train->set_train_brake(1); - } -} - -void TTrain::OnCommand_trainbrakeservice(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - Train->set_train_brake(Train->mvOccupied->BrakeCtrlPosNo / 2 + (Train->mvOccupied->BrakeHandle == TBrakeHandle::FV4a ? 1 : 0)); - } -} - -void TTrain::OnCommand_trainbrakefullservice(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - Train->set_train_brake(Train->mvOccupied->BrakeCtrlPosNo - 1); - } -} - -void TTrain::OnCommand_trainbrakehandleoff(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - Train->set_train_brake(Train->mvOccupied->Handle->GetPos(bh_NP)); - } -} - -void TTrain::OnCommand_trainbrakeemergency(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - Train->set_train_brake(Train->mvOccupied->Handle->GetPos(bh_EB)); - /* - if( Train->mvOccupied->BrakeCtrlPosNo <= 0.1 ) { - // hamulec bezpieczeństwa dla wagonów - Train->mvOccupied->RadioStopFlag = true; - } - */ - } -} - -void TTrain::OnCommand_trainbrakebasepressureincrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - - switch (Train->mvOccupied->BrakeHandle) - { - case TBrakeHandle::FV4a: - { - Train->mvOccupied->BrakeCtrlPos2 = std::clamp(Train->mvOccupied->BrakeCtrlPos2 - 0.01, -1.5, 2.0); - break; - } - default: - { - Train->mvOccupied->BrakeLevelAdd(0.01); - break; - } - } - } -} - -void TTrain::OnCommand_trainbrakebasepressuredecrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - - switch (Train->mvOccupied->BrakeHandle) - { - case TBrakeHandle::FV4a: - { - Train->mvOccupied->BrakeCtrlPos2 = std::clamp(Train->mvOccupied->BrakeCtrlPos2 + 0.01, -1.5, 2.0); - break; - } - default: - { - Train->mvOccupied->BrakeLevelAdd(-0.01); - break; - } - } - } -} - -void TTrain::OnCommand_trainbrakebasepressurereset(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - Train->mvOccupied->BrakeCtrlPos2 = 0; - } -} - -void TTrain::OnCommand_trainbrakeoperationtoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; - if (vehicle == nullptr) - { - return; - } - - vehicle->MoverParameters->Hamulec->SetBrakeStatus(vehicle->MoverParameters->Hamulec->GetBrakeStatus() ^ b_dmg); - } -} - -void TTrain::OnCommand_manualbrakeincrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - - auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; - if (vehicle == nullptr) - { - return; - } - - if (vehicle->MoverParameters->LocalBrake == TLocalBrake::ManualBrake || vehicle->MoverParameters->MBrake == true) - { - - vehicle->MoverParameters->IncManualBrakeLevel(1); - } - } -} - -void TTrain::OnCommand_manualbrakedecrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_RELEASE) - { - - auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; - if (vehicle == nullptr) - { - return; - } - - if (vehicle->MoverParameters->LocalBrake == TLocalBrake::ManualBrake || vehicle->MoverParameters->MBrake == true) - { - - vehicle->MoverParameters->DecManualBrakeLevel(1); - } - } -} - -void TTrain::OnCommand_alarmchaintoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - if (false == Train->mvOccupied->AlarmChainFlag) - { - OnCommand_alarmchainenable(Train, Command); - } - else - { - OnCommand_alarmchaindisable(Train, Command); - } - } -} - -void TTrain::OnCommand_alarmchainenable(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - - // pull - Train->mvOccupied->AlarmChainSwitch(true); - // visual feedback - Train->ggAlarmChain.UpdateValue(1.0); - } -} - -void TTrain::OnCommand_alarmchaindisable(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - - // release - Train->mvOccupied->AlarmChainSwitch(false); - // visual feedback - Train->ggAlarmChain.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_wheelspinbrakeactivate(TTrain *Train, command_data const &Command) -{ - - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - if (Train->ggAntiSlipButton.SubModel == nullptr) - { - if (Command.action == GLFW_PRESS) - { - WriteLog("Wheelspin Brake button is missing, or wasn't defined"); - } - return; - } - - if (Train->mvOccupied->BrakeSystem != TBrakeSystem::ElectroPneumatic) - { - // standard behaviour - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggAntiSlipButton.UpdateValue(1.0, Train->dsbSwitch); - - // NOTE: system activation is (repeatedly) done in the train update routine - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggAntiSlipButton.UpdateValue(0.0); - } - } - else - { - // electro-pneumatic, custom case - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggAntiSlipButton.UpdateValue(1.0, Train->dsbPneumaticSwitch); - - if (Train->mvOccupied->BrakeHandle == TBrakeHandle::St113 && Train->mvControlled->EpFuse == true) - { - Train->mvOccupied->SwitchEPBrake(1); - } - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggAntiSlipButton.UpdateValue(0.0); - - Train->mvOccupied->SwitchEPBrake(0); - } - } -} - -void TTrain::OnCommand_sandboxactivate(TTrain *Train, command_data const &Command) -{ - - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - if (Train->ggSandButton.SubModel == nullptr) - { - if (Command.action == GLFW_PRESS) - { - WriteLog("Sandbox activation button is missing, or wasn't defined"); - } - return; - } - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggSandButton.UpdateValue(1.0, Train->dsbSwitch); - - Train->mvControlled->SandboxManual(true); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggSandButton.UpdateValue(0.0); - - Train->mvControlled->SandboxManual(false); - } -} - -void TTrain::OnCommand_autosandboxtoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->mvOccupied->SandDoseAutoAllow) - { - // turn on - OnCommand_autosandboxactivate(Train, Command); - } - else - { - // turn off - OnCommand_autosandboxdeactivate(Train, Command); - } - } -}; - -void TTrain::OnCommand_autosandboxactivate(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - Train->mvOccupied->SandboxAutoAllow(true); - Train->ggAutoSandButton.UpdateValue(1.0, Train->dsbSwitch); - } -}; - -void TTrain::OnCommand_autosandboxdeactivate(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - Train->mvOccupied->SandboxAutoAllow(false); - Train->ggAutoSandButton.UpdateValue(0.0, Train->dsbSwitch); - } -}; - -void TTrain::OnCommand_epbrakecontrolenable(TTrain *Train, command_data const &Command) -{ - auto const istoggle{(static_cast(Train->ggEPFuseButton.type()) & static_cast(TGaugeType::toggle)) != 0}; - if (Command.action == GLFW_PRESS) - { - // command only works for bistable switch - if (istoggle) - { - if (Train->mvOccupied->EpFuseSwitch(true)) - { - // audio feedback - if (Train->dsbPneumaticSwitch) - { - Train->dsbPneumaticSwitch->play(); - } - Train->ggEPFuseButton.UpdateValue(1.0f, Train->dsbSwitch); - }; - } - } -} - -void TTrain::OnCommand_epbrakecontroldisable(TTrain *Train, command_data const &Command) -{ - auto const istoggle{(static_cast(Train->ggEPFuseButton.type()) & static_cast(TGaugeType::toggle)) != 0}; - if (Command.action == GLFW_PRESS) - { - // command only works for bistable switch - if (istoggle) - { - if (Train->mvOccupied->EpFuseSwitch(false)) - { - Train->ggEPFuseButton.UpdateValue(0.0f, Train->dsbSwitch); - }; - } - } -} - -void TTrain::OnCommand_epbrakecontroltoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - auto const ispush{(static_cast(Train->ggEPFuseButton.type()) & static_cast(TGaugeType::push)) != 0}; - auto const istoggle{(static_cast(Train->ggEPFuseButton.type()) & static_cast(TGaugeType::toggle)) != 0}; - - if (Command.action == GLFW_PRESS) - { - if (istoggle) - { - // switch state - if (false == Train->mvOccupied->EpFuse) - { - // turn on - if (Train->mvOccupied->EpFuseSwitch(true)) - { - // audio feedback - if (Train->dsbPneumaticSwitch) - { - Train->dsbPneumaticSwitch->play(); - } - }; - } - else - { - // turn off - Train->mvOccupied->EpFuseSwitch(false); - } - } - else if (ispush) - { - // potentially turn on - if (Train->mvOccupied->EpFuseSwitch(true)) - { - // audio feedback - if (Train->dsbPneumaticSwitch) - { - Train->dsbPneumaticSwitch->play(); - } - }; - } - // visual feedback - Train->ggEPFuseButton.UpdateValue(ispush ? 1.0f : // push or pushtoggle - Train->mvOccupied->EpFuse ? 1.0f : - 0.0f, // toggle - Train->dsbSwitch); - } - else if (Command.action == GLFW_RELEASE) - { - if (ispush) - { - // return the switch to neutral position - Train->ggEPFuseButton.UpdateValue(0.0f, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_trainbrakeoperationmodeincrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if ((Train->mvOccupied->BrakeOpModeFlag << 1 & Train->mvOccupied->BrakeOpModes) != 0) - { - // next mode - Train->mvOccupied->BrakeOpModeFlag <<= 1; - // visual feedback - Train->ggBrakeOperationModeCtrl.UpdateValue(Train->mvOccupied->BrakeOpModeFlag > 0 ? std::log2(Train->mvOccupied->BrakeOpModeFlag) : 0); // audio fallback - } - } -} - -void TTrain::OnCommand_trainbrakeoperationmodedecrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if ((Train->mvOccupied->BrakeOpModeFlag >> 1 & Train->mvOccupied->BrakeOpModes) != 0) - { - // previous mode - Train->mvOccupied->BrakeOpModeFlag >>= 1; - // visual feedback - Train->ggBrakeOperationModeCtrl.UpdateValue(Train->mvOccupied->BrakeOpModeFlag > 0 ? std::log2(Train->mvOccupied->BrakeOpModeFlag) : 0); - } - } -} - -void TTrain::OnCommand_brakeactingspeedincrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; - if (vehicle == nullptr) - { - return; - } - - if ((vehicle->MoverParameters->BrakeDelayFlag & bdelay_M) != 0) - { - // can't speed it up any more than this - return; - } - auto const fasterbrakesetting = vehicle->MoverParameters->BrakeDelayFlag < bdelay_R ? vehicle->MoverParameters->BrakeDelayFlag << 1 : vehicle->MoverParameters->BrakeDelayFlag | bdelay_M; - - Train->set_train_brake_speed(vehicle, fasterbrakesetting); - } -} - -void TTrain::OnCommand_brakeactingspeeddecrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; - if (vehicle == nullptr) - { - return; - } - - if (vehicle->MoverParameters->BrakeDelayFlag == bdelay_G) - { - // can't slow it down any more than this - return; - } - auto const slowerbrakesetting = vehicle->MoverParameters->BrakeDelayFlag < bdelay_M ? vehicle->MoverParameters->BrakeDelayFlag >> 1 : vehicle->MoverParameters->BrakeDelayFlag ^ bdelay_M; - - Train->set_train_brake_speed(vehicle, slowerbrakesetting); - } -} - -void TTrain::OnCommand_brakeactingspeedsetcargo(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; - if (vehicle == nullptr) - { - return; - } - - Train->set_train_brake_speed(vehicle, bdelay_G); - } -} - -void TTrain::OnCommand_brakeactingspeedsetpassenger(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; - if (vehicle == nullptr) - { - return; - } - - Train->set_train_brake_speed(vehicle, bdelay_P); - } -} - -void TTrain::OnCommand_brakeactingspeedsetrapid(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; - if (vehicle == nullptr) - { - return; - } - - Train->set_train_brake_speed(vehicle, bdelay_R); - } -} - -void TTrain::OnCommand_brakeloadcompensationincrease(TTrain *Train, command_data const &Command) -{ - - if (true == Command.freefly && Command.action == GLFW_PRESS) - { - auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; - if (vehicle != nullptr) - { - vehicle->MoverParameters->IncBrakeMult(); - } - } -} - -void TTrain::OnCommand_brakeloadcompensationdecrease(TTrain *Train, command_data const &Command) -{ - - if (true == Command.freefly && Command.action == GLFW_PRESS) - { - auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; - if (vehicle != nullptr) - { - vehicle->MoverParameters->DecBrakeMult(); - } - } -} - -void TTrain::OnCommand_mubrakingindicatortoggle(TTrain *Train, command_data const &Command) -{ - - if (Train->ggSignallingButton.SubModel == nullptr) - { - if (Command.action == GLFW_PRESS) - { - WriteLog("Braking Indicator switch is missing, or wasn't defined"); - } - return; - } - if (Train->mvControlled->TrainType != dt_EZT) - { - // - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->mvControlled->Signalling) - { - // turn on - Train->mvControlled->Signalling = true; - // visual feedback - Train->ggSignallingButton.UpdateValue(1.0, Train->dsbSwitch); - } - else - { - // turn off - Train->mvControlled->Signalling = false; - // visual feedback - Train->ggSignallingButton.UpdateValue(0.0, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_wiperswitchincrease(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - Train->mvOccupied->wiperSwitchPos++; - if (Train->mvOccupied->wiperSwitchPos > Train->mvOccupied->WiperListSize - 1) - Train->mvOccupied->wiperSwitchPos = Train->mvOccupied->WiperListSize - 1; - - // Visual feedback - Train->ggWiperSw.UpdateValue(Train->mvOccupied->wiperSwitchPos, Train->dsbSwitch); - } -} -void TTrain::OnCommand_wiperswitchdecrease(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - Train->mvOccupied->wiperSwitchPos--; - if (Train->mvOccupied->wiperSwitchPos < 0) - Train->mvOccupied->wiperSwitchPos = 0; - - // visual feedback - Train->ggWiperSw.UpdateValue(Train->mvOccupied->wiperSwitchPos, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_reverserincrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - // HACK: master controller position isn't set in occupied vehicle in E(D)MUs - // so we do a manual check in relevant vehicle here - if (false == Train->mvControlled->EIMDirectionChangeAllow()) - { - return; - } - - if (Train->mvOccupied->DirectionForward()) - { - // aktualizacja skrajnych pojazdów w składzie - if (Train->mvOccupied->DirActive && Train->DynamicObject->Mechanik) - { - - Train->DynamicObject->Mechanik->DirectionChange(); - } - } - } -} - -void TTrain::OnCommand_reverserdecrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - // HACK: master controller position isn't set in occupied vehicle in E(D)MUs - // so we do a manual check in relevant vehicle here - if (false == Train->mvControlled->EIMDirectionChangeAllow()) - { - return; - } - - if (Train->mvOccupied->DirectionBackward()) - { - // aktualizacja skrajnych pojazdów w składzie - if (Train->mvOccupied->DirActive && Train->DynamicObject->Mechanik) - { - - Train->DynamicObject->Mechanik->DirectionChange(); - ; - } - } - } -} - -void TTrain::OnCommand_reverserforwardhigh(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - // HACK: master controller position isn't set in occupied vehicle in E(D)MUs - // so we do a manual check in relevant vehicle here - if (false == Train->mvControlled->EIMDirectionChangeAllow()) - { - return; - } - - // HACK: try to move the reverser one position back, in case it's set to "high forward" - OnCommand_reverserdecrease(Train, Command); - - if (Train->mvOccupied->DirActive < 1) - { - - while (Train->mvOccupied->DirActive < 1 && true == Train->mvOccupied->DirectionForward()) - { - // all work is done in the header - } - // aktualizacja skrajnych pojazdów w składzie - if (Train->mvOccupied->DirActive == 1 && Train->DynamicObject->Mechanik) - { - - Train->DynamicObject->Mechanik->DirectionChange(); - } - } - OnCommand_reverserincrease(Train, Command); - } -} - -void TTrain::OnCommand_reverserforward(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - // HACK: master controller position isn't set in occupied vehicle in E(D)MUs - // so we do a manual check in relevant vehicle here - if (false == Train->mvControlled->EIMDirectionChangeAllow()) - { - return; - } - - // HACK: try to move the reverser one position back, in case it's set to "high forward" - // OnCommand_reverserdecrease( Train, Command ); - // visual feedback - Train->ggDirForwardButton.UpdateValue(1.0, Train->dsbSwitch); - - if (Train->mvOccupied->DirActive == 0) - { - - while (Train->mvOccupied->DirActive < 1 && true == Train->mvOccupied->DirectionForward()) - { - // all work is done in the header - } - // aktualizacja skrajnych pojazdów w składzie - if (Train->mvOccupied->DirActive == 1 && Train->DynamicObject->Mechanik) - { - - Train->DynamicObject->Mechanik->DirectionChange(); - } - } - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - Train->ggDirForwardButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_reverserneutral(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - // HACK: master controller position isn't set in occupied vehicle in E(D)MUs - // so we do a manual check in relevant vehicle here - if (false == Train->mvControlled->EIMDirectionChangeAllow()) - { - return; - } - // visual feedback - Train->ggDirNeutralButton.UpdateValue(1.0, Train->dsbSwitch); - while (Train->mvOccupied->DirActive < 0 && true == Train->mvOccupied->DirectionForward()) - { - // all work is done in the header - } - while (Train->mvOccupied->DirActive > 0 && true == Train->mvOccupied->DirectionBackward()) - { - // all work is done in the header - } - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - Train->ggDirNeutralButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_reverserbackward(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - // HACK: master controller position isn't set in occupied vehicle in E(D)MUs - // so we do a manual check in relevant vehicle here - if (false == Train->mvControlled->EIMDirectionChangeAllow()) - { - return; - } - Train->ggDirBackwardButton.UpdateValue(1.0, Train->dsbSwitch); - if (Train->mvOccupied->DirActive == 0) - { - - while (Train->mvOccupied->DirActive > -1 && true == Train->mvOccupied->DirectionBackward()) - { - // all work is done in the header - } - // aktualizacja skrajnych pojazdów w składzie - if (Train->mvOccupied->DirActive == -1 && Train->DynamicObject->Mechanik) - { - - Train->DynamicObject->Mechanik->DirectionChange(); - } - } - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - Train->ggDirBackwardButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_alerteracknowledge(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggSecurityResetButton.UpdateValue(1.0, Train->dsbSwitch); - - if (Train->mvOccupied->TrainType == dt_EZT || Train->mvOccupied->DirActive != 0) - Train->mvOccupied->SecuritySystem.acknowledge_press(); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggSecurityResetButton.UpdateValue(0.0); - - if (Train->mvOccupied->TrainType == dt_EZT || Train->mvOccupied->DirActive != 0) - Train->mvOccupied->SecuritySystem.acknowledge_release(); - } -} - -void TTrain::OnCommand_cabsignalacknowledge(TTrain *Train, command_data const &Command) -{ - // TODO: visual feedback - if (Command.action == GLFW_PRESS) - { - if (Train->mvOccupied->SecuritySystem.has_separate_acknowledge()) - { - Train->mvOccupied->SecuritySystem.cabsignal_reset(); - Train->ggSHPResetButton.UpdateValue(1.0, Train->dsbSwitch); - } - } - else if (Command.action == GLFW_RELEASE) - { - Train->ggSHPResetButton.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_batterytoggle(TTrain *Train, command_data const &Command) -{ - if (Train->allowBatteryToggle || Command.action != GLFW_REPEAT) - { - // keep the switch from flipping back and forth if key is held down - if (false == Train->mvOccupied->Power24vIsAvailable) - { - // turn on - OnCommand_batteryenable(Train, Command); - } - else - { - // turn off - OnCommand_batterydisable(Train, Command); - } - } -} - -void TTrain::OnCommand_batteryenable(TTrain *Train, command_data const &Command) -{ - if (!Train->mvOccupied->isBatteryButtonImpulse) - { // regular button behavior - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); - Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); - - Train->mvOccupied->BatterySwitch(true); - Train->allowBatteryToggle = false; - // side-effects - if (Train->mvOccupied->LightsPosNo > 0) - { - Train->Dynamic()->SetLights(); - } - } - else if (Command.action == GLFW_RELEASE) - { - if (Train->ggBatteryButton.type() == TGaugeType::push) - { - // return the switch to neutral position - Train->ggBatteryButton.UpdateValue(0.5f); - } - Train->ggBatteryOnButton.UpdateValue(0.0f, Train->dsbSwitch); - Train->allowBatteryToggle = true; - } - } - else // impulse button behavior - { - if (Command.action == GLFW_PRESS) - { - if (Train->mvOccupied->shouldHoldBatteryButton) - { - // jesli przycisk trzeba przytrzymac - Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); - Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); - Train->fBatteryTimer = Train->mvOccupied->BatteryButtonHoldTime; // start timer - } - else - { - // jesli przycisk dziala od razu - Train->mvOccupied->BatterySwitch(true); - Train->allowBatteryToggle = false; - // side-effects - if (Train->mvOccupied->LightsPosNo > 0) - { - Train->Dynamic()->SetLights(); - } - - // visual feedback - Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); - Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); - } - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); - Train->ggBatteryOnButton.UpdateValue(0.0f, Train->dsbSwitch); - Train->fBatteryTimer = -1.f; // - Train->allowBatteryToggle = true; - Train->mvOccupied->batterySwAlreadyFired = false; - } - else if (Command.action == GLFW_REPEAT && Train->mvOccupied->shouldHoldBatteryButton) - { - // trzymamy przycisk - if (Train->fBatteryTimer <= 0.0 && Train->mvOccupied->Battery == false && !Train->mvOccupied->batterySwAlreadyFired) - { - Train->mvOccupied->BatterySwitch(true); - Train->mvOccupied->batterySwAlreadyFired = true; - - // side-effects - if (Train->mvOccupied->LightsPosNo > 0) - { - Train->Dynamic()->SetLights(); - } - Train->allowBatteryToggle = false; - } - } - } -} - -void TTrain::OnCommand_batterydisable(TTrain *Train, command_data const &Command) -{ - if (!Train->mvOccupied->isBatteryButtonImpulse) - { // regular button behavior - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); - Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); - - Train->mvOccupied->BatterySwitch(false); - - // side-effects - if (Train->mvOccupied->LightsPosNo > 0) - { - Train->Dynamic()->SetLights(); - } - } - else if (Command.action == GLFW_RELEASE) - { - if (Train->ggBatteryButton.type() == TGaugeType::push) - { - // return the switch to neutral position - Train->ggBatteryButton.UpdateValue(0.5f); - } - Train->ggBatteryOffButton.UpdateValue(0.0f, Train->dsbSwitch); - } - } - else // impulse button behavior - { - if (Command.action == GLFW_PRESS) - { - if (Train->mvOccupied->shouldHoldBatteryButton) - { - // jesli przycisk trzeba przytrzymac - Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); - Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); - Train->fBatteryTimer = Train->mvOccupied->BatteryButtonHoldTime; // start timer - } - else - { - // jesli przycisk dziala od razu - Train->mvOccupied->BatterySwitch(false); - Train->allowBatteryToggle = false; - - // side-effects - if (Train->mvOccupied->LightsPosNo > 0) - { - Train->Dynamic()->SetLights(); - } - // visual feedback - Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); - Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); - } - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); - Train->ggBatteryOffButton.UpdateValue(0.0f, Train->dsbSwitch); - Train->allowBatteryToggle = true; - Train->mvOccupied->batterySwAlreadyFired = false; - } - else if (Command.action == GLFW_REPEAT && Train->mvOccupied->shouldHoldBatteryButton) - { - // trzymamy przycisk - if (Train->fBatteryTimer <= 0.0 && Train->mvOccupied->Battery == true && !Train->mvOccupied->batterySwAlreadyFired) - { - Train->mvOccupied->BatterySwitch(false); - Train->mvOccupied->batterySwAlreadyFired = true; - - // side-effects - if (Train->mvOccupied->LightsPosNo > 0) - { - Train->Dynamic()->SetLights(); - } - Train->allowBatteryToggle = false; - } - } - } -} - -void TTrain::OnCommand_cabactivationtoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_REPEAT) - { - // keep the switch from flipping back and forth if key is held down - if (0 == Train->mvOccupied->CabActive) - { - // turn on - OnCommand_cabactivationenable(Train, Command); - } - else - { - // turn off - OnCommand_cabactivationdisable(Train, Command); - } - } -} - -void TTrain::OnCommand_cabactivationenable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // visual feedback - if (Train->ggCabActivationButton.type() == TGaugeType::push) - { - Train->ggCabActivationButton.UpdateValue(1.0f, Train->dsbSwitch); - } - - Train->mvOccupied->CabActivisation(); - - // side-effects - if (Train->mvOccupied->LightsPosNo > 0) - { - Train->Dynamic()->SetLights(); - } - } - else if (Command.action == GLFW_RELEASE) - { - if (Train->ggCabActivationButton.type() == TGaugeType::push) - { - // return the switch to neutral position - Train->ggCabActivationButton.UpdateValue(0.5f); - } - } -} - -void TTrain::OnCommand_cabactivationdisable(TTrain *Train, command_data const &Command) -{ - // TBD, TODO: ewentualnie zablokować z FIZ, np. w samochodach się nie odłącza akumulatora - if (Command.action == GLFW_PRESS) - { - // visual feedback - if (Train->ggCabActivationButton.type() == TGaugeType::push) - { - Train->ggCabActivationButton.UpdateValue(0.0f, Train->dsbSwitch); - } - - Train->mvOccupied->CabDeactivisation(); - if (Train->mvOccupied->LightsPosNo > 0 && Train->mvOccupied->InactiveCabFlag & activation::redmarkers) - { - Train->Dynamic()->SetLights(); - } - } - else if (Command.action == GLFW_RELEASE) - { - if (Train->ggCabActivationButton.type() == TGaugeType::push) - { - // return the switch to neutral position - Train->ggCabActivationButton.UpdateValue(0.5f); - } - } -} - -void TTrain::OnCommand_pantographtogglefront(TTrain *Train, command_data const &Command) -{ - - // HACK: presence of pantograph selector prevents manual operation of the individual valves - if (Train->m_controlmapper.contains("pantselect_sw:")) - { - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const &pantograph{Train->mvPantographUnit->Pantographs[end::front]}; - auto const state{pantograph.valve.is_enabled || pantograph.is_active}; // fallback for impulse switches - if (state) - { - OnCommand_pantographlowerfront(Train, Command); - } - else - { - OnCommand_pantographraisefront(Train, Command); - } - } - else if (Command.action == GLFW_RELEASE) - { - // impulse switches return automatically to neutral position - if (Train->mvOccupied->PantSwitchType == "impulse") - { - auto const ismanual{Train->iCabn == 0}; - Train->mvOccupied->OperatePantographValve(end::front, operation_t::none, ismanual ? range_t::local : range_t::consist); - } - } -} - -void TTrain::OnCommand_pantographtogglerear(TTrain *Train, command_data const &Command) -{ - - // HACK: presence of pantograph selector prevents manual operation of the individual valves - if (Train->m_controlmapper.contains("pantselect_sw:")) - { - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const &pantograph{Train->mvPantographUnit->Pantographs[end::rear]}; - auto const state{pantograph.valve.is_enabled || pantograph.is_active}; // fallback for impulse switches - if (state) - { - OnCommand_pantographlowerrear(Train, Command); - } - else - { - OnCommand_pantographraiserear(Train, Command); - } - } - else if (Command.action == GLFW_RELEASE) - { - // impulse switches return automatically to neutral position - if (Train->mvOccupied->PantSwitchType == "impulse") - { - auto const ismanual{Train->iCabn == 0}; - Train->mvOccupied->OperatePantographValve(end::rear, operation_t::none, ismanual ? range_t::local : range_t::consist); - } - } -} - -void TTrain::OnCommand_pantographraisefront(TTrain *Train, command_data const &Command) -{ - - // HACK: presence of pantograph selector prevents manual operation of the individual valves - if (Train->m_controlmapper.contains("pantselect_sw:")) - { - return; - } - // prevent operation without submodel outside of engine compartment - if (Train->iCabn != 0 && false == Train->m_controlmapper.contains("pantfront_sw:")) - { - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - // HACK: don't propagate pantograph commands issued from engine compartment, these are presumed to be manually moved levers - auto const ismanual{Train->iCabn == 0}; - Train->mvOccupied->OperatePantographValve(end::front, Train->mvOccupied->PantSwitchType == "impulse" ? operation_t::enable_on : operation_t::enable, - ismanual ? range_t::local : range_t::consist); - } - else if (Command.action == GLFW_RELEASE) - { - // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch - OnCommand_pantographtogglefront(Train, Command); - } -} - -void TTrain::OnCommand_pantographraiserear(TTrain *Train, command_data const &Command) -{ - - // HACK: presence of pantograph selector prevents manual operation of the individual valves - if (Train->m_controlmapper.contains("pantselect_sw:")) - { - return; - } - // prevent operation without submodel outside of engine compartment - if (Train->iCabn != 0 && false == Train->m_controlmapper.contains("pantrear_sw:")) - { - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - // HACK: don't propagate pantograph commands issued from engine compartment, these are presumed to be manually moved levers - auto const ismanual{Train->iCabn == 0}; - Train->mvOccupied->OperatePantographValve(end::rear, Train->mvOccupied->PantSwitchType == "impulse" ? operation_t::enable_on : operation_t::enable, - ismanual ? range_t::local : range_t::consist); - } - else if (Command.action == GLFW_RELEASE) - { - // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch - OnCommand_pantographtogglerear(Train, Command); - } -} - -void TTrain::OnCommand_pantographlowerfront(TTrain *Train, command_data const &Command) -{ - - // HACK: presence of pantograph selector prevents manual operation of the individual valves - if (Train->m_controlmapper.contains("pantselect_sw:")) - { - return; - } - // prevent operation without submodel outside of engine compartment - if (Train->iCabn != 0 && false == Train->m_controlmapper.contains(Train->mvOccupied->PantSwitchType == "impulse" ? "pantfrontoff_sw:" : "pantfront_sw:")) - { - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - // HACK: don't propagate pantograph commands issued from engine compartment, these are presumed to be manually moved levers - auto const ismanual{Train->iCabn == 0}; - Train->mvOccupied->OperatePantographValve(end::front, Train->mvOccupied->PantSwitchType == "impulse" ? operation_t::disable_on : operation_t::disable, - ismanual ? range_t::local : range_t::consist); - } - else if (Command.action == GLFW_RELEASE) - { - // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch - OnCommand_pantographtogglefront(Train, Command); - } -} - -void TTrain::OnCommand_pantographlowerrear(TTrain *Train, command_data const &Command) -{ - - // HACK: presence of pantograph selector prevents manual operation of the individual valves - if (Train->m_controlmapper.contains("pantselect_sw:")) - { - return; - } - - if (Train->iCabn != 0 && false == Train->m_controlmapper.contains(Train->mvOccupied->PantSwitchType == "impulse" ? "pantrearoff_sw:" : "pantrear_sw:")) - { - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - // HACK: don't propagate pantograph commands issued from engine compartment, these are presumed to be manually moved levers - auto const ismanual{Train->iCabn == 0}; - Train->mvOccupied->OperatePantographValve(end::rear, Train->mvOccupied->PantSwitchType == "impulse" ? operation_t::disable_on : operation_t::disable, - ismanual ? range_t::local : range_t::consist); - } - else if (Command.action == GLFW_RELEASE) - { - // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch - OnCommand_pantographtogglerear(Train, Command); - } -} - -void TTrain::OnCommand_pantographlowerall(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggPantAllDownButton.SubModel == nullptr) - { - // TODO: expand definition of cab controls so we can know if the control is present without testing for presence of 3d switch - if (Command.action == GLFW_PRESS) - { - WriteLog("Lower All Pantographs switch is missing, or wasn't defined"); - } - return; - } - - if (Train->ggPantAllDownButton.type() == TGaugeType::toggle) - { - // two-state switch, only cares about press events - if (Command.action == GLFW_PRESS) - { - Train->mvPantographUnit->DropAllPantographs(false == Train->mvPantographUnit->PantAllDown); - // visual feedback - Train->ggPantAllDownButton.UpdateValue(Train->mvPantographUnit->PantAllDown ? 1.0 : 0.0, Train->dsbSwitch); - } - } - else - { - // impulse switch - Train->mvControlled->DropAllPantographs(Command.action == GLFW_PRESS); - // visual feedback - Train->ggPantAllDownButton.UpdateValue(Command.action == GLFW_PRESS ? 1.0 : 0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_pantographselectnext(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_PRESS) - { - return; - } - - if (false == Train->m_controlmapper.contains("pantselect_sw:")) - { - return; - } - - Train->change_pantograph_selection(1); -} - -void TTrain::OnCommand_pantographselectprevious(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_PRESS) - { - return; - } - - if (false == Train->m_controlmapper.contains("pantselect_sw:")) - { - return; - } - - Train->change_pantograph_selection(-1); -} - -void TTrain::OnCommand_pantographtoggleselected(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Command.action == GLFW_PRESS) - { - // recalculate pantograph state (hujhujhuj) - Train->change_pantograph_selection(1); - Train->change_pantograph_selection(-1); - - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const state{Train->mvPantographUnit->PantsValve.is_enabled || Train->mvPantographUnit->PantsValve.is_active}; // fallback for impulse switches - if (state) - { - OnCommand_pantographlowerselected(Train, Command); - } - else - { - OnCommand_pantographraiseselected(Train, Command); - } - } - else if (Command.action == GLFW_RELEASE) - { - // impulse switches return automatically to neutral position - if (Train->m_controlmapper.contains("pantselectedoff_sw:")) - { - // two buttons setup - if (Train->ggPantSelectedButton.type() != TGaugeType::toggle) - { - Train->mvOccupied->OperatePantographsValve(operation_t::enable_off); - // visual feedback - Train->ggPantSelectedButton.UpdateValue(0.0, Train->dsbSwitch); - } - if (Train->ggPantSelectedDownButton.type() != TGaugeType::toggle) - { - Train->mvOccupied->OperatePantographsValve(operation_t::disable_off); - // visual feedback - Train->ggPantSelectedDownButton.UpdateValue(0.0, Train->dsbSwitch); - } - } - else - { - if (Train->ggPantSelectedButton.type() != TGaugeType::toggle) - { - // special case, just one impulse switch controlling both states - // with neutral position mid-way - Train->mvOccupied->OperatePantographsValve(operation_t::none); - // visual feedback - Train->ggPantSelectedButton.UpdateValue(0.5, Train->dsbSwitch); - } - } - } -} - -void TTrain::OnCommand_pantographraiseselected(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Command.action == GLFW_PRESS) - { - // raise selected - Train->mvOccupied->OperatePantographsValve(Train->ggPantSelectedButton.type() != TGaugeType::toggle ? operation_t::enable_on : operation_t::enable); - // visual feedback - Train->ggPantSelectedButton.UpdateValue(1.0, Train->dsbSwitch); - } - else if (Command.action == GLFW_RELEASE) - { - // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch - OnCommand_pantographtoggleselected(Train, Command); - } -} - -void TTrain::OnCommand_pantographlowerselected(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Command.action == GLFW_PRESS) - { - // lower selected - Train->mvOccupied->OperatePantographsValve(Train->ggPantSelectedDownButton.type() != TGaugeType::toggle ? operation_t::disable_on : operation_t::disable); - // visual feedback - if (Train->m_controlmapper.contains("pantselectedoff_sw:")) - { - // two button setup - Train->ggPantSelectedDownButton.UpdateValue(1.0, Train->dsbSwitch); - } - else - { - // single button - Train->ggPantSelectedButton.UpdateValue(0.0, Train->dsbSwitch); - } - } - else if (Command.action == GLFW_RELEASE) - { - // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch - OnCommand_pantographtoggleselected(Train, Command); - } -} - -void TTrain::update_pantograph_valves() -{ - - auto const &presets{mvOccupied->PantsPreset.first}; - auto &selection{mvOccupied->PantsPreset.second[cab_to_end()]}; - - auto const preset{presets[selection] - '0'}; - auto const swapends{cab_to_end() != end::front}; - // check desired states for both pantographs; value: whether the pantograph should be raised - auto const frontstate{preset & (swapends ? 2 : 1)}; - auto const rearstate{preset & (swapends ? 1 : 2)}; - mvOccupied->OperatePantographValve(end::front, frontstate ? operation_t::enable : operation_t::disable); - mvOccupied->OperatePantographValve(end::rear, rearstate ? operation_t::enable : operation_t::disable); -} - -void TTrain::change_pantograph_selection(int const Change) -{ - - auto const &presets{mvOccupied->PantsPreset.first}; - auto &selection{mvOccupied->PantsPreset.second[cab_to_end()]}; - auto const initialstate{selection}; - selection = std::clamp(selection + Change, 0, std::max(presets.size() - 1, 0)); - - if (selection == initialstate) - { - return; - } // no change, nothing to do - - // potentially adjust pantograph valves to match the new state - if (false == m_controlmapper.contains("pantvalves_sw:")) - { - update_pantograph_valves(); - } -} - -void TTrain::OnCommand_pantographvalvesupdate(TTrain *Train, command_data const &Command) -{ - - bool hasSeparateSwitches = Train->m_controlmapper.contains("pantvalvesupdate_bt:") && Train->m_controlmapper.contains("pantvalvesoff_bt:"); - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Command.action == GLFW_PRESS) - { - if (hasSeparateSwitches) - { - // implement action - Train->update_pantograph_valves(); - // visual feedback - Train->ggPantValvesUpdate.UpdateValue(1.0, Train->dsbSwitch); - } - - // Old logic to maintain compatibility - else - { - Train->update_pantograph_valves(); - Train->ggPantValvesButton.UpdateValue(1.0, Train->dsbSwitch); - } - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - // NOTE: pantvalves_sw: is a specialized button, with no toggle behavior support - if (hasSeparateSwitches) - Train->ggPantValvesUpdate.UpdateValue(0.5, Train->dsbSwitch); - - // Old logic to maintain compatibility - else - Train->ggPantValvesButton.UpdateValue(0.5, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_pantographvalvesoff(TTrain *Train, command_data const &Command) -{ - - bool hasSeparateSwitches = Train->m_controlmapper.contains("pantvalvesupdate_bt:") && Train->m_controlmapper.contains("pantvalvesoff_bt:"); - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Command.action == GLFW_PRESS) - { - // implement action - Train->mvOccupied->OperatePantographValve(end::front, operation_t::disable); - Train->mvOccupied->OperatePantographValve(end::rear, operation_t::disable); - // visual feedback - if (hasSeparateSwitches) - Train->ggPantValvesOff.UpdateValue(1.0, Train->dsbSwitch); - else - Train->ggPantValvesButton.UpdateValue(0.0, Train->dsbSwitch); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - // NOTE: pantvalves_sw: is a speciali zed button, with no toggle behavior support - if (hasSeparateSwitches) - Train->ggPantValvesOff.UpdateValue(0.f, Train->dsbSwitch); - else - Train->ggPantValvesButton.UpdateValue(0.5, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_pantographcompressorvalvetoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only react to press - if (Train->mvControlled->bPantKurek3 == false) - { - // connect pantographs with primary tank - OnCommand_pantographcompressorvalveenable(Train, Command); - } - else - { - // connect pantograps with pantograph compressor - OnCommand_pantographcompressorvalvedisable(Train, Command); - } - } -} - -void TTrain::OnCommand_pantographcompressorvalveenable(TTrain *Train, command_data const &Command) -{ - - auto const valveispresent{Train->ggPantCompressorValve.SubModel != nullptr || (Train->mvOccupied == Train->mvPantographUnit && Train->iCabn == 0)}; - - if (false == valveispresent) - { - // tylko w maszynowym, unless actual device is present - return; - } - - if (Command.action == GLFW_PRESS) - { - // only react to press - // connect pantographs with primary tank - Train->mvControlled->bPantKurek3 = true; - // visual feedback: - Train->ggPantCompressorValve.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_pantographcompressorvalvedisable(TTrain *Train, command_data const &Command) -{ - - auto const valveispresent{Train->ggPantCompressorValve.SubModel != nullptr || (Train->mvOccupied == Train->mvPantographUnit && Train->iCabn == 0)}; - - if (false == valveispresent) - { - // tylko w maszynowym, unless actual device is present - return; - } - - if (Command.action == GLFW_PRESS) - { - // only react to press - // connect pantograps with pantograph compressor - Train->mvControlled->bPantKurek3 = false; - // visual feedback: - Train->ggPantCompressorValve.UpdateValue(1.0); - } -} - -void TTrain::OnCommand_pantographcompressoractivate(TTrain *Train, command_data const &Command) -{ - - // tylko w maszynowym, unless actual device is present - auto const switchispresent{Train->m_controlmapper.contains("pantcompressor_sw:") || (Train->mvOccupied == Train->mvPantographUnit && Train->iCabn == 0)}; - if (false == switchispresent) - { - return; - } - - if (Command.action != GLFW_RELEASE) - { - // press or hold to activate - if (Train->mvPantographUnit->PantPress < 4.8 && true == Train->mvPantographUnit->Power24vIsAvailable) - { - // needs live power source and low enough pressure to work - Train->mvPantographUnit->PantCompFlag = true; - } - // visual feedback - Train->ggPantCompressorButton.UpdateValue(1.0); - } - else - { - // release to disable - Train->mvPantographUnit->PantCompFlag = false; - // visual feedback - Train->ggPantCompressorButton.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_linebreakertoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // press or hold... - if (Train->m_linebreakerstate == 0) - { - // ...to close the circuit - // NOTE: bit of a dirty shortcut here - OnCommand_linebreakerclose(Train, Command); - } - else if (Train->m_linebreakerstate == 1) - { - // ...to open the circuit - OnCommand_linebreakeropen(Train, Command); - } - } - else if (Command.action == GLFW_RELEASE) - { - // release... - if (Train->ggMainOnButton.SubModel != nullptr || Train->ggMainButton.type() != TGaugeType::toggle) - { - // only impulse switches react to release events - // NOTE: we presume dedicated state switch is of impulse type - if (Train->m_linebreakerstate == 0) - { - // ...after opening circuit, or holding for too short time to close it - OnCommand_linebreakeropen(Train, Command); - } - else - { - // ...after closing the circuit - // NOTE: bit of a dirty shortcut here - OnCommand_linebreakerclose(Train, Command); - } - } - // HACK: ignition key ignores lack of submodel, so we can start vehicles without any modeled controls - Train->ggIgnitionKey.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_linebreakeropen(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // visual feedback - if (Train->ggMainOffButton.SubModel != nullptr) - { - Train->ggMainOffButton.UpdateValue(1.0, Train->dsbSwitch); - } - else if (Train->ggMainButton.SubModel != nullptr) - { - Train->ggMainButton.UpdateValue(0.0, Train->dsbSwitch); - } - else if (Train->ggMainOnButton.SubModel != nullptr) - { - // NOTE: legacy behaviour, for vehicles equipped only with impulse close switch - // it doesn't make any real sense to animate this one, but some people can't get over how there's no visual reaction to their keypress - Train->ggMainOnButton.UpdateValue(1.0, Train->dsbSwitch); - return; - } - // play sound immediately when the switch is hit, not after release - Train->fMainRelayTimer = 0.0f; - - if (Train->m_linebreakerstate == 0) - { - return; - } // already in the desired state - - if (true == Train->mvControlled->MainSwitch(false)) - { - Train->m_linebreakerstate = 0; - } - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - // we don't exactly know which of the two buttons was used, so reset both - // for setup with two separate swiches - if (Train->ggMainOnButton.SubModel != nullptr) - { - Train->ggMainOnButton.UpdateValue(0.0, Train->dsbSwitch); - } - if (Train->ggMainOffButton.SubModel != nullptr) - { - Train->ggMainOffButton.UpdateValue(0.0, Train->dsbSwitch); - } - // and the two-state switch too, for good measure - if (Train->ggMainButton.SubModel != nullptr) - { - Train->ggMainButton.UpdateValue(Train->ggMainButton.type() != TGaugeType::toggle ? 0.5 : 0.0, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_linebreakerclose(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // visual feedback - if (Train->ggMainOnButton.SubModel != nullptr) - { - // two separate switches to close and break the circuit - Train->ggMainOnButton.UpdateValue(1.0, Train->dsbSwitch); - } - else if (Train->ggMainButton.SubModel != nullptr) - { - // single two-state switch - Train->ggMainButton.UpdateValue(1.0, Train->dsbSwitch); - } - else - { - // no switch capable of doing the job - // HACK: ignition key ignores lack of submodel, so we can start vehicles without any modeled controls - Train->ggIgnitionKey.UpdateValue(1.0); - return; - } - // the actual closing of the line breaker is handled in the train update routine - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - if (Train->ggMainOnButton.SubModel != nullptr) - { - // setup with two separate switches - Train->ggMainOnButton.UpdateValue(0.0, Train->dsbSwitch); - } - else if (Train->ggMainButton.SubModel != nullptr) - { - if (Train->ggMainButton.type() != TGaugeType::toggle) - { - Train->ggMainButton.UpdateValue(0.5, Train->dsbSwitch); - } - } - - if (Train->m_linebreakerstate == 1) - { - return; - } // already in the desired state - - if (Train->m_linebreakerstate == 2) - { - // we don't need to start the diesel twice, but the other types (with impulse switch setup) still need to be launched - // NOTE: this behaviour should depend on MainOnButton presence and type_delayed - // TODO: change it when/if vehicle definition files get their proper switch types - if (Train->mvControlled->EngineType == TEngineType::ElectricSeriesMotor) - { - // try to finalize state change of the line breaker, set the state based on the outcome - Train->m_linebreakerstate = Train->mvControlled->MainSwitch(true) ? 1 : 0; - } - } - // on button release reset the closing timer - Train->fMainRelayTimer = 0.0f; - } -} - -void TTrain::OnCommand_fuelpumptoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggFuelPumpButton.type() == TGaugeType::push) - { - // impulse switch - // currently there's no off button so we always try to turn it on - OnCommand_fuelpumpenable(Train, Command); - } - else - { - // two-state switch - if (Command.action == GLFW_RELEASE) - { - return; - } - - if (false == Train->mvControlled->FuelPump.is_enabled) - { - // turn on - OnCommand_fuelpumpenable(Train, Command); - } - else - { - // turn off - OnCommand_fuelpumpdisable(Train, Command); - } - } -} - -void TTrain::OnCommand_fuelpumpenable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggFuelPumpButton.type() == TGaugeType::push) - { - // impulse switch - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggFuelPumpButton.UpdateValue(1.0, Train->dsbSwitch); - Train->mvControlled->FuelPumpSwitch(true); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggFuelPumpButton.UpdateValue(0.0, Train->dsbSwitch); - Train->mvControlled->FuelPumpSwitch(false); - } - } - else - { - // two-state switch, only cares about press events - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggFuelPumpButton.UpdateValue(1.0, Train->dsbSwitch); - Train->mvControlled->FuelPumpSwitch(true); - Train->mvControlled->FuelPumpSwitchOff(false); - } - } -} - -void TTrain::OnCommand_fuelpumpdisable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggFuelPumpButton.type() == TGaugeType::push) - { - // impulse switch - // currently there's no disable return type switch - return; - } - else - { - // two-state switch, only cares about press events - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggFuelPumpButton.UpdateValue(0.0, Train->dsbSwitch); - Train->mvControlled->FuelPumpSwitch(false); - Train->mvControlled->FuelPumpSwitchOff(true); - } - } -} - -void TTrain::OnCommand_oilpumptoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggOilPumpButton.type() == TGaugeType::push) - { - // impulse switch - // currently there's no off button so we always try to turn it on - OnCommand_oilpumpenable(Train, Command); - } - else - { - // two-state switch - if (Command.action == GLFW_RELEASE) - { - return; - } - - if (false == Train->mvControlled->OilPump.is_enabled) - { - // turn on - OnCommand_oilpumpenable(Train, Command); - } - else - { - // turn off - OnCommand_oilpumpdisable(Train, Command); - } - } -} - -void TTrain::OnCommand_oilpumpenable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggOilPumpButton.type() == TGaugeType::push) - { - // impulse switch - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggOilPumpButton.UpdateValue(1.0, Train->dsbSwitch); - Train->mvControlled->OilPumpSwitch(true); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggOilPumpButton.UpdateValue(0.0, Train->dsbSwitch); - Train->mvControlled->OilPumpSwitch(false); - } - } - else - { - // two-state switch, only cares about press events - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggOilPumpButton.UpdateValue(1.0, Train->dsbSwitch); - Train->mvControlled->OilPumpSwitch(true); - Train->mvControlled->OilPumpSwitchOff(false); - } - } -} - -void TTrain::OnCommand_oilpumpdisable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggOilPumpButton.type() == TGaugeType::push) - { - // impulse switch - // currently there's no disable return type switch - return; - } - else - { - // two-state switch, only cares about press events - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggOilPumpButton.UpdateValue(0.0, Train->dsbSwitch); - Train->mvControlled->OilPumpSwitch(false); - Train->mvControlled->OilPumpSwitchOff(true); - } - } -} - -void TTrain::OnCommand_waterheaterbreakertoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->mvControlled->WaterHeater.breaker) - { - // turn on - OnCommand_waterheaterbreakerclose(Train, Command); - } - else - { - // turn off - OnCommand_waterheaterbreakeropen(Train, Command); - } - } -} - -void TTrain::OnCommand_waterheaterbreakerclose(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggWaterHeaterBreakerButton.UpdateValue(1.0, Train->dsbSwitch); - - if (true == Train->mvControlled->WaterHeater.breaker) - { - return; - } // already enabled - - Train->mvControlled->WaterHeaterBreakerSwitch(true); - } -} - -void TTrain::OnCommand_waterheaterbreakeropen(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggWaterHeaterBreakerButton.UpdateValue(0.0, Train->dsbSwitch); - - if (false == Train->mvControlled->WaterHeater.breaker) - { - return; - } // already enabled - - Train->mvControlled->WaterHeaterBreakerSwitch(false); - } -} - -void TTrain::OnCommand_waterheatertoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->mvControlled->WaterHeater.is_enabled) - { - // turn on - OnCommand_waterheaterenable(Train, Command); - } - else - { - // turn off - OnCommand_waterheaterdisable(Train, Command); - } - } -} - -void TTrain::OnCommand_waterheaterenable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggWaterHeaterButton.UpdateValue(1.0, Train->dsbSwitch); - - if (true == Train->mvControlled->WaterHeater.is_enabled) - { - return; - } // already enabled - - Train->mvControlled->WaterHeaterSwitch(true); - } -} - -void TTrain::OnCommand_waterheaterdisable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggWaterHeaterButton.UpdateValue(0.0, Train->dsbSwitch); - - if (false == Train->mvControlled->WaterHeater.is_enabled) - { - return; - } // already disabled - - Train->mvControlled->WaterHeaterSwitch(false); - } -} - -void TTrain::OnCommand_waterpumpbreakertoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->mvControlled->WaterPump.breaker) - { - // turn on - OnCommand_waterpumpbreakerclose(Train, Command); - } - else - { - // turn off - OnCommand_waterpumpbreakeropen(Train, Command); - } - } -} - -void TTrain::OnCommand_waterpumpbreakerclose(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggWaterPumpBreakerButton.UpdateValue(1.0, Train->dsbSwitch); - - if (true == Train->mvControlled->WaterPump.breaker) - { - return; - } // already enabled - - Train->mvControlled->WaterPumpBreakerSwitch(true); - } -} - -void TTrain::OnCommand_waterpumpbreakeropen(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggWaterPumpBreakerButton.UpdateValue(0.0, Train->dsbSwitch); - - if (false == Train->mvControlled->WaterPump.breaker) - { - return; - } // already enabled - - Train->mvControlled->WaterPumpBreakerSwitch(false); - } -} - -void TTrain::OnCommand_waterpumptoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggWaterPumpButton.type() == TGaugeType::push) - { - // impulse switch - // currently there's no off button so we always try to turn it on - OnCommand_waterpumpenable(Train, Command); - } - else - { - // two-state switch - if (Command.action == GLFW_RELEASE) - { - return; - } - - if (false == Train->mvControlled->WaterPump.is_enabled) - { - // turn on - OnCommand_waterpumpenable(Train, Command); - } - else - { - // turn off - OnCommand_waterpumpdisable(Train, Command); - } - } -} - -void TTrain::OnCommand_waterpumpenable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggWaterPumpButton.type() == TGaugeType::push) - { - // impulse switch - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggWaterPumpButton.UpdateValue(1.0, Train->dsbSwitch); - Train->mvControlled->WaterPumpSwitch(true); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggWaterPumpButton.UpdateValue(0.0, Train->dsbSwitch); - Train->mvControlled->WaterPumpSwitch(false); - } - } - else - { - // two-state switch, only cares about press events - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggWaterPumpButton.UpdateValue(1.0, Train->dsbSwitch); - Train->mvControlled->WaterPumpSwitch(true); - Train->mvControlled->WaterPumpSwitchOff(false); - } - } -} - -void TTrain::OnCommand_waterpumpdisable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggWaterPumpButton.type() == TGaugeType::push) - { - // impulse switch - // currently there's no disable return type switch - return; - } - else - { - // two-state switch, only cares about press events - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggWaterPumpButton.UpdateValue(0.0, Train->dsbSwitch); - Train->mvControlled->WaterPumpSwitch(false); - Train->mvControlled->WaterPumpSwitchOff(true); - } - } -} - -void TTrain::OnCommand_watercircuitslinktoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->mvControlled->WaterCircuitsLink) - { - // turn on - OnCommand_watercircuitslinkenable(Train, Command); - } - else - { - // turn off - OnCommand_watercircuitslinkdisable(Train, Command); - } - } -} - -void TTrain::OnCommand_watercircuitslinkenable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggWaterCircuitsLinkButton.UpdateValue(1.0, Train->dsbSwitch); - - if (true == Train->mvControlled->WaterCircuitsLink) - { - return; - } // already enabled - - Train->mvControlled->WaterCircuitsLinkSwitch(true); - } -} - -void TTrain::OnCommand_watercircuitslinkdisable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggWaterCircuitsLinkButton.UpdateValue(0.0, Train->dsbSwitch); - - if (false == Train->mvControlled->WaterCircuitsLink) - { - return; - } // already disabled - - Train->mvControlled->WaterCircuitsLinkSwitch(false); - } -} - -void TTrain::OnCommand_convertertoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const overloadrelayisopen{(Train->Dynamic()->Mechanik != nullptr ? Train->Dynamic()->Mechanik->IsAnyConverterOverloadRelayOpen : Train->mvOccupied->ConvOvldFlag)}; - - if (Train->mvOccupied->ConvSwitchType != "impulse" ? Train->ggConverterButton.GetValue() < 0.5 : false == Train->mvOccupied->Power110vIsAvailable && false == overloadrelayisopen) - { - // turn on - OnCommand_converterenable(Train, Command); - } - else - { - // turn off - OnCommand_converterdisable(Train, Command); - } - } - else if (Command.action == GLFW_RELEASE) - { - // on button release... - if (Train->mvOccupied->ConvSwitchType == "impulse") - { - // ...return switches to start position if applicable - Train->ggConverterButton.UpdateValue(0.0, Train->dsbSwitch); - Train->ggConverterOffButton.UpdateValue(0.0, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_converterenable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggConverterButton.UpdateValue(1.0, Train->dsbSwitch); - - // impulse type switch has no effect if there's no power - // NOTE: this is most likely setup wrong, but the whole thing is smoke and mirrors anyway - if (Train->mvOccupied->ConvSwitchType != "impulse" || Train->mvControlled->Mains) - { - // won't start if the line breaker button is still held - Train->mvOccupied->ConverterSwitch(true); - } - } - else if (Command.action == GLFW_RELEASE) - { - // potentially reset impulse switch position, using shared code branch - OnCommand_convertertoggle(Train, Command); - } -} - -void TTrain::OnCommand_converterdisable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggConverterButton.UpdateValue(0.0, Train->dsbSwitch); - if (Train->ggConverterOffButton.SubModel != nullptr) - { - Train->ggConverterOffButton.UpdateValue(1.0, Train->dsbSwitch); - } - - Train->mvOccupied->ConverterSwitch(false); - } - else if (Command.action == GLFW_RELEASE) - { - // potentially reset impulse switch position, using shared code branch - OnCommand_convertertoggle(Train, Command); - } -} - -void TTrain::OnCommand_convertertogglelocal(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->ConverterStart == start_t::automatic) - { - // let the automatic thing do its automatic thing... - return; - } - if (Train->ggConverterLocalButton.SubModel == nullptr) - { - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->mvOccupied->ConverterAllowLocal && Train->ggConverterLocalButton.GetValue() < 0.5) - { - // turn on - // visual feedback - Train->ggConverterLocalButton.UpdateValue(1.0, Train->dsbSwitch); - // effect - Train->mvOccupied->ConverterAllowLocal = true; - /* - if( true == Train->mvControlled->ConverterSwitch( true, range::local ) ) { - // side effects - // control the compressor, if it's paired with the converter - if( Train->mvControlled->CompressorPower == 2 ) { - // hunter-091012: tak jest poprawnie - Train->mvControlled->CompressorSwitch( true, range::local ); - } - } - */ - } - else - { - // turn off - // visual feedback - Train->ggConverterLocalButton.UpdateValue(0.0, Train->dsbSwitch); - // effect - Train->mvOccupied->ConverterAllowLocal = false; - /* - if( true == Train->mvControlled->ConverterSwitch( false, range::local ) ) { - // side effects - // control the compressor, if it's paired with the converter - if( Train->mvControlled->CompressorPower == 2 ) { - // hunter-091012: tak jest poprawnie - Train->mvControlled->CompressorSwitch( false, range::local ); - } - // if there's no (low voltage) power source left, drop pantographs - if( false == Train->mvControlled->Battery ) { - Train->mvControlled->PantFront( false, range::local ); - Train->mvControlled->PantRear( false, range::local ); - } - } - */ - } - } -} - -void TTrain::OnCommand_converteroverloadrelayreset(TTrain *Train, command_data const &Command) -{ - - if (Train->ggConverterFuseButton.SubModel == nullptr) - { - if (Command.action == GLFW_PRESS) - { - WriteLog("Converter Overload Relay Reset button is missing, or wasn't defined"); - } - // return; - } - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggConverterFuseButton.UpdateValue(1.0, Train->dsbSwitch); - - Train->mvControlled->RelayReset(relay_t::primaryconverteroverload); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggConverterFuseButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_compressortoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const compressorisenabled{(Train->Dynamic()->Mechanik ? Train->Dynamic()->Mechanik->IsAnyCompressorEnabled : Train->mvOccupied->CompressorAllow)}; - - if (false == compressorisenabled) - { - // turn on - OnCommand_compressorenable(Train, Command); - } - else - { - // turn off - OnCommand_compressordisable(Train, Command); - } - } - /* - // disabled because we don't have yet support for compressor switch type definition - else if( Command.action == GLFW_RELEASE ) { - // on button release... - if( Train->mvOccupied->CompSwitchType == "impulse" ) { - // ...return switches to start position if applicable - Train->ggCompressorButton.UpdateValue( 0.0, Train->dsbSwitch ); - Train->ggCompressorOffButton.UpdateValue( 0.0, Train->dsbSwitch ); - } - } - */ -} - -void TTrain::OnCommand_compressorenable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggCompressorButton.UpdateValue(1.0, Train->dsbSwitch); - - // impulse type switch has no effect if there's no power - // NOTE: this is most likely setup wrong, but the whole thing is smoke and mirrors anyway - // if( ( Train->mvOccupied->CompSwitchType != "impulse" ) - // || ( Train->mvControlled->Mains ) ) { - - Train->mvOccupied->CompressorSwitch(true); - // } - } - else if (Command.action == GLFW_RELEASE) - { - // potentially reset impulse switch position, using shared code branch - OnCommand_compressortoggle(Train, Command); - } -} - -void TTrain::OnCommand_compressordisable(TTrain *Train, command_data const &Command) -{ - - if (Train->mvControlled->CompressorPower >= 2) - { - return; - } - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggCompressorButton.UpdateValue(0.0, Train->dsbSwitch); - /* - if( Train->ggCompressorOffButton.SubModel != nullptr ) { - Train->ggCompressorOffButton.UpdateValue( 1.0, Train->dsbSwitch ); - } - */ - Train->mvOccupied->CompressorSwitch(false); - } - else if (Command.action == GLFW_RELEASE) - { - // potentially reset impulse switch position, using shared code branch - OnCommand_compressortoggle(Train, Command); - } -} - -void TTrain::OnCommand_compressortogglelocal(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->CompressorPower >= 2) - { - return; - } - if (Train->ggCompressorLocalButton.SubModel == nullptr) - { - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->mvOccupied->CompressorAllowLocal) - { - // turn on - // visual feedback - Train->ggCompressorLocalButton.UpdateValue(1.0, Train->dsbSwitch); - // effect - Train->mvOccupied->CompressorAllowLocal = true; - } - else - { - // turn off - // visual feedback - Train->ggCompressorLocalButton.UpdateValue(0.0, Train->dsbSwitch); - // effect - Train->mvOccupied->CompressorAllowLocal = false; - } - } -} - -void TTrain::OnCommand_compressorpresetactivatenext(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->CompressorListPosNo == 0) - { - return; - } - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggCompressorListButton.type() == TGaugeType::push) - { - // impulse switch - if (Train->mvOccupied->CompressorListPosNo < Train->mvOccupied->CompressorListDefPos + 1) - { - return; - } - - Train->mvOccupied->ChangeCompressorPreset(Command.action == GLFW_PRESS ? Train->mvOccupied->CompressorListDefPos + 1 : Train->mvOccupied->CompressorListDefPos); - // visual feedback - Train->ggCompressorListButton.UpdateValue(Train->mvOccupied->CompressorListPos - 1, Train->dsbSwitch); - } - else - { - // multi-state switch - if (Command.action == GLFW_RELEASE) - { - return; - } - - if (Train->mvOccupied->CompressorListPos < Train->mvOccupied->CompressorListPosNo || true == Train->mvOccupied->CompressorListWrap) - { - // active light preset is stored as value in range 1-LigthPosNo - Train->mvOccupied->ChangeCompressorPreset(Train->mvOccupied->CompressorListPos < Train->mvOccupied->CompressorListPosNo ? Train->mvOccupied->CompressorListPos + 1 : 1); // wrap mode - // visual feedback - Train->ggCompressorListButton.UpdateValue(Train->mvOccupied->CompressorListPos - 1, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_compressorpresetactivateprevious(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->CompressorListPosNo == 0) - { - return; - } - if (Command.action != GLFW_PRESS) - { - return; - } // one change per key press - - if (Train->ggCompressorListButton.type() == TGaugeType::push) - { - // impulse switch toggles only between positions 'default' and 'default+1' - return; - } - - if (Train->mvOccupied->CompressorListPos > 1 || true == Train->mvOccupied->CompressorListWrap) - { - // active light preset is stored as value in range 1-LigthPosNo - Train->mvOccupied->ChangeCompressorPreset(Train->mvOccupied->CompressorListPos > 1 ? Train->mvOccupied->CompressorListPos - 1 : Train->mvOccupied->CompressorListPosNo); // wrap mode - - // visual feedback - if (Train->ggCompressorListButton.SubModel != nullptr) - { - Train->ggCompressorListButton.UpdateValue(Train->mvOccupied->CompressorListPos - 1, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_compressorpresetactivatedefault(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->CompressorListPosNo == 0) - { - return; - } - if (Command.action != GLFW_PRESS) - { - return; - } // one change per key press - - Train->mvOccupied->ChangeCompressorPreset(Train->mvOccupied->CompressorListDefPos); - - // visual feedback - if (Train->ggCompressorListButton.SubModel != nullptr) - { - Train->ggCompressorListButton.UpdateValue(Train->mvOccupied->CompressorListPos - 1, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_motorblowerstogglefront(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggMotorBlowersFrontButton.type() == TGaugeType::push) - { - // impulse switch - // currently there's no off button so we always try to turn it on - OnCommand_motorblowersenablefront(Train, Command); - } - else - { - // two-state switch - if (Command.action == GLFW_RELEASE) - { - return; - } - - if (false == Train->mvControlled->MotorBlowers[end::front].is_enabled) - { - // turn on - OnCommand_motorblowersenablefront(Train, Command); - } - else - { - // turn off - OnCommand_motorblowersdisablefront(Train, Command); - } - } -} - -void TTrain::OnCommand_motorblowersenablefront(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggMotorBlowersFrontButton.type() == TGaugeType::push) - { - // impulse switch - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggMotorBlowersFrontButton.UpdateValue(1.f, Train->dsbSwitch); - Train->mvControlled->MotorBlowersSwitch(true, end::front); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggMotorBlowersFrontButton.UpdateValue(0.f, Train->dsbSwitch); - Train->mvControlled->MotorBlowersSwitch(false, end::front); - } - } - else - { - // two-state switch, only cares about press events - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggMotorBlowersFrontButton.UpdateValue(1.f, Train->dsbSwitch); - Train->mvControlled->MotorBlowersSwitch(true, end::front); - Train->mvControlled->MotorBlowersSwitchOff(false, end::front); - } - } -} - -void TTrain::OnCommand_motorblowersdisablefront(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggMotorBlowersFrontButton.type() == TGaugeType::push) - { - // impulse switch - // currently there's no disable return type switch - return; - } - else - { - // two-state switch, only cares about press events - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggMotorBlowersFrontButton.UpdateValue(0.f, Train->dsbSwitch); - Train->mvControlled->MotorBlowersSwitch(false, end::front); - Train->mvControlled->MotorBlowersSwitchOff(true, end::front); - } - } -} - -void TTrain::OnCommand_motorblowerstogglerear(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggMotorBlowersRearButton.type() == TGaugeType::push) - { - // impulse switch - // currently there's no off button so we always try to turn it on - OnCommand_motorblowersenablerear(Train, Command); - } - else - { - // two-state switch - if (Command.action == GLFW_RELEASE) - { - return; - } - - if (false == Train->mvControlled->MotorBlowers[end::rear].is_enabled) - { - // turn on - OnCommand_motorblowersenablerear(Train, Command); - } - else - { - // turn off - OnCommand_motorblowersdisablerear(Train, Command); - } - } -} - -void TTrain::OnCommand_motorblowersenablerear(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggMotorBlowersRearButton.type() == TGaugeType::push) - { - // impulse switch - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggMotorBlowersRearButton.UpdateValue(1.f, Train->dsbSwitch); - Train->mvControlled->MotorBlowersSwitch(true, end::rear); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggMotorBlowersRearButton.UpdateValue(0.f, Train->dsbSwitch); - Train->mvControlled->MotorBlowersSwitch(false, end::rear); - } - } - else - { - // two-state switch, only cares about press events - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggMotorBlowersRearButton.UpdateValue(1.f, Train->dsbSwitch); - Train->mvControlled->MotorBlowersSwitch(true, end::rear); - Train->mvControlled->MotorBlowersSwitchOff(false, end::rear); - } - } -} - -void TTrain::OnCommand_motorblowersdisablerear(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggMotorBlowersRearButton.type() == TGaugeType::push) - { - // impulse switch - // currently there's no disable return type switch - return; - } - else - { - // two-state switch, only cares about press events - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggMotorBlowersRearButton.UpdateValue(0.f, Train->dsbSwitch); - Train->mvControlled->MotorBlowersSwitch(false, end::rear); - Train->mvControlled->MotorBlowersSwitchOff(true, end::rear); - } - } -} - -void TTrain::OnCommand_motorblowersdisableall(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - if (Train->ggMotorBlowersAllOffButton.type() == TGaugeType::push) - { - // impulse switch - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggMotorBlowersAllOffButton.UpdateValue(1.f, Train->dsbSwitch); - Train->mvControlled->MotorBlowersSwitchOff(true, end::front); - Train->mvControlled->MotorBlowersSwitchOff(true, end::rear); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggMotorBlowersAllOffButton.UpdateValue(0.f, Train->dsbSwitch); - Train->mvControlled->MotorBlowersSwitchOff(false, end::front); - Train->mvControlled->MotorBlowersSwitchOff(false, end::rear); - } - } - else - { - // two-state switch, only cares about press events - // NOTE: generally this switch doesn't come in two-state form - if (Command.action == GLFW_PRESS) - { - if (Train->ggMotorBlowersAllOffButton.GetDesiredValue() < 0.5f) - { - // switch is off, activate - Train->mvControlled->MotorBlowersSwitchOff(true, end::front); - Train->mvControlled->MotorBlowersSwitchOff(true, end::rear); - // visual feedback - Train->ggMotorBlowersRearButton.UpdateValue(1.f, Train->dsbSwitch); - } - else - { - // deactivate - Train->mvControlled->MotorBlowersSwitchOff(false, end::front); - Train->mvControlled->MotorBlowersSwitchOff(false, end::rear); - // visual feedback - Train->ggMotorBlowersRearButton.UpdateValue(0.f, Train->dsbSwitch); - } - } - } -} - -void TTrain::OnCommand_coolingfanstoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_PRESS) - { - return; - } - - Train->mvControlled->RVentForceOn = !Train->mvControlled->RVentForceOn; -} - -void TTrain::OnCommand_motorconnectorsopen(TTrain *Train, command_data const &Command) -{ - - // TODO: don't rely on presense of 3d model to determine presence of the switch - if (Train->ggStLinOffButton.SubModel == nullptr) - { - if (Command.action == GLFW_PRESS) - { - WriteLog("Open Motor Power Connectors button is missing, or wasn't defined"); - } - return; - } - // HACK: because we don't have modeled actual circuits this is a simplification of the real mechanics - // namely, pressing the button will flip it in the entire unit, which isn't exactly physically possible - if (Command.action == GLFW_PRESS) - { - // button works while it's held down but we can ignore repeats - if (false == Train->mvControlled->StLinSwitchOff) - { - // open the connectors - // visual feedback - Train->ggStLinOffButton.UpdateValue(1.0, Train->dsbSwitch); - - Train->mvControlled->StLinSwitchOff = true; - Train->set_paired_open_motor_connectors_button(true); - } - else - { - // potentially close the connectors - OnCommand_motorconnectorsclose(Train, Command); - } - } - else if (Command.action == GLFW_RELEASE) - { - // button released - if (Train->mvControlled->StLinSwitchType != "toggle") - { - // default button type (impulse) ceases its work on button release - // visual feedback - Train->ggStLinOffButton.UpdateValue(0.0, Train->dsbSwitch); - - Train->mvControlled->StLinSwitchOff = false; - Train->set_paired_open_motor_connectors_button(false); - } - } -} - -void TTrain::OnCommand_motorconnectorsclose(TTrain *Train, command_data const &Command) -{ - - // TODO: don't rely on presense of 3d model to determine presence of the switch - if (Train->ggStLinOffButton.SubModel == nullptr) - { - if (Command.action == GLFW_PRESS) - { - WriteLog("Open Motor Power Connectors button is missing, or wasn't defined"); - } - return; - } - - if (Command.action == GLFW_PRESS) - { - if (Train->mvControlled->StLinSwitchType == "toggle") - { - // default type of button (impulse) has only one effect on press, but the toggle type can toggle the state - // visual feedback - Train->ggStLinOffButton.UpdateValue(0.0, Train->dsbSwitch); - } - - if (false == Train->mvControlled->StLinSwitchOff) - { - return; - } // already closed - - Train->mvControlled->StLinSwitchOff = false; - Train->set_paired_open_motor_connectors_button(false); - } -} - -void TTrain::OnCommand_motordisconnect(TTrain *Train, command_data const &Command) -{ - - if (Train->mvControlled->TrainType == dt_EZT ? Train->mvControlled != Train->mvOccupied : Train->iCabn != 0) - { - // tylko w maszynowym - return; - } - - if (Command.action == GLFW_PRESS) - { - Train->mvControlled->CutOffEngine(); - } -} - -void TTrain::OnCommand_motoroverloadrelaythresholdtoggle(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (true == Train->mvControlled->ShuntModeAllow ? false == Train->mvControlled->ShuntMode : false == Train->mvControlled->MotorOverloadRelayHighThreshold) - { - // turn on - OnCommand_motoroverloadrelaythresholdsethigh(Train, Command); - } - else - { - // turn off - OnCommand_motoroverloadrelaythresholdsetlow(Train, Command); - } - } -} - -void TTrain::OnCommand_motoroverloadrelaythresholdsetlow(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - Train->mvControlled->CurrentSwitch(false); - // visual feedback - Train->ggMaxCurrentCtrl.UpdateValue(Train->mvControlled->MotorOverloadRelayHighThreshold ? 1 : 0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_motoroverloadrelaythresholdsethigh(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - Train->mvControlled->CurrentSwitch(true); - // visual feedback - Train->ggMaxCurrentCtrl.UpdateValue(Train->mvControlled->MotorOverloadRelayHighThreshold ? 1 : 0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_motoroverloadrelayreset(TTrain *Train, command_data const &Command) -{ - - if (Train->ggFuseButton.SubModel == nullptr) - { - if (Command.action == GLFW_PRESS) - { - WriteLog("Motor Overload Relay Reset button is missing, or wasn't defined"); - } - // return; - } - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggFuseButton.UpdateValue(1.0, Train->dsbSwitch); - - Train->mvControlled->FuseOn(); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggFuseButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_universalrelayreset(TTrain *Train, command_data const &Command) -{ - - auto const itemindex = static_cast(Command.command) - static_cast(user_command::universalrelayreset1); - auto &item = Train->ggRelayResetButtons[itemindex]; - - // NOTE: relay reset switches are impulse-only - if (Command.action == GLFW_PRESS) - { - Train->mvOccupied->UniversalResetButton(itemindex); - // visual feedback - item.UpdateValue(1.0); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - item.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_lightspresetactivatenext(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo == 0) - { - // no preset selector - return; - } - if (Command.action != GLFW_PRESS) - { - // one change per key press - return; - } - - if (Train->mvOccupied->LightsPos < Train->mvOccupied->LightsPosNo || true == Train->mvOccupied->LightsWrap) - { - // active light preset is stored as value in range 1-LigthPosNo - auto const restartcycle{Train->mvOccupied->LightsPos >= Train->mvOccupied->LightsPosNo}; - Train->mvOccupied->LightsPos = false == restartcycle ? Train->mvOccupied->LightsPos + 1 : 1; // wrap mode - - Train->Dynamic()->SetLights(); - // visual feedback - if (Train->ggLightsButton.SubModel != nullptr) - { - // HACK: skip submodel animation when restarting cycle, since it plays in the 'wrong' direction - if (false == restartcycle) - { - Train->ggLightsButton.UpdateValue(Train->mvOccupied->LightsPos - 1, Train->dsbSwitch); - } - else - { - Train->ggLightsButton.PutValue(Train->mvOccupied->LightsPos - 1); - } - } - } -} - -void TTrain::OnCommand_lightspresetactivateprevious(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo == 0) - { - // no preset selector - return; - } - if (Command.action != GLFW_PRESS) - { - // one change per key press - return; - } - - if (Train->mvOccupied->LightsPos > 1 || true == Train->mvOccupied->LightsWrap) - { - // active light preset is stored as value in range 1-LigthPosNo - auto const restartcycle{Train->mvOccupied->LightsPos <= 1}; - Train->mvOccupied->LightsPos = false == restartcycle ? Train->mvOccupied->LightsPos - 1 : Train->mvOccupied->LightsPosNo; // wrap mode - - Train->Dynamic()->SetLights(); - // visual feedback - if (Train->ggLightsButton.SubModel != nullptr) - { - // HACK: skip submodel animation when restarting cycle, since it plays in the 'wrong' direction - if (false == restartcycle) - { - Train->ggLightsButton.UpdateValue(Train->mvOccupied->LightsPos - 1, Train->dsbSwitch); - } - else - { - Train->ggLightsButton.PutValue(Train->mvOccupied->LightsPos - 1); - } - } - } -} - -void TTrain::OnCommand_headlighttoggleleft(TTrain *Train, command_data const &Command) -{ - - auto const vehicleend{Train->cab_to_end()}; - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_left) == 0) - { - // turn on - OnCommand_headlightenableleft(Train, Command); - } - else - { - // turn off - OnCommand_headlightdisableleft(Train, Command); - } - } -} - -void TTrain::OnCommand_lightsset(TTrain *Train, command_data const &Command) -{ - // set custom item in Lights inventory - Train->mvOccupied->Lights[end::front][17] = Command.param1; - Train->mvOccupied->Lights[end::rear][17] = Command.param2; - Train->mvOccupied->LightsPos = 18; // nasza custom pozycja - Train->Dynamic()->SetLights(); -} - -void TTrain::OnCommand_headlightenableleft(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggLeftLightButton.UpdateValue(1.0, Train->dsbSwitch); - // implementation - auto const vehicleend{Train->cab_to_end()}; - - if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_left) == 0) - { - Train->mvOccupied->iLights[vehicleend] ^= light::headlight_left; - } - // if the light is controlled by 3-way switch, disable marker light - if (Train->ggLeftEndLightButton.SubModel == nullptr) - { - Train->mvOccupied->iLights[vehicleend] &= ~light::redmarker_left; - } - } -} - -void TTrain::OnCommand_headlightdisableleft(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - int const vehicleend{Train->cab_to_end()}; - - if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_left) == 0) - { - return; - } // already disabled - - Train->mvOccupied->iLights[vehicleend] ^= light::headlight_left; - // visual feedback - Train->ggLeftLightButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_headlighttoggleright(TTrain *Train, command_data const &Command) -{ - - auto const vehicleend{Train->cab_to_end()}; - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_right) == 0) - { - // turn on - OnCommand_headlightenableright(Train, Command); - } - else - { - // turn off - OnCommand_headlightdisableright(Train, Command); - } - } -} - -void TTrain::OnCommand_headlightenableright(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->ggRightLightButton.UpdateValue(1.0, Train->dsbSwitch); - // implementation - auto const vehicleend{Train->cab_to_end()}; - - if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_right) == 0) - { - Train->mvOccupied->iLights[vehicleend] ^= light::headlight_right; - } - // if the light is controlled by 3-way switch, disable marker light - if (Train->ggRightEndLightButton.SubModel == nullptr) - { - Train->mvOccupied->iLights[vehicleend] &= ~light::redmarker_right; - } - } -} - -void TTrain::OnCommand_headlightdisableright(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const vehicleend{Train->cab_to_end()}; - - if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_right) == 0) - { - return; - } // already disabled - - Train->mvOccupied->iLights[vehicleend] ^= light::headlight_right; - // visual feedback - Train->ggRightLightButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_headlighttoggleupper(TTrain *Train, command_data const &Command) -{ - - auto const vehicleend{Train->cab_to_end()}; - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_upper) == 0) - { - // turn on - OnCommand_headlightenableupper(Train, Command); - } - else - { - // turn off - OnCommand_headlightdisableupper(Train, Command); - } - } -} - -void TTrain::OnCommand_headlightenableupper(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const vehicleend{Train->cab_to_end()}; - - if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_upper) != 0) - { - return; - } // already enabled - - Train->mvOccupied->iLights[vehicleend] ^= light::headlight_upper; - // visual feedback - Train->ggUpperLightButton.UpdateValue(1.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_headlightdisableupper(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const vehicleend{Train->cab_to_end()}; - - if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_upper) == 0) - { - return; - } // already disabled - - Train->mvOccupied->iLights[vehicleend] ^= light::headlight_upper; - // visual feedback - Train->ggUpperLightButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_redmarkertoggleleft(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const vehicleend{Train->cab_to_end()}; - - if ((Train->mvOccupied->iLights[vehicleend] & light::redmarker_left) == 0) - { - // turn on - OnCommand_redmarkerenableleft(Train, Command); - } - else - { - // turn off - OnCommand_redmarkerdisableleft(Train, Command); - } - } -} - -void TTrain::OnCommand_redmarkerenableleft(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const vehicleend{Train->cab_to_end()}; - - if ((Train->mvOccupied->iLights[vehicleend] & light::redmarker_left) != 0) - { - return; - } // already enabled - - Train->mvOccupied->iLights[vehicleend] ^= light::redmarker_left; - // visual feedback - if (Train->ggLeftEndLightButton.SubModel != nullptr) - { - Train->ggLeftEndLightButton.UpdateValue(1.0, Train->dsbSwitch); - } - else - { - // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch - // this is crude, but for now will do - Train->ggLeftLightButton.UpdateValue(-1.0, Train->dsbSwitch); - // if the light is controlled by 3-way switch, disable the headlight - Train->mvOccupied->iLights[vehicleend] &= ~light::headlight_left; - } - } -} - -void TTrain::OnCommand_redmarkerdisableleft(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const vehicleend{Train->cab_to_end()}; - - if ((Train->mvOccupied->iLights[vehicleend] & light::redmarker_left) == 0) - { - return; - } // already disabled - - Train->mvOccupied->iLights[vehicleend] ^= light::redmarker_left; - // visual feedback - if (Train->ggLeftEndLightButton.SubModel != nullptr) - { - Train->ggLeftEndLightButton.UpdateValue(0.0, Train->dsbSwitch); - } - else - { - // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch - // this is crude, but for now will do - Train->ggLeftLightButton.UpdateValue(0.0, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_redmarkertoggleright(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const vehicleend{Train->cab_to_end()}; - - if ((Train->mvOccupied->iLights[vehicleend] & light::redmarker_right) == 0) - { - // turn on - OnCommand_redmarkerenableright(Train, Command); - } - else - { - // turn off - OnCommand_redmarkerdisableright(Train, Command); - } - } -} - -void TTrain::OnCommand_redmarkerenableright(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const vehicleend{Train->cab_to_end()}; - - if ((Train->mvOccupied->iLights[vehicleend] & light::redmarker_right) != 0) - { - return; - } // already enabled - - Train->mvOccupied->iLights[vehicleend] ^= light::redmarker_right; - // visual feedback - if (Train->ggRightEndLightButton.SubModel != nullptr) - { - Train->ggRightEndLightButton.UpdateValue(1.0, Train->dsbSwitch); - } - else - { - // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch - // this is crude, but for now will do - Train->ggRightLightButton.UpdateValue(-1.0, Train->dsbSwitch); - // if the light is controlled by 3-way switch, disable the headlight - Train->mvOccupied->iLights[vehicleend] &= ~light::headlight_right; - } - } -} - -void TTrain::OnCommand_redmarkerdisableright(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const vehicleend{Train->cab_to_end()}; - - if ((Train->mvOccupied->iLights[vehicleend] & light::redmarker_right) == 0) - { - return; - } // already disabled - - Train->mvOccupied->iLights[vehicleend] ^= light::redmarker_right; - // visual feedback - if (Train->ggRightEndLightButton.SubModel != nullptr) - { - Train->ggRightEndLightButton.UpdateValue(0.0, Train->dsbSwitch); - } - else - { - // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch - // this is crude, but for now will do - Train->ggRightLightButton.UpdateValue(0.0, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_headlighttogglerearleft(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc - auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_right) == 0) - { - OnCommand_headlightenablerearleft(Train, Command); - } - else - { - OnCommand_headlightdisablerearleft(Train, Command); - } - } -} - -void TTrain::OnCommand_headlightenablerearleft(TTrain *Train, command_data const &Command) -{ - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; - // already enabled - if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_right) == 0) - { - // turn on - Train->mvOccupied->iLights[vehicleotherend] ^= light::headlight_right; - // visual feedback - Train->ggRearLeftLightButton.UpdateValue(1.0, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_headlightdisablerearleft(TTrain *Train, command_data const &Command) -{ - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - if (Command.action == GLFW_PRESS) - { - auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; - // already disabled - if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_right) == 0) - { - return; - } - - // turn off - Train->mvOccupied->iLights[vehicleotherend] ^= light::headlight_right; - // visual feedback - Train->ggRearLeftLightButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_headlighttogglerearright(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc - auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_left) == 0) - { - OnCommand_headlightenablerearright(Train, Command); - } - else - { - OnCommand_headlightdisablerearright(Train, Command); - } - } -} - -void TTrain::OnCommand_headlightenablerearright(TTrain *Train, command_data const &Command) -{ - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc - auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; - - if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_left) == 0) - { - // turn on - Train->mvOccupied->iLights[vehicleotherend] ^= light::headlight_left; - // visual feedback - Train->ggRearRightLightButton.UpdateValue(1.0, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_headlightdisablerearright(TTrain *Train, command_data const &Command) -{ - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc - auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; - // already disabled - if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_left) == 0) - { - return; - } - - // turn off - Train->mvOccupied->iLights[vehicleotherend] ^= light::headlight_left; - // visual feedback - Train->ggRearRightLightButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_headlighttogglerearupper(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; - if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_upper) == 0) - { - OnCommand_headlightenablerearupper(Train, Command); - } - else - { - OnCommand_headlightdisablerearupper(Train, Command); - } - } -} - -void TTrain::OnCommand_headlightenablerearupper(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; - if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_upper) == 0) - { - // turn on - Train->mvOccupied->iLights[vehicleotherend] ^= light::headlight_upper; - // visual feedback - Train->ggRearUpperLightButton.UpdateValue(1.0, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_headlightdisablerearupper(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; - // already disabled? - if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_upper) == 0) - { - return; - } - - // turn off - Train->mvOccupied->iLights[vehicleotherend] ^= light::headlight_upper; - // visual feedback - Train->ggRearUpperLightButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_modernlightdimmerincrease(TTrain *Train, command_data const &Command) -{ - if (!Train->mvOccupied->enableModernDimmer) - return; // if modern dimmer is disabled, skip entire command - if (Command.action == GLFW_PRESS) - { - // update modern dimmer state - - auto &dimPos = Train->mvOccupied->modernDimmerPosition; - auto dimCount = Train->mvOccupied->dimPositions.size(); - if (dimPos + 1 < dimCount) - dimPos++; - else if (Train->mvOccupied->modernDimmerCanCycle) - dimPos = 0; // return to 0 - else - return; // już na minimum i nie można cyklicznie - // update lightning - // Train->Dynamic()->SetLights(); - Train->Dynamic()->SetLightDimmings(); - - // visual feedback - if (Train->ggModernLightDimSw.SubModel != nullptr) - Train->ggModernLightDimSw.UpdateValue(dimPos, Train->dsbSwitch); - } -} -void TTrain::OnCommand_modernlightdimmerdecrease(TTrain *Train, command_data const &Command) -{ - if (!Train->mvOccupied->enableModernDimmer) - return; // jeśli dimmer jest wyłączony, olewamy - - if (Command.action == GLFW_PRESS) - { - auto &dimPos = Train->mvOccupied->modernDimmerPosition; - auto dimCount = Train->mvOccupied->dimPositions.size(); - - if (dimCount == 0) - return; - - if (dimPos > 0) - dimPos--; - else if (Train->mvOccupied->modernDimmerCanCycle) - dimPos = static_cast(dimCount - 1); // ostatnia pozycja - else - return; // już na minimum i nie można cyklicznie - - // Train->Dynamic()->SetLights(); - Train->Dynamic()->SetLightDimmings(); - - if (Train->ggModernLightDimSw.SubModel != nullptr) - Train->ggModernLightDimSw.UpdateValue(dimPos, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_redmarkertogglerearleft(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc - auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if ((Train->mvOccupied->iLights[vehicleotherend] & light::redmarker_right) == 0) - { - OnCommand_redmarkerenablerearleft(Train, Command); - } - else - { - OnCommand_redmarkerdisablerearleft(Train, Command); - } - } -} - -void TTrain::OnCommand_redmarkerenablerearleft(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc - auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; - if ((Train->mvOccupied->iLights[vehicleotherend] & light::redmarker_right) == 0) - { - // turn on - Train->mvOccupied->iLights[vehicleotherend] ^= light::redmarker_right; - // visual feedback - Train->ggRearLeftEndLightButton.UpdateValue(1.0, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_redmarkerdisablerearleft(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc - auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; - if ((Train->mvOccupied->iLights[vehicleotherend] & light::redmarker_right) == 0) - { - return; - } - // turn off - Train->mvOccupied->iLights[vehicleotherend] ^= light::redmarker_right; - // visual feedback - Train->ggRearLeftEndLightButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_redmarkertogglerearright(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc - auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if ((Train->mvOccupied->iLights[vehicleotherend] & light::redmarker_left) == 0) - { - OnCommand_redmarkerenablerearright(Train, Command); - } - else - { - OnCommand_redmarkerdisablerearright(Train, Command); - } - } -} - -void TTrain::OnCommand_redmarkerenablerearright(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc - auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; - if ((Train->mvOccupied->iLights[vehicleotherend] & light::redmarker_left) == 0) - { - // turn on - Train->mvOccupied->iLights[vehicleotherend] ^= light::redmarker_left; - // visual feedback - Train->ggRearRightEndLightButton.UpdateValue(1.0, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_redmarkerdisablerearright(TTrain *Train, command_data const &Command) -{ - - if (Train->mvOccupied->LightsPosNo > 0) - { - // lights are controlled by preset selector - return; - } - - if (Command.action == GLFW_PRESS) - { - // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc - auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; - if ((Train->mvOccupied->iLights[vehicleotherend] & light::redmarker_left) == 0) - { - return; - } - // turn off - Train->mvOccupied->iLights[vehicleotherend] ^= light::redmarker_left; - // visual feedback - Train->ggRearRightEndLightButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_redmarkerstoggle(TTrain *Train, command_data const &Command) -{ - - if (true == Command.freefly && Command.action == GLFW_PRESS) - { - - auto *vehicle{std::get(simulation::Region->find_vehicle(Command.location, 10, false, true))}; - - if (vehicle == nullptr) - { - return; - } - - auto locationHead = vehicle->HeadPosition() - glm::dvec3(Command.location); // TODO: Maybe command_data should be dvec3? - auto locationRear = vehicle->RearPosition() - glm::dvec3(Command.location); - int const CouplNr{std::clamp(vehicle->DirectionGet() * (glm::dot(locationHead, locationHead) > glm::dot(locationRear, locationRear) ? 1 : -1), 0, 1)}; // z [-1,1] zrobić [0,1] - - auto const lightset{light::redmarker_left | light::redmarker_right}; - - vehicle->MoverParameters->iLights[CouplNr] = - false == TestFlag(vehicle->MoverParameters->iLights[CouplNr], lightset) ? - vehicle->MoverParameters->iLights[CouplNr] |= lightset : // turn signals on - vehicle->MoverParameters->iLights[CouplNr] ^= lightset; // turn signals off - } -} - -void TTrain::OnCommand_endsignalstoggle(TTrain *Train, command_data const &Command) -{ - - if (true == Command.freefly && Command.action == GLFW_PRESS) - { - - auto *vehicle{std::get(simulation::Region->find_vehicle(Command.location, 10, false, true))}; - - if (vehicle == nullptr) - { - return; - } - int const CouplNr{ - std::clamp(vehicle->DirectionGet() * (glm::length2(vehicle->HeadPosition() - glm::dvec3(Command.location)) > glm::length2(vehicle->RearPosition() - glm::dvec3(Command.location)) ? 1 : -1), 0, - 1)}; // z [-1,1] zrobić [0,1] - - auto const lightset{light::rearendsignals}; - - vehicle->MoverParameters->iLights[CouplNr] = - false == TestFlag(vehicle->MoverParameters->iLights[CouplNr], lightset) ? - vehicle->MoverParameters->iLights[CouplNr] |= lightset : // turn signals on - vehicle->MoverParameters->iLights[CouplNr] ^= lightset; // turn signals off - } -} - -void TTrain::OnCommand_headlightsdimtoggle(TTrain *Train, command_data const &Command) -{ - if (Train->DynamicObject->MoverParameters->enableModernDimmer) - return; - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (Train->DynamicObject->MoverParameters->modernDimmerPosition == 0) - { - // turn on - OnCommand_headlightsdimenable(Train, Command); - } - else - { - // turn off - OnCommand_headlightsdimdisable(Train, Command); - } - } -} - -void TTrain::OnCommand_headlightsdimenable(TTrain *Train, command_data const &Command) -{ - - if (Train->DynamicObject->MoverParameters->enableModernDimmer) - return; - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (Train->ggDimHeadlightsButton.SubModel != nullptr) - { - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - // visual feedback - Train->ggDimHeadlightsButton.UpdateValue(1.0, Train->dsbSwitch); - } - - /* // to jest stara logika - if (true == Train->DynamicObject->DimHeadlights) - { - return; - } // already enabled - - Train->DynamicObject->DimHeadlights = true; - */ - Train->DynamicObject->MoverParameters->modernDimmerPosition = 1; // ustawiamy modern dimmer na flage przyciemnienia - Train->DynamicObject->SetLightDimmings(); - } -} - -void TTrain::OnCommand_headlightsdimdisable(TTrain *Train, command_data const &Command) -{ - - if (Train->DynamicObject->MoverParameters->enableModernDimmer) // nie wiem dlaczego to tak dziala ze jest odwrocona logika - return; - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (Train->ggDimHeadlightsButton.SubModel != nullptr) - { - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - // visual feedback - Train->ggDimHeadlightsButton.UpdateValue(0.0, Train->dsbSwitch); - } - - /* // stara logika przyciemniania - if( false == Train->DynamicObject->DimHeadlights ) { return; } // already enabled - - Train->DynamicObject->DimHeadlights = false; - - */ - Train->DynamicObject->MoverParameters->modernDimmerPosition = 0; // ustawiamy modern dimmer na flage rozjasnienia - Train->DynamicObject->SetLightDimmings(); - } -} - -void TTrain::OnCommand_interiorlighttoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->Cabine[Train->iCabn].bLight) - { - // turn on - OnCommand_interiorlightenable(Train, Command); - } - else - { - // turn off - OnCommand_interiorlightdisable(Train, Command); - } - } -} - -void TTrain::OnCommand_interiorlightenable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->m_controlmapper.contains("cablight_sw:")) - { - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - WriteLog("Interior Light switch is missing, or wasn't defined"); - return; - } - // store lighting switch states - if (false == Train->DynamicObject->JointCabs) - { - // vehicles with separate cabs get separate lighting switch states - Train->Cabine[Train->iCabn].bLight = true; - } - else - { - // joint virtual cabs share lighting switch states - for (auto &cab : Train->Cabine) - { - cab.bLight = true; - } - } - } -} - -void TTrain::OnCommand_interiorlightdisable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->m_controlmapper.contains("cablight_sw:")) - { - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - WriteLog("Interior Light switch is missing, or wasn't defined"); - return; - } - // store lighting switch states - if (false == Train->DynamicObject->JointCabs) - { - // vehicles with separate cabs get separate lighting switch states - Train->Cabine[Train->iCabn].bLight = false; - } - else - { - // joint virtual cabs share lighting switch states - for (auto &cab : Train->Cabine) - { - cab.bLight = false; - } - } - } -} - -void TTrain::OnCommand_interiorlightdimtoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->Cabine[Train->iCabn].bLightDim) - { - // turn on - OnCommand_interiorlightdimenable(Train, Command); - } - else - { - // turn off - OnCommand_interiorlightdimdisable(Train, Command); - } - } -} - -void TTrain::OnCommand_interiorlightdimenable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (Train->ggCabLightDimButton.SubModel == nullptr) - { - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - WriteLog("Dim Interior Light switch is missing, or wasn't defined"); - return; - } - // visual feedback - Train->ggCabLightDimButton.UpdateValue(1.0, Train->dsbSwitch); - // store lighting switch states - if (false == Train->DynamicObject->JointCabs) - { - // vehicles with separate cabs get separate lighting switch states - Train->Cabine[Train->iCabn].bLightDim = true; - } - else - { - // joint virtual cabs share lighting switch states - for (auto &cab : Train->Cabine) - { - cab.bLightDim = true; - } - } - } -} - -void TTrain::OnCommand_interiorlightdimdisable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (Train->ggCabLightDimButton.SubModel == nullptr) - { - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - WriteLog("Dim Interior Light switch is missing, or wasn't defined"); - return; - } - // visual feedback - Train->ggCabLightDimButton.UpdateValue(0.0, Train->dsbSwitch); - // store lighting switch states - if (false == Train->DynamicObject->JointCabs) - { - // vehicles with separate cabs get separate lighting switch states - Train->Cabine[Train->iCabn].bLightDim = false; - } - else - { - // joint virtual cabs share lighting switch states - for (auto &cab : Train->Cabine) - { - cab.bLightDim = false; - } - } - } -} - -void TTrain::OnCommand_compartmentlightstoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - - // keep the switch from flipping back and forth if key is held down - if (false == Train->mvOccupied->CompartmentLights.is_active && false == Train->mvOccupied->CompartmentLights.is_enabled) - { - // turn on - OnCommand_compartmentlightsenable(Train, Command); - } - else - { - // turn off - OnCommand_compartmentlightsdisable(Train, Command); - } -} - -void TTrain::OnCommand_compartmentlightsenable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - Train->mvOccupied->CompartmentLightsSwitch(true); - if (Train->m_controlmapper.contains("compartmentlights_sw:")) - { - auto const istoggle{(static_cast(Train->ggCompartmentLightsButton.type()) & static_cast(TGaugeType::toggle)) != 0}; - if (istoggle) - { - Train->mvOccupied->CompartmentLightsSwitchOff(false); - } - } - // visual feedback - if (Train->m_controlmapper.contains("compartmentlights_sw:")) - { - Train->ggCompartmentLightsButton.UpdateValue(1.0f, Train->dsbSwitch); - } - if (Train->m_controlmapper.contains("compartmentlightson_sw:")) - { - Train->ggCompartmentLightsOnButton.UpdateValue(1.0f, Train->dsbSwitch); - } - } - else if (Command.action == GLFW_RELEASE) - { - if (Train->m_controlmapper.contains("compartmentlights_sw:")) - { - if (Train->ggCompartmentLightsButton.type() == TGaugeType::push) - { - // return the switch to neutral position - Train->mvOccupied->CompartmentLightsSwitch(false); - Train->mvOccupied->CompartmentLightsSwitchOff(false); - Train->ggCompartmentLightsButton.UpdateValue(0.5f); - } - } - if (Train->m_controlmapper.contains("compartmentlightson_sw:")) - { - Train->mvOccupied->CompartmentLightsSwitch(false); - Train->ggCompartmentLightsOnButton.UpdateValue(0.0f, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_compartmentlightsdisable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - Train->mvOccupied->CompartmentLightsSwitchOff(true); - if (Train->m_controlmapper.contains("compartmentlights_sw:")) - { - auto const istoggle{(static_cast(Train->ggCompartmentLightsButton.type()) & static_cast(TGaugeType::toggle)) != 0}; - if (istoggle) - { - Train->mvOccupied->CompartmentLightsSwitch(false); - } - } - // visual feedback - if (Train->m_controlmapper.contains("compartmentlights_sw:")) - { - Train->ggCompartmentLightsButton.UpdateValue(0.0f, Train->dsbSwitch); - } - if (Train->m_controlmapper.contains("compartmentlightsoff_sw:")) - { - Train->ggCompartmentLightsOffButton.UpdateValue(1.0f, Train->dsbSwitch); - } - } - else if (Command.action == GLFW_RELEASE) - { - if (Train->m_controlmapper.contains("compartmentlights_sw:")) - { - if (Train->ggCompartmentLightsButton.type() == TGaugeType::push) - { - // return the switch to neutral position - Train->mvOccupied->CompartmentLightsSwitch(false); - Train->mvOccupied->CompartmentLightsSwitchOff(false); - Train->ggCompartmentLightsButton.UpdateValue(0.5f); - } - } - if (Train->m_controlmapper.contains("compartmentlightsoff_sw:")) - { - Train->mvOccupied->CompartmentLightsSwitchOff(false); - Train->ggCompartmentLightsOffButton.UpdateValue(0.0f, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_instrumentlighttoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->InstrumentLightActive) - { - // turn on - OnCommand_instrumentlightenable(Train, Command); - } - else - { - // turn off - OnCommand_instrumentlightdisable(Train, Command); - } - } -} - -void TTrain::OnCommand_instrumentlightenable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (Train->ggInstrumentLightButton.SubModel == nullptr) - { - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - WriteLog("Instrument Light switch is missing, or wasn't defined"); - return; - } - // visual feedback - Train->ggInstrumentLightButton.UpdateValue(1.0, Train->dsbSwitch); - - if (true == Train->InstrumentLightActive) - { - return; - } // already enabled - - Train->InstrumentLightActive = true; - } -} - -void TTrain::OnCommand_instrumentlightdisable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (Train->ggInstrumentLightButton.SubModel == nullptr) - { - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - WriteLog("Instrument Light switch is missing, or wasn't defined"); - return; - } - // visual feedback - Train->ggInstrumentLightButton.UpdateValue(0.0, Train->dsbSwitch); - - if (false == Train->InstrumentLightActive) - { - return; - } // already disabled - - Train->InstrumentLightActive = false; - } -} - -void TTrain::OnCommand_dashboardlighttoggle(TTrain *Train, command_data const &Command) -{ - if (false == Train->DashboardLightActive) - { - OnCommand_dashboardlightenable(Train, Command); - } - else - { - OnCommand_dashboardlightdisable(Train, Command); - } -} - -void TTrain::OnCommand_dashboardlightenable(TTrain *Train, command_data const &Command) -{ - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (Command.action != GLFW_PRESS) - { - return; - } - - if (Train->ggDashboardLightButton.SubModel == nullptr) - { - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - WriteLog("Dashboard Light switch is missing, or wasn't defined"); - return; - } - - if (false == Train->DashboardLightActive) - { - // turn on - Train->DashboardLightActive = true; - // visual feedback - Train->ggDashboardLightButton.UpdateValue(1.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_dashboardlightdisable(TTrain *Train, command_data const &Command) -{ - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (Command.action != GLFW_PRESS) - { - return; - } - - if (Train->ggDashboardLightButton.SubModel == nullptr) - { - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - WriteLog("Dashboard Light switch is missing, or wasn't defined"); - return; - } - - if (Train->DashboardLightActive) - { - // turn off - Train->DashboardLightActive = false; - // visual feedback - Train->ggDashboardLightButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_timetablelighttoggle(TTrain *Train, command_data const &Command) -{ - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (Command.action != GLFW_PRESS) - { - return; - } - - if (false == Train->TimetableLightActive) - { - OnCommand_timetablelightenable(Train, Command); - } - else - { - OnCommand_timetablelightdisable(Train, Command); - } -} - -void TTrain::OnCommand_timetablelightenable(TTrain *Train, command_data const &Command) -{ - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (Command.action != GLFW_PRESS) - { - return; - } - - if (Train->ggTimetableLightButton.SubModel == nullptr) - { - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - WriteLog("Timetable Light switch is missing, or wasn't defined"); - return; - } - - if (false == Train->TimetableLightActive) - { - // turn on - Train->TimetableLightActive = true; - // visual feedback - Train->ggTimetableLightButton.UpdateValue(1.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_timetablelightdisable(TTrain *Train, command_data const &Command) -{ - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (Command.action != GLFW_PRESS) - { - return; - } - - if (Train->ggTimetableLightButton.SubModel == nullptr) - { - // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels - WriteLog("Timetable Light switch is missing, or wasn't defined"); - return; - } - if (Train->TimetableLightActive) - { - // turn off - Train->TimetableLightActive = false; - // visual feedback - Train->ggTimetableLightButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_heatingtoggle(TTrain *Train, command_data const &Command) -{ - - if (Train->ggTrainHeatingButton.SubModel == nullptr) - { - if (Command.action == GLFW_PRESS) - { - WriteLog("Train Heating switch is missing, or wasn't defined"); - } - return; - } - - if (Command.action == GLFW_PRESS) - { - // ignore repeats so the switch doesn't flip back and forth if key is held down - if (false == Train->mvControlled->HeatingAllow) - { - // turn on - OnCommand_heatingenable(Train, Command); - } - else - { - // turn off - OnCommand_heatingdisable(Train, Command); - } - } - else if (Command.action == GLFW_RELEASE) - { - - if (Train->ggTrainHeatingButton.type() == TGaugeType::push) - { - // impulse switch - // visual feedback - Train->ggTrainHeatingButton.UpdateValue(0.0, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_heatingenable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - Train->mvOccupied->HeatingSwitch(true); - // visual feedback - Train->ggTrainHeatingButton.UpdateValue(1.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_heatingdisable(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - Train->mvOccupied->HeatingSwitch(false); - // visual feedback - Train->ggTrainHeatingButton.UpdateValue(Train->ggTrainHeatingButton.type() == TGaugeType::push ? 1.0 : 0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_generictoggle(TTrain *Train, command_data const &Command) -{ - - auto const itemindex = static_cast(Command.command) - static_cast(user_command::generictoggle0); - auto &item = Train->ggUniversals[itemindex]; - /* - if( item.SubModel == nullptr ) { - if( Command.action == GLFW_PRESS ) { - WriteLog( "Train generic item " + std::to_string( itemindex ) + " is missing, or wasn't defined" ); - } - return; - } - */ - - if (Command.action == GLFW_PRESS) - { - - if (item.type() == TGaugeType::push) - { - // impulse switch - // turn on - // visual feedback - item.UpdateValue(1.0); - } - else - { - // two-state switch - if (item.GetDesiredValue() < 0.5) - { - // turn on - // visual feedback - item.UpdateValue(1.0); - } - else - { - // turn off - // visual feedback - item.UpdateValue(0.0); - } - } - } - else if (Command.action == GLFW_RELEASE) - { - - if (item.type() == TGaugeType::push) - { - // impulse switch - // turn off - // visual feedback - item.UpdateValue(0.0); - } - } -} - -void TTrain::OnCommand_springbraketoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->mvOccupied->SpringBrake.Activate) - { - // turn on - OnCommand_springbrakeenable(Train, Command); - } - else - { - // turn off - OnCommand_springbrakedisable(Train, Command); - } - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - Train->ggSpringBrakeOffButton.UpdateValue(0.0, Train->dsbSwitch); - Train->ggSpringBrakeOnButton.UpdateValue(0.0, Train->dsbSwitch); - } -}; - -void TTrain::OnCommand_springbrakeenable(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - Train->mvOccupied->SpringBrakeActivate(true); - // visual feedback - Train->ggSpringBrakeOnButton.UpdateValue(1.0, Train->dsbSwitch); - Train->ggSpringBrakeOffButton.UpdateValue(0.0, Train->dsbSwitch); - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - Train->ggSpringBrakeOnButton.UpdateValue(0.0, Train->dsbSwitch); - } -}; - -void TTrain::OnCommand_springbrakedisable(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - Train->mvOccupied->SpringBrakeActivate(false); - // visual feedback - Train->ggSpringBrakeOffButton.UpdateValue(1.0, Train->dsbSwitch); - Train->ggSpringBrakeOnButton.UpdateValue(0.0, Train->dsbSwitch); - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - Train->ggSpringBrakeOffButton.UpdateValue(0.0, Train->dsbSwitch); - } -}; -void TTrain::OnCommand_springbrakeshutofftoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - if (false == Train->mvOccupied->SpringBrake.ShuttOff) - { - // turn on - OnCommand_springbrakeshutoffenable(Train, Command); - } - else - { - // turn off - OnCommand_springbrakeshutoffdisable(Train, Command); - } - } -}; - -void TTrain::OnCommand_springbrakeshutoffenable(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - Train->mvOccupied->SpringBrakeShutOff(true); - } -}; - -void TTrain::OnCommand_springbrakeshutoffdisable(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - Train->mvOccupied->SpringBrakeShutOff(false); - } -}; - -void TTrain::OnCommand_springbrakerelease(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - - auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; - if (vehicle == nullptr) - { - return; - } - Train->mvOccupied->SpringBrakeRelease(); - } -}; - -void TTrain::OnCommand_speedcontrolincrease(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - Train->mvOccupied->SpeedCtrlInc(); - // visual feedback - Train->ggSpeedControlIncreaseButton.UpdateValue(1.0, Train->dsbSwitch); - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - Train->ggSpeedControlIncreaseButton.UpdateValue(0.0, Train->dsbSwitch); - } -}; - -void TTrain::OnCommand_speedcontroldecrease(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - Train->mvOccupied->SpeedCtrlDec(); - // visual feedback - Train->ggSpeedControlDecreaseButton.UpdateValue(1.0, Train->dsbSwitch); - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - Train->ggSpeedControlDecreaseButton.UpdateValue(0.0, Train->dsbSwitch); - } -}; - -void TTrain::OnCommand_speedcontrolpowerincrease(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - Train->mvOccupied->SpeedCtrlPowerInc(); - // visual feedback - Train->ggSpeedControlPowerIncreaseButton.UpdateValue(1.0, Train->dsbSwitch); - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - Train->ggSpeedControlPowerIncreaseButton.UpdateValue(0.0, Train->dsbSwitch); - } -}; - -void TTrain::OnCommand_speedcontrolpowerdecrease(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - Train->mvOccupied->SpeedCtrlPowerDec(); - // visual feedback - Train->ggSpeedControlPowerDecreaseButton.UpdateValue(1.0, Train->dsbSwitch); - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - Train->ggSpeedControlPowerDecreaseButton.UpdateValue(0.0, Train->dsbSwitch); - } -}; - -void TTrain::OnCommand_speedcontrolbutton(TTrain *Train, command_data const &Command) -{ - - auto const itemindex = static_cast(Command.command) - static_cast(user_command::speedcontrolbutton0); - auto &item = Train->ggSpeedCtrlButtons[itemindex]; - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - Train->mvOccupied->SpeedCtrlButton(itemindex); - // visual feedback - Train->ggSpeedCtrlButtons[itemindex].UpdateValue(1.0, Train->dsbSwitch); - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - Train->ggSpeedCtrlButtons[itemindex].UpdateValue(0.0, Train->dsbSwitch); - } -}; - -void TTrain::OnCommand_inverterenable(TTrain *Train, command_data const &Command) -{ - - auto itemindex = static_cast(Command.command) - static_cast(user_command::inverterenable1); - auto &item = Train->ggInverterEnableButtons[itemindex]; - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - bool kier = Train->DynamicObject->DirectionGet() * Train->mvOccupied->CabOccupied > 0; - int flag = Train->DynamicObject->MoverParameters->InverterControlCouplerFlag; - TDynamicObject *p = Train->DynamicObject->GetFirstDynamic(Train->mvOccupied->CabOccupied < 0 ? end::rear : end::front, flag); - while (p) - { - if (p->MoverParameters->eimc[eimc_p_Pmax] > 1) - { - if (itemindex < p->MoverParameters->InvertersNo) - { - p->MoverParameters->Inverters[itemindex].Activate = true; - break; - } - else - { - itemindex -= p->MoverParameters->InvertersNo; - } - } - p = kier ? p->Next(flag) : p->Prev(flag); - } - // visual feedback - item.UpdateValue(1.0, Train->dsbSwitch); - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - item.UpdateValue(0.0, Train->dsbSwitch); - } -}; - -void TTrain::OnCommand_inverterdisable(TTrain *Train, command_data const &Command) -{ - - auto itemindex = static_cast(Command.command) - static_cast(user_command::inverterdisable1); - auto &item = Train->ggInverterDisableButtons[itemindex]; - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - bool kier = Train->DynamicObject->DirectionGet() * Train->mvOccupied->CabOccupied > 0; - int flag = Train->DynamicObject->MoverParameters->InverterControlCouplerFlag; - TDynamicObject *p = Train->DynamicObject->GetFirstDynamic(Train->mvOccupied->CabOccupied < 0 ? end::rear : end::front, flag); - while (p) - { - if (p->MoverParameters->eimc[eimc_p_Pmax] > 1) - { - if (itemindex < p->MoverParameters->InvertersNo) - { - p->MoverParameters->Inverters[itemindex].Activate = false; - break; - } - else - { - itemindex -= p->MoverParameters->InvertersNo; - } - } - p = kier ? p->Next(flag) : p->Prev(flag); - } - // visual feedback - item.UpdateValue(1.0, Train->dsbSwitch); - } - else if (Command.action == GLFW_RELEASE) - { - // release - // visual feedback - item.UpdateValue(0.0, Train->dsbSwitch); - } -}; - -void TTrain::OnCommand_invertertoggle(TTrain *Train, command_data const &Command) -{ - - auto itemindex = static_cast(Command.command) - static_cast(user_command::invertertoggle1); - auto &item = Train->ggInverterToggleButtons[itemindex]; - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the switch doesn't flip back and forth if key is held down - bool kier = Train->DynamicObject->DirectionGet() * Train->mvOccupied->CabOccupied > 0; - int flag = Train->DynamicObject->MoverParameters->InverterControlCouplerFlag; - TDynamicObject *p = Train->DynamicObject->GetFirstDynamic(Train->mvOccupied->CabOccupied < 0 ? end::rear : end::front, flag); - while (p) - { - if (p->MoverParameters->eimc[eimc_p_Pmax] > 1) - { - if (itemindex < p->MoverParameters->InvertersNo) - { - p->MoverParameters->Inverters[itemindex].Activate = !p->MoverParameters->Inverters[itemindex].Activate; - // visual feedback - item.UpdateValue(p->MoverParameters->Inverters[itemindex].Activate ? 1.0 : 0.0, Train->dsbSwitch); - break; - } - else - { - itemindex -= p->MoverParameters->InvertersNo; - } - } - p = kier ? p->Next(flag) : p->Prev(flag); - } - } -}; - -void TTrain::OnCommand_doorlocktoggle(TTrain *Train, command_data const &Command) -{ - - if (Train->ggDoorSignallingButton.SubModel == nullptr) - { - if (Command.action == GLFW_PRESS) - { - WriteLog("Door Lock switch is missing, or wasn't defined"); - } - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the sound can loop uninterrupted - if (false == Train->mvOccupied->Doors.lock_enabled) - { - // turn on - // TODO: door lock command to send through consist - Train->mvOccupied->LockDoors(true); - // visual feedback - Train->ggDoorSignallingButton.UpdateValue(1.0, Train->dsbSwitch); - } - else - { - // turn off - // TODO: door lock command to send through consist - Train->mvOccupied->LockDoors(false); - // visual feedback - Train->ggDoorSignallingButton.UpdateValue(0.0, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_doortoggleleft(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // NOTE: test how the door state check works with consists where the occupied vehicle doesn't have opening doors - if (false == (Train->ggDoorLeftButton.GetDesiredValue() > 0.5 || Train->ggDoorLeftOnButton.GetDesiredValue() > 0.5)) - { - // open - OnCommand_dooropenleft(Train, Command); - } - else - { - // close - if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorLeftOffButton.SubModel == nullptr) - { - // OnCommand_doorcloseall( Train, Command ); - // if two-button setup lacks dedicated closing button require the user to press appropriate button manually - return; - } - else - { - OnCommand_doorcloseleft(Train, Command); - } - } - } - else if (Command.action == GLFW_RELEASE) - { - - if (true == (Train->ggDoorLeftButton.GetDesiredValue() > 0.5 || Train->ggDoorLeftOnButton.GetDesiredValue() > 0.5)) - { - // open - if (Train->mvOccupied->Doors.has_autowarning && Train->mvOccupied->DepartureSignal) - { - // complete closing the doors - if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorLeftOffButton.SubModel == nullptr) - { - // OnCommand_doorcloseall( Train, Command ); - // if two-button setup lacks dedicated closing button require the user to press appropriate button manually - return; - } - else - { - OnCommand_doorcloseleft(Train, Command); - } - } - else - { - OnCommand_dooropenleft(Train, Command); - } - } - else - { - // close - if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorLeftOffButton.SubModel == nullptr) - { - // OnCommand_doorcloseall( Train, Command ); - // if two-button setup lacks dedicated closing button require the user to press appropriate button manually - return; - } - else - { - OnCommand_doorcloseleft(Train, Command); - } - } - // visual feedback - // dedicated closing buttons are presumed to be impulse switches and return automatically to neutral position - // NOTE: temporary arrangement, can be removed when LD system is in place - if (Train->ggDoorLeftOffButton.SubModel) - Train->ggDoorLeftOffButton.UpdateValue(0.0, Train->dsbSwitch); - if (Train->ggDoorLeftOnButton.SubModel) - Train->ggDoorLeftOnButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_doorpermitleft(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - if (false == Train->mvOccupied->Doors.permit_presets.empty()) - { - return; - } - - auto const side{(Train->cab_to_end() == end::front ? side::left : side::right)}; - - if (Command.action == GLFW_PRESS) - { - - if (Train->ggDoorLeftPermitButton.is_push()) - { - // impulse switch - Train->mvOccupied->PermitDoors(side); - // visual feedback - Train->ggDoorLeftPermitButton.UpdateValue(1.0, Train->dsbSwitch); - // start potential timer for remote door control - Train->m_doorpermittimers[side] = Train->mvOccupied->DoorsOpenWithPermitAfter; - } - else - { - // two-state switch - auto const newstate{!(Train->ggDoorLeftPermitButton.GetDesiredValue() > 0.5)}; - - Train->mvOccupied->PermitDoors(side, newstate); - // visual feedback - Train->ggDoorLeftPermitButton.UpdateValue(newstate ? 1.0 : 0.0, Train->dsbSwitch); - } - } - else if (Command.action == GLFW_RELEASE) - { - - if (Train->ggDoorLeftPermitButton.is_push()) - { - // impulse switch - // visual feedback - Train->ggDoorLeftPermitButton.UpdateValue(0.0, Train->dsbSwitch); - // reset potential remote door control timer - Train->m_doorpermittimers[side] = -1.f; - } - } -} - -void TTrain::OnCommand_doorpermitright(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_REPEAT) - { - return; - } - if (false == Train->mvOccupied->Doors.permit_presets.empty()) - { - return; - } - - auto const side{(Train->cab_to_end() == end::front ? side::right : side::left)}; - - if (Command.action == GLFW_PRESS) - { - - if (Train->ggDoorRightPermitButton.type() == TGaugeType::push) - { - // impulse switch - Train->mvOccupied->PermitDoors(side); - // visual feedback - Train->ggDoorRightPermitButton.UpdateValue(1.0, Train->dsbSwitch); - // start potential timer for remote door control - Train->m_doorpermittimers[side] = Train->mvOccupied->DoorsOpenWithPermitAfter; - } - else - { - // two-state switch - auto const newstate{!(Train->ggDoorRightPermitButton.GetDesiredValue() > 0.5)}; - - Train->mvOccupied->PermitDoors(side, newstate); - // visual feedback - Train->ggDoorRightPermitButton.UpdateValue(newstate ? 1.0 : 0.0, Train->dsbSwitch); - } - } - else if (Command.action == GLFW_RELEASE) - { - - if (Train->ggDoorRightPermitButton.type() == TGaugeType::push) - { - // impulse switch - // visual feedback - Train->ggDoorRightPermitButton.UpdateValue(0.0, Train->dsbSwitch); - // reset potential remote door control timer - Train->m_doorpermittimers[side] = -1.f; - } - } -} - -void TTrain::OnCommand_doorpermitpresetactivatenext(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - Train->mvOccupied->ChangeDoorPermitPreset(1); - // visual feedback - Train->ggDoorPermitPresetButton.UpdateValue(Train->mvOccupied->Doors.permit_preset, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_doorpermitpresetactivateprevious(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - - Train->mvOccupied->ChangeDoorPermitPreset(-1); - // visual feedback - Train->ggDoorPermitPresetButton.UpdateValue(Train->mvOccupied->Doors.permit_preset, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_dooropenleft(TTrain *Train, command_data const &Command) -{ - - auto const remoteopencontrol{Train->mvOccupied->Doors.open_control == control_t::driver || Train->mvOccupied->Doors.open_control == control_t::mixed}; - - if (false == remoteopencontrol) - { - return; - } - - if (Train->ggDoorLeftOnButton.SubModel == nullptr && Train->ggDoorLeftButton.SubModel == nullptr) - { - - return; - } - - if (Command.action == GLFW_PRESS) - { - Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::left : side::right, true); - // visual feedback - if (Train->ggDoorLeftOnButton.SubModel != nullptr) - { - // two separate impulse switches - Train->ggDoorLeftOnButton.UpdateValue(1.0, Train->dsbSwitch); - } - else - { - // single two-state switch - Train->ggDoorLeftButton.UpdateValue(1.0, Train->dsbSwitch); - } - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - if (Train->ggDoorLeftOnButton.SubModel != nullptr) - { - // two separate impulse switches - Train->ggDoorLeftOnButton.UpdateValue(0.0, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_doorcloseleft(TTrain *Train, command_data const &Command) -{ - - auto const remoteclosecontrol{Train->mvOccupied->Doors.close_control == control_t::driver || Train->mvOccupied->Doors.close_control == control_t::mixed}; - - if (false == remoteclosecontrol) - { - return; - } - - if (Train->ggDoorLeftOffButton.SubModel == nullptr && Train->ggDoorLeftButton.SubModel == nullptr) - { - - return; - } - - if (Command.action == GLFW_PRESS) - { - - if (Train->mvOccupied->Doors.has_autowarning) - { - // automatic departure signal delays actual door closing until the button is released - Train->mvOccupied->signal_departure(true); - } - else - { - // TODO: move door opening/closing to the update, so the switch animation doesn't hinge on door working - Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::left : side::right, false); - } - // visual feedback - if (Train->ggDoorLeftOffButton.SubModel != nullptr) - { - // two separate switches to open and close the door - Train->ggDoorLeftOffButton.UpdateValue(1.0, Train->dsbSwitch); - } - else - { - // single two-state switch - Train->ggDoorLeftButton.UpdateValue(0.0, Train->dsbSwitch); - } - } - else if (Command.action == GLFW_RELEASE) - { - - if (Train->mvOccupied->Doors.has_autowarning) - { - // automatic departure signal delays actual door closing until the button is released - Train->mvOccupied->signal_departure(false); - // now we can actually close the door - Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::left : side::right, false); - } - // visual feedback - // dedicated closing buttons are presumed to be impulse switches and return automatically to neutral position - if (Train->ggDoorLeftOffButton.SubModel) - Train->ggDoorLeftOffButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_doortoggleright(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - // NOTE: test how the door state check works with consists where the occupied vehicle doesn't have opening doors - if (false == (Train->ggDoorRightButton.GetDesiredValue() > 0.5 || Train->ggDoorRightOnButton.GetDesiredValue() > 0.5)) - { - // open - OnCommand_dooropenright(Train, Command); - } - else - { - // close - if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorRightOffButton.SubModel == nullptr) - { - // OnCommand_doorcloseall( Train, Command ); - // if two-button setup lacks dedicated closing button require the user to press appropriate button manually - return; - } - else - { - OnCommand_doorcloseright(Train, Command); - } - } - } - else if (Command.action == GLFW_RELEASE) - { - - if (true == (Train->ggDoorRightButton.GetDesiredValue() > 0.5 || Train->ggDoorRightOnButton.GetDesiredValue() > 0.5)) - { - // open - if (Train->mvOccupied->Doors.has_autowarning && Train->mvOccupied->DepartureSignal) - { - // complete closing the doors - if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorRightOffButton.SubModel == nullptr) - { - // OnCommand_doorcloseall( Train, Command ); - // if two-button setup lacks dedicated closing button require the user to press appropriate button manually - return; - } - else - { - OnCommand_doorcloseright(Train, Command); - } - } - else - { - OnCommand_dooropenright(Train, Command); - } - } - else - { - // close - if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorRightOffButton.SubModel == nullptr) - { - // OnCommand_doorcloseall( Train, Command ); - // if two-button setup lacks dedicated closing button require the user to press appropriate button manually - return; - } - else - { - OnCommand_doorcloseright(Train, Command); - } - } - // visual feedback - // dedicated closing buttons are presumed to be impulse switches and return automatically to neutral position - // NOTE: temporary arrangement, can be removed when LD system is in place - if (Train->ggDoorRightOffButton.SubModel) - Train->ggDoorRightOffButton.UpdateValue(0.0, Train->dsbSwitch); - if (Train->ggDoorRightOnButton.SubModel) - Train->ggDoorRightOnButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_dooropenright(TTrain *Train, command_data const &Command) -{ - - auto const remoteopencontrol{Train->mvOccupied->Doors.open_control == control_t::driver || Train->mvOccupied->Doors.open_control == control_t::mixed}; - - if (false == remoteopencontrol) - { - return; - } - - if (Train->ggDoorRightOnButton.SubModel == nullptr && Train->ggDoorRightButton.SubModel == nullptr) - { - - return; - } - - if (Command.action == GLFW_PRESS) - { - - Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::right : side::left, true); - // visual feedback - if (Train->ggDoorRightOnButton.SubModel != nullptr) - { - // two separate impulse switches - Train->ggDoorRightOnButton.UpdateValue(1.0, Train->dsbSwitch); - } - else - { - // single two-state switch - Train->ggDoorRightButton.UpdateValue(1.0, Train->dsbSwitch); - } - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - if (Train->ggDoorRightOnButton.SubModel != nullptr) - { - // two separate impulse switches - Train->ggDoorRightOnButton.UpdateValue(0.0, Train->dsbSwitch); - } - } -} - -void TTrain::OnCommand_doorcloseright(TTrain *Train, command_data const &Command) -{ - - auto const remoteclosecontrol{Train->mvOccupied->Doors.close_control == control_t::driver || Train->mvOccupied->Doors.close_control == control_t::mixed}; - - if (false == remoteclosecontrol) - { - return; - } - - if (Train->ggDoorRightOffButton.SubModel == nullptr && Train->ggDoorRightButton.SubModel == nullptr) - { - - return; - } - - if (Command.action == GLFW_PRESS) - { - - if (Train->mvOccupied->Doors.has_autowarning) - { - // automatic departure signal delays actual door closing until the button is released - Train->mvOccupied->signal_departure(true); - } - else - { - Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::right : side::left, false); - } - // visual feedback - if (Train->ggDoorRightOffButton.SubModel != nullptr) - { - // two separate switches to open and close the door - Train->ggDoorRightOffButton.UpdateValue(1.0, Train->dsbSwitch); - } - else - { - // single two-state switch - Train->ggDoorRightButton.UpdateValue(0.0, Train->dsbSwitch); - } - } - else if (Command.action == GLFW_RELEASE) - { - - if (Train->mvOccupied->Doors.has_autowarning) - { - // automatic departure signal delays actual door closing until the button is released - Train->mvOccupied->signal_departure(false); - // now we can actually close the door - Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::right : side::left, false); - } - // visual feedback - // dedicated closing buttons are presumed to be impulse switches and return automatically to neutral position - if (Train->ggDoorRightOffButton.SubModel) - Train->ggDoorRightOffButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_dooropenall(TTrain *Train, command_data const &Command) -{ - - auto const remoteopencontrol{Train->mvOccupied->Doors.open_control == control_t::driver || Train->mvOccupied->Doors.open_control == control_t::mixed}; - - if (false == remoteopencontrol) - { - return; - } - - if (Train->ggDoorAllOnButton.SubModel == nullptr) - { - // TODO: expand definition of cab controls so we can know if the control is present without testing for presence of 3d switch - if (Command.action == GLFW_PRESS) - { - WriteLog("Open All Doors switch is missing, or wasn't defined"); - } - return; - } - - if (Command.action == GLFW_PRESS) - { - - Train->mvOccupied->OperateDoors(side::right, true); - Train->mvOccupied->OperateDoors(side::left, true); - // visual feedback - Train->ggDoorAllOnButton.UpdateValue(1.0, Train->dsbSwitch); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggDoorAllOnButton.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_doorcloseall(TTrain *Train, command_data const &Command) -{ - - auto const remoteclosecontrol{Train->mvOccupied->Doors.close_control == control_t::driver || Train->mvOccupied->Doors.close_control == control_t::mixed}; - - if (false == remoteclosecontrol) - { - return; - } - - if (Train->ggDoorAllOffButton.SubModel == nullptr) - { - // TODO: expand definition of cab controls so we can know if the control is present without testing for presence of 3d switch - if (Command.action == GLFW_PRESS) - { - WriteLog("Close All Doors switch is missing, or wasn't defined"); - } - return; - } - - if (Command.action == GLFW_PRESS) - { - - if (Train->mvOccupied->Doors.has_autowarning) - { - Train->mvOccupied->signal_departure(true); - } - if (Train->ggDoorAllOffButton.type() != TGaugeType::push_delayed) - { - // delays the action until the button is released - Train->mvOccupied->OperateDoors(side::right, false); - Train->mvOccupied->OperateDoors(side::left, false); - } - // visual feedback - Train->ggDoorLeftButton.UpdateValue(0.0, Train->dsbSwitch); - Train->ggDoorRightButton.UpdateValue(0.0, Train->dsbSwitch); - if (Train->ggDoorAllOffButton.SubModel) - Train->ggDoorAllOffButton.UpdateValue(1.0, Train->dsbSwitch); - } - else if (Command.action == GLFW_RELEASE) - { - if (Train->mvOccupied->Doors.has_autowarning) - { - Train->mvOccupied->signal_departure(false); - } - if (Train->ggDoorAllOffButton.type() == TGaugeType::push_delayed) - { - // now we can actually close the door - Train->mvOccupied->OperateDoors(side::right, false); - Train->mvOccupied->OperateDoors(side::left, false); - } - // visual feedback - if (Train->ggDoorAllOffButton.SubModel) - Train->ggDoorAllOffButton.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_doorsteptoggle(TTrain *Train, command_data const &Command) -{ - // TODO: move logic/visualization code to the gauge, on_command() should return hint whether it should invoke a reaction - if (Command.action == GLFW_PRESS) - { - // effect - if (false == Train->ggDoorStepButton.is_delayed()) - { - Train->mvOccupied->PermitDoorStep(false == Train->mvOccupied->Doors.step_enabled); - } - // visual feedback - auto const isactive{(Train->ggDoorStepButton.is_push() // always press push button - || Train->mvOccupied->Doors.step_enabled)}; // for toggle buttons indicate item state - Train->ggDoorStepButton.UpdateValue(isactive ? 1 : 0); - } - else if (Command.action == GLFW_RELEASE) - { - // effect - if (Train->ggDoorStepButton.is_delayed()) - { - Train->mvOccupied->PermitDoorStep(false == Train->mvOccupied->Doors.step_enabled); - } - // visual feedback - if (Train->ggDoorStepButton.is_push()) - { - Train->ggDoorStepButton.UpdateValue(0); - } - } -} - -void TTrain::OnCommand_doormodetoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - Train->mvOccupied->ChangeDoorControlMode(false == Train->mvOccupied->Doors.remote_only); - } -} - -void TTrain::OnCommand_mirrorstoggle(TTrain *Train, command_data const &Command) -{ - - if (Command.action != GLFW_PRESS) - { - return; - } - - // only reacting to press, so the sound can loop uninterrupted - if (false == Train->mvOccupied->MirrorForbidden) - { - // turn on - Train->mvOccupied->MirrorForbidden = true; - } - else - { - // turn off - Train->mvOccupied->MirrorForbidden = false; - } -} - -void TTrain::OnCommand_nearestcarcouplingincrease(TTrain *Train, command_data const &Command) -{ - - if (true == Command.freefly && Command.action == GLFW_PRESS) - { - // tryb freefly, press only - auto coupler{-1}; - auto *vehicle{Train->DynamicObject->ABuScanNearestObject(Command.location, Train->DynamicObject->GetTrack(), 1, 1500, coupler)}; - if (vehicle == nullptr) - vehicle = Train->DynamicObject->ABuScanNearestObject(Command.location, Train->DynamicObject->GetTrack(), -1, 1500, coupler); - - if (coupler != -1 && vehicle != nullptr) - { - - vehicle->couple(coupler); - } - if (Train->DynamicObject->Mechanik) - { - // aktualizacja flag kierunku w składzie - Train->DynamicObject->Mechanik->CheckVehicles(Connect); - } - } -} - -void TTrain::OnCommand_nearestcarcouplingdisconnect(TTrain *Train, command_data const &Command) -{ - - if (true == Command.freefly && Command.action == GLFW_PRESS) - { - // tryb freefly, press only - auto coupler{-1}; - auto *vehicle{Train->DynamicObject->ABuScanNearestObject(Command.location, Train->DynamicObject->GetTrack(), 1, 1500, coupler)}; - if (vehicle == nullptr) - vehicle = Train->DynamicObject->ABuScanNearestObject(Command.location, Train->DynamicObject->GetTrack(), -1, 1500, coupler); - - if (coupler != -1 && vehicle != nullptr) - { - - vehicle->uncouple(coupler); - } - if (Train->DynamicObject->Mechanik) - { - // aktualizacja flag kierunku w składzie - Train->DynamicObject->Mechanik->CheckVehicles(Disconnect); - } - } -} - -void TTrain::OnCommand_nearestcarcoupleradapterattach(TTrain *Train, command_data const &Command) -{ - - if (true == Command.freefly && Command.action == GLFW_PRESS) - { - // tryb freefly, press only - auto *vehicle{std::get(simulation::Region->find_vehicle(Command.location, 50, false, true))}; - if (vehicle == nullptr) - { - return; - } - - auto const coupler = - glm::length2(glm::vec3{vehicle->CouplerPosition(end::front)} - Command.location) < glm::length2(glm::vec3{vehicle->CouplerPosition(end::rear)} - Command.location) ? end::front : end::rear; - - vehicle->attach_coupler_adapter(coupler); - } -} - -void TTrain::OnCommand_nearestcarcoupleradapterremove(TTrain *Train, command_data const &Command) -{ - - if (true == Command.freefly && Command.action == GLFW_PRESS) - { - // tryb freefly, press only - auto *vehicle{std::get(simulation::Region->find_vehicle(Command.location, 50, false, true))}; - if (vehicle == nullptr) - { - return; - } - - auto const coupler = - glm::length2(glm::vec3{vehicle->CouplerPosition(end::front)} - Command.location) < glm::length2(glm::vec3{vehicle->CouplerPosition(end::rear)} - Command.location) ? end::front : end::rear; - - vehicle->remove_coupler_adapter(coupler); - } -} - -void TTrain::OnCommand_occupiedcarcouplingdisconnect(TTrain *Train, command_data const &Command) -{ - - // if( false == Train->m_controlmapper.contains( "couplingdisconnect_sw:" ) ) { return; } - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->m_couplingdisconnect = true; - - if (Train->iCabn == 0) - { - return; - } - - if (Train->DynamicObject) - { - Train->DynamicObject->uncouple(Train->cab_to_end()); - if (Train->DynamicObject->Mechanik) - { - // aktualizacja flag kierunku w składzie - Train->DynamicObject->Mechanik->CheckVehicles(Disconnect); - } - } - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->m_couplingdisconnect = false; - } -} - -void TTrain::OnCommand_occupiedcarcouplingdisconnectback(TTrain *Train, command_data const &Command) -{ - - // if( false == Train->m_controlmapper.contains( "couplingdisconnect_sw:" ) ) { return; } - - if (Command.action == GLFW_PRESS) - { - // visual feedback - Train->m_couplingdisconnectback = true; - - if (Train->iCabn == 0) - { - return; - } - - if (Train->DynamicObject) - { - Train->DynamicObject->uncouple(1 - Train->cab_to_end()); - if (Train->DynamicObject->Mechanik) - { - // aktualizacja flag kierunku w składzie - Train->DynamicObject->Mechanik->CheckVehicles(Disconnect); - } - } - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->m_couplingdisconnectback = false; - } -} - -void TTrain::OnCommand_departureannounce(TTrain *Train, command_data const &Command) -{ - - if (Train->ggDepartureSignalButton.SubModel == nullptr) - { - if (Command.action == GLFW_PRESS) - { - WriteLog("Departure Signal button is missing, or wasn't defined"); - } - return; - } - - if (Command.action == GLFW_PRESS) - { - // only reacting to press, so the sound can loop uninterrupted - if (false == Train->mvOccupied->DepartureSignal) - { - // turn on - Train->mvOccupied->signal_departure(true); - // visual feedback - Train->ggDepartureSignalButton.UpdateValue(1.0, Train->dsbSwitch); - } - } - else if (Command.action == GLFW_RELEASE) - { - // turn off - Train->mvOccupied->signal_departure(false); - // visual feedback - Train->ggDepartureSignalButton.UpdateValue(0.0, Train->dsbSwitch); - } -} - -void TTrain::OnCommand_hornlowactivate(TTrain *Train, command_data const &Command) -{ - - if (Train->ggHornButton.SubModel == nullptr && Train->ggHornLowButton.SubModel == nullptr) - { - if (Command.action == GLFW_PRESS) - { - WriteLog("Horn button is missing, or wasn't defined"); - } - return; - } - - if (Command.action == GLFW_PRESS) - { - // only need to react to press, sound will continue until stopped - if (false == TestFlag(Train->mvOccupied->WarningSignal, 1)) - { - // turn on - Train->mvOccupied->WarningSignal |= 1; - /* - if( true == TestFlag( Train->mvOccupied->WarningSignal, 2 ) ) { - // low and high horn are treated as mutually exclusive - Train->mvControlled->WarningSignal &= ~2; - } - */ - // visual feedback - Train->ggHornButton.UpdateValue(-1.0); - Train->ggHornLowButton.UpdateValue(1.0); - } - } - else if (Command.action == GLFW_RELEASE) - { - // turn off - /* - // NOTE: we turn off both low and high horn, due to unreliability of release event when shift key is involved - Train->mvOccupied->WarningSignal &= ~( 1 | 2 ); - */ - Train->mvOccupied->WarningSignal &= ~1; - // visual feedback - Train->ggHornButton.UpdateValue(0.0); - Train->ggHornLowButton.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_hornhighactivate(TTrain *Train, command_data const &Command) -{ - - if (Train->ggHornButton.SubModel == nullptr && Train->ggHornHighButton.SubModel == nullptr) - { - if (Command.action == GLFW_PRESS) - { - WriteLog("Horn button is missing, or wasn't defined"); - } - return; - } - - if (Command.action == GLFW_PRESS) - { - // only need to react to press, sound will continue until stopped - if (false == TestFlag(Train->mvOccupied->WarningSignal, 2)) - { - // turn on - Train->mvOccupied->WarningSignal |= 2; - /* - if( true == TestFlag( Train->mvOccupied->WarningSignal, 1 ) ) { - // low and high horn are treated as mutually exclusive - Train->mvControlled->WarningSignal &= ~1; - } - */ - // visual feedback - Train->ggHornButton.UpdateValue(1.0); - Train->ggHornHighButton.UpdateValue(1.0); - } - } - else if (Command.action == GLFW_RELEASE) - { - // turn off - /* - // NOTE: we turn off both low and high horn, due to unreliability of release event when shift key is involved - Train->mvOccupied->WarningSignal &= ~( 1 | 2 ); - */ - Train->mvOccupied->WarningSignal &= ~2; - // visual feedback - Train->ggHornButton.UpdateValue(0.0); - Train->ggHornHighButton.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_whistleactivate(TTrain *Train, command_data const &Command) -{ - - if (Train->ggWhistleButton.SubModel == nullptr) - { - if (Command.action == GLFW_PRESS) - { - WriteLog("Whistle button is missing, or wasn't defined"); - } - return; - } - - if (Command.action == GLFW_PRESS) - { - // only need to react to press, sound will continue until stopped - if (false == TestFlag(Train->mvOccupied->WarningSignal, 4)) - { - // turn on - Train->mvOccupied->WarningSignal |= 4; - // visual feedback - Train->ggWhistleButton.UpdateValue(1.0); - } - } - else if (Command.action == GLFW_RELEASE) - { - // turn off - Train->mvOccupied->WarningSignal &= ~4; - // visual feedback - Train->ggWhistleButton.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_radiotoggle(TTrain *Train, command_data const &Command) -{ - if (Command.action != GLFW_PRESS) - { - return; - } - - // NOTE: we ignore the lack of 3d model to allow system reset after receiving radio-stop signal - /* - if( false == Train->m_controlmapper.contains( "radio_sw:" ) ) { - return; - } - */ - // 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); - } -} - -void TTrain::OnCommand_radioenable(TTrain *Train, command_data const &Command) -{ - if (Command.action != GLFW_PRESS) - { - return; - } - - if (false == Train->mvOccupied->Radio) - { - Train->mvOccupied->Radio = true; - } -} - -void TTrain::OnCommand_radiodisable(TTrain *Train, command_data const &Command) -{ - if (Command.action != GLFW_PRESS) - { - return; - } - - if (Train->mvOccupied->Radio) - { - Train->mvOccupied->Radio = false; - } -} - -void TTrain::OnCommand_radiochannelincrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - command_data newCommand = Command; - newCommand.param1 = Train->RadioChannel() + 1; - OnCommand_radiochannelset(Train, newCommand); - - Train->ggRadioChannelNext.UpdateValue(1.0); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggRadioChannelNext.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_radiochanneldecrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - command_data newCommand = Command; - newCommand.param1 = Train->RadioChannel() - 1; - OnCommand_radiochannelset(Train, newCommand); - - Train->ggRadioChannelPrevious.UpdateValue(1.0); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggRadioChannelPrevious.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_radiochannelset(TTrain *Train, command_data const &Command) -{ - if (Command.action != GLFW_RELEASE) - { - // on press or hold - Train->RadioChannel() = std::clamp((int)Command.param1, 1, 10); - Train->ggRadioChannelSelector.UpdateValue(Train->RadioChannel() - 1); - } -} - -void TTrain::OnCommand_radiostopsend(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - if (true == Train->mvOccupied->Radio && (Train->mvOccupied->Power24vIsAvailable || Train->mvOccupied->Power110vIsAvailable)) - { - simulation::Region->RadioStop(Train->Dynamic()->GetPosition()); - } - // visual feedback - Train->ggRadioStop.UpdateValue(1.0); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggRadioStop.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_radiostopenable(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS && Train->ggRadioStop.GetValue() == 0) - { - if (true == Train->mvOccupied->Radio && (Train->mvOccupied->Power24vIsAvailable || Train->mvOccupied->Power110vIsAvailable)) - { - simulation::Region->RadioStop(Train->Dynamic()->GetPosition()); - } - // visual feedback - Train->ggRadioStop.UpdateValue(1.0); - } -} - -void TTrain::OnCommand_radiostopdisable(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS && Train->ggRadioStop.GetValue() > 0) - { - // visual feedback - Train->ggRadioStop.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_radiostoptest(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - if (Train->RadioChannel() == 10 && true == Train->mvOccupied->Radio && (Train->mvOccupied->Power24vIsAvailable || Train->mvOccupied->Power110vIsAvailable)) - { - Train->Dynamic()->RadioStop(); - } - // visual feedback - Train->ggRadioTest.UpdateValue(1.0); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggRadioTest.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_radiocall1send(TTrain *Train, command_data const &Command) -{ - if (Command.action == GLFW_PRESS) - { - if (Train->RadioChannel() != 10 && true == Train->mvOccupied->Radio && (Train->mvOccupied->Power24vIsAvailable || Train->mvOccupied->Power110vIsAvailable)) - { - simulation::Events.queue_receivers(radio_message::call1, Train->Dynamic()->GetPosition()); - } - // visual feedback - Train->ggRadioCall1.UpdateValue(1.0); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggRadioCall1.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_radiocall3send(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - if (Train->RadioChannel() != 10 && true == Train->mvOccupied->Radio && (Train->mvOccupied->Power24vIsAvailable || Train->mvOccupied->Power110vIsAvailable)) - { - simulation::Events.queue_receivers(radio_message::call3, Train->Dynamic()->GetPosition()); - } - // visual feedback - Train->ggRadioCall3.UpdateValue(1.0); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggRadioCall3.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_radiovolumeincrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - command_data newCommand = Command; - newCommand.param1 = Train->m_radiovolume + 0.125; - OnCommand_radiovolumeset(Train, newCommand); - Train->ggRadioVolumeNext.UpdateValue(1.0); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggRadioVolumeNext.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_radiovolumedecrease(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - command_data newCommand = Command; - newCommand.param1 = Train->m_radiovolume - 0.125; - OnCommand_radiovolumeset(Train, newCommand); - Train->ggRadioVolumePrevious.UpdateValue(1.0); - } - else if (Command.action == GLFW_RELEASE) - { - // visual feedback - Train->ggRadioVolumePrevious.UpdateValue(0.0); - } -} - -void TTrain::OnCommand_radiovolumeset(TTrain *Train, command_data const &Command) -{ - if (Command.action != GLFW_RELEASE) - { - // on press or hold - Train->m_radiovolume = std::clamp(Command.param1, 0.0, 1.0); - Train->ggRadioVolumeSelector.UpdateValue(Train->m_radiovolume); - audio::event_volume_change = true; - } -} - -void TTrain::OnCommand_cabchangeforward(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - auto const *owner{(Train->DynamicObject->ctOwner != nullptr ? Train->DynamicObject->ctOwner : Train->DynamicObject->Mechanik)}; - auto const movedirection{1}; - if (false == Train->CabChange(movedirection)) - { - auto const exitdirection{(movedirection > 0 ? end::front : end::rear)}; - if (TestFlag(Train->mvOccupied->Couplers[exitdirection].CouplingFlag, coupling::gangway)) - { - // przejscie do nastepnego pojazdu - auto *targetvehicle = exitdirection == end::front ? Train->DynamicObject->PrevConnected() : Train->DynamicObject->NextConnected(); - targetvehicle->MoverParameters->CabOccupied = Train->mvOccupied->Neighbours[exitdirection].vehicle_end ? -1 : 1; - Train->MoveToVehicle(targetvehicle); - } - } - // HACK: match consist door permit state with the preset in the active cab - if (Train->ggDoorPermitPresetButton.SubModel != nullptr) - { - Train->mvOccupied->ChangeDoorPermitPreset(0); - } - // HACK: update lights state - if (Train->mvOccupied->LightsPosNo > 0) - { - Train->DynamicObject->SetLights(); - } - } -} - -void TTrain::OnCommand_cabchangebackward(TTrain *Train, command_data const &Command) -{ - - if (Command.action == GLFW_PRESS) - { - auto const *owner{(Train->DynamicObject->ctOwner != nullptr ? Train->DynamicObject->ctOwner : Train->DynamicObject->Mechanik)}; - auto const movedirection{-1}; - if (false == Train->CabChange(movedirection)) - { - // current vehicle doesn't extend any farther in this direction, check if we there's one connected we can move to - auto const exitdirection{(movedirection > 0 ? end::front : end::rear)}; - if (TestFlag(Train->mvOccupied->Couplers[exitdirection].CouplingFlag, coupling::gangway)) - { - // przejscie do nastepnego pojazdu - auto *targetvehicle = exitdirection == end::front ? Train->DynamicObject->PrevConnected() : Train->DynamicObject->NextConnected(); - targetvehicle->MoverParameters->CabOccupied = Train->mvOccupied->Neighbours[exitdirection].vehicle_end ? -1 : 1; - Train->MoveToVehicle(targetvehicle); - } - } - // HACK: match consist door permit state with the preset in the active cab - if (Train->ggDoorPermitPresetButton.SubModel != nullptr) - { - Train->mvOccupied->ChangeDoorPermitPreset(0); - } - // HACK: update lights state - if (Train->mvOccupied->LightsPosNo > 0) - { - Train->DynamicObject->SetLights(); - } - } -} - -void TTrain::OnCommand_vehiclemoveforwards(TTrain *Train, const command_data &Command) -{ - if (Command.action == GLFW_RELEASE || !DebugModeFlag) - return; - - Train->DynamicObject->move_set(100.0); -} - -void TTrain::OnCommand_vehiclemovebackwards(TTrain *Train, const command_data &Command) -{ - if (Command.action == GLFW_RELEASE || !DebugModeFlag) - return; - - Train->DynamicObject->move_set(-100.0); -} - -void TTrain::OnCommand_vehicleboost(TTrain *Train, const command_data &Command) -{ - if (Command.action == GLFW_RELEASE || !DebugModeFlag) - return; - - double boost = Command.param1 != 0.0 ? Command.param1 : 2.78; - - if (Train->DynamicObject == nullptr) - { - return; - } - - auto *vehicle{Train->DynamicObject}; - while (vehicle) - { - vehicle->MoverParameters->V += vehicle->DirectionGet() * boost; - vehicle = vehicle->Next(); // pozostałe też - } - vehicle = Train->DynamicObject->Prev(); - while (vehicle) - { - vehicle->MoverParameters->V += vehicle->DirectionGet() * boost; - vehicle = vehicle->Prev(); // w drugą stronę też - } -} // cab movement update, fixed step part void TTrain::UpdateCab() @@ -12397,9 +5092,6 @@ uint16_t TTrain::id() return vid; } -#include -#include - void train_table::updateAsync(double dt) { const int threads = std::max(1, Global.trainThreads); diff --git a/vehicle/Train_Commands_Auxiliary.cpp b/vehicle/Train_Commands_Auxiliary.cpp new file mode 100644 index 00000000..551a8977 --- /dev/null +++ b/vehicle/Train_Commands_Auxiliary.cpp @@ -0,0 +1,586 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "vehicle/Train.h" + +#include "world/Event.h" +#include "simulation/simulationtime.h" +#include "utilities/Logs.h" +#include "model/Model3d.h" +#include "vehicle/Driver.h" +#include + +void TTrain::OnCommand_fuelpumptoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggFuelPumpButton.type() == TGaugeType::push) + { + // impulse switch + // currently there's no off button so we always try to turn it on + OnCommand_fuelpumpenable(Train, Command); + } + else + { + // two-state switch + if (Command.action == GLFW_RELEASE) + { + return; + } + + if (false == Train->mvControlled->FuelPump.is_enabled) + { + // turn on + OnCommand_fuelpumpenable(Train, Command); + } + else + { + // turn off + OnCommand_fuelpumpdisable(Train, Command); + } + } +} + +void TTrain::OnCommand_fuelpumpenable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggFuelPumpButton.type() == TGaugeType::push) + { + // impulse switch + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggFuelPumpButton.UpdateValue(1.0, Train->dsbSwitch); + Train->mvControlled->FuelPumpSwitch(true); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggFuelPumpButton.UpdateValue(0.0, Train->dsbSwitch); + Train->mvControlled->FuelPumpSwitch(false); + } + } + else + { + // two-state switch, only cares about press events + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggFuelPumpButton.UpdateValue(1.0, Train->dsbSwitch); + Train->mvControlled->FuelPumpSwitch(true); + Train->mvControlled->FuelPumpSwitchOff(false); + } + } +} + +void TTrain::OnCommand_fuelpumpdisable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggFuelPumpButton.type() == TGaugeType::push) + { + // impulse switch + // currently there's no disable return type switch + return; + } + else + { + // two-state switch, only cares about press events + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggFuelPumpButton.UpdateValue(0.0, Train->dsbSwitch); + Train->mvControlled->FuelPumpSwitch(false); + Train->mvControlled->FuelPumpSwitchOff(true); + } + } +} + +void TTrain::OnCommand_oilpumptoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggOilPumpButton.type() == TGaugeType::push) + { + // impulse switch + // currently there's no off button so we always try to turn it on + OnCommand_oilpumpenable(Train, Command); + } + else + { + // two-state switch + if (Command.action == GLFW_RELEASE) + { + return; + } + + if (false == Train->mvControlled->OilPump.is_enabled) + { + // turn on + OnCommand_oilpumpenable(Train, Command); + } + else + { + // turn off + OnCommand_oilpumpdisable(Train, Command); + } + } +} + +void TTrain::OnCommand_oilpumpenable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggOilPumpButton.type() == TGaugeType::push) + { + // impulse switch + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggOilPumpButton.UpdateValue(1.0, Train->dsbSwitch); + Train->mvControlled->OilPumpSwitch(true); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggOilPumpButton.UpdateValue(0.0, Train->dsbSwitch); + Train->mvControlled->OilPumpSwitch(false); + } + } + else + { + // two-state switch, only cares about press events + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggOilPumpButton.UpdateValue(1.0, Train->dsbSwitch); + Train->mvControlled->OilPumpSwitch(true); + Train->mvControlled->OilPumpSwitchOff(false); + } + } +} + +void TTrain::OnCommand_oilpumpdisable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggOilPumpButton.type() == TGaugeType::push) + { + // impulse switch + // currently there's no disable return type switch + return; + } + else + { + // two-state switch, only cares about press events + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggOilPumpButton.UpdateValue(0.0, Train->dsbSwitch); + Train->mvControlled->OilPumpSwitch(false); + Train->mvControlled->OilPumpSwitchOff(true); + } + } +} + +void TTrain::OnCommand_waterheaterbreakertoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->mvControlled->WaterHeater.breaker) + { + // turn on + OnCommand_waterheaterbreakerclose(Train, Command); + } + else + { + // turn off + OnCommand_waterheaterbreakeropen(Train, Command); + } + } +} + +void TTrain::OnCommand_waterheaterbreakerclose(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggWaterHeaterBreakerButton.UpdateValue(1.0, Train->dsbSwitch); + + if (true == Train->mvControlled->WaterHeater.breaker) + { + return; + } // already enabled + + Train->mvControlled->WaterHeaterBreakerSwitch(true); + } +} + +void TTrain::OnCommand_waterheaterbreakeropen(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggWaterHeaterBreakerButton.UpdateValue(0.0, Train->dsbSwitch); + + if (false == Train->mvControlled->WaterHeater.breaker) + { + return; + } // already enabled + + Train->mvControlled->WaterHeaterBreakerSwitch(false); + } +} + +void TTrain::OnCommand_waterheatertoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->mvControlled->WaterHeater.is_enabled) + { + // turn on + OnCommand_waterheaterenable(Train, Command); + } + else + { + // turn off + OnCommand_waterheaterdisable(Train, Command); + } + } +} + +void TTrain::OnCommand_waterheaterenable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggWaterHeaterButton.UpdateValue(1.0, Train->dsbSwitch); + + if (true == Train->mvControlled->WaterHeater.is_enabled) + { + return; + } // already enabled + + Train->mvControlled->WaterHeaterSwitch(true); + } +} + +void TTrain::OnCommand_waterheaterdisable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggWaterHeaterButton.UpdateValue(0.0, Train->dsbSwitch); + + if (false == Train->mvControlled->WaterHeater.is_enabled) + { + return; + } // already disabled + + Train->mvControlled->WaterHeaterSwitch(false); + } +} + +void TTrain::OnCommand_waterpumpbreakertoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->mvControlled->WaterPump.breaker) + { + // turn on + OnCommand_waterpumpbreakerclose(Train, Command); + } + else + { + // turn off + OnCommand_waterpumpbreakeropen(Train, Command); + } + } +} + +void TTrain::OnCommand_waterpumpbreakerclose(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggWaterPumpBreakerButton.UpdateValue(1.0, Train->dsbSwitch); + + if (true == Train->mvControlled->WaterPump.breaker) + { + return; + } // already enabled + + Train->mvControlled->WaterPumpBreakerSwitch(true); + } +} + +void TTrain::OnCommand_waterpumpbreakeropen(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggWaterPumpBreakerButton.UpdateValue(0.0, Train->dsbSwitch); + + if (false == Train->mvControlled->WaterPump.breaker) + { + return; + } // already enabled + + Train->mvControlled->WaterPumpBreakerSwitch(false); + } +} + +void TTrain::OnCommand_waterpumptoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggWaterPumpButton.type() == TGaugeType::push) + { + // impulse switch + // currently there's no off button so we always try to turn it on + OnCommand_waterpumpenable(Train, Command); + } + else + { + // two-state switch + if (Command.action == GLFW_RELEASE) + { + return; + } + + if (false == Train->mvControlled->WaterPump.is_enabled) + { + // turn on + OnCommand_waterpumpenable(Train, Command); + } + else + { + // turn off + OnCommand_waterpumpdisable(Train, Command); + } + } +} + +void TTrain::OnCommand_waterpumpenable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggWaterPumpButton.type() == TGaugeType::push) + { + // impulse switch + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggWaterPumpButton.UpdateValue(1.0, Train->dsbSwitch); + Train->mvControlled->WaterPumpSwitch(true); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggWaterPumpButton.UpdateValue(0.0, Train->dsbSwitch); + Train->mvControlled->WaterPumpSwitch(false); + } + } + else + { + // two-state switch, only cares about press events + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggWaterPumpButton.UpdateValue(1.0, Train->dsbSwitch); + Train->mvControlled->WaterPumpSwitch(true); + Train->mvControlled->WaterPumpSwitchOff(false); + } + } +} + +void TTrain::OnCommand_waterpumpdisable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggWaterPumpButton.type() == TGaugeType::push) + { + // impulse switch + // currently there's no disable return type switch + return; + } + else + { + // two-state switch, only cares about press events + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggWaterPumpButton.UpdateValue(0.0, Train->dsbSwitch); + Train->mvControlled->WaterPumpSwitch(false); + Train->mvControlled->WaterPumpSwitchOff(true); + } + } +} + +void TTrain::OnCommand_watercircuitslinktoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->mvControlled->WaterCircuitsLink) + { + // turn on + OnCommand_watercircuitslinkenable(Train, Command); + } + else + { + // turn off + OnCommand_watercircuitslinkdisable(Train, Command); + } + } +} + +void TTrain::OnCommand_watercircuitslinkenable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggWaterCircuitsLinkButton.UpdateValue(1.0, Train->dsbSwitch); + + if (true == Train->mvControlled->WaterCircuitsLink) + { + return; + } // already enabled + + Train->mvControlled->WaterCircuitsLinkSwitch(true); + } +} + +void TTrain::OnCommand_watercircuitslinkdisable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggWaterCircuitsLinkButton.UpdateValue(0.0, Train->dsbSwitch); + + if (false == Train->mvControlled->WaterCircuitsLink) + { + return; + } // already disabled + + Train->mvControlled->WaterCircuitsLinkSwitch(false); + } +} + +void TTrain::OnCommand_heatingtoggle(TTrain *Train, command_data const &Command) +{ + + if (Train->ggTrainHeatingButton.SubModel == nullptr) + { + if (Command.action == GLFW_PRESS) + { + WriteLog("Train Heating switch is missing, or wasn't defined"); + } + return; + } + + if (Command.action == GLFW_PRESS) + { + // ignore repeats so the switch doesn't flip back and forth if key is held down + if (false == Train->mvControlled->HeatingAllow) + { + // turn on + OnCommand_heatingenable(Train, Command); + } + else + { + // turn off + OnCommand_heatingdisable(Train, Command); + } + } + else if (Command.action == GLFW_RELEASE && Train->ggTrainHeatingButton.type() == TGaugeType::push) + { + + // impulse switch + // visual feedback + Train->ggTrainHeatingButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_heatingenable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + Train->mvOccupied->HeatingSwitch(true); + // visual feedback + Train->ggTrainHeatingButton.UpdateValue(1.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_heatingdisable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + Train->mvOccupied->HeatingSwitch(false); + // visual feedback + Train->ggTrainHeatingButton.UpdateValue(Train->ggTrainHeatingButton.type() == TGaugeType::push ? 1.0 : 0.0, Train->dsbSwitch); + } +} diff --git a/vehicle/Train_Commands_Brakes.cpp b/vehicle/Train_Commands_Brakes.cpp new file mode 100644 index 00000000..c295d88a --- /dev/null +++ b/vehicle/Train_Commands_Brakes.cpp @@ -0,0 +1,1108 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "vehicle/Train.h" + +#include "utilities/Globals.h" +#include "world/Event.h" +#include "simulation/simulationtime.h" +#include "utilities/Logs.h" +#include "model/Model3d.h" +#include "vehicle/Driver.h" +#include "vehicle/DynObj.h" +#include "rendering/renderer.h" +#include +#include +#include + +void TTrain::OnCommand_DynamicBrakeControllerIncrease(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_RELEASE) + { + return; + } + if (false == Train->mvControlled->SplitEDPneumaticBrake) + { + return; + } + + // step exactly one stop (1 / DBPN) per command, matching the discrete behaviour of jointctrl + Train->mvControlled->IncDynamicBrakeLevel(1.0f); +} + +void TTrain::OnCommand_DynamicBrakeControllerIncreaseFast(TTrain *Train, command_data const &Command) +{ + if (Command.action != GLFW_PRESS) + { + return; + } + if (false == Train->mvControlled->SplitEDPneumaticBrake) + { + return; + } + + Train->mvControlled->IncDynamicBrakeLevel(static_cast(Train->mvControlled->DynamicBrakeCtrlPosNo)); +} + +void TTrain::OnCommand_DynamicBrakeControllerDecrease(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_RELEASE) + { + return; + } + if (false == Train->mvControlled->SplitEDPneumaticBrake) + { + return; + } + + // step exactly one stop (1 / DBPN) per command, matching the discrete behaviour of jointctrl + Train->mvControlled->DecDynamicBrakeLevel(1.0f); +} + +void TTrain::OnCommand_DynamicBrakeControllerDecreaseFast(TTrain *Train, command_data const &Command) +{ + if (Command.action != GLFW_PRESS) + { + return; + } + if (false == Train->mvControlled->SplitEDPneumaticBrake) + { + return; + } + + Train->mvControlled->DecDynamicBrakeLevel(static_cast(Train->mvControlled->DynamicBrakeCtrlPosNo)); +} + +void TTrain::OnCommand_DynamicBrakeControllerSet(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_RELEASE) + { + return; + } + if (false == Train->mvControlled->SplitEDPneumaticBrake) + { + return; + } + + // when input source uses raw 0..1 value, snap to nearest DBPN step + auto const target{std::clamp(Command.param1, 0.0, 1.0)}; + auto const stepCount{std::max(1, Train->mvControlled->DynamicBrakeCtrlPosNo)}; + auto const snapped{std::round(target * stepCount) / stepCount}; + Train->mvControlled->DynamicBrakeLevelSet(snapped); +} + +void TTrain::OnCommand_independentbrakeincrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + + // when SplitEDPneumaticBrake is active the local brake key always operates + // the pneumatic local brake directly, never piggy-backing on the joint controller + auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; + auto const useStepped{Train->ggJointCtrl.SubModel != nullptr && !splitMode}; + if (Train->mvOccupied->LocalBrake != TLocalBrake::ManualBrake) + { + if (false == splitMode && Train->ggJointCtrl.SubModel != nullptr && Train->mvOccupied->MainCtrlPos > 0) + { + OnCommand_mastercontrollerdecrease(Train, Command); + } + else + { + Train->mvOccupied->IncLocalBrakeLevel(useStepped ? 1 : Global.brake_speed * Command.time_delta * LocalBrakePosNo); + if (useStepped) + { + Train->m_mastercontrollerinuse = true; + } + } + } + } +} + +void TTrain::OnCommand_independentbrakeincreasefast(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + + auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; + auto const useJointAnim{Train->ggJointCtrl.SubModel != nullptr && !splitMode}; + if (Train->mvOccupied->LocalBrake != TLocalBrake::ManualBrake) + { + if (false == splitMode && Train->ggJointCtrl.SubModel != nullptr && Train->mvOccupied->MainCtrlPos > 0) + { + OnCommand_mastercontrollerdecreasefast(Train, Command); + } + else + { + Train->mvOccupied->IncLocalBrakeLevel(LocalBrakePosNo); + if (useJointAnim) + { + Train->m_mastercontrollerinuse = true; + } + } + } + } +} + +void TTrain::OnCommand_independentbrakedecrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + + auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; + auto const useStepped{Train->ggJointCtrl.SubModel != nullptr && !splitMode}; + if (Train->mvOccupied->LocalBrake != TLocalBrake::ManualBrake + // Ra 1014-06: AI potrafi zahamować pomocniczym mimo jego braku - odhamować jakoś trzeba + // TODO: sort AI out so it doesn't do things it doesn't have equipment for + || Train->mvOccupied->LocalBrakePosA > 0) + { + if (false == splitMode && Train->ggJointCtrl.SubModel != nullptr && Train->mvOccupied->LocalBrakePosA == 0.0) + { + OnCommand_mastercontrollerincrease(Train, Command); + } + else + { + Train->mvOccupied->DecLocalBrakeLevel(useStepped ? 1 : Global.brake_speed * Command.time_delta * LocalBrakePosNo); + if (useStepped) + { + Train->m_mastercontrollerinuse = true; + } + } + } + } +} + +void TTrain::OnCommand_independentbrakedecreasefast(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + + auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; + auto const useJointAnim{Train->ggJointCtrl.SubModel != nullptr && !splitMode}; + if (Train->mvOccupied->LocalBrake != TLocalBrake::ManualBrake + // Ra 1014-06: AI potrafi zahamować pomocniczym mimo jego braku - odhamować jakoś trzeba + // TODO: sort AI out so it doesn't do things it doesn't have equipment for + || Train->mvOccupied->LocalBrakePosA > 0) + { + if (false == splitMode && Train->ggJointCtrl.SubModel != nullptr && Train->mvOccupied->LocalBrakePosA == 0.0) + { + OnCommand_mastercontrollerincreasefast(Train, Command); + } + else + { + Train->mvOccupied->DecLocalBrakeLevel(LocalBrakePosNo); + if (useJointAnim) + { + Train->m_mastercontrollerinuse = true; + } + } + } + } +} + +void TTrain::OnCommand_independentbrakeset(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + + Train->mvOccupied->LocalBrakePosA = std::clamp(Command.param1, 0.0, 1.0); + } + /* + Train->mvControlled->LocalBrakePos = ( + std::round( + interpolate( + 0.0, + LocalBrakePosNo, + clamp( + Command.param1, + 0.0, 1.0 ) ) ) ); + */ +} + +void TTrain::OnCommand_independentbrakebailoff(TTrain *Train, command_data const &Command) +{ + + if (false == Command.freefly) + { + // TODO: check if this set of conditions can be simplified. + // it'd be more flexible to have an attribute indicating whether bail off position is supported + if (Train->mvControlled->TrainType != dt_EZT && + (Train->mvControlled->EngineType == TEngineType::ElectricSeriesMotor || Train->mvControlled->EngineType == TEngineType::DieselElectric || + Train->mvControlled->EngineType == TEngineType::ElectricInductionMotor) && + Train->mvOccupied->BrakeCtrlPosNo > 0) + { + + if (Command.action == GLFW_PRESS) + { + // press or hold + // visual feedback + Train->ggReleaserButton.UpdateValue(1.0, Train->dsbSwitch); + + Train->mvOccupied->BrakeReleaser(1); + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + Train->ggReleaserButton.UpdateValue(0.0, Train->dsbSwitch); + + Train->mvOccupied->BrakeReleaser(0); + } + } + } + else + { + // car brake handling, while in walk mode + auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; + if (vehicle != nullptr) + { + if (Command.action == GLFW_PRESS) + { + // press or hold + vehicle->MoverParameters->BrakeReleaser(1); + } + else if (Command.action == GLFW_RELEASE) + { + // release + vehicle->MoverParameters->BrakeReleaser(0); + } + } + } +} + +void TTrain::OnCommand_universalbrakebutton1(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // press or hold + // visual feedback + Train->ggUniveralBrakeButton1.UpdateValue(1.0, Train->dsbSwitch); + + Train->mvOccupied->UniversalBrakeButton(0, 1); + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + Train->ggUniveralBrakeButton1.UpdateValue(0.0, Train->dsbSwitch); + + Train->mvOccupied->UniversalBrakeButton(0, 0); + } +} + +void TTrain::OnCommand_universalbrakebutton2(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // press or hold + // visual feedback + Train->ggUniveralBrakeButton2.UpdateValue(1.0, Train->dsbSwitch); + + Train->mvOccupied->UniversalBrakeButton(1, 1); + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + Train->ggUniveralBrakeButton2.UpdateValue(0.0, Train->dsbSwitch); + + Train->mvOccupied->UniversalBrakeButton(1, 0); + } +} + +void TTrain::OnCommand_universalbrakebutton3(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // press or hold + // visual feedback + Train->ggUniveralBrakeButton3.UpdateValue(1.0, Train->dsbSwitch); + + Train->mvOccupied->UniversalBrakeButton(2, 1); + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + Train->ggUniveralBrakeButton3.UpdateValue(0.0, Train->dsbSwitch); + + Train->mvOccupied->UniversalBrakeButton(2, 0); + } +} + +void TTrain::OnCommand_trainbrakeincrease(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_REPEAT && Train->mvOccupied->BrakeHandle == TBrakeHandle::FV4a) + Train->mvOccupied->BrakeLevelAdd(Global.brake_speed * Command.time_delta * Train->mvOccupied->BrakeCtrlPosNo); + else if (Command.action == GLFW_PRESS && Train->mvOccupied->BrakeHandle != TBrakeHandle::FV4a) + Train->set_train_brake(Train->mvOccupied->fBrakeCtrlPos + Global.fBrakeStep); +} + +void TTrain::OnCommand_trainbrakedecrease(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_REPEAT && Train->mvOccupied->BrakeHandle == TBrakeHandle::FV4a) + Train->mvOccupied->BrakeLevelAdd(-Global.brake_speed * Command.time_delta * Train->mvOccupied->BrakeCtrlPosNo); + else if (Command.action == GLFW_PRESS && Train->mvOccupied->BrakeHandle != TBrakeHandle::FV4a) + Train->set_train_brake(Train->mvOccupied->fBrakeCtrlPos - Global.fBrakeStep); + else if (Command.action == GLFW_RELEASE) + { + // release + Train->zero_charging_train_brake(); + } +} + +void TTrain::OnCommand_trainbrakeset(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + // press or hold + Train->mvOccupied->BrakeLevelSet(std::lerp(Train->mvOccupied->Handle->GetPos(bh_MIN), Train->mvOccupied->Handle->GetPos(bh_MAX), std::clamp(Command.param1, 0.0, 1.0))); + } + else + { + // release + Train->zero_charging_train_brake(); + } +} + +void TTrain::OnCommand_trainbrakecharging(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + // press or hold + Train->set_train_brake(-1); + } + else + { + // release + Train->zero_charging_train_brake(); + } +} + +void TTrain::OnCommand_trainbrakerelease(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + Train->set_train_brake(0); + } +} + +void TTrain::OnCommand_trainbrakefirstservice(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + Train->set_train_brake(1); + } +} + +void TTrain::OnCommand_trainbrakeservice(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + Train->set_train_brake(Train->mvOccupied->BrakeCtrlPosNo / 2 + (Train->mvOccupied->BrakeHandle == TBrakeHandle::FV4a ? 1 : 0)); + } +} + +void TTrain::OnCommand_trainbrakefullservice(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + Train->set_train_brake(Train->mvOccupied->BrakeCtrlPosNo - 1); + } +} + +void TTrain::OnCommand_trainbrakehandleoff(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + Train->set_train_brake(Train->mvOccupied->Handle->GetPos(bh_NP)); + } +} + +void TTrain::OnCommand_trainbrakeemergency(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + Train->set_train_brake(Train->mvOccupied->Handle->GetPos(bh_EB)); + /* + if( Train->mvOccupied->BrakeCtrlPosNo <= 0.1 ) { + hamulec bezpieczeństwa dla wagonów + Train->mvOccupied->RadioStopFlag = true; + } + */ + } +} + +void TTrain::OnCommand_trainbrakebasepressureincrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + + switch (Train->mvOccupied->BrakeHandle) + { + case TBrakeHandle::FV4a: + { + Train->mvOccupied->BrakeCtrlPos2 = std::clamp(Train->mvOccupied->BrakeCtrlPos2 - 0.01, -1.5, 2.0); + break; + } + default: + { + Train->mvOccupied->BrakeLevelAdd(0.01); + break; + } + } + } +} + +void TTrain::OnCommand_trainbrakebasepressuredecrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + + switch (Train->mvOccupied->BrakeHandle) + { + case TBrakeHandle::FV4a: + { + Train->mvOccupied->BrakeCtrlPos2 = std::clamp(Train->mvOccupied->BrakeCtrlPos2 + 0.01, -1.5, 2.0); + break; + } + default: + { + Train->mvOccupied->BrakeLevelAdd(-0.01); + break; + } + } + } +} + +void TTrain::OnCommand_trainbrakebasepressurereset(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + Train->mvOccupied->BrakeCtrlPos2 = 0; + } +} + +void TTrain::OnCommand_trainbrakeoperationtoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; + if (vehicle == nullptr) + { + return; + } + + vehicle->MoverParameters->Hamulec->SetBrakeStatus(vehicle->MoverParameters->Hamulec->GetBrakeStatus() ^ b_dmg); + } +} + +void TTrain::OnCommand_manualbrakeincrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + + auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; + if (vehicle == nullptr) + { + return; + } + + if (vehicle->MoverParameters->LocalBrake == TLocalBrake::ManualBrake || vehicle->MoverParameters->MBrake == true) + { + + vehicle->MoverParameters->IncManualBrakeLevel(1); + } + } +} + +void TTrain::OnCommand_manualbrakedecrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + + auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; + if (vehicle == nullptr) + { + return; + } + + if (vehicle->MoverParameters->LocalBrake == TLocalBrake::ManualBrake || vehicle->MoverParameters->MBrake == true) + { + + vehicle->MoverParameters->DecManualBrakeLevel(1); + } + } +} + +void TTrain::OnCommand_alarmchaintoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + if (false == Train->mvOccupied->AlarmChainFlag) + { + OnCommand_alarmchainenable(Train, Command); + } + else + { + OnCommand_alarmchaindisable(Train, Command); + } + } +} + +void TTrain::OnCommand_alarmchainenable(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + + // pull + Train->mvOccupied->AlarmChainSwitch(true); + // visual feedback + Train->ggAlarmChain.UpdateValue(1.0); + } +} + +void TTrain::OnCommand_alarmchaindisable(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + + // release + Train->mvOccupied->AlarmChainSwitch(false); + // visual feedback + Train->ggAlarmChain.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_wheelspinbrakeactivate(TTrain *Train, command_data const &Command) +{ + + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + if (Train->ggAntiSlipButton.SubModel == nullptr) + { + if (Command.action == GLFW_PRESS) + { + WriteLog("Wheelspin Brake button is missing, or wasn't defined"); + } + return; + } + + if (Train->mvOccupied->BrakeSystem != TBrakeSystem::ElectroPneumatic) + { + // standard behaviour + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggAntiSlipButton.UpdateValue(1.0, Train->dsbSwitch); + + // NOTE: system activation is (repeatedly) done in the train update routine + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggAntiSlipButton.UpdateValue(0.0); + } + } + else + { + // electro-pneumatic, custom case + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggAntiSlipButton.UpdateValue(1.0, Train->dsbPneumaticSwitch); + + if (Train->mvOccupied->BrakeHandle == TBrakeHandle::St113 && Train->mvControlled->EpFuse == true) + { + Train->mvOccupied->SwitchEPBrake(1); + } + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggAntiSlipButton.UpdateValue(0.0); + + Train->mvOccupied->SwitchEPBrake(0); + } + } +} + +void TTrain::OnCommand_sandboxactivate(TTrain *Train, command_data const &Command) +{ + + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + if (Train->ggSandButton.SubModel == nullptr) + { + if (Command.action == GLFW_PRESS) + { + WriteLog("Sandbox activation button is missing, or wasn't defined"); + } + return; + } + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggSandButton.UpdateValue(1.0, Train->dsbSwitch); + + Train->mvControlled->SandboxManual(true); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggSandButton.UpdateValue(0.0); + + Train->mvControlled->SandboxManual(false); + } +} + +void TTrain::OnCommand_autosandboxtoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->mvOccupied->SandDoseAutoAllow) + { + // turn on + OnCommand_autosandboxactivate(Train, Command); + } + else + { + // turn off + OnCommand_autosandboxdeactivate(Train, Command); + } + } +}; + +void TTrain::OnCommand_autosandboxactivate(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SandboxAutoAllow(true); + Train->ggAutoSandButton.UpdateValue(1.0, Train->dsbSwitch); + } +}; + +void TTrain::OnCommand_autosandboxdeactivate(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SandboxAutoAllow(false); + Train->ggAutoSandButton.UpdateValue(0.0, Train->dsbSwitch); + } +}; + +void TTrain::OnCommand_epbrakecontrolenable(TTrain *Train, command_data const &Command) +{ + auto const istoggle{(static_cast(Train->ggEPFuseButton.type()) & static_cast(TGaugeType::toggle)) != 0}; + if (Command.action == GLFW_PRESS && istoggle && Train->mvOccupied->EpFuseSwitch(true)) + { + // command only works for bistable switch + // audio feedback + if (Train->dsbPneumaticSwitch) + { + Train->dsbPneumaticSwitch->play(); + } + Train->ggEPFuseButton.UpdateValue(1.0f, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_epbrakecontroldisable(TTrain *Train, command_data const &Command) +{ + auto const istoggle{(static_cast(Train->ggEPFuseButton.type()) & static_cast(TGaugeType::toggle)) != 0}; + if (Command.action == GLFW_PRESS && istoggle && Train->mvOccupied->EpFuseSwitch(false)) + { + // command only works for bistable switch + Train->ggEPFuseButton.UpdateValue(0.0f, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_epbrakecontroltoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + auto const ispush{(static_cast(Train->ggEPFuseButton.type()) & static_cast(TGaugeType::push)) != 0}; + auto const istoggle{(static_cast(Train->ggEPFuseButton.type()) & static_cast(TGaugeType::toggle)) != 0}; + + if (Command.action == GLFW_PRESS) + { + if (istoggle) + { + // switch state + if (false == Train->mvOccupied->EpFuse) + { + // turn on + if (Train->mvOccupied->EpFuseSwitch(true) && Train->dsbPneumaticSwitch) + { + // audio feedback + Train->dsbPneumaticSwitch->play(); + } + } + else + { + // turn off + Train->mvOccupied->EpFuseSwitch(false); + } + } + else if (ispush) + { + // potentially turn on + if (Train->mvOccupied->EpFuseSwitch(true) && Train->dsbPneumaticSwitch) + { + // audio feedback + Train->dsbPneumaticSwitch->play(); + } + } + // visual feedback + Train->ggEPFuseButton.UpdateValue(ispush ? 1.0f : // push or pushtoggle + Train->mvOccupied->EpFuse ? 1.0f : + 0.0f, // toggle + Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE && ispush) + { + // return the switch to neutral position + Train->ggEPFuseButton.UpdateValue(0.0f, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_trainbrakeoperationmodeincrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS && (Train->mvOccupied->BrakeOpModeFlag << 1 & Train->mvOccupied->BrakeOpModes) != 0) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + // next mode + Train->mvOccupied->BrakeOpModeFlag <<= 1; + // visual feedback + Train->ggBrakeOperationModeCtrl.UpdateValue(Train->mvOccupied->BrakeOpModeFlag > 0 ? std::log2(Train->mvOccupied->BrakeOpModeFlag) : 0); // audio fallback + } +} + +void TTrain::OnCommand_trainbrakeoperationmodedecrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS && (Train->mvOccupied->BrakeOpModeFlag >> 1 & Train->mvOccupied->BrakeOpModes) != 0) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + // previous mode + Train->mvOccupied->BrakeOpModeFlag >>= 1; + // visual feedback + Train->ggBrakeOperationModeCtrl.UpdateValue(Train->mvOccupied->BrakeOpModeFlag > 0 ? std::log2(Train->mvOccupied->BrakeOpModeFlag) : 0); + } +} + +void TTrain::OnCommand_brakeactingspeedincrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; + if (vehicle == nullptr) + { + return; + } + + if ((vehicle->MoverParameters->BrakeDelayFlag & bdelay_M) != 0) + { + // can't speed it up any more than this + return; + } + auto const fasterbrakesetting = vehicle->MoverParameters->BrakeDelayFlag < bdelay_R ? vehicle->MoverParameters->BrakeDelayFlag << 1 : vehicle->MoverParameters->BrakeDelayFlag | bdelay_M; + + Train->set_train_brake_speed(vehicle, fasterbrakesetting); + } +} + +void TTrain::OnCommand_brakeactingspeeddecrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; + if (vehicle == nullptr) + { + return; + } + + if (vehicle->MoverParameters->BrakeDelayFlag == bdelay_G) + { + // can't slow it down any more than this + return; + } + auto const slowerbrakesetting = vehicle->MoverParameters->BrakeDelayFlag < bdelay_M ? vehicle->MoverParameters->BrakeDelayFlag >> 1 : vehicle->MoverParameters->BrakeDelayFlag ^ bdelay_M; + + Train->set_train_brake_speed(vehicle, slowerbrakesetting); + } +} + +void TTrain::OnCommand_brakeactingspeedsetcargo(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; + if (vehicle == nullptr) + { + return; + } + + Train->set_train_brake_speed(vehicle, bdelay_G); + } +} + +void TTrain::OnCommand_brakeactingspeedsetpassenger(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; + if (vehicle == nullptr) + { + return; + } + + Train->set_train_brake_speed(vehicle, bdelay_P); + } +} + +void TTrain::OnCommand_brakeactingspeedsetrapid(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; + if (vehicle == nullptr) + { + return; + } + + Train->set_train_brake_speed(vehicle, bdelay_R); + } +} + +void TTrain::OnCommand_brakeloadcompensationincrease(TTrain *Train, command_data const &Command) +{ + + if (true == Command.freefly && Command.action == GLFW_PRESS) + { + auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; + if (vehicle != nullptr) + { + vehicle->MoverParameters->IncBrakeMult(); + } + } +} + +void TTrain::OnCommand_brakeloadcompensationdecrease(TTrain *Train, command_data const &Command) +{ + + if (true == Command.freefly && Command.action == GLFW_PRESS) + { + auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; + if (vehicle != nullptr) + { + vehicle->MoverParameters->DecBrakeMult(); + } + } +} + +void TTrain::OnCommand_mubrakingindicatortoggle(TTrain *Train, command_data const &Command) +{ + + if (Train->ggSignallingButton.SubModel == nullptr) + { + if (Command.action == GLFW_PRESS) + { + WriteLog("Braking Indicator switch is missing, or wasn't defined"); + } + return; + } + if (Train->mvControlled->TrainType != dt_EZT) + { + // + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->mvControlled->Signalling) + { + // turn on + Train->mvControlled->Signalling = true; + // visual feedback + Train->ggSignallingButton.UpdateValue(1.0, Train->dsbSwitch); + } + else + { + // turn off + Train->mvControlled->Signalling = false; + // visual feedback + Train->ggSignallingButton.UpdateValue(0.0, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_springbraketoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->mvOccupied->SpringBrake.Activate) + { + // turn on + OnCommand_springbrakeenable(Train, Command); + } + else + { + // turn off + OnCommand_springbrakedisable(Train, Command); + } + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + Train->ggSpringBrakeOffButton.UpdateValue(0.0, Train->dsbSwitch); + Train->ggSpringBrakeOnButton.UpdateValue(0.0, Train->dsbSwitch); + } +}; + +void TTrain::OnCommand_springbrakeenable(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SpringBrakeActivate(true); + // visual feedback + Train->ggSpringBrakeOnButton.UpdateValue(1.0, Train->dsbSwitch); + Train->ggSpringBrakeOffButton.UpdateValue(0.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + Train->ggSpringBrakeOnButton.UpdateValue(0.0, Train->dsbSwitch); + } +}; + +void TTrain::OnCommand_springbrakedisable(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SpringBrakeActivate(false); + // visual feedback + Train->ggSpringBrakeOffButton.UpdateValue(1.0, Train->dsbSwitch); + Train->ggSpringBrakeOnButton.UpdateValue(0.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + Train->ggSpringBrakeOffButton.UpdateValue(0.0, Train->dsbSwitch); + } +}; + +void TTrain::OnCommand_springbrakeshutofftoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->mvOccupied->SpringBrake.ShuttOff) + { + // turn on + OnCommand_springbrakeshutoffenable(Train, Command); + } + else + { + // turn off + OnCommand_springbrakeshutoffdisable(Train, Command); + } + } +}; + +void TTrain::OnCommand_springbrakeshutoffenable(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SpringBrakeShutOff(true); + } +}; + +void TTrain::OnCommand_springbrakeshutoffdisable(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SpringBrakeShutOff(false); + } +}; + +void TTrain::OnCommand_springbrakerelease(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + + auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; + if (vehicle == nullptr) + { + return; + } + Train->mvOccupied->SpringBrakeRelease(); + } +}; diff --git a/vehicle/Train_Commands_Controls.cpp b/vehicle/Train_Commands_Controls.cpp new file mode 100644 index 00000000..0424bad9 --- /dev/null +++ b/vehicle/Train_Commands_Controls.cpp @@ -0,0 +1,838 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "vehicle/Train.h" + +#include "world/Event.h" +#include "simulation/simulationtime.h" +#include "utilities/Logs.h" +#include "model/Model3d.h" +#include "vehicle/Driver.h" +#include "vehicle/DynObj.h" +#include +#include + +auto const EU07_CONTROLLER_BASERETURNDELAY{0.5f}; +auto const EU07_CONTROLLER_KEYBOARDETURNDELAY{1.5f}; + +void TTrain::OnCommand_aidriverenable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // on press + if (Train->DynamicObject->Mechanik == nullptr) + { + return; + } + + if (true == Train->DynamicObject->Mechanik->AIControllFlag) + { + // żeby nie trzeba było rozłączać dla zresetowania + Train->DynamicObject->Mechanik->TakeControl(false); + } + Train->DynamicObject->Mechanik->TakeControl(true); + } +} + +void TTrain::OnCommand_aidriverdisable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS && Train->DynamicObject->Mechanik) + { + // on press + Train->DynamicObject->Mechanik->TakeControl(false); + } +} + +void TTrain::OnCommand_jointcontrollerset(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + // on press or hold + // value controls brake in range 0-0.5, master controller in range 0.5-1.0 + if (Command.param1 >= 0.5) + { + Train->set_master_controller((Command.param1 * 2 - 1) * + (Train->mvControlled->CoupledCtrl ? Train->mvControlled->MainCtrlPosNo + Train->mvControlled->ScndCtrlPosNo : Train->mvControlled->MainCtrlPosNo)); + Train->m_mastercontrollerinuse = true; + // when SplitEDPneumaticBrake is active the joint controller's negative range + // commands the dedicated dynamic-brake lever instead of the local pneumatic brake + if (Train->mvControlled->SplitEDPneumaticBrake) + { + Train->mvControlled->DynamicBrakeLevelSet(0.0); + } + else + { + Train->mvOccupied->LocalBrakePosA = 0; + } + } + else + { + auto const negativeRange{std::clamp(1.0 - Command.param1 * 2, 0.0, 1.0)}; + if (Train->mvControlled->SplitEDPneumaticBrake) + { + // negative range of jointctrl drives only ED braking, local pneumatic brake stays untouched. + // snap to DBPN discrete stops so the lever animates step-by-step + auto const stepCount{std::max(1, Train->mvControlled->DynamicBrakeCtrlPosNo)}; + auto const snapped{std::round(negativeRange * stepCount) / stepCount}; + Train->mvControlled->DynamicBrakeLevelSet(snapped); + } + else + { + Train->mvOccupied->LocalBrakePosA = negativeRange; + } + if (Train->mvControlled->MainCtrlPowerPos() > 0) + { + Train->set_master_controller(Train->mvControlled->MainCtrlNoPowerPos()); + } + } + } + else + { + // release + Train->m_mastercontrollerinuse = false; + Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_BASERETURNDELAY; // NOTE: keyboard return delay is omitted for other input sources + } +} + +void TTrain::OnCommand_mastercontrollerincrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + // on press or hold + auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; + // when SplitEDPneumaticBrake is true the joint controller's negative range maps + // to the dedicated dynamic-brake lever (DynamicBrakeCtrl) rather than to LocalBrake + auto const negativeRangeActive{splitMode ? Train->mvControlled->DynamicBrakeCtrlPos > 0.0 : Train->mvOccupied->LocalBrakePosA > 0.0}; + if (Train->ggJointCtrl.SubModel != nullptr && negativeRangeActive) + { + if (splitMode) + { + OnCommand_DynamicBrakeControllerDecrease(Train, Command); + Train->m_mastercontrollerinuse = true; + } + else + { + OnCommand_independentbrakedecrease(Train, Command); + } + } + else + { + Train->mvControlled->IncMainCtrl(1); + Train->m_mastercontrollerinuse = true; + } + } + else if (Command.action == GLFW_RELEASE) + { + // release + Train->m_mastercontrollerinuse = false; + Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_KEYBOARDETURNDELAY + EU07_CONTROLLER_BASERETURNDELAY; + } +} + +void TTrain::OnCommand_mastercontrollerincreasefast(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + // on press or hold + auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; + auto const negativeRangeActive{splitMode ? Train->mvControlled->DynamicBrakeCtrlPos > 0.0 : Train->mvOccupied->LocalBrakePosA > 0.0}; + if (Train->ggJointCtrl.SubModel != nullptr && negativeRangeActive) + { + if (splitMode) + { + OnCommand_DynamicBrakeControllerDecreaseFast(Train, Command); + Train->m_mastercontrollerinuse = true; + } + else + { + OnCommand_independentbrakedecreasefast(Train, Command); + } + } + else + { + Train->mvControlled->IncMainCtrl(Train->mvControlled->MainCtrlPosNo); + Train->m_mastercontrollerinuse = true; + } + } + else + { + // release + Train->m_mastercontrollerinuse = false; + Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_KEYBOARDETURNDELAY + EU07_CONTROLLER_BASERETURNDELAY; + } +} + +void TTrain::OnCommand_mastercontrollerdecrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + // on press or hold + auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; + if (Train->ggJointCtrl.SubModel != nullptr && Train->mvControlled->IsMainCtrlNoPowerPos()) + { + // negative range of jointctrl: ED brake when split, otherwise pneumatic local brake + if (splitMode) + { + OnCommand_DynamicBrakeControllerIncrease(Train, Command); + Train->m_mastercontrollerinuse = true; + } + else + { + OnCommand_independentbrakeincrease(Train, Command); + } + } + else + { + Train->mvControlled->DecMainCtrl(1); + Train->m_mastercontrollerinuse = true; + } + } + else if (Command.action == GLFW_RELEASE) + { + // release + Train->m_mastercontrollerinuse = false; + Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_KEYBOARDETURNDELAY + EU07_CONTROLLER_BASERETURNDELAY; + } +} + +void TTrain::OnCommand_mastercontrollerdecreasefast(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + // on press or hold + auto const splitMode{Train->mvControlled->SplitEDPneumaticBrake}; + if (Train->ggJointCtrl.SubModel != nullptr && Train->mvControlled->IsMainCtrlNoPowerPos()) + { + if (splitMode) + { + OnCommand_DynamicBrakeControllerIncreaseFast(Train, Command); + Train->m_mastercontrollerinuse = true; + } + else + { + OnCommand_independentbrakeincreasefast(Train, Command); + } + } + else + { + Train->mvControlled->DecMainCtrl(Train->mvControlled->MainCtrlPowerPos()); + Train->m_mastercontrollerinuse = true; + } + } + else + { + // release + Train->m_mastercontrollerinuse = false; + Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_KEYBOARDETURNDELAY + EU07_CONTROLLER_BASERETURNDELAY; + } +} + +void TTrain::OnCommand_mastercontrollerset(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + // on press or hold + Train->set_master_controller(Command.param1); + Train->m_mastercontrollerinuse = true; + } + else + { + // release + Train->m_mastercontrollerinuse = false; + Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_BASERETURNDELAY; // NOTE: keyboard return delay is omitted for other input sources + } +} + +void TTrain::OnCommand_secondcontrollerincrease(TTrain *Train, command_data const &Command) +{ + + if (Train->mvControlled->EngineType == TEngineType::DieselElectric && true == Train->mvControlled->ShuntModeAllow && true == Train->mvControlled->ShuntMode) + { + if (Command.action != GLFW_RELEASE) + { + Train->mvControlled->AnPos = std::clamp(Train->mvControlled->AnPos + 0.025, 0.0, 1.0); + } + } + else + { + // regular mode + // push or pushtoggle control type + if (Train->ggScndCtrl.is_push()) + { + if (Command.action == GLFW_PRESS) + { + // activate on press + Train->mvControlled->IncScndCtrl(1); + } + } + // toggle control type + else + { + if (Command.action != GLFW_RELEASE) + { + Train->mvControlled->IncScndCtrl(1); + } + } + // HACK: potentially animate push or pushtoggle control + if (Train->ggScndCtrl.is_push()) + { + auto const activeposition{Train->ggScndCtrl.is_toggle() ? 1.f : 1.f}; + auto const neutralposition{Train->ggScndCtrl.is_toggle() ? 0.5f : 0.f}; + Train->ggScndCtrl.UpdateValue(Command.action == GLFW_RELEASE ? neutralposition : activeposition, Train->dsbSwitch); + } + // potentially animate tempomat button + if (Train->ggScndCtrlButton.is_push() && Train->mvControlled->ScndCtrlPos <= 1) + { + Train->ggScndCtrlButton.UpdateValue(Command.action == GLFW_RELEASE ? 0.f : 1.f, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_secondcontrollerincreasefast(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + // on press or hold + if (Train->mvControlled->EngineType == TEngineType::DieselElectric && true == Train->mvControlled->ShuntMode) + { + Train->mvControlled->AnPos = 1.0; + } + else + { + Train->mvControlled->IncScndCtrl(2); + } + } +} + +void TTrain::OnCommand_notchingrelaytoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->mvOccupied->AutoRelayFlag) + { + // turn on + Train->mvOccupied->AutoRelaySwitch(true); + } + else + { + // turn off + Train->mvOccupied->AutoRelaySwitch(false); + } + } +} + +void TTrain::OnCommand_tempomattoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggScndCtrlButton.is_push()) + { + // impulse switch + if (Command.action == GLFW_RELEASE) + { + // just move the button(s) back to default position + // visual feedback + Train->ggScndCtrlButton.UpdateValue(0.0, Train->dsbSwitch); + Train->ggScndCtrlOffButton.UpdateValue(0.0, Train->dsbSwitch); + return; + } + // glfw_press + if (Train->mvControlled->ScndCtrlPos == 0) + { + // turn on if it's not active + Train->mvControlled->IncScndCtrl(1); + // visual feedback + Train->ggScndCtrlButton.UpdateValue(1.0, Train->dsbSwitch); + } + else + { + // otherwise turn off + Train->mvControlled->DecScndCtrl(2); + // visual feedback + if (Train->m_controlmapper.contains("tempomatoff_sw:")) + { + Train->ggScndCtrlOffButton.UpdateValue(1.0, Train->dsbSwitch); + } + else + { + Train->ggScndCtrlButton.UpdateValue(1.0, Train->dsbSwitch); + } + } + } + else + { + // two-state switch + if (Command.action == GLFW_RELEASE) + { + return; + } + + if (Train->mvControlled->ScndCtrlPos == 0) + { + // turn on + Train->mvControlled->IncScndCtrl(1); + // visual feedback + Train->ggScndCtrlButton.UpdateValue(1.0, Train->dsbSwitch); + } + else + { + // turn off + Train->mvControlled->DecScndCtrl(2); + // visual feedback + Train->ggScndCtrlButton.UpdateValue(0.0, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_distancecounteractivate(TTrain *Train, command_data const &Command) +{ + // NOTE: distance meter activation button is presumed to be of impulse type + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggDistanceCounterButton.UpdateValue(1.0, Train->dsbSwitch); + // activate or start anew + if (Train->mvOccupied->isDoubleClickForMeasureNeeded) + { + // handler tempomatu dla podwojnego kliku + if (Train->trainLenghtMeasureTimer >= 0.f) // jesli zdazylismy w czasie sekundy + Train->m_distancecounter = 0.f; // rozpoczynamy pomiar + else + Train->trainLenghtMeasureTimer = Train->mvOccupied->DistanceCounterDoublePressPeriod; // odpalamy zegarek od nowa + } + else + { + // dla pojedynczego kliku + Train->m_distancecounter = 0.f; + } + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggDistanceCounterButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_mucurrentindicatorothersourceactivate(TTrain *Train, command_data const &Command) +{ + + if (Train->ggNextCurrentButton.SubModel == nullptr) + { + if (Command.action == GLFW_PRESS) + { + WriteLog("Current Indicator Source switch is missing, or wasn't defined"); + } + return; + } + + if (Command.action == GLFW_PRESS) + { + // turn on + Train->ShowNextCurrent = true; + // visual feedback + Train->ggNextCurrentButton.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) + { + // turn off + Train->ShowNextCurrent = false; + // visual feedback + Train->ggNextCurrentButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_secondcontrollerdecrease(TTrain *Train, command_data const &Command) +{ + + if (Train->mvControlled->EngineType == TEngineType::DieselElectric && true == Train->mvControlled->ShuntMode) + { + if (Command.action != GLFW_RELEASE) + { + Train->mvControlled->AnPos = std::clamp(Train->mvControlled->AnPos - 0.025, 0.0, 1.0); + } + } + else + { + // regular mode + // push or pushtoggle control type + if (Train->ggScndCtrl.is_push()) + { + // basic push control can't decrease state, but pushtoggle can + if (true == Train->ggScndCtrl.is_toggle() && Command.action == GLFW_PRESS) + { + // activate on press + Train->mvControlled->DecScndCtrl(1); + } + } + // toggle control type + else + { + if (Command.action != GLFW_RELEASE) + { + Train->mvControlled->DecScndCtrl(1); + } + } + // HACK: potentially animate push or pushtoggle control + if (Train->ggScndCtrl.is_push()) + { + auto const activeposition{Train->ggScndCtrl.is_toggle() ? 0.f : 1.f}; + auto const neutralposition{Train->ggScndCtrl.is_toggle() ? 0.5f : 0.f}; + Train->ggScndCtrl.UpdateValue(Command.action == GLFW_RELEASE ? neutralposition : activeposition, Train->dsbSwitch); + } + // potentially animate tempomat button + if (Train->ggScndCtrlButton.is_push() && Train->mvControlled->ScndCtrlPos <= 1) + { + if (Train->m_controlmapper.contains("tempomatoff_sw:")) + { + Train->ggScndCtrlOffButton.UpdateValue(Command.action == GLFW_RELEASE ? 0.f : 1.f, Train->dsbSwitch); + } + else + { + Train->ggScndCtrlButton.UpdateValue(Command.action == GLFW_RELEASE ? 0.f : 1.f, Train->dsbSwitch); + } + } + } +} + +void TTrain::OnCommand_secondcontrollerdecreasefast(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_RELEASE) + { + // on press or hold + if (Train->mvControlled->EngineType == TEngineType::DieselElectric && true == Train->mvControlled->ShuntMode) + { + Train->mvControlled->AnPos = 0.0; + } + else + { + Train->mvControlled->DecScndCtrl(2); + } + } +} + +void TTrain::OnCommand_secondcontrollerset(TTrain *Train, command_data const &Command) +{ + + auto const targetposition{std::min(Command.param1, Train->mvControlled->ScndCtrlPosNo)}; + // HACK: potentially animate push or pushtoggle control + if (Train->ggScndCtrl.is_push()) + { + auto const activeposition{Train->ggScndCtrl.is_toggle() ? + (targetposition < Train->mvControlled->ScndCtrlPos ? 0.f : + targetposition > Train->mvControlled->ScndCtrlPos ? 1.f : + Train->ggScndCtrl.GetDesiredValue()) : // leave the control in its current position if it hits the limit + targetposition == 0 ? 0.f : + 1.f}; + auto const neutralposition{Train->ggScndCtrl.is_toggle() ? 0.5f : 0.f}; + Train->ggScndCtrl.UpdateValue(Command.action == GLFW_RELEASE ? neutralposition : activeposition, Train->dsbSwitch); + } + // update control value + if (Command.action != GLFW_RELEASE) + { + // on press or hold + while (targetposition < Train->mvControlled->GetVirtualScndPos() && true == Train->mvControlled->DecScndCtrl(1)) + { + // all work is done in the header + } + while (targetposition > Train->mvControlled->GetVirtualScndPos() && true == Train->mvControlled->IncScndCtrl(1)) + { + // all work is done in the header + } + } +} + +void TTrain::OnCommand_reverserincrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + // HACK: master controller position isn't set in occupied vehicle in E(D)MUs + // so we do a manual check in relevant vehicle here + if (false == Train->mvControlled->EIMDirectionChangeAllow()) + { + return; + } + + if (Train->mvOccupied->DirectionForward() && Train->mvOccupied->DirActive && Train->DynamicObject->Mechanik) + { + // aktualizacja skrajnych pojazdów w składzie + Train->DynamicObject->Mechanik->DirectionChange(); + } + } +} + +void TTrain::OnCommand_reverserdecrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + // HACK: master controller position isn't set in occupied vehicle in E(D)MUs + // so we do a manual check in relevant vehicle here + if (false == Train->mvControlled->EIMDirectionChangeAllow()) + { + return; + } + + if (Train->mvOccupied->DirectionBackward() && Train->mvOccupied->DirActive && Train->DynamicObject->Mechanik) + { + // aktualizacja skrajnych pojazdów w składzie + Train->DynamicObject->Mechanik->DirectionChange(); + } + } +} + +void TTrain::OnCommand_reverserforwardhigh(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + // HACK: master controller position isn't set in occupied vehicle in E(D)MUs + // so we do a manual check in relevant vehicle here + if (false == Train->mvControlled->EIMDirectionChangeAllow()) + { + return; + } + + // HACK: try to move the reverser one position back, in case it's set to "high forward" + OnCommand_reverserdecrease(Train, Command); + + if (Train->mvOccupied->DirActive < 1) + { + + while (Train->mvOccupied->DirActive < 1 && true == Train->mvOccupied->DirectionForward()) + { + // all work is done in the header + } + // aktualizacja skrajnych pojazdów w składzie + if (Train->mvOccupied->DirActive == 1 && Train->DynamicObject->Mechanik) + { + + Train->DynamicObject->Mechanik->DirectionChange(); + } + } + OnCommand_reverserincrease(Train, Command); + } +} + +void TTrain::OnCommand_reverserforward(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + // HACK: master controller position isn't set in occupied vehicle in E(D)MUs + // so we do a manual check in relevant vehicle here + if (false == Train->mvControlled->EIMDirectionChangeAllow()) + { + return; + } + + // HACK: try to move the reverser one position back, in case it's set to "high forward" + // OnCommand_reverserdecrease( Train, Command ); + // visual feedback + Train->ggDirForwardButton.UpdateValue(1.0, Train->dsbSwitch); + + if (Train->mvOccupied->DirActive == 0) + { + + while (Train->mvOccupied->DirActive < 1 && true == Train->mvOccupied->DirectionForward()) + { + // all work is done in the header + } + // aktualizacja skrajnych pojazdów w składzie + if (Train->mvOccupied->DirActive == 1 && Train->DynamicObject->Mechanik) + { + + Train->DynamicObject->Mechanik->DirectionChange(); + } + } + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + Train->ggDirForwardButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_reverserneutral(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + // HACK: master controller position isn't set in occupied vehicle in E(D)MUs + // so we do a manual check in relevant vehicle here + if (false == Train->mvControlled->EIMDirectionChangeAllow()) + { + return; + } + // visual feedback + Train->ggDirNeutralButton.UpdateValue(1.0, Train->dsbSwitch); + while (Train->mvOccupied->DirActive < 0 && true == Train->mvOccupied->DirectionForward()) + { + // all work is done in the header + } + while (Train->mvOccupied->DirActive > 0 && true == Train->mvOccupied->DirectionBackward()) + { + // all work is done in the header + } + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + Train->ggDirNeutralButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_reverserbackward(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + // HACK: master controller position isn't set in occupied vehicle in E(D)MUs + // so we do a manual check in relevant vehicle here + if (false == Train->mvControlled->EIMDirectionChangeAllow()) + { + return; + } + Train->ggDirBackwardButton.UpdateValue(1.0, Train->dsbSwitch); + if (Train->mvOccupied->DirActive == 0) + { + + while (Train->mvOccupied->DirActive > -1 && true == Train->mvOccupied->DirectionBackward()) + { + // all work is done in the header + } + // aktualizacja skrajnych pojazdów w składzie + if (Train->mvOccupied->DirActive == -1 && Train->DynamicObject->Mechanik) + { + + Train->DynamicObject->Mechanik->DirectionChange(); + } + } + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + Train->ggDirBackwardButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_speedcontrolincrease(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SpeedCtrlInc(); + // visual feedback + Train->ggSpeedControlIncreaseButton.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + Train->ggSpeedControlIncreaseButton.UpdateValue(0.0, Train->dsbSwitch); + } +}; + +void TTrain::OnCommand_speedcontroldecrease(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SpeedCtrlDec(); + // visual feedback + Train->ggSpeedControlDecreaseButton.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + Train->ggSpeedControlDecreaseButton.UpdateValue(0.0, Train->dsbSwitch); + } +}; + +void TTrain::OnCommand_speedcontrolpowerincrease(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SpeedCtrlPowerInc(); + // visual feedback + Train->ggSpeedControlPowerIncreaseButton.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + Train->ggSpeedControlPowerIncreaseButton.UpdateValue(0.0, Train->dsbSwitch); + } +}; + +void TTrain::OnCommand_speedcontrolpowerdecrease(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SpeedCtrlPowerDec(); + // visual feedback + Train->ggSpeedControlPowerDecreaseButton.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + Train->ggSpeedControlPowerDecreaseButton.UpdateValue(0.0, Train->dsbSwitch); + } +}; + +void TTrain::OnCommand_speedcontrolbutton(TTrain *Train, command_data const &Command) +{ + + auto const itemindex = static_cast(Command.command) - static_cast(user_command::speedcontrolbutton0); + auto &item = Train->ggSpeedCtrlButtons[itemindex]; + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SpeedCtrlButton(itemindex); + // visual feedback + Train->ggSpeedCtrlButtons[itemindex].UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + Train->ggSpeedCtrlButtons[itemindex].UpdateValue(0.0, Train->dsbSwitch); + } +}; diff --git a/vehicle/Train_Commands_Doors.cpp b/vehicle/Train_Commands_Doors.cpp new file mode 100644 index 00000000..029194dd --- /dev/null +++ b/vehicle/Train_Commands_Doors.cpp @@ -0,0 +1,851 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "vehicle/Train.h" + +#include "simulation/simulation.h" +#include "world/Event.h" +#include "simulation/simulationtime.h" +#include "utilities/Logs.h" +#include "model/Model3d.h" +#include "vehicle/Driver.h" +#include "vehicle/DynObj.h" +#include "rendering/renderer.h" +#include + +void TTrain::OnCommand_doorlocktoggle(TTrain *Train, command_data const &Command) +{ + + if (Train->ggDoorSignallingButton.SubModel == nullptr) + { + if (Command.action == GLFW_PRESS) + { + WriteLog("Door Lock switch is missing, or wasn't defined"); + } + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the sound can loop uninterrupted + if (false == Train->mvOccupied->Doors.lock_enabled) + { + // turn on + // TODO: door lock command to send through consist + Train->mvOccupied->LockDoors(true); + // visual feedback + Train->ggDoorSignallingButton.UpdateValue(1.0, Train->dsbSwitch); + } + else + { + // turn off + // TODO: door lock command to send through consist + Train->mvOccupied->LockDoors(false); + // visual feedback + Train->ggDoorSignallingButton.UpdateValue(0.0, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_doortoggleleft(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // NOTE: test how the door state check works with consists where the occupied vehicle doesn't have opening doors + if (false == (Train->ggDoorLeftButton.GetDesiredValue() > 0.5 || Train->ggDoorLeftOnButton.GetDesiredValue() > 0.5)) + { + // open + OnCommand_dooropenleft(Train, Command); + } + else + { + // close + if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorLeftOffButton.SubModel == nullptr) + { + // OnCommand_doorcloseall( Train, Command ); + // if two-button setup lacks dedicated closing button require the user to press appropriate button manually + return; + } + else + { + OnCommand_doorcloseleft(Train, Command); + } + } + } + else if (Command.action == GLFW_RELEASE) + { + + if (true == (Train->ggDoorLeftButton.GetDesiredValue() > 0.5 || Train->ggDoorLeftOnButton.GetDesiredValue() > 0.5)) + { + // open + if (Train->mvOccupied->Doors.has_autowarning && Train->mvOccupied->DepartureSignal) + { + // complete closing the doors + if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorLeftOffButton.SubModel == nullptr) + { + // OnCommand_doorcloseall( Train, Command ); + // if two-button setup lacks dedicated closing button require the user to press appropriate button manually + return; + } + else + { + OnCommand_doorcloseleft(Train, Command); + } + } + else + { + OnCommand_dooropenleft(Train, Command); + } + } + else + { + // close + if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorLeftOffButton.SubModel == nullptr) + { + // OnCommand_doorcloseall( Train, Command ); + // if two-button setup lacks dedicated closing button require the user to press appropriate button manually + return; + } + else + { + OnCommand_doorcloseleft(Train, Command); + } + } + // visual feedback + // dedicated closing buttons are presumed to be impulse switches and return automatically to neutral position + // NOTE: temporary arrangement, can be removed when LD system is in place + if (Train->ggDoorLeftOffButton.SubModel) + Train->ggDoorLeftOffButton.UpdateValue(0.0, Train->dsbSwitch); + if (Train->ggDoorLeftOnButton.SubModel) + Train->ggDoorLeftOnButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_doorpermitleft(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + if (false == Train->mvOccupied->Doors.permit_presets.empty()) + { + return; + } + + auto const side{(Train->cab_to_end() == end::front ? side::left : side::right)}; + + if (Command.action == GLFW_PRESS) + { + + if (Train->ggDoorLeftPermitButton.is_push()) + { + // impulse switch + Train->mvOccupied->PermitDoors(side); + // visual feedback + Train->ggDoorLeftPermitButton.UpdateValue(1.0, Train->dsbSwitch); + // start potential timer for remote door control + Train->m_doorpermittimers[side] = Train->mvOccupied->DoorsOpenWithPermitAfter; + } + else + { + // two-state switch + auto const newstate{!(Train->ggDoorLeftPermitButton.GetDesiredValue() > 0.5)}; + + Train->mvOccupied->PermitDoors(side, newstate); + // visual feedback + Train->ggDoorLeftPermitButton.UpdateValue(newstate ? 1.0 : 0.0, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE && Train->ggDoorLeftPermitButton.is_push()) + { + + // impulse switch + // visual feedback + Train->ggDoorLeftPermitButton.UpdateValue(0.0, Train->dsbSwitch); + // reset potential remote door control timer + Train->m_doorpermittimers[side] = -1.f; + } +} + +void TTrain::OnCommand_doorpermitright(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + if (false == Train->mvOccupied->Doors.permit_presets.empty()) + { + return; + } + + auto const side{(Train->cab_to_end() == end::front ? side::right : side::left)}; + + if (Command.action == GLFW_PRESS) + { + + if (Train->ggDoorRightPermitButton.type() == TGaugeType::push) + { + // impulse switch + Train->mvOccupied->PermitDoors(side); + // visual feedback + Train->ggDoorRightPermitButton.UpdateValue(1.0, Train->dsbSwitch); + // start potential timer for remote door control + Train->m_doorpermittimers[side] = Train->mvOccupied->DoorsOpenWithPermitAfter; + } + else + { + // two-state switch + auto const newstate{!(Train->ggDoorRightPermitButton.GetDesiredValue() > 0.5)}; + + Train->mvOccupied->PermitDoors(side, newstate); + // visual feedback + Train->ggDoorRightPermitButton.UpdateValue(newstate ? 1.0 : 0.0, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE && Train->ggDoorRightPermitButton.type() == TGaugeType::push) + { + + // impulse switch + // visual feedback + Train->ggDoorRightPermitButton.UpdateValue(0.0, Train->dsbSwitch); + // reset potential remote door control timer + Train->m_doorpermittimers[side] = -1.f; + } +} + +void TTrain::OnCommand_doorpermitpresetactivatenext(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + Train->mvOccupied->ChangeDoorPermitPreset(1); + // visual feedback + Train->ggDoorPermitPresetButton.UpdateValue(Train->mvOccupied->Doors.permit_preset, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_doorpermitpresetactivateprevious(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + + Train->mvOccupied->ChangeDoorPermitPreset(-1); + // visual feedback + Train->ggDoorPermitPresetButton.UpdateValue(Train->mvOccupied->Doors.permit_preset, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_dooropenleft(TTrain *Train, command_data const &Command) +{ + + auto const remoteopencontrol{Train->mvOccupied->Doors.open_control == control_t::driver || Train->mvOccupied->Doors.open_control == control_t::mixed}; + + if (false == remoteopencontrol) + { + return; + } + + if (Train->ggDoorLeftOnButton.SubModel == nullptr && Train->ggDoorLeftButton.SubModel == nullptr) + { + + return; + } + + if (Command.action == GLFW_PRESS) + { + Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::left : side::right, true); + // visual feedback + if (Train->ggDoorLeftOnButton.SubModel != nullptr) + { + // two separate impulse switches + Train->ggDoorLeftOnButton.UpdateValue(1.0, Train->dsbSwitch); + } + else + { + // single two-state switch + Train->ggDoorLeftButton.UpdateValue(1.0, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE && Train->ggDoorLeftOnButton.SubModel != nullptr) + { + // visual feedback + // two separate impulse switches + Train->ggDoorLeftOnButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_doorcloseleft(TTrain *Train, command_data const &Command) +{ + + auto const remoteclosecontrol{Train->mvOccupied->Doors.close_control == control_t::driver || Train->mvOccupied->Doors.close_control == control_t::mixed}; + + if (false == remoteclosecontrol) + { + return; + } + + if (Train->ggDoorLeftOffButton.SubModel == nullptr && Train->ggDoorLeftButton.SubModel == nullptr) + { + + return; + } + + if (Command.action == GLFW_PRESS) + { + + if (Train->mvOccupied->Doors.has_autowarning) + { + // automatic departure signal delays actual door closing until the button is released + Train->mvOccupied->signal_departure(true); + } + else + { + // TODO: move door opening/closing to the update, so the switch animation doesn't hinge on door working + Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::left : side::right, false); + } + // visual feedback + if (Train->ggDoorLeftOffButton.SubModel != nullptr) + { + // two separate switches to open and close the door + Train->ggDoorLeftOffButton.UpdateValue(1.0, Train->dsbSwitch); + } + else + { + // single two-state switch + Train->ggDoorLeftButton.UpdateValue(0.0, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + + if (Train->mvOccupied->Doors.has_autowarning) + { + // automatic departure signal delays actual door closing until the button is released + Train->mvOccupied->signal_departure(false); + // now we can actually close the door + Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::left : side::right, false); + } + // visual feedback + // dedicated closing buttons are presumed to be impulse switches and return automatically to neutral position + if (Train->ggDoorLeftOffButton.SubModel) + Train->ggDoorLeftOffButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_doortoggleright(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // NOTE: test how the door state check works with consists where the occupied vehicle doesn't have opening doors + if (false == (Train->ggDoorRightButton.GetDesiredValue() > 0.5 || Train->ggDoorRightOnButton.GetDesiredValue() > 0.5)) + { + // open + OnCommand_dooropenright(Train, Command); + } + else + { + // close + if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorRightOffButton.SubModel == nullptr) + { + // OnCommand_doorcloseall( Train, Command ); + // if two-button setup lacks dedicated closing button require the user to press appropriate button manually + return; + } + else + { + OnCommand_doorcloseright(Train, Command); + } + } + } + else if (Command.action == GLFW_RELEASE) + { + + if (true == (Train->ggDoorRightButton.GetDesiredValue() > 0.5 || Train->ggDoorRightOnButton.GetDesiredValue() > 0.5)) + { + // open + if (Train->mvOccupied->Doors.has_autowarning && Train->mvOccupied->DepartureSignal) + { + // complete closing the doors + if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorRightOffButton.SubModel == nullptr) + { + // OnCommand_doorcloseall( Train, Command ); + // if two-button setup lacks dedicated closing button require the user to press appropriate button manually + return; + } + else + { + OnCommand_doorcloseright(Train, Command); + } + } + else + { + OnCommand_dooropenright(Train, Command); + } + } + else + { + // close + if (Train->ggDoorAllOffButton.SubModel != nullptr && Train->ggDoorRightOffButton.SubModel == nullptr) + { + // OnCommand_doorcloseall( Train, Command ); + // if two-button setup lacks dedicated closing button require the user to press appropriate button manually + return; + } + else + { + OnCommand_doorcloseright(Train, Command); + } + } + // visual feedback + // dedicated closing buttons are presumed to be impulse switches and return automatically to neutral position + // NOTE: temporary arrangement, can be removed when LD system is in place + if (Train->ggDoorRightOffButton.SubModel) + Train->ggDoorRightOffButton.UpdateValue(0.0, Train->dsbSwitch); + if (Train->ggDoorRightOnButton.SubModel) + Train->ggDoorRightOnButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_dooropenright(TTrain *Train, command_data const &Command) +{ + + auto const remoteopencontrol{Train->mvOccupied->Doors.open_control == control_t::driver || Train->mvOccupied->Doors.open_control == control_t::mixed}; + + if (false == remoteopencontrol) + { + return; + } + + if (Train->ggDoorRightOnButton.SubModel == nullptr && Train->ggDoorRightButton.SubModel == nullptr) + { + + return; + } + + if (Command.action == GLFW_PRESS) + { + + Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::right : side::left, true); + // visual feedback + if (Train->ggDoorRightOnButton.SubModel != nullptr) + { + // two separate impulse switches + Train->ggDoorRightOnButton.UpdateValue(1.0, Train->dsbSwitch); + } + else + { + // single two-state switch + Train->ggDoorRightButton.UpdateValue(1.0, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE && Train->ggDoorRightOnButton.SubModel != nullptr) + { + // visual feedback + // two separate impulse switches + Train->ggDoorRightOnButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_doorcloseright(TTrain *Train, command_data const &Command) +{ + + auto const remoteclosecontrol{Train->mvOccupied->Doors.close_control == control_t::driver || Train->mvOccupied->Doors.close_control == control_t::mixed}; + + if (false == remoteclosecontrol) + { + return; + } + + if (Train->ggDoorRightOffButton.SubModel == nullptr && Train->ggDoorRightButton.SubModel == nullptr) + { + + return; + } + + if (Command.action == GLFW_PRESS) + { + + if (Train->mvOccupied->Doors.has_autowarning) + { + // automatic departure signal delays actual door closing until the button is released + Train->mvOccupied->signal_departure(true); + } + else + { + Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::right : side::left, false); + } + // visual feedback + if (Train->ggDoorRightOffButton.SubModel != nullptr) + { + // two separate switches to open and close the door + Train->ggDoorRightOffButton.UpdateValue(1.0, Train->dsbSwitch); + } + else + { + // single two-state switch + Train->ggDoorRightButton.UpdateValue(0.0, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + + if (Train->mvOccupied->Doors.has_autowarning) + { + // automatic departure signal delays actual door closing until the button is released + Train->mvOccupied->signal_departure(false); + // now we can actually close the door + Train->mvOccupied->OperateDoors(Train->cab_to_end() == end::front ? side::right : side::left, false); + } + // visual feedback + // dedicated closing buttons are presumed to be impulse switches and return automatically to neutral position + if (Train->ggDoorRightOffButton.SubModel) + Train->ggDoorRightOffButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_dooropenall(TTrain *Train, command_data const &Command) +{ + + auto const remoteopencontrol{Train->mvOccupied->Doors.open_control == control_t::driver || Train->mvOccupied->Doors.open_control == control_t::mixed}; + + if (false == remoteopencontrol) + { + return; + } + + if (Train->ggDoorAllOnButton.SubModel == nullptr) + { + // TODO: expand definition of cab controls so we can know if the control is present without testing for presence of 3d switch + if (Command.action == GLFW_PRESS) + { + WriteLog("Open All Doors switch is missing, or wasn't defined"); + } + return; + } + + if (Command.action == GLFW_PRESS) + { + + Train->mvOccupied->OperateDoors(side::right, true); + Train->mvOccupied->OperateDoors(side::left, true); + // visual feedback + Train->ggDoorAllOnButton.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggDoorAllOnButton.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_doorcloseall(TTrain *Train, command_data const &Command) +{ + + auto const remoteclosecontrol{Train->mvOccupied->Doors.close_control == control_t::driver || Train->mvOccupied->Doors.close_control == control_t::mixed}; + + if (false == remoteclosecontrol) + { + return; + } + + if (Train->ggDoorAllOffButton.SubModel == nullptr) + { + // TODO: expand definition of cab controls so we can know if the control is present without testing for presence of 3d switch + if (Command.action == GLFW_PRESS) + { + WriteLog("Close All Doors switch is missing, or wasn't defined"); + } + return; + } + + if (Command.action == GLFW_PRESS) + { + + if (Train->mvOccupied->Doors.has_autowarning) + { + Train->mvOccupied->signal_departure(true); + } + if (Train->ggDoorAllOffButton.type() != TGaugeType::push_delayed) + { + // delays the action until the button is released + Train->mvOccupied->OperateDoors(side::right, false); + Train->mvOccupied->OperateDoors(side::left, false); + } + // visual feedback + Train->ggDoorLeftButton.UpdateValue(0.0, Train->dsbSwitch); + Train->ggDoorRightButton.UpdateValue(0.0, Train->dsbSwitch); + if (Train->ggDoorAllOffButton.SubModel) + Train->ggDoorAllOffButton.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) + { + if (Train->mvOccupied->Doors.has_autowarning) + { + Train->mvOccupied->signal_departure(false); + } + if (Train->ggDoorAllOffButton.type() == TGaugeType::push_delayed) + { + // now we can actually close the door + Train->mvOccupied->OperateDoors(side::right, false); + Train->mvOccupied->OperateDoors(side::left, false); + } + // visual feedback + if (Train->ggDoorAllOffButton.SubModel) + Train->ggDoorAllOffButton.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_doorsteptoggle(TTrain *Train, command_data const &Command) +{ + // TODO: move logic/visualization code to the gauge, on_command() should return hint whether it should invoke a reaction + if (Command.action == GLFW_PRESS) + { + // effect + if (false == Train->ggDoorStepButton.is_delayed()) + { + Train->mvOccupied->PermitDoorStep(false == Train->mvOccupied->Doors.step_enabled); + } + // visual feedback + auto const isactive{(Train->ggDoorStepButton.is_push() // always press push button + || Train->mvOccupied->Doors.step_enabled)}; // for toggle buttons indicate item state + Train->ggDoorStepButton.UpdateValue(isactive ? 1 : 0); + } + else if (Command.action == GLFW_RELEASE) + { + // effect + if (Train->ggDoorStepButton.is_delayed()) + { + Train->mvOccupied->PermitDoorStep(false == Train->mvOccupied->Doors.step_enabled); + } + // visual feedback + if (Train->ggDoorStepButton.is_push()) + { + Train->ggDoorStepButton.UpdateValue(0); + } + } +} + +void TTrain::OnCommand_doormodetoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + Train->mvOccupied->ChangeDoorControlMode(false == Train->mvOccupied->Doors.remote_only); + } +} + +void TTrain::OnCommand_mirrorstoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_PRESS) + { + return; + } + + // only reacting to press, so the sound can loop uninterrupted + if (false == Train->mvOccupied->MirrorForbidden) + { + // turn on + Train->mvOccupied->MirrorForbidden = true; + } + else + { + // turn off + Train->mvOccupied->MirrorForbidden = false; + } +} + +void TTrain::OnCommand_nearestcarcouplingincrease(TTrain *Train, command_data const &Command) +{ + + if (true == Command.freefly && Command.action == GLFW_PRESS) + { + // tryb freefly, press only + auto coupler{-1}; + auto *vehicle{Train->DynamicObject->ABuScanNearestObject(Command.location, Train->DynamicObject->GetTrack(), 1, 1500, coupler)}; + if (vehicle == nullptr) + vehicle = Train->DynamicObject->ABuScanNearestObject(Command.location, Train->DynamicObject->GetTrack(), -1, 1500, coupler); + + if (coupler != -1 && vehicle != nullptr) + { + + vehicle->couple(coupler); + } + if (Train->DynamicObject->Mechanik) + { + // aktualizacja flag kierunku w składzie + Train->DynamicObject->Mechanik->CheckVehicles(Connect); + } + } +} + +void TTrain::OnCommand_nearestcarcouplingdisconnect(TTrain *Train, command_data const &Command) +{ + + if (true == Command.freefly && Command.action == GLFW_PRESS) + { + // tryb freefly, press only + auto coupler{-1}; + auto *vehicle{Train->DynamicObject->ABuScanNearestObject(Command.location, Train->DynamicObject->GetTrack(), 1, 1500, coupler)}; + if (vehicle == nullptr) + vehicle = Train->DynamicObject->ABuScanNearestObject(Command.location, Train->DynamicObject->GetTrack(), -1, 1500, coupler); + + if (coupler != -1 && vehicle != nullptr) + { + + vehicle->uncouple(coupler); + } + if (Train->DynamicObject->Mechanik) + { + // aktualizacja flag kierunku w składzie + Train->DynamicObject->Mechanik->CheckVehicles(Disconnect); + } + } +} + +void TTrain::OnCommand_nearestcarcoupleradapterattach(TTrain *Train, command_data const &Command) +{ + + if (true == Command.freefly && Command.action == GLFW_PRESS) + { + // tryb freefly, press only + auto *vehicle{std::get(simulation::Region->find_vehicle(Command.location, 50, false, true))}; + if (vehicle == nullptr) + { + return; + } + + auto const coupler = + glm::length2(glm::vec3{vehicle->CouplerPosition(end::front)} - Command.location) < glm::length2(glm::vec3{vehicle->CouplerPosition(end::rear)} - Command.location) ? end::front : end::rear; + + vehicle->attach_coupler_adapter(coupler); + } +} + +void TTrain::OnCommand_nearestcarcoupleradapterremove(TTrain *Train, command_data const &Command) +{ + + if (true == Command.freefly && Command.action == GLFW_PRESS) + { + // tryb freefly, press only + auto *vehicle{std::get(simulation::Region->find_vehicle(Command.location, 50, false, true))}; + if (vehicle == nullptr) + { + return; + } + + auto const coupler = + glm::length2(glm::vec3{vehicle->CouplerPosition(end::front)} - Command.location) < glm::length2(glm::vec3{vehicle->CouplerPosition(end::rear)} - Command.location) ? end::front : end::rear; + + vehicle->remove_coupler_adapter(coupler); + } +} + +void TTrain::OnCommand_occupiedcarcouplingdisconnect(TTrain *Train, command_data const &Command) +{ + + // if( false == Train->m_controlmapper.contains( "couplingdisconnect_sw:" ) ) { return; } + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->m_couplingdisconnect = true; + + if (Train->iCabn == 0) + { + return; + } + + if (Train->DynamicObject) + { + Train->DynamicObject->uncouple(Train->cab_to_end()); + if (Train->DynamicObject->Mechanik) + { + // aktualizacja flag kierunku w składzie + Train->DynamicObject->Mechanik->CheckVehicles(Disconnect); + } + } + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->m_couplingdisconnect = false; + } +} + +void TTrain::OnCommand_occupiedcarcouplingdisconnectback(TTrain *Train, command_data const &Command) +{ + + // if( false == Train->m_controlmapper.contains( "couplingdisconnect_sw:" ) ) { return; } + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->m_couplingdisconnectback = true; + + if (Train->iCabn == 0) + { + return; + } + + if (Train->DynamicObject) + { + Train->DynamicObject->uncouple(1 - Train->cab_to_end()); + if (Train->DynamicObject->Mechanik) + { + // aktualizacja flag kierunku w składzie + Train->DynamicObject->Mechanik->CheckVehicles(Disconnect); + } + } + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->m_couplingdisconnectback = false; + } +} + +void TTrain::OnCommand_departureannounce(TTrain *Train, command_data const &Command) +{ + + if (Train->ggDepartureSignalButton.SubModel == nullptr) + { + if (Command.action == GLFW_PRESS) + { + WriteLog("Departure Signal button is missing, or wasn't defined"); + } + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the sound can loop uninterrupted + if (false == Train->mvOccupied->DepartureSignal) + { + // turn on + Train->mvOccupied->signal_departure(true); + // visual feedback + Train->ggDepartureSignalButton.UpdateValue(1.0, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + // turn off + Train->mvOccupied->signal_departure(false); + // visual feedback + Train->ggDepartureSignalButton.UpdateValue(0.0, Train->dsbSwitch); + } +} diff --git a/vehicle/Train_Commands_Electrical.cpp b/vehicle/Train_Commands_Electrical.cpp new file mode 100644 index 00000000..5ca2edbb --- /dev/null +++ b/vehicle/Train_Commands_Electrical.cpp @@ -0,0 +1,1890 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "vehicle/Train.h" + +#include "world/Event.h" +#include "simulation/simulationtime.h" +#include "utilities/Logs.h" +#include "model/Model3d.h" +#include "vehicle/Driver.h" +#include "vehicle/DynObj.h" +#include +#include + +void TTrain::OnCommand_batterytoggle(TTrain *Train, command_data const &Command) +{ + if (Train->allowBatteryToggle || Command.action != GLFW_REPEAT) + { + // keep the switch from flipping back and forth if key is held down + if (false == Train->mvOccupied->Power24vIsAvailable) + { + // turn on + OnCommand_batteryenable(Train, Command); + } + else + { + // turn off + OnCommand_batterydisable(Train, Command); + } + } +} + +void TTrain::OnCommand_batteryenable(TTrain *Train, command_data const &Command) +{ + if (!Train->mvOccupied->isBatteryButtonImpulse) + { // regular button behavior + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); + + Train->mvOccupied->BatterySwitch(true); + Train->allowBatteryToggle = false; + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + } + else if (Command.action == GLFW_RELEASE) + { + if (Train->ggBatteryButton.type() == TGaugeType::push) + { + // return the switch to neutral position + Train->ggBatteryButton.UpdateValue(0.5f); + } + Train->ggBatteryOnButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->allowBatteryToggle = true; + } + } + else // impulse button behavior + { + if (Command.action == GLFW_PRESS) + { + if (Train->mvOccupied->shouldHoldBatteryButton) + { + // jesli przycisk trzeba przytrzymac + Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->fBatteryTimer = Train->mvOccupied->BatteryButtonHoldTime; // start timer + } + else + { + // jesli przycisk dziala od razu + Train->mvOccupied->BatterySwitch(true); + Train->allowBatteryToggle = false; + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + + // visual feedback + Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->ggBatteryOnButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->fBatteryTimer = -1.f; // + Train->allowBatteryToggle = true; + Train->mvOccupied->batterySwAlreadyFired = false; + } + else if (Command.action == GLFW_REPEAT && Train->mvOccupied->shouldHoldBatteryButton && Train->fBatteryTimer <= 0.0 && Train->mvOccupied->Battery == false && + !Train->mvOccupied->batterySwAlreadyFired) + { + // trzymamy przycisk + Train->mvOccupied->BatterySwitch(true); + Train->mvOccupied->batterySwAlreadyFired = true; + + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + Train->allowBatteryToggle = false; + } + } +} + +void TTrain::OnCommand_batterydisable(TTrain *Train, command_data const &Command) +{ + if (!Train->mvOccupied->isBatteryButtonImpulse) + { // regular button behavior + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); + + Train->mvOccupied->BatterySwitch(false); + + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + } + else if (Command.action == GLFW_RELEASE) + { + if (Train->ggBatteryButton.type() == TGaugeType::push) + { + // return the switch to neutral position + Train->ggBatteryButton.UpdateValue(0.5f); + } + Train->ggBatteryOffButton.UpdateValue(0.0f, Train->dsbSwitch); + } + } + else // impulse button behavior + { + if (Command.action == GLFW_PRESS) + { + if (Train->mvOccupied->shouldHoldBatteryButton) + { + // jesli przycisk trzeba przytrzymac + Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->fBatteryTimer = Train->mvOccupied->BatteryButtonHoldTime; // start timer + } + else + { + // jesli przycisk dziala od razu + Train->mvOccupied->BatterySwitch(false); + Train->allowBatteryToggle = false; + + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + // visual feedback + Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); + Train->ggBatteryOffButton.UpdateValue(1.0f, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->ggBatteryOffButton.UpdateValue(0.0f, Train->dsbSwitch); + Train->allowBatteryToggle = true; + Train->mvOccupied->batterySwAlreadyFired = false; + } + else if (Command.action == GLFW_REPEAT && Train->mvOccupied->shouldHoldBatteryButton && Train->fBatteryTimer <= 0.0 && Train->mvOccupied->Battery == true && + !Train->mvOccupied->batterySwAlreadyFired) + { + // trzymamy przycisk + Train->mvOccupied->BatterySwitch(false); + Train->mvOccupied->batterySwAlreadyFired = true; + + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + Train->allowBatteryToggle = false; + } + } +} + +void TTrain::OnCommand_cabactivationtoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_REPEAT) + { + // keep the switch from flipping back and forth if key is held down + if (0 == Train->mvOccupied->CabActive) + { + // turn on + OnCommand_cabactivationenable(Train, Command); + } + else + { + // turn off + OnCommand_cabactivationdisable(Train, Command); + } + } +} + +void TTrain::OnCommand_cabactivationenable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // visual feedback + if (Train->ggCabActivationButton.type() == TGaugeType::push) + { + Train->ggCabActivationButton.UpdateValue(1.0f, Train->dsbSwitch); + } + + Train->mvOccupied->CabActivisation(); + + // side-effects + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->Dynamic()->SetLights(); + } + } + else if (Command.action == GLFW_RELEASE && Train->ggCabActivationButton.type() == TGaugeType::push) + { + // return the switch to neutral position + Train->ggCabActivationButton.UpdateValue(0.5f); + } +} + +void TTrain::OnCommand_cabactivationdisable(TTrain *Train, command_data const &Command) +{ + // TBD, TODO: ewentualnie zablokować z FIZ, np. w samochodach się nie odłącza akumulatora + if (Command.action == GLFW_PRESS) + { + // visual feedback + if (Train->ggCabActivationButton.type() == TGaugeType::push) + { + Train->ggCabActivationButton.UpdateValue(0.0f, Train->dsbSwitch); + } + + Train->mvOccupied->CabDeactivisation(); + if (Train->mvOccupied->LightsPosNo > 0 && Train->mvOccupied->InactiveCabFlag & activation::redmarkers) + { + Train->Dynamic()->SetLights(); + } + } + else if (Command.action == GLFW_RELEASE && Train->ggCabActivationButton.type() == TGaugeType::push) + { + // return the switch to neutral position + Train->ggCabActivationButton.UpdateValue(0.5f); + } +} + +void TTrain::OnCommand_pantographtogglefront(TTrain *Train, command_data const &Command) +{ + + // HACK: presence of pantograph selector prevents manual operation of the individual valves + if (Train->m_controlmapper.contains("pantselect_sw:")) + { + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const &pantograph{Train->mvPantographUnit->Pantographs[end::front]}; + auto const state{pantograph.valve.is_enabled || pantograph.is_active}; // fallback for impulse switches + if (state) + { + OnCommand_pantographlowerfront(Train, Command); + } + else + { + OnCommand_pantographraisefront(Train, Command); + } + } + else if (Command.action == GLFW_RELEASE && Train->mvOccupied->PantSwitchType == "impulse") + { + // impulse switches return automatically to neutral position + auto const ismanual{Train->iCabn == 0}; + Train->mvOccupied->OperatePantographValve(end::front, operation_t::none, ismanual ? range_t::local : range_t::consist); + } +} + +void TTrain::OnCommand_pantographtogglerear(TTrain *Train, command_data const &Command) +{ + + // HACK: presence of pantograph selector prevents manual operation of the individual valves + if (Train->m_controlmapper.contains("pantselect_sw:")) + { + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const &pantograph{Train->mvPantographUnit->Pantographs[end::rear]}; + auto const state{pantograph.valve.is_enabled || pantograph.is_active}; // fallback for impulse switches + if (state) + { + OnCommand_pantographlowerrear(Train, Command); + } + else + { + OnCommand_pantographraiserear(Train, Command); + } + } + else if (Command.action == GLFW_RELEASE && Train->mvOccupied->PantSwitchType == "impulse") + { + // impulse switches return automatically to neutral position + auto const ismanual{Train->iCabn == 0}; + Train->mvOccupied->OperatePantographValve(end::rear, operation_t::none, ismanual ? range_t::local : range_t::consist); + } +} + +void TTrain::OnCommand_pantographraisefront(TTrain *Train, command_data const &Command) +{ + + // HACK: presence of pantograph selector prevents manual operation of the individual valves + if (Train->m_controlmapper.contains("pantselect_sw:")) + { + return; + } + // prevent operation without submodel outside of engine compartment + if (Train->iCabn != 0 && false == Train->m_controlmapper.contains("pantfront_sw:")) + { + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + // HACK: don't propagate pantograph commands issued from engine compartment, these are presumed to be manually moved levers + auto const ismanual{Train->iCabn == 0}; + Train->mvOccupied->OperatePantographValve(end::front, Train->mvOccupied->PantSwitchType == "impulse" ? operation_t::enable_on : operation_t::enable, + ismanual ? range_t::local : range_t::consist); + } + else if (Command.action == GLFW_RELEASE) + { + // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch + OnCommand_pantographtogglefront(Train, Command); + } +} + +void TTrain::OnCommand_pantographraiserear(TTrain *Train, command_data const &Command) +{ + + // HACK: presence of pantograph selector prevents manual operation of the individual valves + if (Train->m_controlmapper.contains("pantselect_sw:")) + { + return; + } + // prevent operation without submodel outside of engine compartment + if (Train->iCabn != 0 && false == Train->m_controlmapper.contains("pantrear_sw:")) + { + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + // HACK: don't propagate pantograph commands issued from engine compartment, these are presumed to be manually moved levers + auto const ismanual{Train->iCabn == 0}; + Train->mvOccupied->OperatePantographValve(end::rear, Train->mvOccupied->PantSwitchType == "impulse" ? operation_t::enable_on : operation_t::enable, + ismanual ? range_t::local : range_t::consist); + } + else if (Command.action == GLFW_RELEASE) + { + // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch + OnCommand_pantographtogglerear(Train, Command); + } +} + +void TTrain::OnCommand_pantographlowerfront(TTrain *Train, command_data const &Command) +{ + + // HACK: presence of pantograph selector prevents manual operation of the individual valves + if (Train->m_controlmapper.contains("pantselect_sw:")) + { + return; + } + // prevent operation without submodel outside of engine compartment + if (Train->iCabn != 0 && false == Train->m_controlmapper.contains(Train->mvOccupied->PantSwitchType == "impulse" ? "pantfrontoff_sw:" : "pantfront_sw:")) + { + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + // HACK: don't propagate pantograph commands issued from engine compartment, these are presumed to be manually moved levers + auto const ismanual{Train->iCabn == 0}; + Train->mvOccupied->OperatePantographValve(end::front, Train->mvOccupied->PantSwitchType == "impulse" ? operation_t::disable_on : operation_t::disable, + ismanual ? range_t::local : range_t::consist); + } + else if (Command.action == GLFW_RELEASE) + { + // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch + OnCommand_pantographtogglefront(Train, Command); + } +} + +void TTrain::OnCommand_pantographlowerrear(TTrain *Train, command_data const &Command) +{ + + // HACK: presence of pantograph selector prevents manual operation of the individual valves + if (Train->m_controlmapper.contains("pantselect_sw:")) + { + return; + } + + if (Train->iCabn != 0 && false == Train->m_controlmapper.contains(Train->mvOccupied->PantSwitchType == "impulse" ? "pantrearoff_sw:" : "pantrear_sw:")) + { + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + // HACK: don't propagate pantograph commands issued from engine compartment, these are presumed to be manually moved levers + auto const ismanual{Train->iCabn == 0}; + Train->mvOccupied->OperatePantographValve(end::rear, Train->mvOccupied->PantSwitchType == "impulse" ? operation_t::disable_on : operation_t::disable, + ismanual ? range_t::local : range_t::consist); + } + else if (Command.action == GLFW_RELEASE) + { + // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch + OnCommand_pantographtogglerear(Train, Command); + } +} + +void TTrain::OnCommand_pantographlowerall(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggPantAllDownButton.SubModel == nullptr) + { + // TODO: expand definition of cab controls so we can know if the control is present without testing for presence of 3d switch + if (Command.action == GLFW_PRESS) + { + WriteLog("Lower All Pantographs switch is missing, or wasn't defined"); + } + return; + } + + if (Train->ggPantAllDownButton.type() == TGaugeType::toggle) + { + // two-state switch, only cares about press events + if (Command.action == GLFW_PRESS) + { + Train->mvPantographUnit->DropAllPantographs(false == Train->mvPantographUnit->PantAllDown); + // visual feedback + Train->ggPantAllDownButton.UpdateValue(Train->mvPantographUnit->PantAllDown ? 1.0 : 0.0, Train->dsbSwitch); + } + } + else + { + // impulse switch + Train->mvControlled->DropAllPantographs(Command.action == GLFW_PRESS); + // visual feedback + Train->ggPantAllDownButton.UpdateValue(Command.action == GLFW_PRESS ? 1.0 : 0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_pantographselectnext(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_PRESS) + { + return; + } + + if (false == Train->m_controlmapper.contains("pantselect_sw:")) + { + return; + } + + Train->change_pantograph_selection(1); +} + +void TTrain::OnCommand_pantographselectprevious(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_PRESS) + { + return; + } + + if (false == Train->m_controlmapper.contains("pantselect_sw:")) + { + return; + } + + Train->change_pantograph_selection(-1); +} + +void TTrain::OnCommand_pantographtoggleselected(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Command.action == GLFW_PRESS) + { + // recalculate pantograph state (hujhujhuj) + Train->change_pantograph_selection(1); + Train->change_pantograph_selection(-1); + + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const state{Train->mvPantographUnit->PantsValve.is_enabled || Train->mvPantographUnit->PantsValve.is_active}; // fallback for impulse switches + if (state) + { + OnCommand_pantographlowerselected(Train, Command); + } + else + { + OnCommand_pantographraiseselected(Train, Command); + } + } + else if (Command.action == GLFW_RELEASE) + { + // impulse switches return automatically to neutral position + if (Train->m_controlmapper.contains("pantselectedoff_sw:")) + { + // two buttons setup + if (Train->ggPantSelectedButton.type() != TGaugeType::toggle) + { + Train->mvOccupied->OperatePantographsValve(operation_t::enable_off); + // visual feedback + Train->ggPantSelectedButton.UpdateValue(0.0, Train->dsbSwitch); + } + if (Train->ggPantSelectedDownButton.type() != TGaugeType::toggle) + { + Train->mvOccupied->OperatePantographsValve(operation_t::disable_off); + // visual feedback + Train->ggPantSelectedDownButton.UpdateValue(0.0, Train->dsbSwitch); + } + } + else + { + if (Train->ggPantSelectedButton.type() != TGaugeType::toggle) + { + // special case, just one impulse switch controlling both states + // with neutral position mid-way + Train->mvOccupied->OperatePantographsValve(operation_t::none); + // visual feedback + Train->ggPantSelectedButton.UpdateValue(0.5, Train->dsbSwitch); + } + } + } +} + +void TTrain::OnCommand_pantographraiseselected(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Command.action == GLFW_PRESS) + { + // raise selected + Train->mvOccupied->OperatePantographsValve(Train->ggPantSelectedButton.type() != TGaugeType::toggle ? operation_t::enable_on : operation_t::enable); + // visual feedback + Train->ggPantSelectedButton.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) + { + // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch + OnCommand_pantographtoggleselected(Train, Command); + } +} + +void TTrain::OnCommand_pantographlowerselected(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Command.action == GLFW_PRESS) + { + // lower selected + Train->mvOccupied->OperatePantographsValve(Train->ggPantSelectedDownButton.type() != TGaugeType::toggle ? operation_t::disable_on : operation_t::disable); + // visual feedback + if (Train->m_controlmapper.contains("pantselectedoff_sw:")) + { + // two button setup + Train->ggPantSelectedDownButton.UpdateValue(1.0, Train->dsbSwitch); + } + else + { + // single button + Train->ggPantSelectedButton.UpdateValue(0.0, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + // NOTE: bit of a hax here, we're reusing button reset routine so we don't need a copy in every branch + OnCommand_pantographtoggleselected(Train, Command); + } +} + +void TTrain::update_pantograph_valves() +{ + + auto const &presets{mvOccupied->PantsPreset.first}; + auto &selection{mvOccupied->PantsPreset.second[cab_to_end()]}; + + auto const preset{presets[selection] - '0'}; + auto const swapends{cab_to_end() != end::front}; + // check desired states for both pantographs; value: whether the pantograph should be raised + auto const frontstate{preset & (swapends ? 2 : 1)}; + auto const rearstate{preset & (swapends ? 1 : 2)}; + mvOccupied->OperatePantographValve(end::front, frontstate ? operation_t::enable : operation_t::disable); + mvOccupied->OperatePantographValve(end::rear, rearstate ? operation_t::enable : operation_t::disable); +} + +void TTrain::change_pantograph_selection(int const Change) +{ + + auto const &presets{mvOccupied->PantsPreset.first}; + auto &selection{mvOccupied->PantsPreset.second[cab_to_end()]}; + auto const initialstate{selection}; + selection = std::clamp(selection + Change, 0, std::max(presets.size() - 1, 0)); + + if (selection == initialstate) + { + return; + } // no change, nothing to do + + // potentially adjust pantograph valves to match the new state + if (false == m_controlmapper.contains("pantvalves_sw:")) + { + update_pantograph_valves(); + } +} + +void TTrain::OnCommand_pantographvalvesupdate(TTrain *Train, command_data const &Command) +{ + + bool hasSeparateSwitches = Train->m_controlmapper.contains("pantvalvesupdate_bt:") && Train->m_controlmapper.contains("pantvalvesoff_bt:"); + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Command.action == GLFW_PRESS) + { + if (hasSeparateSwitches) + { + // implement action + Train->update_pantograph_valves(); + // visual feedback + Train->ggPantValvesUpdate.UpdateValue(1.0, Train->dsbSwitch); + } + + // Old logic to maintain compatibility + else + { + Train->update_pantograph_valves(); + Train->ggPantValvesButton.UpdateValue(1.0, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + // NOTE: pantvalves_sw: is a specialized button, with no toggle behavior support + if (hasSeparateSwitches) + Train->ggPantValvesUpdate.UpdateValue(0.5, Train->dsbSwitch); + + // Old logic to maintain compatibility + else + Train->ggPantValvesButton.UpdateValue(0.5, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_pantographvalvesoff(TTrain *Train, command_data const &Command) +{ + + bool hasSeparateSwitches = Train->m_controlmapper.contains("pantvalvesupdate_bt:") && Train->m_controlmapper.contains("pantvalvesoff_bt:"); + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Command.action == GLFW_PRESS) + { + // implement action + Train->mvOccupied->OperatePantographValve(end::front, operation_t::disable); + Train->mvOccupied->OperatePantographValve(end::rear, operation_t::disable); + // visual feedback + if (hasSeparateSwitches) + Train->ggPantValvesOff.UpdateValue(1.0, Train->dsbSwitch); + else + Train->ggPantValvesButton.UpdateValue(0.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + // NOTE: pantvalves_sw: is a speciali zed button, with no toggle behavior support + if (hasSeparateSwitches) + Train->ggPantValvesOff.UpdateValue(0.f, Train->dsbSwitch); + else + Train->ggPantValvesButton.UpdateValue(0.5, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_pantographcompressorvalvetoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only react to press + if (Train->mvControlled->bPantKurek3 == false) + { + // connect pantographs with primary tank + OnCommand_pantographcompressorvalveenable(Train, Command); + } + else + { + // connect pantograps with pantograph compressor + OnCommand_pantographcompressorvalvedisable(Train, Command); + } + } +} + +void TTrain::OnCommand_pantographcompressorvalveenable(TTrain *Train, command_data const &Command) +{ + + auto const valveispresent{Train->ggPantCompressorValve.SubModel != nullptr || (Train->mvOccupied == Train->mvPantographUnit && Train->iCabn == 0)}; + + if (false == valveispresent) + { + // tylko w maszynowym, unless actual device is present + return; + } + + if (Command.action == GLFW_PRESS) + { + // only react to press + // connect pantographs with primary tank + Train->mvControlled->bPantKurek3 = true; + // visual feedback: + Train->ggPantCompressorValve.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_pantographcompressorvalvedisable(TTrain *Train, command_data const &Command) +{ + + auto const valveispresent{Train->ggPantCompressorValve.SubModel != nullptr || (Train->mvOccupied == Train->mvPantographUnit && Train->iCabn == 0)}; + + if (false == valveispresent) + { + // tylko w maszynowym, unless actual device is present + return; + } + + if (Command.action == GLFW_PRESS) + { + // only react to press + // connect pantograps with pantograph compressor + Train->mvControlled->bPantKurek3 = false; + // visual feedback: + Train->ggPantCompressorValve.UpdateValue(1.0); + } +} + +void TTrain::OnCommand_pantographcompressoractivate(TTrain *Train, command_data const &Command) +{ + + // tylko w maszynowym, unless actual device is present + auto const switchispresent{Train->m_controlmapper.contains("pantcompressor_sw:") || (Train->mvOccupied == Train->mvPantographUnit && Train->iCabn == 0)}; + if (false == switchispresent) + { + return; + } + + if (Command.action != GLFW_RELEASE) + { + // press or hold to activate + if (Train->mvPantographUnit->PantPress < 4.8 && true == Train->mvPantographUnit->Power24vIsAvailable) + { + // needs live power source and low enough pressure to work + Train->mvPantographUnit->PantCompFlag = true; + } + // visual feedback + Train->ggPantCompressorButton.UpdateValue(1.0); + } + else + { + // release to disable + Train->mvPantographUnit->PantCompFlag = false; + // visual feedback + Train->ggPantCompressorButton.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_linebreakertoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // press or hold... + if (Train->m_linebreakerstate == 0) + { + // ...to close the circuit + // NOTE: bit of a dirty shortcut here + OnCommand_linebreakerclose(Train, Command); + } + else if (Train->m_linebreakerstate == 1) + { + // ...to open the circuit + OnCommand_linebreakeropen(Train, Command); + } + } + else if (Command.action == GLFW_RELEASE) + { + // release... + if (Train->ggMainOnButton.SubModel != nullptr || Train->ggMainButton.type() != TGaugeType::toggle) + { + // only impulse switches react to release events + // NOTE: we presume dedicated state switch is of impulse type + if (Train->m_linebreakerstate == 0) + { + // ...after opening circuit, or holding for too short time to close it + OnCommand_linebreakeropen(Train, Command); + } + else + { + // ...after closing the circuit + // NOTE: bit of a dirty shortcut here + OnCommand_linebreakerclose(Train, Command); + } + } + // HACK: ignition key ignores lack of submodel, so we can start vehicles without any modeled controls + Train->ggIgnitionKey.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_linebreakeropen(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // visual feedback + if (Train->ggMainOffButton.SubModel != nullptr) + { + Train->ggMainOffButton.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Train->ggMainButton.SubModel != nullptr) + { + Train->ggMainButton.UpdateValue(0.0, Train->dsbSwitch); + } + else if (Train->ggMainOnButton.SubModel != nullptr) + { + // NOTE: legacy behaviour, for vehicles equipped only with impulse close switch + // it doesn't make any real sense to animate this one, but some people can't get over how there's no visual reaction to their keypress + Train->ggMainOnButton.UpdateValue(1.0, Train->dsbSwitch); + return; + } + // play sound immediately when the switch is hit, not after release + Train->fMainRelayTimer = 0.0f; + + if (Train->m_linebreakerstate == 0) + { + return; + } // already in the desired state + + if (true == Train->mvControlled->MainSwitch(false)) + { + Train->m_linebreakerstate = 0; + } + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + // we don't exactly know which of the two buttons was used, so reset both + // for setup with two separate swiches + if (Train->ggMainOnButton.SubModel != nullptr) + { + Train->ggMainOnButton.UpdateValue(0.0, Train->dsbSwitch); + } + if (Train->ggMainOffButton.SubModel != nullptr) + { + Train->ggMainOffButton.UpdateValue(0.0, Train->dsbSwitch); + } + // and the two-state switch too, for good measure + if (Train->ggMainButton.SubModel != nullptr) + { + Train->ggMainButton.UpdateValue(Train->ggMainButton.type() != TGaugeType::toggle ? 0.5 : 0.0, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_linebreakerclose(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // visual feedback + if (Train->ggMainOnButton.SubModel != nullptr) + { + // two separate switches to close and break the circuit + Train->ggMainOnButton.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Train->ggMainButton.SubModel != nullptr) + { + // single two-state switch + Train->ggMainButton.UpdateValue(1.0, Train->dsbSwitch); + } + else + { + // no switch capable of doing the job + // HACK: ignition key ignores lack of submodel, so we can start vehicles without any modeled controls + Train->ggIgnitionKey.UpdateValue(1.0); + return; + } + // the actual closing of the line breaker is handled in the train update routine + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + if (Train->ggMainOnButton.SubModel != nullptr) + { + // setup with two separate switches + Train->ggMainOnButton.UpdateValue(0.0, Train->dsbSwitch); + } + else if (Train->ggMainButton.SubModel != nullptr && Train->ggMainButton.type() != TGaugeType::toggle) + { + Train->ggMainButton.UpdateValue(0.5, Train->dsbSwitch); + } + + if (Train->m_linebreakerstate == 1) + { + return; + } // already in the desired state + + if (Train->m_linebreakerstate == 2 && Train->mvControlled->EngineType == TEngineType::ElectricSeriesMotor) + { + // we don't need to start the diesel twice, but the other types (with impulse switch setup) still need to be launched + // NOTE: this behaviour should depend on MainOnButton presence and type_delayed + // TODO: change it when/if vehicle definition files get their proper switch types + // try to finalize state change of the line breaker, set the state based on the outcome + Train->m_linebreakerstate = Train->mvControlled->MainSwitch(true) ? 1 : 0; + } + // on button release reset the closing timer + Train->fMainRelayTimer = 0.0f; + } +} + +void TTrain::OnCommand_convertertoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const overloadrelayisopen{(Train->Dynamic()->Mechanik != nullptr ? Train->Dynamic()->Mechanik->IsAnyConverterOverloadRelayOpen : Train->mvOccupied->ConvOvldFlag)}; + + if (Train->mvOccupied->ConvSwitchType != "impulse" ? Train->ggConverterButton.GetValue() < 0.5 : false == Train->mvOccupied->Power110vIsAvailable && false == overloadrelayisopen) + { + // turn on + OnCommand_converterenable(Train, Command); + } + else + { + // turn off + OnCommand_converterdisable(Train, Command); + } + } + else if (Command.action == GLFW_RELEASE && Train->mvOccupied->ConvSwitchType == "impulse") + { + // on button release... + // ...return switches to start position if applicable + Train->ggConverterButton.UpdateValue(0.0, Train->dsbSwitch); + Train->ggConverterOffButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_converterenable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggConverterButton.UpdateValue(1.0, Train->dsbSwitch); + + // impulse type switch has no effect if there's no power + // NOTE: this is most likely setup wrong, but the whole thing is smoke and mirrors anyway + if (Train->mvOccupied->ConvSwitchType != "impulse" || Train->mvControlled->Mains) + { + // won't start if the line breaker button is still held + Train->mvOccupied->ConverterSwitch(true); + } + } + else if (Command.action == GLFW_RELEASE) + { + // potentially reset impulse switch position, using shared code branch + OnCommand_convertertoggle(Train, Command); + } +} + +void TTrain::OnCommand_converterdisable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggConverterButton.UpdateValue(0.0, Train->dsbSwitch); + if (Train->ggConverterOffButton.SubModel != nullptr) + { + Train->ggConverterOffButton.UpdateValue(1.0, Train->dsbSwitch); + } + + Train->mvOccupied->ConverterSwitch(false); + } + else if (Command.action == GLFW_RELEASE) + { + // potentially reset impulse switch position, using shared code branch + OnCommand_convertertoggle(Train, Command); + } +} + +void TTrain::OnCommand_convertertogglelocal(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->ConverterStart == start_t::automatic) + { + // let the automatic thing do its automatic thing... + return; + } + if (Train->ggConverterLocalButton.SubModel == nullptr) + { + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->mvOccupied->ConverterAllowLocal && Train->ggConverterLocalButton.GetValue() < 0.5) + { + // turn on + // visual feedback + Train->ggConverterLocalButton.UpdateValue(1.0, Train->dsbSwitch); + // effect + Train->mvOccupied->ConverterAllowLocal = true; + /* + if( true == Train->mvControlled->ConverterSwitch( true, range::local ) ) { + side effects + control the compressor, if it's paired with the converter + if( Train->mvControlled->CompressorPower == 2 ) { + hunter-091012: tak jest poprawnie + Train->mvControlled->CompressorSwitch( true, range::local ); + } + } + */ + } + else + { + // turn off + // visual feedback + Train->ggConverterLocalButton.UpdateValue(0.0, Train->dsbSwitch); + // effect + Train->mvOccupied->ConverterAllowLocal = false; + /* + if( true == Train->mvControlled->ConverterSwitch( false, range::local ) ) { + side effects + control the compressor, if it's paired with the converter + if( Train->mvControlled->CompressorPower == 2 ) { + hunter-091012: tak jest poprawnie + Train->mvControlled->CompressorSwitch( false, range::local ); + } + if there's no (low voltage) power source left, drop pantographs + if( false == Train->mvControlled->Battery ) { + Train->mvControlled->PantFront( false, range::local ); + Train->mvControlled->PantRear( false, range::local ); + } + } + */ + } + } +} + +void TTrain::OnCommand_converteroverloadrelayreset(TTrain *Train, command_data const &Command) +{ + + if (Train->ggConverterFuseButton.SubModel == nullptr && Command.action == GLFW_PRESS) + { + WriteLog("Converter Overload Relay Reset button is missing, or wasn't defined"); + // return; + } + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggConverterFuseButton.UpdateValue(1.0, Train->dsbSwitch); + + Train->mvControlled->RelayReset(relay_t::primaryconverteroverload); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggConverterFuseButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_compressortoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const compressorisenabled{(Train->Dynamic()->Mechanik ? Train->Dynamic()->Mechanik->IsAnyCompressorEnabled : Train->mvOccupied->CompressorAllow)}; + + if (false == compressorisenabled) + { + // turn on + OnCommand_compressorenable(Train, Command); + } + else + { + // turn off + OnCommand_compressordisable(Train, Command); + } + } + /* + disabled because we don't have yet support for compressor switch type definition + else if( Command.action == GLFW_RELEASE ) { + on button release... + if( Train->mvOccupied->CompSwitchType == "impulse" ) { + ...return switches to start position if applicable + Train->ggCompressorButton.UpdateValue( 0.0, Train->dsbSwitch ); + Train->ggCompressorOffButton.UpdateValue( 0.0, Train->dsbSwitch ); + } + } + */ +} + +void TTrain::OnCommand_compressorenable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggCompressorButton.UpdateValue(1.0, Train->dsbSwitch); + + // impulse type switch has no effect if there's no power + // NOTE: this is most likely setup wrong, but the whole thing is smoke and mirrors anyway + // if( ( Train->mvOccupied->CompSwitchType != "impulse" ) + // || ( Train->mvControlled->Mains ) ) { + + Train->mvOccupied->CompressorSwitch(true); + // } + } + else if (Command.action == GLFW_RELEASE) + { + // potentially reset impulse switch position, using shared code branch + OnCommand_compressortoggle(Train, Command); + } +} + +void TTrain::OnCommand_compressordisable(TTrain *Train, command_data const &Command) +{ + + if (Train->mvControlled->CompressorPower >= 2) + { + return; + } + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggCompressorButton.UpdateValue(0.0, Train->dsbSwitch); + /* + if( Train->ggCompressorOffButton.SubModel != nullptr ) { + Train->ggCompressorOffButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + */ + Train->mvOccupied->CompressorSwitch(false); + } + else if (Command.action == GLFW_RELEASE) + { + // potentially reset impulse switch position, using shared code branch + OnCommand_compressortoggle(Train, Command); + } +} + +void TTrain::OnCommand_compressortogglelocal(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->CompressorPower >= 2) + { + return; + } + if (Train->ggCompressorLocalButton.SubModel == nullptr) + { + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->mvOccupied->CompressorAllowLocal) + { + // turn on + // visual feedback + Train->ggCompressorLocalButton.UpdateValue(1.0, Train->dsbSwitch); + // effect + Train->mvOccupied->CompressorAllowLocal = true; + } + else + { + // turn off + // visual feedback + Train->ggCompressorLocalButton.UpdateValue(0.0, Train->dsbSwitch); + // effect + Train->mvOccupied->CompressorAllowLocal = false; + } + } +} + +void TTrain::OnCommand_compressorpresetactivatenext(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->CompressorListPosNo == 0) + { + return; + } + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggCompressorListButton.type() == TGaugeType::push) + { + // impulse switch + if (Train->mvOccupied->CompressorListPosNo < Train->mvOccupied->CompressorListDefPos + 1) + { + return; + } + + Train->mvOccupied->ChangeCompressorPreset(Command.action == GLFW_PRESS ? Train->mvOccupied->CompressorListDefPos + 1 : Train->mvOccupied->CompressorListDefPos); + // visual feedback + Train->ggCompressorListButton.UpdateValue(Train->mvOccupied->CompressorListPos - 1, Train->dsbSwitch); + } + else + { + // multi-state switch + if (Command.action == GLFW_RELEASE) + { + return; + } + + if (Train->mvOccupied->CompressorListPos < Train->mvOccupied->CompressorListPosNo || true == Train->mvOccupied->CompressorListWrap) + { + // active light preset is stored as value in range 1-LigthPosNo + Train->mvOccupied->ChangeCompressorPreset(Train->mvOccupied->CompressorListPos < Train->mvOccupied->CompressorListPosNo ? Train->mvOccupied->CompressorListPos + 1 : 1); // wrap mode + // visual feedback + Train->ggCompressorListButton.UpdateValue(Train->mvOccupied->CompressorListPos - 1, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_compressorpresetactivateprevious(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->CompressorListPosNo == 0) + { + return; + } + if (Command.action != GLFW_PRESS) + { + return; + } // one change per key press + + if (Train->ggCompressorListButton.type() == TGaugeType::push) + { + // impulse switch toggles only between positions 'default' and 'default+1' + return; + } + + if (Train->mvOccupied->CompressorListPos > 1 || true == Train->mvOccupied->CompressorListWrap) + { + // active light preset is stored as value in range 1-LigthPosNo + Train->mvOccupied->ChangeCompressorPreset(Train->mvOccupied->CompressorListPos > 1 ? Train->mvOccupied->CompressorListPos - 1 : Train->mvOccupied->CompressorListPosNo); // wrap mode + + // visual feedback + if (Train->ggCompressorListButton.SubModel != nullptr) + { + Train->ggCompressorListButton.UpdateValue(Train->mvOccupied->CompressorListPos - 1, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_compressorpresetactivatedefault(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->CompressorListPosNo == 0) + { + return; + } + if (Command.action != GLFW_PRESS) + { + return; + } // one change per key press + + Train->mvOccupied->ChangeCompressorPreset(Train->mvOccupied->CompressorListDefPos); + + // visual feedback + if (Train->ggCompressorListButton.SubModel != nullptr) + { + Train->ggCompressorListButton.UpdateValue(Train->mvOccupied->CompressorListPos - 1, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_motorblowerstogglefront(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggMotorBlowersFrontButton.type() == TGaugeType::push) + { + // impulse switch + // currently there's no off button so we always try to turn it on + OnCommand_motorblowersenablefront(Train, Command); + } + else + { + // two-state switch + if (Command.action == GLFW_RELEASE) + { + return; + } + + if (false == Train->mvControlled->MotorBlowers[end::front].is_enabled) + { + // turn on + OnCommand_motorblowersenablefront(Train, Command); + } + else + { + // turn off + OnCommand_motorblowersdisablefront(Train, Command); + } + } +} + +void TTrain::OnCommand_motorblowersenablefront(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggMotorBlowersFrontButton.type() == TGaugeType::push) + { + // impulse switch + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggMotorBlowersFrontButton.UpdateValue(1.f, Train->dsbSwitch); + Train->mvControlled->MotorBlowersSwitch(true, end::front); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggMotorBlowersFrontButton.UpdateValue(0.f, Train->dsbSwitch); + Train->mvControlled->MotorBlowersSwitch(false, end::front); + } + } + else + { + // two-state switch, only cares about press events + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggMotorBlowersFrontButton.UpdateValue(1.f, Train->dsbSwitch); + Train->mvControlled->MotorBlowersSwitch(true, end::front); + Train->mvControlled->MotorBlowersSwitchOff(false, end::front); + } + } +} + +void TTrain::OnCommand_motorblowersdisablefront(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggMotorBlowersFrontButton.type() == TGaugeType::push) + { + // impulse switch + // currently there's no disable return type switch + return; + } + else + { + // two-state switch, only cares about press events + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggMotorBlowersFrontButton.UpdateValue(0.f, Train->dsbSwitch); + Train->mvControlled->MotorBlowersSwitch(false, end::front); + Train->mvControlled->MotorBlowersSwitchOff(true, end::front); + } + } +} + +void TTrain::OnCommand_motorblowerstogglerear(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggMotorBlowersRearButton.type() == TGaugeType::push) + { + // impulse switch + // currently there's no off button so we always try to turn it on + OnCommand_motorblowersenablerear(Train, Command); + } + else + { + // two-state switch + if (Command.action == GLFW_RELEASE) + { + return; + } + + if (false == Train->mvControlled->MotorBlowers[end::rear].is_enabled) + { + // turn on + OnCommand_motorblowersenablerear(Train, Command); + } + else + { + // turn off + OnCommand_motorblowersdisablerear(Train, Command); + } + } +} + +void TTrain::OnCommand_motorblowersenablerear(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggMotorBlowersRearButton.type() == TGaugeType::push) + { + // impulse switch + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggMotorBlowersRearButton.UpdateValue(1.f, Train->dsbSwitch); + Train->mvControlled->MotorBlowersSwitch(true, end::rear); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggMotorBlowersRearButton.UpdateValue(0.f, Train->dsbSwitch); + Train->mvControlled->MotorBlowersSwitch(false, end::rear); + } + } + else + { + // two-state switch, only cares about press events + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggMotorBlowersRearButton.UpdateValue(1.f, Train->dsbSwitch); + Train->mvControlled->MotorBlowersSwitch(true, end::rear); + Train->mvControlled->MotorBlowersSwitchOff(false, end::rear); + } + } +} + +void TTrain::OnCommand_motorblowersdisablerear(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggMotorBlowersRearButton.type() == TGaugeType::push) + { + // impulse switch + // currently there's no disable return type switch + return; + } + else + { + // two-state switch, only cares about press events + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggMotorBlowersRearButton.UpdateValue(0.f, Train->dsbSwitch); + Train->mvControlled->MotorBlowersSwitch(false, end::rear); + Train->mvControlled->MotorBlowersSwitchOff(true, end::rear); + } + } +} + +void TTrain::OnCommand_motorblowersdisableall(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + if (Train->ggMotorBlowersAllOffButton.type() == TGaugeType::push) + { + // impulse switch + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggMotorBlowersAllOffButton.UpdateValue(1.f, Train->dsbSwitch); + Train->mvControlled->MotorBlowersSwitchOff(true, end::front); + Train->mvControlled->MotorBlowersSwitchOff(true, end::rear); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggMotorBlowersAllOffButton.UpdateValue(0.f, Train->dsbSwitch); + Train->mvControlled->MotorBlowersSwitchOff(false, end::front); + Train->mvControlled->MotorBlowersSwitchOff(false, end::rear); + } + } + else + { + // two-state switch, only cares about press events + // NOTE: generally this switch doesn't come in two-state form + if (Command.action == GLFW_PRESS) + { + if (Train->ggMotorBlowersAllOffButton.GetDesiredValue() < 0.5f) + { + // switch is off, activate + Train->mvControlled->MotorBlowersSwitchOff(true, end::front); + Train->mvControlled->MotorBlowersSwitchOff(true, end::rear); + // visual feedback + Train->ggMotorBlowersRearButton.UpdateValue(1.f, Train->dsbSwitch); + } + else + { + // deactivate + Train->mvControlled->MotorBlowersSwitchOff(false, end::front); + Train->mvControlled->MotorBlowersSwitchOff(false, end::rear); + // visual feedback + Train->ggMotorBlowersRearButton.UpdateValue(0.f, Train->dsbSwitch); + } + } + } +} + +void TTrain::OnCommand_coolingfanstoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action != GLFW_PRESS) + { + return; + } + + Train->mvControlled->RVentForceOn = !Train->mvControlled->RVentForceOn; +} + +void TTrain::OnCommand_motorconnectorsopen(TTrain *Train, command_data const &Command) +{ + + // TODO: don't rely on presense of 3d model to determine presence of the switch + if (Train->ggStLinOffButton.SubModel == nullptr) + { + if (Command.action == GLFW_PRESS) + { + WriteLog("Open Motor Power Connectors button is missing, or wasn't defined"); + } + return; + } + // HACK: because we don't have modeled actual circuits this is a simplification of the real mechanics + // namely, pressing the button will flip it in the entire unit, which isn't exactly physically possible + if (Command.action == GLFW_PRESS) + { + // button works while it's held down but we can ignore repeats + if (false == Train->mvControlled->StLinSwitchOff) + { + // open the connectors + // visual feedback + Train->ggStLinOffButton.UpdateValue(1.0, Train->dsbSwitch); + + Train->mvControlled->StLinSwitchOff = true; + Train->set_paired_open_motor_connectors_button(true); + } + else + { + // potentially close the connectors + OnCommand_motorconnectorsclose(Train, Command); + } + } + else if (Command.action == GLFW_RELEASE && Train->mvControlled->StLinSwitchType != "toggle") + { + // button released + // default button type (impulse) ceases its work on button release + // visual feedback + Train->ggStLinOffButton.UpdateValue(0.0, Train->dsbSwitch); + + Train->mvControlled->StLinSwitchOff = false; + Train->set_paired_open_motor_connectors_button(false); + } +} + +void TTrain::OnCommand_motorconnectorsclose(TTrain *Train, command_data const &Command) +{ + + // TODO: don't rely on presense of 3d model to determine presence of the switch + if (Train->ggStLinOffButton.SubModel == nullptr) + { + if (Command.action == GLFW_PRESS) + { + WriteLog("Open Motor Power Connectors button is missing, or wasn't defined"); + } + return; + } + + if (Command.action == GLFW_PRESS) + { + if (Train->mvControlled->StLinSwitchType == "toggle") + { + // default type of button (impulse) has only one effect on press, but the toggle type can toggle the state + // visual feedback + Train->ggStLinOffButton.UpdateValue(0.0, Train->dsbSwitch); + } + + if (false == Train->mvControlled->StLinSwitchOff) + { + return; + } // already closed + + Train->mvControlled->StLinSwitchOff = false; + Train->set_paired_open_motor_connectors_button(false); + } +} + +void TTrain::OnCommand_motordisconnect(TTrain *Train, command_data const &Command) +{ + + if (Train->mvControlled->TrainType == dt_EZT ? Train->mvControlled != Train->mvOccupied : Train->iCabn != 0) + { + // tylko w maszynowym + return; + } + + if (Command.action == GLFW_PRESS) + { + Train->mvControlled->CutOffEngine(); + } +} + +void TTrain::OnCommand_motoroverloadrelaythresholdtoggle(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (true == Train->mvControlled->ShuntModeAllow ? false == Train->mvControlled->ShuntMode : false == Train->mvControlled->MotorOverloadRelayHighThreshold) + { + // turn on + OnCommand_motoroverloadrelaythresholdsethigh(Train, Command); + } + else + { + // turn off + OnCommand_motoroverloadrelaythresholdsetlow(Train, Command); + } + } +} + +void TTrain::OnCommand_motoroverloadrelaythresholdsetlow(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvControlled->CurrentSwitch(false); + // visual feedback + Train->ggMaxCurrentCtrl.UpdateValue(Train->mvControlled->MotorOverloadRelayHighThreshold ? 1 : 0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_motoroverloadrelaythresholdsethigh(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvControlled->CurrentSwitch(true); + // visual feedback + Train->ggMaxCurrentCtrl.UpdateValue(Train->mvControlled->MotorOverloadRelayHighThreshold ? 1 : 0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_motoroverloadrelayreset(TTrain *Train, command_data const &Command) +{ + + if (Train->ggFuseButton.SubModel == nullptr && Command.action == GLFW_PRESS) + { + WriteLog("Motor Overload Relay Reset button is missing, or wasn't defined"); + // return; + } + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggFuseButton.UpdateValue(1.0, Train->dsbSwitch); + + Train->mvControlled->FuseOn(); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggFuseButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_universalrelayreset(TTrain *Train, command_data const &Command) +{ + + auto const itemindex = static_cast(Command.command) - static_cast(user_command::universalrelayreset1); + auto &item = Train->ggRelayResetButtons[itemindex]; + + // NOTE: relay reset switches are impulse-only + if (Command.action == GLFW_PRESS) + { + Train->mvOccupied->UniversalResetButton(itemindex); + // visual feedback + item.UpdateValue(1.0); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + item.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_inverterenable(TTrain *Train, command_data const &Command) +{ + + auto itemindex = static_cast(Command.command) - static_cast(user_command::inverterenable1); + auto &item = Train->ggInverterEnableButtons[itemindex]; + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + bool kier = Train->DynamicObject->DirectionGet() * Train->mvOccupied->CabOccupied > 0; + int flag = Train->DynamicObject->MoverParameters->InverterControlCouplerFlag; + TDynamicObject *p = Train->DynamicObject->GetFirstDynamic(Train->mvOccupied->CabOccupied < 0 ? end::rear : end::front, flag); + while (p) + { + if (p->MoverParameters->eimc[eimc_p_Pmax] > 1) + { + if (itemindex < p->MoverParameters->InvertersNo) + { + p->MoverParameters->Inverters[itemindex].Activate = true; + break; + } + else + { + itemindex -= p->MoverParameters->InvertersNo; + } + } + p = kier ? p->Next(flag) : p->Prev(flag); + } + // visual feedback + item.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + item.UpdateValue(0.0, Train->dsbSwitch); + } +}; + +void TTrain::OnCommand_inverterdisable(TTrain *Train, command_data const &Command) +{ + + auto itemindex = static_cast(Command.command) - static_cast(user_command::inverterdisable1); + auto &item = Train->ggInverterDisableButtons[itemindex]; + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + bool kier = Train->DynamicObject->DirectionGet() * Train->mvOccupied->CabOccupied > 0; + int flag = Train->DynamicObject->MoverParameters->InverterControlCouplerFlag; + TDynamicObject *p = Train->DynamicObject->GetFirstDynamic(Train->mvOccupied->CabOccupied < 0 ? end::rear : end::front, flag); + while (p) + { + if (p->MoverParameters->eimc[eimc_p_Pmax] > 1) + { + if (itemindex < p->MoverParameters->InvertersNo) + { + p->MoverParameters->Inverters[itemindex].Activate = false; + break; + } + else + { + itemindex -= p->MoverParameters->InvertersNo; + } + } + p = kier ? p->Next(flag) : p->Prev(flag); + } + // visual feedback + item.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) + { + // release + // visual feedback + item.UpdateValue(0.0, Train->dsbSwitch); + } +}; + +void TTrain::OnCommand_invertertoggle(TTrain *Train, command_data const &Command) +{ + + auto itemindex = static_cast(Command.command) - static_cast(user_command::invertertoggle1); + auto &item = Train->ggInverterToggleButtons[itemindex]; + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + bool kier = Train->DynamicObject->DirectionGet() * Train->mvOccupied->CabOccupied > 0; + int flag = Train->DynamicObject->MoverParameters->InverterControlCouplerFlag; + TDynamicObject *p = Train->DynamicObject->GetFirstDynamic(Train->mvOccupied->CabOccupied < 0 ? end::rear : end::front, flag); + while (p) + { + if (p->MoverParameters->eimc[eimc_p_Pmax] > 1) + { + if (itemindex < p->MoverParameters->InvertersNo) + { + p->MoverParameters->Inverters[itemindex].Activate = !p->MoverParameters->Inverters[itemindex].Activate; + // visual feedback + item.UpdateValue(p->MoverParameters->Inverters[itemindex].Activate ? 1.0 : 0.0, Train->dsbSwitch); + break; + } + else + { + itemindex -= p->MoverParameters->InvertersNo; + } + } + p = kier ? p->Next(flag) : p->Prev(flag); + } + } +}; diff --git a/vehicle/Train_Commands_Lights.cpp b/vehicle/Train_Commands_Lights.cpp new file mode 100644 index 00000000..e4cc64e8 --- /dev/null +++ b/vehicle/Train_Commands_Lights.cpp @@ -0,0 +1,1508 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "vehicle/Train.h" + +#include "simulation/simulation.h" +#include "world/Event.h" +#include "simulation/simulationtime.h" +#include "utilities/Logs.h" +#include "model/Model3d.h" +#include "vehicle/Driver.h" +#include "vehicle/DynObj.h" +#include "rendering/renderer.h" +#include +#include + +void TTrain::OnCommand_wiperswitchincrease(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + Train->mvOccupied->wiperSwitchPos++; + if (Train->mvOccupied->wiperSwitchPos > Train->mvOccupied->WiperListSize - 1) + Train->mvOccupied->wiperSwitchPos = Train->mvOccupied->WiperListSize - 1; + + // Visual feedback + Train->ggWiperSw.UpdateValue(Train->mvOccupied->wiperSwitchPos, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_wiperswitchdecrease(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + Train->mvOccupied->wiperSwitchPos--; + if (Train->mvOccupied->wiperSwitchPos < 0) + Train->mvOccupied->wiperSwitchPos = 0; + + // visual feedback + Train->ggWiperSw.UpdateValue(Train->mvOccupied->wiperSwitchPos, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_lightspresetactivatenext(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo == 0) + { + // no preset selector + return; + } + if (Command.action != GLFW_PRESS) + { + // one change per key press + return; + } + + if (Train->mvOccupied->LightsPos < Train->mvOccupied->LightsPosNo || true == Train->mvOccupied->LightsWrap) + { + // active light preset is stored as value in range 1-LigthPosNo + auto const restartcycle{Train->mvOccupied->LightsPos >= Train->mvOccupied->LightsPosNo}; + Train->mvOccupied->LightsPos = false == restartcycle ? Train->mvOccupied->LightsPos + 1 : 1; // wrap mode + + Train->Dynamic()->SetLights(); + // visual feedback + if (Train->ggLightsButton.SubModel != nullptr) + { + // HACK: skip submodel animation when restarting cycle, since it plays in the 'wrong' direction + if (false == restartcycle) + { + Train->ggLightsButton.UpdateValue(Train->mvOccupied->LightsPos - 1, Train->dsbSwitch); + } + else + { + Train->ggLightsButton.PutValue(Train->mvOccupied->LightsPos - 1); + } + } + } +} + +void TTrain::OnCommand_lightspresetactivateprevious(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo == 0) + { + // no preset selector + return; + } + if (Command.action != GLFW_PRESS) + { + // one change per key press + return; + } + + if (Train->mvOccupied->LightsPos > 1 || true == Train->mvOccupied->LightsWrap) + { + // active light preset is stored as value in range 1-LigthPosNo + auto const restartcycle{Train->mvOccupied->LightsPos <= 1}; + Train->mvOccupied->LightsPos = false == restartcycle ? Train->mvOccupied->LightsPos - 1 : Train->mvOccupied->LightsPosNo; // wrap mode + + Train->Dynamic()->SetLights(); + // visual feedback + if (Train->ggLightsButton.SubModel != nullptr) + { + // HACK: skip submodel animation when restarting cycle, since it plays in the 'wrong' direction + if (false == restartcycle) + { + Train->ggLightsButton.UpdateValue(Train->mvOccupied->LightsPos - 1, Train->dsbSwitch); + } + else + { + Train->ggLightsButton.PutValue(Train->mvOccupied->LightsPos - 1); + } + } + } +} + +void TTrain::OnCommand_headlighttoggleleft(TTrain *Train, command_data const &Command) +{ + + auto const vehicleend{Train->cab_to_end()}; + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_left) == 0) + { + // turn on + OnCommand_headlightenableleft(Train, Command); + } + else + { + // turn off + OnCommand_headlightdisableleft(Train, Command); + } + } +} + +void TTrain::OnCommand_lightsset(TTrain *Train, command_data const &Command) +{ + // set custom item in Lights inventory + Train->mvOccupied->Lights[end::front][17] = Command.param1; + Train->mvOccupied->Lights[end::rear][17] = Command.param2; + Train->mvOccupied->LightsPos = 18; // nasza custom pozycja + Train->Dynamic()->SetLights(); +} + +void TTrain::OnCommand_headlightenableleft(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggLeftLightButton.UpdateValue(1.0, Train->dsbSwitch); + // implementation + auto const vehicleend{Train->cab_to_end()}; + + if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_left) == 0) + { + Train->mvOccupied->iLights[vehicleend] ^= light::headlight_left; + } + // if the light is controlled by 3-way switch, disable marker light + if (Train->ggLeftEndLightButton.SubModel == nullptr) + { + Train->mvOccupied->iLights[vehicleend] &= ~light::redmarker_left; + } + } +} + +void TTrain::OnCommand_headlightdisableleft(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + int const vehicleend{Train->cab_to_end()}; + + if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_left) == 0) + { + return; + } // already disabled + + Train->mvOccupied->iLights[vehicleend] ^= light::headlight_left; + // visual feedback + Train->ggLeftLightButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_headlighttoggleright(TTrain *Train, command_data const &Command) +{ + + auto const vehicleend{Train->cab_to_end()}; + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_right) == 0) + { + // turn on + OnCommand_headlightenableright(Train, Command); + } + else + { + // turn off + OnCommand_headlightdisableright(Train, Command); + } + } +} + +void TTrain::OnCommand_headlightenableright(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggRightLightButton.UpdateValue(1.0, Train->dsbSwitch); + // implementation + auto const vehicleend{Train->cab_to_end()}; + + if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_right) == 0) + { + Train->mvOccupied->iLights[vehicleend] ^= light::headlight_right; + } + // if the light is controlled by 3-way switch, disable marker light + if (Train->ggRightEndLightButton.SubModel == nullptr) + { + Train->mvOccupied->iLights[vehicleend] &= ~light::redmarker_right; + } + } +} + +void TTrain::OnCommand_headlightdisableright(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const vehicleend{Train->cab_to_end()}; + + if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_right) == 0) + { + return; + } // already disabled + + Train->mvOccupied->iLights[vehicleend] ^= light::headlight_right; + // visual feedback + Train->ggRightLightButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_headlighttoggleupper(TTrain *Train, command_data const &Command) +{ + + auto const vehicleend{Train->cab_to_end()}; + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_upper) == 0) + { + // turn on + OnCommand_headlightenableupper(Train, Command); + } + else + { + // turn off + OnCommand_headlightdisableupper(Train, Command); + } + } +} + +void TTrain::OnCommand_headlightenableupper(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const vehicleend{Train->cab_to_end()}; + + if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_upper) != 0) + { + return; + } // already enabled + + Train->mvOccupied->iLights[vehicleend] ^= light::headlight_upper; + // visual feedback + Train->ggUpperLightButton.UpdateValue(1.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_headlightdisableupper(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const vehicleend{Train->cab_to_end()}; + + if ((Train->mvOccupied->iLights[vehicleend] & light::headlight_upper) == 0) + { + return; + } // already disabled + + Train->mvOccupied->iLights[vehicleend] ^= light::headlight_upper; + // visual feedback + Train->ggUpperLightButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_redmarkertoggleleft(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const vehicleend{Train->cab_to_end()}; + + if ((Train->mvOccupied->iLights[vehicleend] & light::redmarker_left) == 0) + { + // turn on + OnCommand_redmarkerenableleft(Train, Command); + } + else + { + // turn off + OnCommand_redmarkerdisableleft(Train, Command); + } + } +} + +void TTrain::OnCommand_redmarkerenableleft(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const vehicleend{Train->cab_to_end()}; + + if ((Train->mvOccupied->iLights[vehicleend] & light::redmarker_left) != 0) + { + return; + } // already enabled + + Train->mvOccupied->iLights[vehicleend] ^= light::redmarker_left; + // visual feedback + if (Train->ggLeftEndLightButton.SubModel != nullptr) + { + Train->ggLeftEndLightButton.UpdateValue(1.0, Train->dsbSwitch); + } + else + { + // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch + // this is crude, but for now will do + Train->ggLeftLightButton.UpdateValue(-1.0, Train->dsbSwitch); + // if the light is controlled by 3-way switch, disable the headlight + Train->mvOccupied->iLights[vehicleend] &= ~light::headlight_left; + } + } +} + +void TTrain::OnCommand_redmarkerdisableleft(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const vehicleend{Train->cab_to_end()}; + + if ((Train->mvOccupied->iLights[vehicleend] & light::redmarker_left) == 0) + { + return; + } // already disabled + + Train->mvOccupied->iLights[vehicleend] ^= light::redmarker_left; + // visual feedback + if (Train->ggLeftEndLightButton.SubModel != nullptr) + { + Train->ggLeftEndLightButton.UpdateValue(0.0, Train->dsbSwitch); + } + else + { + // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch + // this is crude, but for now will do + Train->ggLeftLightButton.UpdateValue(0.0, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_redmarkertoggleright(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const vehicleend{Train->cab_to_end()}; + + if ((Train->mvOccupied->iLights[vehicleend] & light::redmarker_right) == 0) + { + // turn on + OnCommand_redmarkerenableright(Train, Command); + } + else + { + // turn off + OnCommand_redmarkerdisableright(Train, Command); + } + } +} + +void TTrain::OnCommand_redmarkerenableright(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const vehicleend{Train->cab_to_end()}; + + if ((Train->mvOccupied->iLights[vehicleend] & light::redmarker_right) != 0) + { + return; + } // already enabled + + Train->mvOccupied->iLights[vehicleend] ^= light::redmarker_right; + // visual feedback + if (Train->ggRightEndLightButton.SubModel != nullptr) + { + Train->ggRightEndLightButton.UpdateValue(1.0, Train->dsbSwitch); + } + else + { + // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch + // this is crude, but for now will do + Train->ggRightLightButton.UpdateValue(-1.0, Train->dsbSwitch); + // if the light is controlled by 3-way switch, disable the headlight + Train->mvOccupied->iLights[vehicleend] &= ~light::headlight_right; + } + } +} + +void TTrain::OnCommand_redmarkerdisableright(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const vehicleend{Train->cab_to_end()}; + + if ((Train->mvOccupied->iLights[vehicleend] & light::redmarker_right) == 0) + { + return; + } // already disabled + + Train->mvOccupied->iLights[vehicleend] ^= light::redmarker_right; + // visual feedback + if (Train->ggRightEndLightButton.SubModel != nullptr) + { + Train->ggRightEndLightButton.UpdateValue(0.0, Train->dsbSwitch); + } + else + { + // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch + // this is crude, but for now will do + Train->ggRightLightButton.UpdateValue(0.0, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_headlighttogglerearleft(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc + auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_right) == 0) + { + OnCommand_headlightenablerearleft(Train, Command); + } + else + { + OnCommand_headlightdisablerearleft(Train, Command); + } + } +} + +void TTrain::OnCommand_headlightenablerearleft(TTrain *Train, command_data const &Command) +{ + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; + // already enabled + if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_right) == 0) + { + // turn on + Train->mvOccupied->iLights[vehicleotherend] ^= light::headlight_right; + // visual feedback + Train->ggRearLeftLightButton.UpdateValue(1.0, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_headlightdisablerearleft(TTrain *Train, command_data const &Command) +{ + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + if (Command.action == GLFW_PRESS) + { + auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; + // already disabled + if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_right) == 0) + { + return; + } + + // turn off + Train->mvOccupied->iLights[vehicleotherend] ^= light::headlight_right; + // visual feedback + Train->ggRearLeftLightButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_headlighttogglerearright(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc + auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_left) == 0) + { + OnCommand_headlightenablerearright(Train, Command); + } + else + { + OnCommand_headlightdisablerearright(Train, Command); + } + } +} + +void TTrain::OnCommand_headlightenablerearright(TTrain *Train, command_data const &Command) +{ + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc + auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; + + if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_left) == 0) + { + // turn on + Train->mvOccupied->iLights[vehicleotherend] ^= light::headlight_left; + // visual feedback + Train->ggRearRightLightButton.UpdateValue(1.0, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_headlightdisablerearright(TTrain *Train, command_data const &Command) +{ + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc + auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; + // already disabled + if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_left) == 0) + { + return; + } + + // turn off + Train->mvOccupied->iLights[vehicleotherend] ^= light::headlight_left; + // visual feedback + Train->ggRearRightLightButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_headlighttogglerearupper(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; + if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_upper) == 0) + { + OnCommand_headlightenablerearupper(Train, Command); + } + else + { + OnCommand_headlightdisablerearupper(Train, Command); + } + } +} + +void TTrain::OnCommand_headlightenablerearupper(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; + if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_upper) == 0) + { + // turn on + Train->mvOccupied->iLights[vehicleotherend] ^= light::headlight_upper; + // visual feedback + Train->ggRearUpperLightButton.UpdateValue(1.0, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_headlightdisablerearupper(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; + // already disabled? + if ((Train->mvOccupied->iLights[vehicleotherend] & light::headlight_upper) == 0) + { + return; + } + + // turn off + Train->mvOccupied->iLights[vehicleotherend] ^= light::headlight_upper; + // visual feedback + Train->ggRearUpperLightButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_modernlightdimmerincrease(TTrain *Train, command_data const &Command) +{ + if (!Train->mvOccupied->enableModernDimmer) + return; // if modern dimmer is disabled, skip entire command + if (Command.action == GLFW_PRESS) + { + // update modern dimmer state + + auto &dimPos = Train->mvOccupied->modernDimmerPosition; + auto dimCount = Train->mvOccupied->dimPositions.size(); + if (dimPos + 1 < dimCount) + dimPos++; + else if (Train->mvOccupied->modernDimmerCanCycle) + dimPos = 0; // return to 0 + else + return; // już na minimum i nie można cyklicznie + // update lightning + // Train->Dynamic()->SetLights(); + Train->Dynamic()->SetLightDimmings(); + + // visual feedback + if (Train->ggModernLightDimSw.SubModel != nullptr) + Train->ggModernLightDimSw.UpdateValue(dimPos, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_modernlightdimmerdecrease(TTrain *Train, command_data const &Command) +{ + if (!Train->mvOccupied->enableModernDimmer) + return; // jeśli dimmer jest wyłączony, olewamy + + if (Command.action == GLFW_PRESS) + { + auto &dimPos = Train->mvOccupied->modernDimmerPosition; + auto dimCount = Train->mvOccupied->dimPositions.size(); + + if (dimCount == 0) + return; + + if (dimPos > 0) + dimPos--; + else if (Train->mvOccupied->modernDimmerCanCycle) + dimPos = static_cast(dimCount - 1); // ostatnia pozycja + else + return; // już na minimum i nie można cyklicznie + + // Train->Dynamic()->SetLights(); + Train->Dynamic()->SetLightDimmings(); + + if (Train->ggModernLightDimSw.SubModel != nullptr) + Train->ggModernLightDimSw.UpdateValue(dimPos, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_redmarkertogglerearleft(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc + auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if ((Train->mvOccupied->iLights[vehicleotherend] & light::redmarker_right) == 0) + { + OnCommand_redmarkerenablerearleft(Train, Command); + } + else + { + OnCommand_redmarkerdisablerearleft(Train, Command); + } + } +} + +void TTrain::OnCommand_redmarkerenablerearleft(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc + auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; + if ((Train->mvOccupied->iLights[vehicleotherend] & light::redmarker_right) == 0) + { + // turn on + Train->mvOccupied->iLights[vehicleotherend] ^= light::redmarker_right; + // visual feedback + Train->ggRearLeftEndLightButton.UpdateValue(1.0, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_redmarkerdisablerearleft(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc + auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; + if ((Train->mvOccupied->iLights[vehicleotherend] & light::redmarker_right) == 0) + { + return; + } + // turn off + Train->mvOccupied->iLights[vehicleotherend] ^= light::redmarker_right; + // visual feedback + Train->ggRearLeftEndLightButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_redmarkertogglerearright(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc + auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if ((Train->mvOccupied->iLights[vehicleotherend] & light::redmarker_left) == 0) + { + OnCommand_redmarkerenablerearright(Train, Command); + } + else + { + OnCommand_redmarkerdisablerearright(Train, Command); + } + } +} + +void TTrain::OnCommand_redmarkerenablerearright(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc + auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; + if ((Train->mvOccupied->iLights[vehicleotherend] & light::redmarker_left) == 0) + { + // turn on + Train->mvOccupied->iLights[vehicleotherend] ^= light::redmarker_left; + // visual feedback + Train->ggRearRightEndLightButton.UpdateValue(1.0, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_redmarkerdisablerearright(TTrain *Train, command_data const &Command) +{ + + if (Train->mvOccupied->LightsPosNo > 0) + { + // lights are controlled by preset selector + return; + } + + if (Command.action == GLFW_PRESS) + { + // NOTE: we toggle the light on opposite side, as 'rear right' is 'front left' on the rear end etc + auto const vehicleotherend{(Train->cab_to_end() == end::front ? end::rear : end::front)}; + if ((Train->mvOccupied->iLights[vehicleotherend] & light::redmarker_left) == 0) + { + return; + } + // turn off + Train->mvOccupied->iLights[vehicleotherend] ^= light::redmarker_left; + // visual feedback + Train->ggRearRightEndLightButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_redmarkerstoggle(TTrain *Train, command_data const &Command) +{ + + if (true == Command.freefly && Command.action == GLFW_PRESS) + { + + auto *vehicle{std::get(simulation::Region->find_vehicle(Command.location, 10, false, true))}; + + if (vehicle == nullptr) + { + return; + } + + auto locationHead = vehicle->HeadPosition() - glm::dvec3(Command.location); // TODO: Maybe command_data should be dvec3? + auto locationRear = vehicle->RearPosition() - glm::dvec3(Command.location); + int const CouplNr{std::clamp(vehicle->DirectionGet() * (glm::dot(locationHead, locationHead) > glm::dot(locationRear, locationRear) ? 1 : -1), 0, 1)}; // z [-1,1] zrobić [0,1] + + auto const lightset{light::redmarker_left | light::redmarker_right}; + + vehicle->MoverParameters->iLights[CouplNr] = false == TestFlag(vehicle->MoverParameters->iLights[CouplNr], lightset) ? + vehicle->MoverParameters->iLights[CouplNr] |= lightset : // turn signals on + vehicle->MoverParameters->iLights[CouplNr] ^= lightset; // turn signals off + } +} + +void TTrain::OnCommand_endsignalstoggle(TTrain *Train, command_data const &Command) +{ + + if (true == Command.freefly && Command.action == GLFW_PRESS) + { + + auto *vehicle{std::get(simulation::Region->find_vehicle(Command.location, 10, false, true))}; + + if (vehicle == nullptr) + { + return; + } + int const CouplNr{ + std::clamp(vehicle->DirectionGet() * (glm::length2(vehicle->HeadPosition() - glm::dvec3(Command.location)) > glm::length2(vehicle->RearPosition() - glm::dvec3(Command.location)) ? 1 : -1), + 0, 1)}; // z [-1,1] zrobić [0,1] + + auto const lightset{light::rearendsignals}; + + vehicle->MoverParameters->iLights[CouplNr] = false == TestFlag(vehicle->MoverParameters->iLights[CouplNr], lightset) ? + vehicle->MoverParameters->iLights[CouplNr] |= lightset : // turn signals on + vehicle->MoverParameters->iLights[CouplNr] ^= lightset; // turn signals off + } +} + +void TTrain::OnCommand_headlightsdimtoggle(TTrain *Train, command_data const &Command) +{ + if (Train->DynamicObject->MoverParameters->enableModernDimmer) + return; + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (Train->DynamicObject->MoverParameters->modernDimmerPosition == 0) + { + // turn on + OnCommand_headlightsdimenable(Train, Command); + } + else + { + // turn off + OnCommand_headlightsdimdisable(Train, Command); + } + } +} + +void TTrain::OnCommand_headlightsdimenable(TTrain *Train, command_data const &Command) +{ + + if (Train->DynamicObject->MoverParameters->enableModernDimmer) + return; + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (Train->ggDimHeadlightsButton.SubModel != nullptr) + { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + // visual feedback + Train->ggDimHeadlightsButton.UpdateValue(1.0, Train->dsbSwitch); + } + + /* to jest stara logika + if (true == Train->DynamicObject->DimHeadlights) + { + return; + } already enabled + + Train->DynamicObject->DimHeadlights = true; + */ + Train->DynamicObject->MoverParameters->modernDimmerPosition = 1; // ustawiamy modern dimmer na flage przyciemnienia + Train->DynamicObject->SetLightDimmings(); + } +} + +void TTrain::OnCommand_headlightsdimdisable(TTrain *Train, command_data const &Command) +{ + + if (Train->DynamicObject->MoverParameters->enableModernDimmer) // nie wiem dlaczego to tak dziala ze jest odwrocona logika + return; + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (Train->ggDimHeadlightsButton.SubModel != nullptr) + { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + // visual feedback + Train->ggDimHeadlightsButton.UpdateValue(0.0, Train->dsbSwitch); + } + + /* stara logika przyciemniania + if( false == Train->DynamicObject->DimHeadlights ) { return; } already enabled + + Train->DynamicObject->DimHeadlights = false; + + */ + Train->DynamicObject->MoverParameters->modernDimmerPosition = 0; // ustawiamy modern dimmer na flage rozjasnienia + Train->DynamicObject->SetLightDimmings(); + } +} + +void TTrain::OnCommand_interiorlighttoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->Cabine[Train->iCabn].bLight) + { + // turn on + OnCommand_interiorlightenable(Train, Command); + } + else + { + // turn off + OnCommand_interiorlightdisable(Train, Command); + } + } +} + +void TTrain::OnCommand_interiorlightenable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->m_controlmapper.contains("cablight_sw:")) + { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog("Interior Light switch is missing, or wasn't defined"); + return; + } + // store lighting switch states + if (false == Train->DynamicObject->JointCabs) + { + // vehicles with separate cabs get separate lighting switch states + Train->Cabine[Train->iCabn].bLight = true; + } + else + { + // joint virtual cabs share lighting switch states + for (auto &cab : Train->Cabine) + { + cab.bLight = true; + } + } + } +} + +void TTrain::OnCommand_interiorlightdisable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->m_controlmapper.contains("cablight_sw:")) + { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog("Interior Light switch is missing, or wasn't defined"); + return; + } + // store lighting switch states + if (false == Train->DynamicObject->JointCabs) + { + // vehicles with separate cabs get separate lighting switch states + Train->Cabine[Train->iCabn].bLight = false; + } + else + { + // joint virtual cabs share lighting switch states + for (auto &cab : Train->Cabine) + { + cab.bLight = false; + } + } + } +} + +void TTrain::OnCommand_interiorlightdimtoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->Cabine[Train->iCabn].bLightDim) + { + // turn on + OnCommand_interiorlightdimenable(Train, Command); + } + else + { + // turn off + OnCommand_interiorlightdimdisable(Train, Command); + } + } +} + +void TTrain::OnCommand_interiorlightdimenable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (Train->ggCabLightDimButton.SubModel == nullptr) + { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog("Dim Interior Light switch is missing, or wasn't defined"); + return; + } + // visual feedback + Train->ggCabLightDimButton.UpdateValue(1.0, Train->dsbSwitch); + // store lighting switch states + if (false == Train->DynamicObject->JointCabs) + { + // vehicles with separate cabs get separate lighting switch states + Train->Cabine[Train->iCabn].bLightDim = true; + } + else + { + // joint virtual cabs share lighting switch states + for (auto &cab : Train->Cabine) + { + cab.bLightDim = true; + } + } + } +} + +void TTrain::OnCommand_interiorlightdimdisable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (Train->ggCabLightDimButton.SubModel == nullptr) + { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog("Dim Interior Light switch is missing, or wasn't defined"); + return; + } + // visual feedback + Train->ggCabLightDimButton.UpdateValue(0.0, Train->dsbSwitch); + // store lighting switch states + if (false == Train->DynamicObject->JointCabs) + { + // vehicles with separate cabs get separate lighting switch states + Train->Cabine[Train->iCabn].bLightDim = false; + } + else + { + // joint virtual cabs share lighting switch states + for (auto &cab : Train->Cabine) + { + cab.bLightDim = false; + } + } + } +} + +void TTrain::OnCommand_compartmentlightstoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_REPEAT) + { + return; + } + + // keep the switch from flipping back and forth if key is held down + if (false == Train->mvOccupied->CompartmentLights.is_active && false == Train->mvOccupied->CompartmentLights.is_enabled) + { + // turn on + OnCommand_compartmentlightsenable(Train, Command); + } + else + { + // turn off + OnCommand_compartmentlightsdisable(Train, Command); + } +} + +void TTrain::OnCommand_compartmentlightsenable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + Train->mvOccupied->CompartmentLightsSwitch(true); + if (Train->m_controlmapper.contains("compartmentlights_sw:")) + { + auto const istoggle{(static_cast(Train->ggCompartmentLightsButton.type()) & static_cast(TGaugeType::toggle)) != 0}; + if (istoggle) + { + Train->mvOccupied->CompartmentLightsSwitchOff(false); + } + } + // visual feedback + if (Train->m_controlmapper.contains("compartmentlights_sw:")) + { + Train->ggCompartmentLightsButton.UpdateValue(1.0f, Train->dsbSwitch); + } + if (Train->m_controlmapper.contains("compartmentlightson_sw:")) + { + Train->ggCompartmentLightsOnButton.UpdateValue(1.0f, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + if (Train->m_controlmapper.contains("compartmentlights_sw:") && Train->ggCompartmentLightsButton.type() == TGaugeType::push) + { + // return the switch to neutral position + Train->mvOccupied->CompartmentLightsSwitch(false); + Train->mvOccupied->CompartmentLightsSwitchOff(false); + Train->ggCompartmentLightsButton.UpdateValue(0.5f); + } + if (Train->m_controlmapper.contains("compartmentlightson_sw:")) + { + Train->mvOccupied->CompartmentLightsSwitch(false); + Train->ggCompartmentLightsOnButton.UpdateValue(0.0f, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_compartmentlightsdisable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + Train->mvOccupied->CompartmentLightsSwitchOff(true); + if (Train->m_controlmapper.contains("compartmentlights_sw:")) + { + auto const istoggle{(static_cast(Train->ggCompartmentLightsButton.type()) & static_cast(TGaugeType::toggle)) != 0}; + if (istoggle) + { + Train->mvOccupied->CompartmentLightsSwitch(false); + } + } + // visual feedback + if (Train->m_controlmapper.contains("compartmentlights_sw:")) + { + Train->ggCompartmentLightsButton.UpdateValue(0.0f, Train->dsbSwitch); + } + if (Train->m_controlmapper.contains("compartmentlightsoff_sw:")) + { + Train->ggCompartmentLightsOffButton.UpdateValue(1.0f, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + if (Train->m_controlmapper.contains("compartmentlights_sw:") && Train->ggCompartmentLightsButton.type() == TGaugeType::push) + { + // return the switch to neutral position + Train->mvOccupied->CompartmentLightsSwitch(false); + Train->mvOccupied->CompartmentLightsSwitchOff(false); + Train->ggCompartmentLightsButton.UpdateValue(0.5f); + } + if (Train->m_controlmapper.contains("compartmentlightsoff_sw:")) + { + Train->mvOccupied->CompartmentLightsSwitchOff(false); + Train->ggCompartmentLightsOffButton.UpdateValue(0.0f, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_instrumentlighttoggle(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (false == Train->InstrumentLightActive) + { + // turn on + OnCommand_instrumentlightenable(Train, Command); + } + else + { + // turn off + OnCommand_instrumentlightdisable(Train, Command); + } + } +} + +void TTrain::OnCommand_instrumentlightenable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (Train->ggInstrumentLightButton.SubModel == nullptr) + { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog("Instrument Light switch is missing, or wasn't defined"); + return; + } + // visual feedback + Train->ggInstrumentLightButton.UpdateValue(1.0, Train->dsbSwitch); + + if (true == Train->InstrumentLightActive) + { + return; + } // already enabled + + Train->InstrumentLightActive = true; + } +} + +void TTrain::OnCommand_instrumentlightdisable(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (Train->ggInstrumentLightButton.SubModel == nullptr) + { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog("Instrument Light switch is missing, or wasn't defined"); + return; + } + // visual feedback + Train->ggInstrumentLightButton.UpdateValue(0.0, Train->dsbSwitch); + + if (false == Train->InstrumentLightActive) + { + return; + } // already disabled + + Train->InstrumentLightActive = false; + } +} + +void TTrain::OnCommand_dashboardlighttoggle(TTrain *Train, command_data const &Command) +{ + if (false == Train->DashboardLightActive) + { + OnCommand_dashboardlightenable(Train, Command); + } + else + { + OnCommand_dashboardlightdisable(Train, Command); + } +} + +void TTrain::OnCommand_dashboardlightenable(TTrain *Train, command_data const &Command) +{ + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (Command.action != GLFW_PRESS) + { + return; + } + + if (Train->ggDashboardLightButton.SubModel == nullptr) + { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog("Dashboard Light switch is missing, or wasn't defined"); + return; + } + + if (false == Train->DashboardLightActive) + { + // turn on + Train->DashboardLightActive = true; + // visual feedback + Train->ggDashboardLightButton.UpdateValue(1.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_dashboardlightdisable(TTrain *Train, command_data const &Command) +{ + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (Command.action != GLFW_PRESS) + { + return; + } + + if (Train->ggDashboardLightButton.SubModel == nullptr) + { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog("Dashboard Light switch is missing, or wasn't defined"); + return; + } + + if (Train->DashboardLightActive) + { + // turn off + Train->DashboardLightActive = false; + // visual feedback + Train->ggDashboardLightButton.UpdateValue(0.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_timetablelighttoggle(TTrain *Train, command_data const &Command) +{ + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (Command.action != GLFW_PRESS) + { + return; + } + + if (false == Train->TimetableLightActive) + { + OnCommand_timetablelightenable(Train, Command); + } + else + { + OnCommand_timetablelightdisable(Train, Command); + } +} + +void TTrain::OnCommand_timetablelightenable(TTrain *Train, command_data const &Command) +{ + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (Command.action != GLFW_PRESS) + { + return; + } + + if (Train->ggTimetableLightButton.SubModel == nullptr) + { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog("Timetable Light switch is missing, or wasn't defined"); + return; + } + + if (false == Train->TimetableLightActive) + { + // turn on + Train->TimetableLightActive = true; + // visual feedback + Train->ggTimetableLightButton.UpdateValue(1.0, Train->dsbSwitch); + } +} + +void TTrain::OnCommand_timetablelightdisable(TTrain *Train, command_data const &Command) +{ + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if (Command.action != GLFW_PRESS) + { + return; + } + + if (Train->ggTimetableLightButton.SubModel == nullptr) + { + // TODO: proper control deviced definition for the interiors, that doesn't hinge of presence of 3d submodels + WriteLog("Timetable Light switch is missing, or wasn't defined"); + return; + } + if (Train->TimetableLightActive) + { + // turn off + Train->TimetableLightActive = false; + // visual feedback + Train->ggTimetableLightButton.UpdateValue(0.0, Train->dsbSwitch); + } +} diff --git a/vehicle/Train_Commands_Misc.cpp b/vehicle/Train_Commands_Misc.cpp new file mode 100644 index 00000000..eb4f096a --- /dev/null +++ b/vehicle/Train_Commands_Misc.cpp @@ -0,0 +1,211 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "vehicle/Train.h" + +#include "world/Event.h" +#include "simulation/simulationtime.h" +#include "model/Model3d.h" +#include "vehicle/Driver.h" +#include "vehicle/DynObj.h" +#include + +void TTrain::OnCommand_alerteracknowledge(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + // visual feedback + Train->ggSecurityResetButton.UpdateValue(1.0, Train->dsbSwitch); + + if (Train->mvOccupied->TrainType == dt_EZT || Train->mvOccupied->DirActive != 0) + Train->mvOccupied->SecuritySystem.acknowledge_press(); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggSecurityResetButton.UpdateValue(0.0); + + if (Train->mvOccupied->TrainType == dt_EZT || Train->mvOccupied->DirActive != 0) + Train->mvOccupied->SecuritySystem.acknowledge_release(); + } +} + +void TTrain::OnCommand_cabsignalacknowledge(TTrain *Train, command_data const &Command) +{ + // TODO: visual feedback + if (Command.action == GLFW_PRESS) + { + if (Train->mvOccupied->SecuritySystem.has_separate_acknowledge()) + { + Train->mvOccupied->SecuritySystem.cabsignal_reset(); + Train->ggSHPResetButton.UpdateValue(1.0, Train->dsbSwitch); + } + } + else if (Command.action == GLFW_RELEASE) + { + Train->ggSHPResetButton.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_generictoggle(TTrain *Train, command_data const &Command) +{ + + auto const itemindex = static_cast(Command.command) - static_cast(user_command::generictoggle0); + auto &item = Train->ggUniversals[itemindex]; + /* + if( item.SubModel == nullptr ) { + if( Command.action == GLFW_PRESS ) { + WriteLog( "Train generic item " + std::to_string( itemindex ) + " is missing, or wasn't defined" ); + } + return; + } + */ + + if (Command.action == GLFW_PRESS) + { + + if (item.type() == TGaugeType::push) + { + // impulse switch + // turn on + // visual feedback + item.UpdateValue(1.0); + } + else + { + // two-state switch + if (item.GetDesiredValue() < 0.5) + { + // turn on + // visual feedback + item.UpdateValue(1.0); + } + else + { + // turn off + // visual feedback + item.UpdateValue(0.0); + } + } + } + else if (Command.action == GLFW_RELEASE && item.type() == TGaugeType::push) + { + + // impulse switch + // turn off + // visual feedback + item.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_cabchangeforward(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + auto const *owner{(Train->DynamicObject->ctOwner != nullptr ? Train->DynamicObject->ctOwner : Train->DynamicObject->Mechanik)}; + auto const movedirection{1}; + if (false == Train->CabChange(movedirection)) + { + auto const exitdirection{(movedirection > 0 ? end::front : end::rear)}; + if (TestFlag(Train->mvOccupied->Couplers[exitdirection].CouplingFlag, coupling::gangway)) + { + // przejscie do nastepnego pojazdu + auto *targetvehicle = exitdirection == end::front ? Train->DynamicObject->PrevConnected() : Train->DynamicObject->NextConnected(); + targetvehicle->MoverParameters->CabOccupied = Train->mvOccupied->Neighbours[exitdirection].vehicle_end ? -1 : 1; + Train->MoveToVehicle(targetvehicle); + } + } + // HACK: match consist door permit state with the preset in the active cab + if (Train->ggDoorPermitPresetButton.SubModel != nullptr) + { + Train->mvOccupied->ChangeDoorPermitPreset(0); + } + // HACK: update lights state + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->DynamicObject->SetLights(); + } + } +} + +void TTrain::OnCommand_cabchangebackward(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + auto const *owner{(Train->DynamicObject->ctOwner != nullptr ? Train->DynamicObject->ctOwner : Train->DynamicObject->Mechanik)}; + auto const movedirection{-1}; + if (false == Train->CabChange(movedirection)) + { + // current vehicle doesn't extend any farther in this direction, check if we there's one connected we can move to + auto const exitdirection{(movedirection > 0 ? end::front : end::rear)}; + if (TestFlag(Train->mvOccupied->Couplers[exitdirection].CouplingFlag, coupling::gangway)) + { + // przejscie do nastepnego pojazdu + auto *targetvehicle = exitdirection == end::front ? Train->DynamicObject->PrevConnected() : Train->DynamicObject->NextConnected(); + targetvehicle->MoverParameters->CabOccupied = Train->mvOccupied->Neighbours[exitdirection].vehicle_end ? -1 : 1; + Train->MoveToVehicle(targetvehicle); + } + } + // HACK: match consist door permit state with the preset in the active cab + if (Train->ggDoorPermitPresetButton.SubModel != nullptr) + { + Train->mvOccupied->ChangeDoorPermitPreset(0); + } + // HACK: update lights state + if (Train->mvOccupied->LightsPosNo > 0) + { + Train->DynamicObject->SetLights(); + } + } +} + +void TTrain::OnCommand_vehiclemoveforwards(TTrain *Train, const command_data &Command) +{ + if (Command.action == GLFW_RELEASE || !DebugModeFlag) + return; + + Train->DynamicObject->move_set(100.0); +} + +void TTrain::OnCommand_vehiclemovebackwards(TTrain *Train, const command_data &Command) +{ + if (Command.action == GLFW_RELEASE || !DebugModeFlag) + return; + + Train->DynamicObject->move_set(-100.0); +} + +void TTrain::OnCommand_vehicleboost(TTrain *Train, const command_data &Command) +{ + if (Command.action == GLFW_RELEASE || !DebugModeFlag) + return; + + double boost = Command.param1 != 0.0 ? Command.param1 : 2.78; + + if (Train->DynamicObject == nullptr) + { + return; + } + + auto *vehicle{Train->DynamicObject}; + while (vehicle) + { + vehicle->MoverParameters->V += vehicle->DirectionGet() * boost; + vehicle = vehicle->Next(); // pozostałe też + } + vehicle = Train->DynamicObject->Prev(); + while (vehicle) + { + vehicle->MoverParameters->V += vehicle->DirectionGet() * boost; + vehicle = vehicle->Prev(); // w drugą stronę też + } +} diff --git a/vehicle/Train_Commands_Radio.cpp b/vehicle/Train_Commands_Radio.cpp new file mode 100644 index 00000000..0c10fa70 --- /dev/null +++ b/vehicle/Train_Commands_Radio.cpp @@ -0,0 +1,382 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "vehicle/Train.h" + +#include "simulation/simulation.h" +#include "world/Event.h" +#include "simulation/simulationtime.h" +#include "utilities/Logs.h" +#include "model/Model3d.h" +#include "vehicle/Driver.h" +#include "vehicle/DynObj.h" +#include "rendering/renderer.h" +#include +#include + +void TTrain::OnCommand_hornlowactivate(TTrain *Train, command_data const &Command) +{ + + if (Train->ggHornButton.SubModel == nullptr && Train->ggHornLowButton.SubModel == nullptr) + { + if (Command.action == GLFW_PRESS) + { + WriteLog("Horn button is missing, or wasn't defined"); + } + return; + } + + if (Command.action == GLFW_PRESS) + { + // only need to react to press, sound will continue until stopped + if (false == TestFlag(Train->mvOccupied->WarningSignal, 1)) + { + // turn on + Train->mvOccupied->WarningSignal |= 1; + /* + if( true == TestFlag( Train->mvOccupied->WarningSignal, 2 ) ) { + low and high horn are treated as mutually exclusive + Train->mvControlled->WarningSignal &= ~2; + } + */ + // visual feedback + Train->ggHornButton.UpdateValue(-1.0); + Train->ggHornLowButton.UpdateValue(1.0); + } + } + else if (Command.action == GLFW_RELEASE) + { + // turn off + /* + NOTE: we turn off both low and high horn, due to unreliability of release event when shift key is involved + Train->mvOccupied->WarningSignal &= ~( 1 | 2 ); + */ + Train->mvOccupied->WarningSignal &= ~1; + // visual feedback + Train->ggHornButton.UpdateValue(0.0); + Train->ggHornLowButton.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_hornhighactivate(TTrain *Train, command_data const &Command) +{ + + if (Train->ggHornButton.SubModel == nullptr && Train->ggHornHighButton.SubModel == nullptr) + { + if (Command.action == GLFW_PRESS) + { + WriteLog("Horn button is missing, or wasn't defined"); + } + return; + } + + if (Command.action == GLFW_PRESS) + { + // only need to react to press, sound will continue until stopped + if (false == TestFlag(Train->mvOccupied->WarningSignal, 2)) + { + // turn on + Train->mvOccupied->WarningSignal |= 2; + /* + if( true == TestFlag( Train->mvOccupied->WarningSignal, 1 ) ) { + low and high horn are treated as mutually exclusive + Train->mvControlled->WarningSignal &= ~1; + } + */ + // visual feedback + Train->ggHornButton.UpdateValue(1.0); + Train->ggHornHighButton.UpdateValue(1.0); + } + } + else if (Command.action == GLFW_RELEASE) + { + // turn off + /* + NOTE: we turn off both low and high horn, due to unreliability of release event when shift key is involved + Train->mvOccupied->WarningSignal &= ~( 1 | 2 ); + */ + Train->mvOccupied->WarningSignal &= ~2; + // visual feedback + Train->ggHornButton.UpdateValue(0.0); + Train->ggHornHighButton.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_whistleactivate(TTrain *Train, command_data const &Command) +{ + + if (Train->ggWhistleButton.SubModel == nullptr) + { + if (Command.action == GLFW_PRESS) + { + WriteLog("Whistle button is missing, or wasn't defined"); + } + return; + } + + if (Command.action == GLFW_PRESS) + { + // only need to react to press, sound will continue until stopped + if (false == TestFlag(Train->mvOccupied->WarningSignal, 4)) + { + // turn on + Train->mvOccupied->WarningSignal |= 4; + // visual feedback + Train->ggWhistleButton.UpdateValue(1.0); + } + } + else if (Command.action == GLFW_RELEASE) + { + // turn off + Train->mvOccupied->WarningSignal &= ~4; + // visual feedback + Train->ggWhistleButton.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_radiotoggle(TTrain *Train, command_data const &Command) +{ + if (Command.action != GLFW_PRESS) + { + return; + } + + // NOTE: we ignore the lack of 3d model to allow system reset after receiving radio-stop signal + /* + if( false == Train->m_controlmapper.contains( "radio_sw:" ) ) { + return; + } + */ + // 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); + } +} + +void TTrain::OnCommand_radioenable(TTrain *Train, command_data const &Command) +{ + if (Command.action != GLFW_PRESS) + { + return; + } + + if (false == Train->mvOccupied->Radio) + { + Train->mvOccupied->Radio = true; + } +} + +void TTrain::OnCommand_radiodisable(TTrain *Train, command_data const &Command) +{ + if (Command.action != GLFW_PRESS) + { + return; + } + + if (Train->mvOccupied->Radio) + { + Train->mvOccupied->Radio = false; + } +} + +void TTrain::OnCommand_radiochannelincrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + command_data newCommand = Command; + newCommand.param1 = Train->RadioChannel() + 1; + OnCommand_radiochannelset(Train, newCommand); + + Train->ggRadioChannelNext.UpdateValue(1.0); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggRadioChannelNext.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_radiochanneldecrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + command_data newCommand = Command; + newCommand.param1 = Train->RadioChannel() - 1; + OnCommand_radiochannelset(Train, newCommand); + + Train->ggRadioChannelPrevious.UpdateValue(1.0); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggRadioChannelPrevious.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_radiochannelset(TTrain *Train, command_data const &Command) +{ + if (Command.action != GLFW_RELEASE) + { + // on press or hold + Train->RadioChannel() = std::clamp((int)Command.param1, 1, 10); + Train->ggRadioChannelSelector.UpdateValue(Train->RadioChannel() - 1); + } +} + +void TTrain::OnCommand_radiostopsend(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + if (true == Train->mvOccupied->Radio && (Train->mvOccupied->Power24vIsAvailable || Train->mvOccupied->Power110vIsAvailable)) + { + simulation::Region->RadioStop(Train->Dynamic()->GetPosition()); + } + // visual feedback + Train->ggRadioStop.UpdateValue(1.0); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggRadioStop.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_radiostopenable(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS && Train->ggRadioStop.GetValue() == 0) + { + if (true == Train->mvOccupied->Radio && (Train->mvOccupied->Power24vIsAvailable || Train->mvOccupied->Power110vIsAvailable)) + { + simulation::Region->RadioStop(Train->Dynamic()->GetPosition()); + } + // visual feedback + Train->ggRadioStop.UpdateValue(1.0); + } +} + +void TTrain::OnCommand_radiostopdisable(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS && Train->ggRadioStop.GetValue() > 0) + { + // visual feedback + Train->ggRadioStop.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_radiostoptest(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + if (Train->RadioChannel() == 10 && true == Train->mvOccupied->Radio && (Train->mvOccupied->Power24vIsAvailable || Train->mvOccupied->Power110vIsAvailable)) + { + Train->Dynamic()->RadioStop(); + } + // visual feedback + Train->ggRadioTest.UpdateValue(1.0); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggRadioTest.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_radiocall1send(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_PRESS) + { + if (Train->RadioChannel() != 10 && true == Train->mvOccupied->Radio && (Train->mvOccupied->Power24vIsAvailable || Train->mvOccupied->Power110vIsAvailable)) + { + simulation::Events.queue_receivers(radio_message::call1, Train->Dynamic()->GetPosition()); + } + // visual feedback + Train->ggRadioCall1.UpdateValue(1.0); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggRadioCall1.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_radiocall3send(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + if (Train->RadioChannel() != 10 && true == Train->mvOccupied->Radio && (Train->mvOccupied->Power24vIsAvailable || Train->mvOccupied->Power110vIsAvailable)) + { + simulation::Events.queue_receivers(radio_message::call3, Train->Dynamic()->GetPosition()); + } + // visual feedback + Train->ggRadioCall3.UpdateValue(1.0); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggRadioCall3.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_radiovolumeincrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + command_data newCommand = Command; + newCommand.param1 = Train->m_radiovolume + 0.125; + OnCommand_radiovolumeset(Train, newCommand); + Train->ggRadioVolumeNext.UpdateValue(1.0); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggRadioVolumeNext.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_radiovolumedecrease(TTrain *Train, command_data const &Command) +{ + + if (Command.action == GLFW_PRESS) + { + command_data newCommand = Command; + newCommand.param1 = Train->m_radiovolume - 0.125; + OnCommand_radiovolumeset(Train, newCommand); + Train->ggRadioVolumePrevious.UpdateValue(1.0); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggRadioVolumePrevious.UpdateValue(0.0); + } +} + +void TTrain::OnCommand_radiovolumeset(TTrain *Train, command_data const &Command) +{ + if (Command.action != GLFW_RELEASE) + { + // on press or hold + Train->m_radiovolume = std::clamp(Command.param1, 0.0, 1.0); + Train->ggRadioVolumeSelector.UpdateValue(Train->m_radiovolume); + audio::event_volume_change = true; + } +}