diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 6c618d1e..34650052 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1754,6 +1754,8 @@ class TMoverParameters bool HasCamshaft{false}; int DynamicBrakeType = 0; /*patrz dbrake_**/ int DynamicBrakeAmpmeters = 2; /*liczba amperomierzy przy hamowaniu ED*/ + bool SplitEDPneumaticBrake = false; /*czy hamulec ED i pneumatyczny pomocniczy są rozdzielone na osobne nastawniki*/ + int DynamicBrakeCtrlPosNo = 10; /*ilosc pozycji nastawnika hamulca ED (DBPN, domyslnie 10)*/ double DynamicBrakeRes = 5.8; /*rezystancja oporników przy hamowaniu ED*/ double DynamicBrakeRes1 = 5.8; /*rezystancja oporników przy hamowaniu ED - 1 tryb*/ double DynamicBrakeRes2 = 5.8; /*rezystancja oporników przy hamowaniu ED - 2 tryb*/ @@ -2030,6 +2032,7 @@ class TMoverParameters int ManualBrakePos = 0; /*nastawa hamulca recznego*/ double LocalBrakePosA = 0.0; /*nastawa hamulca pomocniczego*/ double LocalBrakePosAEIM = 0.0; /*pozycja hamulca pomocniczego ep dla asynchronicznych ezt*/ + double DynamicBrakeCtrlPos = 0.0; /*nastawa nastawnika hamulca elektrodynamicznego (0..1) - aktywne tylko gdy SplitEDPneumaticBrake*/ bool UniversalBrakeButtonActive[3] = {false, false, false}; /* brake button pressed */ /* int BrakeStatus = b_off; //0 - odham, 1 - ham., 2 - uszk., 4 - odluzniacz, 8 - antyposlizg, 16 - uzyte EP, 32 - pozycja R, 64 - powrot z R @@ -2380,6 +2383,12 @@ class TMoverParameters /*! ABu 010205: - skrajne polozenia ham. pomocniczego*/ bool IncManualBrakeLevel(int CtrlSpeed); bool DecManualBrakeLevel(int CtrlSpeed); + /*! oddzielny nastawnik hamulca elektrodynamicznego (gdy SplitEDPneumaticBrake)*/ + bool IncDynamicBrakeLevel(float const CtrlSpeed); + bool DecDynamicBrakeLevel(float const CtrlSpeed); + bool DynamicBrakeLevelSet(double Position); + double DynamicBrakeRatio(void) const; + bool DynamicBrakeAvailable(void) const; /*czy ED dostepny w aktualnym oknie predkosci Vh0..Vh1*/ bool DynamicBrakeSwitch(bool Switch); bool RadiostopSwitch(bool Switch); bool AlarmChainSwitch(bool const State); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index a8abecc7..fe99e7d6 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -3882,6 +3882,79 @@ bool TMoverParameters::DecLocalBrakeLevel(float const CtrlSpeed) return DBL; } +// ************************************************************************************************* +// zwiększenie nastawy nastawnika hamulca elektrodynamicznego (DynamicBrakeCtrl) +// uzywane gdy SplitEDPneumaticBrake = true +// ************************************************************************************************* +bool TMoverParameters::IncDynamicBrakeLevel(float const CtrlSpeed) +{ + if (false == SplitEDPneumaticBrake) + return false; + if (DynamicBrakeCtrlPosNo < 1) + return false; + if (DynamicBrakeCtrlPos < 1.0) + { + DynamicBrakeCtrlPos = std::min(1.0, DynamicBrakeCtrlPos + (double)CtrlSpeed / (double)DynamicBrakeCtrlPosNo); + return true; + } + return false; +} + +// ************************************************************************************************* +// zmniejszenie nastawy nastawnika hamulca elektrodynamicznego (DynamicBrakeCtrl) +// ************************************************************************************************* +bool TMoverParameters::DecDynamicBrakeLevel(float const CtrlSpeed) +{ + if (false == SplitEDPneumaticBrake) + return false; + if (DynamicBrakeCtrlPosNo < 1) + return false; + if (DynamicBrakeCtrlPos > 0.0) + { + DynamicBrakeCtrlPos = std::max(0.0, DynamicBrakeCtrlPos - (double)CtrlSpeed / (double)DynamicBrakeCtrlPosNo); + return true; + } + return false; +} + +// ************************************************************************************************* +// bezposrednie ustawienie nastawnika hamulca elektrodynamicznego (DynamicBrakeCtrl) +// ************************************************************************************************* +bool TMoverParameters::DynamicBrakeLevelSet(double Position) +{ + if (false == SplitEDPneumaticBrake) + return false; + DynamicBrakeCtrlPos = clamp(Position, 0.0, 1.0); + return true; +} + +// ************************************************************************************************* +// odczyt nastawy nastawnika hamulca elektrodynamicznego (DynamicBrakeCtrl) +// zwraca 0 jezeli SplitEDPneumaticBrake nie jest aktywne (dla zachowania starej logiki) +// ************************************************************************************************* +double TMoverParameters::DynamicBrakeRatio(void) const +{ + if (false == SplitEDPneumaticBrake) + return 0.0; + return clamp(DynamicBrakeCtrlPos, 0.0, 1.0); +} + +// ************************************************************************************************* +// czy hamulec ED jest aktualnie dostepny w oknie predkosci Vh0..Vh1 +// ************************************************************************************************* +bool TMoverParameters::DynamicBrakeAvailable(void) const +{ + double const vh0{eimc[eimc_p_Vh0]}; + double const vh1{eimc[eimc_p_Vh1]}; + if (vh1 <= 0.001) + { + // brak zdefiniowanej strefy - ED dziala zawsze + return true; + } + // strefa wylaczenia jest definiowana przez Vh0 (minimum); powyzej Vh0 ED dziala + return (Vel >= vh0); +} + // ************************************************************************************************* // Q: 20160711 // zwiększenie nastawy hamulca ręcznego @@ -4438,7 +4511,13 @@ void TMoverParameters::UpdatePipePressure(double dt) dpLocalValve = LocHandle->GetPF(std::max(lbpa, LocalBrakePosAEIM), Hamulec->GetBCP(), ScndPipePress, dt, 0); } else - dpLocalValve = LocHandle->GetPF(LocalBrakePosAEIM, Hamulec->GetBCP(), ScndPipePress, dt, 0); + { + // in EIM stock the pneumatic local brake is normally driven only by the MED algorithm + // (LocalBrakePosAEIM). When SplitEDPneumaticBrake is active the dedicated LocalBrake + // lever should apply pneumatic pressure on the locomotive directly, bypassing MED. + double lbpa = SplitEDPneumaticBrake ? LocalBrakePosA : 0.0; + dpLocalValve = LocHandle->GetPF(std::max(lbpa, LocalBrakePosAEIM), Hamulec->GetBCP(), ScndPipePress, dt, 0); + } LockPipe = PipePress < (LockPipe ? LockPipeOff : LockPipeOn); bool lock_new = (LockPipe && !UnlockPipe && (BrakeCtrlPosR > HandleUnlock)) || ((EmergencyCutsOffHandle) && (EmergencyValveFlow > 0)); // new simple codition based on .fiz @@ -6232,14 +6311,19 @@ double TMoverParameters::TractionForce(double dt) } double edBCP = Hamulec->GetEDBCP(); auto const localbrakeactive{(CabOccupied != 0) && (LocHandle->GetCP() > 0.25)}; + // gdy SplitEDPneumaticBrake jest aktywne, hamulec pomocniczy (LocalBrake) NIE wymusza + // zalaczenia hamulca elektrodynamicznego - ED jest sterowany wlasnym nastawnikiem + auto const dynbrakectrlactive{SplitEDPneumaticBrake && (DynamicBrakeRatio() > 0.01) && DynamicBrakeAvailable()}; + auto const localbrakeforED{SplitEDPneumaticBrake ? false : localbrakeactive}; if ((false == Doors.instances[side::left].is_closed) || (false == Doors.instances[side::right].is_closed) || (Doors.permit_needed && (Doors.instances[side::left].open_permit || Doors.instances[side::right].open_permit))) { DynamicBrakeFlag = true; } - else if (((edBCP < 0.25) && (false == localbrakeactive) && (AnPos < 0.01)) || ((edBCP < 0.25) && (ShuntModeAllow) && (LocalBrakePosA < 0.01))) + else if (((edBCP < 0.25) && (false == localbrakeforED) && (false == dynbrakectrlactive) && (AnPos < 0.01)) || + ((edBCP < 0.25) && (ShuntModeAllow) && (false == dynbrakectrlactive) && (LocalBrakePosA < 0.01))) DynamicBrakeFlag = false; - else if ((((BrakePress > 0.25) && (edBCP > 0.25) || localbrakeactive)) || (AnPos > 0.02)) + else if ((((BrakePress > 0.25) && (edBCP > 0.25) || localbrakeforED)) || (AnPos > 0.02) || dynbrakectrlactive) DynamicBrakeFlag = true; edBCP = Hamulec->GetEDBCP() * eimc[eimc_p_abed]; // stala napedu if ((DynamicBrakeFlag)) @@ -6266,8 +6350,21 @@ double TMoverParameters::TractionForce(double dt) } else { - PosRatio = -std::max(std::min(edBCP * 1.0 / MaxBrakePress[0], 1.0), AnPos) * std::max(0.0, std::min(1.0, (Vel - eimc[eimc_p_Vh0]) / (eimc[eimc_p_Vh1] - eimc[eimc_p_Vh0]))); - eimv[eimv_Fzad] = -std::min(1.0, std::max(LocalBrakeRatio(), edBCP / MaxBrakePress[0])); + // strefa wylaczenia ED (Vh0..Vh1) - mnoznik 0..1 zaleznie od predkosci + double const vhRamp = std::max(0.0, std::min(1.0, (Vel - eimc[eimc_p_Vh0]) / (eimc[eimc_p_Vh1] - eimc[eimc_p_Vh0]))); + if (SplitEDPneumaticBrake) + { + // w trybie split LocalBrake nie zaleca ED; uzywany jest DynamicBrakeCtrl + // oraz zwykle zapotrzebowanie z hamulca zespolonego (edBCP) + double const edLeverDemand = DynamicBrakeRatio(); + PosRatio = -std::max(std::max(edLeverDemand, std::min(edBCP / MaxBrakePress[0], 1.0)), AnPos) * vhRamp; + eimv[eimv_Fzad] = -std::min(1.0, std::max(edLeverDemand, edBCP / MaxBrakePress[0])); + } + else + { + PosRatio = -std::max(std::min(edBCP * 1.0 / MaxBrakePress[0], 1.0), AnPos) * vhRamp; + eimv[eimv_Fzad] = -std::min(1.0, std::max(LocalBrakeRatio(), edBCP / MaxBrakePress[0])); + } } tmp = 5; } @@ -7230,10 +7327,26 @@ void TMoverParameters::CheckEIMIC(double dt) { double offset = EIMCtrlAdditionalZeros ? 1.0 : 0.0; double multiplier = (EIMCtrlEmergency ? 1.0 : 0.0) + offset; + // gdy SplitEDPneumaticBrake jest wlaczone, sterowanie ujemne (hamowanie ED) bierzemy + // z osobnego nastawnika DynamicBrakeCtrl, a nie z hamulca pomocniczego (LocalBrake). + // Dodatkowo zapotrzebowanie ED jest ograniczone przez strefe Vh0..Vh1: powyzej Vh1 - pelny ED, + // pomiedzy Vh1 a Vh0 - liniowe zanikanie, ponizej Vh0 - zerowe (brak hamowania pneumatycznego + // jako uzupelnienia, poniewaz LocalBrake jest oddzielny i operuje wylacznie pneumatyka). + double brakeDemand = SplitEDPneumaticBrake ? DynamicBrakeRatio() : LocalBrakeRatio(); + if (SplitEDPneumaticBrake) + { + double const vh0 = eimc[eimc_p_Vh0]; + double const vh1 = eimc[eimc_p_Vh1]; + if (vh1 > vh0 + 0.001) + { + double const vhRamp = clamp((Vel - vh0) / (vh1 - vh0), 0.0, 1.0); + brakeDemand *= vhRamp; + } + } switch (EIMCtrlType) { case 0: - eimic = (LocalBrakeRatio() > 0.01 ? -LocalBrakeRatio() : eimic_analog > 0.01 ? eimic_analog : (double)MainCtrlPos / (double)MainCtrlPosNo); + eimic = (brakeDemand > 0.01 ? -brakeDemand : eimic_analog > 0.01 ? eimic_analog : (double)MainCtrlPos / (double)MainCtrlPosNo); if (EIMCtrlAdditionalZeros || EIMCtrlEmergency) { if (eimic > 0.001) @@ -7347,7 +7460,9 @@ void TMoverParameters::CheckEIMIC(double dt) eimic = 0; // shut off retarder if ((UniCtrlIntegratedBrakeCtrl == false) && (UniCtrlIntegratedLocalBrakeCtrl == false)) { - eimic = (LocalBrakeRatio() > 0.01 ? -LocalBrakeRatio() : eimic); + // w trybie SplitEDPneumaticBrake hamowanie ED przychodzi z osobnego nastawnika, + // LocalBrake operuje wylacznie pneumatycznym hamulcem lokomotywy + eimic = (brakeDemand > 0.01 ? -brakeDemand : eimic); } } if (LocHandleTimeTraxx) @@ -10707,6 +10822,18 @@ void TMoverParameters::LoadFIZ_Cntrl(std::string const &line) extract_value(DynamicBrakeAmpmeters, "DBAM", line, ""); } + // split ED/pneumatic brake control: when true the local brake operates only on the + // pneumatic locomotive cylinder while electrodynamic braking is commanded by a + // separate "dynamicbrakectrl" lever (or the negative range of jointctrl). + extract_value(SplitEDPneumaticBrake, "SplitEDPneumaticBrake", line, ""); + // number of stepped positions for the dedicated ED brake controller (default 10) + DynamicBrakeCtrlPosNo = 10; + extract_value(DynamicBrakeCtrlPosNo, "DBPN", line, ""); + if (DynamicBrakeCtrlPosNo < 1) + { + DynamicBrakeCtrlPosNo = 10; + } + extract_value(MainCtrlPosNo, "MCPN", line, ""); extract_value(ScndCtrlPosNo, "SCPN", line, ""); extract_value(ScndInMain, "SCIM", line, ""); diff --git a/application/application.cpp b/application/application.cpp index 5355b795..ba09bde9 100644 --- a/application/application.cpp +++ b/application/application.cpp @@ -319,6 +319,12 @@ int eu07_application::init(int Argc, char *Argv[]) return result; } + // configure the OS console according to Globals.ShowSystemConsole. + // must run AFTER init_settings (so the ini-loaded value is honoured) and + // BEFORE the first WriteLog below (so colored \033[...] sequences emitted + // by utilities/Logs.cpp land in a console with VT processing enabled). + init_console(); + WriteLog("Starting MaSzyna rail vehicle simulator (release: " + Global.asVersion + ")"); WriteLog("For online documentation and additional files refer to: http://eu07.pl"); WriteLog("Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, " @@ -978,6 +984,102 @@ void eu07_application::init_debug() #endif } +// Honours Globals.ShowSystemConsole (default: true). +// +// Windows: if the toggle is on, ensure a console is attached (allocate one when +// the binary was linked as the WINDOWS subsystem and none is inherited), then +// reopen the C stdio streams onto it and turn on ENABLE_VIRTUAL_TERMINAL_PROCESSING +// so the ANSI colour escapes used by utilities/Logs.cpp render correctly. +// If the toggle is off, hide the console window (or free an allocated one) so +// the GUI launches without a stray cmd window. +// +// Other platforms: no-op. stdout is the launching terminal (or already detached); +// hiding it on Linux/macOS would mean redirecting to /dev/null and is left to the +// user's shell (e.g. "./eu07 >/dev/null 2>&1"). +void eu07_application::init_console() +{ +#ifdef _WIN32 + HWND consoleWnd = ::GetConsoleWindow(); + const bool hadConsole = (consoleWnd != nullptr); + + if (Global.ShowSystemConsole) + { + if (!hadConsole) + { + // no console inherited (e.g. WINDOWS subsystem build, or launched + // detached) -- create one and wire stdio to it so printf in + // utilities/Logs.cpp actually reaches the user + if (::AllocConsole()) + { + FILE *fp = nullptr; + freopen_s(&fp, "CONOUT$", "w", stdout); + freopen_s(&fp, "CONOUT$", "w", stderr); + freopen_s(&fp, "CONIN$", "r", stdin); + // keep C++ streams in sync with the redirected C streams + std::ios::sync_with_stdio(true); + std::cout.clear(); + std::cerr.clear(); + std::clog.clear(); + std::cin.clear(); + consoleWnd = ::GetConsoleWindow(); + } + } + + // enable ANSI virtual-terminal processing so the colour escapes in + // utilities/Logs.cpp ("\033[1;37;41m...", "\033[32m...") render as + // colours instead of literal garbage on the conhost. + // + // IMPORTANT: do NOT rely on GetStdHandle(STD_OUTPUT_HANDLE). After + // AllocConsole + freopen_s the CRT may have rewired things, and on a + // console-subsystem build the std handle can also point to a redirected + // pipe/file rather than the actual console screen buffer -- in either + // case SetConsoleMode silently fails and the escape bytes leak through + // as text ("←[32m" etc). Open CONOUT$ directly to get the real screen + // buffer handle, then flip VT on it. + auto enable_vt = [](const char *devName) { + HANDLE h = ::CreateFileA( + devName, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, + OPEN_EXISTING, + 0, + nullptr); + if (h == INVALID_HANDLE_VALUE) + return; + DWORD mode = 0; + if (::GetConsoleMode(h, &mode)) + { + ::SetConsoleMode(h, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT); + } + ::CloseHandle(h); + }; + // CONOUT$ is the console's active screen buffer; enabling VT on it + // affects everything that ends up being written there, regardless of + // which FILE* / std handle the writer used + enable_vt("CONOUT$"); + + if (consoleWnd) + { + ::ShowWindow(consoleWnd, SW_SHOW); + // give the console a recognisable title + ::SetConsoleTitleA("MaSzyna log"); + } + } + else + { + // user wants no console window -- hide whatever we have + if (consoleWnd) + { + ::ShowWindow(consoleWnd, SW_HIDE); + } + // if we'd allocated one ourselves on a previous run path we'd FreeConsole here, + // but on first init the console (if any) was inherited from the launcher and + // belongs to it -- just hiding the window is the least-surprising behaviour + } +#endif +} + void eu07_application::init_files() { diff --git a/application/application.h b/application/application.h index d461a0c9..11415603 100644 --- a/application/application.h +++ b/application/application.h @@ -101,6 +101,7 @@ private: // methods bool needs_ogl() const; void init_debug(); + void init_console(); void init_files(); int init_settings( int Argc, char *Argv[] ); int init_locale(); diff --git a/gl/cubemap.cpp b/gl/cubemap.cpp index 1b8d71b9..ca0e6c08 100644 --- a/gl/cubemap.cpp +++ b/gl/cubemap.cpp @@ -17,11 +17,16 @@ gl::cubemap::~cubemap() void gl::cubemap::alloc(GLint format, int width, int height, GLenum components, GLenum type) { - glBindTexture(GL_TEXTURE_CUBE_MAP, *this); - for (GLuint tgt = GL_TEXTURE_CUBE_MAP_POSITIVE_X; tgt <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; tgt++) - glTexImage2D(tgt, 0, format, width, height, 0, components, type, nullptr); + glBindTexture(GL_TEXTURE_CUBE_MAP, *this); + for (GLuint tgt = GL_TEXTURE_CUBE_MAP_POSITIVE_X; tgt <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; tgt++) + glTexImage2D(tgt, 0, format, width, height, 0, components, type, nullptr); - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + // make the cubemap sample-complete with no mipmaps required. + // generate_mipmaps() will later override MIN_FILTER once mips actually exist. + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); } void gl::cubemap::bind(int unit) diff --git a/input/command.cpp b/input/command.cpp index 73d0b40b..dc4ff462 100644 --- a/input/command.cpp +++ b/input/command.cpp @@ -29,6 +29,13 @@ commanddescription_sequence Commands_descriptions = { {"mastercontrollerdecrease", command_target::vehicle, command_mode::oneoff}, {"mastercontrollerdecreasefast", command_target::vehicle, command_mode::oneoff}, {"mastercontrollerset", command_target::vehicle, command_mode::oneoff}, + + {"dynamicbrakecontrollerincrease", command_target::vehicle, command_mode::oneoff}, + {"dynamicbrakecontrollerdecrease", command_target::vehicle, command_mode::oneoff}, + {"dynamicbrakecontrollerset", command_target::vehicle, command_mode::oneoff}, + {"dynamicbrakecontrollerincreasefast", command_target::vehicle, command_mode::oneoff}, + {"dynamicbrakecontrollerdecreasefast", command_target::vehicle, command_mode::oneoff}, + {"secondcontrollerincrease", command_target::vehicle, command_mode::oneoff}, {"secondcontrollerincreasefast", command_target::vehicle, command_mode::oneoff}, {"secondcontrollerdecrease", command_target::vehicle, command_mode::oneoff}, @@ -409,6 +416,11 @@ std::unordered_map commandMap = { {"mastercontrollerdecrease", user_command::mastercontrollerdecrease}, {"mastercontrollerdecreasefast", user_command::mastercontrollerdecreasefast}, {"mastercontrollerset", user_command::mastercontrollerset}, + {"dynamicbrakecontrollerincrease", user_command::dynamicbrakecontrollerincrease}, + {"dynamicbrakecontrollerdecrease", user_command::dynamicbrakecontrollerdecrease}, + {"dynamicbrakecontrollerset", user_command::dynamicbrakecontrollerset}, + {"dynamicbrakecontrollerincreasefast", user_command::dynamicbrakecontrollerincreasefast}, + {"dynamicbrakecontrollerdecreasefast", user_command::dynamicbrakecontrollerdecreasefast}, {"secondcontrollerincrease", user_command::secondcontrollerincrease}, {"secondcontrollerincreasefast", user_command::secondcontrollerincreasefast}, {"secondcontrollerdecrease", user_command::secondcontrollerdecrease}, diff --git a/input/command.h b/input/command.h index 53c56d7e..b12063db 100644 --- a/input/command.h +++ b/input/command.h @@ -24,6 +24,11 @@ enum class user_command mastercontrollerdecrease, mastercontrollerdecreasefast, mastercontrollerset, + dynamicbrakecontrollerincrease, + dynamicbrakecontrollerdecrease, + dynamicbrakecontrollerset, + dynamicbrakecontrollerincreasefast, + dynamicbrakecontrollerdecreasefast, secondcontrollerincrease, secondcontrollerincreasefast, secondcontrollerdecrease, diff --git a/input/driverkeyboardinput.cpp b/input/driverkeyboardinput.cpp index 829185c9..48c8c1fc 100644 --- a/input/driverkeyboardinput.cpp +++ b/input/driverkeyboardinput.cpp @@ -32,6 +32,13 @@ driverkeyboard_input::default_bindings() { { user_command::mastercontrollerdecrease, {GLFW_KEY_KP_SUBTRACT, ""} }, { user_command::mastercontrollerdecreasefast, {GLFW_KEY_KP_SUBTRACT | keymodifier::shift, ""} }, // mastercontrollerset, + + { user_command::dynamicbrakecontrollerincrease, {GLFW_KEY_KP_3 | keymodifier::control, ""} }, + { user_command::dynamicbrakecontrollerdecrease, {GLFW_KEY_KP_9 | keymodifier::control, ""} }, + // mastercontrollerset, + { user_command::dynamicbrakecontrollerincreasefast, {GLFW_KEY_KP_3 | keymodifier::control | keymodifier::shift, ""} }, + { user_command::dynamicbrakecontrollerdecreasefast, {GLFW_KEY_KP_9 | keymodifier::control | keymodifier::shift, ""} }, + { user_command::secondcontrollerincrease, {GLFW_KEY_KP_DIVIDE, ""} }, { user_command::secondcontrollerincreasefast, {GLFW_KEY_KP_DIVIDE | keymodifier::shift, ""} }, { user_command::secondcontrollerdecrease, {GLFW_KEY_KP_MULTIPLY, ""} }, diff --git a/input/drivermouseinput.cpp b/input/drivermouseinput.cpp index 8324bd1c..8f96dc24 100644 --- a/input/drivermouseinput.cpp +++ b/input/drivermouseinput.cpp @@ -533,6 +533,9 @@ drivermouse_input::default_bindings() { { "mainctrl:", { user_command::mastercontrollerset, user_command::none } }, + { "dynamicbrakectrl:", { + user_command::dynamicbrakecontrollerset, + user_command::none } }, { "scndctrl:", { user_command::secondcontrollerset, user_command::none } }, diff --git a/scripting/PyInt.cpp b/scripting/PyInt.cpp index 1beacf39..9c9bb033 100644 --- a/scripting/PyInt.cpp +++ b/scripting/PyInt.cpp @@ -312,15 +312,37 @@ void python_taskqueue::exit() m_condition.notify_all(); // let them free up their shit before we proceed m_workers = {}; - // get rid of the leftover tasks - // with the workers dead we don't have to worry about concurrent access anymore - for (auto task : m_tasks.data) + // drop any pending render/upload tasks. the workers are joined at this + // point so the locks are strictly defensive, but they cost nothing and + // document intent. clearing the deque also actually releases the tasks, + // which the previous code did not do (cancel() is a no-op stub). { - task->cancel(); + std::lock_guard lock(m_tasks.mutex); + for (auto &task : m_tasks.data) + { + task->cancel(); + } + m_tasks.data.clear(); } - // take a bow + { + std::lock_guard lock(m_uploadtasks.mutex); + m_uploadtasks.data.clear(); + } + // reclaim cached python objects while the interpreter is still alive, + // so no Py_DECREF lands on a finalized interpreter during later teardown acquire_lock(); + for (auto &entry : m_renderers) + { + Py_XDECREF(entry.second); + } + m_renderers.clear(); + Py_XDECREF(m_stderr); + m_stderr = nullptr; + Py_XDECREF(m_main); + m_main = nullptr; + // take a bow Py_Finalize(); + m_initialized = false; } // adds specified task along with provided collection of data to the work queue. returns true on success @@ -518,8 +540,10 @@ void python_taskqueue::run(GLFWwindow *Context, rendertask_sequence &Tasks, uplo // TBD, TODO: add some idle time between tasks in case we're on a single thread cpu? } while (task != nullptr); // if there's nothing left to do wait until there is - // but check every now and then on your own to minimize potential deadlock situations - Condition.wait_for(std::chrono::seconds(5)); + // short timeout: notify_all() in exit() can race with the worker's + // transition into the wait, and the run loop also drives prompt + // shutdown checks + Condition.wait_for(std::chrono::milliseconds(250)); } // clean up thread state data PyEval_AcquireLock(); @@ -527,6 +551,12 @@ void python_taskqueue::run(GLFWwindow *Context, rendertask_sequence &Tasks, uplo PyThreadState_Clear(threadstate); PyThreadState_Delete(threadstate); PyEval_ReleaseLock(); + + // detach the GL context before the worker terminates; some drivers + // (NVIDIA on X11, certain Mesa/Wayland configs) hang in process teardown + // if a context is still current on a dying thread + if (Context) + glfwMakeContextCurrent(nullptr); } void python_taskqueue::update() diff --git a/shaders/envmapping.glsl b/shaders/envmapping.glsl index 019d742b..028f2e70 100644 --- a/shaders/envmapping.glsl +++ b/shaders/envmapping.glsl @@ -8,6 +8,14 @@ vec3 envmap_color( vec3 normal ) vec3 refvec = reflect(f_pos.xyz, normal); // view space refvec = vec3(inv_view * vec4(refvec, 0.0)); // world space vec3 envcolor = texture(envmap, refvec).rgb; + // Sanitize. The env cubemap can briefly contain NaN/Inf after a + // reflection-pass regeneration (m_empty_cubemap was bound during the + // face render and on NVIDIA can sample as undefined). Without this + // guard, a single bad texel propagates through env_reflection in + // apply_lights() and produces one-frame black flashes on glossy + // (esp. specgloss) surfaces. + if (any(isnan(envcolor)) || any(isinf(envcolor))) envcolor = vec3(0.0); + envcolor = max(envcolor, vec3(0.0)); #else vec3 envcolor = vec3(0.5); #endif @@ -21,8 +29,13 @@ vec3 envmap_color_lod(vec3 fragnormal, float lod) #if ENVMAP_ENABLED vec3 refvec = reflect(f_pos.xyz, fragnormal); // view space — matches envmap_color exactly refvec = vec3(inv_view * vec4(refvec, 0.0)); // world space — was missing - return textureLod(envmap, refvec, lod).rgb; + vec3 envcolor = textureLod(envmap, refvec, lod).rgb; + // See envmap_color() above — same NaN/Inf sanitize, also needed here + // because mipmap generation propagates a single NaN texel across the + // whole mip chain. + if (any(isnan(envcolor)) || any(isinf(envcolor))) envcolor = vec3(0.0); + return max(envcolor, vec3(0.0)); #else return vec3(0.5); // was vec3(0.0), match the non-LOD fallback #endif -} \ No newline at end of file +} diff --git a/shaders/tonemapping.glsl b/shaders/tonemapping.glsl index 27fff21b..152b3b7e 100644 --- a/shaders/tonemapping.glsl +++ b/shaders/tonemapping.glsl @@ -46,6 +46,17 @@ vec4 tonemap(vec4 x) // with pureWhite=1.0 it collapses to identity (L*(1+L)/(1+L) = L) and // just clips HDR>1.0 at the framebuffer -> washed-out / burnt look. // ACES gives a smooth highlight shoulder + slight toe contrast. - return FBOUT(vec4(ACESFilm(x.rgb), x.a)); + + // Last-line-of-defense sanitize. ACESFilm has the form + // (x*(a*x+b)) / (x*(c*x+d)+e) + // which maps NaN -> NaN and +Inf -> NaN (Inf/Inf). Either turns the + // pixel black after framebuffer clamp. A negative HDR input feeds a + // negative numerator/denominator and can produce non-physical output + // that also looks like a black flash. Clamp to a sensible range + // before the curve so a single bad upstream pixel can't escape. + vec3 hdr = x.rgb; + hdr = mix(hdr, vec3(0.0), vec3(any(isnan(hdr)) || any(isinf(hdr)))); + hdr = max(hdr, vec3(0.0)); + return FBOUT(vec4(ACESFilm(hdr), x.a)); //return FBOUT(vec4(reinhard(x.rgb), x.a)); } diff --git a/utilities/Globals.cpp b/utilities/Globals.cpp index bdb5caf9..23cf9ab9 100644 --- a/utilities/Globals.cpp +++ b/utilities/Globals.cpp @@ -1086,6 +1086,12 @@ bool global_settings::ConfigParseDebug(cParser& Parser, const std::string& token return true; } + if (token == "showsystemconsole") + { + ParseOne(Parser, ShowSystemConsole); + return true; + } + if (token == "shakefactor") { ParseOne(Parser, ShakingMultiplierBF); @@ -1516,6 +1522,7 @@ global_settings::export_as_text( std::ostream &Output ) const { export_as_text( Output, "fullphysics", FullPhysics ); export_as_text( Output, "debuglog", iWriteLogEnabled ); export_as_text( Output, "multiplelogs", MultipleLogs ); + export_as_text( Output, "showsystemconsole", ShowSystemConsole ); export_as_text( Output, "logs.filter", DisabledLogTypes ); Output << "mousescale " diff --git a/utilities/Globals.h b/utilities/Globals.h index a42f059c..be79e42e 100644 --- a/utilities/Globals.h +++ b/utilities/Globals.h @@ -86,6 +86,7 @@ struct global_settings { bool priorityLoadText3D{false}; // ladowanie T3D priorytetowo int iWriteLogEnabled{ 3 }; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów bool MultipleLogs{ false }; + bool ShowSystemConsole{ false }; // toggle visibility of the OS console window with log output unsigned int DisabledLogTypes{ 0 }; bool ParserLogIncludes{ true }; // simulation diff --git a/vehicle/DynObj.cpp b/vehicle/DynObj.cpp index 3c0272ea..504078c6 100644 --- a/vehicle/DynObj.cpp +++ b/vehicle/DynObj.cpp @@ -293,7 +293,7 @@ material_data::assign( std::string const &Replacableskin ) { // check for the pipe method first if( contains( Replacableskin, '|' ) ) { cParser nameparser( Replacableskin ); - nameparser.getTokens( 4, true, "|" ); + nameparser.getTokens( 4, false, "|" ); int skinindex = 0; std::string texturename; nameparser >> texturename; while( ( texturename != "" ) && ( skinindex < 4 ) ) { diff --git a/vehicle/Train.cpp b/vehicle/Train.cpp index e098dbe3..b79657f8 100644 --- a/vehicle/Train.cpp +++ b/vehicle/Train.cpp @@ -38,424 +38,450 @@ extern user_command command; } */ -void -control_mapper::clear() { +void control_mapper::clear() +{ - *this = control_mapper(); + *this = control_mapper(); } -void -control_mapper::insert( TGauge const &Gauge, std::string const &Label ) { +void control_mapper::insert(TGauge const &Gauge, std::string const &Label) +{ - if( Gauge.SubModel != nullptr ) { m_controlnames.emplace( Gauge.SubModel, Label ); } - if( Gauge.SubModelOn != nullptr ) { m_controlnames.emplace( Gauge.SubModelOn, Label ); } + if (Gauge.SubModel != nullptr) + { + m_controlnames.emplace(Gauge.SubModel, Label); + } + if (Gauge.SubModelOn != nullptr) + { + m_controlnames.emplace(Gauge.SubModelOn, Label); + } - m_names.emplace( Label ); + m_names.emplace(Label); } -std::string -control_mapper::find( TSubModel const *Control ) const { +std::string control_mapper::find(TSubModel const *Control) const +{ - auto const lookup = m_controlnames.find( Control ); - if( lookup != m_controlnames.end() ) { - return lookup->second; - } - else { - return ""; - } + auto const lookup = m_controlnames.find(Control); + if (lookup != m_controlnames.end()) + { + return lookup->second; + } + else + { + return ""; + } } -bool -control_mapper::contains( std::string const Control ) const { +bool control_mapper::contains(std::string const Control) const +{ - return ( m_names.find( Control ) != m_names.end() ); + return (m_names.find(Control) != m_names.end()); } -void TTrain::screen_entry::deserialize( cParser &Input ) { +void TTrain::screen_entry::deserialize(cParser &Input) +{ - while( true == deserialize_mapping( Input ) ) { - ; // all work done by while() - } + while (true == deserialize_mapping(Input)) + { + ; // all work done by while() + } } -bool TTrain::screen_entry::deserialize_mapping( cParser &Input ) { - // token can be a key or block end - auto const key { Input.getToken( true, "\n\r\t ,;[]" ) }; +bool TTrain::screen_entry::deserialize_mapping(cParser &Input) +{ + // token can be a key or block end + auto const key{Input.getToken(true, "\n\r\t ,;[]")}; - if( ( true == key.empty() ) || ( key == "}" ) ) { return false; } + if ((true == key.empty()) || (key == "}")) + { + return false; + } - if( key == "{" ) { - script = Input.getToken(); - } - else if( key == "target:" ) { - target = Input.getToken(); - } - else if (key == "updatetime:") { + if (key == "{") + { + script = Input.getToken(); + } + else if (key == "target:") + { + target = Input.getToken(); + } + else if (key == "updatetime:") + { updatetime = Input.getToken(); } - else if( key == "parameters:" ) { - parameters = dictionary_source( Input.getToken() ); - } - else { - // HACK: we expect this to be true only if the screen entry doesn't start with a { which means legacy configuration format - target = key; - script = Input.getToken(); - return false; - } + else if (key == "parameters:") + { + parameters = dictionary_source(Input.getToken()); + } + else + { + // HACK: we expect this to be true only if the screen entry doesn't start with a { which means legacy configuration format + target = key; + script = Input.getToken(); + return false; + } - return true; + return true; } void TCab::Load(cParser &Parser) { - // NOTE: clearing control tables here is bit of a crutch, imposed by current scheme of loading compartments anew on each cab change - ggList.clear(); - btList.clear(); + // NOTE: clearing control tables here is bit of a crutch, imposed by current scheme of loading compartments anew on each cab change + ggList.clear(); + btList.clear(); - std::string token; - Parser.getTokens(); - Parser >> token; - if (token == "cablight:") - { - Parser.getTokens( 9, false ); -/* - Parser - >> dimm.r - >> dimm.g - >> dimm.b - >> intlit.r - >> intlit.g - >> intlit.b - >> intlitlow.r - >> intlitlow.g - >> intlitlow.b; -*/ - Parser.getTokens(); Parser >> token; - } - CabPos1.x = std::stod( token ); - Parser.getTokens( 5, false ); - Parser - >> CabPos1.y - >> CabPos1.z - >> CabPos2.x - >> CabPos2.y - >> CabPos2.z; + std::string token; + Parser.getTokens(); + Parser >> token; + if (token == "cablight:") + { + Parser.getTokens(9, false); + /* + Parser + >> dimm.r + >> dimm.g + >> dimm.b + >> intlit.r + >> intlit.g + >> intlit.b + >> intlitlow.r + >> intlitlow.g + >> intlitlow.b; + */ + Parser.getTokens(); + Parser >> token; + } + CabPos1.x = std::stod(token); + Parser.getTokens(5, false); + Parser >> CabPos1.y >> CabPos1.z >> CabPos2.x >> CabPos2.y >> CabPos2.z; - bEnabled = true; - bOccupied = true; + bEnabled = true; + bOccupied = true; } TGauge &TCab::Gauge(int n) { // pobranie adresu obiektu aniomowanego ruchem -/* - if (n < 0) - { // rezerwacja wolnego - ggList[iGauges].Clear(); - return ggList + iGauges++; - } - else if (n < iGauges) - return ggList + n; - return NULL; -*/ - if( n < 0 ) { - ggList.emplace_back(); - return ggList.back(); - } - else { - return ggList[ n ]; - } + /* + if (n < 0) + { // rezerwacja wolnego + ggList[iGauges].Clear(); + return ggList + iGauges++; + } + else if (n < iGauges) + return ggList + n; + return NULL; + */ + if (n < 0) + { + ggList.emplace_back(); + return ggList.back(); + } + else + { + return ggList[n]; + } }; TButton &TCab::Button(int n) { // pobranie adresu obiektu animowanego wyborem 1 z 2 -/* - if (n < 0) - { // rezerwacja wolnego - return btList + iButtons++; - } - else if (n < iButtons) - return btList + n; - return NULL; -*/ - if( n < 0 ) { - btList.emplace_back(); - return btList.back(); - } - else { - return btList[ n ]; - } + /* + if (n < 0) + { // rezerwacja wolnego + return btList + iButtons++; + } + else if (n < iButtons) + return btList + n; + return NULL; + */ + if (n < 0) + { + btList.emplace_back(); + return btList.back(); + } + else + { + return btList[n]; + } }; -void TCab::Update( bool const Power ) +void TCab::Update(bool const Power) { // odczyt parametrów i ustawienie animacji submodelom - for( auto &gauge : ggList ) { - // animacje izometryczne - gauge.UpdateValue(); // odczyt parametru i przeliczenie na kąt - gauge.Update(); // ustawienie animacji - } + for (auto &gauge : ggList) + { + // animacje izometryczne + gauge.UpdateValue(); // odczyt parametru i przeliczenie na kąt + gauge.Update(); // ustawienie animacji + } - for( auto &button : btList ) { - // animacje dwustanowe - button.Update( Power ); // odczyt parametru i wybór submodelu - } + for (auto &button : btList) + { + // animacje dwustanowe + button.Update(Power); // odczyt parametru i wybór submodelu + } }; // NOTE: we're currently using universal handlers and static handler map but it may be beneficial to have these implemented on individual class instance basis // TBD, TODO: consider this approach if we ever want to have customized consist behaviour to received commands, based on the consist/vehicle type or whatever TTrain::commandhandler_map const TTrain::m_commandhandlers = { - { user_command::aidriverenable, &TTrain::OnCommand_aidriverenable }, - { user_command::aidriverdisable, &TTrain::OnCommand_aidriverdisable }, - { user_command::jointcontrollerset, &TTrain::OnCommand_jointcontrollerset }, - { user_command::mastercontrollerincrease, &TTrain::OnCommand_mastercontrollerincrease }, - { user_command::mastercontrollerincreasefast, &TTrain::OnCommand_mastercontrollerincreasefast }, - { user_command::mastercontrollerdecrease, &TTrain::OnCommand_mastercontrollerdecrease }, - { user_command::mastercontrollerdecreasefast, &TTrain::OnCommand_mastercontrollerdecreasefast }, - { user_command::mastercontrollerset, &TTrain::OnCommand_mastercontrollerset }, - { user_command::secondcontrollerincrease, &TTrain::OnCommand_secondcontrollerincrease }, - { user_command::secondcontrollerincreasefast, &TTrain::OnCommand_secondcontrollerincreasefast }, - { user_command::secondcontrollerdecrease, &TTrain::OnCommand_secondcontrollerdecrease }, - { user_command::secondcontrollerdecreasefast, &TTrain::OnCommand_secondcontrollerdecreasefast }, - { user_command::secondcontrollerset, &TTrain::OnCommand_secondcontrollerset }, - { user_command::notchingrelaytoggle, &TTrain::OnCommand_notchingrelaytoggle }, - { user_command::tempomattoggle, &TTrain::OnCommand_tempomattoggle }, - { user_command::mucurrentindicatorothersourceactivate, &TTrain::OnCommand_mucurrentindicatorothersourceactivate }, - { user_command::independentbrakeincrease, &TTrain::OnCommand_independentbrakeincrease }, - { user_command::independentbrakeincreasefast, &TTrain::OnCommand_independentbrakeincreasefast }, - { user_command::independentbrakedecrease, &TTrain::OnCommand_independentbrakedecrease }, - { user_command::independentbrakedecreasefast, &TTrain::OnCommand_independentbrakedecreasefast }, - { user_command::independentbrakeset, &TTrain::OnCommand_independentbrakeset }, - { user_command::independentbrakebailoff, &TTrain::OnCommand_independentbrakebailoff }, - { user_command::universalbrakebutton1, &TTrain::OnCommand_universalbrakebutton1 }, - { user_command::universalbrakebutton2, &TTrain::OnCommand_universalbrakebutton2 }, - { user_command::universalbrakebutton3, &TTrain::OnCommand_universalbrakebutton3 }, - { user_command::trainbrakeincrease, &TTrain::OnCommand_trainbrakeincrease }, - { user_command::trainbrakedecrease, &TTrain::OnCommand_trainbrakedecrease }, - { user_command::trainbrakeset, &TTrain::OnCommand_trainbrakeset }, - { user_command::trainbrakecharging, &TTrain::OnCommand_trainbrakecharging }, - { user_command::trainbrakerelease, &TTrain::OnCommand_trainbrakerelease }, - { user_command::trainbrakefirstservice, &TTrain::OnCommand_trainbrakefirstservice }, - { user_command::trainbrakeservice, &TTrain::OnCommand_trainbrakeservice }, - { user_command::trainbrakefullservice, &TTrain::OnCommand_trainbrakefullservice }, - { user_command::trainbrakehandleoff, &TTrain::OnCommand_trainbrakehandleoff }, - { user_command::trainbrakeemergency, &TTrain::OnCommand_trainbrakeemergency }, - { user_command::trainbrakebasepressureincrease, &TTrain::OnCommand_trainbrakebasepressureincrease }, - { user_command::trainbrakebasepressuredecrease, &TTrain::OnCommand_trainbrakebasepressuredecrease }, - { user_command::trainbrakebasepressurereset, &TTrain::OnCommand_trainbrakebasepressurereset }, - { user_command::trainbrakeoperationtoggle, &TTrain::OnCommand_trainbrakeoperationtoggle }, - { user_command::manualbrakeincrease, &TTrain::OnCommand_manualbrakeincrease }, - { user_command::manualbrakedecrease, &TTrain::OnCommand_manualbrakedecrease }, - { user_command::alarmchaintoggle, &TTrain::OnCommand_alarmchaintoggle }, - { user_command::alarmchainenable, &TTrain::OnCommand_alarmchainenable}, - { user_command::alarmchaindisable, &TTrain::OnCommand_alarmchaindisable}, - { user_command::wheelspinbrakeactivate, &TTrain::OnCommand_wheelspinbrakeactivate }, - { user_command::sandboxactivate, &TTrain::OnCommand_sandboxactivate }, - { user_command::autosandboxtoggle, &TTrain::OnCommand_autosandboxtoggle }, - { user_command::autosandboxactivate, &TTrain::OnCommand_autosandboxactivate }, - { user_command::autosandboxdeactivate, &TTrain::OnCommand_autosandboxdeactivate }, - { user_command::epbrakecontroltoggle, &TTrain::OnCommand_epbrakecontroltoggle }, - { user_command::epbrakecontrolenable, &TTrain::OnCommand_epbrakecontrolenable }, - { user_command::epbrakecontroldisable, &TTrain::OnCommand_epbrakecontroldisable }, - { user_command::trainbrakeoperationmodeincrease, &TTrain::OnCommand_trainbrakeoperationmodeincrease }, - { user_command::trainbrakeoperationmodedecrease, &TTrain::OnCommand_trainbrakeoperationmodedecrease }, - { user_command::brakeactingspeedincrease, &TTrain::OnCommand_brakeactingspeedincrease }, - { user_command::brakeactingspeeddecrease, &TTrain::OnCommand_brakeactingspeeddecrease }, - { user_command::brakeactingspeedsetcargo, &TTrain::OnCommand_brakeactingspeedsetcargo }, - { user_command::brakeactingspeedsetpassenger, &TTrain::OnCommand_brakeactingspeedsetpassenger }, - { user_command::brakeactingspeedsetrapid, &TTrain::OnCommand_brakeactingspeedsetrapid }, - { user_command::brakeloadcompensationincrease, &TTrain::OnCommand_brakeloadcompensationincrease }, - { user_command::brakeloadcompensationdecrease, &TTrain::OnCommand_brakeloadcompensationdecrease }, - { user_command::mubrakingindicatortoggle, &TTrain::OnCommand_mubrakingindicatortoggle }, - { user_command::reverserincrease, &TTrain::OnCommand_reverserincrease }, - { user_command::reverserdecrease, &TTrain::OnCommand_reverserdecrease }, - { user_command::reverserforwardhigh, &TTrain::OnCommand_reverserforwardhigh }, - { user_command::reverserforward, &TTrain::OnCommand_reverserforward }, - { user_command::reverserneutral, &TTrain::OnCommand_reverserneutral }, - { user_command::reverserbackward, &TTrain::OnCommand_reverserbackward }, - { user_command::alerteracknowledge, &TTrain::OnCommand_alerteracknowledge }, - { user_command::cabsignalacknowledge, &TTrain::OnCommand_cabsignalacknowledge }, - { user_command::batterytoggle, &TTrain::OnCommand_batterytoggle }, - { user_command::batteryenable, &TTrain::OnCommand_batteryenable }, - { user_command::batterydisable, &TTrain::OnCommand_batterydisable }, - { user_command::cabactivationtoggle, &TTrain::OnCommand_cabactivationtoggle }, - { user_command::cabactivationenable, &TTrain::OnCommand_cabactivationenable }, - { user_command::cabactivationdisable, &TTrain::OnCommand_cabactivationdisable }, - { user_command::pantographcompressorvalvetoggle, &TTrain::OnCommand_pantographcompressorvalvetoggle }, - { user_command::pantographcompressorvalveenable, &TTrain::OnCommand_pantographcompressorvalveenable }, - { user_command::pantographcompressorvalvedisable, &TTrain::OnCommand_pantographcompressorvalvedisable }, - { user_command::pantographcompressoractivate, &TTrain::OnCommand_pantographcompressoractivate }, - { user_command::pantographtogglefront, &TTrain::OnCommand_pantographtogglefront }, - { user_command::pantographtogglerear, &TTrain::OnCommand_pantographtogglerear }, - { user_command::pantographraisefront, &TTrain::OnCommand_pantographraisefront }, - { user_command::pantographraiserear, &TTrain::OnCommand_pantographraiserear }, - { user_command::pantographlowerfront, &TTrain::OnCommand_pantographlowerfront }, - { user_command::pantographlowerrear, &TTrain::OnCommand_pantographlowerrear }, + {user_command::aidriverenable, &TTrain::OnCommand_aidriverenable}, + {user_command::aidriverdisable, &TTrain::OnCommand_aidriverdisable}, + {user_command::jointcontrollerset, &TTrain::OnCommand_jointcontrollerset}, + {user_command::mastercontrollerincrease, &TTrain::OnCommand_mastercontrollerincrease}, + {user_command::mastercontrollerincreasefast, &TTrain::OnCommand_mastercontrollerincreasefast}, + {user_command::mastercontrollerdecrease, &TTrain::OnCommand_mastercontrollerdecrease}, + {user_command::mastercontrollerdecreasefast, &TTrain::OnCommand_mastercontrollerdecreasefast}, + {user_command::mastercontrollerset, &TTrain::OnCommand_mastercontrollerset}, + {user_command::secondcontrollerincrease, &TTrain::OnCommand_secondcontrollerincrease}, + {user_command::secondcontrollerincreasefast, &TTrain::OnCommand_secondcontrollerincreasefast}, + {user_command::secondcontrollerdecrease, &TTrain::OnCommand_secondcontrollerdecrease}, + {user_command::secondcontrollerdecreasefast, &TTrain::OnCommand_secondcontrollerdecreasefast}, + {user_command::secondcontrollerset, &TTrain::OnCommand_secondcontrollerset}, + {user_command::dynamicbrakecontrollerincrease, &TTrain::OnCommand_DynamicBrakeControllerIncrease}, + {user_command::dynamicbrakecontrollerincreasefast, &TTrain::OnCommand_DynamicBrakeControllerIncreaseFast}, + {user_command::dynamicbrakecontrollerdecrease, &TTrain::OnCommand_DynamicBrakeControllerDecrease}, + {user_command::dynamicbrakecontrollerdecreasefast, &TTrain::OnCommand_DynamicBrakeControllerDecreaseFast}, + {user_command::dynamicbrakecontrollerset, &TTrain::OnCommand_DynamicBrakeControllerSet}, + {user_command::notchingrelaytoggle, &TTrain::OnCommand_notchingrelaytoggle}, + {user_command::tempomattoggle, &TTrain::OnCommand_tempomattoggle}, + {user_command::mucurrentindicatorothersourceactivate, &TTrain::OnCommand_mucurrentindicatorothersourceactivate}, + {user_command::independentbrakeincrease, &TTrain::OnCommand_independentbrakeincrease}, + {user_command::independentbrakeincreasefast, &TTrain::OnCommand_independentbrakeincreasefast}, + {user_command::independentbrakedecrease, &TTrain::OnCommand_independentbrakedecrease}, + {user_command::independentbrakedecreasefast, &TTrain::OnCommand_independentbrakedecreasefast}, + {user_command::independentbrakeset, &TTrain::OnCommand_independentbrakeset}, + {user_command::independentbrakebailoff, &TTrain::OnCommand_independentbrakebailoff}, + {user_command::universalbrakebutton1, &TTrain::OnCommand_universalbrakebutton1}, + {user_command::universalbrakebutton2, &TTrain::OnCommand_universalbrakebutton2}, + {user_command::universalbrakebutton3, &TTrain::OnCommand_universalbrakebutton3}, + {user_command::trainbrakeincrease, &TTrain::OnCommand_trainbrakeincrease}, + {user_command::trainbrakedecrease, &TTrain::OnCommand_trainbrakedecrease}, + {user_command::trainbrakeset, &TTrain::OnCommand_trainbrakeset}, + {user_command::trainbrakecharging, &TTrain::OnCommand_trainbrakecharging}, + {user_command::trainbrakerelease, &TTrain::OnCommand_trainbrakerelease}, + {user_command::trainbrakefirstservice, &TTrain::OnCommand_trainbrakefirstservice}, + {user_command::trainbrakeservice, &TTrain::OnCommand_trainbrakeservice}, + {user_command::trainbrakefullservice, &TTrain::OnCommand_trainbrakefullservice}, + {user_command::trainbrakehandleoff, &TTrain::OnCommand_trainbrakehandleoff}, + {user_command::trainbrakeemergency, &TTrain::OnCommand_trainbrakeemergency}, + {user_command::trainbrakebasepressureincrease, &TTrain::OnCommand_trainbrakebasepressureincrease}, + {user_command::trainbrakebasepressuredecrease, &TTrain::OnCommand_trainbrakebasepressuredecrease}, + {user_command::trainbrakebasepressurereset, &TTrain::OnCommand_trainbrakebasepressurereset}, + {user_command::trainbrakeoperationtoggle, &TTrain::OnCommand_trainbrakeoperationtoggle}, + {user_command::manualbrakeincrease, &TTrain::OnCommand_manualbrakeincrease}, + {user_command::manualbrakedecrease, &TTrain::OnCommand_manualbrakedecrease}, + {user_command::alarmchaintoggle, &TTrain::OnCommand_alarmchaintoggle}, + {user_command::alarmchainenable, &TTrain::OnCommand_alarmchainenable}, + {user_command::alarmchaindisable, &TTrain::OnCommand_alarmchaindisable}, + {user_command::wheelspinbrakeactivate, &TTrain::OnCommand_wheelspinbrakeactivate}, + {user_command::sandboxactivate, &TTrain::OnCommand_sandboxactivate}, + {user_command::autosandboxtoggle, &TTrain::OnCommand_autosandboxtoggle}, + {user_command::autosandboxactivate, &TTrain::OnCommand_autosandboxactivate}, + {user_command::autosandboxdeactivate, &TTrain::OnCommand_autosandboxdeactivate}, + {user_command::epbrakecontroltoggle, &TTrain::OnCommand_epbrakecontroltoggle}, + {user_command::epbrakecontrolenable, &TTrain::OnCommand_epbrakecontrolenable}, + {user_command::epbrakecontroldisable, &TTrain::OnCommand_epbrakecontroldisable}, + {user_command::trainbrakeoperationmodeincrease, &TTrain::OnCommand_trainbrakeoperationmodeincrease}, + {user_command::trainbrakeoperationmodedecrease, &TTrain::OnCommand_trainbrakeoperationmodedecrease}, + {user_command::brakeactingspeedincrease, &TTrain::OnCommand_brakeactingspeedincrease}, + {user_command::brakeactingspeeddecrease, &TTrain::OnCommand_brakeactingspeeddecrease}, + {user_command::brakeactingspeedsetcargo, &TTrain::OnCommand_brakeactingspeedsetcargo}, + {user_command::brakeactingspeedsetpassenger, &TTrain::OnCommand_brakeactingspeedsetpassenger}, + {user_command::brakeactingspeedsetrapid, &TTrain::OnCommand_brakeactingspeedsetrapid}, + {user_command::brakeloadcompensationincrease, &TTrain::OnCommand_brakeloadcompensationincrease}, + {user_command::brakeloadcompensationdecrease, &TTrain::OnCommand_brakeloadcompensationdecrease}, + {user_command::mubrakingindicatortoggle, &TTrain::OnCommand_mubrakingindicatortoggle}, + {user_command::reverserincrease, &TTrain::OnCommand_reverserincrease}, + {user_command::reverserdecrease, &TTrain::OnCommand_reverserdecrease}, + {user_command::reverserforwardhigh, &TTrain::OnCommand_reverserforwardhigh}, + {user_command::reverserforward, &TTrain::OnCommand_reverserforward}, + {user_command::reverserneutral, &TTrain::OnCommand_reverserneutral}, + {user_command::reverserbackward, &TTrain::OnCommand_reverserbackward}, + {user_command::alerteracknowledge, &TTrain::OnCommand_alerteracknowledge}, + {user_command::cabsignalacknowledge, &TTrain::OnCommand_cabsignalacknowledge}, + {user_command::batterytoggle, &TTrain::OnCommand_batterytoggle}, + {user_command::batteryenable, &TTrain::OnCommand_batteryenable}, + {user_command::batterydisable, &TTrain::OnCommand_batterydisable}, + {user_command::cabactivationtoggle, &TTrain::OnCommand_cabactivationtoggle}, + {user_command::cabactivationenable, &TTrain::OnCommand_cabactivationenable}, + {user_command::cabactivationdisable, &TTrain::OnCommand_cabactivationdisable}, + {user_command::pantographcompressorvalvetoggle, &TTrain::OnCommand_pantographcompressorvalvetoggle}, + {user_command::pantographcompressorvalveenable, &TTrain::OnCommand_pantographcompressorvalveenable}, + {user_command::pantographcompressorvalvedisable, &TTrain::OnCommand_pantographcompressorvalvedisable}, + {user_command::pantographcompressoractivate, &TTrain::OnCommand_pantographcompressoractivate}, + {user_command::pantographtogglefront, &TTrain::OnCommand_pantographtogglefront}, + {user_command::pantographtogglerear, &TTrain::OnCommand_pantographtogglerear}, + {user_command::pantographraisefront, &TTrain::OnCommand_pantographraisefront}, + {user_command::pantographraiserear, &TTrain::OnCommand_pantographraiserear}, + {user_command::pantographlowerfront, &TTrain::OnCommand_pantographlowerfront}, + {user_command::pantographlowerrear, &TTrain::OnCommand_pantographlowerrear}, {user_command::wiperswitchincrease, &TTrain::OnCommand_wiperswitchincrease}, {user_command::wiperswitchdecrease, &TTrain::OnCommand_wiperswitchdecrease}, {user_command::lightsset, &TTrain::OnCommand_lightsset}, - { user_command::pantographlowerall, &TTrain::OnCommand_pantographlowerall }, - { user_command::pantographselectnext, &TTrain::OnCommand_pantographselectnext }, - { user_command::pantographselectprevious, &TTrain::OnCommand_pantographselectprevious }, - { user_command::pantographtoggleselected, &TTrain::OnCommand_pantographtoggleselected }, - { user_command::pantographraiseselected, &TTrain::OnCommand_pantographraiseselected }, - { user_command::pantographlowerselected, &TTrain::OnCommand_pantographlowerselected }, - { user_command::pantographvalvesupdate, &TTrain::OnCommand_pantographvalvesupdate }, - { user_command::pantographvalvesoff, &TTrain::OnCommand_pantographvalvesoff }, - { user_command::linebreakertoggle, &TTrain::OnCommand_linebreakertoggle }, - { user_command::linebreakeropen, &TTrain::OnCommand_linebreakeropen }, - { user_command::linebreakerclose, &TTrain::OnCommand_linebreakerclose }, - { user_command::fuelpumptoggle, &TTrain::OnCommand_fuelpumptoggle }, - { user_command::fuelpumpenable, &TTrain::OnCommand_fuelpumpenable }, - { user_command::fuelpumpdisable, &TTrain::OnCommand_fuelpumpdisable }, - { user_command::oilpumptoggle, &TTrain::OnCommand_oilpumptoggle }, - { user_command::oilpumpenable, &TTrain::OnCommand_oilpumpenable }, - { user_command::oilpumpdisable, &TTrain::OnCommand_oilpumpdisable }, - { user_command::waterheaterbreakertoggle, &TTrain::OnCommand_waterheaterbreakertoggle }, - { user_command::waterheaterbreakerclose, &TTrain::OnCommand_waterheaterbreakerclose }, - { user_command::waterheaterbreakeropen, &TTrain::OnCommand_waterheaterbreakeropen }, - { user_command::waterheatertoggle, &TTrain::OnCommand_waterheatertoggle }, - { user_command::waterheaterenable, &TTrain::OnCommand_waterheaterenable }, - { user_command::waterheaterdisable, &TTrain::OnCommand_waterheaterdisable }, - { user_command::waterpumpbreakertoggle, &TTrain::OnCommand_waterpumpbreakertoggle }, - { user_command::waterpumpbreakerclose, &TTrain::OnCommand_waterpumpbreakerclose }, - { user_command::waterpumpbreakeropen, &TTrain::OnCommand_waterpumpbreakeropen }, - { user_command::waterpumptoggle, &TTrain::OnCommand_waterpumptoggle }, - { user_command::waterpumpenable, &TTrain::OnCommand_waterpumpenable }, - { user_command::waterpumpdisable, &TTrain::OnCommand_waterpumpdisable }, - { user_command::watercircuitslinktoggle, &TTrain::OnCommand_watercircuitslinktoggle }, - { user_command::watercircuitslinkenable, &TTrain::OnCommand_watercircuitslinkenable }, - { user_command::watercircuitslinkdisable, &TTrain::OnCommand_watercircuitslinkdisable }, - { user_command::convertertoggle, &TTrain::OnCommand_convertertoggle }, - { user_command::converterenable, &TTrain::OnCommand_converterenable }, - { user_command::converterdisable, &TTrain::OnCommand_converterdisable }, - { user_command::convertertogglelocal, &TTrain::OnCommand_convertertogglelocal }, - { user_command::converteroverloadrelayreset, &TTrain::OnCommand_converteroverloadrelayreset }, - { user_command::compressortoggle, &TTrain::OnCommand_compressortoggle }, - { user_command::compressorenable, &TTrain::OnCommand_compressorenable }, - { user_command::compressordisable, &TTrain::OnCommand_compressordisable }, - { user_command::compressortogglelocal, &TTrain::OnCommand_compressortogglelocal }, - { user_command::compressorpresetactivatenext, &TTrain::OnCommand_compressorpresetactivatenext }, - { user_command::compressorpresetactivateprevious, &TTrain::OnCommand_compressorpresetactivateprevious }, - { user_command::compressorpresetactivatedefault, &TTrain::OnCommand_compressorpresetactivatedefault }, - { user_command::motorblowerstogglefront, &TTrain::OnCommand_motorblowerstogglefront }, - { user_command::motorblowerstogglerear, &TTrain::OnCommand_motorblowerstogglerear }, - { user_command::motorblowersdisableall, &TTrain::OnCommand_motorblowersdisableall }, - { user_command::coolingfanstoggle, &TTrain::OnCommand_coolingfanstoggle }, - { user_command::motorconnectorsopen, &TTrain::OnCommand_motorconnectorsopen }, - { user_command::motorconnectorsclose, &TTrain::OnCommand_motorconnectorsclose }, - { user_command::motordisconnect, &TTrain::OnCommand_motordisconnect }, - { user_command::motoroverloadrelaythresholdtoggle, &TTrain::OnCommand_motoroverloadrelaythresholdtoggle }, - { user_command::motoroverloadrelaythresholdsetlow, &TTrain::OnCommand_motoroverloadrelaythresholdsetlow }, - { user_command::motoroverloadrelaythresholdsethigh, &TTrain::OnCommand_motoroverloadrelaythresholdsethigh }, - { user_command::motoroverloadrelayreset, &TTrain::OnCommand_motoroverloadrelayreset }, - { user_command::universalrelayreset1, &TTrain::OnCommand_universalrelayreset }, - { user_command::universalrelayreset2, &TTrain::OnCommand_universalrelayreset }, - { user_command::universalrelayreset3, &TTrain::OnCommand_universalrelayreset }, - { user_command::heatingtoggle, &TTrain::OnCommand_heatingtoggle }, - { user_command::heatingenable, &TTrain::OnCommand_heatingenable }, - { user_command::heatingdisable, &TTrain::OnCommand_heatingdisable }, - { user_command::lightspresetactivatenext, &TTrain::OnCommand_lightspresetactivatenext }, - { user_command::lightspresetactivateprevious, &TTrain::OnCommand_lightspresetactivateprevious }, - { user_command::headlighttoggleleft, &TTrain::OnCommand_headlighttoggleleft }, - { user_command::headlightenableleft, &TTrain::OnCommand_headlightenableleft }, - { user_command::headlightdisableleft, &TTrain::OnCommand_headlightdisableleft }, - { user_command::headlighttoggleright, &TTrain::OnCommand_headlighttoggleright }, - { user_command::headlightenableright, &TTrain::OnCommand_headlightenableright }, - { user_command::headlightdisableright, &TTrain::OnCommand_headlightdisableright }, - { user_command::headlighttoggleupper, &TTrain::OnCommand_headlighttoggleupper }, - { user_command::headlightenableupper, &TTrain::OnCommand_headlightenableupper }, - { user_command::headlightdisableupper, &TTrain::OnCommand_headlightdisableupper }, - { user_command::redmarkertoggleleft, &TTrain::OnCommand_redmarkertoggleleft }, - { user_command::redmarkerenableleft, &TTrain::OnCommand_redmarkerenableleft }, - { user_command::redmarkerdisableleft, &TTrain::OnCommand_redmarkerdisableleft }, - { user_command::redmarkertoggleright, &TTrain::OnCommand_redmarkertoggleright }, - { user_command::redmarkerenableright, &TTrain::OnCommand_redmarkerenableright }, - { user_command::redmarkerdisableright, &TTrain::OnCommand_redmarkerdisableright }, - { user_command::headlighttogglerearleft, &TTrain::OnCommand_headlighttogglerearleft }, - { user_command::headlightenablerearleft, &TTrain::OnCommand_headlightenablerearleft }, - { user_command::headlightdisablerearleft, &TTrain::OnCommand_headlightdisablerearleft }, - { user_command::headlighttogglerearright, &TTrain::OnCommand_headlighttogglerearright }, - { user_command::headlightenablerearright, &TTrain::OnCommand_headlightenablerearright }, - { user_command::headlightdisablerearright, &TTrain::OnCommand_headlightdisablerearright }, - { user_command::headlighttogglerearupper, &TTrain::OnCommand_headlighttogglerearupper }, - { user_command::headlightenablerearupper, &TTrain::OnCommand_headlightenablerearupper }, - { user_command::headlightdisablerearupper, &TTrain::OnCommand_headlightdisablerearupper }, + {user_command::pantographlowerall, &TTrain::OnCommand_pantographlowerall}, + {user_command::pantographselectnext, &TTrain::OnCommand_pantographselectnext}, + {user_command::pantographselectprevious, &TTrain::OnCommand_pantographselectprevious}, + {user_command::pantographtoggleselected, &TTrain::OnCommand_pantographtoggleselected}, + {user_command::pantographraiseselected, &TTrain::OnCommand_pantographraiseselected}, + {user_command::pantographlowerselected, &TTrain::OnCommand_pantographlowerselected}, + {user_command::pantographvalvesupdate, &TTrain::OnCommand_pantographvalvesupdate}, + {user_command::pantographvalvesoff, &TTrain::OnCommand_pantographvalvesoff}, + {user_command::linebreakertoggle, &TTrain::OnCommand_linebreakertoggle}, + {user_command::linebreakeropen, &TTrain::OnCommand_linebreakeropen}, + {user_command::linebreakerclose, &TTrain::OnCommand_linebreakerclose}, + {user_command::fuelpumptoggle, &TTrain::OnCommand_fuelpumptoggle}, + {user_command::fuelpumpenable, &TTrain::OnCommand_fuelpumpenable}, + {user_command::fuelpumpdisable, &TTrain::OnCommand_fuelpumpdisable}, + {user_command::oilpumptoggle, &TTrain::OnCommand_oilpumptoggle}, + {user_command::oilpumpenable, &TTrain::OnCommand_oilpumpenable}, + {user_command::oilpumpdisable, &TTrain::OnCommand_oilpumpdisable}, + {user_command::waterheaterbreakertoggle, &TTrain::OnCommand_waterheaterbreakertoggle}, + {user_command::waterheaterbreakerclose, &TTrain::OnCommand_waterheaterbreakerclose}, + {user_command::waterheaterbreakeropen, &TTrain::OnCommand_waterheaterbreakeropen}, + {user_command::waterheatertoggle, &TTrain::OnCommand_waterheatertoggle}, + {user_command::waterheaterenable, &TTrain::OnCommand_waterheaterenable}, + {user_command::waterheaterdisable, &TTrain::OnCommand_waterheaterdisable}, + {user_command::waterpumpbreakertoggle, &TTrain::OnCommand_waterpumpbreakertoggle}, + {user_command::waterpumpbreakerclose, &TTrain::OnCommand_waterpumpbreakerclose}, + {user_command::waterpumpbreakeropen, &TTrain::OnCommand_waterpumpbreakeropen}, + {user_command::waterpumptoggle, &TTrain::OnCommand_waterpumptoggle}, + {user_command::waterpumpenable, &TTrain::OnCommand_waterpumpenable}, + {user_command::waterpumpdisable, &TTrain::OnCommand_waterpumpdisable}, + {user_command::watercircuitslinktoggle, &TTrain::OnCommand_watercircuitslinktoggle}, + {user_command::watercircuitslinkenable, &TTrain::OnCommand_watercircuitslinkenable}, + {user_command::watercircuitslinkdisable, &TTrain::OnCommand_watercircuitslinkdisable}, + {user_command::convertertoggle, &TTrain::OnCommand_convertertoggle}, + {user_command::converterenable, &TTrain::OnCommand_converterenable}, + {user_command::converterdisable, &TTrain::OnCommand_converterdisable}, + {user_command::convertertogglelocal, &TTrain::OnCommand_convertertogglelocal}, + {user_command::converteroverloadrelayreset, &TTrain::OnCommand_converteroverloadrelayreset}, + {user_command::compressortoggle, &TTrain::OnCommand_compressortoggle}, + {user_command::compressorenable, &TTrain::OnCommand_compressorenable}, + {user_command::compressordisable, &TTrain::OnCommand_compressordisable}, + {user_command::compressortogglelocal, &TTrain::OnCommand_compressortogglelocal}, + {user_command::compressorpresetactivatenext, &TTrain::OnCommand_compressorpresetactivatenext}, + {user_command::compressorpresetactivateprevious, &TTrain::OnCommand_compressorpresetactivateprevious}, + {user_command::compressorpresetactivatedefault, &TTrain::OnCommand_compressorpresetactivatedefault}, + {user_command::motorblowerstogglefront, &TTrain::OnCommand_motorblowerstogglefront}, + {user_command::motorblowerstogglerear, &TTrain::OnCommand_motorblowerstogglerear}, + {user_command::motorblowersdisableall, &TTrain::OnCommand_motorblowersdisableall}, + {user_command::coolingfanstoggle, &TTrain::OnCommand_coolingfanstoggle}, + {user_command::motorconnectorsopen, &TTrain::OnCommand_motorconnectorsopen}, + {user_command::motorconnectorsclose, &TTrain::OnCommand_motorconnectorsclose}, + {user_command::motordisconnect, &TTrain::OnCommand_motordisconnect}, + {user_command::motoroverloadrelaythresholdtoggle, &TTrain::OnCommand_motoroverloadrelaythresholdtoggle}, + {user_command::motoroverloadrelaythresholdsetlow, &TTrain::OnCommand_motoroverloadrelaythresholdsetlow}, + {user_command::motoroverloadrelaythresholdsethigh, &TTrain::OnCommand_motoroverloadrelaythresholdsethigh}, + {user_command::motoroverloadrelayreset, &TTrain::OnCommand_motoroverloadrelayreset}, + {user_command::universalrelayreset1, &TTrain::OnCommand_universalrelayreset}, + {user_command::universalrelayreset2, &TTrain::OnCommand_universalrelayreset}, + {user_command::universalrelayreset3, &TTrain::OnCommand_universalrelayreset}, + {user_command::heatingtoggle, &TTrain::OnCommand_heatingtoggle}, + {user_command::heatingenable, &TTrain::OnCommand_heatingenable}, + {user_command::heatingdisable, &TTrain::OnCommand_heatingdisable}, + {user_command::lightspresetactivatenext, &TTrain::OnCommand_lightspresetactivatenext}, + {user_command::lightspresetactivateprevious, &TTrain::OnCommand_lightspresetactivateprevious}, + {user_command::headlighttoggleleft, &TTrain::OnCommand_headlighttoggleleft}, + {user_command::headlightenableleft, &TTrain::OnCommand_headlightenableleft}, + {user_command::headlightdisableleft, &TTrain::OnCommand_headlightdisableleft}, + {user_command::headlighttoggleright, &TTrain::OnCommand_headlighttoggleright}, + {user_command::headlightenableright, &TTrain::OnCommand_headlightenableright}, + {user_command::headlightdisableright, &TTrain::OnCommand_headlightdisableright}, + {user_command::headlighttoggleupper, &TTrain::OnCommand_headlighttoggleupper}, + {user_command::headlightenableupper, &TTrain::OnCommand_headlightenableupper}, + {user_command::headlightdisableupper, &TTrain::OnCommand_headlightdisableupper}, + {user_command::redmarkertoggleleft, &TTrain::OnCommand_redmarkertoggleleft}, + {user_command::redmarkerenableleft, &TTrain::OnCommand_redmarkerenableleft}, + {user_command::redmarkerdisableleft, &TTrain::OnCommand_redmarkerdisableleft}, + {user_command::redmarkertoggleright, &TTrain::OnCommand_redmarkertoggleright}, + {user_command::redmarkerenableright, &TTrain::OnCommand_redmarkerenableright}, + {user_command::redmarkerdisableright, &TTrain::OnCommand_redmarkerdisableright}, + {user_command::headlighttogglerearleft, &TTrain::OnCommand_headlighttogglerearleft}, + {user_command::headlightenablerearleft, &TTrain::OnCommand_headlightenablerearleft}, + {user_command::headlightdisablerearleft, &TTrain::OnCommand_headlightdisablerearleft}, + {user_command::headlighttogglerearright, &TTrain::OnCommand_headlighttogglerearright}, + {user_command::headlightenablerearright, &TTrain::OnCommand_headlightenablerearright}, + {user_command::headlightdisablerearright, &TTrain::OnCommand_headlightdisablerearright}, + {user_command::headlighttogglerearupper, &TTrain::OnCommand_headlighttogglerearupper}, + {user_command::headlightenablerearupper, &TTrain::OnCommand_headlightenablerearupper}, + {user_command::headlightdisablerearupper, &TTrain::OnCommand_headlightdisablerearupper}, {user_command::modernlightdimmerdecrease, &TTrain::OnCommand_modernlightdimmerdecrease}, {user_command::modernlightdimmerincrease, &TTrain::OnCommand_modernlightdimmerincrease}, - { user_command::redmarkertogglerearleft, &TTrain::OnCommand_redmarkertogglerearleft }, - { user_command::redmarkerenablerearleft, &TTrain::OnCommand_redmarkerenablerearleft }, - { user_command::redmarkerdisablerearleft, &TTrain::OnCommand_redmarkerdisablerearleft }, - { user_command::redmarkertogglerearright, &TTrain::OnCommand_redmarkertogglerearright }, - { user_command::redmarkerenablerearright, &TTrain::OnCommand_redmarkerenablerearright }, - { user_command::redmarkerdisablerearright, &TTrain::OnCommand_redmarkerdisablerearright }, - { user_command::redmarkerstoggle, &TTrain::OnCommand_redmarkerstoggle }, - { user_command::endsignalstoggle, &TTrain::OnCommand_endsignalstoggle }, - { user_command::headlightsdimtoggle, &TTrain::OnCommand_headlightsdimtoggle }, - { user_command::headlightsdimenable, &TTrain::OnCommand_headlightsdimenable }, - { user_command::headlightsdimdisable, &TTrain::OnCommand_headlightsdimdisable }, - { user_command::interiorlighttoggle, &TTrain::OnCommand_interiorlighttoggle }, - { user_command::interiorlightenable, &TTrain::OnCommand_interiorlightenable }, - { user_command::interiorlightdisable, &TTrain::OnCommand_interiorlightdisable }, - { user_command::interiorlightdimtoggle, &TTrain::OnCommand_interiorlightdimtoggle }, - { user_command::interiorlightdimenable, &TTrain::OnCommand_interiorlightdimenable }, - { user_command::interiorlightdimdisable, &TTrain::OnCommand_interiorlightdimdisable }, - { user_command::compartmentlightstoggle, &TTrain::OnCommand_compartmentlightstoggle }, - { user_command::compartmentlightsenable, &TTrain::OnCommand_compartmentlightsenable }, - { user_command::compartmentlightsdisable, &TTrain::OnCommand_compartmentlightsdisable }, - { user_command::instrumentlighttoggle, &TTrain::OnCommand_instrumentlighttoggle }, - { user_command::instrumentlightenable, &TTrain::OnCommand_instrumentlightenable }, - { user_command::instrumentlightdisable, &TTrain::OnCommand_instrumentlightdisable }, - { user_command::dashboardlighttoggle, &TTrain::OnCommand_dashboardlighttoggle }, - { user_command::dashboardlightenable, &TTrain::OnCommand_dashboardlightenable }, - { user_command::dashboardlightdisable, &TTrain::OnCommand_dashboardlightdisable }, - { user_command::timetablelighttoggle, &TTrain::OnCommand_timetablelighttoggle }, - { user_command::timetablelightenable, &TTrain::OnCommand_timetablelightenable }, - { user_command::timetablelightdisable, &TTrain::OnCommand_timetablelightdisable }, - { user_command::doorlocktoggle, &TTrain::OnCommand_doorlocktoggle }, - { user_command::doortoggleleft, &TTrain::OnCommand_doortoggleleft }, - { user_command::doortoggleright, &TTrain::OnCommand_doortoggleright }, - { user_command::doorpermitleft, &TTrain::OnCommand_doorpermitleft }, - { user_command::doorpermitright, &TTrain::OnCommand_doorpermitright }, - { user_command::doorpermitpresetactivatenext, &TTrain::OnCommand_doorpermitpresetactivatenext }, - { user_command::doorpermitpresetactivateprevious, &TTrain::OnCommand_doorpermitpresetactivateprevious }, - { user_command::dooropenleft, &TTrain::OnCommand_dooropenleft }, - { user_command::dooropenright, &TTrain::OnCommand_dooropenright }, - { user_command::doorcloseleft, &TTrain::OnCommand_doorcloseleft }, - { user_command::doorcloseright, &TTrain::OnCommand_doorcloseright }, - { user_command::dooropenall, &TTrain::OnCommand_dooropenall }, - { user_command::doorcloseall, &TTrain::OnCommand_doorcloseall }, - { user_command::doorsteptoggle, &TTrain::OnCommand_doorsteptoggle }, - { user_command::doormodetoggle, &TTrain::OnCommand_doormodetoggle }, - { user_command::mirrorstoggle, &TTrain::OnCommand_mirrorstoggle }, - { user_command::nearestcarcouplingincrease, &TTrain::OnCommand_nearestcarcouplingincrease }, - { user_command::nearestcarcouplingdisconnect, &TTrain::OnCommand_nearestcarcouplingdisconnect }, - { user_command::nearestcarcoupleradapterattach, &TTrain::OnCommand_nearestcarcoupleradapterattach }, - { user_command::nearestcarcoupleradapterremove, &TTrain::OnCommand_nearestcarcoupleradapterremove }, - { user_command::occupiedcarcouplingdisconnect, &TTrain::OnCommand_occupiedcarcouplingdisconnect }, - { user_command::departureannounce, &TTrain::OnCommand_departureannounce }, - { user_command::hornlowactivate, &TTrain::OnCommand_hornlowactivate }, - { user_command::hornhighactivate, &TTrain::OnCommand_hornhighactivate }, - { user_command::whistleactivate, &TTrain::OnCommand_whistleactivate }, - { user_command::radiotoggle, &TTrain::OnCommand_radiotoggle }, - { user_command::radioenable, &TTrain::OnCommand_radioenable }, - { user_command::radiodisable, &TTrain::OnCommand_radiodisable }, - { user_command::radiochannelincrease, &TTrain::OnCommand_radiochannelincrease }, - { user_command::radiochanneldecrease, &TTrain::OnCommand_radiochanneldecrease }, - { user_command::radiochannelset, &TTrain::OnCommand_radiochannelset }, - { user_command::radiostopsend, &TTrain::OnCommand_radiostopsend }, - { user_command::radiostopenable, &TTrain::OnCommand_radiostopenable }, - { user_command::radiostopdisable, &TTrain::OnCommand_radiostopdisable }, - { user_command::radiostoptest, &TTrain::OnCommand_radiostoptest }, - { user_command::radiocall1send, &TTrain::OnCommand_radiocall1send }, - { user_command::radiocall3send, &TTrain::OnCommand_radiocall3send }, - { user_command::radiovolumeincrease, &TTrain::OnCommand_radiovolumeincrease }, - { user_command::radiovolumedecrease, &TTrain::OnCommand_radiovolumedecrease }, - { user_command::radiovolumeset, &TTrain::OnCommand_radiovolumeset }, - { user_command::cabchangeforward, &TTrain::OnCommand_cabchangeforward }, - { user_command::cabchangebackward, &TTrain::OnCommand_cabchangebackward }, + {user_command::redmarkertogglerearleft, &TTrain::OnCommand_redmarkertogglerearleft}, + {user_command::redmarkerenablerearleft, &TTrain::OnCommand_redmarkerenablerearleft}, + {user_command::redmarkerdisablerearleft, &TTrain::OnCommand_redmarkerdisablerearleft}, + {user_command::redmarkertogglerearright, &TTrain::OnCommand_redmarkertogglerearright}, + {user_command::redmarkerenablerearright, &TTrain::OnCommand_redmarkerenablerearright}, + {user_command::redmarkerdisablerearright, &TTrain::OnCommand_redmarkerdisablerearright}, + {user_command::redmarkerstoggle, &TTrain::OnCommand_redmarkerstoggle}, + {user_command::endsignalstoggle, &TTrain::OnCommand_endsignalstoggle}, + {user_command::headlightsdimtoggle, &TTrain::OnCommand_headlightsdimtoggle}, + {user_command::headlightsdimenable, &TTrain::OnCommand_headlightsdimenable}, + {user_command::headlightsdimdisable, &TTrain::OnCommand_headlightsdimdisable}, + {user_command::interiorlighttoggle, &TTrain::OnCommand_interiorlighttoggle}, + {user_command::interiorlightenable, &TTrain::OnCommand_interiorlightenable}, + {user_command::interiorlightdisable, &TTrain::OnCommand_interiorlightdisable}, + {user_command::interiorlightdimtoggle, &TTrain::OnCommand_interiorlightdimtoggle}, + {user_command::interiorlightdimenable, &TTrain::OnCommand_interiorlightdimenable}, + {user_command::interiorlightdimdisable, &TTrain::OnCommand_interiorlightdimdisable}, + {user_command::compartmentlightstoggle, &TTrain::OnCommand_compartmentlightstoggle}, + {user_command::compartmentlightsenable, &TTrain::OnCommand_compartmentlightsenable}, + {user_command::compartmentlightsdisable, &TTrain::OnCommand_compartmentlightsdisable}, + {user_command::instrumentlighttoggle, &TTrain::OnCommand_instrumentlighttoggle}, + {user_command::instrumentlightenable, &TTrain::OnCommand_instrumentlightenable}, + {user_command::instrumentlightdisable, &TTrain::OnCommand_instrumentlightdisable}, + {user_command::dashboardlighttoggle, &TTrain::OnCommand_dashboardlighttoggle}, + {user_command::dashboardlightenable, &TTrain::OnCommand_dashboardlightenable}, + {user_command::dashboardlightdisable, &TTrain::OnCommand_dashboardlightdisable}, + {user_command::timetablelighttoggle, &TTrain::OnCommand_timetablelighttoggle}, + {user_command::timetablelightenable, &TTrain::OnCommand_timetablelightenable}, + {user_command::timetablelightdisable, &TTrain::OnCommand_timetablelightdisable}, + {user_command::doorlocktoggle, &TTrain::OnCommand_doorlocktoggle}, + {user_command::doortoggleleft, &TTrain::OnCommand_doortoggleleft}, + {user_command::doortoggleright, &TTrain::OnCommand_doortoggleright}, + {user_command::doorpermitleft, &TTrain::OnCommand_doorpermitleft}, + {user_command::doorpermitright, &TTrain::OnCommand_doorpermitright}, + {user_command::doorpermitpresetactivatenext, &TTrain::OnCommand_doorpermitpresetactivatenext}, + {user_command::doorpermitpresetactivateprevious, &TTrain::OnCommand_doorpermitpresetactivateprevious}, + {user_command::dooropenleft, &TTrain::OnCommand_dooropenleft}, + {user_command::dooropenright, &TTrain::OnCommand_dooropenright}, + {user_command::doorcloseleft, &TTrain::OnCommand_doorcloseleft}, + {user_command::doorcloseright, &TTrain::OnCommand_doorcloseright}, + {user_command::dooropenall, &TTrain::OnCommand_dooropenall}, + {user_command::doorcloseall, &TTrain::OnCommand_doorcloseall}, + {user_command::doorsteptoggle, &TTrain::OnCommand_doorsteptoggle}, + {user_command::doormodetoggle, &TTrain::OnCommand_doormodetoggle}, + {user_command::mirrorstoggle, &TTrain::OnCommand_mirrorstoggle}, + {user_command::nearestcarcouplingincrease, &TTrain::OnCommand_nearestcarcouplingincrease}, + {user_command::nearestcarcouplingdisconnect, &TTrain::OnCommand_nearestcarcouplingdisconnect}, + {user_command::nearestcarcoupleradapterattach, &TTrain::OnCommand_nearestcarcoupleradapterattach}, + {user_command::nearestcarcoupleradapterremove, &TTrain::OnCommand_nearestcarcoupleradapterremove}, + {user_command::occupiedcarcouplingdisconnect, &TTrain::OnCommand_occupiedcarcouplingdisconnect}, + {user_command::departureannounce, &TTrain::OnCommand_departureannounce}, + {user_command::hornlowactivate, &TTrain::OnCommand_hornlowactivate}, + {user_command::hornhighactivate, &TTrain::OnCommand_hornhighactivate}, + {user_command::whistleactivate, &TTrain::OnCommand_whistleactivate}, + {user_command::radiotoggle, &TTrain::OnCommand_radiotoggle}, + {user_command::radioenable, &TTrain::OnCommand_radioenable}, + {user_command::radiodisable, &TTrain::OnCommand_radiodisable}, + {user_command::radiochannelincrease, &TTrain::OnCommand_radiochannelincrease}, + {user_command::radiochanneldecrease, &TTrain::OnCommand_radiochanneldecrease}, + {user_command::radiochannelset, &TTrain::OnCommand_radiochannelset}, + {user_command::radiostopsend, &TTrain::OnCommand_radiostopsend}, + {user_command::radiostopenable, &TTrain::OnCommand_radiostopenable}, + {user_command::radiostopdisable, &TTrain::OnCommand_radiostopdisable}, + {user_command::radiostoptest, &TTrain::OnCommand_radiostoptest}, + {user_command::radiocall1send, &TTrain::OnCommand_radiocall1send}, + {user_command::radiocall3send, &TTrain::OnCommand_radiocall3send}, + {user_command::radiovolumeincrease, &TTrain::OnCommand_radiovolumeincrease}, + {user_command::radiovolumedecrease, &TTrain::OnCommand_radiovolumedecrease}, + {user_command::radiovolumeset, &TTrain::OnCommand_radiovolumeset}, + {user_command::cabchangeforward, &TTrain::OnCommand_cabchangeforward}, + {user_command::cabchangebackward, &TTrain::OnCommand_cabchangebackward}, {user_command::generictoggle0, &TTrain::OnCommand_generictoggle}, {user_command::generictoggle1, &TTrain::OnCommand_generictoggle}, {user_command::generictoggle2, &TTrain::OnCommand_generictoggle}, @@ -486,337 +512,341 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { {user_command::generictoggle27, &TTrain::OnCommand_generictoggle}, {user_command::generictoggle28, &TTrain::OnCommand_generictoggle}, {user_command::generictoggle29, &TTrain::OnCommand_generictoggle}, - { user_command::vehiclemoveforwards, &TTrain::OnCommand_vehiclemoveforwards }, - { user_command::vehiclemovebackwards, &TTrain::OnCommand_vehiclemovebackwards }, - { user_command::vehicleboost, &TTrain::OnCommand_vehicleboost }, - { user_command::springbraketoggle, &TTrain::OnCommand_springbraketoggle }, - { user_command::springbrakeenable, &TTrain::OnCommand_springbrakeenable }, - { user_command::springbrakedisable, &TTrain::OnCommand_springbrakedisable }, - { user_command::springbrakeshutofftoggle, &TTrain::OnCommand_springbrakeshutofftoggle }, - { user_command::springbrakeshutoffenable, &TTrain::OnCommand_springbrakeshutoffenable }, - { user_command::springbrakeshutoffdisable, &TTrain::OnCommand_springbrakeshutoffdisable }, - { user_command::springbrakerelease, &TTrain::OnCommand_springbrakerelease }, - { user_command::distancecounteractivate, &TTrain::OnCommand_distancecounteractivate }, - { user_command::speedcontrolincrease, &TTrain::OnCommand_speedcontrolincrease }, - { user_command::speedcontroldecrease, &TTrain::OnCommand_speedcontroldecrease }, - { user_command::speedcontrolpowerincrease, &TTrain::OnCommand_speedcontrolpowerincrease }, - { user_command::speedcontrolpowerdecrease, &TTrain::OnCommand_speedcontrolpowerdecrease }, - { user_command::speedcontrolbutton0, &TTrain::OnCommand_speedcontrolbutton }, - { user_command::speedcontrolbutton1, &TTrain::OnCommand_speedcontrolbutton }, - { user_command::speedcontrolbutton2, &TTrain::OnCommand_speedcontrolbutton }, - { user_command::speedcontrolbutton3, &TTrain::OnCommand_speedcontrolbutton }, - { user_command::speedcontrolbutton4, &TTrain::OnCommand_speedcontrolbutton }, - { user_command::speedcontrolbutton5, &TTrain::OnCommand_speedcontrolbutton }, - { user_command::speedcontrolbutton6, &TTrain::OnCommand_speedcontrolbutton }, - { user_command::speedcontrolbutton7, &TTrain::OnCommand_speedcontrolbutton }, - { user_command::speedcontrolbutton8, &TTrain::OnCommand_speedcontrolbutton }, - { user_command::speedcontrolbutton9, &TTrain::OnCommand_speedcontrolbutton }, - { user_command::inverterenable1, &TTrain::OnCommand_inverterenable }, - { user_command::inverterenable2, &TTrain::OnCommand_inverterenable }, - { user_command::inverterenable3, &TTrain::OnCommand_inverterenable }, - { user_command::inverterenable4, &TTrain::OnCommand_inverterenable }, - { user_command::inverterenable5, &TTrain::OnCommand_inverterenable }, - { user_command::inverterenable6, &TTrain::OnCommand_inverterenable }, - { user_command::inverterenable7, &TTrain::OnCommand_inverterenable }, - { user_command::inverterenable8, &TTrain::OnCommand_inverterenable }, - { user_command::inverterenable9, &TTrain::OnCommand_inverterenable }, - { user_command::inverterenable10, &TTrain::OnCommand_inverterenable }, - { user_command::inverterenable11, &TTrain::OnCommand_inverterenable }, - { user_command::inverterenable12, &TTrain::OnCommand_inverterenable }, - { user_command::inverterdisable1, &TTrain::OnCommand_inverterdisable }, - { user_command::inverterdisable2, &TTrain::OnCommand_inverterdisable }, - { user_command::inverterdisable3, &TTrain::OnCommand_inverterdisable }, - { user_command::inverterdisable4, &TTrain::OnCommand_inverterdisable }, - { user_command::inverterdisable5, &TTrain::OnCommand_inverterdisable }, - { user_command::inverterdisable6, &TTrain::OnCommand_inverterdisable }, - { user_command::inverterdisable7, &TTrain::OnCommand_inverterdisable }, - { user_command::inverterdisable8, &TTrain::OnCommand_inverterdisable }, - { user_command::inverterdisable9, &TTrain::OnCommand_inverterdisable }, - { user_command::inverterdisable10, &TTrain::OnCommand_inverterdisable }, - { user_command::inverterdisable11, &TTrain::OnCommand_inverterdisable }, - { user_command::inverterdisable12, &TTrain::OnCommand_inverterdisable }, - { user_command::invertertoggle1, &TTrain::OnCommand_invertertoggle }, - { user_command::invertertoggle2, &TTrain::OnCommand_invertertoggle }, - { user_command::invertertoggle3, &TTrain::OnCommand_invertertoggle }, - { user_command::invertertoggle4, &TTrain::OnCommand_invertertoggle }, - { user_command::invertertoggle5, &TTrain::OnCommand_invertertoggle }, - { user_command::invertertoggle6, &TTrain::OnCommand_invertertoggle }, - { user_command::invertertoggle7, &TTrain::OnCommand_invertertoggle }, - { user_command::invertertoggle8, &TTrain::OnCommand_invertertoggle }, - { user_command::invertertoggle9, &TTrain::OnCommand_invertertoggle }, - { user_command::invertertoggle10, &TTrain::OnCommand_invertertoggle }, - { user_command::invertertoggle11, &TTrain::OnCommand_invertertoggle }, - { user_command::invertertoggle12, &TTrain::OnCommand_invertertoggle }, + {user_command::vehiclemoveforwards, &TTrain::OnCommand_vehiclemoveforwards}, + {user_command::vehiclemovebackwards, &TTrain::OnCommand_vehiclemovebackwards}, + {user_command::vehicleboost, &TTrain::OnCommand_vehicleboost}, + {user_command::springbraketoggle, &TTrain::OnCommand_springbraketoggle}, + {user_command::springbrakeenable, &TTrain::OnCommand_springbrakeenable}, + {user_command::springbrakedisable, &TTrain::OnCommand_springbrakedisable}, + {user_command::springbrakeshutofftoggle, &TTrain::OnCommand_springbrakeshutofftoggle}, + {user_command::springbrakeshutoffenable, &TTrain::OnCommand_springbrakeshutoffenable}, + {user_command::springbrakeshutoffdisable, &TTrain::OnCommand_springbrakeshutoffdisable}, + {user_command::springbrakerelease, &TTrain::OnCommand_springbrakerelease}, + {user_command::distancecounteractivate, &TTrain::OnCommand_distancecounteractivate}, + {user_command::speedcontrolincrease, &TTrain::OnCommand_speedcontrolincrease}, + {user_command::speedcontroldecrease, &TTrain::OnCommand_speedcontroldecrease}, + {user_command::speedcontrolpowerincrease, &TTrain::OnCommand_speedcontrolpowerincrease}, + {user_command::speedcontrolpowerdecrease, &TTrain::OnCommand_speedcontrolpowerdecrease}, + {user_command::speedcontrolbutton0, &TTrain::OnCommand_speedcontrolbutton}, + {user_command::speedcontrolbutton1, &TTrain::OnCommand_speedcontrolbutton}, + {user_command::speedcontrolbutton2, &TTrain::OnCommand_speedcontrolbutton}, + {user_command::speedcontrolbutton3, &TTrain::OnCommand_speedcontrolbutton}, + {user_command::speedcontrolbutton4, &TTrain::OnCommand_speedcontrolbutton}, + {user_command::speedcontrolbutton5, &TTrain::OnCommand_speedcontrolbutton}, + {user_command::speedcontrolbutton6, &TTrain::OnCommand_speedcontrolbutton}, + {user_command::speedcontrolbutton7, &TTrain::OnCommand_speedcontrolbutton}, + {user_command::speedcontrolbutton8, &TTrain::OnCommand_speedcontrolbutton}, + {user_command::speedcontrolbutton9, &TTrain::OnCommand_speedcontrolbutton}, + {user_command::inverterenable1, &TTrain::OnCommand_inverterenable}, + {user_command::inverterenable2, &TTrain::OnCommand_inverterenable}, + {user_command::inverterenable3, &TTrain::OnCommand_inverterenable}, + {user_command::inverterenable4, &TTrain::OnCommand_inverterenable}, + {user_command::inverterenable5, &TTrain::OnCommand_inverterenable}, + {user_command::inverterenable6, &TTrain::OnCommand_inverterenable}, + {user_command::inverterenable7, &TTrain::OnCommand_inverterenable}, + {user_command::inverterenable8, &TTrain::OnCommand_inverterenable}, + {user_command::inverterenable9, &TTrain::OnCommand_inverterenable}, + {user_command::inverterenable10, &TTrain::OnCommand_inverterenable}, + {user_command::inverterenable11, &TTrain::OnCommand_inverterenable}, + {user_command::inverterenable12, &TTrain::OnCommand_inverterenable}, + {user_command::inverterdisable1, &TTrain::OnCommand_inverterdisable}, + {user_command::inverterdisable2, &TTrain::OnCommand_inverterdisable}, + {user_command::inverterdisable3, &TTrain::OnCommand_inverterdisable}, + {user_command::inverterdisable4, &TTrain::OnCommand_inverterdisable}, + {user_command::inverterdisable5, &TTrain::OnCommand_inverterdisable}, + {user_command::inverterdisable6, &TTrain::OnCommand_inverterdisable}, + {user_command::inverterdisable7, &TTrain::OnCommand_inverterdisable}, + {user_command::inverterdisable8, &TTrain::OnCommand_inverterdisable}, + {user_command::inverterdisable9, &TTrain::OnCommand_inverterdisable}, + {user_command::inverterdisable10, &TTrain::OnCommand_inverterdisable}, + {user_command::inverterdisable11, &TTrain::OnCommand_inverterdisable}, + {user_command::inverterdisable12, &TTrain::OnCommand_inverterdisable}, + {user_command::invertertoggle1, &TTrain::OnCommand_invertertoggle}, + {user_command::invertertoggle2, &TTrain::OnCommand_invertertoggle}, + {user_command::invertertoggle3, &TTrain::OnCommand_invertertoggle}, + {user_command::invertertoggle4, &TTrain::OnCommand_invertertoggle}, + {user_command::invertertoggle5, &TTrain::OnCommand_invertertoggle}, + {user_command::invertertoggle6, &TTrain::OnCommand_invertertoggle}, + {user_command::invertertoggle7, &TTrain::OnCommand_invertertoggle}, + {user_command::invertertoggle8, &TTrain::OnCommand_invertertoggle}, + {user_command::invertertoggle9, &TTrain::OnCommand_invertertoggle}, + {user_command::invertertoggle10, &TTrain::OnCommand_invertertoggle}, + {user_command::invertertoggle11, &TTrain::OnCommand_invertertoggle}, + {user_command::invertertoggle12, &TTrain::OnCommand_invertertoggle}, }; std::vector const TTrain::fPress_labels = { - "ch1: ", "ch2: ", "ch3: ", "ch4: ", "ch5: ", "ch6: ", "ch7: ", "ch8: ", "ch9: ", "ch0: " -}; + "ch1: ", "ch2: ", "ch3: ", "ch4: ", "ch5: ", "ch6: ", "ch7: ", "ch8: ", "ch9: ", "ch0: "}; -TTrain::TTrain() { +TTrain::TTrain() +{ - ShowNextCurrent = false; - // McZapkie-240302 - przyda sie do tachometru - fTachoVelocity = 0; - fTachoCount = 0; - fPPress = fNPress = 0; + ShowNextCurrent = false; + // McZapkie-240302 - przyda sie do tachometru + fTachoVelocity = 0; + fTachoCount = 0; + fPPress = fNPress = 0; - // asMessage=""; + // asMessage=""; pMechOffset = glm::dvec3(0, 0, 0); - fBlinkTimer = 0; - fHaslerTimer = 0; - DynamicSet(NULL); // ustawia wszystkie mv* - //----- + fBlinkTimer = 0; + fHaslerTimer = 0; + DynamicSet(NULL); // ustawia wszystkie mv* + //----- pMechSittingPosition = glm::dvec3(0, 0, 0); // ABu: 180404 - fTachoTimer = 0.0; // włączenie skoków wskazań prędkościomierza + fTachoTimer = 0.0; // włączenie skoków wskazań prędkościomierza - // - for( int i = 0; i < 8; i++ ) { - bMains[ i ] = false; - fCntVol[ i ] = 0.0f; - bPants[ i ][ 0 ] = false; - bPants[ i ][ 1 ] = false; - bFuse[ i ] = false; - bBatt[ i ] = false; - bConv[ i ] = false; - bComp[ i ][ 0 ] = false; - bComp[ i ][ 1 ] = false; - //bComp[ i ][ 2 ] = false; - //bComp[ i ][ 3 ] = false; - bHeat[ i ] = false; - } + // + for (int i = 0; i < 8; i++) + { + bMains[i] = false; + fCntVol[i] = 0.0f; + bPants[i][0] = false; + bPants[i][1] = false; + bFuse[i] = false; + bBatt[i] = false; + bConv[i] = false; + bComp[i][0] = false; + bComp[i][1] = false; + // bComp[ i ][ 2 ] = false; + // bComp[ i ][ 3 ] = false; + bHeat[i] = false; + } bCompressors.clear(); - for( int i = 0; i < 9; ++i ) + for (int i = 0; i < 9; ++i) for (int j = 0; j < 10; ++j) { fEIMParams[i][j] = 0.0; fDieselParams[i][j] = 0.0; } - for ( int i = 0; i < 20; ++i ) + for (int i = 0; i < 20; ++i) { - for ( int j = 0; j < 7; ++j ) + for (int j = 0; j < 7; ++j) fPress[i][j] = 0.0; bBrakes[i][0] = bBrakes[i][1] = false; } } -TTrain::~TTrain() -{ -} +TTrain::~TTrain() {} bool TTrain::Init(TDynamicObject *NewDynamicObject, bool e3d) { // powiązanie ręcznego sterowania kabiną z pojazdem - if( NewDynamicObject->Mechanik == nullptr ) { - /* - ErrorLog( "Bad config: can't take control of inactive vehicle \"" + NewDynamicObject->asName + "\"" ); - return false; - */ - auto const activecab { ( - NewDynamicObject->MoverParameters->CabOccupied > 0 ? "1" : - NewDynamicObject->MoverParameters->CabOccupied < 0 ? "2" : - "p" ) }; - NewDynamicObject->create_controller( activecab, NewDynamicObject->ctOwner != nullptr ); - } + if (NewDynamicObject->Mechanik == nullptr) + { + /* + ErrorLog( "Bad config: can't take control of inactive vehicle \"" + NewDynamicObject->asName + "\"" ); + return false; + */ + auto const activecab{(NewDynamicObject->MoverParameters->CabOccupied > 0 ? "1" : NewDynamicObject->MoverParameters->CabOccupied < 0 ? "2" : "p")}; + NewDynamicObject->create_controller(activecab, NewDynamicObject->ctOwner != nullptr); + } - DynamicSet(NewDynamicObject); - if (!e3d) - if (DynamicObject->Mechanik == NULL) - return false; + DynamicSet(NewDynamicObject); + if (!e3d) + if (DynamicObject->Mechanik == NULL) + return false; - DynamicObject->MechInside = true; + DynamicObject->MechInside = true; - fMainRelayTimer = 0; // Hunter, do k...y nędzy, ustawiaj wartości początkowe zmiennych! + fMainRelayTimer = 0; // Hunter, do k...y nędzy, ustawiaj wartości początkowe zmiennych! - iCabn = ( - mvOccupied->CabOccupied > 0 ? 1 : - mvOccupied->CabOccupied < 0 ? 2 : - 0 ); + iCabn = (mvOccupied->CabOccupied > 0 ? 1 : mvOccupied->CabOccupied < 0 ? 2 : 0); - { - Global.CurrentMaxTextureSize = Global.iMaxCabTextureSize; + { + Global.CurrentMaxTextureSize = Global.iMaxCabTextureSize; - auto const filename { mvOccupied->TypeName + ".mmd" }; - LoadMMediaFile( filename ); - InitializeCab( - mvOccupied->CabOccupied, - filename ); + auto const filename{mvOccupied->TypeName + ".mmd"}; + LoadMMediaFile(filename); + InitializeCab(mvOccupied->CabOccupied, filename); - Global.CurrentMaxTextureSize = Global.iMaxTextureSize; + Global.CurrentMaxTextureSize = Global.iMaxTextureSize; - if( DynamicObject->Controller == Humandriver ) { - // McZapkie-030303: mozliwosc wyswietlania kabiny, w przyszlosci dac opcje w mmd - DynamicObject->bDisplayCab = true; - } - } + if (DynamicObject->Controller == Humandriver) + { + // McZapkie-030303: mozliwosc wyswietlania kabiny, w przyszlosci dac opcje w mmd + DynamicObject->bDisplayCab = true; + } + } - // Ra: taka proteza - przesłanie kierunku do członów connected - /* - if (mvControlled->DirActive > 0) - { // było do przodu - mvControlled->DirectionBackward(); - mvControlled->DirectionForward(); - } - else if (mvControlled->DirActive < 0) - { - mvControlled->DirectionForward(); - mvControlled->DirectionBackward(); - } - */ - if( false == DynamicObject->Mechanik->AIControllFlag ) { - DynamicObject->Mechanik->sync_consist_reversers(); - } + // Ra: taka proteza - przesłanie kierunku do członów connected + /* + if (mvControlled->DirActive > 0) + { // było do przodu + mvControlled->DirectionBackward(); + mvControlled->DirectionForward(); + } + else if (mvControlled->DirActive < 0) + { + mvControlled->DirectionForward(); + mvControlled->DirectionBackward(); + } + */ + if (false == DynamicObject->Mechanik->AIControllFlag) + { + DynamicObject->Mechanik->sync_consist_reversers(); + } - return true; + return true; } -std::shared_ptr TTrain::GetTrainState( dictionary_source const &Extraparameters ) { +std::shared_ptr TTrain::GetTrainState(dictionary_source const &Extraparameters) +{ - if( ( mvOccupied == nullptr ) - || ( mvControlled == nullptr ) ) { return nullptr; } + if ((mvOccupied == nullptr) || (mvControlled == nullptr)) + { + return nullptr; + } - auto dict = std::make_shared( Extraparameters ); - if( dict == nullptr ) { return nullptr; } + auto dict = std::make_shared(Extraparameters); + if (dict == nullptr) + { + return nullptr; + } - dict->insert( "name", DynamicObject->asName ); - dict->insert( "cab", mvOccupied->CabOccupied ); - dict->insert( "cabactive", mvOccupied->CabActive ); - dict->insert( "master", mvOccupied->CabMaster ); - // basic systems state data - dict->insert( "battery", mvOccupied->Power24vIsAvailable ); - dict->insert( "linebreaker", mvControlled->Mains ); - dict->insert( "main_init", ( mvControlled->MainsInitTimeCountdown < mvControlled->MainsInitTime ) && ( mvControlled->MainsInitTimeCountdown > 0.0 ) ); - dict->insert( "main_ready", ( false == mvControlled->Mains ) && ( fHVoltage > 0.0 ) && ( mvControlled->MainsInitTimeCountdown <= 0.0 ) ); - dict->insert( "converter", mvOccupied->Power110vIsAvailable ); - dict->insert( "converter_overload", mvControlled->ConvOvldFlag ); - dict->insert( "compress", mvControlled->CompressorFlag ); - dict->insert( "pant_compressor", mvPantographUnit->PantCompFlag ); - dict->insert( "lights_front", mvOccupied->iLights[ end::front ] ); - dict->insert( "lights_rear", mvOccupied->iLights[ end::rear ] ); + dict->insert("name", DynamicObject->asName); + dict->insert("cab", mvOccupied->CabOccupied); + dict->insert("cabactive", mvOccupied->CabActive); + dict->insert("master", mvOccupied->CabMaster); + // basic systems state data + dict->insert("battery", mvOccupied->Power24vIsAvailable); + dict->insert("linebreaker", mvControlled->Mains); + dict->insert("main_init", (mvControlled->MainsInitTimeCountdown < mvControlled->MainsInitTime) && (mvControlled->MainsInitTimeCountdown > 0.0)); + dict->insert("main_ready", (false == mvControlled->Mains) && (fHVoltage > 0.0) && (mvControlled->MainsInitTimeCountdown <= 0.0)); + dict->insert("converter", mvOccupied->Power110vIsAvailable); + dict->insert("converter_overload", mvControlled->ConvOvldFlag); + dict->insert("compress", mvControlled->CompressorFlag); + dict->insert("pant_compressor", mvPantographUnit->PantCompFlag); + dict->insert("lights_front", mvOccupied->iLights[end::front]); + dict->insert("lights_rear", mvOccupied->iLights[end::rear]); dict->insert("off_from_dimmer", mvOccupied->dimPositions[mvOccupied->modernDimmerPosition].isOff); - dict->insert( "lights_compartments", mvOccupied->CompartmentLights.is_active || mvOccupied->CompartmentLights.is_disabled ); - if( Dynamic()->Mechanik ) { - auto const *controller { Dynamic()->Mechanik }; - auto const cabmodifier { cab_to_end() == end::front ? 1 : -1 }; - auto const traindirection { controller->Direction() * cabmodifier }; - auto const *frontvehicle { controller->Vehicle( traindirection >= 0 ? end::front : end::rear ) }; - auto const *rearvehicle { controller->Vehicle( traindirection >= 0 ? end::rear : end::front ) }; - auto const frontvehicledirection { ( frontvehicle->DirectionGet() == controller->Vehicle()->DirectionGet() ? 1 : -1 ) }; - auto const rearvehicledirection { ( rearvehicle->DirectionGet() == controller->Vehicle()->DirectionGet() ? 1 : -1 ) }; - auto const fronttrainlights { frontvehicle->MoverParameters->iLights[ frontvehicledirection * cabmodifier >= 0 ? end::front : end::rear ] }; - auto const reartrainlights{ rearvehicle->MoverParameters->iLights[ rearvehicledirection * cabmodifier >= 0 ? end::rear : end::front ] }; - dict->insert( "lights_train_front", fronttrainlights ); - dict->insert( "lights_train_rear", reartrainlights ); - } - else { - // fallback, in the unlikely case we lose the controller - dict->insert( "lights_train_front", mvOccupied->iLights[ end::front ] ); - dict->insert( "lights_train_rear", mvOccupied->iLights[ end::rear ] ); - } - // reverser - dict->insert( "direction", mvOccupied->DirActive ); - // throttle - dict->insert( "mainctrl_pos", mvControlled->MainCtrlPos ); - dict->insert( "mainctrl_pos_count", mvControlled->MainCtrlPosNo ); - dict->insert( "main_ctrl_actual_pos", mvControlled->MainCtrlActualPos ); - dict->insert( "scndctrl_pos", mvControlled->ScndCtrlPos ); - dict->insert( "scnd_ctrl_actual_pos", mvControlled->ScndCtrlActualPos ); - dict->insert( "brakectrl_pos", mvControlled->fBrakeCtrlPos ); - dict->insert( "localbrake_pos", mvControlled->LocalBrakePosA ); - dict->insert( "new_speed", mvOccupied->NewSpeed); - dict->insert( "speedctrl", mvOccupied->SpeedCtrlValue); - dict->insert( "speedctrlpower", mvOccupied->SpeedCtrlUnit.DesiredPower ); - dict->insert( "speedctrlactive", mvOccupied->SpeedCtrlUnit.IsActive ); - dict->insert( "speedctrlstandby", mvOccupied->SpeedCtrlUnit.Standby ); - // brakes - dict->insert( "manual_brake", ( mvOccupied->ManualBrakePos > 0 ) ); - bool const bEP = ( mvControlled->LocHandle->GetCP() > 0.2 ) || ( fEIMParams[ 0 ][ 5 ] > 0.01 ); - dict->insert( "dir_brake", bEP ); - bool bPN { false }; - if( ( typeid( *mvOccupied->Hamulec ) == typeid( TLSt ) ) - || ( typeid( *mvOccupied->Hamulec ) == typeid( TEStED ) ) ) { + dict->insert("lights_compartments", mvOccupied->CompartmentLights.is_active || mvOccupied->CompartmentLights.is_disabled); + if (Dynamic()->Mechanik) + { + auto const *controller{Dynamic()->Mechanik}; + auto const cabmodifier{cab_to_end() == end::front ? 1 : -1}; + auto const traindirection{controller->Direction() * cabmodifier}; + auto const *frontvehicle{controller->Vehicle(traindirection >= 0 ? end::front : end::rear)}; + auto const *rearvehicle{controller->Vehicle(traindirection >= 0 ? end::rear : end::front)}; + auto const frontvehicledirection{(frontvehicle->DirectionGet() == controller->Vehicle()->DirectionGet() ? 1 : -1)}; + auto const rearvehicledirection{(rearvehicle->DirectionGet() == controller->Vehicle()->DirectionGet() ? 1 : -1)}; + auto const fronttrainlights{frontvehicle->MoverParameters->iLights[frontvehicledirection * cabmodifier >= 0 ? end::front : end::rear]}; + auto const reartrainlights{rearvehicle->MoverParameters->iLights[rearvehicledirection * cabmodifier >= 0 ? end::rear : end::front]}; + dict->insert("lights_train_front", fronttrainlights); + dict->insert("lights_train_rear", reartrainlights); + } + else + { + // fallback, in the unlikely case we lose the controller + dict->insert("lights_train_front", mvOccupied->iLights[end::front]); + dict->insert("lights_train_rear", mvOccupied->iLights[end::rear]); + } + // reverser + dict->insert("direction", mvOccupied->DirActive); + // throttle + dict->insert("mainctrl_pos", mvControlled->MainCtrlPos); + dict->insert("mainctrl_pos_count", mvControlled->MainCtrlPosNo); + dict->insert("main_ctrl_actual_pos", mvControlled->MainCtrlActualPos); + dict->insert("scndctrl_pos", mvControlled->ScndCtrlPos); + dict->insert("scnd_ctrl_actual_pos", mvControlled->ScndCtrlActualPos); + dict->insert("brakectrl_pos", mvControlled->fBrakeCtrlPos); + dict->insert("localbrake_pos", mvControlled->LocalBrakePosA); + dict->insert("new_speed", mvOccupied->NewSpeed); + dict->insert("speedctrl", mvOccupied->SpeedCtrlValue); + dict->insert("speedctrlpower", mvOccupied->SpeedCtrlUnit.DesiredPower); + dict->insert("speedctrlactive", mvOccupied->SpeedCtrlUnit.IsActive); + dict->insert("speedctrlstandby", mvOccupied->SpeedCtrlUnit.Standby); + // brakes + dict->insert("manual_brake", (mvOccupied->ManualBrakePos > 0)); + bool const bEP = (mvControlled->LocHandle->GetCP() > 0.2) || (fEIMParams[0][5] > 0.01); + dict->insert("dir_brake", bEP); + bool bPN{false}; + if ((typeid(*mvOccupied->Hamulec) == typeid(TLSt)) || (typeid(*mvOccupied->Hamulec) == typeid(TEStED))) + { - TBrake* temp_ham = mvOccupied->Hamulec.get(); - bPN = ( static_cast( temp_ham )->GetEDBCP() > 0.2 ); - } - dict->insert( "indir_brake", bPN ); - dict->insert( "emergency_brake", mvOccupied->AlarmChainFlag ); - dict->insert( "brake_delay_flag", mvOccupied->BrakeDelayFlag ); - dict->insert( "brake_op_mode_flag", mvOccupied->BrakeOpModeFlag ); - dict->insert( "pipelock", mvOccupied->LockPipe); - // other controls - dict->insert( "ca", mvOccupied->SecuritySystem.is_vigilance_blinking()); - dict->insert( "shp", mvOccupied->SecuritySystem.is_cabsignal_blinking()); - dict->insert( "distance_counter", m_distancecounter ); - dict->insert( "pantpress", std::abs( mvPantographUnit->PantPress ) ); - dict->insert( "universal3", InstrumentLightActive ); - for (auto idx = 0; idx < ggUniversals.size(); idx++) { - if (idx != 3) { + TBrake *temp_ham = mvOccupied->Hamulec.get(); + bPN = (static_cast(temp_ham)->GetEDBCP() > 0.2); + } + dict->insert("indir_brake", bPN); + dict->insert("emergency_brake", mvOccupied->AlarmChainFlag); + dict->insert("brake_delay_flag", mvOccupied->BrakeDelayFlag); + dict->insert("brake_op_mode_flag", mvOccupied->BrakeOpModeFlag); + dict->insert("pipelock", mvOccupied->LockPipe); + // other controls + dict->insert("ca", mvOccupied->SecuritySystem.is_vigilance_blinking()); + dict->insert("shp", mvOccupied->SecuritySystem.is_cabsignal_blinking()); + dict->insert("distance_counter", m_distancecounter); + dict->insert("pantpress", std::abs(mvPantographUnit->PantPress)); + dict->insert("universal3", InstrumentLightActive); + for (auto idx = 0; idx < ggUniversals.size(); idx++) + { + if (idx != 3) + { dict->insert("universal" + std::to_string(idx), (ggUniversals[idx].GetValue() > 0.5)); } } - dict->insert( "radio", mvOccupied->Radio ); - dict->insert( "radio_channel", RadioChannel() ); - dict->insert( "radio_volume", m_radiovolume ); - dict->insert( "door_lock", mvOccupied->Doors.lock_enabled ); - dict->insert( "door_step", mvOccupied->Doors.step_enabled ); - dict->insert( "door_permit_left", mvOccupied->Doors.instances[side::left].open_permit ); - dict->insert( "door_permit_right", mvOccupied->Doors.instances[side::right].open_permit ); - // movement data - dict->insert( "velocity", std::abs( mvOccupied->Vel ) ); - dict->insert( "tractionforce", std::abs( mvOccupied->Ft ) ); - dict->insert( "slipping_wheels", mvOccupied->SlippingWheels ); - dict->insert( "sanding", mvOccupied->SandDose ); - dict->insert( "odometer", mvOccupied->DistCounter ); - // electric current data - dict->insert( "traction_voltage", std::abs( mvPantographUnit->PantographVoltage ) ); - dict->insert( "voltage", std::abs( mvControlled->EngineVoltage ) ); - dict->insert( "im", std::abs( mvControlled->Im ) ); - dict->insert( "fuse", mvControlled->FuseFlag ); - dict->insert( "epfuse", mvOccupied->EpFuse ); - dict->insert( "power_drawn", mvOccupied->EnergyMeter.first); - dict->insert( "power_returned", mvOccupied->EnergyMeter.second); + dict->insert("radio", mvOccupied->Radio); + dict->insert("radio_channel", RadioChannel()); + dict->insert("radio_volume", m_radiovolume); + dict->insert("door_lock", mvOccupied->Doors.lock_enabled); + dict->insert("door_step", mvOccupied->Doors.step_enabled); + dict->insert("door_permit_left", mvOccupied->Doors.instances[side::left].open_permit); + dict->insert("door_permit_right", mvOccupied->Doors.instances[side::right].open_permit); + // movement data + dict->insert("velocity", std::abs(mvOccupied->Vel)); + dict->insert("tractionforce", std::abs(mvOccupied->Ft)); + dict->insert("slipping_wheels", mvOccupied->SlippingWheels); + dict->insert("sanding", mvOccupied->SandDose); + dict->insert("odometer", mvOccupied->DistCounter); + // electric current data + dict->insert("traction_voltage", std::abs(mvPantographUnit->PantographVoltage)); + dict->insert("voltage", std::abs(mvControlled->EngineVoltage)); + dict->insert("im", std::abs(mvControlled->Im)); + dict->insert("fuse", mvControlled->FuseFlag); + dict->insert("epfuse", mvOccupied->EpFuse); + dict->insert("power_drawn", mvOccupied->EnergyMeter.first); + dict->insert("power_returned", mvOccupied->EnergyMeter.second); - // induction motor state data - char const *TXTT[ 10 ] = { "fd", "fdt", "fdb", "pd", "pdt", "pdb", "itothv", "1", "2", "3" }; - char const *TXTC[ 10 ] = { "fr", "frt", "frb", "pr", "prt", "prb", "im", "vm", "ihv", "uhv" }; - char const *TXTD[ 10 ] = { "enrot", "nrot", "fill_des", "fill_real", "clutch_des", "clutch_real", "water_temp", "oil_press", "engine_temp", "retarder_fill" }; - char const *TXTP[ 7 ] = { "bc", "bp", "sp", "cp", "rp", "mass", "spring" }; - char const *TXTB[ 2 ] = { "spring_active", "spring_shutoff" }; - for( int j = 0; j < 10; ++j ) - dict->insert( ( "eimp_t_" + std::string( TXTT[ j ] ) ), fEIMParams[ 0 ][ j ] ); - for( int i = 0; i < 8; ++i ) { - auto const idx { std::to_string( i + 1 ) }; - for( int j = 0; j < 10; ++j ) - dict->insert( ( "eimp_c" + idx + "_" + std::string( TXTC[ j ] ) ), fEIMParams[ i + 1 ][ j ] ); + // induction motor state data + char const *TXTT[10] = {"fd", "fdt", "fdb", "pd", "pdt", "pdb", "itothv", "1", "2", "3"}; + char const *TXTC[10] = {"fr", "frt", "frb", "pr", "prt", "prb", "im", "vm", "ihv", "uhv"}; + char const *TXTD[10] = {"enrot", "nrot", "fill_des", "fill_real", "clutch_des", "clutch_real", "water_temp", "oil_press", "engine_temp", "retarder_fill"}; + char const *TXTP[7] = {"bc", "bp", "sp", "cp", "rp", "mass", "spring"}; + char const *TXTB[2] = {"spring_active", "spring_shutoff"}; + for (int j = 0; j < 10; ++j) + dict->insert(("eimp_t_" + std::string(TXTT[j])), fEIMParams[0][j]); + for (int i = 0; i < 8; ++i) + { + auto const idx{std::to_string(i + 1)}; + for (int j = 0; j < 10; ++j) + dict->insert(("eimp_c" + idx + "_" + std::string(TXTC[j])), fEIMParams[i + 1][j]); for (int j = 0; j < 10; ++j) dict->insert(("diesel_param_" + idx + "_" + std::string(TXTD[j])), fDieselParams[i + 1][j]); - dict->insert( ( "eimp_c" + idx + "_ms" ), bMains[ i ] ); - dict->insert( ( "eimp_c" + idx + "_cv" ), fCntVol[ i ] ); - dict->insert( ( "eimp_c" + idx + "_fuse" ), bFuse[ i ] ); - dict->insert( ( "eimp_c" + idx + "_batt" ), bBatt[ i ] ); - dict->insert( ( "eimp_c" + idx + "_conv" ), bConv[ i ] ); - dict->insert( ( "eimp_c" + idx + "_heat" ), bHeat[ i ] ); + dict->insert(("eimp_c" + idx + "_ms"), bMains[i]); + dict->insert(("eimp_c" + idx + "_cv"), fCntVol[i]); + dict->insert(("eimp_c" + idx + "_fuse"), bFuse[i]); + dict->insert(("eimp_c" + idx + "_batt"), bBatt[i]); + dict->insert(("eimp_c" + idx + "_conv"), bConv[i]); + dict->insert(("eimp_c" + idx + "_heat"), bHeat[i]); - dict->insert( ( "eimp_u" + idx + "_pf" ), bPants[ i ][ 0 ] ); - dict->insert( ( "eimp_u" + idx + "_pr" ), bPants[ i ][ 1 ] ); - dict->insert( ( "eimp_u" + idx + "_comp_a" ), bComp[ i ][ 0 ] ); - dict->insert( ( "eimp_u" + idx + "_comp_w" ), bComp[ i ][ 1 ] ); - } + dict->insert(("eimp_u" + idx + "_pf"), bPants[i][0]); + dict->insert(("eimp_u" + idx + "_pr"), bPants[i][1]); + dict->insert(("eimp_u" + idx + "_comp_a"), bComp[i][0]); + dict->insert(("eimp_u" + idx + "_comp_w"), bComp[i][1]); + } - dict->insert( "compressors_no", (int)bCompressors.size() ); + dict->insert("compressors_no", (int)bCompressors.size()); for (int i = 0; i < bCompressors.size(); i++) { - auto const idx { std::to_string( i + 1 ) }; - dict->insert("compressors_" + idx + "_allow", std::get<0>(bCompressors[i])); + auto const idx{std::to_string(i + 1)}; + dict->insert("compressors_" + idx + "_allow", std::get<0>(bCompressors[i])); dict->insert("compressors_" + idx + "_work", std::get<1>(bCompressors[i])); dict->insert("compressors_" + idx + "_car_no", std::get<2>(bCompressors[i])); } - bool kier = (DynamicObject->DirectionGet() * mvOccupied->CabOccupied > 0); TDynamicObject *p = DynamicObject->GetFirstDynamic(mvOccupied->CabOccupied < 0 ? end::rear : end::front, 4); int in = 0; @@ -826,7 +856,8 @@ std::shared_ptr TTrain::GetTrainState( dictionary_source cons { in++; dict->insert(("eimp_c" + std::to_string(in) + "_invno"), p->MoverParameters->InvertersNo); - for (int j = 0; j < p->MoverParameters->InvertersNo; j++) { + for (int j = 0; j < p->MoverParameters->InvertersNo; j++) + { dict->insert(("eimp_c" + std::to_string(in) + "_inv" + std::to_string(j + 1) + "_act"), p->MoverParameters->Inverters[j].IsActive); dict->insert(("eimp_c" + std::to_string(in) + "_inv" + std::to_string(j + 1) + "_error"), p->MoverParameters->Inverters[j].Error); dict->insert(("eimp_c" + std::to_string(in) + "_inv" + std::to_string(j + 1) + "_allow"), p->MoverParameters->Inverters[j].Activate); @@ -834,836 +865,1067 @@ std::shared_ptr TTrain::GetTrainState( dictionary_source cons } p = (kier ? p->Next(4) : p->Prev(4)); } - for( int i = 0; i < 20; ++i ) { - for( int j = 0; j < 7; ++j ) { - dict->insert( ( "eimp_pn" + std::to_string( i + 1 ) + "_" + TXTP[ j ] ), fPress[ i ][ j ] ); - } - for ( int j = 0; j < 2; ++j) { - dict->insert( ( "brakes_" + std::to_string( i + 1 ) + "_" + TXTB[ j ] ), bBrakes[ i ][ j ] ); + for (int i = 0; i < 20; ++i) + { + for (int j = 0; j < 7; ++j) + { + dict->insert(("eimp_pn" + std::to_string(i + 1) + "_" + TXTP[j]), fPress[i][j]); } - } - // multi-unit state data - dict->insert( "car_no", iCarNo ); - dict->insert( "power_no", iPowerNo ); - dict->insert( "unit_no", iUnitNo ); + for (int j = 0; j < 2; ++j) + { + dict->insert(("brakes_" + std::to_string(i + 1) + "_" + TXTB[j]), bBrakes[i][j]); + } + } + // multi-unit state data + dict->insert("car_no", iCarNo); + dict->insert("power_no", iPowerNo); + dict->insert("unit_no", iUnitNo); - for( int i = 0; i < 20; i++ ) { - auto const caridx { std::to_string( i + 1 ) }; - dict->insert( ( "doors_" + caridx ), bDoors[ i ][ 0 ] ); - dict->insert( ( "doors_l_" + caridx ), bDoors[ i ][ 1 ] ); - dict->insert( ( "doors_r_" + caridx ), bDoors[ i ][ 2 ] ); - dict->insert( ( "doorstep_l_" + caridx ), bDoors[ i ][ 3 ] ); - dict->insert( ( "doorstep_r_" + caridx ), bDoors[ i ][ 4 ] ); - dict->insert( ( "doors_no_" + caridx ), iDoorNo[ i ] ); - dict->insert( ( "code_" + caridx ), ( std::to_string( iUnits[ i ] ) + cCode[ i ] ) ); - dict->insert( ( "car_name" + caridx ), asCarName[ i ] ); - dict->insert( ( "slip_" + caridx ), bSlip[ i ] ); - } - // ai state data - auto const *driver { ( - DynamicObject->ctOwner != nullptr ? - DynamicObject->ctOwner : - DynamicObject->Mechanik ) }; + for (int i = 0; i < 20; i++) + { + auto const caridx{std::to_string(i + 1)}; + dict->insert(("doors_" + caridx), bDoors[i][0]); + dict->insert(("doors_l_" + caridx), bDoors[i][1]); + dict->insert(("doors_r_" + caridx), bDoors[i][2]); + dict->insert(("doorstep_l_" + caridx), bDoors[i][3]); + dict->insert(("doorstep_r_" + caridx), bDoors[i][4]); + dict->insert(("doors_no_" + caridx), iDoorNo[i]); + dict->insert(("code_" + caridx), (std::to_string(iUnits[i]) + cCode[i])); + dict->insert(("car_name" + caridx), asCarName[i]); + dict->insert(("slip_" + caridx), bSlip[i]); + } + // ai state data + auto const *driver{(DynamicObject->ctOwner != nullptr ? DynamicObject->ctOwner : DynamicObject->Mechanik)}; - dict->insert( "velocity_desired", driver->VelDesired ); - dict->insert( "velroad", driver->VelRoad ); - dict->insert( "vellimitlast", driver->VelLimitLast ); - dict->insert( "velsignallast", driver->VelSignalLast ); - dict->insert( "velsignalnext", driver->VelSignalNext ); - dict->insert( "velnext", driver->VelNext ); - dict->insert( "actualproximitydist", driver->ActualProximityDist ); - // train data - driver->TrainTimetable().serialize( dict.get() ); - dict->insert( "train_atpassengerstop", driver->IsAtPassengerStop ); - dict->insert( "train_length", driver->fLength ); - // world state data - dict->insert( "scenario", Global.SceneryFile ); - dict->insert( "hours", static_cast( simulation::Time.data().wHour ) ); - dict->insert( "minutes", static_cast( simulation::Time.data().wMinute ) ); - dict->insert( "seconds", static_cast( simulation::Time.second() ) ); - dict->insert( "air_temperature", Global.AirTemperature ); - dict->insert( "light_level", Global.fLuminance - std::max( 0.f, Global.Overcast - 1.f ) ); + dict->insert("velocity_desired", driver->VelDesired); + dict->insert("velroad", driver->VelRoad); + dict->insert("vellimitlast", driver->VelLimitLast); + dict->insert("velsignallast", driver->VelSignalLast); + dict->insert("velsignalnext", driver->VelSignalNext); + dict->insert("velnext", driver->VelNext); + dict->insert("actualproximitydist", driver->ActualProximityDist); + // train data + driver->TrainTimetable().serialize(dict.get()); + dict->insert("train_atpassengerstop", driver->IsAtPassengerStop); + dict->insert("train_length", driver->fLength); + // world state data + dict->insert("scenario", Global.SceneryFile); + dict->insert("hours", static_cast(simulation::Time.data().wHour)); + dict->insert("minutes", static_cast(simulation::Time.data().wMinute)); + dict->insert("seconds", static_cast(simulation::Time.second())); + dict->insert("air_temperature", Global.AirTemperature); + dict->insert("light_level", Global.fLuminance - std::max(0.f, Global.Overcast - 1.f)); - return dict; + return dict; } -TTrain::state_t -TTrain::get_state() const { +TTrain::state_t TTrain::get_state() const +{ return { - btLampkaSHP.GetValue(), - btLampkaCzuwaka.GetValue(), - btLampkaRadioStop.GetValue(), - btLampkaOpory.GetValue(), - btLampkaWylSzybki.GetValue(), - btLampkaPrzekRozn.GetValue(), - btLampkaNadmSil.GetValue(), - btLampkaStyczn.GetValue(), - btLampkaPoslizg.GetValue(), - btLampkaNadmPrzetw.GetValue(), - btLampkaPrzetwOff.GetValue(), - btLampkaNadmSpr.GetValue(), - btLampkaNadmWent.GetValue(), - btLampkaWysRozr.GetValue(), - btLampkaOgrzewanieSkladu.GetValue(), - static_cast(iCabn), - btHaslerBrakes.GetValue(), - btHaslerCurrent.GetValue(), - mvOccupied->SecuritySystem.is_beeping(), - btLampkaHVoltageB.GetValue(), - fTachoVelocity, - static_cast(mvOccupied->Compressor), - static_cast(mvOccupied->PipePress), - static_cast(mvOccupied->BrakePress), - static_cast(mvPantographUnit->PantPress), - fHVoltage, - { fHCurrent[(mvControlled->TrainType & dt_EZT) ? 0 : 1], fHCurrent[2], fHCurrent[3] }, - ggLVoltage.GetValue(), - mvOccupied->DistCounter, - static_cast(RadioChannel()), - btLampkaSpringBrakeActive.GetValue(), - btLampkaNapNastHam.GetValue(), - mvOccupied->DirActive > 0, - mvOccupied->DirActive < 0, - mvOccupied->Doors.instances[mvOccupied->CabOccupied < 0 ? side::right : side::left].open_permit, - mvOccupied->Doors.instances[mvOccupied->CabOccupied < 0 ? side::right : side::left].is_open, - mvOccupied->Doors.instances[mvOccupied->CabOccupied < 0 ? side::left : side::right].open_permit, - mvOccupied->Doors.instances[mvOccupied->CabOccupied < 0 ? side::left : side::right].is_open, - mvOccupied->Doors.step_enabled, - mvOccupied->Power24vIsAvailable, - 0, - mvOccupied->LockPipe, - btLampkaRadioMessage.GetValue(), - }; + btLampkaSHP.GetValue(), + btLampkaCzuwaka.GetValue(), + btLampkaRadioStop.GetValue(), + btLampkaOpory.GetValue(), + btLampkaWylSzybki.GetValue(), + btLampkaPrzekRozn.GetValue(), + btLampkaNadmSil.GetValue(), + btLampkaStyczn.GetValue(), + btLampkaPoslizg.GetValue(), + btLampkaNadmPrzetw.GetValue(), + btLampkaPrzetwOff.GetValue(), + btLampkaNadmSpr.GetValue(), + btLampkaNadmWent.GetValue(), + btLampkaWysRozr.GetValue(), + btLampkaOgrzewanieSkladu.GetValue(), + static_cast(iCabn), + btHaslerBrakes.GetValue(), + btHaslerCurrent.GetValue(), + mvOccupied->SecuritySystem.is_beeping(), + btLampkaHVoltageB.GetValue(), + fTachoVelocity, + static_cast(mvOccupied->Compressor), + static_cast(mvOccupied->PipePress), + static_cast(mvOccupied->BrakePress), + static_cast(mvPantographUnit->PantPress), + fHVoltage, + {fHCurrent[(mvControlled->TrainType & dt_EZT) ? 0 : 1], fHCurrent[2], fHCurrent[3]}, + ggLVoltage.GetValue(), + mvOccupied->DistCounter, + static_cast(RadioChannel()), + btLampkaSpringBrakeActive.GetValue(), + btLampkaNapNastHam.GetValue(), + mvOccupied->DirActive > 0, + mvOccupied->DirActive < 0, + mvOccupied->Doors.instances[mvOccupied->CabOccupied < 0 ? side::right : side::left].open_permit, + mvOccupied->Doors.instances[mvOccupied->CabOccupied < 0 ? side::right : side::left].is_open, + mvOccupied->Doors.instances[mvOccupied->CabOccupied < 0 ? side::left : side::right].open_permit, + mvOccupied->Doors.instances[mvOccupied->CabOccupied < 0 ? side::left : side::right].is_open, + mvOccupied->Doors.step_enabled, + mvOccupied->Power24vIsAvailable, + 0, + mvOccupied->LockPipe, + btLampkaRadioMessage.GetValue(), + }; } -bool TTrain::is_eztoer() const { +bool TTrain::is_eztoer() const +{ - return - ( ( mvControlled->TrainType == dt_EZT ) - && ( mvOccupied->BrakeSubsystem == TBrakeSubSystem::ss_ESt ) - && ( mvControlled->Power24vIsAvailable == true ) - && ( mvControlled->EpFuse == true ) - && ( mvControlled->DirActive != 0 ) ); // od yB + return ((mvControlled->TrainType == dt_EZT) && (mvOccupied->BrakeSubsystem == TBrakeSubSystem::ss_ESt) && (mvControlled->Power24vIsAvailable == true) && (mvControlled->EpFuse == true) && + (mvControlled->DirActive != 0)); // od yB } // mover master controller to specified position -void TTrain::set_master_controller( double const Position ) { +void TTrain::set_master_controller(double const Position) +{ - auto positionchange { - std::min( - Position, - ( mvControlled->CoupledCtrl ? - mvControlled->MainCtrlPosNo + mvControlled->ScndCtrlPosNo : - mvControlled->MainCtrlPosNo ) ) - - ( mvControlled->CoupledCtrl ? - mvControlled->MainCtrlPos + mvControlled->ScndCtrlPos : - mvControlled->MainCtrlPos ) }; - while( ( positionchange < 0 ) - && ( true == mvControlled->DecMainCtrl( 1 ) ) ) { - ++positionchange; - } - while( ( positionchange > 0 ) - && ( true == mvControlled->IncMainCtrl( 1 ) ) ) { - --positionchange; - } + auto positionchange{std::min(Position, (mvControlled->CoupledCtrl ? mvControlled->MainCtrlPosNo + mvControlled->ScndCtrlPosNo : mvControlled->MainCtrlPosNo)) - + (mvControlled->CoupledCtrl ? mvControlled->MainCtrlPos + mvControlled->ScndCtrlPos : mvControlled->MainCtrlPos)}; + while ((positionchange < 0) && (true == mvControlled->DecMainCtrl(1))) + { + ++positionchange; + } + while ((positionchange > 0) && (true == mvControlled->IncMainCtrl(1))) + { + --positionchange; + } } // moves train brake lever to specified position, potentially emits switch sound if conditions are met -void TTrain::set_train_brake( double const Position ) { +void TTrain::set_train_brake(double const Position) +{ - auto const originalbrakeposition { static_cast( 100.0 * mvOccupied->fBrakeCtrlPos ) }; - mvOccupied->BrakeLevelSet( Position ); + auto const originalbrakeposition{static_cast(100.0 * mvOccupied->fBrakeCtrlPos)}; + mvOccupied->BrakeLevelSet(Position); - if( static_cast( 100.0 * mvOccupied->fBrakeCtrlPos ) == originalbrakeposition ) { return; } + if (static_cast(100.0 * mvOccupied->fBrakeCtrlPos) == originalbrakeposition) + { + return; + } - if( ( true == is_eztoer() ) - && ( false == ( - ( ( originalbrakeposition / 100 == 0 ) || ( originalbrakeposition / 100 >= 5 ) ) - && ( ( mvOccupied->BrakeCtrlPos == 0 ) || ( mvOccupied->BrakeCtrlPos >= 5 ) ) ) ) ) { - // sound feedback if the lever movement activates one of the switches - if( dsbPneumaticSwitch ) { - dsbPneumaticSwitch->play(); - } - } + if ((true == is_eztoer()) && (false == (((originalbrakeposition / 100 == 0) || (originalbrakeposition / 100 >= 5)) && ((mvOccupied->BrakeCtrlPos == 0) || (mvOccupied->BrakeCtrlPos >= 5))))) + { + // sound feedback if the lever movement activates one of the switches + if (dsbPneumaticSwitch) + { + dsbPneumaticSwitch->play(); + } + } } -void TTrain::zero_charging_train_brake() { +void TTrain::zero_charging_train_brake() +{ - if( ( mvOccupied->BrakeCtrlPos == -1 ) - && ( DynamicObject->Controller != AIdriver ) - && ( Global.iFeedbackMode < 3 ) - && ( ( mvOccupied->BrakeHandle == TBrakeHandle::FVel6 ) - || ( mvOccupied->BrakeHandle == TBrakeHandle::MHZ_EN57 ) - || ( mvOccupied->BrakeHandle == TBrakeHandle::MHZ_K8P ) ) ) { - // Odskakiwanie hamulce EP - set_train_brake( 0 ); - } + if ((mvOccupied->BrakeCtrlPos == -1) && (DynamicObject->Controller != AIdriver) && (Global.iFeedbackMode < 3) && + ((mvOccupied->BrakeHandle == TBrakeHandle::FVel6) || (mvOccupied->BrakeHandle == TBrakeHandle::MHZ_EN57) || (mvOccupied->BrakeHandle == TBrakeHandle::MHZ_K8P))) + { + // Odskakiwanie hamulce EP + set_train_brake(0); + } } -void TTrain::set_train_brake_speed( TDynamicObject *Vehicle, int const Speed ) { +void TTrain::set_train_brake_speed(TDynamicObject *Vehicle, int const Speed) +{ - if( true == Vehicle->MoverParameters->BrakeDelaySwitch( Speed ) ) { - // visual feedback - // TODO: add setting indicator to vehicle class, for external lever/indicator - if( Vehicle == DynamicObject ) { - if( ggBrakeProfileCtrl.SubModel != nullptr ) { - ggBrakeProfileCtrl.UpdateValue( - ( ( mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? - 2.0 : - mvOccupied->BrakeDelayFlag - 1 ), - dsbSwitch ); - } - if( ggBrakeProfileG.SubModel != nullptr ) { - ggBrakeProfileG.UpdateValue( - ( mvOccupied->BrakeDelayFlag == bdelay_G ? - 1.0 : - 0.0 ), - dsbSwitch ); - } - if( ggBrakeProfileR.SubModel != nullptr ) { - ggBrakeProfileR.UpdateValue( - ( ( mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? - 1.0 : - 0.0 ), - dsbSwitch ); - } - } - } + if (true == Vehicle->MoverParameters->BrakeDelaySwitch(Speed)) + { + // visual feedback + // TODO: add setting indicator to vehicle class, for external lever/indicator + if (Vehicle == DynamicObject) + { + if (ggBrakeProfileCtrl.SubModel != nullptr) + { + ggBrakeProfileCtrl.UpdateValue(((mvOccupied->BrakeDelayFlag & bdelay_R) != 0 ? 2.0 : mvOccupied->BrakeDelayFlag - 1), dsbSwitch); + } + if (ggBrakeProfileG.SubModel != nullptr) + { + ggBrakeProfileG.UpdateValue((mvOccupied->BrakeDelayFlag == bdelay_G ? 1.0 : 0.0), dsbSwitch); + } + if (ggBrakeProfileR.SubModel != nullptr) + { + ggBrakeProfileR.UpdateValue(((mvOccupied->BrakeDelayFlag & bdelay_R) != 0 ? 1.0 : 0.0), dsbSwitch); + } + } + } } -void TTrain::set_paired_open_motor_connectors_button( bool const State ) { +void TTrain::set_paired_open_motor_connectors_button(bool const State) +{ - if( ( mvControlled->TrainType == dt_ET41 ) - || ( mvControlled->TrainType == dt_ET42 ) ) { - // crude implementation of the button affecting entire unit for multi-unit engines - // TODO: rework it into part of standard command propagation system - if( ( mvControlled->Couplers[ end::front ].Connected != nullptr ) - && ( true == TestFlag( mvControlled->Couplers[ end::front ].CouplingFlag, coupling::permanent ) ) ) { - mvControlled->Couplers[ end::front ].Connected->StLinSwitchOff = State; - } - if( ( mvControlled->Couplers[ end::rear ].Connected != nullptr ) - && ( true == TestFlag( mvControlled->Couplers[ end::rear ].CouplingFlag, coupling::permanent ) ) ) { - mvControlled->Couplers[ end::rear ].Connected->StLinSwitchOff = State; - } - } + if ((mvControlled->TrainType == dt_ET41) || (mvControlled->TrainType == dt_ET42)) + { + // crude implementation of the button affecting entire unit for multi-unit engines + // TODO: rework it into part of standard command propagation system + if ((mvControlled->Couplers[end::front].Connected != nullptr) && (true == TestFlag(mvControlled->Couplers[end::front].CouplingFlag, coupling::permanent))) + { + mvControlled->Couplers[end::front].Connected->StLinSwitchOff = State; + } + if ((mvControlled->Couplers[end::rear].Connected != nullptr) && (true == TestFlag(mvControlled->Couplers[end::rear].CouplingFlag, coupling::permanent))) + { + mvControlled->Couplers[end::rear].Connected->StLinSwitchOff = State; + } + } } // locates nearest vehicle belonging to the consist -TDynamicObject * -TTrain::find_nearest_consist_vehicle(bool freefly, glm::vec3 pos) const { +TDynamicObject *TTrain::find_nearest_consist_vehicle(bool freefly, glm::vec3 pos) const +{ if (!freefly) return DynamicObject; - auto coupler { -2 }; // scan for vehicle, not any specific coupler - auto *vehicle{ DynamicObject->ABuScanNearestObject( pos, DynamicObject->GetTrack(), 1, 1500, coupler ) }; - if( vehicle == nullptr ) - vehicle = DynamicObject->ABuScanNearestObject( pos, DynamicObject->GetTrack(), -1, 1500, coupler ); - // TBD, TODO: perform owner test for the located vehicle - return vehicle; + auto coupler{-2}; // scan for vehicle, not any specific coupler + auto *vehicle{DynamicObject->ABuScanNearestObject(pos, DynamicObject->GetTrack(), 1, 1500, coupler)}; + if (vehicle == nullptr) + vehicle = DynamicObject->ABuScanNearestObject(pos, DynamicObject->GetTrack(), -1, 1500, coupler); + // TBD, TODO: perform owner test for the located vehicle + return vehicle; } - // command handlers -void TTrain::OnCommand_aidriverenable( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_aidriverenable(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { - // on press - if( Train->DynamicObject->Mechanik == nullptr ) { return; } + 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 ); - } + 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 ) { +void TTrain::OnCommand_aidriverdisable(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { - // on press + if (Command.action == GLFW_PRESS) + { + // on press - if( Train->DynamicObject->Mechanik ) - Train->DynamicObject->Mechanik->TakeControl( false ); - } + if (Train->DynamicObject->Mechanik) + Train->DynamicObject->Mechanik->TakeControl(false); + } } -auto const EU07_CONTROLLER_BASERETURNDELAY { 0.5f }; -auto const EU07_CONTROLLER_KEYBOARDETURNDELAY { 1.5f }; +auto const EU07_CONTROLLER_BASERETURNDELAY{0.5f}; +auto const EU07_CONTROLLER_KEYBOARDETURNDELAY{1.5f}; -void TTrain::OnCommand_jointcontrollerset( TTrain *Train, command_data const &Command ) { +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; - Train->mvOccupied->LocalBrakePosA = 0; - } - else { - Train->mvOccupied->LocalBrakePosA = ( - std::clamp( - 1.0 - ( Command.param1 * 2 ), - 0.0, 1.0 ) ); - 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 - } + 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{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 ) { +void TTrain::OnCommand_mastercontrollerincrease(TTrain *Train, command_data const &Command) +{ - if( Command.action != GLFW_RELEASE ) { - // on press or hold - if( ( Train->ggJointCtrl.SubModel != nullptr ) - && ( Train->mvOccupied->LocalBrakePosA > 0.0 ) ) { - 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; - } + 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 ) { +void TTrain::OnCommand_mastercontrollerincreasefast(TTrain *Train, command_data const &Command) +{ - if( Command.action != GLFW_RELEASE ) { - // on press or hold - if( ( Train->ggJointCtrl.SubModel != nullptr ) - && ( Train->mvOccupied->LocalBrakePosA > 0.0 ) ) { - 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; - } + 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 ) { +void TTrain::OnCommand_mastercontrollerdecrease(TTrain *Train, command_data const &Command) +{ - if( Command.action != GLFW_RELEASE ) { - // on press or hold - if( ( Train->ggJointCtrl.SubModel != nullptr ) - && ( Train->mvControlled->IsMainCtrlNoPowerPos() ) ) { - 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; - } + 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 ) { +void TTrain::OnCommand_mastercontrollerdecreasefast(TTrain *Train, command_data const &Command) +{ - if( Command.action != GLFW_RELEASE ) { - // on press or hold - if( ( Train->ggJointCtrl.SubModel != nullptr ) - && ( Train->mvControlled->IsMainCtrlNoPowerPos() ) ) { - 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; - } + 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 ) { +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 - } + 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_secondcontrollerincrease( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_DynamicBrakeControllerIncreaseFast(TTrain *Train, command_data const &Command) +{ + if (Command.action != GLFW_PRESS) + { + return; + } + if (false == Train->mvControlled->SplitEDPneumaticBrake) + { + return; + } - 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 ); - } - } + Train->mvControlled->IncDynamicBrakeLevel(static_cast(Train->mvControlled->DynamicBrakeCtrlPosNo)); } -void TTrain::OnCommand_secondcontrollerincreasefast( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_DynamicBrakeControllerDecrease(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_RELEASE) + { + return; + } + if (false == Train->mvControlled->SplitEDPneumaticBrake) + { + return; + } - 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 ); - } - } + // step exactly one stop (1 / DBPN) per command, matching the discrete behaviour of jointctrl + Train->mvControlled->DecDynamicBrakeLevel(1.0f); } -void TTrain::OnCommand_notchingrelaytoggle( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_DynamicBrakeControllerDecreaseFast(TTrain *Train, command_data const &Command) +{ + if (Command.action != GLFW_PRESS) + { + return; + } + if (false == Train->mvControlled->SplitEDPneumaticBrake) + { + 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->AutoRelayFlag ) { - // turn on - Train->mvOccupied->AutoRelaySwitch( true ); - } - else { - //turn off - Train->mvOccupied->AutoRelaySwitch( false ); - } - } + Train->mvControlled->DecDynamicBrakeLevel(static_cast(Train->mvControlled->DynamicBrakeCtrlPosNo)); } -void TTrain::OnCommand_tempomattoggle( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_DynamicBrakeControllerSet(TTrain *Train, command_data const &Command) +{ + if (Command.action == GLFW_RELEASE) + { + return; + } + if (false == Train->mvControlled->SplitEDPneumaticBrake) + { + return; + } - 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 ); - } - } + // when input source uses raw 0..1 value, snap to nearest DBPN step + auto const target{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_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 +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 = 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->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 ); - } + } + } + 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 ) { +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 (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 ); - } + 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 ) { +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 ); - } - } - } + if ((Train->mvControlled->EngineType == TEngineType::DieselElectric) && (true == Train->mvControlled->ShuntMode)) + { + if (Command.action != GLFW_RELEASE) + { + Train->mvControlled->AnPos = 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 ) { +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 ); - } - } + 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 ) { +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 - ; - } - } + 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 ) { +void TTrain::OnCommand_independentbrakeincrease(TTrain *Train, command_data const &Command) +{ - if( Command.action != GLFW_RELEASE ) { + if (Command.action != GLFW_RELEASE) + { - if( Train->mvOccupied->LocalBrake != TLocalBrake::ManualBrake ) { - if( ( Train->ggJointCtrl.SubModel != nullptr ) - && ( Train->mvOccupied->MainCtrlPos > 0 ) ) { - OnCommand_mastercontrollerdecrease( Train, Command ); - } - else { - Train->mvOccupied->IncLocalBrakeLevel( (Train->ggJointCtrl.SubModel == nullptr) ? - (Global.brake_speed * Command.time_delta * LocalBrakePosNo) : 1 ); - if( Train->ggJointCtrl.SubModel != nullptr ) { - Train->m_mastercontrollerinuse = true; - } - } - } - } + // 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 ) { +void TTrain::OnCommand_independentbrakeincreasefast(TTrain *Train, command_data const &Command) +{ - if( Command.action != GLFW_RELEASE ) { + if (Command.action != GLFW_RELEASE) + { - if( Train->mvOccupied->LocalBrake != TLocalBrake::ManualBrake ) { - if( ( Train->ggJointCtrl.SubModel != nullptr ) - && ( Train->mvOccupied->MainCtrlPos > 0 ) ) { - OnCommand_mastercontrollerdecreasefast( Train, Command ); - } - else { - Train->mvOccupied->IncLocalBrakeLevel( LocalBrakePosNo ); - if( Train->ggJointCtrl.SubModel != nullptr ) { - Train->m_mastercontrollerinuse = true; - } - } - } - } + 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 ) { +void TTrain::OnCommand_independentbrakedecrease(TTrain *Train, command_data const &Command) +{ - if( Command.action != GLFW_RELEASE ) { + if (Command.action != GLFW_RELEASE) + { - 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( ( Train->ggJointCtrl.SubModel != nullptr ) - && ( Train->mvOccupied->LocalBrakePosA == 0.0 ) ) { - OnCommand_mastercontrollerincrease( Train, Command ); - } - else { - Train->mvOccupied->DecLocalBrakeLevel( - (Train->ggJointCtrl.SubModel == nullptr) ? - (Global.brake_speed * Command.time_delta * LocalBrakePosNo) : 1); - if( Train->ggJointCtrl.SubModel != nullptr ) { - Train->m_mastercontrollerinuse = true; - } - } - } - } + 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 ) { +void TTrain::OnCommand_independentbrakedecreasefast(TTrain *Train, command_data const &Command) +{ - if( Command.action != GLFW_RELEASE ) { + if (Command.action != GLFW_RELEASE) + { - 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( ( Train->ggJointCtrl.SubModel != nullptr ) - && ( Train->mvOccupied->LocalBrakePosA == 0.0 ) ) { - OnCommand_mastercontrollerincreasefast( Train, Command ); - } - else { - Train->mvOccupied->DecLocalBrakeLevel( LocalBrakePosNo ); - if( Train->ggJointCtrl.SubModel != nullptr ) { - Train->m_mastercontrollerinuse = true; - } - } - } - } + 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 ) { +void TTrain::OnCommand_independentbrakeset(TTrain *Train, command_data const &Command) +{ - if( Command.action != GLFW_RELEASE ) { + 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, - std::clamp( - Command.param1, - 0.0, 1.0 ) ) ) ); -*/ + Train->mvOccupied->LocalBrakePosA = (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 ) { +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 (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) { + if (Command.action == GLFW_PRESS) + { // press or hold // visual feedback - Train->ggUniveralBrakeButton1.UpdateValue(1.0, Train->dsbSwitch); + Train->ggReleaserButton.UpdateValue(1.0, Train->dsbSwitch); - Train->mvOccupied->UniversalBrakeButton(0,1); + Train->mvOccupied->BrakeReleaser(1); } - else if (Command.action == GLFW_RELEASE) { + else if (Command.action == GLFW_RELEASE) + { // release // visual feedback - Train->ggUniveralBrakeButton1.UpdateValue(0.0, Train->dsbSwitch); + Train->ggReleaserButton.UpdateValue(0.0, Train->dsbSwitch); - Train->mvOccupied->UniversalBrakeButton(0,0); + 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_universalbrakebutton2(TTrain *Train, command_data const &Command) { +void TTrain::OnCommand_universalbrakebutton1(TTrain *Train, command_data const &Command) +{ - if (Command.action == GLFW_PRESS) { + 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) { + else if (Command.action == GLFW_RELEASE) + { // release // visual feedback Train->ggUniveralBrakeButton2.UpdateValue(0.0, Train->dsbSwitch); @@ -1672,16 +1934,19 @@ void TTrain::OnCommand_universalbrakebutton2(TTrain *Train, command_data const & } } -void TTrain::OnCommand_universalbrakebutton3(TTrain *Train, command_data const &Command) { +void TTrain::OnCommand_universalbrakebutton3(TTrain *Train, command_data const &Command) +{ - if (Command.action == GLFW_PRESS) { + 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) { + else if (Command.action == GLFW_RELEASE) + { // release // visual feedback Train->ggUniveralBrakeButton3.UpdateValue(0.0, Train->dsbSwitch); @@ -1690,557 +1955,680 @@ void TTrain::OnCommand_universalbrakebutton3(TTrain *Train, command_data const & } } -void TTrain::OnCommand_trainbrakeincrease( TTrain *Train, command_data const &Command ) { +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 ); + 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 ); + Train->set_train_brake(Train->mvOccupied->fBrakeCtrlPos + Global.fBrakeStep); } -void TTrain::OnCommand_trainbrakedecrease( TTrain *Train, command_data const &Command ) { +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 ); + 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(); - } + 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 ) { +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(); - } + if (Command.action != GLFW_RELEASE) + { + // press or hold + Train->mvOccupied->BrakeLevelSet(interpolate(Train->mvOccupied->Handle->GetPos(bh_MIN), Train->mvOccupied->Handle->GetPos(bh_MAX), clamp(Command.param1, 0.0, 1.0))); + } + else + { + // release + Train->zero_charging_train_brake(); + } } -void TTrain::OnCommand_trainbrakecharging( TTrain *Train, command_data const &Command ) { +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(); - } + 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 ) { +void TTrain::OnCommand_trainbrakerelease(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + if (Command.action == GLFW_PRESS) + { - Train->set_train_brake( 0 ); - } + Train->set_train_brake(0); + } } -void TTrain::OnCommand_trainbrakefirstservice( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_trainbrakefirstservice(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + if (Command.action == GLFW_PRESS) + { - Train->set_train_brake( 1 ); - } + Train->set_train_brake(1); + } } -void TTrain::OnCommand_trainbrakeservice( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_trainbrakeservice(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + if (Command.action == GLFW_PRESS) + { - Train->set_train_brake( ( - Train->mvOccupied->BrakeCtrlPosNo / 2 - + ( Train->mvOccupied->BrakeHandle == TBrakeHandle::FV4a ? - 1 : - 0 ) ) ); - } + 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 ) { +void TTrain::OnCommand_trainbrakefullservice(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + if (Command.action == GLFW_PRESS) + { - Train->set_train_brake( Train->mvOccupied->BrakeCtrlPosNo - 1 ); - } + Train->set_train_brake(Train->mvOccupied->BrakeCtrlPosNo - 1); + } } -void TTrain::OnCommand_trainbrakehandleoff( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_trainbrakehandleoff(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + if (Command.action == GLFW_PRESS) + { - Train->set_train_brake( Train->mvOccupied->Handle->GetPos( bh_NP ) ); - } + Train->set_train_brake(Train->mvOccupied->Handle->GetPos(bh_NP)); + } } -void TTrain::OnCommand_trainbrakeemergency( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_trainbrakeemergency(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + 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; - } -*/ - } + 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 ) { +void TTrain::OnCommand_trainbrakebasepressureincrease(TTrain *Train, command_data const &Command) +{ - if( Command.action != GLFW_RELEASE ) { + 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; - } - } - } + switch (Train->mvOccupied->BrakeHandle) + { + case TBrakeHandle::FV4a: + { + Train->mvOccupied->BrakeCtrlPos2 = 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 ) { +void TTrain::OnCommand_trainbrakebasepressuredecrease(TTrain *Train, command_data const &Command) +{ - if( Command.action != GLFW_RELEASE ) { + 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; - } - } - } + switch (Train->mvOccupied->BrakeHandle) + { + case TBrakeHandle::FV4a: + { + Train->mvOccupied->BrakeCtrlPos2 = 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 ) { +void TTrain::OnCommand_trainbrakebasepressurereset(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + if (Command.action == GLFW_PRESS) + { - Train->mvOccupied->BrakeCtrlPos2 = 0; - } + Train->mvOccupied->BrakeCtrlPos2 = 0; + } } -void TTrain::OnCommand_trainbrakeoperationtoggle( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_trainbrakeoperationtoggle(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + if (Command.action == GLFW_PRESS) + { - auto *vehicle { Train->find_nearest_consist_vehicle(Command.freefly, Command.location) }; - if( vehicle == nullptr ) { return; } + 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 ); - } + vehicle->MoverParameters->Hamulec->SetBrakeStatus(vehicle->MoverParameters->Hamulec->GetBrakeStatus() ^ b_dmg); + } } -void TTrain::OnCommand_manualbrakeincrease( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_manualbrakeincrease(TTrain *Train, command_data const &Command) +{ - if( Command.action != GLFW_RELEASE ) { + if (Command.action != GLFW_RELEASE) + { - auto *vehicle { Train->find_nearest_consist_vehicle(Command.freefly, Command.location) }; - if( vehicle == nullptr ) { return; } + 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 ) ) { + if ((vehicle->MoverParameters->LocalBrake == TLocalBrake::ManualBrake) || (vehicle->MoverParameters->MBrake == true)) + { - vehicle->MoverParameters->IncManualBrakeLevel( 1 ); - } - } + vehicle->MoverParameters->IncManualBrakeLevel(1); + } + } } -void TTrain::OnCommand_manualbrakedecrease( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_manualbrakedecrease(TTrain *Train, command_data const &Command) +{ - if( Command.action != GLFW_RELEASE ) { + if (Command.action != GLFW_RELEASE) + { - auto *vehicle { Train->find_nearest_consist_vehicle(Command.freefly, Command.location) }; - if( vehicle == nullptr ) { return; } + 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 ) ) { + if ((vehicle->MoverParameters->LocalBrake == TLocalBrake::ManualBrake) || (vehicle->MoverParameters->MBrake == true)) + { - vehicle->MoverParameters->DecManualBrakeLevel( 1 ); - } - } + vehicle->MoverParameters->DecManualBrakeLevel(1); + } + } } -void TTrain::OnCommand_alarmchaintoggle( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_alarmchaintoggle(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + if (Command.action == GLFW_PRESS) + { - if( false == Train->mvOccupied->AlarmChainFlag ) { - OnCommand_alarmchainenable(Train, Command); - } - else { - OnCommand_alarmchaindisable(Train, Command); - } - } + 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) { + if (Command.action == GLFW_PRESS) + { - // pull - Train->mvOccupied->AlarmChainSwitch(true); - // visual feedback - Train->ggAlarmChain.UpdateValue(1.0); - } + // 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) + { -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); - } + // release + Train->mvOccupied->AlarmChainSwitch(false); + // visual feedback + Train->ggAlarmChain.UpdateValue(0.0); + } } -void TTrain::OnCommand_wheelspinbrakeactivate( TTrain *Train, command_data const &Command ) { +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; - } + // 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 ); + 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 ); + // 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 ); + 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 ); - } - } + Train->mvOccupied->SwitchEPBrake(0); + } + } } -void TTrain::OnCommand_sandboxactivate( TTrain *Train, command_data const &Command ) { +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; - } + // 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 ); + 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(true); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggSandButton.UpdateValue(0.0); - Train->mvControlled->SandboxManual( false ); - } + Train->mvControlled->SandboxManual(false); + } } -void TTrain::OnCommand_autosandboxtoggle(TTrain *Train, command_data const &Command) { +void TTrain::OnCommand_autosandboxtoggle(TTrain *Train, command_data const &Command) +{ - if (Command.action == GLFW_PRESS) { + 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) { + if (false == Train->mvOccupied->SandDoseAutoAllow) + { // turn on OnCommand_autosandboxactivate(Train, Command); } - else { - //turn off + else + { + // turn off OnCommand_autosandboxdeactivate(Train, Command); } } }; -void TTrain::OnCommand_autosandboxactivate(TTrain *Train, command_data const &Command) { - if (Command.action == GLFW_PRESS) { +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) { +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_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_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_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_brakeactingspeeddecrease( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_epbrakecontroltoggle(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + if (Command.action == GLFW_REPEAT) + { + return; + } - auto *vehicle { Train->find_nearest_consist_vehicle(Command.freefly, Command.location) }; - if( vehicle == nullptr ) { 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( 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 ); - } + 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_brakeactingspeedsetcargo( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_trainbrakeoperationmodeincrease(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 ); - } + 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_brakeactingspeedsetpassenger( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_trainbrakeoperationmodedecrease(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 ); - } + 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_brakeactingspeedsetrapid( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_brakeactingspeedincrease(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + if (Command.action == GLFW_PRESS) + { - auto *vehicle{ Train->find_nearest_consist_vehicle(Command.freefly, Command.location) }; - if( vehicle == nullptr ) { return; } + auto *vehicle{Train->find_nearest_consist_vehicle(Command.freefly, Command.location)}; + if (vehicle == nullptr) + { + return; + } - Train->set_train_brake_speed( vehicle, bdelay_R ); - } + 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_brakeloadcompensationincrease( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_brakeactingspeeddecrease(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(); - } - } + 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_brakeloadcompensationdecrease( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_brakeactingspeedsetcargo(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(); - } - } + 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_mubrakingindicatortoggle( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_brakeactingspeedsetpassenger(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) + { - 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 ); - } - } + 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) @@ -2251,7 +2639,7 @@ void TTrain::OnCommand_wiperswitchincrease(TTrain *Train, command_data const &Co if (Train->mvOccupied->wiperSwitchPos > Train->mvOccupied->WiperListSize - 1) Train->mvOccupied->wiperSwitchPos = Train->mvOccupied->WiperListSize - 1; - // Visual feedback + // Visual feedback Train->ggWiperSw.UpdateValue(Train->mvOccupied->wiperSwitchPos, Train->dsbSwitch); } } @@ -2263,211 +2651,261 @@ void TTrain::OnCommand_wiperswitchdecrease(TTrain *Train, command_data const &Co if (Train->mvOccupied->wiperSwitchPos < 0) Train->mvOccupied->wiperSwitchPos = 0; - // visual feedback - Train->ggWiperSw.UpdateValue(Train->mvOccupied->wiperSwitchPos, Train->dsbSwitch); + // visual feedback + Train->ggWiperSw.UpdateValue(Train->mvOccupied->wiperSwitchPos, Train->dsbSwitch); } } -void TTrain::OnCommand_reverserincrease( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_reverserincrease(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + 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: 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 ) ) { + if (Train->mvOccupied->DirectionForward()) + { + // aktualizacja skrajnych pojazdów w składzie + if ((Train->mvOccupied->DirActive) && (Train->DynamicObject->Mechanik)) + { - Train->DynamicObject->Mechanik->DirectionChange(); - } - } - } + Train->DynamicObject->Mechanik->DirectionChange(); + } + } + } } -void TTrain::OnCommand_reverserdecrease( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_reverserdecrease(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + 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: 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 ) ) { + if (Train->mvOccupied->DirectionBackward()) + { + // aktualizacja skrajnych pojazdów w składzie + if ((Train->mvOccupied->DirActive) && (Train->DynamicObject->Mechanik)) + { - Train->DynamicObject->Mechanik->DirectionChange();; - } - } - } + Train->DynamicObject->Mechanik->DirectionChange(); + ; + } + } + } } -void TTrain::OnCommand_reverserforwardhigh( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_reverserforwardhigh(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + 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: 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 ); + // 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 ) { + 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 ) ) { + 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 ); - } + Train->DynamicObject->Mechanik->DirectionChange(); + } + } + OnCommand_reverserincrease(Train, Command); + } } -void TTrain::OnCommand_reverserforward( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_reverserforward(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + 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: 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 ); + // 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 ) { + 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 ) ) { + 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) { + 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 ) { +void TTrain::OnCommand_reverserneutral(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + 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: 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) { + 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 ) { +void TTrain::OnCommand_reverserbackward(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + 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 ) { + // 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 ) ) { + 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) { + 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 ); +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) + 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 ); + } + else if (Command.action == GLFW_RELEASE) + { + // visual feedback + Train->ggSecurityResetButton.UpdateValue(0.0); - if (Train->mvOccupied->TrainType == dt_EZT || Train->mvOccupied->DirActive != 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 ) { +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 ); - } + 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 ) +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 ); - } - } + // 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 ) { +void TTrain::OnCommand_batteryenable(TTrain *Train, command_data const &Command) +{ if (!Train->mvOccupied->isBatteryButtonImpulse) { // regular button behavior if (Command.action == GLFW_PRESS) @@ -2494,43 +2932,42 @@ void TTrain::OnCommand_batteryenable( TTrain *Train, command_data const &Command Train->ggBatteryOnButton.UpdateValue(0.0f, Train->dsbSwitch); Train->allowBatteryToggle = true; } - } + } else // impulse button behavior { - if (Command.action == GLFW_PRESS) - { + if (Command.action == GLFW_PRESS) + { if (Train->mvOccupied->shouldHoldBatteryButton) { - // jesli przycisk trzeba przytrzymac + // 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 + } + else + { + // jesli przycisk dziala od razu Train->mvOccupied->BatterySwitch(true); Train->allowBatteryToggle = false; - // side-effects + // side-effects if (Train->mvOccupied->LightsPosNo > 0) { Train->Dynamic()->SetLights(); } - // visual feedback + // visual feedback Train->ggBatteryButton.UpdateValue(1.0f, Train->dsbSwitch); Train->ggBatteryOnButton.UpdateValue(1.0f, Train->dsbSwitch); - } - } + } + } else if (Command.action == GLFW_RELEASE) { - // visual feedback + // visual feedback Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); Train->ggBatteryOnButton.UpdateValue(0.0f, Train->dsbSwitch); - Train->fBatteryTimer = -1.f; // - Train->allowBatteryToggle = true; + Train->fBatteryTimer = -1.f; // + Train->allowBatteryToggle = true; Train->mvOccupied->batterySwAlreadyFired = false; - } else if (Command.action == GLFW_REPEAT && Train->mvOccupied->shouldHoldBatteryButton) { @@ -2551,7 +2988,8 @@ void TTrain::OnCommand_batteryenable( TTrain *Train, command_data const &Command } } -void TTrain::OnCommand_batterydisable( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_batterydisable(TTrain *Train, command_data const &Command) +{ if (!Train->mvOccupied->isBatteryButtonImpulse) { // regular button behavior if (Command.action == GLFW_PRESS) @@ -2610,7 +3048,7 @@ void TTrain::OnCommand_batterydisable( TTrain *Train, command_data const &Comman // visual feedback Train->ggBatteryButton.UpdateValue(0.0f, Train->dsbSwitch); Train->ggBatteryOffButton.UpdateValue(0.0f, Train->dsbSwitch); - Train->allowBatteryToggle = true; + Train->allowBatteryToggle = true; Train->mvOccupied->batterySwAlreadyFired = false; } else if (Command.action == GLFW_REPEAT && Train->mvOccupied->shouldHoldBatteryButton) @@ -2629,427 +3067,495 @@ void TTrain::OnCommand_batterydisable( TTrain *Train, command_data const &Comman Train->allowBatteryToggle = false; } } - } } -void TTrain::OnCommand_cabactivationtoggle(TTrain *Train, command_data const &Command) { +void TTrain::OnCommand_cabactivationtoggle(TTrain *Train, command_data const &Command) +{ - if (Command.action != GLFW_REPEAT) { + if (Command.action != GLFW_REPEAT) + { // keep the switch from flipping back and forth if key is held down - if (0 == Train->mvOccupied->CabActive) { + if (0 == Train->mvOccupied->CabActive) + { // turn on OnCommand_cabactivationenable(Train, Command); } - else { - //turn off + else + { + // turn off OnCommand_cabactivationdisable(Train, Command); } } } -void TTrain::OnCommand_cabactivationenable(TTrain *Train, command_data const &Command) { +void TTrain::OnCommand_cabactivationenable(TTrain *Train, command_data const &Command) +{ - if (Command.action == GLFW_PRESS) { + if (Command.action == GLFW_PRESS) + { // visual feedback - if (Train->ggCabActivationButton.type() == TGaugeType::push) { + if (Train->ggCabActivationButton.type() == TGaugeType::push) + { Train->ggCabActivationButton.UpdateValue(1.0f, Train->dsbSwitch); } Train->mvOccupied->CabActivisation(); // side-effects - if (Train->mvOccupied->LightsPosNo > 0) { + if (Train->mvOccupied->LightsPosNo > 0) + { Train->Dynamic()->SetLights(); } } - else if (Command.action == GLFW_RELEASE) { - if (Train->ggCabActivationButton.type() == TGaugeType::push) { + 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) { +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) { + if (Command.action == GLFW_PRESS) + { // visual feedback - if (Train->ggCabActivationButton.type() == TGaugeType::push) { + 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)) { + 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) { + 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 ) { +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; } + // 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 ) ); - } - } + 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 ) { +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; } + // 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 ) ); - } - } + 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 ) { +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; } + // 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 ); - } + 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 ) { +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; } + // 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 ); - } + 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 ) { +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; - } + // 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 ); - } + 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 ) { +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; } + // 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 ((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 ); - } + 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 ) { +void TTrain::OnCommand_pantographlowerall(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_REPEAT ) { return; } + 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.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 ); - } + 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 ) { +void TTrain::OnCommand_pantographselectnext(TTrain *Train, command_data const &Command) +{ - if( Command.action != GLFW_PRESS ) { return; } + if (Command.action != GLFW_PRESS) + { + return; + } - if( false == Train->m_controlmapper.contains( "pantselect_sw:" ) ) { return; } + if (false == Train->m_controlmapper.contains("pantselect_sw:")) + { + return; + } - Train->change_pantograph_selection( 1 ); + Train->change_pantograph_selection(1); } -void TTrain::OnCommand_pantographselectprevious( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_pantographselectprevious(TTrain *Train, command_data const &Command) +{ - if( Command.action != GLFW_PRESS ) { return; } + if (Command.action != GLFW_PRESS) + { + return; + } - if( false == Train->m_controlmapper.contains( "pantselect_sw:" ) ) { return; } + if (false == Train->m_controlmapper.contains("pantselect_sw:")) + { + return; + } - Train->change_pantograph_selection( -1 ); + Train->change_pantograph_selection(-1); } -void TTrain::OnCommand_pantographtoggleselected( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_pantographtoggleselected(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_REPEAT ) { return; } + if (Command.action == GLFW_REPEAT) + { + return; + } - if( Command.action == GLFW_PRESS ) { - // recalculate pantograph state (hujhujhuj) + 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 ); - } - } - } + // 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 ) { +void TTrain::OnCommand_pantographraiseselected(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_REPEAT ) { return; } + 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 ); - } + 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 ) { +void TTrain::OnCommand_pantographlowerselected(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_REPEAT ) { return; } + 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 ); - } + 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() { +void TTrain::update_pantograph_valves() +{ - auto const &presets { mvOccupied->PantsPreset.first }; - auto &selection { mvOccupied->PantsPreset.second[ cab_to_end() ] }; + 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 ) ); + 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 ) { +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 ) ); + auto const &presets{mvOccupied->PantsPreset.first}; + auto &selection{mvOccupied->PantsPreset.second[cab_to_end()]}; + auto const initialstate{selection}; + selection = clamp(selection + Change, 0, std::max(presets.size() - 1, 0)); - if( selection == initialstate ) { return; } // no change, nothing to do + 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(); - } + // 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 ) { +void TTrain::OnCommand_pantographvalvesupdate(TTrain *Train, command_data const &Command) +{ - bool hasSeparateSwitches = Train->m_controlmapper.contains("pantvalvesupdate_bt:") && - Train->m_controlmapper.contains("pantvalvesoff_bt:"); + bool hasSeparateSwitches = Train->m_controlmapper.contains("pantvalvesupdate_bt:") && Train->m_controlmapper.contains("pantvalvesoff_bt:"); - if( Command.action == GLFW_REPEAT ) { return; } + if (Command.action == GLFW_REPEAT) + { + return; + } - if( Command.action == GLFW_PRESS ) { + if (Command.action == GLFW_PRESS) + { if (hasSeparateSwitches) { // implement action @@ -3059,1889 +3565,2331 @@ void TTrain::OnCommand_pantographvalvesupdate( TTrain *Train, command_data const } // Old logic to maintain compatibility - else - { + 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 + } + } + 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 + else Train->ggPantValvesButton.UpdateValue(0.5, Train->dsbSwitch); - } + } } -void TTrain::OnCommand_pantographvalvesoff( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_pantographvalvesoff(TTrain *Train, command_data const &Command) +{ - bool hasSeparateSwitches = Train->m_controlmapper.contains("pantvalvesupdate_bt:") && Train->m_controlmapper.contains("pantvalvesoff_bt:"); + bool hasSeparateSwitches = Train->m_controlmapper.contains("pantvalvesupdate_bt:") && Train->m_controlmapper.contains("pantvalvesoff_bt:"); - if( Command.action == GLFW_REPEAT ) { return; } + 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 (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 + 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 ); - } + Train->ggPantValvesButton.UpdateValue(0.5, Train->dsbSwitch); + } } -void TTrain::OnCommand_pantographcompressorvalvetoggle( TTrain *Train, command_data const &Command ) { +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 ); - } - } + 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 ) { +void TTrain::OnCommand_pantographcompressorvalveenable(TTrain *Train, command_data const &Command) +{ - auto const valveispresent { - ( Train->ggPantCompressorValve.SubModel != nullptr ) - || ( ( Train->mvOccupied == Train->mvPantographUnit ) - && ( Train->iCabn == 0 ) ) }; + 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 (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 ); - } + 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 ) { +void TTrain::OnCommand_pantographcompressorvalvedisable(TTrain *Train, command_data const &Command) +{ - auto const valveispresent { - ( Train->ggPantCompressorValve.SubModel != nullptr ) - || ( ( Train->mvOccupied == Train->mvPantographUnit ) - && ( Train->iCabn == 0 ) ) }; + 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 (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 ); - } + 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 - +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 - if (Train->ggCompressorListButton.SubModel != nullptr) { + 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_compressorpresetactivatedefault(TTrain *Train, command_data const &Command) { +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->mvOccupied->CompressorListPosNo == 0) + { + return; + } + if (Command.action != GLFW_PRESS) + { + return; + } // one change per key press - Train->mvOccupied->ChangeCompressorPreset( Train->mvOccupied->CompressorListDefPos ); + if (Train->ggCompressorListButton.type() == TGaugeType::push) + { + // impulse switch toggles only between positions 'default' and 'default+1' + return; + } - // visual feedback - if (Train->ggCompressorListButton.SubModel != nullptr) { + 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_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 ) +void TTrain::OnCommand_compressorpresetactivatedefault(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 ); - } - } + + 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_motoroverloadrelaythresholdsetlow( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_motorblowerstogglefront(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 ); - } + 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_motoroverloadrelaythresholdsethigh( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_motorblowersenablefront(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 ); - } + 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_motoroverloadrelayreset( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_motorblowersdisablefront(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_REPEAT) + { + 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 ); - } + 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_universalrelayreset( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_motorblowerstogglerear(TTrain *Train, command_data const &Command) +{ - auto const itemindex = static_cast( Command.command ) - static_cast( user_command::universalrelayreset1 ); - auto &item = Train->ggRelayResetButtons[ itemindex ]; + if (Command.action == GLFW_REPEAT) + { + return; + } - // 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 ); - } + 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_lightspresetactivatenext( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_motorblowersenablerear(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 (Command.action == GLFW_REPEAT) + { + 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 ); - } - } - } + 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_lightspresetactivateprevious( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_motorblowersdisablerear(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 (Command.action == GLFW_REPEAT) + { + 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 ); - } - } - } + 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_headlighttoggleleft( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_motorblowersdisableall(TTrain *Train, command_data const &Command) +{ - auto const vehicleend { Train->cab_to_end() }; + if (Command.action == GLFW_REPEAT) + { + 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->mvOccupied->iLights[ vehicleend ] & light::headlight_left ) == 0 ) { - // turn on - OnCommand_headlightenableleft( Train, Command ); - } - else { - //turn off - OnCommand_headlightdisableleft( Train, Command ); - } - } + 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 + // 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 ) { +void TTrain::OnCommand_headlightenableleft(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 (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; - } - } + 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 ) { +void TTrain::OnCommand_headlightdisableleft(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 (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 + 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 ); - } + 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 ) { +void TTrain::OnCommand_headlighttoggleright(TTrain *Train, command_data const &Command) +{ - auto const vehicleend { Train->cab_to_end() }; + 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 ); - } - } + 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 ) { +void TTrain::OnCommand_headlightenableright(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 (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; - } - } + 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 ) { +void TTrain::OnCommand_headlightdisableright(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 (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 + 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 ); - } + 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 ) { +void TTrain::OnCommand_headlighttoggleupper(TTrain *Train, command_data const &Command) +{ - auto const vehicleend { Train->cab_to_end() }; + 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 ); - } - } + 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 ) { +void TTrain::OnCommand_headlightenableupper(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 (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 + 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 ); - } + 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 ) { +void TTrain::OnCommand_headlightdisableupper(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 (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 + 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 ); - } + 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 ) { +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 (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 ); - } - } + 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 ) { +void TTrain::OnCommand_redmarkerenableleft(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 (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 + 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; - } - } + 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 ) { +void TTrain::OnCommand_redmarkerdisableleft(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 (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 + 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 ); - } - } + 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 ) { +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 (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 ); - } - } + 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 ) { +void TTrain::OnCommand_redmarkerenableright(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 (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 + 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; - } - } + 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 ) { +void TTrain::OnCommand_redmarkerdisableright(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 (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 + 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 ); - } - } + 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 ) { +void TTrain::OnCommand_headlighttogglerearleft(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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); - } - } + 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; - } +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 ); - } - } + 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;} +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 ); - } + // 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_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; - } +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 (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 ); - } - } + 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; - } +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; } + 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 ); - } + // 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 ) { +void TTrain::OnCommand_headlighttogglerearupper(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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); - } - } + 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 ) { +void TTrain::OnCommand_headlightenablerearupper(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 ); - } - } + 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 ) { +void TTrain::OnCommand_headlightdisablerearupper(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 ; } + 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 ); - } + // 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) +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 + if (Command.action == GLFW_PRESS) + { + // update modern dimmer state - auto &dimPos = Train->mvOccupied->modernDimmerPosition; + auto &dimPos = Train->mvOccupied->modernDimmerPosition; auto dimCount = Train->mvOccupied->dimPositions.size(); if (dimPos + 1 < dimCount) dimPos++; @@ -4949,12 +5897,11 @@ void TTrain::OnCommand_modernlightdimmerincrease(TTrain* Train, command_data con dimPos = 0; // return to 0 else return; // już na minimum i nie można cyklicznie - // update lightning - //Train->Dynamic()->SetLights(); - Train->Dynamic()->SetLightDimmings(); + // update lightning + // Train->Dynamic()->SetLights(); + Train->Dynamic()->SetLightDimmings(); - - // visual feedback + // visual feedback if (Train->ggModernLightDimSw.SubModel != nullptr) Train->ggModernLightDimSw.UpdateValue(dimPos, Train->dsbSwitch); } @@ -4979,7 +5926,7 @@ void TTrain::OnCommand_modernlightdimmerdecrease(TTrain *Train, command_data con else return; // już na minimum i nie można cyklicznie - //Train->Dynamic()->SetLights(); + // Train->Dynamic()->SetLights(); Train->Dynamic()->SetLightDimmings(); if (Train->ggModernLightDimSw.SubModel != nullptr) @@ -4987,716 +5934,860 @@ void TTrain::OnCommand_modernlightdimmerdecrease(TTrain *Train, command_data con } } -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_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 ) { +void TTrain::OnCommand_redmarkerenablerearleft(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 ); - } - } + 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 ) { +void TTrain::OnCommand_redmarkerdisablerearleft(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 ); - } + 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 ) { +void TTrain::OnCommand_redmarkertogglerearright(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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); - } - } + 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 ) { +void TTrain::OnCommand_redmarkerenablerearright(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 ); - } - } + 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 ) { +void TTrain::OnCommand_redmarkerdisablerearright(TTrain *Train, command_data const &Command) +{ - if( Train->mvOccupied->LightsPosNo > 0 ) { - // lights are controlled by preset selector - return; - } + 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 ); - } + 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 ) { +void TTrain::OnCommand_redmarkerstoggle(TTrain *Train, command_data const &Command) +{ - if( ( true == Command.freefly ) - && ( Command.action == GLFW_PRESS ) ) { + if ((true == Command.freefly) && (Command.action == GLFW_PRESS)) + { - auto *vehicle { std::get( simulation::Region->find_vehicle( Command.location, 10, false, true ) ) }; + auto *vehicle{std::get(simulation::Region->find_vehicle(Command.location, 10, false, true))}; - if( vehicle == nullptr ) { return; } + if (vehicle == nullptr) + { + return; + } - auto locationHead = vehicle->HeadPosition() - glm::dvec3(Command.location); // TODO: Maybe command_data should be dvec3? + 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] + int const CouplNr{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 }; + 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 - } + 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 ) { +void TTrain::OnCommand_endsignalstoggle(TTrain *Train, command_data const &Command) +{ - if( ( true == Command.freefly ) - && ( Command.action == GLFW_PRESS ) ) { + if ((true == Command.freefly) && (Command.action == GLFW_PRESS)) + { - auto *vehicle { std::get( simulation::Region->find_vehicle( Command.location, 10, false, true ) ) }; + 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] + if (vehicle == nullptr) + { + return; + } + int const CouplNr{ + 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 }; + 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 - } + 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 ) { +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 (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 ); - } - } + // turn on + OnCommand_headlightsdimenable(Train, Command); + } + else + { + // turn off + OnCommand_headlightsdimdisable(Train, Command); + } + } } -void TTrain::OnCommand_headlightsdimenable( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_headlightsdimenable(TTrain *Train, command_data const &Command) +{ - if (Train->DynamicObject->MoverParameters->enableModernDimmer) + 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 + 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) + /* // 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->DynamicObject->DimHeadlights = true; - */ - Train->DynamicObject->MoverParameters->modernDimmerPosition = 1; // ustawiamy modern dimmer na flage przyciemnienia - Train->DynamicObject->SetLightDimmings(); - } + Train->InstrumentLightActive = true; + } } -void TTrain::OnCommand_headlightsdimdisable( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_instrumentlightdisable(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) { + 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) { + 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 + else + { + // turn off OnCommand_springbrakedisable(Train, Command); } } - else if (Command.action == GLFW_RELEASE) { + else if (Command.action == GLFW_RELEASE) + { // release // visual feedback Train->ggSpringBrakeOffButton.UpdateValue(0.0, Train->dsbSwitch); @@ -5704,154 +6795,190 @@ void TTrain::OnCommand_springbraketoggle(TTrain *Train, command_data const &Comm } }; -void TTrain::OnCommand_springbrakeenable(TTrain *Train, command_data const &Command) { - if (Command.action == GLFW_PRESS) { +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) { + 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) { +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) { + 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) { +void TTrain::OnCommand_springbrakeshutofftoggle(TTrain *Train, command_data const &Command) +{ - if (Command.action == GLFW_PRESS) { + 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) { + if (false == Train->mvOccupied->SpringBrake.ShuttOff) + { // turn on OnCommand_springbrakeshutoffenable(Train, Command); } - else { - //turn off + else + { + // turn off OnCommand_springbrakeshutoffdisable(Train, Command); } } }; -void TTrain::OnCommand_springbrakeshutoffenable(TTrain *Train, command_data const &Command) { - if (Command.action == GLFW_PRESS) { +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) { +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) { +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; } + 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) { +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) { + 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) { +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) { + 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) { +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) { + 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) { +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) { + 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) { +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) { + 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) { + 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) { +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) { + 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; @@ -5869,26 +6996,28 @@ void TTrain::OnCommand_inverterenable(TTrain *Train, command_data const &Command { 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) { + 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) { +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) { + 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; @@ -5906,26 +7035,28 @@ void TTrain::OnCommand_inverterdisable(TTrain *Train, command_data const &Comman { 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) { + 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) { +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) { + 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; @@ -5945,1495 +7076,1661 @@ void TTrain::OnCommand_invertertoggle(TTrain *Train, command_data const &Command { itemindex -= p->MoverParameters->InvertersNo; } - } p = (kier ? p->Next(flag) : p->Prev(flag)); } } }; -void TTrain::OnCommand_doorlocktoggle(TTrain *Train, command_data const &Command) { +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 (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 ); - } - } + 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 ) { +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 (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 ); - } + 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 ) { +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; } + 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 ) }; + auto const side{(Train->cab_to_end() == end::front ? side::left : side::right)}; - if( Command.action == GLFW_PRESS ) { + 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 ) }; + 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->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; - } - } + 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 ) { +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; } + 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 ) }; + auto const side{(Train->cab_to_end() == end::front ? side::right : side::left)}; - if( Command.action == GLFW_PRESS ) { + 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 ) }; + 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->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; - } - } + 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 ) { +void TTrain::OnCommand_doorpermitpresetactivatenext(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + if (Command.action == GLFW_PRESS) + { - Train->mvOccupied->ChangeDoorPermitPreset( 1 ); - // visual feedback - Train->ggDoorPermitPresetButton.UpdateValue( Train->mvOccupied->Doors.permit_preset, Train->dsbSwitch ); - } + 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 ) { +void TTrain::OnCommand_doorpermitpresetactivateprevious(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { + if (Command.action == GLFW_PRESS) + { - Train->mvOccupied->ChangeDoorPermitPreset( -1 ); - // visual feedback - Train->ggDoorPermitPresetButton.UpdateValue( Train->mvOccupied->Doors.permit_preset, Train->dsbSwitch ); - } + 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) +{ -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)}; - auto const remoteopencontrol { - ( Train->mvOccupied->Doors.open_control == control_t::driver ) - || ( Train->mvOccupied->Doors.open_control == control_t::mixed ) }; + if (false == remoteopencontrol) + { + return; + } - if( false == remoteopencontrol ) { return; } + if ((Train->ggDoorLeftOnButton.SubModel == nullptr) && (Train->ggDoorLeftButton.SubModel == nullptr)) + { - if( ( Train->ggDoorLeftOnButton.SubModel == nullptr ) - && ( Train->ggDoorLeftButton.SubModel == nullptr ) ) { + return; + } - 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 ); - } - } + 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 ) { +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 ) }; + auto const remoteclosecontrol{(Train->mvOccupied->Doors.close_control == control_t::driver) || (Train->mvOccupied->Doors.close_control == control_t::mixed)}; - if( false == remoteclosecontrol ) { return; } + if (false == remoteclosecontrol) + { + return; + } - if( ( Train->ggDoorLeftOffButton.SubModel == nullptr ) - && ( Train->ggDoorLeftButton.SubModel == nullptr ) ) { + if ((Train->ggDoorLeftOffButton.SubModel == nullptr) && (Train->ggDoorLeftButton.SubModel == nullptr)) + { - return; - } + return; + } - if( Command.action == GLFW_PRESS ) { + 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(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 ); - } + 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 ) { +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 (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 ); - } + 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 ) { +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 ) }; + auto const remoteopencontrol{(Train->mvOccupied->Doors.open_control == control_t::driver) || (Train->mvOccupied->Doors.open_control == control_t::mixed)}; - if( false == remoteopencontrol ) { return; } + if (false == remoteopencontrol) + { + return; + } - if( ( Train->ggDoorRightOnButton.SubModel == nullptr ) - && ( Train->ggDoorRightButton.SubModel == nullptr ) ) { + if ((Train->ggDoorRightOnButton.SubModel == nullptr) && (Train->ggDoorRightButton.SubModel == nullptr)) + { - return; - } + return; + } - if( Command.action == GLFW_PRESS ) { + 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 ); - } - } + 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 ) { +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 ) }; + auto const remoteclosecontrol{(Train->mvOccupied->Doors.close_control == control_t::driver) || (Train->mvOccupied->Doors.close_control == control_t::mixed)}; - if( false == remoteclosecontrol ) { return; } + if (false == remoteclosecontrol) + { + return; + } - if( ( Train->ggDoorRightOffButton.SubModel == nullptr ) - && ( Train->ggDoorRightButton.SubModel == nullptr ) ) { + if ((Train->ggDoorRightOffButton.SubModel == nullptr) && (Train->ggDoorRightButton.SubModel == nullptr)) + { - return; - } + return; + } - if( Command.action == GLFW_PRESS ) { + 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(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 ); - } + 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 ) { +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 ) }; + auto const remoteopencontrol{(Train->mvOccupied->Doors.open_control == control_t::driver) || (Train->mvOccupied->Doors.open_control == control_t::mixed)}; - if( false == remoteopencontrol ) { return; } + 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 (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 ) { + 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 ); - } + 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 ) { +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 ) }; + auto const remoteclosecontrol{(Train->mvOccupied->Doors.close_control == control_t::driver) || (Train->mvOccupied->Doors.close_control == control_t::mixed)}; - if( false == remoteclosecontrol ) { return; } + 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 (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 (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 ); - } + 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_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 ) { +void TTrain::OnCommand_doormodetoggle(TTrain *Train, command_data const &Command) +{ - if( Command.action == GLFW_PRESS ) { - Train->mvOccupied->ChangeDoorControlMode( false == Train->mvOccupied->Doors.remote_only ); - } + if (Command.action == GLFW_PRESS) + { + Train->mvOccupied->ChangeDoorControlMode(false == Train->mvOccupied->Doors.remote_only); + } } -void TTrain::OnCommand_mirrorstoggle(TTrain *Train, command_data const &Command) { +void TTrain::OnCommand_mirrorstoggle(TTrain *Train, command_data const &Command) +{ - if (Command.action != GLFW_PRESS) { return; } + if (Command.action != GLFW_PRESS) + { + return; + } -// only reacting to press, so the sound can loop uninterrupted - if (false == Train->mvOccupied->MirrorForbidden) { + // only reacting to press, so the sound can loop uninterrupted + if (false == Train->mvOccupied->MirrorForbidden) + { // turn on Train->mvOccupied->MirrorForbidden = true; } - else { + else + { // turn off Train->mvOccupied->MirrorForbidden = false; } } -void TTrain::OnCommand_nearestcarcouplingincrease( TTrain *Train, command_data const &Command ) { +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 ((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 ) ) { + if ((coupler != -1) && (vehicle != nullptr)) + { - vehicle->couple( coupler ); - } - if( Train->DynamicObject->Mechanik ) { - // aktualizacja flag kierunku w składzie - Train->DynamicObject->Mechanik->CheckVehicles( Connect ); - } - } + 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 ) { +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 ((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 ) ) { + if ((coupler != -1) && (vehicle != nullptr)) + { - vehicle->uncouple( coupler ); - } - if( Train->DynamicObject->Mechanik ) { - // aktualizacja flag kierunku w składzie - Train->DynamicObject->Mechanik->CheckVehicles( Disconnect ); - } - } + 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 ) { +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; } + 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 ); + 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 ); - } + vehicle->attach_coupler_adapter(coupler); + } } -void TTrain::OnCommand_nearestcarcoupleradapterremove( TTrain *Train, command_data const &Command ) { +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; } + 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 ); + 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 ); - } + 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) { +void TTrain::OnCommand_occupiedcarcouplingdisconnect(TTrain *Train, command_data const &Command) +{ // if( false == Train->m_controlmapper.contains( "couplingdisconnect_sw:" ) ) { return; } - if (Command.action == GLFW_PRESS) { + if (Command.action == GLFW_PRESS) + { // visual feedback - Train->m_couplingdisconnectback = true; + Train->m_couplingdisconnect = true; - if (Train->iCabn == 0) { return; } + if (Train->iCabn == 0) + { + return; + } - if (Train->DynamicObject) { - Train->DynamicObject->uncouple( 1 - Train->cab_to_end() ); - if (Train->DynamicObject->Mechanik) { + 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) { + 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 ) +void TTrain::OnCommand_departureannounce(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 ); + + if (Train->ggDepartureSignalButton.SubModel == nullptr) + { + if (Command.action == GLFW_PRESS) + { + WriteLog("Departure Signal button is missing, or wasn't defined"); + } + return; } - else if( Command.action == GLFW_RELEASE ) { + + 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->ggRadioCall1.UpdateValue( 0.0 ); + Train->ggDepartureSignalButton.UpdateValue(0.0, Train->dsbSwitch); } } -void TTrain::OnCommand_radiocall3send( TTrain *Train, command_data const &Command ) { +void TTrain::OnCommand_hornlowactivate(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 ); - } + 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_radiovolumeincrease(TTrain *Train, command_data const &Command) { +void TTrain::OnCommand_hornhighactivate(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); + 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() = 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) { + else if (Command.action == GLFW_RELEASE) + { // visual feedback Train->ggRadioVolumeNext.UpdateValue(0.0); } } -void TTrain::OnCommand_radiovolumedecrease(TTrain *Train, command_data const &Command) { +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); + 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) { + 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_radiovolumeset(TTrain *Train, command_data const &Command) +{ + if (Command.action != GLFW_RELEASE) + { + // on press or hold + Train->m_radiovolume = 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) +{ -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(); - } - } + 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 ) { +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(); - } - } + 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) { +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) { +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) { +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; } + if (Train->DynamicObject == nullptr) + { + return; + } - auto *vehicle { Train->DynamicObject }; - while( vehicle ) { + auto *vehicle{Train->DynamicObject}; + while (vehicle) + { vehicle->MoverParameters->V += vehicle->DirectionGet() * boost; vehicle = vehicle->Next(); // pozostałe też } vehicle = Train->DynamicObject->Prev(); - while( vehicle ) { + while (vehicle) + { vehicle->MoverParameters->V += vehicle->DirectionGet() * boost; vehicle = vehicle->Prev(); // w drugą stronę też } } - // cab movement update, fixed step part -void TTrain::UpdateCab() { +void TTrain::UpdateCab() +{ - // Ra: przesiadka, jeśli AI zmieniło kabinę (a człon?)... - if( ( DynamicObject->Mechanik ) // może nie być? - && ( DynamicObject->Mechanik->AIControllFlag ) ) { + // Ra: przesiadka, jeśli AI zmieniło kabinę (a człon?)... + if ((DynamicObject->Mechanik) // może nie być? + && (DynamicObject->Mechanik->AIControllFlag)) + { - if( iCabn != ( // numer kabiny (-1: kabina B) - mvOccupied->CabOccupied == -1 ? - 2 : - mvOccupied->CabOccupied ) ) { + if (iCabn != ( // numer kabiny (-1: kabina B) + mvOccupied->CabOccupied == -1 ? 2 : mvOccupied->CabOccupied)) + { - InitializeCab( - mvOccupied->CabOccupied, - mvOccupied->TypeName + ".mmd" ); - } - } - iCabn = ( mvOccupied->CabOccupied == -1 ? - 2 : - mvOccupied->CabOccupied ); + InitializeCab(mvOccupied->CabOccupied, mvOccupied->TypeName + ".mmd"); + } + } + iCabn = (mvOccupied->CabOccupied == -1 ? 2 : mvOccupied->CabOccupied); } -bool TTrain::Update( double const Deltatime ) +bool TTrain::Update(double const Deltatime) { - // train state update - // line breaker: - if( m_linebreakerstate == 0 ) { - if( true == mvControlled->Mains ) { - // crude way to sync state of the linebreaker with ai-issued commands - m_linebreakerstate = 1; - } - } - if( m_linebreakerstate == 1 ) { - if( false == ( mvControlled->Mains || mvControlled->dizel_startup ) ) { - // crude way to catch cases where the main was knocked out - // because the state of the line breaker isn't changed to match, we need to do it here manually - m_linebreakerstate = 0; - } - } + // train state update + // line breaker: + if (m_linebreakerstate == 0) + { + if (true == mvControlled->Mains) + { + // crude way to sync state of the linebreaker with ai-issued commands + m_linebreakerstate = 1; + } + } + if (m_linebreakerstate == 1) + { + if (false == (mvControlled->Mains || mvControlled->dizel_startup)) + { + // crude way to catch cases where the main was knocked out + // because the state of the line breaker isn't changed to match, we need to do it here manually + m_linebreakerstate = 0; + } + } - if( ( ( ggMainButton.SubModel != nullptr ) && ( ggMainButton.GetDesiredValue() > 0.95 ) ) - || ( ( ggMainOnButton.SubModel != nullptr ) && ( ggMainOnButton.GetDesiredValue() > 0.95 ) - || ( ggIgnitionKey.GetDesiredValue() > 0.95 ) ) ) { // HACK: fallback - // keep track of period the line breaker button is held down, to determine when/if circuit closes - if( mvControlled->MainSwitchCheck() ) { - fMainRelayTimer += Deltatime; - } - } - else { - // button isn't down, reset the timer - fMainRelayTimer = 0.0f; - } - if( ggMainOffButton.GetDesiredValue() > 0.95 ) { - // if the button disconnecting the line breaker is down prevent the timer from accumulating - fMainRelayTimer = 0.0f; - } - if( m_linebreakerstate == 0 ) { - if( fMainRelayTimer > mvControlled->InitialCtrlDelay ) { - // wlaczanie WSa z opoznieniem - // mark the line breaker as ready to close; for electric series vehicles with impulse switch the setup is completed on button release - m_linebreakerstate = 2; - } - } - if( m_linebreakerstate == 2 ) { - // for diesels and/or vehicles with toggle switch setup we complete the engine start here - // TODO: make it a test for main_on_bt of type push_delayed instead - if( ( ggMainOnButton.SubModel == nullptr ) - || ( mvControlled->EngineType != TEngineType::ElectricSeriesMotor ) ) { - // try to finalize state change of the line breaker, set the state based on the outcome - m_linebreakerstate = ( - mvControlled->MainSwitch( true ) ? - 1 : - 0 ); - } - } - // door permits - for( auto idx = 0; idx < 2; ++idx ) { - auto &doorpermittimer { m_doorpermittimers[ idx ] }; - if( doorpermittimer < 0.f ) { - continue; - } - doorpermittimer -= Deltatime; - if( doorpermittimer < 0.f ) { - mvOccupied->OperateDoors( static_cast( idx ), true ); - } - } + if (((ggMainButton.SubModel != nullptr) && (ggMainButton.GetDesiredValue() > 0.95)) || + ((ggMainOnButton.SubModel != nullptr) && (ggMainOnButton.GetDesiredValue() > 0.95) || (ggIgnitionKey.GetDesiredValue() > 0.95))) + { // HACK: fallback + // keep track of period the line breaker button is held down, to determine when/if circuit closes + if (mvControlled->MainSwitchCheck()) + { + fMainRelayTimer += Deltatime; + } + } + else + { + // button isn't down, reset the timer + fMainRelayTimer = 0.0f; + } + if (ggMainOffButton.GetDesiredValue() > 0.95) + { + // if the button disconnecting the line breaker is down prevent the timer from accumulating + fMainRelayTimer = 0.0f; + } + if (m_linebreakerstate == 0) + { + if (fMainRelayTimer > mvControlled->InitialCtrlDelay) + { + // wlaczanie WSa z opoznieniem + // mark the line breaker as ready to close; for electric series vehicles with impulse switch the setup is completed on button release + m_linebreakerstate = 2; + } + } + if (m_linebreakerstate == 2) + { + // for diesels and/or vehicles with toggle switch setup we complete the engine start here + // TODO: make it a test for main_on_bt of type push_delayed instead + if ((ggMainOnButton.SubModel == nullptr) || (mvControlled->EngineType != TEngineType::ElectricSeriesMotor)) + { + // try to finalize state change of the line breaker, set the state based on the outcome + m_linebreakerstate = (mvControlled->MainSwitch(true) ? 1 : 0); + } + } + // door permits + for (auto idx = 0; idx < 2; ++idx) + { + auto &doorpermittimer{m_doorpermittimers[idx]}; + if (doorpermittimer < 0.f) + { + continue; + } + doorpermittimer -= Deltatime; + if (doorpermittimer < 0.f) + { + mvOccupied->OperateDoors(static_cast(idx), true); + } + } - // train measurement timer - if (trainLenghtMeasureTimer >= 0.f) { + // train measurement timer + if (trainLenghtMeasureTimer >= 0.f) + { trainLenghtMeasureTimer -= Deltatime; if (trainLenghtMeasureTimer < 0.f) trainLenghtMeasureTimer = -1.f; - } + } - // battery timer - if (fBatteryTimer >= 0.f) { + // battery timer + if (fBatteryTimer >= 0.f) + { fBatteryTimer -= Deltatime; if (fBatteryTimer < 0.f) fBatteryTimer = -1.f; - } + } - // helper variables - if( DynamicObject->Mechanik != nullptr ) { - m_doors = ( - DynamicObject->Mechanik->IsAnyDoorOpen[ side::right ] - || DynamicObject->Mechanik->IsAnyDoorOpen[ side::left ] ); - m_doorpermits = ( - DynamicObject->Mechanik->IsAnyDoorPermitActive[ side::right ] - || DynamicObject->Mechanik->IsAnyDoorPermitActive[ side::left ] ); - m_doorspermitleft = mvOccupied->Doors.instances[(cab_to_end() == end::front ? side::left : side::right)].open_permit - && ((simulation::Time.data().wSecond % 2 < 1) - || (mvOccupied->DoorsPermitLightBlinking < 1) - || ((mvOccupied->DoorsPermitLightBlinking < 2) - && (DynamicObject->Mechanik->IsAnyDoorOpen[(cab_to_end() == end::front ? side::left : side::right)]) - || ((mvOccupied->DoorsPermitLightBlinking < 3) - && DynamicObject->Mechanik->IsAnyDoorOnlyOpen[(cab_to_end() == end::front ? side::left : side::right)]))); - m_doorspermitright = mvOccupied->Doors.instances[(cab_to_end() == end::front ? side::right : side::left)].open_permit - && ((simulation::Time.data().wSecond % 2 < 1) - || (mvOccupied->DoorsPermitLightBlinking < 1) - || ((mvOccupied->DoorsPermitLightBlinking < 2) - && (DynamicObject->Mechanik->IsAnyDoorOpen[(cab_to_end() == end::front ? side::right : side::left)]) - || ((mvOccupied->DoorsPermitLightBlinking < 3) - && DynamicObject->Mechanik->IsAnyDoorOnlyOpen[(cab_to_end() == end::front ? side::right : side::left)]))); - } - m_dirforward = ( mvControlled->DirActive > 0 ); - m_dirneutral = ( mvControlled->DirActive == 0 ); - m_dirbackward = ( mvControlled->DirActive < 0 ); + // helper variables + if (DynamicObject->Mechanik != nullptr) + { + m_doors = (DynamicObject->Mechanik->IsAnyDoorOpen[side::right] || DynamicObject->Mechanik->IsAnyDoorOpen[side::left]); + m_doorpermits = (DynamicObject->Mechanik->IsAnyDoorPermitActive[side::right] || DynamicObject->Mechanik->IsAnyDoorPermitActive[side::left]); + m_doorspermitleft = mvOccupied->Doors.instances[(cab_to_end() == end::front ? side::left : side::right)].open_permit && + ((simulation::Time.data().wSecond % 2 < 1) || (mvOccupied->DoorsPermitLightBlinking < 1) || + ((mvOccupied->DoorsPermitLightBlinking < 2) && (DynamicObject->Mechanik->IsAnyDoorOpen[(cab_to_end() == end::front ? side::left : side::right)]) || + ((mvOccupied->DoorsPermitLightBlinking < 3) && DynamicObject->Mechanik->IsAnyDoorOnlyOpen[(cab_to_end() == end::front ? side::left : side::right)]))); + m_doorspermitright = mvOccupied->Doors.instances[(cab_to_end() == end::front ? side::right : side::left)].open_permit && + ((simulation::Time.data().wSecond % 2 < 1) || (mvOccupied->DoorsPermitLightBlinking < 1) || + ((mvOccupied->DoorsPermitLightBlinking < 2) && (DynamicObject->Mechanik->IsAnyDoorOpen[(cab_to_end() == end::front ? side::right : side::left)]) || + ((mvOccupied->DoorsPermitLightBlinking < 3) && DynamicObject->Mechanik->IsAnyDoorOnlyOpen[(cab_to_end() == end::front ? side::right : side::left)]))); + } + m_dirforward = (mvControlled->DirActive > 0); + m_dirneutral = (mvControlled->DirActive == 0); + m_dirbackward = (mvControlled->DirActive < 0); - // check for received user commands - // NOTE: this is a temporary arrangement, for the transition period from old command setup to the new one - // eventually commands are going to be retrieved directly by the vehicle, filtered through active control stand - // and ultimately executed, provided the stand allows it. - command_data commanddata; - while( simulation::Commands.pop( commanddata, static_cast( command_target::vehicle ) | id() ) ) { + // check for received user commands + // NOTE: this is a temporary arrangement, for the transition period from old command setup to the new one + // eventually commands are going to be retrieved directly by the vehicle, filtered through active control stand + // and ultimately executed, provided the stand allows it. + command_data commanddata; + while (simulation::Commands.pop(commanddata, static_cast(command_target::vehicle) | id())) + { - auto lookup = m_commandhandlers.find( commanddata.command ); - if( lookup != m_commandhandlers.end() ) { - // debug data - if( commanddata.action == GLFW_PRESS ) { - WriteLog( mvOccupied->Name + " received command: [" + simulation::Commands_descriptions[ static_cast( commanddata.command ) ].name + "]" ); - } - // pass the command to the assigned handler - lookup->second( this, commanddata ); - } - } + auto lookup = m_commandhandlers.find(commanddata.command); + if (lookup != m_commandhandlers.end()) + { + // debug data + if (commanddata.action == GLFW_PRESS) + { + WriteLog(mvOccupied->Name + " received command: [" + simulation::Commands_descriptions[static_cast(commanddata.command)].name + "]"); + } + // pass the command to the assigned handler + lookup->second(this, commanddata); + } + } - UpdateCab(); + UpdateCab(); - if( ( DynamicObject->Mechanik != nullptr ) - && ( false == DynamicObject->Mechanik->AIControllFlag ) ) { - // nie blokujemy AI - if( ( mvOccupied->TrainType == dt_ET40 ) - || ( mvOccupied->TrainType == dt_EP05 ) - || ( mvOccupied->HasCamshaft ) ) { - // dla ET40 i EU05 automatyczne cofanie nastawnika - i tak nie będzie to działać dobrze... - // TODO: use deltatime to stabilize speed -/* - if( false == ( - ( input::command == user_command::mastercontrollerset ) - || ( input::command == user_command::mastercontrollerincrease ) - || ( input::command == user_command::mastercontrollerdecrease ) ) ) { -*/ - if( false == ( m_mastercontrollerinuse || Global.ctrlState ) ) { - m_mastercontrollerreturndelay -= Deltatime; - if( m_mastercontrollerreturndelay < 0.f ) { - m_mastercontrollerreturndelay = EU07_CONTROLLER_BASERETURNDELAY; - if( mvOccupied->MainCtrlPos > mvOccupied->MainCtrlActualPos ) { - mvOccupied->DecMainCtrl( 1 ); - } - else if( mvOccupied->MainCtrlPos < mvOccupied->MainCtrlActualPos ) { - // Ra 15-01: a to nie miało być tylko cofanie? - mvOccupied->IncMainCtrl( 1 ); - } - } - } - } - } + if ((DynamicObject->Mechanik != nullptr) && (false == DynamicObject->Mechanik->AIControllFlag)) + { + // nie blokujemy AI + if ((mvOccupied->TrainType == dt_ET40) || (mvOccupied->TrainType == dt_EP05) || (mvOccupied->HasCamshaft)) + { + // dla ET40 i EU05 automatyczne cofanie nastawnika - i tak nie będzie to działać dobrze... + // TODO: use deltatime to stabilize speed + /* + if( false == ( + ( input::command == user_command::mastercontrollerset ) + || ( input::command == user_command::mastercontrollerincrease ) + || ( input::command == user_command::mastercontrollerdecrease ) ) ) { + */ + if (false == (m_mastercontrollerinuse || Global.ctrlState)) + { + m_mastercontrollerreturndelay -= Deltatime; + if (m_mastercontrollerreturndelay < 0.f) + { + m_mastercontrollerreturndelay = EU07_CONTROLLER_BASERETURNDELAY; + if (mvOccupied->MainCtrlPos > mvOccupied->MainCtrlActualPos) + { + mvOccupied->DecMainCtrl(1); + } + else if (mvOccupied->MainCtrlPos < mvOccupied->MainCtrlActualPos) + { + // Ra 15-01: a to nie miało być tylko cofanie? + mvOccupied->IncMainCtrl(1); + } + } + } + } + } - // McZapkie: predkosc wyswietlana na tachometrze brana jest z obrotow kol - auto const maxtacho { 3.0 }; + // McZapkie: predkosc wyswietlana na tachometrze brana jest z obrotow kol + auto const maxtacho{3.0}; - double maxSpeed = mvControlled->Vmax * 1.05; // zachowanie starej logiki jak nie ma definicji max tarczki + double maxSpeed = mvControlled->Vmax * 1.05; // zachowanie starej logiki jak nie ma definicji max tarczki if (mvOccupied->maxTachoSpeed != 0) { maxSpeed = mvOccupied->maxTachoSpeed; - } - fTachoVelocity = static_cast(std::min(std::abs(11.31 * mvControlled->WheelDiameter * mvControlled->nrot), maxSpeed)); - { // skacze osobna zmienna - float ff = simulation::Time.data().wSecond; // skacze co sekunde - pol sekundy - // pomiar, pol sekundy ustawienie - if (ff != fTachoTimer) // jesli w tej sekundzie nie zmienial - { + } + fTachoVelocity = static_cast(std::min(std::abs(11.31 * mvControlled->WheelDiameter * mvControlled->nrot), maxSpeed)); + { // skacze osobna zmienna + float ff = simulation::Time.data().wSecond; // skacze co sekunde - pol sekundy + // pomiar, pol sekundy ustawienie + if (ff != fTachoTimer) // jesli w tej sekundzie nie zmienial + { if (fTachoVelocity >= 5) // jedzie fTachoVelocityJump = fTachoVelocity + (2.0 - LocalRandom(3) + LocalRandom(3)) * 0.5; else if (fTachoVelocity < 5 && fTachoVelocity > 1) fTachoVelocityJump = Random(0, 4); // tu ma sie bujac jak wariat i zatrzymac na jakiejs predkosci - // fTachoVelocityJump = 0; // stoi - fTachoTimer = ff; // juz zmienil - } - } - if (fTachoVelocity > 1) // McZapkie-270503: podkrecanie tachometru - { - // szybciej zacznij stukac - fTachoCount = std::min( maxtacho, fTachoCount + Deltatime * 3 ); - } - else if( fTachoCount > 0 ) { - // schodz powoli - niektore haslery to ze 4 sekundy potrafia stukac - fTachoCount = std::max( 0.0, fTachoCount - Deltatime * 0.66 ); - } + // fTachoVelocityJump = 0; // stoi + fTachoTimer = ff; // juz zmienil + } + } + if (fTachoVelocity > 1) // McZapkie-270503: podkrecanie tachometru + { + // szybciej zacznij stukac + fTachoCount = std::min(maxtacho, fTachoCount + Deltatime * 3); + } + else if (fTachoCount > 0) + { + // schodz powoli - niektore haslery to ze 4 sekundy potrafia stukac + fTachoCount = std::max(0.0, fTachoCount - Deltatime * 0.66); + } - // Ra 2014-09: napięcia i prądy muszą być ustalone najpierw, bo wysyłane są ewentualnie na PoKeys - if( ( mvControlled->EngineType != TEngineType::DieselElectric ) - && ( mvControlled->EngineType != TEngineType::ElectricInductionMotor ) ) { // Ra 2014-09: czy taki rozdzia? ma sens? - fHVoltage = std::max( - mvControlled->PantographVoltage, - mvControlled->GetTrainsetHighVoltage() ); // Winger czy to nie jest zle? - } - // *mvControlled->Mains); - else { - fHVoltage = mvControlled->EngineVoltage; - } - if (ShowNextCurrent) - { // jeśli pokazywać drugi człon - if (mvSecond) - { // o ile jest ten drugi - fHCurrent[0] = mvSecond->ShowCurrent(0) * 1.05; - fHCurrent[1] = mvSecond->ShowCurrent(1) * 1.05; - fHCurrent[2] = mvSecond->ShowCurrent(2) * 1.05; - fHCurrent[3] = mvSecond->ShowCurrent(3) * 1.05; - } - else - fHCurrent[0] = fHCurrent[1] = fHCurrent[2] = fHCurrent[3] = - 0.0; // gdy nie ma człona - } - else - { // normalne pokazywanie - fHCurrent[0] = mvControlled->ShowCurrent(0); - fHCurrent[1] = mvControlled->ShowCurrent(1); - fHCurrent[2] = mvControlled->ShowCurrent(2); - fHCurrent[3] = mvControlled->ShowCurrent(3); - } + // Ra 2014-09: napięcia i prądy muszą być ustalone najpierw, bo wysyłane są ewentualnie na PoKeys + if ((mvControlled->EngineType != TEngineType::DieselElectric) && (mvControlled->EngineType != TEngineType::ElectricInductionMotor)) + { // Ra 2014-09: czy taki rozdzia? ma sens? + fHVoltage = std::max(mvControlled->PantographVoltage, + mvControlled->GetTrainsetHighVoltage()); // Winger czy to nie jest zle? + } + // *mvControlled->Mains); + else + { + fHVoltage = mvControlled->EngineVoltage; + } + if (ShowNextCurrent) + { // jeśli pokazywać drugi człon + if (mvSecond) + { // o ile jest ten drugi + fHCurrent[0] = mvSecond->ShowCurrent(0) * 1.05; + fHCurrent[1] = mvSecond->ShowCurrent(1) * 1.05; + fHCurrent[2] = mvSecond->ShowCurrent(2) * 1.05; + fHCurrent[3] = mvSecond->ShowCurrent(3) * 1.05; + } + else + fHCurrent[0] = fHCurrent[1] = fHCurrent[2] = fHCurrent[3] = 0.0; // gdy nie ma człona + } + else + { // normalne pokazywanie + fHCurrent[0] = mvControlled->ShowCurrent(0); + fHCurrent[1] = mvControlled->ShowCurrent(1); + fHCurrent[2] = mvControlled->ShowCurrent(2); + fHCurrent[3] = mvControlled->ShowCurrent(3); + } - bool kier = (DynamicObject->DirectionGet() * mvOccupied->CabOccupied > 0); - TDynamicObject *p = DynamicObject->GetFirstDynamic(mvOccupied->CabOccupied < 0 ? end::rear : end::front, 4); - int in = 0; - fEIMParams[0][6] = 0; - iCarNo = 0; - iPowerNo = 0; - iUnitNo = 1; + bool kier = (DynamicObject->DirectionGet() * mvOccupied->CabOccupied > 0); + TDynamicObject *p = DynamicObject->GetFirstDynamic(mvOccupied->CabOccupied < 0 ? end::rear : end::front, 4); + int in = 0; + fEIMParams[0][6] = 0; + iCarNo = 0; + iPowerNo = 0; + iUnitNo = 1; - for (int i = 0; i < 8; i++) - { - bMains[i] = false; - fCntVol[i] = 0.0f; - bPants[i][0] = false; - bPants[i][1] = false; - bFuse[i] = false; - bBatt[i] = false; - bConv[i] = false; - bComp[i][0] = false; - bComp[i][1] = false; - //bComp[i][2] = false; - //bComp[i][3] = false; - bHeat[i] = false; - } + for (int i = 0; i < 8; i++) + { + bMains[i] = false; + fCntVol[i] = 0.0f; + bPants[i][0] = false; + bPants[i][1] = false; + bFuse[i] = false; + bBatt[i] = false; + bConv[i] = false; + bComp[i][0] = false; + bComp[i][1] = false; + // bComp[i][2] = false; + // bComp[i][3] = false; + bHeat[i] = false; + } bCompressors.clear(); - for (int i = 0; i < 20; i++) - { - if (p) - { - fPress[i][0] = p->MoverParameters->BrakePress; - fPress[i][1] = p->MoverParameters->PipePress; - fPress[i][2] = p->MoverParameters->ScndPipePress; + for (int i = 0; i < 20; i++) + { + if (p) + { + fPress[i][0] = p->MoverParameters->BrakePress; + fPress[i][1] = p->MoverParameters->PipePress; + fPress[i][2] = p->MoverParameters->ScndPipePress; fPress[i][3] = p->MoverParameters->CntrlPipePress; fPress[i][4] = p->MoverParameters->Hamulec->GetBRP(); fPress[i][5] = (p->MoverParameters->TotalMass - p->MoverParameters->Mred) * 0.001; fPress[i][6] = p->MoverParameters->SpringBrake.SBP; bBrakes[i][0] = p->MoverParameters->SpringBrake.IsActive; bBrakes[i][1] = p->MoverParameters->SpringBrake.ShuttOff; - bDoors[i][1] = ( p->MoverParameters->Doors.instances[ side::left ].position > 0.f ); - bDoors[i][2] = ( p->MoverParameters->Doors.instances[ side::right ].position > 0.f ); - bDoors[i][3] = ( p->MoverParameters->Doors.instances[ side::left ].step_position > 0.f ); - bDoors[i][4] = ( p->MoverParameters->Doors.instances[ side::right ].step_position > 0.f ); - bDoors[i][0] = ( bDoors[i][1] || bDoors[i][2] ); - iDoorNo[i] = p->iAnimType[ANIM_DOORS]; - iUnits[i] = iUnitNo; - cCode[i] = p->MoverParameters->TypeName[p->MoverParameters->TypeName.length() - 1]; - asCarName[i] = p->name(); - if( p->MoverParameters->EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) { - bPants[iUnitNo - 1][end::front] = ( bPants[iUnitNo - 1][end::front] || p->MoverParameters->Pantographs[end::front].is_active ); - bPants[iUnitNo - 1][end::rear] = ( bPants[iUnitNo - 1][end::rear] || p->MoverParameters->Pantographs[end::rear].is_active ); - } - // TBD, TODO: clean up compressor data arrangement? - if( iUnitNo <= 8 ) { - bComp[iUnitNo - 1][0] = (bComp[iUnitNo - 1][0] || p->MoverParameters->CompressorAllow || (p->MoverParameters->CompressorStart == start_t::automatic)); - } - if (p->MoverParameters->CompressorSpeed > 0.00001) - { - if( iUnitNo <= 8 ) { - bComp[iUnitNo - 1][1] = (bComp[iUnitNo - 1][1] || p->MoverParameters->CompressorFlag); - } - bCompressors.emplace_back( - p->MoverParameters->CompressorAllow || (p->MoverParameters->CompressorStart == start_t::automatic), - p->MoverParameters->CompressorFlag, - i); - } - bSlip[i] = p->MoverParameters->SlippingWheels; - if ((in < 8) && (p->MoverParameters->eimc[eimc_p_Pmax] > 1)) - { - fEIMParams[1 + in][0] = p->MoverParameters->eimv[eimv_Fmax]; - fEIMParams[1 + in][1] = std::max(fEIMParams[1 + in][0], 0.f); - fEIMParams[1 + in][2] = -std::min(fEIMParams[1 + in][0], 0.f); - fEIMParams[1 + in][3] = p->MoverParameters->eimv[eimv_Fmax] / std::max(p->MoverParameters->eimv[eimv_Fful], 1.); - fEIMParams[1 + in][4] = std::max(fEIMParams[1 + in][3], 0.f); - fEIMParams[1 + in][5] = -std::min(fEIMParams[1 + in][3], 0.f); - fEIMParams[1 + in][6] = p->MoverParameters->eimv[eimv_If]; - fEIMParams[1 + in][7] = p->MoverParameters->eimv[eimv_U]; - fEIMParams[1 + in][8] = p->MoverParameters->Itot;//p->MoverParameters->eimv[eimv_Ipoj]; - fEIMParams[1 + in][9] = p->MoverParameters->EngineVoltage; - fEIMParams[0][6] += fEIMParams[1 + in][8]; - bMains[in] = p->MoverParameters->Mains; - fCntVol[in] = p->MoverParameters->BatteryVoltage; - bFuse[in] = p->MoverParameters->FuseFlag; - bBatt[in] = p->MoverParameters->Battery; - bConv[in] = p->MoverParameters->ConverterFlag; - bHeat[in] = p->MoverParameters->Heating; - //bComp[in][2] = (p->MoverParameters->CompressorAllow || (p->MoverParameters->CompressorStart == start_t::automatic)); - //bComp[in][3] = (p->MoverParameters->CompressorFlag); - in++; - iPowerNo = in; - } - if ((in < 8) - && ((p->MoverParameters->EngineType==TEngineType::DieselEngine) - ||(p->MoverParameters->EngineType==TEngineType::DieselElectric))) + bDoors[i][1] = (p->MoverParameters->Doors.instances[side::left].position > 0.f); + bDoors[i][2] = (p->MoverParameters->Doors.instances[side::right].position > 0.f); + bDoors[i][3] = (p->MoverParameters->Doors.instances[side::left].step_position > 0.f); + bDoors[i][4] = (p->MoverParameters->Doors.instances[side::right].step_position > 0.f); + bDoors[i][0] = (bDoors[i][1] || bDoors[i][2]); + iDoorNo[i] = p->iAnimType[ANIM_DOORS]; + iUnits[i] = iUnitNo; + cCode[i] = p->MoverParameters->TypeName[p->MoverParameters->TypeName.length() - 1]; + asCarName[i] = p->name(); + if (p->MoverParameters->EnginePowerSource.SourceType == TPowerSource::CurrentCollector) { - fDieselParams[1 + in][0] = p->MoverParameters->enrot*60; + bPants[iUnitNo - 1][end::front] = (bPants[iUnitNo - 1][end::front] || p->MoverParameters->Pantographs[end::front].is_active); + bPants[iUnitNo - 1][end::rear] = (bPants[iUnitNo - 1][end::rear] || p->MoverParameters->Pantographs[end::rear].is_active); + } + // TBD, TODO: clean up compressor data arrangement? + if (iUnitNo <= 8) + { + bComp[iUnitNo - 1][0] = (bComp[iUnitNo - 1][0] || p->MoverParameters->CompressorAllow || (p->MoverParameters->CompressorStart == start_t::automatic)); + } + if (p->MoverParameters->CompressorSpeed > 0.00001) + { + if (iUnitNo <= 8) + { + bComp[iUnitNo - 1][1] = (bComp[iUnitNo - 1][1] || p->MoverParameters->CompressorFlag); + } + bCompressors.emplace_back(p->MoverParameters->CompressorAllow || (p->MoverParameters->CompressorStart == start_t::automatic), p->MoverParameters->CompressorFlag, i); + } + bSlip[i] = p->MoverParameters->SlippingWheels; + if ((in < 8) && (p->MoverParameters->eimc[eimc_p_Pmax] > 1)) + { + fEIMParams[1 + in][0] = p->MoverParameters->eimv[eimv_Fmax]; + fEIMParams[1 + in][1] = Max0R(fEIMParams[1 + in][0], 0); + fEIMParams[1 + in][2] = -Min0R(fEIMParams[1 + in][0], 0); + fEIMParams[1 + in][3] = p->MoverParameters->eimv[eimv_Fmax] / Max0R(p->MoverParameters->eimv[eimv_Fful], 1); + fEIMParams[1 + in][4] = Max0R(fEIMParams[1 + in][3], 0); + fEIMParams[1 + in][5] = -Min0R(fEIMParams[1 + in][3], 0); + fEIMParams[1 + in][6] = p->MoverParameters->eimv[eimv_If]; + fEIMParams[1 + in][7] = p->MoverParameters->eimv[eimv_U]; + fEIMParams[1 + in][8] = p->MoverParameters->Itot; // p->MoverParameters->eimv[eimv_Ipoj]; + fEIMParams[1 + in][9] = p->MoverParameters->EngineVoltage; + fEIMParams[0][6] += fEIMParams[1 + in][8]; + bMains[in] = p->MoverParameters->Mains; + fCntVol[in] = p->MoverParameters->BatteryVoltage; + bFuse[in] = p->MoverParameters->FuseFlag; + bBatt[in] = p->MoverParameters->Battery; + bConv[in] = p->MoverParameters->ConverterFlag; + bHeat[in] = p->MoverParameters->Heating; + // bComp[in][2] = (p->MoverParameters->CompressorAllow || (p->MoverParameters->CompressorStart == start_t::automatic)); + // bComp[in][3] = (p->MoverParameters->CompressorFlag); + in++; + iPowerNo = in; + } + if ((in < 8) && ((p->MoverParameters->EngineType == TEngineType::DieselEngine) || (p->MoverParameters->EngineType == TEngineType::DieselElectric))) + { + fDieselParams[1 + in][0] = p->MoverParameters->enrot * 60; fDieselParams[1 + in][1] = p->MoverParameters->nrot; fDieselParams[1 + in][2] = p->MoverParameters->RList[p->MoverParameters->MainCtrlPos].R; fDieselParams[1 + in][3] = p->MoverParameters->dizel_fill; @@ -7452,1076 +8749,1045 @@ bool TTrain::Update( double const Deltatime ) in++; iPowerNo = in; } - if ((kier ? p->Next(coupling::permanent) : p->Prev(coupling::permanent)) != (kier ? p->Next(coupling::control) : p->Prev(coupling::control))) - iUnitNo++; - p = (kier ? p->Next(coupling::control) : p->Prev(coupling::control)); - iCarNo = i + 1; - } - else - { - fPress[i][0] - = fPress[i][1] - = fPress[i][2] - = fPress[i][3] - = fPress[i][4] - = fPress[i][5] - = 0; - bDoors[i][0] - = bDoors[i][1] - = bDoors[i][2] - = bDoors[i][3] - = bDoors[i][4] - = false; - bBrakes[i][0] - = bBrakes[i][1] - = false; + if ((kier ? p->Next(coupling::permanent) : p->Prev(coupling::permanent)) != (kier ? p->Next(coupling::control) : p->Prev(coupling::control))) + iUnitNo++; + p = (kier ? p->Next(coupling::control) : p->Prev(coupling::control)); + iCarNo = i + 1; + } + else + { + fPress[i][0] = fPress[i][1] = fPress[i][2] = fPress[i][3] = fPress[i][4] = fPress[i][5] = 0; + bDoors[i][0] = bDoors[i][1] = bDoors[i][2] = bDoors[i][3] = bDoors[i][4] = false; + bBrakes[i][0] = bBrakes[i][1] = false; bSlip[i] = false; - iUnits[i] = 0; - cCode[i] = 0; //'0'; - asCarName[i] = ""; - } - } + iUnits[i] = 0; + cCode[i] = 0; //'0'; + asCarName[i] = ""; + } + } -// if (mvControlled == mvOccupied) -// fEIMParams[0][3] = mvControlled->eimv[eimv_Fzad]; // procent zadany -// else -// fEIMParams[0][3] = -// mvControlled->eimv[eimv_Fzad] - mvOccupied->LocalBrakeRatio(); // procent zadany + // if (mvControlled == mvOccupied) + // fEIMParams[0][3] = mvControlled->eimv[eimv_Fzad]; // procent zadany + // else + // fEIMParams[0][3] = + // mvControlled->eimv[eimv_Fzad] - mvOccupied->LocalBrakeRatio(); // procent zadany fEIMParams[0][3] = mvOccupied->eimic_real; - fEIMParams[0][4] = std::max(fEIMParams[0][3], 0.f); - fEIMParams[0][5] = -std::min(fEIMParams[0][3], 0.f); - fEIMParams[0][1] = fEIMParams[0][4] * mvControlled->eimv[eimv_Fful]; - fEIMParams[0][2] = fEIMParams[0][5] * mvControlled->eimv[eimv_Fful]; - fEIMParams[0][0] = fEIMParams[0][1] - fEIMParams[0][2]; - fEIMParams[0][7] = 0; - fEIMParams[0][8] = 0; - fEIMParams[0][9] = 0; + fEIMParams[0][4] = Max0R(fEIMParams[0][3], 0); + fEIMParams[0][5] = -Min0R(fEIMParams[0][3], 0); + fEIMParams[0][1] = fEIMParams[0][4] * mvControlled->eimv[eimv_Fful]; + fEIMParams[0][2] = fEIMParams[0][5] * mvControlled->eimv[eimv_Fful]; + fEIMParams[0][0] = fEIMParams[0][1] - fEIMParams[0][2]; + fEIMParams[0][7] = 0; + fEIMParams[0][8] = 0; + fEIMParams[0][9] = 0; - for (int i = in; i < 8; i++) - { + for (int i = in; i < 8; i++) + { for (int j = 0; j <= 9; j++) { fEIMParams[1 + i][j] = 0; fDieselParams[1 + i][j] = 0; } - } + } #ifdef _WIN32 - if (Global.iFeedbackMode == 4) { - // wykonywać tylko gdy wyprowadzone na pulpit - // Ra: sterowanie miernikiem: zbiornik główny - Console::ValueSet(0, mvOccupied->Compressor); - // Ra: sterowanie miernikiem: przewód główny - Console::ValueSet(1, mvOccupied->PipePress); - // Ra: sterowanie miernikiem: cylinder hamulcowy - Console::ValueSet(2, mvOccupied->BrakePress); - // woltomierz wysokiego napięcia - Console::ValueSet(3, fHVoltage); - // Ra: sterowanie miernikiem: drugi amperomierz - Console::ValueSet(4, fHCurrent[2]); - // pierwszy amperomierz; dla EZT prąd całkowity - Console::ValueSet(5, fHCurrent[(mvControlled->TrainType & dt_EZT) ? 0 : 1]); - // Ra: prędkość na pin 43 - wyjście analogowe (to nie jest PWM); skakanie zapewnia mechanika napędu - Console::ValueSet(6, fTachoVelocity); - } + if (Global.iFeedbackMode == 4) + { + // wykonywać tylko gdy wyprowadzone na pulpit + // Ra: sterowanie miernikiem: zbiornik główny + Console::ValueSet(0, mvOccupied->Compressor); + // Ra: sterowanie miernikiem: przewód główny + Console::ValueSet(1, mvOccupied->PipePress); + // Ra: sterowanie miernikiem: cylinder hamulcowy + Console::ValueSet(2, mvOccupied->BrakePress); + // woltomierz wysokiego napięcia + Console::ValueSet(3, fHVoltage); + // Ra: sterowanie miernikiem: drugi amperomierz + Console::ValueSet(4, fHCurrent[2]); + // pierwszy amperomierz; dla EZT prąd całkowity + Console::ValueSet(5, fHCurrent[(mvControlled->TrainType & dt_EZT) ? 0 : 1]); + // Ra: prędkość na pin 43 - wyjście analogowe (to nie jest PWM); skakanie zapewnia mechanika napędu + Console::ValueSet(6, fTachoVelocity); + } #endif - //------------------ - // hunter-261211: nadmiarowy przetwornicy i ogrzewania - // Ra 15-01: to musi stąd wylecieć - zależności nie mogą być w kabinie - if (mvControlled->ConverterFlag == true) - { - fConverterTimer += Deltatime; - if ((mvControlled->CompressorFlag == true) && (mvControlled->CompressorPower == 1) && - ((mvControlled->EngineType == TEngineType::ElectricSeriesMotor) || - (mvControlled->TrainType == dt_EZT)) && - (DynamicObject->Controller == Humandriver) // hunter-110212: poprawka dla EZT - && ( false == DynamicObject->Mechanik->AIControllFlag ) ) - { // hunter-091012: poprawka (zmiana warunku z CompressorPower /rozne od 0/ na /rowne 1/) - if (fConverterTimer < fConverterPrzekaznik) - { - mvControlled->ConvOvldFlag = true; - if (mvControlled->TrainType != dt_EZT) - mvControlled->MainSwitch( false, ( mvControlled->TrainType == dt_EZT ? range_t::unit : range_t::local ) ); - } - else if( fConverterTimer >= fConverterPrzekaznik ) { - // changed switch from always true to take into account state of the compressor switch - mvControlled->CompressorSwitch( mvControlled->CompressorAllow ); - } - } - } - else - fConverterTimer = 0; - //------------------ - auto const lowvoltagepower { mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable }; + //------------------ + // hunter-261211: nadmiarowy przetwornicy i ogrzewania + // Ra 15-01: to musi stąd wylecieć - zależności nie mogą być w kabinie + if (mvControlled->ConverterFlag == true) + { + fConverterTimer += Deltatime; + if ((mvControlled->CompressorFlag == true) && (mvControlled->CompressorPower == 1) && ((mvControlled->EngineType == TEngineType::ElectricSeriesMotor) || (mvControlled->TrainType == dt_EZT)) && + (DynamicObject->Controller == Humandriver) // hunter-110212: poprawka dla EZT + && (false == DynamicObject->Mechanik->AIControllFlag)) + { // hunter-091012: poprawka (zmiana warunku z CompressorPower /rozne od 0/ na /rowne 1/) + if (fConverterTimer < fConverterPrzekaznik) + { + mvControlled->ConvOvldFlag = true; + if (mvControlled->TrainType != dt_EZT) + mvControlled->MainSwitch(false, (mvControlled->TrainType == dt_EZT ? range_t::unit : range_t::local)); + } + else if (fConverterTimer >= fConverterPrzekaznik) + { + // changed switch from always true to take into account state of the compressor switch + mvControlled->CompressorSwitch(mvControlled->CompressorAllow); + } + } + } + else + fConverterTimer = 0; + //------------------ + auto const lowvoltagepower{mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable}; - // youBy - prad w drugim czlonie: galaz lub calosc - { - TDynamicObject *tmp { nullptr }; - if (DynamicObject->NextConnected()) - if ((TestFlag(mvControlled->Couplers[end::rear].CouplingFlag, coupling::control)) && - (mvOccupied->CabOccupied == 1)) - tmp = DynamicObject->NextConnected(); - if (DynamicObject->PrevConnected()) - if ((TestFlag(mvControlled->Couplers[end::front].CouplingFlag, coupling::control)) && - (mvOccupied->CabOccupied == -1)) - tmp = DynamicObject->PrevConnected(); - if( tmp ) { - if( tmp->MoverParameters->Power > 0 ) { - if( ggI1B.SubModel ) { - ggI1B.UpdateValue( tmp->MoverParameters->ShowCurrent( 1 ) ); - ggI1B.Update(); - } - if( ggI2B.SubModel ) { - ggI2B.UpdateValue( tmp->MoverParameters->ShowCurrent( 2 ) ); - ggI2B.Update(); - } - if( ggI3B.SubModel ) { - ggI3B.UpdateValue( tmp->MoverParameters->ShowCurrent( 3 ) ); - ggI3B.Update(); - } - if( ggItotalB.SubModel ) { - ggItotalB.UpdateValue( tmp->MoverParameters->ShowCurrent( 0 ) ); - ggItotalB.Update(); - } - if( ggWater1TempB.SubModel ) { - ggWater1TempB.UpdateValue( tmp->MoverParameters->dizel_heat.temperatura1 ); - ggWater1TempB.Update(); - } - if( ggOilPressB.SubModel ) { - ggOilPressB.UpdateValue( tmp->MoverParameters->OilPump.pressure ); - ggOilPressB.Update(); - } - } - } - } - // McZapkie-300302: zegarek - if (ggClockMInd.SubModel) - { - ggClockSInd.UpdateValue(simulation::Time.data().wSecond); - ggClockSInd.Update(); - ggClockMInd.UpdateValue(simulation::Time.data().wMinute); - ggClockMInd.Update(); - ggClockHInd.UpdateValue(simulation::Time.data().wHour + simulation::Time.data().wMinute / 60.0); - ggClockHInd.Update(); - } + // youBy - prad w drugim czlonie: galaz lub calosc + { + TDynamicObject *tmp{nullptr}; + if (DynamicObject->NextConnected()) + if ((TestFlag(mvControlled->Couplers[end::rear].CouplingFlag, coupling::control)) && (mvOccupied->CabOccupied == 1)) + tmp = DynamicObject->NextConnected(); + if (DynamicObject->PrevConnected()) + if ((TestFlag(mvControlled->Couplers[end::front].CouplingFlag, coupling::control)) && (mvOccupied->CabOccupied == -1)) + tmp = DynamicObject->PrevConnected(); + if (tmp) + { + if (tmp->MoverParameters->Power > 0) + { + if (ggI1B.SubModel) + { + ggI1B.UpdateValue(tmp->MoverParameters->ShowCurrent(1)); + ggI1B.Update(); + } + if (ggI2B.SubModel) + { + ggI2B.UpdateValue(tmp->MoverParameters->ShowCurrent(2)); + ggI2B.Update(); + } + if (ggI3B.SubModel) + { + ggI3B.UpdateValue(tmp->MoverParameters->ShowCurrent(3)); + ggI3B.Update(); + } + if (ggItotalB.SubModel) + { + ggItotalB.UpdateValue(tmp->MoverParameters->ShowCurrent(0)); + ggItotalB.Update(); + } + if (ggWater1TempB.SubModel) + { + ggWater1TempB.UpdateValue(tmp->MoverParameters->dizel_heat.temperatura1); + ggWater1TempB.Update(); + } + if (ggOilPressB.SubModel) + { + ggOilPressB.UpdateValue(tmp->MoverParameters->OilPump.pressure); + ggOilPressB.Update(); + } + } + } + } + // McZapkie-300302: zegarek + if (ggClockMInd.SubModel) + { + ggClockSInd.UpdateValue(simulation::Time.data().wSecond); + ggClockSInd.Update(); + ggClockMInd.UpdateValue(simulation::Time.data().wMinute); + ggClockMInd.Update(); + ggClockHInd.UpdateValue(simulation::Time.data().wHour + simulation::Time.data().wMinute / 60.0); + ggClockHInd.Update(); + } - Cabine[iCabn].Update( lowvoltagepower ); // nowy sposób ustawienia animacji -/* - if (ggZbS.SubModel) - { - ggZbS.UpdateValue(mvOccupied->Handle->GetCP()); - ggZbS.Update(); - } -*/ - // replacement for the above. TODO: move it to a more suitable place - m_brakehandlecp = mvOccupied->Handle->GetCP(); + Cabine[iCabn].Update(lowvoltagepower); // nowy sposób ustawienia animacji + /* + if (ggZbS.SubModel) + { + ggZbS.UpdateValue(mvOccupied->Handle->GetCP()); + ggZbS.Update(); + } + */ + // replacement for the above. TODO: move it to a more suitable place + m_brakehandlecp = mvOccupied->Handle->GetCP(); - // youBy - napiecie na silnikach - if (ggEngineVoltage.SubModel) - { - if (mvControlled->DynamicBrakeFlag) - { - ggEngineVoltage.UpdateValue(std::abs(mvControlled->Im * 5)); - } - else - { - int x; - if ((mvControlled->TrainType == dt_ET42) && - (mvControlled->Imax == mvControlled->ImaxHi)) - x = 1; - else - x = 2; - if ((mvControlled->RList[mvControlled->MainCtrlActualPos].Mn > 0) && - (std::abs(mvControlled->Im) > 0)) - { - ggEngineVoltage.UpdateValue( - (x * (std::abs(mvControlled->EngineVoltage) - - mvControlled->RList[mvControlled->MainCtrlActualPos].R * - std::abs(mvControlled->Im)) / - mvControlled->RList[mvControlled->MainCtrlActualPos].Mn)); - } - else - { - ggEngineVoltage.UpdateValue(0); - } - } - ggEngineVoltage.Update(); - } + // youBy - napiecie na silnikach + if (ggEngineVoltage.SubModel) + { + if (mvControlled->DynamicBrakeFlag) + { + ggEngineVoltage.UpdateValue(std::abs(mvControlled->Im * 5)); + } + else + { + int x; + if ((mvControlled->TrainType == dt_ET42) && (mvControlled->Imax == mvControlled->ImaxHi)) + x = 1; + else + x = 2; + if ((mvControlled->RList[mvControlled->MainCtrlActualPos].Mn > 0) && (std::abs(mvControlled->Im) > 0)) + { + ggEngineVoltage.UpdateValue((x * (std::abs(mvControlled->EngineVoltage) - mvControlled->RList[mvControlled->MainCtrlActualPos].R * std::abs(mvControlled->Im)) / + mvControlled->RList[mvControlled->MainCtrlActualPos].Mn)); + } + else + { + ggEngineVoltage.UpdateValue(0); + } + } + ggEngineVoltage.Update(); + } - // Winger 140404 - woltomierz NN - if (ggLVoltage.SubModel) - { - // NOTE: since we don't have functional converter object, we're faking it here by simple check whether converter is on - // TODO: implement object-based circuits and power systems model so we can have this working more properly - ggLVoltage.UpdateValue( - std::max( - ( mvOccupied->Power110vIsAvailable ? - mvOccupied->NominalBatteryVoltage : - 0.0 ), - ( mvOccupied->Power24vIsAvailable ? - mvOccupied->BatteryVoltage : - 0.0 ) ) ); - ggLVoltage.Update(); - } + // Winger 140404 - woltomierz NN + if (ggLVoltage.SubModel) + { + // NOTE: since we don't have functional converter object, we're faking it here by simple check whether converter is on + // TODO: implement object-based circuits and power systems model so we can have this working more properly + ggLVoltage.UpdateValue(std::max((mvOccupied->Power110vIsAvailable ? mvOccupied->NominalBatteryVoltage : 0.0), (mvOccupied->Power24vIsAvailable ? mvOccupied->BatteryVoltage : 0.0))); + ggLVoltage.Update(); + } - if (mvControlled->EngineType == TEngineType::DieselElectric) - { // ustawienie zmiennych dla silnika spalinowego - fEngine[1] = mvControlled->ShowEngineRotation(1); - fEngine[2] = mvControlled->ShowEngineRotation(2); - } + if (mvControlled->EngineType == TEngineType::DieselElectric) + { // ustawienie zmiennych dla silnika spalinowego + fEngine[1] = mvControlled->ShowEngineRotation(1); + fEngine[2] = mvControlled->ShowEngineRotation(2); + } - else if (mvControlled->EngineType == TEngineType::DieselEngine) - { // albo dla innego spalinowego - fEngine[1] = mvControlled->ShowEngineRotation(1); - fEngine[2] = mvControlled->ShowEngineRotation(2); - fEngine[3] = mvControlled->ShowEngineRotation(3); - if (ggMainGearStatus.SubModel) - { - if (mvControlled->Mains) - ggMainGearStatus.UpdateValue(1.1 - std::abs(mvControlled->dizel_automaticgearstatus)); - else - ggMainGearStatus.UpdateValue(0.0); - ggMainGearStatus.Update(); - } - if( ( ggIgnitionKey.SubModel) - && ( ggIgnitionKey.GetDesiredValue() == 0.0 ) ) - { - ggIgnitionKey.UpdateValue( - ( mvControlled->Mains ) - || ( mvControlled->dizel_startup ) - || ( fMainRelayTimer > 0.f ) - || ( ( ggMainButton.SubModel != nullptr ) && ( ggMainButton.GetDesiredValue() > 0.95 ) ) - || ( ( ggMainOnButton.SubModel != nullptr ) && ( ggMainOnButton.GetDesiredValue() > 0.95 ) ) ); - } - ggIgnitionKey.Update(); - } + else if (mvControlled->EngineType == TEngineType::DieselEngine) + { // albo dla innego spalinowego + fEngine[1] = mvControlled->ShowEngineRotation(1); + fEngine[2] = mvControlled->ShowEngineRotation(2); + fEngine[3] = mvControlled->ShowEngineRotation(3); + if (ggMainGearStatus.SubModel) + { + if (mvControlled->Mains) + ggMainGearStatus.UpdateValue(1.1 - std::abs(mvControlled->dizel_automaticgearstatus)); + else + ggMainGearStatus.UpdateValue(0.0); + ggMainGearStatus.Update(); + } + if ((ggIgnitionKey.SubModel) && (ggIgnitionKey.GetDesiredValue() == 0.0)) + { + ggIgnitionKey.UpdateValue((mvControlled->Mains) || (mvControlled->dizel_startup) || (fMainRelayTimer > 0.f) || + ((ggMainButton.SubModel != nullptr) && (ggMainButton.GetDesiredValue() > 0.95)) || + ((ggMainOnButton.SubModel != nullptr) && (ggMainOnButton.GetDesiredValue() > 0.95))); + } + ggIgnitionKey.Update(); + } - if (mvControlled->SlippingWheels) { - // Ra 2014-12: lokomotywy 181/182 dostają SlippingWheels po zahamowaniu powyżej 2.85 bara i buczały - double veldiff = (DynamicObject->GetVelocity() - fTachoVelocity) / mvControlled->Vmax; - if( veldiff < -0.01 ) { - // 1% Vmax rezerwy, żeby 181/182 nie buczały po zahamowaniu, ale to proteza - if( std::abs( mvControlled->Im ) > 10.0 ) { - btLampkaPoslizg.Turn( true ); - } - } - } - else { - btLampkaPoslizg.Turn( false ); - } + if (mvControlled->SlippingWheels) + { + // Ra 2014-12: lokomotywy 181/182 dostają SlippingWheels po zahamowaniu powyżej 2.85 bara i buczały + double veldiff = (DynamicObject->GetVelocity() - fTachoVelocity) / mvControlled->Vmax; + if (veldiff < -0.01) + { + // 1% Vmax rezerwy, żeby 181/182 nie buczały po zahamowaniu, ale to proteza + if (std::abs(mvControlled->Im) > 10.0) + { + btLampkaPoslizg.Turn(true); + } + } + } + else + { + btLampkaPoslizg.Turn(false); + } - // Lampka pracujacej sprezacki + // Lampka pracujacej sprezacki if (mvControlled->CompressorFlag || mvOccupied->CompressorFlag) btCompressors.Turn(true); else btCompressors.Turn(false); - // Lampka zezwolenia na hamowanie ED - if (mvControlled->EpFuse) + // Lampka zezwolenia na hamowanie ED + if (mvControlled->EpFuse) btEDenabled.Turn(true); else btEDenabled.Turn(false); - // Lampka aktywowanej kabiny - if (mvControlled->CabActive != 0) { + // Lampka aktywowanej kabiny + if (mvControlled->CabActive != 0) + { btCabActived.Turn(true); - } - else { + } + else + { btCabActived.Turn(false); - } + } - if (mvControlled->Battery && mvControlled->CabActive != 0) + if (mvControlled->Battery && mvControlled->CabActive != 0) btAKLVents.Turn(true); else btAKLVents.Turn(false); - - if( true == lowvoltagepower ) { - // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa - if( mvOccupied->SecuritySystem.is_vigilance_blinking() ) { - if( fBlinkTimer > fCzuwakBlink ) - fBlinkTimer = -fCzuwakBlink; - else - fBlinkTimer += Deltatime; - - btLampkaCzuwaka.Turn( fBlinkTimer > 0 ); - } - else { - fBlinkTimer = 0.0; - btLampkaCzuwaka.Turn( false ); - } - - btLampkaSHP.Turn(mvOccupied->SecuritySystem.is_cabsignal_blinking()); - btLampkaCzuwakaSHP.Turn( btLampkaSHP.GetValue() || btLampkaCzuwaka.GetValue() ); - - btLampkaWylSzybki.Turn( - ( ( (m_linebreakerstate == 2) - || (true == mvControlled->Mains) ) ? - true : - false ) ); - btLampkaWylSzybkiOff.Turn( - ( ( ( m_linebreakerstate == 2 ) - || ( true == mvControlled->Mains ) ) ? - false : - true ) ); - btLampkaMainBreakerReady.Turn( - ( ( ( mvControlled->MainsInitTimeCountdown > 0.0 ) - || ( m_linebreakerstate == 2 ) - || ( true == mvControlled->Mains ) ) ? - false : - true ) ); - btLampkaMainBreakerBlinkingIfReady.Turn( - ( ( (m_linebreakerstate == 2) - || (true == mvControlled->Mains) - || ( ( mvControlled->MainsInitTimeCountdown < 0.0 ) && ( simulation::Time.data().wMilliseconds > 500 ) ) ) ? - true : - false ) ); - - btLampkaPrzetw.Turn( mvOccupied->Power110vIsAvailable ); - btLampkaPrzetwOff.Turn( false == mvOccupied->Power110vIsAvailable ); - btLampkaNadmPrzetw.Turn( Dynamic()->Mechanik ? Dynamic()->Mechanik->IsAnyConverterOverloadRelayOpen : mvControlled->ConvOvldFlag ); - - btLampkaOpory.Turn( - mvControlled->StLinFlag ? - mvControlled->ResistorsFlagCheck() : - false ); - - btLampkaBezoporowa.Turn( - ( true == mvControlled->ResistorsFlagCheck() ) - || ( mvControlled->MainCtrlActualPos == 0 ) ); // do EU04 - - btLampkaStyczn.Turn( - ( ( mvControlled->StLinFlag ) || ( mvControlled->ControlPressureSwitch ) ) ? - false : - ( mvControlled->BrakePress < 1.0 ) ); // mozna prowadzic rozruch - - btLampkaPrzekRozn.Turn( - ( ( mvControlled->GroundRelay ) || ( mvControlled->ControlPressureSwitch ) ) ? - false : - ( mvControlled->BrakePress < 1.0 ) ); // relay is off and needs a reset - - btLampkaNadmSil.Turn( - ( ( false == mvControlled->FuseFlagCheck() ) || ( mvControlled->ControlPressureSwitch ) ) ? - false : - ( mvControlled->BrakePress < 1.0 ) ); // relay is off and needs a reset - - if( ( ( mvControlled->CabOccupied == 1 ) && ( TestFlag( mvControlled->Couplers[ end::rear ].CouplingFlag, coupling::control ) ) ) - || ( ( mvControlled->CabOccupied == -1 ) && ( TestFlag( mvControlled->Couplers[ end::front ].CouplingFlag, coupling::control ) ) ) ) { - btLampkaUkrotnienie.Turn( true ); - } - else { - btLampkaUkrotnienie.Turn( false ); - } - - // if - // ((TestFlag(mvControlled->BrakeStatus,+b_Rused+b_Ractive)))//Lampka drugiego stopnia hamowania - btLampkaHamPosp.Turn((TestFlag(mvOccupied->Hamulec->GetBrakeStatus(), 1))); // lampka drugiego stopnia hamowania - //TODO: youBy wyciągnąć flagę wysokiego stopnia - - // hunter-121211: lampka zanikowo-pradowego wentylatorow: - btLampkaNadmWent.Turn( ( mvControlled->RventRot < 5.0 ) && ( mvControlled->ResistorsFlagCheck() ) ); - //------- - - btLampkaWysRozr.Turn(!(mvControlled->Imax < mvControlled->ImaxHi)); - - if( ( false == mvControlled->DelayCtrlFlag ) - && ( ( mvControlled->ScndCtrlActualPos > 0 ) - || ( ( mvControlled->RList[ mvControlled->MainCtrlActualPos ].ScndAct != 0 ) - && ( mvControlled->RList[ mvControlled->MainCtrlActualPos ].ScndAct != 255 ) ) ) ) { - btLampkaBoczniki.Turn( true ); - } - else { - btLampkaBoczniki.Turn( false ); - } - - btLampkaNapNastHam.Turn(mvControlled->DirActive != 0); // napiecie na nastawniku hamulcowym - btLampkaSprezarka.Turn(mvControlled->CompressorFlag); // mutopsitka dziala - btLampkaSprezarkaOff.Turn( false == mvControlled->CompressorFlag ); - btLampkaFuelPumpOff.Turn( false == mvControlled->FuelPump.is_active ); - // boczniki - unsigned char scp; // Ra: dopisałem "unsigned" - // Ra: w SU45 boczniki wchodzą na MainCtrlPos, a nie na MainCtrlActualPos - // - pokićkał ktoś? - scp = mvControlled->RList[mvControlled->MainCtrlPos].ScndAct; - scp = (scp == 255 ? 0 : scp); // Ra: whatta hella is this? - if ((mvControlled->ScndCtrlPos > 0) || (mvControlled->ScndInMain != 0) && (scp > 0)) - { // boczniki pojedynczo - btLampkaBocznik1.Turn( true ); - btLampkaBocznik2.Turn(mvControlled->ScndCtrlPos > 1); - btLampkaBocznik3.Turn(mvControlled->ScndCtrlPos > 2); - btLampkaBocznik4.Turn(mvControlled->ScndCtrlPos > 3); - } - else - { // wyłączone wszystkie cztery - btLampkaBocznik1.Turn( false ); - btLampkaBocznik2.Turn( false ); - btLampkaBocznik3.Turn( false ); - btLampkaBocznik4.Turn( false ); - } - - if( mvControlled->Signalling == true ) { - if( mvOccupied->BrakePress >= 1.45f ) { - btLampkaHamowanie1zes.Turn( true ); - } - if( mvControlled->BrakePress < 0.75f ) { - btLampkaHamowanie1zes.Turn( false ); - } - } - else { - btLampkaHamowanie1zes.Turn( false ); - } - - switch (mvControlled->TrainType) { - // zależnie od typu lokomotywy - case dt_EZT: { - btLampkaHamienie.Turn( ( mvControlled->BrakePress >= 0.2 ) && mvControlled->Signalling ); - break; - } - case dt_ET41: { - // odhamowanie drugiego członu - if( mvSecond ) { - // bo może komuś przyjść do głowy jeżdżenie jednym członem - btLampkaHamienie.Turn( mvSecond->BrakePress < 0.4 ); - } - break; - } - default: { - btLampkaHamienie.Turn( ( mvOccupied->BrakePress >= 0.1 ) || mvControlled->DynamicBrakeFlag ); - btLampkaBrakingOff.Turn( ( mvOccupied->BrakePress < 0.1 ) && ( false == mvControlled->DynamicBrakeFlag ) ); - break; - } - } - // KURS90 - btLampkaMaxSila.Turn(abs(mvControlled->Im) >= 350); - btLampkaPrzekrMaxSila.Turn(abs(mvControlled->Im) >= 450); - btLampkaRadio.Turn(mvOccupied->Radio); - btLampkaRadioMessage.Turn(radio_message_played); - btLampkaRadioStop.Turn( mvOccupied->Radio && mvOccupied->RadioStopFlag ); - btLampkaHamulecReczny.Turn(mvOccupied->ManualBrakePos > 0); - // NBMX wrzesien 2003 - drzwi oraz sygnał odjazdu - if( DynamicObject->Mechanik != nullptr ) { - btLampkaDoorLeft.Turn( DynamicObject->Mechanik->IsAnyDoorOpen[ ( cab_to_end() == end::front ? side::left : side::right ) ] ); - btLampkaDoorRight.Turn( DynamicObject->Mechanik->IsAnyDoorOpen[ ( cab_to_end() == end::front ? side::right : side::left ) ] ); - } - btLampkaBlokadaDrzwi.Turn( mvOccupied->Doors.is_locked ); - btLampkaDoorLockOff.Turn( false == mvOccupied->Doors.lock_enabled ); - btLampkaDepartureSignal.Turn( mvControlled->DepartureSignal ); - btLampkaNapNastHam.Turn((mvControlled->DirActive != 0) && (mvOccupied->EpFuse)); // napiecie na nastawniku hamulcowym - - // Wylaczanie lampek kierunku gdy jedziemy - // Feature uruchamiany z fiz z sekcji Ctrl. wpisem HideDirStatusWhenMoving=Yes (domyslnie No) - if (mvOccupied->HideDirStatusWhenMoving && // Czy ta funkcja jest w ogole wlaczona - mvOccupied->Vel > mvOccupied->HideDirStatusSpeed) // Uzaleznienie od predkosci + if (true == lowvoltagepower) + { + // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa + if (mvOccupied->SecuritySystem.is_vigilance_blinking()) { - btLampkaForward.Turn(false); + if (fBlinkTimer > fCzuwakBlink) + fBlinkTimer = -fCzuwakBlink; + else + fBlinkTimer += Deltatime; + + btLampkaCzuwaka.Turn(fBlinkTimer > 0); + } + else + { + fBlinkTimer = 0.0; + btLampkaCzuwaka.Turn(false); + } + + btLampkaSHP.Turn(mvOccupied->SecuritySystem.is_cabsignal_blinking()); + btLampkaCzuwakaSHP.Turn(btLampkaSHP.GetValue() || btLampkaCzuwaka.GetValue()); + + btLampkaWylSzybki.Turn((((m_linebreakerstate == 2) || (true == mvControlled->Mains)) ? true : false)); + btLampkaWylSzybkiOff.Turn((((m_linebreakerstate == 2) || (true == mvControlled->Mains)) ? false : true)); + btLampkaMainBreakerReady.Turn((((mvControlled->MainsInitTimeCountdown > 0.0) || (m_linebreakerstate == 2) || (true == mvControlled->Mains)) ? false : true)); + btLampkaMainBreakerBlinkingIfReady.Turn( + (((m_linebreakerstate == 2) || (true == mvControlled->Mains) || ((mvControlled->MainsInitTimeCountdown < 0.0) && (simulation::Time.data().wMilliseconds > 500))) ? true : false)); + + btLampkaPrzetw.Turn(mvOccupied->Power110vIsAvailable); + btLampkaPrzetwOff.Turn(false == mvOccupied->Power110vIsAvailable); + btLampkaNadmPrzetw.Turn(Dynamic()->Mechanik ? Dynamic()->Mechanik->IsAnyConverterOverloadRelayOpen : mvControlled->ConvOvldFlag); + + btLampkaOpory.Turn(mvControlled->StLinFlag ? mvControlled->ResistorsFlagCheck() : false); + + btLampkaBezoporowa.Turn((true == mvControlled->ResistorsFlagCheck()) || (mvControlled->MainCtrlActualPos == 0)); // do EU04 + + btLampkaStyczn.Turn(((mvControlled->StLinFlag) || (mvControlled->ControlPressureSwitch)) ? false : (mvControlled->BrakePress < 1.0)); // mozna prowadzic rozruch + + btLampkaPrzekRozn.Turn(((mvControlled->GroundRelay) || (mvControlled->ControlPressureSwitch)) ? false : (mvControlled->BrakePress < 1.0)); // relay is off and needs a reset + + btLampkaNadmSil.Turn(((false == mvControlled->FuseFlagCheck()) || (mvControlled->ControlPressureSwitch)) ? false : (mvControlled->BrakePress < 1.0)); // relay is off and needs a reset + + if (((mvControlled->CabOccupied == 1) && (TestFlag(mvControlled->Couplers[end::rear].CouplingFlag, coupling::control))) || + ((mvControlled->CabOccupied == -1) && (TestFlag(mvControlled->Couplers[end::front].CouplingFlag, coupling::control)))) + { + btLampkaUkrotnienie.Turn(true); + } + else + { + btLampkaUkrotnienie.Turn(false); + } + + // if + // ((TestFlag(mvControlled->BrakeStatus,+b_Rused+b_Ractive)))//Lampka drugiego stopnia hamowania + btLampkaHamPosp.Turn((TestFlag(mvOccupied->Hamulec->GetBrakeStatus(), 1))); // lampka drugiego stopnia hamowania + // TODO: youBy wyciągnąć flagę wysokiego stopnia + + // hunter-121211: lampka zanikowo-pradowego wentylatorow: + btLampkaNadmWent.Turn((mvControlled->RventRot < 5.0) && (mvControlled->ResistorsFlagCheck())); + //------- + + btLampkaWysRozr.Turn(!(mvControlled->Imax < mvControlled->ImaxHi)); + + if ((false == mvControlled->DelayCtrlFlag) && + ((mvControlled->ScndCtrlActualPos > 0) || ((mvControlled->RList[mvControlled->MainCtrlActualPos].ScndAct != 0) && (mvControlled->RList[mvControlled->MainCtrlActualPos].ScndAct != 255)))) + { + btLampkaBoczniki.Turn(true); + } + else + { + btLampkaBoczniki.Turn(false); + } + + btLampkaNapNastHam.Turn(mvControlled->DirActive != 0); // napiecie na nastawniku hamulcowym + btLampkaSprezarka.Turn(mvControlled->CompressorFlag); // mutopsitka dziala + btLampkaSprezarkaOff.Turn(false == mvControlled->CompressorFlag); + btLampkaFuelPumpOff.Turn(false == mvControlled->FuelPump.is_active); + // boczniki + unsigned char scp; // Ra: dopisałem "unsigned" + // Ra: w SU45 boczniki wchodzą na MainCtrlPos, a nie na MainCtrlActualPos + // - pokićkał ktoś? + scp = mvControlled->RList[mvControlled->MainCtrlPos].ScndAct; + scp = (scp == 255 ? 0 : scp); // Ra: whatta hella is this? + if ((mvControlled->ScndCtrlPos > 0) || (mvControlled->ScndInMain != 0) && (scp > 0)) + { // boczniki pojedynczo + btLampkaBocznik1.Turn(true); + btLampkaBocznik2.Turn(mvControlled->ScndCtrlPos > 1); + btLampkaBocznik3.Turn(mvControlled->ScndCtrlPos > 2); + btLampkaBocznik4.Turn(mvControlled->ScndCtrlPos > 3); + } + else + { // wyłączone wszystkie cztery + btLampkaBocznik1.Turn(false); + btLampkaBocznik2.Turn(false); + btLampkaBocznik3.Turn(false); + btLampkaBocznik4.Turn(false); + } + + if (mvControlled->Signalling == true) + { + if (mvOccupied->BrakePress >= 1.45f) + { + btLampkaHamowanie1zes.Turn(true); + } + if (mvControlled->BrakePress < 0.75f) + { + btLampkaHamowanie1zes.Turn(false); + } + } + else + { + btLampkaHamowanie1zes.Turn(false); + } + + switch (mvControlled->TrainType) + { + // zależnie od typu lokomotywy + case dt_EZT: + { + btLampkaHamienie.Turn((mvControlled->BrakePress >= 0.2) && mvControlled->Signalling); + break; + } + case dt_ET41: + { + // odhamowanie drugiego członu + if (mvSecond) + { + // bo może komuś przyjść do głowy jeżdżenie jednym członem + btLampkaHamienie.Turn(mvSecond->BrakePress < 0.4); + } + break; + } + default: + { + btLampkaHamienie.Turn((mvOccupied->BrakePress >= 0.1) || mvControlled->DynamicBrakeFlag); + btLampkaBrakingOff.Turn((mvOccupied->BrakePress < 0.1) && (false == mvControlled->DynamicBrakeFlag)); + break; + } + } + // KURS90 + btLampkaMaxSila.Turn(abs(mvControlled->Im) >= 350); + btLampkaPrzekrMaxSila.Turn(abs(mvControlled->Im) >= 450); + btLampkaRadio.Turn(mvOccupied->Radio); + btLampkaRadioMessage.Turn(radio_message_played); + btLampkaRadioStop.Turn(mvOccupied->Radio && mvOccupied->RadioStopFlag); + btLampkaHamulecReczny.Turn(mvOccupied->ManualBrakePos > 0); + // NBMX wrzesien 2003 - drzwi oraz sygnał odjazdu + if (DynamicObject->Mechanik != nullptr) + { + btLampkaDoorLeft.Turn(DynamicObject->Mechanik->IsAnyDoorOpen[(cab_to_end() == end::front ? side::left : side::right)]); + btLampkaDoorRight.Turn(DynamicObject->Mechanik->IsAnyDoorOpen[(cab_to_end() == end::front ? side::right : side::left)]); + } + btLampkaBlokadaDrzwi.Turn(mvOccupied->Doors.is_locked); + btLampkaDoorLockOff.Turn(false == mvOccupied->Doors.lock_enabled); + btLampkaDepartureSignal.Turn(mvControlled->DepartureSignal); + btLampkaNapNastHam.Turn((mvControlled->DirActive != 0) && (mvOccupied->EpFuse)); // napiecie na nastawniku hamulcowym + + // Wylaczanie lampek kierunku gdy jedziemy + // Feature uruchamiany z fiz z sekcji Ctrl. wpisem HideDirStatusWhenMoving=Yes (domyslnie No) + if (mvOccupied->HideDirStatusWhenMoving && // Czy ta funkcja jest w ogole wlaczona + mvOccupied->Vel > mvOccupied->HideDirStatusSpeed) // Uzaleznienie od predkosci + { + btLampkaForward.Turn(false); btLampkaBackward.Turn(false); btLampkaNeutral.Turn(false); - } - else { + } + else + { btLampkaForward.Turn(mvControlled->DirActive > 0); // jazda do przodu btLampkaBackward.Turn(mvControlled->DirActive < 0); // jazda do tyłu btLampkaNeutral.Turn(mvControlled->DirActive == 0); // kierunek neutral - } + } - btLampkaED.Turn(mvControlled->DynamicBrakeFlag); // hamulec ED - btLampkaBrakeProfileG.Turn( TestFlag( mvOccupied->BrakeDelayFlag, bdelay_G ) ); - btLampkaBrakeProfileP.Turn( TestFlag( mvOccupied->BrakeDelayFlag, bdelay_P ) ); - btLampkaBrakeProfileR.Turn( TestFlag( mvOccupied->BrakeDelayFlag, bdelay_R ) ); - btLampkaSpringBrakeActive.Turn( mvOccupied->SpringBrake.IsActive ); - btLampkaSpringBrakeInactive.Turn( !mvOccupied->SpringBrake.IsActive ); - // light indicators - // NOTE: sides are hardcoded to deal with setups where single cab is equipped with all indicators - btLampkaUpperLight.Turn( ( mvOccupied->iLights[ end::front ] & light::headlight_upper ) != 0 ); - btLampkaLeftLight.Turn( ( mvOccupied->iLights[ end::front ] & light::headlight_left ) != 0 ); - btLampkaRightLight.Turn( ( mvOccupied->iLights[ end::front ] & light::headlight_right ) != 0 ); - btLampkaLeftEndLight.Turn( ( mvOccupied->iLights[ end::front ] & light::redmarker_left ) != 0 ); - btLampkaRightEndLight.Turn( ( mvOccupied->iLights[ end::front ] & light::redmarker_right ) != 0 ); - btLampkaRearUpperLight.Turn( ( mvOccupied->iLights[ end::rear ] & light::headlight_upper ) != 0 ); - btLampkaRearLeftLight.Turn( ( mvOccupied->iLights[ end::rear ] & light::headlight_left ) != 0 ); - btLampkaRearRightLight.Turn( ( mvOccupied->iLights[ end::rear ] & light::headlight_right ) != 0 ); - btLampkaRearLeftEndLight.Turn( ( mvOccupied->iLights[ end::rear ] & light::redmarker_left ) != 0 ); - btLampkaRearRightEndLight.Turn( ( mvOccupied->iLights[ end::rear ] & light::redmarker_right ) != 0 ); - // others - btLampkaMalfunction.Turn( mvControlled->dizel_heat.PA ); - // overheat indicator lamps - btLampkaOilOverheat.Turn( mvControlled->dizel_heat.oil.is_hot ); - btLampkaWaterOverheat.Turn( mvControlled->dizel_heat.water.is_hot ); - btLampkaWaterAuxOverheat.Turn( mvControlled->dizel_heat.water_aux.is_hot ); - btLampkaEngineOverheat.Turn( mvControlled->dizel_heat.engine_is_hot ); - btLampkaMotorBlowers.Turn( ( mvControlled->MotorBlowers[ end::front ].is_active ) && ( mvControlled->MotorBlowers[ end::rear ].is_active ) ); - btLampkaCoolingFans.Turn( mvControlled->RventRot > 1.0 ); - btLampkaTempomat.Turn( mvOccupied->SpeedCtrlUnit.IsActive ); - btLampkaDistanceCounter.Turn( m_distancecounter >= 0.f ); - // universal devices state indicators - for( auto idx = 0; idx < btUniversals.size(); ++idx ) { - btUniversals[ idx ].Turn( ggUniversals[ idx ].GetValue() > 0.5 ); - } - } - else { - // wylaczone - btLampkaCzuwaka.Turn( false ); - btLampkaSHP.Turn( false ); - btLampkaCzuwakaSHP.Turn( false ); - btLampkaWylSzybki.Turn( false ); - btLampkaWylSzybkiOff.Turn( false ); - btLampkaMainBreakerReady.Turn( false ); - btLampkaMainBreakerBlinkingIfReady.Turn( false ); - btLampkaWysRozr.Turn( false ); - btLampkaOpory.Turn( false ); - btLampkaStyczn.Turn( false ); - btLampkaUkrotnienie.Turn( false ); - btLampkaHamPosp.Turn( false ); - btLampkaBoczniki.Turn( false ); - btLampkaNapNastHam.Turn( false ); - btLampkaPrzetw.Turn( false ); - btLampkaPrzetwOff.Turn( false ); - btLampkaNadmPrzetw.Turn( false ); - btLampkaSprezarka.Turn( false ); - btLampkaSprezarkaOff.Turn( false ); - btLampkaFuelPumpOff.Turn( false ); - btLampkaBezoporowa.Turn( false ); - btLampkaHamowanie1zes.Turn( false ); - btLampkaHamienie.Turn( false ); - btLampkaBrakingOff.Turn( false ); - btLampkaBrakeProfileG.Turn( false ); - btLampkaBrakeProfileP.Turn( false ); - btLampkaBrakeProfileR.Turn( false ); - btLampkaSpringBrakeActive.Turn( false ); - btLampkaSpringBrakeInactive.Turn( false ); - // overheat indicator lamps off - btLampkaOilOverheat.Turn( false ); - btLampkaWaterOverheat.Turn( false ); - btLampkaWaterAuxOverheat.Turn( false ); - btLampkaEngineOverheat.Turn( false ); - btLampkaMaxSila.Turn( false ); - btLampkaPrzekrMaxSila.Turn( false ); - btLampkaRadio.Turn( false ); - btLampkaRadioMessage.Turn( false ); - btLampkaRadioStop.Turn( false ); - btLampkaHamulecReczny.Turn( false ); - btLampkaDoorLeft.Turn( false ); - btLampkaDoorRight.Turn( false ); - btLampkaBlokadaDrzwi.Turn( false ); - btLampkaDoorLockOff.Turn( false ); - btLampkaDepartureSignal.Turn( false ); - btLampkaNapNastHam.Turn( false ); - btLampkaForward.Turn( false ); - btLampkaBackward.Turn( false ); + btLampkaED.Turn(mvControlled->DynamicBrakeFlag); // hamulec ED + btLampkaBrakeProfileG.Turn(TestFlag(mvOccupied->BrakeDelayFlag, bdelay_G)); + btLampkaBrakeProfileP.Turn(TestFlag(mvOccupied->BrakeDelayFlag, bdelay_P)); + btLampkaBrakeProfileR.Turn(TestFlag(mvOccupied->BrakeDelayFlag, bdelay_R)); + btLampkaSpringBrakeActive.Turn(mvOccupied->SpringBrake.IsActive); + btLampkaSpringBrakeInactive.Turn(!mvOccupied->SpringBrake.IsActive); + // light indicators + // NOTE: sides are hardcoded to deal with setups where single cab is equipped with all indicators + btLampkaUpperLight.Turn((mvOccupied->iLights[end::front] & light::headlight_upper) != 0); + btLampkaLeftLight.Turn((mvOccupied->iLights[end::front] & light::headlight_left) != 0); + btLampkaRightLight.Turn((mvOccupied->iLights[end::front] & light::headlight_right) != 0); + btLampkaLeftEndLight.Turn((mvOccupied->iLights[end::front] & light::redmarker_left) != 0); + btLampkaRightEndLight.Turn((mvOccupied->iLights[end::front] & light::redmarker_right) != 0); + btLampkaRearUpperLight.Turn((mvOccupied->iLights[end::rear] & light::headlight_upper) != 0); + btLampkaRearLeftLight.Turn((mvOccupied->iLights[end::rear] & light::headlight_left) != 0); + btLampkaRearRightLight.Turn((mvOccupied->iLights[end::rear] & light::headlight_right) != 0); + btLampkaRearLeftEndLight.Turn((mvOccupied->iLights[end::rear] & light::redmarker_left) != 0); + btLampkaRearRightEndLight.Turn((mvOccupied->iLights[end::rear] & light::redmarker_right) != 0); + // others + btLampkaMalfunction.Turn(mvControlled->dizel_heat.PA); + // overheat indicator lamps + btLampkaOilOverheat.Turn(mvControlled->dizel_heat.oil.is_hot); + btLampkaWaterOverheat.Turn(mvControlled->dizel_heat.water.is_hot); + btLampkaWaterAuxOverheat.Turn(mvControlled->dizel_heat.water_aux.is_hot); + btLampkaEngineOverheat.Turn(mvControlled->dizel_heat.engine_is_hot); + btLampkaMotorBlowers.Turn((mvControlled->MotorBlowers[end::front].is_active) && (mvControlled->MotorBlowers[end::rear].is_active)); + btLampkaCoolingFans.Turn(mvControlled->RventRot > 1.0); + btLampkaTempomat.Turn(mvOccupied->SpeedCtrlUnit.IsActive); + btLampkaDistanceCounter.Turn(m_distancecounter >= 0.f); + // universal devices state indicators + for (auto idx = 0; idx < btUniversals.size(); ++idx) + { + btUniversals[idx].Turn(ggUniversals[idx].GetValue() > 0.5); + } + } + else + { + // wylaczone + btLampkaCzuwaka.Turn(false); + btLampkaSHP.Turn(false); + btLampkaCzuwakaSHP.Turn(false); + btLampkaWylSzybki.Turn(false); + btLampkaWylSzybkiOff.Turn(false); + btLampkaMainBreakerReady.Turn(false); + btLampkaMainBreakerBlinkingIfReady.Turn(false); + btLampkaWysRozr.Turn(false); + btLampkaOpory.Turn(false); + btLampkaStyczn.Turn(false); + btLampkaUkrotnienie.Turn(false); + btLampkaHamPosp.Turn(false); + btLampkaBoczniki.Turn(false); + btLampkaNapNastHam.Turn(false); + btLampkaPrzetw.Turn(false); + btLampkaPrzetwOff.Turn(false); + btLampkaNadmPrzetw.Turn(false); + btLampkaSprezarka.Turn(false); + btLampkaSprezarkaOff.Turn(false); + btLampkaFuelPumpOff.Turn(false); + btLampkaBezoporowa.Turn(false); + btLampkaHamowanie1zes.Turn(false); + btLampkaHamienie.Turn(false); + btLampkaBrakingOff.Turn(false); + btLampkaBrakeProfileG.Turn(false); + btLampkaBrakeProfileP.Turn(false); + btLampkaBrakeProfileR.Turn(false); + btLampkaSpringBrakeActive.Turn(false); + btLampkaSpringBrakeInactive.Turn(false); + // overheat indicator lamps off + btLampkaOilOverheat.Turn(false); + btLampkaWaterOverheat.Turn(false); + btLampkaWaterAuxOverheat.Turn(false); + btLampkaEngineOverheat.Turn(false); + btLampkaMaxSila.Turn(false); + btLampkaPrzekrMaxSila.Turn(false); + btLampkaRadio.Turn(false); + btLampkaRadioMessage.Turn(false); + btLampkaRadioStop.Turn(false); + btLampkaHamulecReczny.Turn(false); + btLampkaDoorLeft.Turn(false); + btLampkaDoorRight.Turn(false); + btLampkaBlokadaDrzwi.Turn(false); + btLampkaDoorLockOff.Turn(false); + btLampkaDepartureSignal.Turn(false); + btLampkaNapNastHam.Turn(false); + btLampkaForward.Turn(false); + btLampkaBackward.Turn(false); btLampkaNeutral.Turn(false); - btLampkaED.Turn( false ); - // light indicators - btLampkaUpperLight.Turn( false ); - btLampkaLeftLight.Turn( false ); - btLampkaRightLight.Turn( false ); - btLampkaLeftEndLight.Turn( false ); - btLampkaRightEndLight.Turn( false ); - btLampkaRearUpperLight.Turn( false ); - btLampkaRearLeftLight.Turn( false ); - btLampkaRearRightLight.Turn( false ); - btLampkaRearLeftEndLight.Turn( false ); - btLampkaRearRightEndLight.Turn( false ); - // others - btLampkaMalfunction.Turn( false ); - btLampkaMotorBlowers.Turn( false ); - btLampkaCoolingFans.Turn( false ); - btLampkaTempomat.Turn( false ); - btLampkaDistanceCounter.Turn( false ); - // universal devices state indicators - for( auto &universal : btUniversals ) { - universal.Turn( false ); - } - } + btLampkaED.Turn(false); + // light indicators + btLampkaUpperLight.Turn(false); + btLampkaLeftLight.Turn(false); + btLampkaRightLight.Turn(false); + btLampkaLeftEndLight.Turn(false); + btLampkaRightEndLight.Turn(false); + btLampkaRearUpperLight.Turn(false); + btLampkaRearLeftLight.Turn(false); + btLampkaRearRightLight.Turn(false); + btLampkaRearLeftEndLight.Turn(false); + btLampkaRearRightEndLight.Turn(false); + // others + btLampkaMalfunction.Turn(false); + btLampkaMotorBlowers.Turn(false); + btLampkaCoolingFans.Turn(false); + btLampkaTempomat.Turn(false); + btLampkaDistanceCounter.Turn(false); + // universal devices state indicators + for (auto &universal : btUniversals) + { + universal.Turn(false); + } + } - { // yB - wskazniki drugiego czlonu - TDynamicObject *tmp { nullptr }; //=mvControlled->mvSecond; //Ra 2014-07: trzeba to jeszcze wyjąć z kabiny... - // Ra 2014-07: no nie ma potrzeby szukać tego w każdej klatce - if ((TestFlag(mvControlled->Couplers[1].CouplingFlag, coupling::control)) && - (mvOccupied->CabOccupied > 0)) - tmp = DynamicObject->NextConnected(); - if ((TestFlag(mvControlled->Couplers[0].CouplingFlag, coupling::control)) && - (mvOccupied->CabOccupied < 0)) - tmp = DynamicObject->PrevConnected(); + { // yB - wskazniki drugiego czlonu + TDynamicObject *tmp{nullptr}; //=mvControlled->mvSecond; //Ra 2014-07: trzeba to jeszcze wyjąć z kabiny... + // Ra 2014-07: no nie ma potrzeby szukać tego w każdej klatce + if ((TestFlag(mvControlled->Couplers[1].CouplingFlag, coupling::control)) && (mvOccupied->CabOccupied > 0)) + tmp = DynamicObject->NextConnected(); + if ((TestFlag(mvControlled->Couplers[0].CouplingFlag, coupling::control)) && (mvOccupied->CabOccupied < 0)) + tmp = DynamicObject->PrevConnected(); - if( tmp ) { - if( lowvoltagepower ) { + if (tmp) + { + if (lowvoltagepower) + { - auto const *mover{ tmp->MoverParameters }; + auto const *mover{tmp->MoverParameters}; - btLampkaWylSzybkiB.Turn( mover->Mains ); - btLampkaWylSzybkiBOff.Turn( - ( false == mover->Mains ) - /*&& ( mover->MainsInitTimeCountdown <= 0.0 )*/ - /*&& ( fHVoltage != 0.0 )*/ ); + btLampkaWylSzybkiB.Turn(mover->Mains); + btLampkaWylSzybkiBOff.Turn((false == mover->Mains) + /*&& ( mover->MainsInitTimeCountdown <= 0.0 )*/ + /*&& ( fHVoltage != 0.0 )*/); - btLampkaOporyB.Turn( mover->ResistorsFlagCheck() ); - btLampkaBezoporowaB.Turn( - ( true == mover->ResistorsFlagCheck() ) - || ( mover->MainCtrlActualPos == 0 ) ); // do EU04 + btLampkaOporyB.Turn(mover->ResistorsFlagCheck()); + btLampkaBezoporowaB.Turn((true == mover->ResistorsFlagCheck()) || (mover->MainCtrlActualPos == 0)); // do EU04 - if( ( mover->StLinFlag ) - || ( mover->ControlPressureSwitch ) ) { - btLampkaStycznB.Turn( false ); - } - else if( mover->BrakePress < 1.0 ) { - btLampkaStycznB.Turn( true ); // mozna prowadzic rozruch - } - // hunter-271211: sygnalizacja poslizgu w pierwszym pojezdzie, gdy wystapi w drugim - if( mover->SlippingWheels ) { - // Ra 2014-12: lokomotywy 181/182 dostają SlippingWheels po zahamowaniu powyżej 2.85 bara i buczały - auto const veldiff { ( DynamicObject->GetVelocity() - fTachoVelocity ) / mvControlled->Vmax }; - if( veldiff < -0.01 ) { - // 1% Vmax rezerwy, żeby 181/182 nie buczały po zahamowaniu, ale to proteza - auto const lightstate { std::abs( mover->Im ) > 10.0 }; - btLampkaPoslizg.Turn( btLampkaPoslizg.GetValue() || lightstate ); - } - } + if ((mover->StLinFlag) || (mover->ControlPressureSwitch)) + { + btLampkaStycznB.Turn(false); + } + else if (mover->BrakePress < 1.0) + { + btLampkaStycznB.Turn(true); // mozna prowadzic rozruch + } + // hunter-271211: sygnalizacja poslizgu w pierwszym pojezdzie, gdy wystapi w drugim + if (mover->SlippingWheels) + { + // Ra 2014-12: lokomotywy 181/182 dostają SlippingWheels po zahamowaniu powyżej 2.85 bara i buczały + auto const veldiff{(DynamicObject->GetVelocity() - fTachoVelocity) / mvControlled->Vmax}; + if (veldiff < -0.01) + { + // 1% Vmax rezerwy, żeby 181/182 nie buczały po zahamowaniu, ale to proteza + auto const lightstate{std::abs(mover->Im) > 10.0}; + btLampkaPoslizg.Turn(btLampkaPoslizg.GetValue() || lightstate); + } + } - btLampkaSprezarkaB.Turn( mover->CompressorFlag ); // mutopsitka dziala - btLampkaSprezarkaBOff.Turn( false == mover->CompressorFlag ); - if( mvControlled->Signalling == true ) { - if( mover->BrakePress >= 1.45f ) { - btLampkaHamowanie2zes.Turn( true ); - } - if( mover->BrakePress < 0.75f ) { - btLampkaHamowanie2zes.Turn( false ); - } - } - else { - btLampkaHamowanie2zes.Turn( false ); - } - btLampkaNadmPrzetwB.Turn( mover->ConvOvldFlag ); // nadmiarowy przetwornicy? - btLampkaPrzetwB.Turn( mover->ConverterFlag ); // zalaczenie przetwornicy - btLampkaPrzetwBOff.Turn( false == mover->ConverterFlag ); - btLampkaHVoltageB.Turn( mover->NoVoltRelay && mover->OvervoltageRelay ); - btLampkaMalfunctionB.Turn( mover->dizel_heat.PA ); - // motor fuse indicator turns on if the fuse was blown in any unit under control - if( mover->Mains ) { - btLampkaNadmSil.Turn( btLampkaNadmSil.GetValue() || mover->FuseFlagCheck() ); - } - } - else // wylaczone - { - btLampkaWylSzybkiB.Turn( false ); - btLampkaWylSzybkiBOff.Turn( false ); - btLampkaOporyB.Turn( false ); - btLampkaStycznB.Turn( false ); - btLampkaSprezarkaB.Turn( false ); - btLampkaSprezarkaBOff.Turn( false ); - btLampkaBezoporowaB.Turn( false ); - btLampkaHamowanie2zes.Turn( false ); - btLampkaNadmPrzetwB.Turn( false ); - btLampkaPrzetwB.Turn( false ); - btLampkaPrzetwBOff.Turn( false ); - btLampkaHVoltageB.Turn( false ); - btLampkaMalfunctionB.Turn( false ); - } - } - } - // McZapkie-080602: obroty (albo translacje) regulatorow - if( ggJointCtrl.SubModel != nullptr ) { - // joint master controller moves forward to adjust power and backward to adjust brakes - auto const brakerangemultiplier { - /* NOTE: scaling disabled as it was conflicting with associating sounds with control positions - ( mvControlled->CoupledCtrl ? - mvControlled->MainCtrlPosNo + mvControlled->ScndCtrlPosNo : - mvControlled->MainCtrlPosNo ) - / static_cast(LocalBrakePosNo) - */ - 1 }; - ggJointCtrl.UpdateValue( - ( mvOccupied->LocalBrakePosA > 0.0 ? mvOccupied->LocalBrakePosA * LocalBrakePosNo * -1 * brakerangemultiplier : - mvControlled->CoupledCtrl ? double( mvControlled->MainCtrlPos + mvControlled->ScndCtrlPos ) : - double( mvControlled->MainCtrlPos ) ), - dsbNastawnikJazdy ); - ggJointCtrl.Update(); - } - if ( ggMainCtrl.SubModel != nullptr ) { + btLampkaSprezarkaB.Turn(mover->CompressorFlag); // mutopsitka dziala + btLampkaSprezarkaBOff.Turn(false == mover->CompressorFlag); + if (mvControlled->Signalling == true) + { + if (mover->BrakePress >= 1.45f) + { + btLampkaHamowanie2zes.Turn(true); + } + if (mover->BrakePress < 0.75f) + { + btLampkaHamowanie2zes.Turn(false); + } + } + else + { + btLampkaHamowanie2zes.Turn(false); + } + btLampkaNadmPrzetwB.Turn(mover->ConvOvldFlag); // nadmiarowy przetwornicy? + btLampkaPrzetwB.Turn(mover->ConverterFlag); // zalaczenie przetwornicy + btLampkaPrzetwBOff.Turn(false == mover->ConverterFlag); + btLampkaHVoltageB.Turn(mover->NoVoltRelay && mover->OvervoltageRelay); + btLampkaMalfunctionB.Turn(mover->dizel_heat.PA); + // motor fuse indicator turns on if the fuse was blown in any unit under control + if (mover->Mains) + { + btLampkaNadmSil.Turn(btLampkaNadmSil.GetValue() || mover->FuseFlagCheck()); + } + } + else // wylaczone + { + btLampkaWylSzybkiB.Turn(false); + btLampkaWylSzybkiBOff.Turn(false); + btLampkaOporyB.Turn(false); + btLampkaStycznB.Turn(false); + btLampkaSprezarkaB.Turn(false); + btLampkaSprezarkaBOff.Turn(false); + btLampkaBezoporowaB.Turn(false); + btLampkaHamowanie2zes.Turn(false); + btLampkaNadmPrzetwB.Turn(false); + btLampkaPrzetwB.Turn(false); + btLampkaPrzetwBOff.Turn(false); + btLampkaHVoltageB.Turn(false); + btLampkaMalfunctionB.Turn(false); + } + } + } + // McZapkie-080602: obroty (albo translacje) regulatorow + if (ggJointCtrl.SubModel != nullptr) + { + // joint master controller moves forward to adjust power and backward to adjust brakes + auto const brakerangemultiplier{/* NOTE: scaling disabled as it was conflicting with associating sounds with control positions + ( mvControlled->CoupledCtrl ? + mvControlled->MainCtrlPosNo + mvControlled->ScndCtrlPosNo : + mvControlled->MainCtrlPosNo ) + / static_cast(LocalBrakePosNo) + */ + 1}; + // when SplitEDPneumaticBrake is active the negative range of the joint controller + // represents the dedicated dynamic-brake lever (DBPN steps), not the pneumatic local brake + auto const negativePart{mvControlled->SplitEDPneumaticBrake ? + (mvControlled->DynamicBrakeCtrlPos > 0.0 ? mvControlled->DynamicBrakeCtrlPos * mvControlled->DynamicBrakeCtrlPosNo * -1 * brakerangemultiplier : 0.0) : + (mvOccupied->LocalBrakePosA > 0.0 ? mvOccupied->LocalBrakePosA * LocalBrakePosNo * -1 * brakerangemultiplier : 0.0)}; + ggJointCtrl.UpdateValue((negativePart < 0.0 ? negativePart : + mvControlled->CoupledCtrl ? double(mvControlled->MainCtrlPos + mvControlled->ScndCtrlPos) : + double(mvControlled->MainCtrlPos)), + dsbNastawnikJazdy); + ggJointCtrl.Update(); + } + if (ggMainCtrl.SubModel != nullptr) + { #ifdef _WIN32 - if( ( DynamicObject->Mechanik != nullptr ) - && ( false == DynamicObject->Mechanik->AIControllFlag ) // nie blokujemy AI - && ( Global.iFeedbackMode == 4 ) - && ( Global.fCalibrateIn[ 2 ][ 1 ] != 0.0 ) ) { + if ((DynamicObject->Mechanik != nullptr) && (false == DynamicObject->Mechanik->AIControllFlag) // nie blokujemy AI + && (Global.iFeedbackMode == 4) && (Global.fCalibrateIn[2][1] != 0.0)) + { - set_master_controller( Console::AnalogCalibrateGet( 2 ) * mvOccupied->MainCtrlPosNo ); + set_master_controller(Console::AnalogCalibrateGet(2) * mvOccupied->MainCtrlPosNo); mvOccupied->eimic_analog = Console::AnalogCalibrateGet(2); } #endif - if( mvControlled->CoupledCtrl ) { - ggMainCtrl.UpdateValue( - double( mvControlled->MainCtrlPos + mvControlled->ScndCtrlPos ), - dsbNastawnikJazdy ); - } - else { - ggMainCtrl.UpdateValue( - double( mvControlled->MainCtrlPos ), - dsbNastawnikJazdy ); - } - ggMainCtrl.Update(); - } - if (ggMainCtrlAct.SubModel != nullptr ) - { - if (mvControlled->CoupledCtrl) - ggMainCtrlAct.UpdateValue( - double(mvControlled->MainCtrlActualPos + mvControlled->ScndCtrlActualPos)); - else - ggMainCtrlAct.UpdateValue(double(mvControlled->MainCtrlActualPos)); - ggMainCtrlAct.Update(); - } - if (ggScndCtrl.SubModel != nullptr ) { - // Ra: od byte odejmowane boolean i konwertowane potem na double? - if( false == ggScndCtrl.is_push() ) { - ggScndCtrl.UpdateValue( - double( mvControlled->ScndCtrlPos - - ( ( mvControlled->TrainType == dt_ET42 ) && mvControlled->DynamicBrakeFlag ) ), - dsbNastawnikBocz ); - } - ggScndCtrl.Update(); - } - if( ggScndCtrlButton.SubModel != nullptr ) { - if( ggScndCtrlButton.is_toggle() ) { - ggScndCtrlButton.UpdateValue( - ( ( mvControlled->ScndCtrlPos > 0 ) ? 1.f : 0.f ), - dsbSwitch ); - } - ggScndCtrlButton.Update( lowvoltagepower ); - } - if( ggScndCtrlOffButton.SubModel != nullptr ) { - ggScndCtrlOffButton.Update( lowvoltagepower ); - } - if( ggDistanceCounterButton.SubModel != nullptr ) { - ggDistanceCounterButton.Update(); - } - if (ggDirKey.SubModel != nullptr ) { - if( mvControlled->TrainType != dt_EZT ) { - ggDirKey.UpdateValue( - double( mvControlled->DirActive ), - dsbReverserKey ); - } - else { - ggDirKey.UpdateValue( - double( mvControlled->DirActive ) + double( mvControlled->Imin == mvControlled->IminHi ), - dsbReverserKey ); - } - ggDirKey.Update(); - } - if (ggBrakeCtrl.SubModel != nullptr ) - { + if (mvControlled->CoupledCtrl) + { + ggMainCtrl.UpdateValue(double(mvControlled->MainCtrlPos + mvControlled->ScndCtrlPos), dsbNastawnikJazdy); + } + else + { + ggMainCtrl.UpdateValue(double(mvControlled->MainCtrlPos), dsbNastawnikJazdy); + } + ggMainCtrl.Update(); + } + if (ggMainCtrlAct.SubModel != nullptr) + { + if (mvControlled->CoupledCtrl) + ggMainCtrlAct.UpdateValue(double(mvControlled->MainCtrlActualPos + mvControlled->ScndCtrlActualPos)); + else + ggMainCtrlAct.UpdateValue(double(mvControlled->MainCtrlActualPos)); + ggMainCtrlAct.Update(); + } + if (ggScndCtrl.SubModel != nullptr) + { + // Ra: od byte odejmowane boolean i konwertowane potem na double? + if (false == ggScndCtrl.is_push()) + { + ggScndCtrl.UpdateValue(double(mvControlled->ScndCtrlPos - ((mvControlled->TrainType == dt_ET42) && mvControlled->DynamicBrakeFlag)), dsbNastawnikBocz); + } + ggScndCtrl.Update(); + } + if (ggScndCtrlButton.SubModel != nullptr) + { + if (ggScndCtrlButton.is_toggle()) + { + ggScndCtrlButton.UpdateValue(((mvControlled->ScndCtrlPos > 0) ? 1.f : 0.f), dsbSwitch); + } + ggScndCtrlButton.Update(lowvoltagepower); + } + if (ggScndCtrlOffButton.SubModel != nullptr) + { + ggScndCtrlOffButton.Update(lowvoltagepower); + } + if (ggDistanceCounterButton.SubModel != nullptr) + { + ggDistanceCounterButton.Update(); + } + if (ggDirKey.SubModel != nullptr) + { + if (mvControlled->TrainType != dt_EZT) + { + ggDirKey.UpdateValue(double(mvControlled->DirActive), dsbReverserKey); + } + else + { + ggDirKey.UpdateValue(double(mvControlled->DirActive) + double(mvControlled->Imin == mvControlled->IminHi), dsbReverserKey); + } + ggDirKey.Update(); + } + if (ggBrakeCtrl.SubModel != nullptr) + { #ifdef _WIN32 - if (DynamicObject->Mechanik ? - (DynamicObject->Mechanik->AIControllFlag ? false : - (Global.iFeedbackMode == 4 /*|| (Global.bMWDmasterEnable && Global.bMWDBreakEnable)*/)) : - false && Global.fCalibrateIn[ 0 ][ 1 ] != 0.0) // nie blokujemy AI - { // Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba + if (DynamicObject->Mechanik ? (DynamicObject->Mechanik->AIControllFlag ? false : (Global.iFeedbackMode == 4 /*|| (Global.bMWDmasterEnable && Global.bMWDBreakEnable)*/)) : + false && Global.fCalibrateIn[0][1] != 0.0) // nie blokujemy AI + { // Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba // Firleju: dlatego kasujemy i zastepujemy funkcją w Console if (mvOccupied->BrakeHandle == TBrakeHandle::FV4a) - { - double b = Console::AnalogCalibrateGet(0); + { + double b = Console::AnalogCalibrateGet(0); b = b * 8.0 - 2.0; - b = std::clamp( b, -2.0, (double)mvOccupied->BrakeCtrlPosNo ); // przycięcie zmiennej do granic + b = clamp(b, -2.0, mvOccupied->BrakeCtrlPosNo); // przycięcie zmiennej do granic ggBrakeCtrl.UpdateValue(b); // przesów bez zaokrąglenia mvOccupied->BrakeLevelSet(b); } - else if (mvOccupied->BrakeHandle == TBrakeHandle::FVel6) // może można usunąć ograniczenie do FV4a i FVel6? - { - double b = Console::AnalogCalibrateGet(0); + else if (mvOccupied->BrakeHandle == TBrakeHandle::FVel6) // może można usunąć ograniczenie do FV4a i FVel6? + { + double b = Console::AnalogCalibrateGet(0); b = b * 7.0 - 1.0; - b = std::clamp(b, -1.0, (double)mvOccupied->BrakeCtrlPosNo); // przycięcie zmiennej do granic - ggBrakeCtrl.UpdateValue(b); // przesów bez zaokrąglenia - mvOccupied->BrakeLevelSet(b); - } - else { - double b = Console::AnalogCalibrateGet( 0 ); - b = b * ( mvOccupied->Handle->GetPos( bh_MAX ) - mvOccupied->Handle->GetPos( bh_MIN ) ) + mvOccupied->Handle->GetPos( bh_MIN ); - b = std::clamp(b, mvOccupied->Handle->GetPos(bh_MIN), mvOccupied->Handle->GetPos(bh_MAX)); // przycięcie zmiennej do granic - ggBrakeCtrl.UpdateValue( b ); // przesów bez zaokrąglenia - mvOccupied->BrakeLevelSet( b ); - } - } - else + b = clamp(b, -1.0, mvOccupied->BrakeCtrlPosNo); // przycięcie zmiennej do granic + ggBrakeCtrl.UpdateValue(b); // przesów bez zaokrąglenia + mvOccupied->BrakeLevelSet(b); + } + else + { + double b = Console::AnalogCalibrateGet(0); + b = b * (mvOccupied->Handle->GetPos(bh_MAX) - mvOccupied->Handle->GetPos(bh_MIN)) + mvOccupied->Handle->GetPos(bh_MIN); + b = clamp(b, mvOccupied->Handle->GetPos(bh_MIN), mvOccupied->Handle->GetPos(bh_MAX)); // przycięcie zmiennej do granic + ggBrakeCtrl.UpdateValue(b); // przesów bez zaokrąglenia + mvOccupied->BrakeLevelSet(b); + } + } + else #endif - { - // else //standardowa prodedura z kranem powiązanym z klawiaturą - // ggBrakeCtrl.UpdateValue(double(mvOccupied->BrakeCtrlPos)); - ggBrakeCtrl.UpdateValue( mvOccupied->fBrakeCtrlPos ); - ggBrakeCtrl.Update(); - } - } + { + // else //standardowa prodedura z kranem powiązanym z klawiaturą + // ggBrakeCtrl.UpdateValue(double(mvOccupied->BrakeCtrlPos)); + ggBrakeCtrl.UpdateValue(mvOccupied->fBrakeCtrlPos); + ggBrakeCtrl.Update(); + } + } - if( ggLocalBrake.SubModel != nullptr ) { + if (ggLocalBrake.SubModel != nullptr) + { #ifdef _WIN32 - if( ( DynamicObject->Mechanik != nullptr ) - && ( false == DynamicObject->Mechanik->AIControllFlag ) // nie blokujemy AI - && ( mvOccupied->BrakeLocHandle == TBrakeHandle::FD1 ) - && ( ( Global.iFeedbackMode == 4 ) && Global.fCalibrateIn[ 0 ][ 1 ] != 0.0 -/* || ( Global.bMWDmasterEnable && Global.bMWDBreakEnable )*/ ) ) { - // Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba - // Firleju: dlatego kasujemy i zastepujemy funkcją w Console - auto const b = std::clamp( - (double)Console::AnalogCalibrateGet( 1 ), - 0.0, - 1.0 ); - mvOccupied->LocalBrakePosA = b; - ggLocalBrake.UpdateValue( b * LocalBrakePosNo ); - } - else + if ((DynamicObject->Mechanik != nullptr) && (false == DynamicObject->Mechanik->AIControllFlag) // nie blokujemy AI + && (mvOccupied->BrakeLocHandle == TBrakeHandle::FD1) && + ((Global.iFeedbackMode == 4) && Global.fCalibrateIn[0][1] != 0.0 + /* || ( Global.bMWDmasterEnable && Global.bMWDBreakEnable )*/)) + { + // Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba + // Firleju: dlatego kasujemy i zastepujemy funkcją w Console + auto const b = clamp(Console::AnalogCalibrateGet(1), 0.0, 1.0); + mvOccupied->LocalBrakePosA = b; + ggLocalBrake.UpdateValue(b * LocalBrakePosNo); + } + else #endif - { - // standardowa prodedura z kranem powiązanym z klawiaturą - ggLocalBrake.UpdateValue( mvOccupied->LocalBrakePosA * LocalBrakePosNo ); - } - ggLocalBrake.Update(); - } - ggDirForwardButton.Update( lowvoltagepower ); - ggDirNeutralButton.Update( lowvoltagepower ); - ggDirBackwardButton.Update( lowvoltagepower ); - ggAlarmChain.Update(); - ggBrakeProfileCtrl.Update(); - ggBrakeProfileG.Update(); - ggBrakeProfileR.Update(); + { + // standardowa prodedura z kranem powiązanym z klawiaturą + ggLocalBrake.UpdateValue(mvOccupied->LocalBrakePosA * LocalBrakePosNo); + } + ggLocalBrake.Update(); + } + ggDirForwardButton.Update(lowvoltagepower); + ggDirNeutralButton.Update(lowvoltagepower); + ggDirBackwardButton.Update(lowvoltagepower); + ggAlarmChain.Update(); + ggBrakeProfileCtrl.Update(); + ggBrakeProfileG.Update(); + ggBrakeProfileR.Update(); ggBrakeOperationModeCtrl.Update(); ggWiperSw.Update(); - ggMaxCurrentCtrl.UpdateValue( - ( true == mvControlled->ShuntModeAllow ? - ( true == mvControlled->ShuntMode ? - 1.f : - 0.f ) : - ( mvControlled->MotorOverloadRelayHighThreshold ? - 1.f : - 0.f ) ) ); - ggMaxCurrentCtrl.Update(); - // NBMX wrzesien 2003 - drzwi - ggDoorLeftPermitButton.Update( lowvoltagepower ); - ggDoorRightPermitButton.Update( lowvoltagepower ); - ggDoorPermitPresetButton.Update( lowvoltagepower ); - ggDoorLeftButton.Update( lowvoltagepower ); - ggDoorRightButton.Update( lowvoltagepower ); - ggDoorLeftOnButton.Update( lowvoltagepower ); - ggDoorRightOnButton.Update( lowvoltagepower ); - ggDoorLeftOffButton.Update( lowvoltagepower ); - ggDoorRightOffButton.Update( lowvoltagepower ); - ggDoorAllOnButton.Update( lowvoltagepower ); - ggDoorAllOffButton.Update( lowvoltagepower ); - ggDoorSignallingButton.Update( lowvoltagepower ); - ggDoorStepButton.Update( lowvoltagepower ); - // NBMX dzwignia sprezarki - ggCompressorButton.Update(); - ggCompressorLocalButton.Update(); + ggMaxCurrentCtrl.UpdateValue((true == mvControlled->ShuntModeAllow ? (true == mvControlled->ShuntMode ? 1.f : 0.f) : (mvControlled->MotorOverloadRelayHighThreshold ? 1.f : 0.f))); + ggMaxCurrentCtrl.Update(); + // NBMX wrzesien 2003 - drzwi + ggDoorLeftPermitButton.Update(lowvoltagepower); + ggDoorRightPermitButton.Update(lowvoltagepower); + ggDoorPermitPresetButton.Update(lowvoltagepower); + ggDoorLeftButton.Update(lowvoltagepower); + ggDoorRightButton.Update(lowvoltagepower); + ggDoorLeftOnButton.Update(lowvoltagepower); + ggDoorRightOnButton.Update(lowvoltagepower); + ggDoorLeftOffButton.Update(lowvoltagepower); + ggDoorRightOffButton.Update(lowvoltagepower); + ggDoorAllOnButton.Update(lowvoltagepower); + ggDoorAllOffButton.Update(lowvoltagepower); + ggDoorSignallingButton.Update(lowvoltagepower); + ggDoorStepButton.Update(lowvoltagepower); + // NBMX dzwignia sprezarki + ggCompressorButton.Update(); + ggCompressorLocalButton.Update(); ggCompressorListButton.Update(); - //--------- - // hunter-080812: poprawka na ogrzewanie w elektrykach - usuniete uzaleznienie od przetwornicy - if( ( mvControlled->Heating == true ) - && ( mvControlled->ConvOvldFlag == false ) ) - btLampkaOgrzewanieSkladu.Turn( true ); - else - btLampkaOgrzewanieSkladu.Turn( false ); + //--------- + // hunter-080812: poprawka na ogrzewanie w elektrykach - usuniete uzaleznienie od przetwornicy + if ((mvControlled->Heating == true) && (mvControlled->ConvOvldFlag == false)) + btLampkaOgrzewanieSkladu.Turn(true); + else + btLampkaOgrzewanieSkladu.Turn(false); - //---------- + //---------- - // lights - auto const lightpower { ( - InstrumentLightType == 0 ? mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable : - InstrumentLightType == 1 ? mvControlled->Mains : - InstrumentLightType == 2 ? mvOccupied->Power110vIsAvailable : - InstrumentLightType == 3 ? mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable : - InstrumentLightType == 4 ? mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable : - false ) }; - InstrumentLightActive = ( - InstrumentLightType == 3 ? true : // TODO: link the light state with the state of the master key - InstrumentLightType == 4 ? ( mvOccupied->iLights[end::front] != 0 ) || ( mvOccupied->iLights[end::rear] != 0 ) : - InstrumentLightActive ); - btInstrumentLight.Turn( InstrumentLightActive && lightpower ); - btDashboardLight.Turn( DashboardLightActive && lightpower ); - btTimetableLight.Turn( TimetableLightActive && lightpower ); + // lights + auto const lightpower{(InstrumentLightType == 0 ? mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable : + InstrumentLightType == 1 ? mvControlled->Mains : + InstrumentLightType == 2 ? mvOccupied->Power110vIsAvailable : + InstrumentLightType == 3 ? mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable : + InstrumentLightType == 4 ? mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable : + false)}; + InstrumentLightActive = (InstrumentLightType == 3 ? true : // TODO: link the light state with the state of the master key + InstrumentLightType == 4 ? (mvOccupied->iLights[end::front] != 0) || (mvOccupied->iLights[end::rear] != 0) : + InstrumentLightActive); + btInstrumentLight.Turn(InstrumentLightActive && lightpower); + btDashboardLight.Turn(DashboardLightActive && lightpower); + btTimetableLight.Turn(TimetableLightActive && lightpower); - // guziki: - ggMainOffButton.Update(); - ggMainOnButton.Update(); - ggMainButton.Update(); - ggSecurityResetButton.Update(); - ggSHPResetButton.Update(); - ggReleaserButton.Update(); + // guziki: + ggMainOffButton.Update(); + ggMainOnButton.Update(); + ggMainButton.Update(); + ggSecurityResetButton.Update(); + ggSHPResetButton.Update(); + ggReleaserButton.Update(); ggSpringBrakeOnButton.Update(); ggSpringBrakeOffButton.Update(); ggUniveralBrakeButton1.Update(); ggUniveralBrakeButton2.Update(); ggUniveralBrakeButton3.Update(); - ggEPFuseButton.Update(); - ggAntiSlipButton.Update(); - ggSandButton.Update(); - ggAutoSandButton.Update(); - ggFuseButton.Update(); - ggConverterFuseButton.Update(); - ggStLinOffButton.Update(); - ggRadioChannelSelector.Update(); - ggRadioChannelPrevious.Update(); - ggRadioChannelNext.Update(); - ggRadioStop.Update(); - ggRadioTest.Update(); - ggRadioCall1.Update(); - ggRadioCall3.Update(); + ggEPFuseButton.Update(); + ggAntiSlipButton.Update(); + ggSandButton.Update(); + ggAutoSandButton.Update(); + ggFuseButton.Update(); + ggConverterFuseButton.Update(); + ggStLinOffButton.Update(); + ggRadioChannelSelector.Update(); + ggRadioChannelPrevious.Update(); + ggRadioChannelNext.Update(); + ggRadioStop.Update(); + ggRadioTest.Update(); + ggRadioCall1.Update(); + ggRadioCall3.Update(); ggRadioVolumeSelector.Update(); ggRadioVolumePrevious.Update(); ggRadioVolumeNext.Update(); - ggDepartureSignalButton.Update(); -/* - ggPantFrontButton.Update(); - ggPantRearButton.Update(); - ggPantFrontButtonOff.Update(); - ggPantRearButtonOff.Update(); -*/ - ggPantAllDownButton.Update(); - ggPantSelectedDownButton.Update(); - ggPantSelectedButton.Update(); - ggPantValvesButton.Update(); - ggPantCompressorButton.Update(); - ggPantCompressorValve.Update(); + ggDepartureSignalButton.Update(); + /* + ggPantFrontButton.Update(); + ggPantRearButton.Update(); + ggPantFrontButtonOff.Update(); + ggPantRearButtonOff.Update(); + */ + ggPantAllDownButton.Update(); + ggPantSelectedDownButton.Update(); + ggPantSelectedButton.Update(); + ggPantValvesButton.Update(); + ggPantCompressorButton.Update(); + ggPantCompressorValve.Update(); - ggPantValvesOff.Update(); + ggPantValvesOff.Update(); ggPantValvesUpdate.Update(); - ggLightsButton.Update(); - ggUpperLightButton.Update(); - ggLeftLightButton.Update(); - ggRightLightButton.Update(); - ggLeftEndLightButton.Update(); - ggRightEndLightButton.Update(); + ggLightsButton.Update(); + ggUpperLightButton.Update(); + ggLeftLightButton.Update(); + ggRightLightButton.Update(); + ggLeftEndLightButton.Update(); + ggRightEndLightButton.Update(); ggModernLightDimSw.Update(); - // hunter-230112 - ggRearUpperLightButton.Update(); - ggRearLeftLightButton.Update(); - ggRearRightLightButton.Update(); - ggRearLeftEndLightButton.Update(); - ggRearRightEndLightButton.Update(); - ggDimHeadlightsButton.Update(); + // hunter-230112 + ggRearUpperLightButton.Update(); + ggRearLeftLightButton.Update(); + ggRearRightLightButton.Update(); + ggRearLeftEndLightButton.Update(); + ggRearRightEndLightButton.Update(); ggDimHeadlightsButton.Update(); - //------------ - ggConverterButton.Update(); - ggConverterLocalButton.Update(); - ggConverterOffButton.Update(); - ggTrainHeatingButton.Update(); - ggSignallingButton.Update(); - ggNextCurrentButton.Update(); - ggHornButton.Update(); - ggHornLowButton.Update(); - ggHornHighButton.Update(); - ggWhistleButton.Update(); - if( DynamicObject->Mechanik != nullptr ) { - ggHelperButton.UpdateValue( DynamicObject->Mechanik->HelperState ); - } + ggDimHeadlightsButton.Update(); + //------------ + ggConverterButton.Update(); + ggConverterLocalButton.Update(); + ggConverterOffButton.Update(); + ggTrainHeatingButton.Update(); + ggSignallingButton.Update(); + ggNextCurrentButton.Update(); + ggHornButton.Update(); + ggHornLowButton.Update(); + ggHornHighButton.Update(); + ggWhistleButton.Update(); + if (DynamicObject->Mechanik != nullptr) + { + ggHelperButton.UpdateValue(DynamicObject->Mechanik->HelperState); + } ggHelperButton.Update(); - ggSpeedControlIncreaseButton.Update( lowvoltagepower ); - ggSpeedControlDecreaseButton.Update( lowvoltagepower ); - ggSpeedControlPowerIncreaseButton.Update( lowvoltagepower ); - ggSpeedControlPowerDecreaseButton.Update( lowvoltagepower ); - for (auto &speedctrlbutton : ggSpeedCtrlButtons) { - speedctrlbutton.Update( lowvoltagepower ); + ggSpeedControlIncreaseButton.Update(lowvoltagepower); + ggSpeedControlDecreaseButton.Update(lowvoltagepower); + ggSpeedControlPowerIncreaseButton.Update(lowvoltagepower); + ggSpeedControlPowerDecreaseButton.Update(lowvoltagepower); + for (auto &speedctrlbutton : ggSpeedCtrlButtons) + { + speedctrlbutton.Update(lowvoltagepower); } - for( auto &universal : ggUniversals ) { - universal.Update(); - } - for (auto &item : ggInverterEnableButtons) { + for (auto &universal : ggUniversals) + { + universal.Update(); + } + for (auto &item : ggInverterEnableButtons) + { item.Update(); } - for (auto &item : ggInverterDisableButtons) { + for (auto &item : ggInverterDisableButtons) + { item.Update(); } - for (auto &item : ggInverterToggleButtons) { + for (auto &item : ggInverterToggleButtons) + { item.Update(); } - for( auto &relayresetbutton : ggRelayResetButtons ) { - relayresetbutton.Update(); - } - // hunter-091012 - ggInstrumentLightButton.Update(); - ggDashboardLightButton.Update(); - ggTimetableLightButton.Update(); - ggCabLightDimButton.Update(); - ggCompartmentLightsButton.Update(); - ggCompartmentLightsOnButton.Update(); - ggCompartmentLightsOffButton.Update(); - ggBatteryButton.Update(); - ggBatteryOnButton.Update(); - ggBatteryOffButton.Update(); + for (auto &relayresetbutton : ggRelayResetButtons) + { + relayresetbutton.Update(); + } + // hunter-091012 + ggInstrumentLightButton.Update(); + ggDashboardLightButton.Update(); + ggTimetableLightButton.Update(); + ggCabLightDimButton.Update(); + ggCompartmentLightsButton.Update(); + ggCompartmentLightsOnButton.Update(); + ggCompartmentLightsOffButton.Update(); + ggBatteryButton.Update(); + ggBatteryOnButton.Update(); + ggBatteryOffButton.Update(); if ((ggCabActivationButton.SubModel != nullptr) && (ggCabActivationButton.type() != TGaugeType::push)) { ggCabActivationButton.UpdateValue(mvOccupied->IsCabMaster() ? 1.0 : 0.0); } ggCabActivationButton.Update(); - ggWaterPumpBreakerButton.Update(); - ggWaterPumpButton.Update(); - ggWaterHeaterBreakerButton.Update(); - ggWaterHeaterButton.Update(); - ggWaterCircuitsLinkButton.Update(); - ggFuelPumpButton.Update(); - ggOilPumpButton.Update(); - ggMotorBlowersFrontButton.Update(); - ggMotorBlowersRearButton.Update(); - ggMotorBlowersAllOffButton.Update(); + ggWaterPumpBreakerButton.Update(); + ggWaterPumpButton.Update(); + ggWaterHeaterBreakerButton.Update(); + ggWaterHeaterButton.Update(); + ggWaterCircuitsLinkButton.Update(); + ggFuelPumpButton.Update(); + ggOilPumpButton.Update(); + ggMotorBlowersFrontButton.Update(); + ggMotorBlowersRearButton.Update(); + ggMotorBlowersAllOffButton.Update(); - // wyprowadzenie sygnałów dla haslera na PoKeys (zaznaczanie na taśmie) - btHaslerBrakes.Turn(mvOccupied->BrakePress > 0.4); // ciśnienie w cylindrach - btHaslerCurrent.Turn(mvOccupied->Im != 0.0); // prąd na silnikach + // wyprowadzenie sygnałów dla haslera na PoKeys (zaznaczanie na taśmie) + btHaslerBrakes.Turn(mvOccupied->BrakePress > 0.4); // ciśnienie w cylindrach + btHaslerCurrent.Turn(mvOccupied->Im != 0.0); // prąd na silnikach - // calculate current level of interior illumination - { - // TODO: organize it along with rest of train update in a more sensible arrangement - // Ra: uzeleżnic od napięcia w obwodzie sterowania - // hunter-091012: uzaleznienie jasnosci od przetwornicy - int cabidx { 0 }; - for( auto &cab : Cabine ) { + // calculate current level of interior illumination + { + // TODO: organize it along with rest of train update in a more sensible arrangement + // Ra: uzeleżnic od napięcia w obwodzie sterowania + // hunter-091012: uzaleznienie jasnosci od przetwornicy + int cabidx{0}; + for (auto &cab : Cabine) + { - auto const cablightlevel = - ( ( cab.bLight == false ) ? 0.f : - ( cab.bLightDim == true ) ? 0.4f : - 1.f ) - * ( mvOccupied->Power110vIsAvailable ? 1.f : 0.5f ); + auto const cablightlevel = ((cab.bLight == false) ? 0.f : (cab.bLightDim == true) ? 0.4f : 1.f) * (mvOccupied->Power110vIsAvailable ? 1.f : 0.5f); - if( cab.LightLevel != cablightlevel ) { - cab.LightLevel = cablightlevel; - DynamicObject->set_cab_lights( cabidx, cab.LightLevel ); - } - if( cabidx == iCabn ) { - DynamicObject->InteriorLightLevel = cablightlevel; - } + if (cab.LightLevel != cablightlevel) + { + cab.LightLevel = cablightlevel; + DynamicObject->set_cab_lights(cabidx, cab.LightLevel); + } + if (cabidx == iCabn) + { + DynamicObject->InteriorLightLevel = cablightlevel; + } - ++cabidx; - } - } + ++cabidx; + } + } - // anti slip system activation, maintained while the control button is down - if( mvOccupied->BrakeSystem != TBrakeSystem::ElectroPneumatic ) { - if( ggAntiSlipButton.GetDesiredValue() > 0.95 ) { - mvControlled->AntiSlippingBrake(); - } - } - // screens + // anti slip system activation, maintained while the control button is down + if (mvOccupied->BrakeSystem != TBrakeSystem::ElectroPneumatic) + { + if (ggAntiSlipButton.GetDesiredValue() > 0.95) + { + mvControlled->AntiSlippingBrake(); + } + } + // screens - if (!FreeFlyModeFlag && simulation::Train == this) // don't bother if we're outside - update_screens(Deltatime); + if (!FreeFlyModeFlag && simulation::Train == this) // don't bother if we're outside + update_screens(Deltatime); - // update direction relay + // update direction relay if (prevBatState != mvOccupied->Power24vIsAvailable) - SetupDirectionRelays(); + SetupDirectionRelays(); if (prevDirection != mvOccupied->DirActive) UpdateDirectionRelays(); - prevBatState = mvOccupied->Power24vIsAvailable; + prevBatState = mvOccupied->Power24vIsAvailable; prevDirection = mvOccupied->DirActive; + // sounds + update_sounds(Deltatime); - - - // sounds - update_sounds( Deltatime ); - - return true; //(DynamicObject->Update(dt)); + return true; //(DynamicObject->Update(dt)); } // koniec update -void TTrain::UpdateDirectionRelays() { +void TTrain::UpdateDirectionRelays() +{ if (mvOccupied->DirActive < 0 && mvOccupied->Power24vIsAvailable) // wstecz Dynamic()->sDirectionRelayR.play(); if (mvOccupied->DirActive == 0 && mvOccupied->Power24vIsAvailable) // neutral @@ -8530,219 +9796,236 @@ void TTrain::UpdateDirectionRelays() { Dynamic()->sDirectionRelayD.play(); } -void TTrain::SetupDirectionRelays() { - if (mvOccupied->Power24vIsAvailable) - { +void TTrain::SetupDirectionRelays() +{ + if (mvOccupied->Power24vIsAvailable) + { if (mvOccupied->DirActive < 0 && mvOccupied->Power24vIsAvailable) // wstecz Dynamic()->sDirectionRelayR.play(); if (mvOccupied->DirActive > 0 && mvOccupied->Power24vIsAvailable) // przod Dynamic()->sDirectionRelayD.play(); - } - else if (mvOccupied->DirActive != 0) // neutral + } + else if (mvOccupied->DirActive != 0) // neutral Dynamic()->sDirectionRelayN.play(); } -void -TTrain::update_sounds( double const Deltatime ) { +void TTrain::update_sounds(double const Deltatime) +{ - double volume { 0.0 }; - double const brakevolumescale { 0.5 }; + double volume{0.0}; + double const brakevolumescale{0.5}; - // Winger-160404 - syczenie pomocniczego (luzowanie) - if( m_lastlocalbrakepressure != -1.f ) { - // calculate rate of pressure drop in local brake cylinder, once it's been initialized - auto const brakepressuredifference { mvOccupied->LocBrakePress - m_lastlocalbrakepressure }; - m_localbrakepressurechange = std::lerp( m_localbrakepressurechange, 10 * ( brakepressuredifference / Deltatime ), 0.1f ); - } - m_lastlocalbrakepressure = mvOccupied->LocBrakePress; - // local brake, release - if( rsSBHiss ) { - if( ( m_localbrakepressurechange < -0.05f ) - && ( mvOccupied->LocBrakePress > mvOccupied->BrakePress - 0.05 ) ) { - rsSBHiss->gain( std::clamp( rsSBHiss->m_amplitudeoffset + rsSBHiss->m_amplitudefactor * -m_localbrakepressurechange * 0.05, 0.0, 1.5 ) ); - rsSBHiss->play( sound_flags::exclusive | sound_flags::looping ); - } - else { - // don't stop the sound too abruptly - volume = std::max( 0.0, rsSBHiss->gain() - 0.1 * Deltatime ); - rsSBHiss->gain( volume ); - if( volume < 0.05 ) { - rsSBHiss->stop(); - } - } - } - // local brake, engage - if( rsSBHissU ) { - if( m_localbrakepressurechange > 0.05f ) { - rsSBHissU->gain( std::clamp( rsSBHissU->m_amplitudeoffset + rsSBHissU->m_amplitudefactor * m_localbrakepressurechange * 0.05, 0.0, 1.5 ) ); - rsSBHissU->play( sound_flags::exclusive | sound_flags::looping ); - } - else { - // don't stop the sound too abruptly - volume = std::max( 0.0, rsSBHissU->gain() - 0.1 * Deltatime ); - rsSBHissU->gain( volume ); - if( volume < 0.05 ) { - rsSBHissU->stop(); - } - } - } + // Winger-160404 - syczenie pomocniczego (luzowanie) + if (m_lastlocalbrakepressure != -1.f) + { + // calculate rate of pressure drop in local brake cylinder, once it's been initialized + auto const brakepressuredifference{mvOccupied->LocBrakePress - m_lastlocalbrakepressure}; + m_localbrakepressurechange = interpolate(m_localbrakepressurechange, 10 * (brakepressuredifference / Deltatime), 0.1f); + } + m_lastlocalbrakepressure = mvOccupied->LocBrakePress; + // local brake, release + if (rsSBHiss) + { + if ((m_localbrakepressurechange < -0.05f) && (mvOccupied->LocBrakePress > mvOccupied->BrakePress - 0.05)) + { + rsSBHiss->gain(clamp(rsSBHiss->m_amplitudeoffset + rsSBHiss->m_amplitudefactor * -m_localbrakepressurechange * 0.05, 0.0, 1.5)); + rsSBHiss->play(sound_flags::exclusive | sound_flags::looping); + } + else + { + // don't stop the sound too abruptly + volume = std::max(0.0, rsSBHiss->gain() - 0.1 * Deltatime); + rsSBHiss->gain(volume); + if (volume < 0.05) + { + rsSBHiss->stop(); + } + } + } + // local brake, engage + if (rsSBHissU) + { + if (m_localbrakepressurechange > 0.05f) + { + rsSBHissU->gain(clamp(rsSBHissU->m_amplitudeoffset + rsSBHissU->m_amplitudefactor * m_localbrakepressurechange * 0.05, 0.0, 1.5)); + rsSBHissU->play(sound_flags::exclusive | sound_flags::looping); + } + else + { + // don't stop the sound too abruptly + volume = std::max(0.0, rsSBHissU->gain() - 0.1 * Deltatime); + rsSBHissU->gain(volume); + if (volume < 0.05) + { + rsSBHissU->stop(); + } + } + } - // McZapkie-280302 - syczenie - // TODO: softer volume reduction than plain abrupt stop, perhaps as reusable wrapper? - if( ( mvOccupied->BrakeHandle == TBrakeHandle::FV4a ) - || ( mvOccupied->BrakeHandle == TBrakeHandle::FVel6 ) ) { - // upuszczanie z PG - if( rsHiss ) { - fPPress = std::lerp( fPPress, static_cast( mvOccupied->Handle->GetSound( s_fv4a_b ) ), 0.05f ); - volume = ( - fPPress > 0 ? - rsHiss->m_amplitudefactor * fPPress * 0.25 + rsHiss->m_amplitudeoffset : - 0 ); - if( volume * brakevolumescale > 0.05 ) { - rsHiss->gain( volume * brakevolumescale ); - rsHiss->play( sound_flags::exclusive | sound_flags::looping ); - } - else { - rsHiss->stop(); - } - } - // napelnianie PG - if( rsHissU ) { - fNPress = std::lerp( fNPress, static_cast( mvOccupied->Handle->GetSound( s_fv4a_u ) ), 0.25f ); - volume = ( - fNPress > 0 ? - rsHissU->m_amplitudefactor * fNPress + rsHissU->m_amplitudeoffset : - 0 ); - if( volume * brakevolumescale > 0.05 ) { - rsHissU->gain( volume * brakevolumescale ); - rsHissU->play( sound_flags::exclusive | sound_flags::looping ); - } - else { - rsHissU->stop(); - } - } - // upuszczanie przy naglym - if( rsHissE ) { - volume = mvOccupied->Handle->GetSound( s_fv4a_e ) * rsHissE->m_amplitudefactor + rsHissE->m_amplitudeoffset; - if( volume * brakevolumescale > 0.05 ) { - rsHissE->gain( volume * brakevolumescale ); - rsHissE->play( sound_flags::exclusive | sound_flags::looping ); - } - else { - rsHissE->stop(); - } - } - // upuszczanie sterujacego fala - if( rsHissX ) { - volume = mvOccupied->Handle->GetSound( s_fv4a_x ) * rsHissX->m_amplitudefactor + rsHissX->m_amplitudeoffset; - if( volume * brakevolumescale > 0.05 ) { - rsHissX->gain( volume * brakevolumescale ); - rsHissX->play( sound_flags::exclusive | sound_flags::looping ); - } - else { - rsHissX->stop(); - } - } - // upuszczanie z czasowego - if( rsHissT ) { - volume = mvOccupied->Handle->GetSound( s_fv4a_t ) * rsHissT->m_amplitudefactor + +rsHissT->m_amplitudeoffset; - if( volume * brakevolumescale > 0.05 ) { - rsHissT->gain( volume * brakevolumescale ); - rsHissT->play( sound_flags::exclusive | sound_flags::looping ); - } - else { - rsHissT->stop(); - } - } + // McZapkie-280302 - syczenie + // TODO: softer volume reduction than plain abrupt stop, perhaps as reusable wrapper? + if ((mvOccupied->BrakeHandle == TBrakeHandle::FV4a) || (mvOccupied->BrakeHandle == TBrakeHandle::FVel6)) + { + // upuszczanie z PG + if (rsHiss) + { + fPPress = interpolate(fPPress, static_cast(mvOccupied->Handle->GetSound(s_fv4a_b)), 0.05f); + volume = (fPPress > 0 ? rsHiss->m_amplitudefactor * fPPress * 0.25 + rsHiss->m_amplitudeoffset : 0); + if (volume * brakevolumescale > 0.05) + { + rsHiss->gain(volume * brakevolumescale); + rsHiss->play(sound_flags::exclusive | sound_flags::looping); + } + else + { + rsHiss->stop(); + } + } + // napelnianie PG + if (rsHissU) + { + fNPress = interpolate(fNPress, static_cast(mvOccupied->Handle->GetSound(s_fv4a_u)), 0.25f); + volume = (fNPress > 0 ? rsHissU->m_amplitudefactor * fNPress + rsHissU->m_amplitudeoffset : 0); + if (volume * brakevolumescale > 0.05) + { + rsHissU->gain(volume * brakevolumescale); + rsHissU->play(sound_flags::exclusive | sound_flags::looping); + } + else + { + rsHissU->stop(); + } + } + // upuszczanie przy naglym + if (rsHissE) + { + volume = mvOccupied->Handle->GetSound(s_fv4a_e) * rsHissE->m_amplitudefactor + rsHissE->m_amplitudeoffset; + if (volume * brakevolumescale > 0.05) + { + rsHissE->gain(volume * brakevolumescale); + rsHissE->play(sound_flags::exclusive | sound_flags::looping); + } + else + { + rsHissE->stop(); + } + } + // upuszczanie sterujacego fala + if (rsHissX) + { + volume = mvOccupied->Handle->GetSound(s_fv4a_x) * rsHissX->m_amplitudefactor + rsHissX->m_amplitudeoffset; + if (volume * brakevolumescale > 0.05) + { + rsHissX->gain(volume * brakevolumescale); + rsHissX->play(sound_flags::exclusive | sound_flags::looping); + } + else + { + rsHissX->stop(); + } + } + // upuszczanie z czasowego + if (rsHissT) + { + volume = mvOccupied->Handle->GetSound(s_fv4a_t) * rsHissT->m_amplitudefactor + +rsHissT->m_amplitudeoffset; + if (volume * brakevolumescale > 0.05) + { + rsHissT->gain(volume * brakevolumescale); + rsHissT->play(sound_flags::exclusive | sound_flags::looping); + } + else + { + rsHissT->stop(); + } + } + } + else + { + // jesli nie FV4a + // upuszczanie z PG + if (rsHiss) + { + fPPress = (4.0f * fPPress + std::max(0.0, mvOccupied->dpMainValve)) / (4.0f + 1.0f); + volume = (fPPress > 0.0f ? 2.0 * rsHiss->m_amplitudefactor * fPPress + rsHiss->m_amplitudeoffset : 0.0); + if (volume > 0.05) + { + rsHiss->gain(volume); + rsHiss->play(sound_flags::exclusive | sound_flags::looping); + } + else + { + rsHiss->stop(); + } + } + // napelnianie PG + if (rsHissU) + { + fNPress = (4.0f * fNPress + Min0R(0.0, mvOccupied->dpMainValve)) / (4.0f + 1.0f); + volume = (fNPress < 0.0f ? -1.0 * rsHissU->m_amplitudefactor * fNPress + rsHissU->m_amplitudeoffset : 0.0); + if (volume > 0.01) + { + rsHissU->gain(volume); + rsHissU->play(sound_flags::exclusive | sound_flags::looping); + } + else + { + rsHissU->stop(); + } + } + } // koniec nie FV4a - } else { - // jesli nie FV4a - // upuszczanie z PG - if( rsHiss ) { - fPPress = ( 4.0f * fPPress + std::max( 0.0, mvOccupied->dpMainValve ) ) / ( 4.0f + 1.0f ); - volume = ( - fPPress > 0.0f ? - 2.0 * rsHiss->m_amplitudefactor * fPPress + rsHiss->m_amplitudeoffset : - 0.0 ); - if( volume > 0.05 ) { - rsHiss->gain( volume ); - rsHiss->play( sound_flags::exclusive | sound_flags::looping ); - } - else { - rsHiss->stop(); - } - } - // napelnianie PG - if( rsHissU ) { - fNPress = ( 4.0f * fNPress + std::min( 0.0, mvOccupied->dpMainValve ) ) / ( 4.0f + 1.0f ); - volume = ( - fNPress < 0.0f ? - -1.0 * rsHissU->m_amplitudefactor * fNPress + rsHissU->m_amplitudeoffset : - 0.0 ); - if( volume > 0.01 ) { - rsHissU->gain( volume ); - rsHissU->play( sound_flags::exclusive | sound_flags::looping ); - } - else { - rsHissU->stop(); - } - } - } // koniec nie FV4a + // brakes + if (rsBrake) + { + if ((mvOccupied->UnitBrakeForce > 10.0) && (mvOccupied->Vel > 0.05)) + { - // brakes - if( rsBrake ) { - if( ( mvOccupied->UnitBrakeForce > 10.0 ) - && ( mvOccupied->Vel > 0.05 ) ) { + auto const brakeforceratio{ + clamp(mvOccupied->UnitBrakeForce / std::max(1.0, mvOccupied->BrakeForceR(1.0, mvOccupied->Vel) / (mvOccupied->NAxles * std::max(1, mvOccupied->NBpA))), 0.0, 1.0)}; + // HACK: in external view mute the sound rather than stop it, in case there's an opening bookend it'd (re)play on sound restart after returning inside + volume = (FreeFlyModeFlag ? 0.0 : rsBrake->m_amplitudeoffset + std::sqrt(brakeforceratio * interpolate(0.4, 1.0, (mvOccupied->Vel / (1 + mvOccupied->Vmax)))) * rsBrake->m_amplitudefactor); + rsBrake->pitch(rsBrake->m_frequencyoffset + mvOccupied->Vel * rsBrake->m_frequencyfactor); + rsBrake->gain(volume); + rsBrake->play(sound_flags::exclusive | sound_flags::looping); + } + else + { + rsBrake->stop(); + } + } - auto const brakeforceratio{ - std::clamp( - mvOccupied->UnitBrakeForce / std::max( 1.0, mvOccupied->BrakeForceR( 1.0, mvOccupied->Vel ) / ( mvOccupied->NAxles * std::max( 1, mvOccupied->NBpA ) ) ), - 0.0, 1.0 ) }; - // HACK: in external view mute the sound rather than stop it, in case there's an opening bookend it'd (re)play on sound restart after returning inside - volume = ( - FreeFlyModeFlag ? - 0.0 : - rsBrake->m_amplitudeoffset - + std::sqrt( brakeforceratio * std::lerp( 0.4, 1.0, ( mvOccupied->Vel / ( 1 + mvOccupied->Vmax ) ) ) ) * rsBrake->m_amplitudefactor ); - rsBrake->pitch( rsBrake->m_frequencyoffset + mvOccupied->Vel * rsBrake->m_frequencyfactor ); - rsBrake->gain( volume ); - rsBrake->play( sound_flags::exclusive | sound_flags::looping ); - } - else { - rsBrake->stop(); - } - } + // ambient sound + // since it's typically ticking of the clock we can center it on tachometer or on middle of compartment bounding area + if (rsFadeSound) + { + rsFadeSound->play(sound_flags::exclusive | sound_flags::looping); + } - // ambient sound - // since it's typically ticking of the clock we can center it on tachometer or on middle of compartment bounding area - if( rsFadeSound ) { - rsFadeSound->play( sound_flags::exclusive | sound_flags::looping ); - } + if (dsbSlipAlarm) + { + // alarm przy poslizgu dla 181/182 - BOMBARDIER + if ((mvControlled->SlippingWheels) && (DynamicObject->GetVelocity() > 1.0)) + { + dsbSlipAlarm->play(sound_flags::exclusive | sound_flags::looping); + } + else + { + dsbSlipAlarm->stop(); + } + } - if( dsbSlipAlarm ) { - // alarm przy poslizgu dla 181/182 - BOMBARDIER - if( ( mvControlled->SlippingWheels ) - && ( DynamicObject->GetVelocity() > 1.0 ) ) { - dsbSlipAlarm->play( sound_flags::exclusive | sound_flags::looping ); - } - else { - dsbSlipAlarm->stop(); - } - } - - // dzwiek wiatru rozbijajacego sie o szyby w kabinie - if (rsWindSound) - { + // dzwiek wiatru rozbijajacego sie o szyby w kabinie + if (rsWindSound) + { if (!FreeFlyModeFlag && !Global.CabWindowOpen && DynamicObject->GetVelocity() > 0.5) - update_sounds_resonancenoise(*rsWindSound); - else + update_sounds_resonancenoise(*rsWindSound); + else rsWindSound->stop(FreeFlyModeFlag); - } + } - - // dzwiek rezonansu (taki drugi runningnoise w sumie) + // dzwiek rezonansu (taki drugi runningnoise w sumie) if (rsResonanceNoise) - { + { if (!FreeFlyModeFlag && !Global.CabWindowOpen && DynamicObject->GetVelocity() > 0.5) { @@ -8750,152 +10033,163 @@ TTrain::update_sounds( double const Deltatime ) { } else rsResonanceNoise->stop(FreeFlyModeFlag); - } + } + // szum w czasie jazdy + if (rsRunningNoise) + { + if ((false == FreeFlyModeFlag) && (false == Global.CabWindowOpen) && (DynamicObject->GetVelocity() > 0.5)) + { - // szum w czasie jazdy - if( rsRunningNoise ) { - if( ( false == FreeFlyModeFlag ) - && ( false == Global.CabWindowOpen ) - && ( DynamicObject->GetVelocity() > 0.5 ) ) { + update_sounds_runningnoise(*rsRunningNoise); + } + else + { + // don't play the optional ending sound if the listener switches views + rsRunningNoise->stop(true == FreeFlyModeFlag); + } + } + // hunting oscillation noise + if (rsHuntingNoise) + { + if ((false == FreeFlyModeFlag) && (false == Global.CabWindowOpen) && (DynamicObject->GetVelocity() > 0.5) && (DynamicObject->IsHunting)) + { - update_sounds_runningnoise( *rsRunningNoise ); - } - else { - // don't play the optional ending sound if the listener switches views - rsRunningNoise->stop( true == FreeFlyModeFlag ); - } - } - // hunting oscillation noise - if( rsHuntingNoise ) { - if( ( false == FreeFlyModeFlag ) - && ( false == Global.CabWindowOpen ) - && ( DynamicObject->GetVelocity() > 0.5 ) - && ( DynamicObject->IsHunting ) ) { + update_sounds_runningnoise(*rsHuntingNoise); + // modify calculated sound volume by hunting amount + auto const huntingamount = interpolate( + 0.0, 1.0, clamp((mvOccupied->Vel - DynamicObject->HuntingShake.fadein_begin) / (DynamicObject->HuntingShake.fadein_end - DynamicObject->HuntingShake.fadein_begin), 0.0, 1.0)); - update_sounds_runningnoise( *rsHuntingNoise ); - // modify calculated sound volume by hunting amount - auto const huntingamount = - std::lerp( - 0.0, 1.0, - std::clamp( - ( mvOccupied->Vel - DynamicObject->HuntingShake.fadein_begin ) / ( DynamicObject->HuntingShake.fadein_end - DynamicObject->HuntingShake.fadein_begin ), - 0.0, 1.0 ) ); + rsHuntingNoise->gain(rsHuntingNoise->gain() * huntingamount); + } + else + { + // don't play the optional ending sound if the listener switches views + rsHuntingNoise->stop(true == FreeFlyModeFlag); + } + } + // rain sound + if (m_rainsound) + { + if ((false == FreeFlyModeFlag) && (false == Global.CabWindowOpen) && (Global.Weather == "rain:")) + { + if (m_rainsound->is_combined()) + { + m_rainsound->pitch(Global.Overcast - 1.0); + } + m_rainsound->gain(m_rainsound->m_amplitudeoffset + m_rainsound->m_amplitudefactor * 1.f); + m_rainsound->play(sound_flags::exclusive | sound_flags::looping); + } + else + { + m_rainsound->stop(); + } + } - rsHuntingNoise->gain( rsHuntingNoise->gain() * huntingamount ); - } - else { - // don't play the optional ending sound if the listener switches views - rsHuntingNoise->stop( true == FreeFlyModeFlag ); - } - } - // rain sound - if( m_rainsound ) { - if( ( false == FreeFlyModeFlag ) - && ( false == Global.CabWindowOpen ) - && ( Global.Weather == "rain:" ) ) { - if( m_rainsound->is_combined() ) { - m_rainsound->pitch( Global.Overcast - 1.0 ); - } - m_rainsound->gain( m_rainsound->m_amplitudeoffset + m_rainsound->m_amplitudefactor * 1.f ); - m_rainsound->play( sound_flags::exclusive | sound_flags::looping ); - } - else { - m_rainsound->stop(); - } - } + if (dsbHasler) + { + if (fTachoCount >= 3.f) + { + auto const frequency{(true == dsbHasler->is_combined() ? fTachoVelocity * 0.01 : dsbHasler->m_frequencyoffset + dsbHasler->m_frequencyfactor)}; + dsbHasler->pitch(frequency); + dsbHasler->gain(dsbHasler->m_amplitudeoffset + dsbHasler->m_amplitudefactor); + dsbHasler->play(sound_flags::exclusive | sound_flags::looping); + } + else if (fTachoCount < 1.f) + { + dsbHasler->stop(); + } + } - if( dsbHasler ) { - if( fTachoCount >= 3.f ) { - auto const frequency{ ( - true == dsbHasler->is_combined() ? - fTachoVelocity * 0.01 : - dsbHasler->m_frequencyoffset + dsbHasler->m_frequencyfactor ) }; - dsbHasler->pitch( frequency ); - dsbHasler->gain( dsbHasler->m_amplitudeoffset + dsbHasler->m_amplitudefactor ); - dsbHasler->play( sound_flags::exclusive | sound_flags::looping ); - } - else if( fTachoCount < 1.f ) { - dsbHasler->stop(); - } - } + // power-reliant sounds + if (mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable) + { - // power-reliant sounds - if( mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable ) { - - // buzzer shp - if (mvOccupied->SecuritySystem.is_cabsignal_beeping()) { - if (dsbBuzzerShp && false == dsbBuzzerShp->is_playing()) { + // buzzer shp + if (mvOccupied->SecuritySystem.is_cabsignal_beeping()) + { + if (dsbBuzzerShp && false == dsbBuzzerShp->is_playing()) + { dsbBuzzerShp->pitch(dsbBuzzerShp->m_frequencyoffset + dsbBuzzerShp->m_frequencyfactor); dsbBuzzerShp->gain(dsbBuzzerShp->m_amplitudeoffset + dsbBuzzerShp->m_amplitudefactor); dsbBuzzerShp->play(sound_flags::looping); - } - } - else { - if (dsbBuzzerShp && true == dsbBuzzerShp->is_playing()) { + } + } + else + { + if (dsbBuzzerShp && true == dsbBuzzerShp->is_playing()) + { dsbBuzzerShp->stop(); - } - } + } + } - // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa - // hunter-091012: rozdzielenie alarmow - if( mvOccupied->SecuritySystem.is_beeping() ) { - if( dsbBuzzer && false == dsbBuzzer->is_playing() ) { - dsbBuzzer->pitch( dsbBuzzer->m_frequencyoffset + dsbBuzzer->m_frequencyfactor ); - dsbBuzzer->gain( dsbBuzzer->m_amplitudeoffset + dsbBuzzer->m_amplitudefactor ); - dsbBuzzer->play( sound_flags::looping ); + // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa + // hunter-091012: rozdzielenie alarmow + if (mvOccupied->SecuritySystem.is_beeping()) + { + if (dsbBuzzer && false == dsbBuzzer->is_playing()) + { + dsbBuzzer->pitch(dsbBuzzer->m_frequencyoffset + dsbBuzzer->m_frequencyfactor); + dsbBuzzer->gain(dsbBuzzer->m_amplitudeoffset + dsbBuzzer->m_amplitudefactor); + dsbBuzzer->play(sound_flags::looping); #ifdef _WIN32 - Console::BitsSet( 1 << 14 ); // ustawienie bitu 16 na PoKeys + Console::BitsSet(1 << 14); // ustawienie bitu 16 na PoKeys #endif - } - } - else { - if( dsbBuzzer && true == dsbBuzzer->is_playing() ) { - dsbBuzzer->stop(); + } + } + else + { + if (dsbBuzzer && true == dsbBuzzer->is_playing()) + { + dsbBuzzer->stop(); #ifdef _WIN32 - Console::BitsClear( 1 << 14 ); // ustawienie bitu 16 na PoKeys + Console::BitsClear(1 << 14); // ustawienie bitu 16 na PoKeys #endif - } - } - // distance meter alert - if( m_distancecounterclear ) { - auto const *owner{ ( - DynamicObject->ctOwner != nullptr ? - DynamicObject->ctOwner : - DynamicObject->Mechanik ) }; - if( m_distancecounter > owner->fLength ) { - // play assigned sound if the train travelled its full length since meter activation - // TBD: check all combinations of directions and active cab - m_distancecounter = -1.f; // turn off the meter after its task is done - m_distancecounterclear->pitch( m_distancecounterclear->m_frequencyoffset + m_distancecounterclear->m_frequencyfactor ); - m_distancecounterclear->gain( m_distancecounterclear->m_amplitudeoffset + m_distancecounterclear->m_amplitudefactor ); - m_distancecounterclear->play( sound_flags::exclusive ); - } - } - } - else { - // stop power-reliant sounds if power is cut - if( dsbBuzzer ) { - if( true == dsbBuzzer->is_playing() ) { - dsbBuzzer->stop(); + } + } + // distance meter alert + if (m_distancecounterclear) + { + auto const *owner{(DynamicObject->ctOwner != nullptr ? DynamicObject->ctOwner : DynamicObject->Mechanik)}; + if (m_distancecounter > owner->fLength) + { + // play assigned sound if the train travelled its full length since meter activation + // TBD: check all combinations of directions and active cab + m_distancecounter = -1.f; // turn off the meter after its task is done + m_distancecounterclear->pitch(m_distancecounterclear->m_frequencyoffset + m_distancecounterclear->m_frequencyfactor); + m_distancecounterclear->gain(m_distancecounterclear->m_amplitudeoffset + m_distancecounterclear->m_amplitudefactor); + m_distancecounterclear->play(sound_flags::exclusive); + } + } + } + else + { + // stop power-reliant sounds if power is cut + if (dsbBuzzer) + { + if (true == dsbBuzzer->is_playing()) + { + dsbBuzzer->stop(); #ifdef _WIN32 - Console::BitsClear( 1 << 14 ); // ustawienie bitu 16 na PoKeys + Console::BitsClear(1 << 14); // ustawienie bitu 16 na PoKeys #endif - } - } + } + } - if (dsbBuzzerShp && dsbBuzzerShp->is_playing()) { + if (dsbBuzzerShp && dsbBuzzerShp->is_playing()) + { dsbBuzzerShp->stop(); - } + } { } - if( m_distancecounterclear ) { - m_distancecounterclear->stop(); - } - } + if (m_distancecounterclear) + { + m_distancecounterclear->stop(); + } + } - update_sounds_radio(); + update_sounds_radio(); } void TTrain::update_sounds_resonancenoise(sound_source &Sound) @@ -8905,7 +10199,7 @@ void TTrain::update_sounds_resonancenoise(sound_source &Sound) auto const frequency{Sound.m_frequencyoffset + Sound.m_frequencyfactor * mvOccupied->Vel * normalizer}; // volume calculation - auto volume = Sound.m_amplitudeoffset + Sound.m_amplitudefactor * std::lerp(mvOccupied->Vel / (1 + mvOccupied->Vmax), 1.0, 0.5); // scale base volume between 0.5-1.0 + auto volume = Sound.m_amplitudeoffset + Sound.m_amplitudefactor * interpolate(mvOccupied->Vel / (1 + mvOccupied->Vmax), 1.0, 0.5); // scale base volume between 0.5-1.0 if (volume > 0.05) { @@ -8917,796 +10211,792 @@ void TTrain::update_sounds_resonancenoise(sound_source &Sound) } } -void TTrain::update_sounds_runningnoise( sound_source &Sound ) { - // frequency calculation - auto const normalizer { ( - true == Sound.is_combined() ? - mvOccupied->Vmax * 0.01f : - 1.f ) }; - auto const frequency { - Sound.m_frequencyoffset - + Sound.m_frequencyfactor * mvOccupied->Vel * normalizer }; +void TTrain::update_sounds_runningnoise(sound_source &Sound) +{ + // frequency calculation + auto const normalizer{(true == Sound.is_combined() ? mvOccupied->Vmax * 0.01f : 1.f)}; + auto const frequency{Sound.m_frequencyoffset + Sound.m_frequencyfactor * mvOccupied->Vel * normalizer}; - // volume calculation - auto volume = - Sound.m_amplitudeoffset - + Sound.m_amplitudefactor * std::lerp( - mvOccupied->Vel / ( 1 + mvOccupied->Vmax ), 1.0, - 0.5 ); // scale base volume between 0.5-1.0 - if( std::abs( mvOccupied->nrot ) > 0.01 ) { - // hamulce wzmagaja halas - auto const brakeforceratio { ( - std::clamp( - mvOccupied->UnitBrakeForce / std::max( 1.0, mvOccupied->BrakeForceR( 1.0, mvOccupied->Vel ) / ( mvOccupied->NAxles * std::max( 1, mvOccupied->NBpA ) ) ), - 0.0, 1.0 ) ) }; + // volume calculation + auto volume = Sound.m_amplitudeoffset + Sound.m_amplitudefactor * interpolate(mvOccupied->Vel / (1 + mvOccupied->Vmax), 1.0, + 0.5); // scale base volume between 0.5-1.0 + if (std::abs(mvOccupied->nrot) > 0.01) + { + // hamulce wzmagaja halas + auto const brakeforceratio{(clamp(mvOccupied->UnitBrakeForce / std::max(1.0, mvOccupied->BrakeForceR(1.0, mvOccupied->Vel) / (mvOccupied->NAxles * std::max(1, mvOccupied->NBpA))), 0.0, 1.0))}; - volume *= 1 + 0.125 * brakeforceratio; - } - // scale volume by track quality - // TODO: track quality and/or environment factors as separate subroutine - volume *= - std::lerp( - 0.8, 1.2, - std::clamp( - DynamicObject->MyTrack->iQualityFlag / 20.0, - 0.0, 1.0 ) ); - // for single sample sounds muffle the playback at low speeds - if( false == Sound.is_combined() ) { - volume *= - std::lerp( - 0.0, 1.0, - std::clamp( - mvOccupied->Vel / 25.0, - 0.0, 1.0 ) ); - } + volume *= 1 + 0.125 * brakeforceratio; + } + // scale volume by track quality + // TODO: track quality and/or environment factors as separate subroutine + volume *= interpolate(0.8, 1.2, clamp(DynamicObject->MyTrack->iQualityFlag / 20.0, 0.0, 1.0)); + // for single sample sounds muffle the playback at low speeds + if (false == Sound.is_combined()) + { + volume *= interpolate(0.0, 1.0, clamp(mvOccupied->Vel / 25.0, 0.0, 1.0)); + } - if( volume > 0.05 ) { - Sound - .pitch( frequency ) - .gain( volume ) - .play( sound_flags::exclusive | sound_flags::looping ); - } - else { - Sound.stop(); - } + if (volume > 0.05) + { + Sound.pitch(frequency).gain(volume).play(sound_flags::exclusive | sound_flags::looping); + } + else + { + Sound.stop(); + } } -void TTrain::update_sounds_radio() { +void TTrain::update_sounds_radio() +{ radio_message_played = false; - if( false == m_radiomessages.empty() ) { - // erase completed radio messages from the list - m_radiomessages.erase( - std::remove_if( - std::begin( m_radiomessages ), std::end( m_radiomessages ), - []( auto const &source ) { - return ( false == source.second->is_playing() ); } ), - std::end( m_radiomessages ) ); - } - // adjust audibility of remaining messages based on current radio conditions - auto const radioenabled { ( true == mvOccupied->Radio ) && ( mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable ) }; - for( auto &message : m_radiomessages ) { - auto const volume { - ( true == radioenabled ) - && ( Dynamic()->Mechanik != nullptr ) - && ( message.first == RadioChannel() ) ? - m_radiovolume : - 0.0 }; - message.second->gain( volume ); + if (false == m_radiomessages.empty()) + { + // erase completed radio messages from the list + m_radiomessages.erase(std::remove_if(std::begin(m_radiomessages), std::end(m_radiomessages), [](auto const &source) { return (false == source.second->is_playing()); }), + std::end(m_radiomessages)); + } + // adjust audibility of remaining messages based on current radio conditions + auto const radioenabled{(true == mvOccupied->Radio) && (mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable)}; + for (auto &message : m_radiomessages) + { + auto const volume{(true == radioenabled) && (Dynamic()->Mechanik != nullptr) && (message.first == RadioChannel()) ? m_radiovolume : 0.0}; + message.second->gain(volume); radio_message_played |= (true == radioenabled) && (Dynamic()->Mechanik != nullptr) && (message.first == RadioChannel()); - } - // radiostop - if( m_radiostop ) { - if( ( true == radioenabled ) - && ( true == mvOccupied->RadioStopFlag ) ) { - m_radiostop->play( sound_flags::exclusive | sound_flags::looping ); + } + // radiostop + if (m_radiostop) + { + if ((true == radioenabled) && (true == mvOccupied->RadioStopFlag)) + { + m_radiostop->play(sound_flags::exclusive | sound_flags::looping); radio_message_played |= true; - } - else { - m_radiostop->stop(); - } - } + } + else + { + m_radiostop->stop(); + } + } if (radio_message_played) { btLampkaRadioMessage.gain(m_radiovolume); } } -void TTrain::update_screens(double dt) { - for (auto &screen : m_screens) { - if (screen.updatetimecounter >= 0) - screen.updatetimecounter += dt; +void TTrain::update_screens(double dt) +{ + for (auto &screen : m_screens) + { + if (screen.updatetimecounter >= 0) + screen.updatetimecounter += dt; - if (screen.updatetimecounter <= screen.updatetime) - continue; + if (screen.updatetimecounter <= screen.updatetime) + continue; - screen.updatetimecounter = screen.updatetime > 0 ? 0 : -1; + screen.updatetimecounter = screen.updatetime > 0 ? 0 : -1; - auto state_dict = GetTrainState(screen.parameters); + auto state_dict = GetTrainState(screen.parameters); - state_dict->insert("touches", *screen.touch_list); - screen.touch_list->clear(); + state_dict->insert("touches", *screen.touch_list); + screen.touch_list->clear(); - Application.request({ screen.script, state_dict, screen.rt } ); - } + Application.request({screen.script, state_dict, screen.rt}); + } } -void TTrain::add_distance( double const Distance ) { +void TTrain::add_distance(double const Distance) +{ - auto const meterenabled { ( m_distancecounter >= 0 ) && ( mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable) }; + auto const meterenabled{(m_distancecounter >= 0) && (mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable)}; - if( true == meterenabled ) { m_distancecounter += Distance * Occupied()->CabOccupied; } - else { m_distancecounter = -1.f; } + if (true == meterenabled) + { + m_distancecounter += Distance * Occupied()->CabOccupied; + } + else + { + m_distancecounter = -1.f; + } } bool TTrain::CabChange(int iDirection) { // McZapkie-090902: zmiana kabiny 1->0->2 i z powrotem - if( ( DynamicObject->Mechanik == nullptr ) - || ( true == DynamicObject->Mechanik->AIControllFlag ) ) { - // jeśli prowadzi AI albo jest w innym członie - // jak AI prowadzi, to nie można mu mieszać - if (std::abs(mvOccupied->CabOccupied + iDirection) > 1) - return false; // ewentualna zmiana pojazdu - mvOccupied->CabOccupied += iDirection; - } - else - { // jeśli pojazd prowadzony ręcznie albo wcale (wagon) - mvOccupied->CabDeactivisationAuto(); - if( mvOccupied->ChangeCab( iDirection ) ) { - if( InitializeCab( mvOccupied->CabOccupied, mvOccupied->TypeName + ".mmd" ) ) { - // zmiana kabiny w ramach tego samego pojazdu - mvOccupied->CabActivisationAuto(); // załączenie rozrządu (wirtualne kabiny) - DynamicObject->Mechanik->DirectionChange(); - return true; // udało się zmienić kabinę - } - } - // aktywizacja poprzedniej, bo jeszcze nie wiadomo, czy jakiś pojazd jest - mvOccupied->CabActivisationAuto(); - } - return false; // ewentualna zmiana pojazdu + if ((DynamicObject->Mechanik == nullptr) || (true == DynamicObject->Mechanik->AIControllFlag)) + { + // jeśli prowadzi AI albo jest w innym członie + // jak AI prowadzi, to nie można mu mieszać + if (std::abs(mvOccupied->CabOccupied + iDirection) > 1) + return false; // ewentualna zmiana pojazdu + mvOccupied->CabOccupied += iDirection; + } + else + { // jeśli pojazd prowadzony ręcznie albo wcale (wagon) + mvOccupied->CabDeactivisationAuto(); + if (mvOccupied->ChangeCab(iDirection)) + { + if (InitializeCab(mvOccupied->CabOccupied, mvOccupied->TypeName + ".mmd")) + { + // zmiana kabiny w ramach tego samego pojazdu + mvOccupied->CabActivisationAuto(); // załączenie rozrządu (wirtualne kabiny) + DynamicObject->Mechanik->DirectionChange(); + return true; // udało się zmienić kabinę + } + } + // aktywizacja poprzedniej, bo jeszcze nie wiadomo, czy jakiś pojazd jest + mvOccupied->CabActivisationAuto(); + } + return false; // ewentualna zmiana pojazdu } // McZapkie-310302 // wczytywanie pliku z danymi multimedialnymi (dzwieki, kontrolki, kabiny) bool TTrain::LoadMMediaFile(std::string const &asFileName) { - // initialize sounds so potential entries from previous vehicle don't stick around - std::unordered_map< - std::string, - std::tuple &, sound_placement, float, sound_type, int, double>> - internalsounds = { - {"ctrl:", {dsbNastawnikJazdy, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, - {"ctrlscnd:", {dsbNastawnikBocz, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, - {"reverserkey:", {dsbReverserKey, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, - {"buzzer:", {dsbBuzzer, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, - {"buzzershp:", {dsbBuzzerShp, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, - {"radiostop:", {m_radiostop, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, - {"slipalarm:", {dsbSlipAlarm, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, - {"distancecounter:", {m_distancecounterclear, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, - {"tachoclock:", {dsbHasler, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, - {"switch:", {dsbSwitch, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, - {"pneumaticswitch:", {dsbPneumaticSwitch, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, - {"airsound:", {rsHiss, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, sound_parameters::amplitude, 100.0}}, - {"airsound2:", {rsHissU, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, sound_parameters::amplitude, 100.0}}, - {"airsound3:", {rsHissE, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, sound_parameters::amplitude, 100.0}}, - {"airsound4:", {rsHissX, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, sound_parameters::amplitude, 100.0}}, - {"airsound5:", {rsHissT, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, sound_parameters::amplitude, 100.0}}, - {"localbrakesound:", {rsSBHiss, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, sound_parameters::amplitude, 100.0}}, - {"localbrakesound2:", {rsSBHissU, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, sound_parameters::amplitude, 100.0}}, - {"brakesound:", {rsBrake, sound_placement::internal, -1, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency, 100.0}}, - {"fadesound:", {rsFadeSound, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, - {"runningnoise:", {rsRunningNoise, sound_placement::internal, EU07_SOUND_GLOBALRANGE, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency, mvOccupied->Vmax }}, - {"resonancenoise:", {rsResonanceNoise, sound_placement::internal, EU07_SOUND_GLOBALRANGE, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency, mvOccupied->Vmax }}, - {"windsound:", {rsWindSound, sound_placement::internal, EU07_SOUND_GLOBALRANGE, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency, mvOccupied->Vmax }}, - {"huntingnoise:", {rsHuntingNoise, sound_placement::internal, EU07_SOUND_GLOBALRANGE, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency, mvOccupied->Vmax }}, - {"rainsound:", {m_rainsound, sound_placement::internal, -1, sound_type::single, 0, 100.0}}, - }; - for( auto &soundconfig : internalsounds ) { - std::get &>( soundconfig.second ).reset(); - } - // NOTE: since radiosound is an incomplete template not using std::optional it gets a special treatment - m_radiosound.owner( DynamicObject ); + // initialize sounds so potential entries from previous vehicle don't stick around + std::unordered_map &, sound_placement, float, sound_type, int, double>> internalsounds = { + {"ctrl:", {dsbNastawnikJazdy, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, + {"ctrlscnd:", {dsbNastawnikBocz, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, + {"reverserkey:", {dsbReverserKey, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, + {"buzzer:", {dsbBuzzer, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, + {"buzzershp:", {dsbBuzzerShp, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, + {"radiostop:", {m_radiostop, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, + {"slipalarm:", {dsbSlipAlarm, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, + {"distancecounter:", {m_distancecounterclear, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, + {"tachoclock:", {dsbHasler, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, + {"switch:", {dsbSwitch, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, + {"pneumaticswitch:", {dsbPneumaticSwitch, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, + {"airsound:", {rsHiss, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, sound_parameters::amplitude, 100.0}}, + {"airsound2:", {rsHissU, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, sound_parameters::amplitude, 100.0}}, + {"airsound3:", {rsHissE, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, sound_parameters::amplitude, 100.0}}, + {"airsound4:", {rsHissX, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, sound_parameters::amplitude, 100.0}}, + {"airsound5:", {rsHissT, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, sound_parameters::amplitude, 100.0}}, + {"localbrakesound:", {rsSBHiss, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, sound_parameters::amplitude, 100.0}}, + {"localbrakesound2:", {rsSBHissU, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, sound_parameters::amplitude, 100.0}}, + {"brakesound:", {rsBrake, sound_placement::internal, -1, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency, 100.0}}, + {"fadesound:", {rsFadeSound, sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE, sound_type::single, 0, 100.0}}, + {"runningnoise:", {rsRunningNoise, sound_placement::internal, EU07_SOUND_GLOBALRANGE, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency, mvOccupied->Vmax}}, + {"resonancenoise:", {rsResonanceNoise, sound_placement::internal, EU07_SOUND_GLOBALRANGE, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency, mvOccupied->Vmax}}, + {"windsound:", {rsWindSound, sound_placement::internal, EU07_SOUND_GLOBALRANGE, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency, mvOccupied->Vmax}}, + {"huntingnoise:", {rsHuntingNoise, sound_placement::internal, EU07_SOUND_GLOBALRANGE, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency, mvOccupied->Vmax}}, + {"rainsound:", {m_rainsound, sound_placement::internal, -1, sound_type::single, 0, 100.0}}, + }; + for (auto &soundconfig : internalsounds) + { + std::get &>(soundconfig.second).reset(); + } + // NOTE: since radiosound is an incomplete template not using std::optional it gets a special treatment + m_radiosound.owner(DynamicObject); CabSoundLocations.clear(); - cParser parser( asFileName, cParser::buffer_FILE, DynamicObject->asBaseDir, true, std::vector(), true ); - // NOTE: yaml-style comments are disabled until conflict in use of # is resolved - // parser.addCommentStyle( "#", "\n" ); - std::string token; - do - { - token = ""; - parser.getTokens(); - parser >> token; - } while ((token != "") && (token != "internaldata:")); + cParser parser(asFileName, cParser::buffer_FILE, DynamicObject->asBaseDir, true, std::vector(), true); + // NOTE: yaml-style comments are disabled until conflict in use of # is resolved + // parser.addCommentStyle( "#", "\n" ); + std::string token; + do + { + token = ""; + parser.getTokens(); + parser >> token; + } while ((token != "") && (token != "internaldata:")); - if (token == "internaldata:") { + if (token == "internaldata:") + { - do { - token = ""; - parser.getTokens(); - parser >> token; + do + { + token = ""; + parser.getTokens(); + parser >> token; - auto lookup { internalsounds.find( token ) }; - if( lookup == internalsounds.end() ) { continue; } + auto lookup{internalsounds.find(token)}; + if (lookup == internalsounds.end()) + { + continue; + } - auto const soundconfig { lookup->second }; - sound_source sound { - std::get( soundconfig ), - std::get( soundconfig ) }; - sound.deserialize( - parser, - std::get( soundconfig ), - std::get( soundconfig ), - std::get( soundconfig ) ); - sound.owner( DynamicObject ); - std::get &>( soundconfig ) = sound; - } while( token != "" ); + auto const soundconfig{lookup->second}; + sound_source sound{std::get(soundconfig), std::get(soundconfig)}; + sound.deserialize(parser, std::get(soundconfig), std::get(soundconfig), std::get(soundconfig)); + sound.owner(DynamicObject); + std::get &>(soundconfig) = sound; + } while (token != ""); - - // assign default samples to sound emitters which weren't included in the config file - if( !m_rainsound ) { - sound_source rainsound; - rainsound.deserialize( "rainsound_default", sound_type::single ); - rainsound.owner( DynamicObject ); - m_rainsound = rainsound; - } - if (!rsSBHiss) { - // fallback for vehicles without defined local brake hiss sound - rsSBHiss = rsHiss; - } - if (!rsSBHissU) { - // fallback for vehicles without defined local brake hiss sound - rsSBHissU = rsHissU; - } - if (rsBrake) { - rsBrake->m_frequencyfactor /= (1 + mvOccupied->Vmax); - } - if (rsResonanceNoise) { + // assign default samples to sound emitters which weren't included in the config file + if (!m_rainsound) + { + sound_source rainsound; + rainsound.deserialize("rainsound_default", sound_type::single); + rainsound.owner(DynamicObject); + m_rainsound = rainsound; + } + if (!rsSBHiss) + { + // fallback for vehicles without defined local brake hiss sound + rsSBHiss = rsHiss; + } + if (!rsSBHissU) + { + // fallback for vehicles without defined local brake hiss sound + rsSBHissU = rsHissU; + } + if (rsBrake) + { + rsBrake->m_frequencyfactor /= (1 + mvOccupied->Vmax); + } + if (rsResonanceNoise) + { rsResonanceNoise->m_frequencyfactor /= (1 + mvOccupied->Vmax); - } - if (rsWindSound) { + } + if (rsWindSound) + { rsWindSound->m_frequencyfactor /= (1 + mvOccupied->Vmax); - } - if (rsRunningNoise) { - rsRunningNoise->m_frequencyfactor /= (1 + mvOccupied->Vmax); - } - if (rsHuntingNoise) { - rsHuntingNoise->m_frequencyfactor /= (1 + mvOccupied->Vmax); - } - } - auto const nullvector{ glm::vec3() }; + } + if (rsRunningNoise) + { + rsRunningNoise->m_frequencyfactor /= (1 + mvOccupied->Vmax); + } + if (rsHuntingNoise) + { + rsHuntingNoise->m_frequencyfactor /= (1 + mvOccupied->Vmax); + } + } + auto const nullvector{glm::vec3()}; std::vector>> sounds = { - dsbReverserKey, dsbNastawnikJazdy, dsbNastawnikBocz, - dsbSwitch, dsbPneumaticSwitch, - rsHiss, rsHissU, rsHissE, rsHissX, rsHissT, rsSBHiss, rsSBHissU, - rsFadeSound, rsRunningNoise, rsResonanceNoise,rsWindSound, rsHuntingNoise, - dsbHasler, dsbBuzzer,dsbBuzzerShp, dsbSlipAlarm, m_distancecounterclear, m_rainsound, m_radiostop - }; - for (auto &sound : sounds) { - if (sound.get()) { + dsbReverserKey, dsbNastawnikJazdy, dsbNastawnikBocz, dsbSwitch, dsbPneumaticSwitch, rsHiss, rsHissU, rsHissE, rsHissX, rsHissT, rsSBHiss, + rsSBHissU, rsFadeSound, rsRunningNoise, rsResonanceNoise, rsWindSound, rsHuntingNoise, dsbHasler, dsbBuzzer, dsbBuzzerShp, dsbSlipAlarm, m_distancecounterclear, + m_rainsound, m_radiostop}; + for (auto &sound : sounds) + { + if (sound.get()) + { CabSoundLocations.emplace_back(sound, sound.get()->offset()); } } - return true; + return true; } bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) { - m_controlmapper.clear(); - // clear python screens - m_screens.clear(); - // reset sound positions - auto const nullvector { glm::vec3() }; - std::vector>> sounds = { - dsbReverserKey, dsbNastawnikJazdy, dsbNastawnikBocz, - dsbSwitch, dsbPneumaticSwitch, - rsHiss, rsHissU, rsHissE, rsHissX, rsHissT, rsSBHiss, rsSBHissU, - rsFadeSound, rsRunningNoise, rsResonanceNoise, rsWindSound, rsHuntingNoise, - dsbHasler, dsbBuzzer, dsbBuzzerShp, dsbSlipAlarm, m_distancecounterclear, m_rainsound, m_radiostop - }; - for( auto &sound : sounds ) { - if( sound.get() ) { - sound.get()->offset( nullvector ); - } - } - m_radiosound.offset( nullvector ); - for (auto &sound : CabSoundLocations) { - if ((sound.first.get()) - && (sound.first.get()->offset() == nullvector)) { + m_controlmapper.clear(); + // clear python screens + m_screens.clear(); + // reset sound positions + auto const nullvector{glm::vec3()}; + std::vector>> sounds = { + dsbReverserKey, dsbNastawnikJazdy, dsbNastawnikBocz, dsbSwitch, dsbPneumaticSwitch, rsHiss, rsHissU, rsHissE, rsHissX, rsHissT, rsSBHiss, + rsSBHissU, rsFadeSound, rsRunningNoise, rsResonanceNoise, rsWindSound, rsHuntingNoise, dsbHasler, dsbBuzzer, dsbBuzzerShp, dsbSlipAlarm, m_distancecounterclear, + m_rainsound, m_radiostop}; + for (auto &sound : sounds) + { + if (sound.get()) + { + sound.get()->offset(nullvector); + } + } + m_radiosound.offset(nullvector); + for (auto &sound : CabSoundLocations) + { + if ((sound.first.get()) && (sound.first.get()->offset() == nullvector)) + { sound.first.get()->offset(sound.second); } } - // reset view angles - pMechViewAngle = { 0.0, 0.0 }; + // reset view angles + pMechViewAngle = {0.0, 0.0}; - is_cab_initialized = true; // the attempt may fail, but it's the attempt that counts + is_cab_initialized = true; // the attempt may fail, but it's the attempt that counts - bool parse = false; - int cabindex = 0; - DynamicObject->mdKabina = nullptr; // likwidacja wskaźnika na dotychczasową kabinę - switch (NewCabNo) - { // ustalenie numeru kabiny do wczytania - case -1: - cabindex = 2; - break; - case 1: - cabindex = 1; - break; - case 0: - cabindex = 0; - break; - } - iCabn = cabindex; + bool parse = false; + int cabindex = 0; + DynamicObject->mdKabina = nullptr; // likwidacja wskaźnika na dotychczasową kabinę + switch (NewCabNo) + { // ustalenie numeru kabiny do wczytania + case -1: + cabindex = 2; + break; + case 1: + cabindex = 1; + break; + case 0: + cabindex = 0; + break; + } + iCabn = cabindex; - std::string cabstr("cab" + std::to_string(cabindex) + "definition:"); + std::string cabstr("cab" + std::to_string(cabindex) + "definition:"); - cParser parser( asFileName, cParser::buffer_FILE, DynamicObject->asBaseDir, true, std::vector(), true ); - // NOTE: yaml-style comments are disabled until conflict in use of # is resolved - // parser.addCommentStyle( "#", "\n" ); - std::string token; - do - { - // szukanie kabiny - token = ""; - parser.getTokens(); - parser >> token; - } while ((token != "") && (token != cabstr)); + cParser parser(asFileName, cParser::buffer_FILE, DynamicObject->asBaseDir, true, std::vector(), true); + // NOTE: yaml-style comments are disabled until conflict in use of # is resolved + // parser.addCommentStyle( "#", "\n" ); + std::string token; + do + { + // szukanie kabiny + token = ""; + parser.getTokens(); + parser >> token; + } while ((token != "") && (token != cabstr)); - if (token == cabstr) - { - // jeśli znaleziony wpis kabiny - Cabine[cabindex].Load(parser); - // NOTE: the position and angle definitions depend on strict entry order - // TODO: refactor into more flexible arrangement - parser.getTokens(); - parser >> token; - if( token == std::string( "driver" + std::to_string( cabindex ) + "angle:" ) ) { - // camera view angle - parser.getTokens( 2, false ); - // angle is specified in degrees but internally stored in radians - glm::vec2 viewangle; - parser - >> viewangle.y // yaw first, then pitch - >> viewangle.x; - pMechViewAngle = glm::radians( viewangle ); + if (token == cabstr) + { + // jeśli znaleziony wpis kabiny + Cabine[cabindex].Load(parser); + // NOTE: the position and angle definitions depend on strict entry order + // TODO: refactor into more flexible arrangement + parser.getTokens(); + parser >> token; + if (token == std::string("driver" + std::to_string(cabindex) + "angle:")) + { + // camera view angle + parser.getTokens(2, false); + // angle is specified in degrees but internally stored in radians + glm::vec2 viewangle; + parser >> viewangle.y // yaw first, then pitch + >> viewangle.x; + pMechViewAngle = glm::radians(viewangle); - Global.pCamera.Angle.x = pMechViewAngle.x; - Global.pCamera.Angle.y = pMechViewAngle.y; + Global.pCamera.Angle.x = pMechViewAngle.x; + Global.pCamera.Angle.y = pMechViewAngle.y; - parser.getTokens(); - parser >> token; - } - if (token == std::string("driver" + std::to_string(cabindex) + "pos:")) - { - // pozycja poczatkowa maszynisty - parser.getTokens(3, false); - parser - >> pMechOffset.x - >> pMechOffset.y - >> pMechOffset.z; - pMechSittingPosition = pMechOffset; + parser.getTokens(); + parser >> token; + } + if (token == std::string("driver" + std::to_string(cabindex) + "pos:")) + { + // pozycja poczatkowa maszynisty + parser.getTokens(3, false); + parser >> pMechOffset.x >> pMechOffset.y >> pMechOffset.z; + pMechSittingPosition = pMechOffset; - parser.getTokens(); - parser >> token; - } - // ABu: pozycja siedzaca mechanika - if (token == std::string("driver" + std::to_string(cabindex) + "sitpos:")) - { - // ABu 180404 pozycja siedzaca maszynisty - parser.getTokens(3, false); - parser - >> pMechSittingPosition.x - >> pMechSittingPosition.y - >> pMechSittingPosition.z; + parser.getTokens(); + parser >> token; + } + // ABu: pozycja siedzaca mechanika + if (token == std::string("driver" + std::to_string(cabindex) + "sitpos:")) + { + // ABu 180404 pozycja siedzaca maszynisty + parser.getTokens(3, false); + parser >> pMechSittingPosition.x >> pMechSittingPosition.y >> pMechSittingPosition.z; - parser.getTokens(); - parser >> token; - } - // else parse=false; - do { - if( parse == true ) { - token = ""; - parser.getTokens(); - parser >> token; - } - else { - parse = true; - } - // inicjacja kabiny - // Ra 2014-08: zmieniamy zasady - zamiast przypisywać submodel do - // istniejących obiektów animujących - // będziemy teraz uaktywniać obiekty animujące z tablicy i podawać im - // submodel oraz wskaźnik na parametr - if (token == std::string("cab" + std::to_string(cabindex) + "model:")) - { - // model kabiny - parser.getTokens(); - parser >> token; + parser.getTokens(); + parser >> token; + } + // else parse=false; + do + { + if (parse == true) + { + token = ""; + parser.getTokens(); + parser >> token; + } + else + { + parse = true; + } + // inicjacja kabiny + // Ra 2014-08: zmieniamy zasady - zamiast przypisywać submodel do + // istniejących obiektów animujących + // będziemy teraz uaktywniać obiekty animujące z tablicy i podawać im + // submodel oraz wskaźnik na parametr + if (token == std::string("cab" + std::to_string(cabindex) + "model:")) + { + // model kabiny + parser.getTokens(); + parser >> token; std::replace(token.begin(), token.end(), '\\', '/'); - if (token != "none") - { - // bieżąca sciezka do tekstur to dynamic/... - Global.asCurrentTexturePath = DynamicObject->asBaseDir; - // szukaj kabinę jako oddzielny model - // name can contain leading slash, erase it to avoid creation of double slashes when the name is combined with current directory - replace_slashes( token ); - erase_leading_slashes( token ); - if( token[ 0 ] == '/' ) { - token.erase( 0, 1 ); - } - TModel3d *kabina = TModelsManager::GetModel(DynamicObject->asBaseDir + token, true, true, - (Global.network_servers.empty() && !Global.network_client) ? 0 : id()); - // z powrotem defaultowa sciezka do tekstur - Global.asCurrentTexturePath = paths::textures; - // if (DynamicObject->mdKabina!=k) - if (kabina != nullptr) - { - DynamicObject->mdKabina = kabina; // nowa kabina - } - //(mdKabina) może zostać to samo po przejściu do innego członu bez - // zmiany kabiny, przy powrocie musi być wiązanie ponowne - // else - // break; //wyjście z pętli, bo model zostaje bez zmian - } - else if (cabindex == 1) { - // model tylko, gdy nie ma kabiny 1 - // McZapkie-170103: szukaj elementy kabiny w glownym modelu - DynamicObject->mdKabina = DynamicObject->mdModel; - } - clear_cab_controls(); - } -/* - if (nullptr == DynamicObject->mdKabina) - { - // don't bother with other parts until the cab is initialised - continue; - } -*/ - else if (true == initialize_gauge(parser, token, cabindex)) - { - // matched the token, grab the next one - continue; - } - else if (true == initialize_button(parser, token, cabindex)) - { - // matched the token, grab the next one - continue; - } - // TODO: add "pydestination:" - else if (token == "pyscreen:") - { - screen_entry screen; - screen.deserialize(parser); - if ((false == screen.script.empty()) && (substr_path(screen.script).empty())) - { - screen.script = DynamicObject->asBaseDir + screen.script; - } + if (token != "none") + { + // bieżąca sciezka do tekstur to dynamic/... + Global.asCurrentTexturePath = DynamicObject->asBaseDir; + // szukaj kabinę jako oddzielny model + // name can contain leading slash, erase it to avoid creation of double slashes when the name is combined with current directory + replace_slashes(token); + erase_leading_slashes(token); + if (token[0] == '/') + { + token.erase(0, 1); + } + TModel3d *kabina = TModelsManager::GetModel(DynamicObject->asBaseDir + token, true, true, (Global.network_servers.empty() && !Global.network_client) ? 0 : id()); + // z powrotem defaultowa sciezka do tekstur + Global.asCurrentTexturePath = paths::textures; + // if (DynamicObject->mdKabina!=k) + if (kabina != nullptr) + { + DynamicObject->mdKabina = kabina; // nowa kabina + } + //(mdKabina) może zostać to samo po przejściu do innego członu bez + // zmiany kabiny, przy powrocie musi być wiązanie ponowne + // else + // break; //wyjście z pętli, bo model zostaje bez zmian + } + else if (cabindex == 1) + { + // model tylko, gdy nie ma kabiny 1 + // McZapkie-170103: szukaj elementy kabiny w glownym modelu + DynamicObject->mdKabina = DynamicObject->mdModel; + } + clear_cab_controls(); + } + /* + if (nullptr == DynamicObject->mdKabina) + { + // don't bother with other parts until the cab is initialised + continue; + } + */ + else if (true == initialize_gauge(parser, token, cabindex)) + { + // matched the token, grab the next one + continue; + } + else if (true == initialize_button(parser, token, cabindex)) + { + // matched the token, grab the next one + continue; + } + // TODO: add "pydestination:" + else if (token == "pyscreen:") + { + screen_entry screen; + screen.deserialize(parser); + if ((false == screen.script.empty()) && (substr_path(screen.script).empty())) + { + screen.script = DynamicObject->asBaseDir + screen.script; + } - ITexture *tex = nullptr; - TSubModel *submodel = nullptr; - if (screen.target != "none") - { - submodel = (DynamicObject->mdKabina ? - DynamicObject->mdKabina->GetFromName(screen.target) : - DynamicObject->mdLowPolyInt ? - DynamicObject->mdLowPolyInt->GetFromName(screen.target) : - nullptr); - if (submodel == nullptr) - { - WriteLog("Python Screen: submodel " + screen.target + - " not found - Ignoring screen"); - continue; - } - auto const material{submodel->GetMaterial()}; - if (material <= 0) - { - // sub model nie posiada tekstury lub tekstura wymienna - nie obslugiwana - WriteLog("Python Screen: invalid texture id " + std::to_string(material) + - " - Ignoring screen"); - continue; - } + ITexture *tex = nullptr; + TSubModel *submodel = nullptr; + if (screen.target != "none") + { + submodel = (DynamicObject->mdKabina ? DynamicObject->mdKabina->GetFromName(screen.target) : + DynamicObject->mdLowPolyInt ? DynamicObject->mdLowPolyInt->GetFromName(screen.target) : + nullptr); + if (submodel == nullptr) + { + WriteLog("Python Screen: submodel " + screen.target + " not found - Ignoring screen"); + continue; + } + auto const material{submodel->GetMaterial()}; + if (material <= 0) + { + // sub model nie posiada tekstury lub tekstura wymienna - nie obslugiwana + WriteLog("Python Screen: invalid texture id " + std::to_string(material) + " - Ignoring screen"); + continue; + } - tex = &GfxRenderer->Texture(GfxRenderer->Material(material)->GetTexture(0)); - } - else - { - // TODO: fix leak - tex = ITexture::null_texture(); - tex->make_stub(); - } + tex = &GfxRenderer->Texture(GfxRenderer->Material(material)->GetTexture(0)); + } + else + { + // TODO: fix leak + tex = ITexture::null_texture(); + tex->make_stub(); + } - tex->create(true); // make the surface static so it doesn't get destroyed by garbage - // collector if the user spends long time outside cab - // TBD, TODO: keep texture handles around, so we can undo the static switch when the - // user changes cabs? - auto rt = std::make_shared(); - rt->shared_tex = tex; + tex->create(true); // make the surface static so it doesn't get destroyed by garbage + // collector if the user spends long time outside cab + // TBD, TODO: keep texture handles around, so we can undo the static switch when the + // user changes cabs? + auto rt = std::make_shared(); + rt->shared_tex = tex; - // record renderer and material binding for future update requests - m_screens.emplace_back(screen); - m_screens.back().rt = rt; + // record renderer and material binding for future update requests + m_screens.emplace_back(screen); + m_screens.back().rt = rt; - m_screens.back().touch_list = std::make_shared>(); - if (submodel) - submodel->screen_touch_list = m_screens.back().touch_list; + m_screens.back().touch_list = std::make_shared>(); + if (submodel) + submodel->screen_touch_list = m_screens.back().touch_list; - if (Global.python_displaywindows) - m_screens.back().viewer = std::make_unique(rt, m_screens.back().touch_list, m_screens.back().script); - } - else if (token == "pyscreenupdatetime:") { - parser.getTokens(); - parser >> ScreenUpdateRate; - } - // btLampkaUnknown`"unknown",mdKabina,false); - } while ( ( token != "" ) -// TODO: enable full per-cab deserialization when/if .mmd files get proper per-cab switch configuration -// && ( token != "cab1definition:" ) -// && ( token != "cab2definition:" ) - && ( token != "cab0definition:" ) ); + if (Global.python_displaywindows) + m_screens.back().viewer = std::make_unique(rt, m_screens.back().touch_list, m_screens.back().script); + } + else if (token == "pyscreenupdatetime:") + { + parser.getTokens(); + parser >> ScreenUpdateRate; + } + // btLampkaUnknown`"unknown",mdKabina,false); + } while ((token != "") + // TODO: enable full per-cab deserialization when/if .mmd files get proper per-cab switch configuration + // && ( token != "cab1definition:" ) + // && ( token != "cab2definition:" ) + && (token != "cab0definition:")); for (auto &screen : m_screens) { - if (screen.updatetime > 0) { + if (screen.updatetime > 0) + { screen.updatetime = std::max((int)screen.updatetime, Global.PythonScreenUpdateRate) * 0.001; } - if (screen.updatetime == 0) { + if (screen.updatetime == 0) + { screen.updatetime = std::max(Global.PythonScreenUpdateRate, ScreenUpdateRate) * 0.001; } - if (screen.updatetime < -1) { + if (screen.updatetime < -1) + { screen.updatetime = -screen.updatetime * 0.001; } } - } - else - { - return false; - } -/* - if (DynamicObject->mdKabina) - { + } + else + { + return false; + } + /* + if (DynamicObject->mdKabina) + { + */ + // configure placement of sound emitters which aren't bound with any device model, and weren't placed manually + auto const caboffset{glm::dvec3{(Cabine[cabindex].CabPos1 + Cabine[cabindex].CabPos2) * 0.5f} + glm::dvec3{0, 1, 0}}; + // NOTE: since radiosound is an incomplete template not using std::optional it gets a special treatment + if (m_radiosound.offset() == nullvector) + { + m_radiosound.offset(btLampkaRadio.model_offset()); + } + if (m_radiosound.offset() == nullvector) + { + m_radiosound.offset(caboffset); + } + std::vector>, glm::vec3>> soundlocations = { + {dsbReverserKey, ggDirKey.model_offset()}, + {dsbNastawnikJazdy, ggJointCtrl.model_offset()}, + {dsbNastawnikJazdy, ggMainCtrl.model_offset()}, // NOTE: fallback for vehicles without universal controller + {dsbNastawnikBocz, ggScndCtrl.model_offset()}, + {dsbSwitch, caboffset}, + {dsbPneumaticSwitch, caboffset}, + {rsHiss, ggBrakeCtrl.model_offset()}, + {rsHissU, ggBrakeCtrl.model_offset()}, + {rsHissE, ggBrakeCtrl.model_offset()}, + {rsHissX, ggBrakeCtrl.model_offset()}, + {rsHissT, ggBrakeCtrl.model_offset()}, + {rsSBHiss, ggLocalBrake.model_offset()}, + {rsSBHiss, ggBrakeCtrl.model_offset()}, // NOTE: fallback if the local brake model can't be located + {rsSBHissU, ggLocalBrake.model_offset()}, + {rsSBHissU, ggBrakeCtrl.model_offset()}, // NOTE: fallback if the local brake model can't be located + {rsFadeSound, caboffset}, + {rsRunningNoise, caboffset}, + {rsResonanceNoise, caboffset}, + {rsWindSound, caboffset}, + {rsHuntingNoise, caboffset}, + {dsbHasler, caboffset}, + {dsbBuzzer, btLampkaCzuwaka.model_offset()}, + {dsbBuzzerShp, btLampkaCzuwaka.model_offset()}, + {dsbSlipAlarm, caboffset}, + {m_distancecounterclear, btLampkaCzuwaka.model_offset()}, + {m_rainsound, caboffset}, + {m_radiostop, m_radiosound.offset()}, + }; + for (auto &sound : soundlocations) + { + if ((sound.first.get()) && (sound.first.get()->offset() == nullvector)) + { + sound.first.get()->offset(sound.second); + } + } + // second pass, in case some items received no positioning due to missing submodels etc + for (auto &sound : soundlocations) + { + if ((sound.first.get()) && (sound.first.get()->offset() == nullvector)) + { + sound.first.get()->offset(caboffset); + } + } + + if (DynamicObject->mdKabina) + DynamicObject->mdKabina->Init(); // obrócenie modelu oraz optymalizacja, również zapisanie binarnego + + set_cab_controls(NewCabNo < 0 ? 2 : NewCabNo); + + // set pantograpths (hujhujhuj) + change_pantograph_selection(0); + + /* + return true; +} +return (token == "none"); */ - // configure placement of sound emitters which aren't bound with any device model, and weren't placed manually - auto const caboffset { glm::dvec3 { ( Cabine[ cabindex ].CabPos1 + Cabine[ cabindex ].CabPos2 ) * 0.5f } +glm::dvec3 { 0, 1, 0 } }; - // NOTE: since radiosound is an incomplete template not using std::optional it gets a special treatment - if( m_radiosound.offset() == nullvector ) { - m_radiosound.offset( btLampkaRadio.model_offset() ); - } - if( m_radiosound.offset() == nullvector ) { - m_radiosound.offset( caboffset ); - } - std::vector>, glm::vec3>> - soundlocations = { - {dsbReverserKey, ggDirKey.model_offset()}, - {dsbNastawnikJazdy, ggJointCtrl.model_offset()}, - {dsbNastawnikJazdy, ggMainCtrl.model_offset()}, // NOTE: fallback for vehicles without universal controller - {dsbNastawnikBocz, ggScndCtrl.model_offset()}, - {dsbSwitch, caboffset}, - {dsbPneumaticSwitch, caboffset}, - {rsHiss, ggBrakeCtrl.model_offset()}, - {rsHissU, ggBrakeCtrl.model_offset()}, - {rsHissE, ggBrakeCtrl.model_offset()}, - {rsHissX, ggBrakeCtrl.model_offset()}, - {rsHissT, ggBrakeCtrl.model_offset()}, - {rsSBHiss, ggLocalBrake.model_offset()}, - {rsSBHiss, ggBrakeCtrl.model_offset()}, // NOTE: fallback if the local brake model can't be located - {rsSBHissU, ggLocalBrake.model_offset()}, - {rsSBHissU, ggBrakeCtrl.model_offset()}, // NOTE: fallback if the local brake model can't be located - {rsFadeSound, caboffset}, - {rsRunningNoise, caboffset}, - {rsResonanceNoise, caboffset}, - {rsWindSound, caboffset}, - {rsHuntingNoise, caboffset}, - {dsbHasler, caboffset}, - {dsbBuzzer, btLampkaCzuwaka.model_offset()}, - {dsbBuzzerShp, btLampkaCzuwaka.model_offset()}, - {dsbSlipAlarm, caboffset}, - {m_distancecounterclear, btLampkaCzuwaka.model_offset()}, - {m_rainsound, caboffset}, - {m_radiostop, m_radiosound.offset()}, - }; - for( auto & sound : soundlocations ) { - if( ( sound.first.get() ) - && ( sound.first.get()->offset() == nullvector ) ) { - sound.first.get()->offset( sound.second ); - } - } - // second pass, in case some items received no positioning due to missing submodels etc - for( auto & sound : soundlocations ) { - if( ( sound.first.get() ) - && ( sound.first.get()->offset() == nullvector ) ) { - sound.first.get()->offset( caboffset ); - } - } - - if( DynamicObject->mdKabina ) - DynamicObject->mdKabina->Init(); // obrócenie modelu oraz optymalizacja, również zapisanie binarnego - - set_cab_controls( NewCabNo < 0 ? 2 : NewCabNo ); - - // set pantograpths (hujhujhuj) - change_pantograph_selection(0); - - /* - return true; - } - return (token == "none"); -*/ - return true; + return true; } glm::dvec3 TTrain::MirrorPosition(bool lewe) { // zwraca współrzędne widoku kamery z lusterka - auto const shiftdirection { ( lewe ? -1 : 1 ) * ( iCabn == 2 ? 1 : -1 ) }; + auto const shiftdirection{(lewe ? -1 : 1) * (iCabn == 2 ? 1 : -1)}; - return DynamicObject->mMatrix * - glm::dvec4( - mvOccupied->Dim.W * ( 0.5 * shiftdirection ) + ( 0.2 * shiftdirection ), - 1.5 + Cabine[iCabn].CabPos1.y, - std::lerp( Cabine[ iCabn ].CabPos1.z , Cabine[ iCabn ].CabPos2.z, 0.5 ), 1.0); + return DynamicObject->mMatrix * + glm::dvec4(mvOccupied->Dim.W * (0.5 * shiftdirection) + (0.2 * shiftdirection), 1.5 + Cabine[iCabn].CabPos1.y, interpolate(Cabine[iCabn].CabPos1.z, Cabine[iCabn].CabPos2.z, 0.5), 1.0); }; void TTrain::DynamicSet(TDynamicObject *d) { // taka proteza: chcę podłączyć - // kabinę EN57 bezpośrednio z - // silnikowym, aby nie robić tego - // przez ukrotnienie - // drugi silnikowy i tak musi być ukrotniony, podobnie jak kolejna jednostka - // problem się robi ze światłami, które będą zapalane w silnikowym, ale muszą - // świecić się w rozrządczych - // dla EZT światła czołowe będą "zapalane w silnikowym", ale widziane z - // rozrządczych - // również wczytywanie MMD powinno dotyczyć aktualnego członu - // problematyczna może być kwestia wybranej kabiny (w silnikowym...) - // jeśli silnikowy będzie zapięty odwrotnie (tzn. -1), to i tak powinno - // jeździć dobrze - // również hamowanie wykonuje się zaworem w członie, a nie w silnikowym... - DynamicObject = d; // jedyne miejsce zmiany - mvOccupied = mvControlled = ( d ? DynamicObject->MoverParameters : nullptr ); // albo silnikowy w EZT + // kabinę EN57 bezpośrednio z + // silnikowym, aby nie robić tego + // przez ukrotnienie + // drugi silnikowy i tak musi być ukrotniony, podobnie jak kolejna jednostka + // problem się robi ze światłami, które będą zapalane w silnikowym, ale muszą + // świecić się w rozrządczych + // dla EZT światła czołowe będą "zapalane w silnikowym", ale widziane z + // rozrządczych + // również wczytywanie MMD powinno dotyczyć aktualnego członu + // problematyczna może być kwestia wybranej kabiny (w silnikowym...) + // jeśli silnikowy będzie zapięty odwrotnie (tzn. -1), to i tak powinno + // jeździć dobrze + // również hamowanie wykonuje się zaworem w członie, a nie w silnikowym... + DynamicObject = d; // jedyne miejsce zmiany + mvOccupied = mvControlled = (d ? DynamicObject->MoverParameters : nullptr); // albo silnikowy w EZT - if( DynamicObject == nullptr ) { return; } + if (DynamicObject == nullptr) + { + return; + } - mvControlled = DynamicObject->FindPowered()->MoverParameters; - mvSecond = NULL; // gdyby się nic nie znalazło - if (mvOccupied->Power > 1.0) // dwuczłonowe lub ukrotnienia, żeby nie szukać każdorazowo - if (mvOccupied->Couplers[1].Connected ? - mvOccupied->Couplers[1].AllowedFlag & coupling::control : - false) - { // gdy jest człon od sprzęgu 1, a sprzęg łączony - // warsztatowo (powiedzmy) - if (mvOccupied->Couplers[1].Connected->Power > 1.0) // ten drugi ma moc - mvSecond = - (TMoverParameters *)mvOccupied->Couplers[1].Connected; // wskaźnik na drugiego - } - else if (mvOccupied->Couplers[0].Connected ? - mvOccupied->Couplers[0].AllowedFlag & coupling::control : - false) - { // gdy jest człon od sprzęgu 0, a sprzęg łączony - // warsztatowo (powiedzmy) - if (mvOccupied->Couplers[0].Connected->Power > 1.0) // ale ten drugi ma moc - mvSecond = - (TMoverParameters *)mvOccupied->Couplers[0].Connected; // wskaźnik na drugiego - } - // cache nearest unit equipped with pantographs - { - auto *lookup { DynamicObject->FindPantographCarrier() }; - // HACK: set pointer to existing vehicle to avoid error checking all over the place - mvPantographUnit = ( - lookup != nullptr ? - lookup->MoverParameters : - mvControlled ); - } + mvControlled = DynamicObject->FindPowered()->MoverParameters; + mvSecond = NULL; // gdyby się nic nie znalazło + if (mvOccupied->Power > 1.0) // dwuczłonowe lub ukrotnienia, żeby nie szukać każdorazowo + if (mvOccupied->Couplers[1].Connected ? mvOccupied->Couplers[1].AllowedFlag & coupling::control : false) + { // gdy jest człon od sprzęgu 1, a sprzęg łączony + // warsztatowo (powiedzmy) + if (mvOccupied->Couplers[1].Connected->Power > 1.0) // ten drugi ma moc + mvSecond = (TMoverParameters *)mvOccupied->Couplers[1].Connected; // wskaźnik na drugiego + } + else if (mvOccupied->Couplers[0].Connected ? mvOccupied->Couplers[0].AllowedFlag & coupling::control : false) + { // gdy jest człon od sprzęgu 0, a sprzęg łączony + // warsztatowo (powiedzmy) + if (mvOccupied->Couplers[0].Connected->Power > 1.0) // ale ten drugi ma moc + mvSecond = (TMoverParameters *)mvOccupied->Couplers[0].Connected; // wskaźnik na drugiego + } + // cache nearest unit equipped with pantographs + { + auto *lookup{DynamicObject->FindPantographCarrier()}; + // HACK: set pointer to existing vehicle to avoid error checking all over the place + mvPantographUnit = (lookup != nullptr ? lookup->MoverParameters : mvControlled); + } }; -void -TTrain::MoveToVehicle(TDynamicObject *target) { +void TTrain::MoveToVehicle(TDynamicObject *target) +{ // > Ra: to nie może być tak robione, to zbytnia proteza jest // indeed, too much hacks... // TODO: cleanup TTrain *target_train = simulation::Trains.find(target->name()); - if (target_train) { + if (target_train) + { // let's try to destroy this TTrain and move to already existing one - if (!Dynamic()->Mechanik || !Dynamic()->Mechanik->AIControllFlag) { + if (!Dynamic()->Mechanik || !Dynamic()->Mechanik->AIControllFlag) + { // tylko jeśli ręcznie prowadzony // jeśli prowadzi AI, to mu nie robimy dywersji! Occupied()->CabDeactivisation(); Occupied()->CabOccupied = 0; - Occupied()->BrakeLevelSet(Occupied()->Handle->GetPos(bh_NP)); //rozwala sterowanie hamulcem GF 04-2016 - Occupied()->MainCtrlPos = Occupied()->MainCtrlNoPowerPos(); - Occupied()->ScndCtrlPos = 0; - Dynamic()->MechInside = false; + Occupied()->BrakeLevelSet(Occupied()->Handle->GetPos(bh_NP)); // rozwala sterowanie hamulcem GF 04-2016 + Occupied()->MainCtrlPos = Occupied()->MainCtrlNoPowerPos(); + Occupied()->ScndCtrlPos = 0; + Dynamic()->MechInside = false; Dynamic()->Controller = AIdriver; Dynamic()->bDisplayCab = false; - Dynamic()->ABuSetModelShake( {} ); + Dynamic()->ABuSetModelShake({}); - if( Dynamic()->Mechanik ) - Dynamic()->Mechanik->MoveTo( target ); + if (Dynamic()->Mechanik) + Dynamic()->Mechanik->MoveTo(target); target_train->Occupied()->LimPipePress = target_train->Occupied()->PipePress; - target_train->Occupied()->CabActivisationAuto( true ); // załączenie rozrządu (wirtualne kabiny) + target_train->Occupied()->CabActivisationAuto(true); // załączenie rozrządu (wirtualne kabiny) target_train->Dynamic()->MechInside = true; - if( target_train->Dynamic()->Mechanik ) { - target_train->Dynamic()->Controller = target_train->Dynamic()->Mechanik->AIControllFlag; - target_train->Dynamic()->Mechanik->DirectionChange(); - } - else { - target_train->Dynamic()->Controller = Humandriver; - } - } else { + if (target_train->Dynamic()->Mechanik) + { + target_train->Dynamic()->Controller = target_train->Dynamic()->Mechanik->AIControllFlag; + target_train->Dynamic()->Mechanik->DirectionChange(); + } + else + { + target_train->Dynamic()->Controller = Humandriver; + } + } + else + { target_train->Dynamic()->bDisplayCab = false; - target_train->Dynamic()->ABuSetModelShake( {} ); + target_train->Dynamic()->ABuSetModelShake({}); } - target_train->Dynamic()->ABuSetModelShake( {} ); // zerowanie przesunięcia przed powrotem? + target_train->Dynamic()->ABuSetModelShake({}); // zerowanie przesunięcia przed powrotem? // potentially move player - if (simulation::Train == this) { + if (simulation::Train == this) + { simulation::Train = target_train; - // our local driver may potentially be in external view mode, in which case we shouldn't activate cab visualization - target_train->Dynamic()->bDisplayCab |= !FreeFlyModeFlag; - } + // our local driver may potentially be in external view mode, in which case we shouldn't activate cab visualization + target_train->Dynamic()->bDisplayCab |= !FreeFlyModeFlag; + } // delete this TTrain pending_delete = true; - } else { + } + else + { // move this TTrain to other dynamic // remove TTrain from global list, we're going to change dynamic anyway simulation::Trains.detach(Dynamic()->name()); - if (!Dynamic()->Mechanik || !Dynamic()->Mechanik->AIControllFlag) { + if (!Dynamic()->Mechanik || !Dynamic()->Mechanik->AIControllFlag) + { // tylko jeśli ręcznie prowadzony // jeśli prowadzi AI, to mu nie robimy dywersji! Occupied()->CabDeactivisation(); Occupied()->CabOccupied = 0; - Occupied()->BrakeLevelSet(Occupied()->Handle->GetPos(bh_NP)); //rozwala sterowanie hamulcem GF 04-2016 - Occupied()->MainCtrlPos = Occupied()->MainCtrlNoPowerPos(); - Occupied()->ScndCtrlPos = 0; - Dynamic()->MechInside = false; + Occupied()->BrakeLevelSet(Occupied()->Handle->GetPos(bh_NP)); // rozwala sterowanie hamulcem GF 04-2016 + Occupied()->MainCtrlPos = Occupied()->MainCtrlNoPowerPos(); + Occupied()->ScndCtrlPos = 0; + Dynamic()->MechInside = false; Dynamic()->Controller = AIdriver; Dynamic()->bDisplayCab = false; - Dynamic()->ABuSetModelShake( {} ); + Dynamic()->ABuSetModelShake({}); - if( Dynamic()->Mechanik ) - Dynamic()->Mechanik->MoveTo( target ); + if (Dynamic()->Mechanik) + Dynamic()->Mechanik->MoveTo(target); - DynamicSet( target ); + DynamicSet(target); - Dynamic()->MechInside = true; - if( Dynamic()->Mechanik ) { - Dynamic()->Controller = Dynamic()->Mechanik->AIControllFlag; - Dynamic()->Mechanik->DirectionChange(); - } - else { - Dynamic()->Controller = Humandriver; - } + Dynamic()->MechInside = true; + if (Dynamic()->Mechanik) + { + Dynamic()->Controller = Dynamic()->Mechanik->AIControllFlag; + Dynamic()->Mechanik->DirectionChange(); + } + else + { + Dynamic()->Controller = Humandriver; + } Occupied()->LimPipePress = Occupied()->PipePress; - Occupied()->CabActivisationAuto( true ); // załączenie rozrządu (wirtualne kabiny) - } else { + Occupied()->CabActivisationAuto(true); // załączenie rozrządu (wirtualne kabiny) + } + else + { Dynamic()->bDisplayCab = false; - Dynamic()->ABuSetModelShake( {} ); + Dynamic()->ABuSetModelShake({}); DynamicSet(target); } - { - auto const filename { Occupied()->TypeName + ".mmd" }; - LoadMMediaFile( filename ); - InitializeCab( - Occupied()->CabActive, - filename ); - } + { + auto const filename{Occupied()->TypeName + ".mmd"}; + LoadMMediaFile(filename); + InitializeCab(Occupied()->CabActive, filename); + } - Dynamic()->ABuSetModelShake( {} ); // zerowanie przesunięcia przed powrotem? + Dynamic()->ABuSetModelShake({}); // zerowanie przesunięcia przed powrotem? - if( simulation::Train == this ) { - // our local driver may potentially be in external view mode, in which case we shouldn't activate cab visualization - Dynamic()->bDisplayCab |= !FreeFlyModeFlag; - } + if (simulation::Train == this) + { + // our local driver may potentially be in external view mode, in which case we shouldn't activate cab visualization + Dynamic()->bDisplayCab |= !FreeFlyModeFlag; + } // add it back with updated dynamic name simulation::Trains.insert(this); @@ -9717,686 +11007,597 @@ TTrain::MoveToVehicle(TDynamicObject *target) { bool TTrain::point_inside(glm::dvec3 const Point) const { - return ( Point.x >= Cabine[ iCabn ].CabPos1.x ) && ( Point.x <= Cabine[ iCabn ].CabPos2.x ) - && ( Point.y >= Cabine[ iCabn ].CabPos1.y + 0.5 ) && ( Point.y <= Cabine[ iCabn ].CabPos2.y + 1.8 ) - && ( Point.z >= Cabine[ iCabn ].CabPos1.z ) && ( Point.z <= Cabine[ iCabn ].CabPos2.z ); + return (Point.x >= Cabine[iCabn].CabPos1.x) && (Point.x <= Cabine[iCabn].CabPos2.x) && (Point.y >= Cabine[iCabn].CabPos1.y + 0.5) && (Point.y <= Cabine[iCabn].CabPos2.y + 1.8) && + (Point.z >= Cabine[iCabn].CabPos1.z) && (Point.z <= Cabine[iCabn].CabPos2.z); } glm::dvec3 TTrain::clamp_inside(glm::dvec3 const &Point) const { - if( DebugModeFlag ) { return Point; } + if (DebugModeFlag) + { + return Point; + } - return { - std::clamp( Point.x, (double)Cabine[ iCabn ].CabPos1.x, (double)Cabine[ iCabn ].CabPos2.x ), - std::clamp( Point.y, (double)Cabine[ iCabn ].CabPos1.y + 0.5, (double)Cabine[ iCabn ].CabPos2.y + 1.8 ), - std::clamp( Point.z, (double)Cabine[ iCabn ].CabPos1.z, (double)Cabine[ iCabn ].CabPos2.z ) }; + return {clamp(Point.x, (double)Cabine[iCabn].CabPos1.x, (double)Cabine[iCabn].CabPos2.x), clamp(Point.y, (double)Cabine[iCabn].CabPos1.y + 0.5, (double)Cabine[iCabn].CabPos2.y + 1.8), + clamp(Point.z, (double)Cabine[iCabn].CabPos1.z, (double)Cabine[iCabn].CabPos2.z)}; } -const TTrain::screenentry_sequence& TTrain::get_screens() { +const TTrain::screenentry_sequence &TTrain::get_screens() +{ update_screens(Timer::GetDeltaTime()); return m_screens; } -void -TTrain::radio_message( sound_source *Message, int const Channel ) { +void TTrain::radio_message(sound_source *Message, int const Channel) +{ - auto const soundrange { Message->range() }; - if( ( soundrange > 0 ) - && ( glm::length2( Message->location() - glm::dvec3 { DynamicObject->GetPosition() } ) > sq(soundrange) ) ) { - // skip message playback if the receiver is outside of the emitter's range - return; - } - // NOTE: we initiate playback of all sounds in range, in case the user switches on the radio or tunes to the right channel mid-play - m_radiomessages.emplace_back( - Channel, - std::make_shared( m_radiosound ) ); - // assign sound to the template and play it - auto &message = *( m_radiomessages.back().second.get() ); - auto const radioenabled { ( true == mvOccupied->Radio ) && ( mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable ) }; - auto const volume { - ( true == radioenabled ) - && ( Dynamic()->Mechanik != nullptr ) - && ( Channel == RadioChannel() ) ? - 1.0 : - 0.0 }; - message - .copy_sounds( *Message ) - .gain( volume ) - .play(); + auto const soundrange{Message->range()}; + if ((soundrange > 0) && (glm::length2(Message->location() - glm::dvec3{DynamicObject->GetPosition()}) > sq(soundrange))) + { + // skip message playback if the receiver is outside of the emitter's range + return; + } + // NOTE: we initiate playback of all sounds in range, in case the user switches on the radio or tunes to the right channel mid-play + m_radiomessages.emplace_back(Channel, std::make_shared(m_radiosound)); + // assign sound to the template and play it + auto &message = *(m_radiomessages.back().second.get()); + auto const radioenabled{(true == mvOccupied->Radio) && (mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable)}; + auto const volume{(true == radioenabled) && (Dynamic()->Mechanik != nullptr) && (Channel == RadioChannel()) ? 1.0 : 0.0}; + message.copy_sounds(*Message).gain(volume).play(); } // clears state of all cabin controls void TTrain::clear_cab_controls() { - // indicators exposed to custom control devices - btLampkaSHP.Clear(0); - btLampkaCzuwaka.Clear(1); - btLampkaOpory.Clear(2); - btLampkaWylSzybki.Clear(3); - btLampkaNadmSil.Clear(4); - btLampkaStyczn.Clear(5); - btLampkaPoslizg.Clear(6); - btLampkaNadmPrzetw.Clear(((mvControlled->TrainType & dt_EZT) != 0) ? -1 : 7); // EN57 nie ma tej lampki - btLampkaPrzetwOff.Clear(((mvControlled->TrainType & dt_EZT) != 0) ? 7 : -1 ); // za to ma tę - btLampkaNadmSpr.Clear(8); - btLampkaNadmWent.Clear(9); - btLampkaWysRozr.Clear(((mvControlled->TrainType & dt_ET22) != 0) ? -1 : 10); // ET22 nie ma tej lampki - btLampkaOgrzewanieSkladu.Clear(11); - // overheat indicator lamps - btLampkaOilOverheat.Clear(-1); - btLampkaWaterOverheat.Clear(-1); - btLampkaWaterAuxOverheat.Clear(-1); - btLampkaEngineOverheat.Clear(-1); - btHaslerBrakes.Clear(12); // ciśnienie w cylindrach do odbijania na haslerze - btHaslerCurrent.Clear(13); // prąd na silnikach do odbijania na haslerze - // Numer 14 jest używany dla buczka SHP w update_sounds() - // Jeśli ustawiamy nową wartość dla PoKeys wolna jest 15 + // indicators exposed to custom control devices + btLampkaSHP.Clear(0); + btLampkaCzuwaka.Clear(1); + btLampkaOpory.Clear(2); + btLampkaWylSzybki.Clear(3); + btLampkaNadmSil.Clear(4); + btLampkaStyczn.Clear(5); + btLampkaPoslizg.Clear(6); + btLampkaNadmPrzetw.Clear(((mvControlled->TrainType & dt_EZT) != 0) ? -1 : 7); // EN57 nie ma tej lampki + btLampkaPrzetwOff.Clear(((mvControlled->TrainType & dt_EZT) != 0) ? 7 : -1); // za to ma tę + btLampkaNadmSpr.Clear(8); + btLampkaNadmWent.Clear(9); + btLampkaWysRozr.Clear(((mvControlled->TrainType & dt_ET22) != 0) ? -1 : 10); // ET22 nie ma tej lampki + btLampkaOgrzewanieSkladu.Clear(11); + // overheat indicator lamps + btLampkaOilOverheat.Clear(-1); + btLampkaWaterOverheat.Clear(-1); + btLampkaWaterAuxOverheat.Clear(-1); + btLampkaEngineOverheat.Clear(-1); + btHaslerBrakes.Clear(12); // ciśnienie w cylindrach do odbijania na haslerze + btHaslerCurrent.Clear(13); // prąd na silnikach do odbijania na haslerze + // Numer 14 jest używany dla buczka SHP w update_sounds() + // Jeśli ustawiamy nową wartość dla PoKeys wolna jest 15 - // other cab controls - // TODO: arrange in more readable manner, and eventually refactor - ggJointCtrl.Clear(); - ggMainCtrl.Clear(); - ggMainCtrlAct.Clear(); - ggScndCtrl.Clear(); - ggScndCtrlButton.Clear(); - ggScndCtrlOffButton.Clear(); - ggDistanceCounterButton.Clear(); - ggDirKey.Clear(); - ggDirForwardButton.Clear(); - ggDirNeutralButton.Clear(); - ggDirBackwardButton.Clear(); - ggBrakeCtrl.Clear(); - ggLocalBrake.Clear(); - ggAlarmChain.Clear(); - ggBrakeProfileCtrl.Clear(); - ggBrakeProfileG.Clear(); - ggBrakeProfileR.Clear(); + // other cab controls + // TODO: arrange in more readable manner, and eventually refactor + ggJointCtrl.Clear(); + ggMainCtrl.Clear(); + ggMainCtrlAct.Clear(); + ggScndCtrl.Clear(); + ggScndCtrlButton.Clear(); + ggScndCtrlOffButton.Clear(); + ggDistanceCounterButton.Clear(); + ggDirKey.Clear(); + ggDirForwardButton.Clear(); + ggDirNeutralButton.Clear(); + ggDirBackwardButton.Clear(); + ggBrakeCtrl.Clear(); + ggLocalBrake.Clear(); + ggAlarmChain.Clear(); + ggBrakeProfileCtrl.Clear(); + ggBrakeProfileG.Clear(); + ggBrakeProfileR.Clear(); ggBrakeOperationModeCtrl.Clear(); ggWiperSw.Clear(); - ggMaxCurrentCtrl.Clear(); - ggMainOffButton.Clear(); - ggMainOnButton.Clear(); - ggSecurityResetButton.Clear(); - ggSHPResetButton.Clear(); - ggReleaserButton.Clear(); + ggMaxCurrentCtrl.Clear(); + ggMainOffButton.Clear(); + ggMainOnButton.Clear(); + ggSecurityResetButton.Clear(); + ggSHPResetButton.Clear(); + ggReleaserButton.Clear(); ggSpringBrakeOnButton.Clear(); ggSpringBrakeOffButton.Clear(); ggUniveralBrakeButton1.Clear(); ggUniveralBrakeButton2.Clear(); ggUniveralBrakeButton3.Clear(); - ggEPFuseButton.Clear(); - ggSandButton.Clear(); - ggAutoSandButton.Clear(); - ggAntiSlipButton.Clear(); - ggHornButton.Clear(); - ggHornLowButton.Clear(); - ggHornHighButton.Clear(); - ggWhistleButton.Clear(); + ggEPFuseButton.Clear(); + ggSandButton.Clear(); + ggAutoSandButton.Clear(); + ggAntiSlipButton.Clear(); + ggHornButton.Clear(); + ggHornLowButton.Clear(); + ggHornHighButton.Clear(); + ggWhistleButton.Clear(); ggHelperButton.Clear(); - ggNextCurrentButton.Clear(); + ggNextCurrentButton.Clear(); ggSpeedControlIncreaseButton.Clear(); ggSpeedControlDecreaseButton.Clear(); ggSpeedControlPowerIncreaseButton.Clear(); ggSpeedControlPowerDecreaseButton.Clear(); - for (auto &speedctrlbutton : ggSpeedCtrlButtons) { + for (auto &speedctrlbutton : ggSpeedCtrlButtons) + { speedctrlbutton.Clear(); } - for( auto &universal : ggUniversals ) { - universal.Clear(); - } - for (auto &item : ggInverterEnableButtons) { + for (auto &universal : ggUniversals) + { + universal.Clear(); + } + for (auto &item : ggInverterEnableButtons) + { item.Clear(); } - for (auto &item : ggInverterDisableButtons) { + for (auto &item : ggInverterDisableButtons) + { item.Clear(); } - for (auto &item : ggInverterToggleButtons) { + for (auto &item : ggInverterToggleButtons) + { item.Clear(); } - for( auto &relayresetbutton : ggRelayResetButtons ) { - relayresetbutton.Clear(); - } - ggInstrumentLightButton.Clear(); - ggDashboardLightButton.Clear(); - ggTimetableLightButton.Clear(); - // hunter-091012 - ggCabLightDimButton.Clear(); - ggCompartmentLightsButton.Clear(); - ggCompartmentLightsOnButton.Clear(); - ggCompartmentLightsOffButton.Clear(); - ggBatteryButton.Clear(); - ggBatteryOnButton.Clear(); - ggBatteryOffButton.Clear(); + for (auto &relayresetbutton : ggRelayResetButtons) + { + relayresetbutton.Clear(); + } + ggInstrumentLightButton.Clear(); + ggDashboardLightButton.Clear(); + ggTimetableLightButton.Clear(); + // hunter-091012 + ggCabLightDimButton.Clear(); + ggCompartmentLightsButton.Clear(); + ggCompartmentLightsOnButton.Clear(); + ggCompartmentLightsOffButton.Clear(); + ggBatteryButton.Clear(); + ggBatteryOnButton.Clear(); + ggBatteryOffButton.Clear(); ggCabActivationButton.Clear(); - //------- - ggFuseButton.Clear(); - ggConverterFuseButton.Clear(); - ggStLinOffButton.Clear(); - ggRadioChannelSelector.Clear(); - ggRadioChannelPrevious.Clear(); - ggRadioChannelNext.Clear(); - ggRadioStop.Clear(); - ggRadioTest.Clear(); - ggRadioCall1.Clear(); - ggRadioCall3.Clear(); + //------- + ggFuseButton.Clear(); + ggConverterFuseButton.Clear(); + ggStLinOffButton.Clear(); + ggRadioChannelSelector.Clear(); + ggRadioChannelPrevious.Clear(); + ggRadioChannelNext.Clear(); + ggRadioStop.Clear(); + ggRadioTest.Clear(); + ggRadioCall1.Clear(); + ggRadioCall3.Clear(); ggRadioVolumeSelector.Clear(); ggRadioVolumePrevious.Clear(); ggRadioVolumeNext.Clear(); - ggDoorLeftPermitButton.Clear(); - ggDoorRightPermitButton.Clear(); - ggDoorPermitPresetButton.Clear(); - ggDoorLeftButton.Clear(); - ggDoorRightButton.Clear(); - ggDoorLeftOnButton.Clear(); - ggDoorRightOnButton.Clear(); - ggDoorLeftOffButton.Clear(); - ggDoorRightOffButton.Clear(); - ggDoorAllOnButton.Clear(); - ggDoorAllOffButton.Clear(); - ggTrainHeatingButton.Clear(); - ggSignallingButton.Clear(); - ggDoorSignallingButton.Clear(); - ggDoorStepButton.Clear(); - ggDepartureSignalButton.Clear(); - ggCompressorButton.Clear(); - ggCompressorLocalButton.Clear(); - ggConverterButton.Clear(); - ggConverterOffButton.Clear(); - ggConverterLocalButton.Clear(); - ggMainButton.Clear(); -/* - ggPantFrontButton.Clear(); - ggPantRearButton.Clear(); - ggPantFrontButtonOff.Clear(); - ggPantRearButtonOff.Clear(); -*/ - ggPantAllDownButton.Clear(); - ggPantSelectedButton.Clear(); - ggPantSelectedDownButton.Clear(); - ggPantValvesButton.Clear(); - ggPantCompressorButton.Clear(); - ggPantCompressorValve.Clear(); + ggDoorLeftPermitButton.Clear(); + ggDoorRightPermitButton.Clear(); + ggDoorPermitPresetButton.Clear(); + ggDoorLeftButton.Clear(); + ggDoorRightButton.Clear(); + ggDoorLeftOnButton.Clear(); + ggDoorRightOnButton.Clear(); + ggDoorLeftOffButton.Clear(); + ggDoorRightOffButton.Clear(); + ggDoorAllOnButton.Clear(); + ggDoorAllOffButton.Clear(); + ggTrainHeatingButton.Clear(); + ggSignallingButton.Clear(); + ggDoorSignallingButton.Clear(); + ggDoorStepButton.Clear(); + ggDepartureSignalButton.Clear(); + ggCompressorButton.Clear(); + ggCompressorLocalButton.Clear(); + ggConverterButton.Clear(); + ggConverterOffButton.Clear(); + ggConverterLocalButton.Clear(); + ggMainButton.Clear(); + /* + ggPantFrontButton.Clear(); + ggPantRearButton.Clear(); + ggPantFrontButtonOff.Clear(); + ggPantRearButtonOff.Clear(); + */ + ggPantAllDownButton.Clear(); + ggPantSelectedButton.Clear(); + ggPantSelectedDownButton.Clear(); + ggPantValvesButton.Clear(); + ggPantCompressorButton.Clear(); + ggPantCompressorValve.Clear(); - ggPantValvesOff.Clear(); + ggPantValvesOff.Clear(); ggPantValvesUpdate.Clear(); - ggI1B.Clear(); - ggI2B.Clear(); - ggI3B.Clear(); - ggItotalB.Clear(); - ggOilPressB.Clear(); - ggWater1TempB.Clear(); + ggI1B.Clear(); + ggI2B.Clear(); + ggI3B.Clear(); + ggItotalB.Clear(); + ggOilPressB.Clear(); + ggWater1TempB.Clear(); - ggClockSInd.Clear(); - ggClockMInd.Clear(); - ggClockHInd.Clear(); - ggEngineVoltage.Clear(); - ggLVoltage.Clear(); - ggMainGearStatus.Clear(); - ggIgnitionKey.Clear(); + ggClockSInd.Clear(); + ggClockMInd.Clear(); + ggClockHInd.Clear(); + ggEngineVoltage.Clear(); + ggLVoltage.Clear(); + ggMainGearStatus.Clear(); + ggIgnitionKey.Clear(); - ggWaterPumpBreakerButton.Clear(); - ggWaterPumpButton.Clear(); - ggWaterHeaterBreakerButton.Clear(); - ggWaterHeaterButton.Clear(); - ggWaterCircuitsLinkButton.Clear(); - ggFuelPumpButton.Clear(); - ggOilPumpButton.Clear(); - ggMotorBlowersFrontButton.Clear(); - ggMotorBlowersRearButton.Clear(); - ggMotorBlowersAllOffButton.Clear(); + ggWaterPumpBreakerButton.Clear(); + ggWaterPumpButton.Clear(); + ggWaterHeaterBreakerButton.Clear(); + ggWaterHeaterButton.Clear(); + ggWaterCircuitsLinkButton.Clear(); + ggFuelPumpButton.Clear(); + ggOilPumpButton.Clear(); + ggMotorBlowersFrontButton.Clear(); + ggMotorBlowersRearButton.Clear(); + ggMotorBlowersAllOffButton.Clear(); - btLampkaPrzetw.Clear(); - btLampkaPrzetwB.Clear(); - btLampkaPrzetwBOff.Clear(); - btLampkaPrzekRozn.Clear(); - btLampkaPrzekRoznPom.Clear(); - btLampkaUkrotnienie.Clear(); - btLampkaHamPosp.Clear(); - btLampkaWylSzybkiOff.Clear(); - btLampkaWylSzybkiB.Clear(); - btLampkaWylSzybkiBOff.Clear(); - btLampkaMainBreakerReady.Clear(); - btLampkaMainBreakerBlinkingIfReady.Clear(); - btLampkaBezoporowa.Clear(); - btLampkaBezoporowaB.Clear(); - btLampkaMaxSila.Clear(); - btLampkaPrzekrMaxSila.Clear(); - btLampkaRadio.Clear(); + btLampkaPrzetw.Clear(); + btLampkaPrzetwB.Clear(); + btLampkaPrzetwBOff.Clear(); + btLampkaPrzekRozn.Clear(); + btLampkaPrzekRoznPom.Clear(); + btLampkaUkrotnienie.Clear(); + btLampkaHamPosp.Clear(); + btLampkaWylSzybkiOff.Clear(); + btLampkaWylSzybkiB.Clear(); + btLampkaWylSzybkiBOff.Clear(); + btLampkaMainBreakerReady.Clear(); + btLampkaMainBreakerBlinkingIfReady.Clear(); + btLampkaBezoporowa.Clear(); + btLampkaBezoporowaB.Clear(); + btLampkaMaxSila.Clear(); + btLampkaPrzekrMaxSila.Clear(); + btLampkaRadio.Clear(); btLampkaRadioMessage.Clear(); - btLampkaRadioStop.Clear(); - btLampkaHamulecReczny.Clear(); - btLampkaBlokadaDrzwi.Clear(); - btLampkaDoorLockOff.Clear(); - for( auto &universal : btUniversals ) { - universal.Clear(); - } - btInstrumentLight.Clear(); - btDashboardLight.Clear(); - btTimetableLight.Clear(); - btLampkaWentZaluzje.Clear(); - btLampkaDoorLeft.Clear(); - btLampkaDoorRight.Clear(); - btLampkaDepartureSignal.Clear(); - btLampkaRezerwa.Clear(); - btLampkaBoczniki.Clear(); - btLampkaBocznik1.Clear(); - btLampkaBocznik2.Clear(); - btLampkaBocznik3.Clear(); - btLampkaBocznik4.Clear(); - btLampkaRadiotelefon.Clear(); - btLampkaHamienie.Clear(); - btLampkaBrakingOff.Clear(); - btLampkaED.Clear(); - btLampkaBrakeProfileG.Clear(); - btLampkaBrakeProfileP.Clear(); - btLampkaBrakeProfileR.Clear(); + btLampkaRadioStop.Clear(); + btLampkaHamulecReczny.Clear(); + btLampkaBlokadaDrzwi.Clear(); + btLampkaDoorLockOff.Clear(); + for (auto &universal : btUniversals) + { + universal.Clear(); + } + btInstrumentLight.Clear(); + btDashboardLight.Clear(); + btTimetableLight.Clear(); + btLampkaWentZaluzje.Clear(); + btLampkaDoorLeft.Clear(); + btLampkaDoorRight.Clear(); + btLampkaDepartureSignal.Clear(); + btLampkaRezerwa.Clear(); + btLampkaBoczniki.Clear(); + btLampkaBocznik1.Clear(); + btLampkaBocznik2.Clear(); + btLampkaBocznik3.Clear(); + btLampkaBocznik4.Clear(); + btLampkaRadiotelefon.Clear(); + btLampkaHamienie.Clear(); + btLampkaBrakingOff.Clear(); + btLampkaED.Clear(); + btLampkaBrakeProfileG.Clear(); + btLampkaBrakeProfileP.Clear(); + btLampkaBrakeProfileR.Clear(); btLampkaSpringBrakeActive.Clear(); btLampkaSpringBrakeInactive.Clear(); - btLampkaSprezarka.Clear(); - btLampkaSprezarkaB.Clear(); - btLampkaSprezarkaOff.Clear(); - btLampkaSprezarkaBOff.Clear(); - btLampkaFuelPumpOff.Clear(); - btLampkaNapNastHam.Clear(); - btLampkaOporyB.Clear(); - btLampkaStycznB.Clear(); - btLampkaHamowanie1zes.Clear(); - btLampkaHamowanie2zes.Clear(); - btLampkaNadmPrzetwB.Clear(); - btLampkaHVoltageB.Clear(); - btLampkaForward.Clear(); - btLampkaBackward.Clear(); + btLampkaSprezarka.Clear(); + btLampkaSprezarkaB.Clear(); + btLampkaSprezarkaOff.Clear(); + btLampkaSprezarkaBOff.Clear(); + btLampkaFuelPumpOff.Clear(); + btLampkaNapNastHam.Clear(); + btLampkaOporyB.Clear(); + btLampkaStycznB.Clear(); + btLampkaHamowanie1zes.Clear(); + btLampkaHamowanie2zes.Clear(); + btLampkaNadmPrzetwB.Clear(); + btLampkaHVoltageB.Clear(); + btLampkaForward.Clear(); + btLampkaBackward.Clear(); btLampkaNeutral.Clear(); - // light indicators - btLampkaUpperLight.Clear(); - btLampkaLeftLight.Clear(); - btLampkaRightLight.Clear(); - btLampkaLeftEndLight.Clear(); - btLampkaRightEndLight.Clear(); - btLampkaRearUpperLight.Clear(); - btLampkaRearLeftLight.Clear(); - btLampkaRearRightLight.Clear(); - btLampkaRearLeftEndLight.Clear(); - btLampkaRearRightEndLight.Clear(); - // others - btLampkaMalfunction.Clear(); - btLampkaMalfunctionB.Clear(); - btLampkaMotorBlowers.Clear(); - btLampkaCoolingFans.Clear(); - btLampkaTempomat.Clear(); - btLampkaDistanceCounter.Clear(); + // light indicators + btLampkaUpperLight.Clear(); + btLampkaLeftLight.Clear(); + btLampkaRightLight.Clear(); + btLampkaLeftEndLight.Clear(); + btLampkaRightEndLight.Clear(); + btLampkaRearUpperLight.Clear(); + btLampkaRearLeftLight.Clear(); + btLampkaRearRightLight.Clear(); + btLampkaRearLeftEndLight.Clear(); + btLampkaRearRightEndLight.Clear(); + // others + btLampkaMalfunction.Clear(); + btLampkaMalfunctionB.Clear(); + btLampkaMotorBlowers.Clear(); + btLampkaCoolingFans.Clear(); + btLampkaTempomat.Clear(); + btLampkaDistanceCounter.Clear(); - ggLeftLightButton.Clear(); - ggRightLightButton.Clear(); - ggUpperLightButton.Clear(); - ggDimHeadlightsButton.Clear(); + ggLeftLightButton.Clear(); + ggRightLightButton.Clear(); + ggUpperLightButton.Clear(); + ggDimHeadlightsButton.Clear(); ggModernLightDimSw.Clear(); - ggLeftEndLightButton.Clear(); - ggRightEndLightButton.Clear(); - ggLightsButton.Clear(); - // hunter-230112 - ggRearLeftLightButton.Clear(); - ggRearRightLightButton.Clear(); - ggRearUpperLightButton.Clear(); - ggRearLeftEndLightButton.Clear(); - ggRearRightEndLightButton.Clear(); + ggLeftEndLightButton.Clear(); + ggRightEndLightButton.Clear(); + ggLightsButton.Clear(); + // hunter-230112 + ggRearLeftLightButton.Clear(); + ggRearRightLightButton.Clear(); + ggRearUpperLightButton.Clear(); + ggRearLeftEndLightButton.Clear(); + ggRearRightEndLightButton.Clear(); } // NOTE: we can get rid of this function once we have per-cab persistent state -void TTrain::set_cab_controls( int const Cab ) { - // switches - // battery - ggBatteryButton.PutValue( - ( ggBatteryButton.type() == TGaugeType::push ? 0.5f : - mvOccupied->Power24vIsAvailable ? 1.f : - 0.f ) ); +void TTrain::set_cab_controls(int const Cab) +{ + // switches + // battery + ggBatteryButton.PutValue((ggBatteryButton.type() == TGaugeType::push ? 0.5f : mvOccupied->Power24vIsAvailable ? 1.f : 0.f)); // activation - ggCabActivationButton.PutValue( - (ggCabActivationButton.type() == TGaugeType::push ? 0.5f : - mvOccupied->IsCabMaster() ? 1.f : - 0.f)); - // line breaker - if( ggMainButton.SubModel != nullptr ) { // instead of single main button there can be on/off pair - ggMainButton.PutValue( - ( ggMainButton.type() == TGaugeType::push ? 0.5f : - m_linebreakerstate > 0 ? 1.f : - 0.f ) ); - } + ggCabActivationButton.PutValue((ggCabActivationButton.type() == TGaugeType::push ? 0.5f : mvOccupied->IsCabMaster() ? 1.f : 0.f)); + // line breaker + if (ggMainButton.SubModel != nullptr) + { // instead of single main button there can be on/off pair + ggMainButton.PutValue((ggMainButton.type() == TGaugeType::push ? 0.5f : m_linebreakerstate > 0 ? 1.f : 0.f)); + } - if (ggModernLightDimSw.SubModel != nullptr) { + if (ggModernLightDimSw.SubModel != nullptr) + { mvOccupied->modernDimmerPosition = mvOccupied->modernDimmerDefaultPosition; - ggModernLightDimSw.PutValue(mvOccupied->modernDimmerDefaultPosition); - } + ggModernLightDimSw.PutValue(mvOccupied->modernDimmerDefaultPosition); + } - // Init separate buttons - if (ggPantValvesUpdate.SubModel != nullptr) + // Init separate buttons + if (ggPantValvesUpdate.SubModel != nullptr) { ggPantValvesUpdate.PutValue(0.f); } - if (ggPantValvesOff.SubModel != nullptr) - { + if (ggPantValvesOff.SubModel != nullptr) + { ggPantValvesOff.PutValue(0.f); - } + } - // motor connectors - ggStLinOffButton.PutValue( - ( mvControlled->StLinSwitchOff ? - 1.f : - 0.f ) ); - // radio - ggRadioChannelSelector.PutValue( ( Dynamic()->Mechanik ? Dynamic()->Mechanik->iRadioChannel : 1 ) - 1 ); - // pantographs -/* - if( mvOccupied->PantSwitchType != "impulse" ) { - if( ggPantFrontButton.SubModel ) { - ggPantFrontButton.PutValue( - ( mvControlled->Pantographs[end::front].valve.is_enabled ? - 1.f : - 0.f ) ); - } - if( ggPantFrontButtonOff.SubModel ) { - ggPantFrontButtonOff.PutValue( - ( mvControlled->Pantographs[end::front].valve.is_disabled ? - 1.f : - 0.f ) ); - } - } - if( mvOccupied->PantSwitchType != "impulse" ) { - if( ggPantRearButton.SubModel ) { - ggPantRearButton.PutValue( - ( mvControlled->Pantographs[end::rear].valve.is_enabled ? - 1.f : - 0.f ) ); - } - if( ggPantRearButtonOff.SubModel ) { - ggPantRearButtonOff.PutValue( - ( mvControlled->Pantographs[end::rear].valve.is_disabled ? - 1.f : - 0.f ) ); - } - } -*/ - // front/end pantograph selection is relative to occupied cab - if( ggPantSelectedButton.type() == TGaugeType::toggle ) { - ggPantSelectedButton.PutValue( - ( mvPantographUnit->PantsValve.is_enabled ? - 1.f : - 0.f ) ); - } - else { - if( false == m_controlmapper.contains( "pantselectedoff_sw:" ) ) { - // single impulse switch arrangement, with neutral position mid-way - ggPantSelectedButton.PutValue( 0.5f ); - } - } - if( ggPantSelectedDownButton.type() == TGaugeType::toggle ) { - ggPantSelectedDownButton.PutValue( - ( mvPantographUnit->PantsValve.is_disabled ? - 1.f : - 0.f ) ); - } + // motor connectors + ggStLinOffButton.PutValue((mvControlled->StLinSwitchOff ? 1.f : 0.f)); + // radio + ggRadioChannelSelector.PutValue((Dynamic()->Mechanik ? Dynamic()->Mechanik->iRadioChannel : 1) - 1); + // pantographs + /* + if( mvOccupied->PantSwitchType != "impulse" ) { + if( ggPantFrontButton.SubModel ) { + ggPantFrontButton.PutValue( + ( mvControlled->Pantographs[end::front].valve.is_enabled ? + 1.f : + 0.f ) ); + } + if( ggPantFrontButtonOff.SubModel ) { + ggPantFrontButtonOff.PutValue( + ( mvControlled->Pantographs[end::front].valve.is_disabled ? + 1.f : + 0.f ) ); + } + } + if( mvOccupied->PantSwitchType != "impulse" ) { + if( ggPantRearButton.SubModel ) { + ggPantRearButton.PutValue( + ( mvControlled->Pantographs[end::rear].valve.is_enabled ? + 1.f : + 0.f ) ); + } + if( ggPantRearButtonOff.SubModel ) { + ggPantRearButtonOff.PutValue( + ( mvControlled->Pantographs[end::rear].valve.is_disabled ? + 1.f : + 0.f ) ); + } + } + */ + // front/end pantograph selection is relative to occupied cab + if (ggPantSelectedButton.type() == TGaugeType::toggle) + { + ggPantSelectedButton.PutValue((mvPantographUnit->PantsValve.is_enabled ? 1.f : 0.f)); + } + else + { + if (false == m_controlmapper.contains("pantselectedoff_sw:")) + { + // single impulse switch arrangement, with neutral position mid-way + ggPantSelectedButton.PutValue(0.5f); + } + } + if (ggPantSelectedDownButton.type() == TGaugeType::toggle) + { + ggPantSelectedDownButton.PutValue((mvPantographUnit->PantsValve.is_disabled ? 1.f : 0.f)); + } - ggPantValvesButton.PutValue( 0.5f ); + ggPantValvesButton.PutValue(0.5f); - // auxiliary compressor - ggPantCompressorValve.PutValue( - mvControlled->bPantKurek3 ? - 0.f : // default setting is pantographs connected with primary tank - 1.f ); - ggPantCompressorButton.PutValue( - mvPantographUnit->PantCompFlag ? - 1.f : - 0.f ); - // converter - if( mvOccupied->ConvSwitchType != "impulse" ) { - ggConverterButton.PutValue( - mvControlled->ConverterAllow ? - 1.f : - 0.f ); - } - ggConverterLocalButton.PutValue( - mvControlled->ConverterAllowLocal ? - 1.f : - 0.f ); - // compressor - ggCompressorButton.PutValue( - mvControlled->CompressorAllow ? - 1.f : - 0.f ); - ggCompressorLocalButton.PutValue( - mvControlled->CompressorAllowLocal ? - 1.f : - 0.f ); + // auxiliary compressor + ggPantCompressorValve.PutValue(mvControlled->bPantKurek3 ? 0.f : // default setting is pantographs connected with primary tank + 1.f); + ggPantCompressorButton.PutValue(mvPantographUnit->PantCompFlag ? 1.f : 0.f); + // converter + if (mvOccupied->ConvSwitchType != "impulse") + { + ggConverterButton.PutValue(mvControlled->ConverterAllow ? 1.f : 0.f); + } + ggConverterLocalButton.PutValue(mvControlled->ConverterAllowLocal ? 1.f : 0.f); + // compressor + ggCompressorButton.PutValue(mvControlled->CompressorAllow ? 1.f : 0.f); + ggCompressorLocalButton.PutValue(mvControlled->CompressorAllowLocal ? 1.f : 0.f); ggCompressorListButton.PutValue(mvOccupied->CompressorListPos - 1); - // motor overload relay threshold / shunt mode - ggMaxCurrentCtrl.PutValue( - ( true == mvControlled->ShuntModeAllow ? - ( true == mvControlled->ShuntMode ? - 1.f : - 0.f ) : - ( mvControlled->MotorOverloadRelayHighThreshold ? - 1.f : - 0.f ) ) ); - // lights - ggLightsButton.PutValue( mvOccupied->LightsPos - 1 ); + // motor overload relay threshold / shunt mode + ggMaxCurrentCtrl.PutValue((true == mvControlled->ShuntModeAllow ? (true == mvControlled->ShuntMode ? 1.f : 0.f) : (mvControlled->MotorOverloadRelayHighThreshold ? 1.f : 0.f))); + // lights + ggLightsButton.PutValue(mvOccupied->LightsPos - 1); - auto const vehicleend { cab_to_end( Cab ) }; + auto const vehicleend{cab_to_end(Cab)}; - if( ( mvOccupied->iLights[ vehicleend ] & light::headlight_left ) != 0 ) { - ggLeftLightButton.PutValue( 1.f ); - } - if( ( mvOccupied->iLights[ vehicleend ] & light::headlight_right ) != 0 ) { - ggRightLightButton.PutValue( 1.f ); - } - if( ( mvOccupied->iLights[ vehicleend ] & light::headlight_upper ) != 0 ) { - ggUpperLightButton.PutValue( 1.f ); - } - if( ( mvOccupied->iLights[ vehicleend ] & light::redmarker_left ) != 0 ) { - if( ggLeftEndLightButton.SubModel != nullptr ) { - ggLeftEndLightButton.PutValue( 1.f ); - } - else { - ggLeftLightButton.PutValue( -1.f ); - } - } - if( ( mvOccupied->iLights[ vehicleend ] & light::redmarker_right ) != 0 ) { - if( ggRightEndLightButton.SubModel != nullptr ) { - ggRightEndLightButton.PutValue( 1.f ); - } - else { - ggRightLightButton.PutValue( -1.f ); - } - } - if( 1 == DynamicObject->MoverParameters->modernDimmerPosition ) { + if ((mvOccupied->iLights[vehicleend] & light::headlight_left) != 0) + { + ggLeftLightButton.PutValue(1.f); + } + if ((mvOccupied->iLights[vehicleend] & light::headlight_right) != 0) + { + ggRightLightButton.PutValue(1.f); + } + if ((mvOccupied->iLights[vehicleend] & light::headlight_upper) != 0) + { + ggUpperLightButton.PutValue(1.f); + } + if ((mvOccupied->iLights[vehicleend] & light::redmarker_left) != 0) + { + if (ggLeftEndLightButton.SubModel != nullptr) + { + ggLeftEndLightButton.PutValue(1.f); + } + else + { + ggLeftLightButton.PutValue(-1.f); + } + } + if ((mvOccupied->iLights[vehicleend] & light::redmarker_right) != 0) + { + if (ggRightEndLightButton.SubModel != nullptr) + { + ggRightEndLightButton.PutValue(1.f); + } + else + { + ggRightLightButton.PutValue(-1.f); + } + } + if (1 == DynamicObject->MoverParameters->modernDimmerPosition) + { ggDimHeadlightsButton.PutValue(DynamicObject->MoverParameters->modernDimmerPosition); - } - // cab lights - if( true == Cabine[Cab].bLightDim ) { - ggCabLightDimButton.PutValue( 1.f ); - } - // compartment lights - ggCompartmentLightsButton.PutValue( - ( ggCompartmentLightsButton.type() == TGaugeType::push ? 0.5f : - mvOccupied->CompartmentLights.is_enabled ? 1.f : - 0.f ) ); - // instrument lights - ggInstrumentLightButton.PutValue( ( - InstrumentLightActive ? - 1.f : - 0.f ) ); - ggDashboardLightButton.PutValue( ( - DashboardLightActive ? - 1.f : - 0.f ) ); - ggTimetableLightButton.PutValue( ( - TimetableLightActive ? - 1.f : - 0.f ) ); - // doors permits - if( false == ggDoorLeftPermitButton.is_push() ) { - ggDoorLeftPermitButton.PutValue( mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::left : side::right ) ].open_permit ? 1.f : 0.f ); - } - if( false == ggDoorRightPermitButton.is_push() ) { - ggDoorRightPermitButton.PutValue( mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::right : side::left ) ].open_permit ? 1.f : 0.f ); - } - ggDoorPermitPresetButton.PutValue( mvOccupied->Doors.permit_preset ); - // door controls - ggDoorLeftButton.PutValue( mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::left : side::right ) ].is_closed ? 0.f : 1.f ); - ggDoorRightButton.PutValue( mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::right : side::left ) ].is_closed ? 0.f : 1.f ); - // door lock - ggDoorSignallingButton.PutValue( - mvOccupied->Doors.lock_enabled ? - 1.f : - 0.f ); - // door step - if( false == ggDoorStepButton.is_push() ) { - ggDoorStepButton.PutValue( - mvOccupied->Doors.step_enabled ? - 1.f : - 0.f ); - } - // heating - if( false == ggTrainHeatingButton.is_push() ) { - ggTrainHeatingButton.PutValue( - mvControlled->Heating ? - 1.f : - 0.f ); - } - // brake acting time - if( ggBrakeProfileCtrl.SubModel != nullptr ) { - ggBrakeProfileCtrl.PutValue( - ( ( mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? - 2.f : - mvOccupied->BrakeDelayFlag - 1 ) ); - } - if( ggBrakeProfileG.SubModel != nullptr ) { - ggBrakeProfileG.PutValue( - mvOccupied->BrakeDelayFlag == bdelay_G ? - 1.f : - 0.f ); - } - if( ggBrakeProfileR.SubModel != nullptr ) { - ggBrakeProfileR.PutValue( - ( mvOccupied->BrakeDelayFlag & bdelay_R ) != 0 ? - 1.f : - 0.f ); - } + } + // cab lights + if (true == Cabine[Cab].bLightDim) + { + ggCabLightDimButton.PutValue(1.f); + } + // compartment lights + ggCompartmentLightsButton.PutValue((ggCompartmentLightsButton.type() == TGaugeType::push ? 0.5f : mvOccupied->CompartmentLights.is_enabled ? 1.f : 0.f)); + // instrument lights + ggInstrumentLightButton.PutValue((InstrumentLightActive ? 1.f : 0.f)); + ggDashboardLightButton.PutValue((DashboardLightActive ? 1.f : 0.f)); + ggTimetableLightButton.PutValue((TimetableLightActive ? 1.f : 0.f)); + // doors permits + if (false == ggDoorLeftPermitButton.is_push()) + { + ggDoorLeftPermitButton.PutValue(mvOccupied->Doors.instances[(cab_to_end() == end::front ? side::left : side::right)].open_permit ? 1.f : 0.f); + } + if (false == ggDoorRightPermitButton.is_push()) + { + ggDoorRightPermitButton.PutValue(mvOccupied->Doors.instances[(cab_to_end() == end::front ? side::right : side::left)].open_permit ? 1.f : 0.f); + } + ggDoorPermitPresetButton.PutValue(mvOccupied->Doors.permit_preset); + // door controls + ggDoorLeftButton.PutValue(mvOccupied->Doors.instances[(cab_to_end() == end::front ? side::left : side::right)].is_closed ? 0.f : 1.f); + ggDoorRightButton.PutValue(mvOccupied->Doors.instances[(cab_to_end() == end::front ? side::right : side::left)].is_closed ? 0.f : 1.f); + // door lock + ggDoorSignallingButton.PutValue(mvOccupied->Doors.lock_enabled ? 1.f : 0.f); + // door step + if (false == ggDoorStepButton.is_push()) + { + ggDoorStepButton.PutValue(mvOccupied->Doors.step_enabled ? 1.f : 0.f); + } + // heating + if (false == ggTrainHeatingButton.is_push()) + { + ggTrainHeatingButton.PutValue(mvControlled->Heating ? 1.f : 0.f); + } + // brake acting time + if (ggBrakeProfileCtrl.SubModel != nullptr) + { + ggBrakeProfileCtrl.PutValue(((mvOccupied->BrakeDelayFlag & bdelay_R) != 0 ? 2.f : mvOccupied->BrakeDelayFlag - 1)); + } + if (ggBrakeProfileG.SubModel != nullptr) + { + ggBrakeProfileG.PutValue(mvOccupied->BrakeDelayFlag == bdelay_G ? 1.f : 0.f); + } + if (ggBrakeProfileR.SubModel != nullptr) + { + ggBrakeProfileR.PutValue((mvOccupied->BrakeDelayFlag & bdelay_R) != 0 ? 1.f : 0.f); + } - if (ggWiperSw.SubModel != nullptr) + if (ggWiperSw.SubModel != nullptr) { ggWiperSw.PutValue(mvOccupied->wiperSwitchPos); } - if (ggBrakeOperationModeCtrl.SubModel != nullptr) { - ggBrakeOperationModeCtrl.PutValue( - (mvOccupied->BrakeOpModeFlag > 0 ? - std::log2(mvOccupied->BrakeOpModeFlag) : - 0)); + if (ggBrakeOperationModeCtrl.SubModel != nullptr) + { + ggBrakeOperationModeCtrl.PutValue((mvOccupied->BrakeOpModeFlag > 0 ? std::log2(mvOccupied->BrakeOpModeFlag) : 0)); } - // alarm chain - ggAlarmChain.PutValue( - mvControlled->AlarmChainFlag ? - 1.f : - 0.f ); - // brake signalling - ggSignallingButton.PutValue( - mvControlled->Signalling ? - 1.f : - 0.f ); - // multiple-unit current indicator source - ggNextCurrentButton.PutValue( - ShowNextCurrent ? - 1.f : - 0.f ); - // water pump - ggWaterPumpBreakerButton.PutValue( - mvControlled->WaterPump.breaker ? - 1.f : - 0.f ); - if( ggWaterPumpButton.type() != TGaugeType::push ) { - ggWaterPumpButton.PutValue( - mvControlled->WaterPump.is_enabled ? - 1.f : - 0.f ); - } - // water heater - ggWaterHeaterBreakerButton.PutValue( - mvControlled->WaterHeater.breaker ? - 1.f : - 0.f ); - ggWaterHeaterButton.PutValue( - mvControlled->WaterHeater.is_enabled ? - 1.f : - 0.f ); - ggWaterCircuitsLinkButton.PutValue( - mvControlled->WaterCircuitsLink ? - 1.f : - 0.f ); - // fuel pump - if( ggFuelPumpButton.type() != TGaugeType::push ) { - ggFuelPumpButton.PutValue( - mvControlled->FuelPump.is_enabled ? - 1.f : - 0.f ); - } - // oil pump - if( ggOilPumpButton.type() != TGaugeType::push ) { - ggOilPumpButton.PutValue( - mvControlled->OilPump.is_enabled ? - 1.f : - 0.f ); - } - // traction motor fans - if( ggMotorBlowersFrontButton.type() != TGaugeType::push ) { - ggMotorBlowersFrontButton.PutValue( - mvControlled->MotorBlowers[end::front].is_enabled ? - 1.f : - 0.f ); - } - if( ggMotorBlowersRearButton.type() != TGaugeType::push ) { - ggMotorBlowersRearButton.PutValue( - mvControlled->MotorBlowers[end::rear].is_enabled ? - 1.f : - 0.f ); - } - if( ggMotorBlowersAllOffButton.type() != TGaugeType::push ) { - ggMotorBlowersAllOffButton.PutValue( - ( mvControlled->MotorBlowers[end::front].is_disabled - || mvControlled->MotorBlowers[end::rear].is_disabled ) ? - 1.f : - 0.f ); - } - // second controller - if( ggScndCtrl.is_push() ) { - ggScndCtrl.PutValue( - ggScndCtrl.is_toggle() ? - 0.5f : // pushtoggle is two-way control with neutral position in the middle - 0.f ); // push is on/off control, active while held down, due to legacy use - } - // tempomat - if( false == ggScndCtrlButton.is_push() ) { - ggScndCtrlButton.PutValue( - ( mvControlled->ScndCtrlPos > 0 ) ? - 1.f : - 0.f ); - } - // sandbox - if( ggAutoSandButton.type() != TGaugeType::push ) { - ggAutoSandButton.PutValue( - mvControlled->SandDoseAutoAllow ? - 1.f : - 0.f ); - } - // radio - ggRadioVolumeSelector.PutValue( m_radiovolume ); + // alarm chain + ggAlarmChain.PutValue(mvControlled->AlarmChainFlag ? 1.f : 0.f); + // brake signalling + ggSignallingButton.PutValue(mvControlled->Signalling ? 1.f : 0.f); + // multiple-unit current indicator source + ggNextCurrentButton.PutValue(ShowNextCurrent ? 1.f : 0.f); + // water pump + ggWaterPumpBreakerButton.PutValue(mvControlled->WaterPump.breaker ? 1.f : 0.f); + if (ggWaterPumpButton.type() != TGaugeType::push) + { + ggWaterPumpButton.PutValue(mvControlled->WaterPump.is_enabled ? 1.f : 0.f); + } + // water heater + ggWaterHeaterBreakerButton.PutValue(mvControlled->WaterHeater.breaker ? 1.f : 0.f); + ggWaterHeaterButton.PutValue(mvControlled->WaterHeater.is_enabled ? 1.f : 0.f); + ggWaterCircuitsLinkButton.PutValue(mvControlled->WaterCircuitsLink ? 1.f : 0.f); + // fuel pump + if (ggFuelPumpButton.type() != TGaugeType::push) + { + ggFuelPumpButton.PutValue(mvControlled->FuelPump.is_enabled ? 1.f : 0.f); + } + // oil pump + if (ggOilPumpButton.type() != TGaugeType::push) + { + ggOilPumpButton.PutValue(mvControlled->OilPump.is_enabled ? 1.f : 0.f); + } + // traction motor fans + if (ggMotorBlowersFrontButton.type() != TGaugeType::push) + { + ggMotorBlowersFrontButton.PutValue(mvControlled->MotorBlowers[end::front].is_enabled ? 1.f : 0.f); + } + if (ggMotorBlowersRearButton.type() != TGaugeType::push) + { + ggMotorBlowersRearButton.PutValue(mvControlled->MotorBlowers[end::rear].is_enabled ? 1.f : 0.f); + } + if (ggMotorBlowersAllOffButton.type() != TGaugeType::push) + { + ggMotorBlowersAllOffButton.PutValue((mvControlled->MotorBlowers[end::front].is_disabled || mvControlled->MotorBlowers[end::rear].is_disabled) ? 1.f : 0.f); + } + // second controller + if (ggScndCtrl.is_push()) + { + ggScndCtrl.PutValue(ggScndCtrl.is_toggle() ? 0.5f : // pushtoggle is two-way control with neutral position in the middle + 0.f); // push is on/off control, active while held down, due to legacy use + } + // tempomat + if (false == ggScndCtrlButton.is_push()) + { + ggScndCtrlButton.PutValue((mvControlled->ScndCtrlPos > 0) ? 1.f : 0.f); + } + // sandbox + if (ggAutoSandButton.type() != TGaugeType::push) + { + ggAutoSandButton.PutValue(mvControlled->SandDoseAutoAllow ? 1.f : 0.f); + } + // radio + ggRadioVolumeSelector.PutValue(m_radiovolume); - //finding each inverter - not so optimal, but action ins performed only during changing cabin + // finding each inverter - not so optimal, but action ins performed only during changing cabin bool kier = (DynamicObject->DirectionGet() * mvOccupied->CabOccupied > 0); int flag = DynamicObject->MoverParameters->InverterControlCouplerFlag; int itemstart = 0; - for (auto &item : ggInverterToggleButtons) //for each button + for (auto &item : ggInverterToggleButtons) // for each button { int itemindex = itemstart; itemstart++; @@ -10408,601 +11609,613 @@ void TTrain::set_cab_controls( int const Cab ) { if (itemindex < p->MoverParameters->InvertersNo) { // visual feedback - ggInverterToggleButtons[itemstart-1].PutValue(p->MoverParameters->Inverters[itemindex].Activate ? 1.0 : 0.0); + ggInverterToggleButtons[itemstart - 1].PutValue(p->MoverParameters->Inverters[itemindex].Activate ? 1.0 : 0.0); break; } else { itemindex -= p->MoverParameters->InvertersNo; } - } p = (kier ? p->Next(flag) : p->Prev(flag)); } } - // we reset all indicators, as they're set during the update pass - // TODO: when cleaning up break setting indicator state into a separate function, so we can reuse it + // we reset all indicators, as they're set during the update pass + // TODO: when cleaning up break setting indicator state into a separate function, so we can reuse it } // initializes a button matching provided label. returns: true if the label was found, false otherwise // TODO: refactor the cabin controls into some sensible structure -bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int const Cabindex) { +bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int const Cabindex) +{ - std::unordered_map const lights = { - { "i-maxft:", btLampkaMaxSila }, - { "i-maxftt:", btLampkaPrzekrMaxSila }, - { "i-radio:", btLampkaRadio }, - { "i-radiomessage:", btLampkaRadioMessage }, - { "i-radiostop:", btLampkaRadioStop }, - { "i-manual_brake:", btLampkaHamulecReczny }, - { "i-door_blocked:", btLampkaBlokadaDrzwi }, - { "i-door_blockedoff:", btLampkaDoorLockOff }, - { "i-slippery:", btLampkaPoslizg }, - { "i-contactors:", btLampkaStyczn }, - { "i-conv_ovld:", btLampkaNadmPrzetw }, - { "i-converter:", btLampkaPrzetw }, - { "i-converteroff:", btLampkaPrzetwOff }, - { "i-converterb:", btLampkaPrzetwB }, - { "i-converterboff:", btLampkaPrzetwBOff }, - { "i-diff_relay:", btLampkaPrzekRozn }, - { "i-diff_relay2:", btLampkaPrzekRoznPom }, - { "i-motor_ovld:", btLampkaNadmSil }, - { "i-train_controll:", btLampkaUkrotnienie }, - { "i-brake_delay_r:", btLampkaHamPosp }, - { "i-mainbreaker:", btLampkaWylSzybki }, - { "i-mainbreakerb:", btLampkaWylSzybkiB }, - { "i-mainbreakeroff:", btLampkaWylSzybkiOff }, - { "i-mainbreakerboff:", btLampkaWylSzybkiBOff }, - { "i-mainbreakerready:", btLampkaMainBreakerReady }, - { "i-mainbreakerblinking:", btLampkaMainBreakerBlinkingIfReady }, - { "i-vent_ovld:", btLampkaNadmWent }, - { "i-comp_ovld:", btLampkaNadmSpr }, - // overheat indicator lamps - { "i-oil_overheat:", btLampkaOilOverheat }, - { "i-water_overheat:", btLampkaWaterOverheat }, - { "i-wateraux_overheat:", btLampkaWaterAuxOverheat }, - { "i-engine_overheat:", btLampkaEngineOverheat }, - { "i-resistors:", btLampkaOpory }, - { "i-no_resistors:", btLampkaBezoporowa }, - { "i-no_resistors_b:", btLampkaBezoporowaB }, - { "i-highcurrent:", btLampkaWysRozr }, - { "i-vent_trim:", btLampkaWentZaluzje }, - { "i-motorblowers:", btLampkaMotorBlowers }, - { "i-coolingfans:", btLampkaCoolingFans }, - { "i-tempomat:", btLampkaTempomat }, - { "i-distancecounter:", btLampkaDistanceCounter }, - { "i-trainheating:", btLampkaOgrzewanieSkladu }, - { "i-security_aware:", btLampkaCzuwaka }, - { "i-security_cabsignal:", btLampkaSHP }, - { "i-security_aware_cabsignal:", btLampkaCzuwakaSHP }, - { "i-door_left:", btLampkaDoorLeft }, - { "i-door_right:", btLampkaDoorRight }, - { "i-departure_signal:", btLampkaDepartureSignal }, - { "i-reserve:", btLampkaRezerwa }, - { "i-scnd:", btLampkaBoczniki }, - { "i-scnd1:", btLampkaBocznik1 }, - { "i-scnd2:", btLampkaBocznik2 }, - { "i-scnd3:", btLampkaBocznik3 }, - { "i-scnd4:", btLampkaBocznik4 }, - { "i-braking:", btLampkaHamienie }, - { "i-brakingoff:", btLampkaBrakingOff }, - { "i-dynamicbrake:", btLampkaED }, - { "i-brakeprofileg:", btLampkaBrakeProfileG }, - { "i-brakeprofilep:", btLampkaBrakeProfileP }, - { "i-brakeprofiler:", btLampkaBrakeProfileR }, - { "i-springbrakeactive:", btLampkaSpringBrakeActive }, - { "i-springbrakeinactive:", btLampkaSpringBrakeInactive }, - { "i-braking-ezt:", btLampkaHamowanie1zes }, - { "i-braking-ezt2:", btLampkaHamowanie2zes }, - { "i-compressor:", btLampkaSprezarka }, - { "i-compressorb:", btLampkaSprezarkaB }, - { "i-compressoroff:", btLampkaSprezarkaOff }, - { "i-compressorboff:", btLampkaSprezarkaBOff }, - { "i-fuelpumpoff:", btLampkaFuelPumpOff }, - { "i-voltbrake:", btLampkaNapNastHam }, - { "i-resistorsb:", btLampkaOporyB }, - { "i-contactorsb:", btLampkaStycznB }, - { "i-conv_ovldb:", btLampkaNadmPrzetwB }, - { "i-hvoltageb:", btLampkaHVoltageB }, - { "i-malfunction:", btLampkaMalfunction }, - { "i-malfunctionb:", btLampkaMalfunctionB }, - { "i-forward:", btLampkaForward }, - { "i-backward:", btLampkaBackward }, - { "i-neutral:", btLampkaNeutral }, - { "i-upperlight:", btLampkaUpperLight }, - { "i-leftlight:", btLampkaLeftLight }, - { "i-rightlight:", btLampkaRightLight }, - { "i-leftend:", btLampkaLeftEndLight }, - { "i-rightend:", btLampkaRightEndLight }, - { "i-rearupperlight:", btLampkaRearUpperLight }, - { "i-rearleftlight:", btLampkaRearLeftLight }, - { "i-rearrightlight:", btLampkaRearRightLight }, - { "i-rearleftend:", btLampkaRearLeftEndLight }, - { "i-rearrightend:", btLampkaRearRightEndLight }, - { "i-dashboardlight:", btDashboardLight }, - { "i-timetablelight:", btTimetableLight }, - { "i-universal0:", btUniversals[ 0 ] }, - { "i-universal1:", btUniversals[ 1 ] }, - { "i-universal2:", btUniversals[ 2 ] }, - { "i-universal3:", btUniversals[ 3 ] }, - { "i-universal4:", btUniversals[ 4 ] }, - { "i-universal5:", btUniversals[ 5 ] }, - { "i-universal6:", btUniversals[ 6 ] }, - { "i-universal7:", btUniversals[ 7 ] }, - { "i-universal8:", btUniversals[ 8 ] }, - { "i-universal9:", btUniversals[ 9 ] }, - { "i-cabactived:", btCabActived }, - {"i-aklvents:", btAKLVents}, - {"i-compressorany:", btCompressors }, - {"i-edenabled", btEDenabled }, - }; - { - auto lookup = lights.find( Label ); - if( lookup != lights.end() ) { - lookup->second.Load( Parser, DynamicObject ); - return true; - } - } - // TODO: move viable dedicated lights to the automatic light array - std::unordered_map const autolights = { - { "i-doors:", &m_doors }, - { "i-doorpermit_left:", &m_doorspermitleft }, - { "i-doorpermit_right:", &m_doorspermitright }, - { "i-doorpermit_any:", &m_doorpermits }, - { "i-doorstep:", &mvOccupied->Doors.step_enabled }, - { "i-mainpipelock:", &mvOccupied->LockPipe }, - { "i-battery:", &mvOccupied->Power24vIsAvailable }, - { "i-cablight:", &Cabine[ iCabn ].bLight }, - }; - { - auto lookup = autolights.find( Label ); - if( lookup != autolights.end() ) { - auto &button = Cabine[ Cabindex ].Button( -1 ); // pierwsza wolna lampka - button.Load( Parser, DynamicObject ); - button.AssignBool( lookup->second ); - return true; - } - } - // custom lights - if( Label == "i-instrumentlight:" ) { - btInstrumentLight.Load( Parser, DynamicObject ); - InstrumentLightType = 0; - } - else if( Label == "i-instrumentlight_m:" ) { - btInstrumentLight.Load( Parser, DynamicObject ); - InstrumentLightType = 1; - } - else if( Label == "i-instrumentlight_c:" ) { - btInstrumentLight.Load( Parser, DynamicObject ); - InstrumentLightType = 2; - } - else if( Label == "i-instrumentlight_a:" ) { - btInstrumentLight.Load( Parser, DynamicObject ); - InstrumentLightType = 3; - } - else if( Label == "i-instrumentlight_l:" ) { - btInstrumentLight.Load( Parser, DynamicObject ); - InstrumentLightType = 4; - } - else if (Label == "i-doors:") - { - int i = Parser.getToken() - 1; - auto &button = Cabine[Cabindex].Button(-1); // pierwsza wolna lampka - button.Load(Parser, DynamicObject); - button.AssignBool(bDoors[0] + 3 * i); - } - else - { - // failed to match the label - return false; - } + std::unordered_map const lights = { + {"i-maxft:", btLampkaMaxSila}, + {"i-maxftt:", btLampkaPrzekrMaxSila}, + {"i-radio:", btLampkaRadio}, + {"i-radiomessage:", btLampkaRadioMessage}, + {"i-radiostop:", btLampkaRadioStop}, + {"i-manual_brake:", btLampkaHamulecReczny}, + {"i-door_blocked:", btLampkaBlokadaDrzwi}, + {"i-door_blockedoff:", btLampkaDoorLockOff}, + {"i-slippery:", btLampkaPoslizg}, + {"i-contactors:", btLampkaStyczn}, + {"i-conv_ovld:", btLampkaNadmPrzetw}, + {"i-converter:", btLampkaPrzetw}, + {"i-converteroff:", btLampkaPrzetwOff}, + {"i-converterb:", btLampkaPrzetwB}, + {"i-converterboff:", btLampkaPrzetwBOff}, + {"i-diff_relay:", btLampkaPrzekRozn}, + {"i-diff_relay2:", btLampkaPrzekRoznPom}, + {"i-motor_ovld:", btLampkaNadmSil}, + {"i-train_controll:", btLampkaUkrotnienie}, + {"i-brake_delay_r:", btLampkaHamPosp}, + {"i-mainbreaker:", btLampkaWylSzybki}, + {"i-mainbreakerb:", btLampkaWylSzybkiB}, + {"i-mainbreakeroff:", btLampkaWylSzybkiOff}, + {"i-mainbreakerboff:", btLampkaWylSzybkiBOff}, + {"i-mainbreakerready:", btLampkaMainBreakerReady}, + {"i-mainbreakerblinking:", btLampkaMainBreakerBlinkingIfReady}, + {"i-vent_ovld:", btLampkaNadmWent}, + {"i-comp_ovld:", btLampkaNadmSpr}, + // overheat indicator lamps + {"i-oil_overheat:", btLampkaOilOverheat}, + {"i-water_overheat:", btLampkaWaterOverheat}, + {"i-wateraux_overheat:", btLampkaWaterAuxOverheat}, + {"i-engine_overheat:", btLampkaEngineOverheat}, + {"i-resistors:", btLampkaOpory}, + {"i-no_resistors:", btLampkaBezoporowa}, + {"i-no_resistors_b:", btLampkaBezoporowaB}, + {"i-highcurrent:", btLampkaWysRozr}, + {"i-vent_trim:", btLampkaWentZaluzje}, + {"i-motorblowers:", btLampkaMotorBlowers}, + {"i-coolingfans:", btLampkaCoolingFans}, + {"i-tempomat:", btLampkaTempomat}, + {"i-distancecounter:", btLampkaDistanceCounter}, + {"i-trainheating:", btLampkaOgrzewanieSkladu}, + {"i-security_aware:", btLampkaCzuwaka}, + {"i-security_cabsignal:", btLampkaSHP}, + {"i-security_aware_cabsignal:", btLampkaCzuwakaSHP}, + {"i-door_left:", btLampkaDoorLeft}, + {"i-door_right:", btLampkaDoorRight}, + {"i-departure_signal:", btLampkaDepartureSignal}, + {"i-reserve:", btLampkaRezerwa}, + {"i-scnd:", btLampkaBoczniki}, + {"i-scnd1:", btLampkaBocznik1}, + {"i-scnd2:", btLampkaBocznik2}, + {"i-scnd3:", btLampkaBocznik3}, + {"i-scnd4:", btLampkaBocznik4}, + {"i-braking:", btLampkaHamienie}, + {"i-brakingoff:", btLampkaBrakingOff}, + {"i-dynamicbrake:", btLampkaED}, + {"i-brakeprofileg:", btLampkaBrakeProfileG}, + {"i-brakeprofilep:", btLampkaBrakeProfileP}, + {"i-brakeprofiler:", btLampkaBrakeProfileR}, + {"i-springbrakeactive:", btLampkaSpringBrakeActive}, + {"i-springbrakeinactive:", btLampkaSpringBrakeInactive}, + {"i-braking-ezt:", btLampkaHamowanie1zes}, + {"i-braking-ezt2:", btLampkaHamowanie2zes}, + {"i-compressor:", btLampkaSprezarka}, + {"i-compressorb:", btLampkaSprezarkaB}, + {"i-compressoroff:", btLampkaSprezarkaOff}, + {"i-compressorboff:", btLampkaSprezarkaBOff}, + {"i-fuelpumpoff:", btLampkaFuelPumpOff}, + {"i-voltbrake:", btLampkaNapNastHam}, + {"i-resistorsb:", btLampkaOporyB}, + {"i-contactorsb:", btLampkaStycznB}, + {"i-conv_ovldb:", btLampkaNadmPrzetwB}, + {"i-hvoltageb:", btLampkaHVoltageB}, + {"i-malfunction:", btLampkaMalfunction}, + {"i-malfunctionb:", btLampkaMalfunctionB}, + {"i-forward:", btLampkaForward}, + {"i-backward:", btLampkaBackward}, + {"i-neutral:", btLampkaNeutral}, + {"i-upperlight:", btLampkaUpperLight}, + {"i-leftlight:", btLampkaLeftLight}, + {"i-rightlight:", btLampkaRightLight}, + {"i-leftend:", btLampkaLeftEndLight}, + {"i-rightend:", btLampkaRightEndLight}, + {"i-rearupperlight:", btLampkaRearUpperLight}, + {"i-rearleftlight:", btLampkaRearLeftLight}, + {"i-rearrightlight:", btLampkaRearRightLight}, + {"i-rearleftend:", btLampkaRearLeftEndLight}, + {"i-rearrightend:", btLampkaRearRightEndLight}, + {"i-dashboardlight:", btDashboardLight}, + {"i-timetablelight:", btTimetableLight}, + {"i-universal0:", btUniversals[0]}, + {"i-universal1:", btUniversals[1]}, + {"i-universal2:", btUniversals[2]}, + {"i-universal3:", btUniversals[3]}, + {"i-universal4:", btUniversals[4]}, + {"i-universal5:", btUniversals[5]}, + {"i-universal6:", btUniversals[6]}, + {"i-universal7:", btUniversals[7]}, + {"i-universal8:", btUniversals[8]}, + {"i-universal9:", btUniversals[9]}, + {"i-cabactived:", btCabActived}, + {"i-aklvents:", btAKLVents}, + {"i-compressorany:", btCompressors}, + {"i-edenabled", btEDenabled}, + }; + { + auto lookup = lights.find(Label); + if (lookup != lights.end()) + { + lookup->second.Load(Parser, DynamicObject); + return true; + } + } + // TODO: move viable dedicated lights to the automatic light array + std::unordered_map const autolights = { + {"i-doors:", &m_doors}, + {"i-doorpermit_left:", &m_doorspermitleft}, + {"i-doorpermit_right:", &m_doorspermitright}, + {"i-doorpermit_any:", &m_doorpermits}, + {"i-doorstep:", &mvOccupied->Doors.step_enabled}, + {"i-mainpipelock:", &mvOccupied->LockPipe}, + {"i-battery:", &mvOccupied->Power24vIsAvailable}, + {"i-cablight:", &Cabine[iCabn].bLight}, + }; + { + auto lookup = autolights.find(Label); + if (lookup != autolights.end()) + { + auto &button = Cabine[Cabindex].Button(-1); // pierwsza wolna lampka + button.Load(Parser, DynamicObject); + button.AssignBool(lookup->second); + return true; + } + } + // custom lights + if (Label == "i-instrumentlight:") + { + btInstrumentLight.Load(Parser, DynamicObject); + InstrumentLightType = 0; + } + else if (Label == "i-instrumentlight_m:") + { + btInstrumentLight.Load(Parser, DynamicObject); + InstrumentLightType = 1; + } + else if (Label == "i-instrumentlight_c:") + { + btInstrumentLight.Load(Parser, DynamicObject); + InstrumentLightType = 2; + } + else if (Label == "i-instrumentlight_a:") + { + btInstrumentLight.Load(Parser, DynamicObject); + InstrumentLightType = 3; + } + else if (Label == "i-instrumentlight_l:") + { + btInstrumentLight.Load(Parser, DynamicObject); + InstrumentLightType = 4; + } + else if (Label == "i-doors:") + { + int i = Parser.getToken() - 1; + auto &button = Cabine[Cabindex].Button(-1); // pierwsza wolna lampka + button.Load(Parser, DynamicObject); + button.AssignBool(bDoors[0] + 3 * i); + } + else + { + // failed to match the label + return false; + } - return true; + return true; } // initializes a gauge matching provided label. returns: true if the label was found, false otherwise // TODO: refactor the cabin controls into some sensible structure -bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int const Cabindex) { +bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int const Cabindex) +{ - std::unordered_map const gauges = { - { "jointctrl:", ggJointCtrl }, - { "mainctrl:", ggMainCtrl }, - { "scndctrl:", ggScndCtrl }, - { "dirkey:" , ggDirKey }, - { "brakectrl:", ggBrakeCtrl }, - { "localbrake:", ggLocalBrake }, - { "alarmchain:", ggAlarmChain }, - { "brakeprofile_sw:", ggBrakeProfileCtrl }, - { "brakeprofileg_sw:", ggBrakeProfileG }, - { "brakeprofiler_sw:", ggBrakeProfileR }, - { "brakeopmode_sw:", ggBrakeOperationModeCtrl }, - { "maxcurrent_sw:", ggMaxCurrentCtrl }, - { "main_off_bt:", ggMainOffButton }, - { "main_on_bt:", ggMainOnButton }, - { "security_reset_bt:", ggSecurityResetButton }, - { "shp_reset_bt:", ggSHPResetButton }, - { "releaser_bt:", ggReleaserButton }, - { "springbrakeon_bt:", ggSpringBrakeOnButton }, - { "springbrakeoff_bt:", ggSpringBrakeOffButton }, - { "universalbrake1_bt:", ggUniveralBrakeButton1 }, - { "universalbrake2_bt:", ggUniveralBrakeButton2 }, - { "universalbrake3_bt:", ggUniveralBrakeButton3 }, - { "epbrake_bt:", ggEPFuseButton }, - { "sand_bt:", ggSandButton }, - { "autosandallow_sw:", ggAutoSandButton }, - { "antislip_bt:", ggAntiSlipButton }, - { "horn_bt:", ggHornButton }, - { "hornlow_bt:", ggHornLowButton }, - { "hornhigh_bt:", ggHornHighButton }, - { "whistle_bt:", ggWhistleButton }, - { "helper_bt:", ggHelperButton }, - { "fuse_bt:", ggFuseButton }, - { "converterfuse_bt:", ggConverterFuseButton }, - { "stlinoff_bt:", ggStLinOffButton }, - { "doorpermitpreset_sw:", ggDoorPermitPresetButton }, - { "door_left_sw:", ggDoorLeftButton }, - { "door_right_sw:", ggDoorRightButton }, - { "doorlefton_sw:", ggDoorLeftOnButton }, - { "doorrighton_sw:", ggDoorRightOnButton }, - { "doorleftoff_sw:", ggDoorLeftOffButton }, - { "doorrightoff_sw:", ggDoorRightOffButton }, - { "doorallon_sw:", ggDoorAllOnButton }, - { "departure_signal_bt:", ggDepartureSignalButton }, - { "upperlight_sw:", ggUpperLightButton }, - { "leftlight_sw:", ggLeftLightButton }, - { "rightlight_sw:", ggRightLightButton }, - { "dimheadlights_sw:", ggDimHeadlightsButton }, - { "leftend_sw:", ggLeftEndLightButton }, - { "rightend_sw:", ggRightEndLightButton }, - { "lights_sw:", ggLightsButton }, - { "moderndimmer_sw:", ggModernLightDimSw }, - { "rearupperlight_sw:", ggRearUpperLightButton }, - { "rearleftlight_sw:", ggRearLeftLightButton }, - { "rearrightlight_sw:", ggRearRightLightButton }, - { "rearleftend_sw:", ggRearLeftEndLightButton }, - { "rearrightend_sw:", ggRearRightEndLightButton }, - { "compressor_sw:", ggCompressorButton }, - { "compressorlocal_sw:", ggCompressorLocalButton }, - { "compressorlist_sw:", ggCompressorListButton }, - { "converter_sw:", ggConverterButton }, - { "converterlocal_sw:", ggConverterLocalButton }, - { "converteroff_sw:", ggConverterOffButton }, - { "main_sw:", ggMainButton }, - { "waterpumpbreaker_sw:", ggWaterPumpBreakerButton }, - { "waterpump_sw:", ggWaterPumpButton }, - { "waterheaterbreaker_sw:", ggWaterHeaterBreakerButton }, - { "waterheater_sw:", ggWaterHeaterButton }, - { "water1tempb:", ggWater1TempB }, - { "watercircuitslink_sw:", ggWaterCircuitsLinkButton }, - { "fuelpump_sw:", ggFuelPumpButton }, - { "oilpump_sw:", ggOilPumpButton }, - { "oilpressb:", ggOilPressB }, - { "motorblowersfront_sw:", ggMotorBlowersFrontButton }, - { "motorblowersrear_sw:", ggMotorBlowersRearButton }, - { "motorblowersalloff_sw:", ggMotorBlowersAllOffButton }, - { "radiochannel_sw:", ggRadioChannelSelector }, - { "radiochannelprev_sw:", ggRadioChannelPrevious }, - { "radiochannelnext_sw:", ggRadioChannelNext }, - { "radiostop_sw:", ggRadioStop }, - { "radiotest_sw:", ggRadioTest }, - { "radiocall1_sw:", ggRadioCall1 }, - { "radiocall3_sw:", ggRadioCall3 }, - { "radiovolume_sw:", ggRadioVolumeSelector }, - { "radiovolumeprev_sw:", ggRadioVolumePrevious }, - { "radiovolumenext_sw:", ggRadioVolumeNext }, -/* - { "pantfront_sw:", ggPantFrontButton }, - { "pantrear_sw:", ggPantRearButton }, - { "pantfrontoff_sw:", ggPantFrontButtonOff }, - { "pantrearoff_sw:", ggPantRearButtonOff }, -*/ - { "pantalloff_sw:", ggPantAllDownButton }, - { "pantselected_sw:", ggPantSelectedButton }, - { "pantselectedoff_sw:", ggPantSelectedDownButton }, - { "pantvalves_sw:", ggPantValvesButton }, - { "pantcompressor_sw:", ggPantCompressorButton }, - { "pantcompressorvalve_sw:", ggPantCompressorValve }, - { "trainheating_sw:", ggTrainHeatingButton }, - { "signalling_sw:", ggSignallingButton }, - { "door_signalling_sw:", ggDoorSignallingButton }, - { "nextcurrent_sw:", ggNextCurrentButton }, - { "instrumentlight_sw:", ggInstrumentLightButton }, - { "dashboardlight_sw:", ggDashboardLightButton }, - { "timetablelight_sw:", ggTimetableLightButton }, - { "cablightdim_sw:", ggCabLightDimButton }, - { "compartmentlights_sw:", ggCompartmentLightsButton }, - { "compartmentlightson_sw:", ggCompartmentLightsOnButton }, - { "compartmentlightsoff_sw:", ggCompartmentLightsOffButton }, - { "battery_sw:", ggBatteryButton }, - { "batteryon_sw:", ggBatteryOnButton }, - { "batteryoff_sw:", ggBatteryOffButton }, - { "cabactivation_sw:", ggCabActivationButton }, - { "distancecounter_sw:", ggDistanceCounterButton }, - { "relayreset1_bt:", ggRelayResetButtons[ 0 ] }, - { "relayreset2_bt:", ggRelayResetButtons[ 1 ] }, - { "relayreset3_bt:", ggRelayResetButtons[ 2 ] }, - {"universal0:", ggUniversals[0]}, - {"universal1:", ggUniversals[1]}, - {"universal2:", ggUniversals[2]}, - {"universal3:", ggUniversals[3]}, - {"universal4:", ggUniversals[4]}, - {"universal5:", ggUniversals[5]}, - {"universal6:", ggUniversals[6]}, - {"universal7:", ggUniversals[7]}, - {"universal8:", ggUniversals[8]}, - {"universal9:", ggUniversals[9]}, - {"universal10:", ggUniversals[10]}, - {"universal11:", ggUniversals[11]}, - {"universal12:", ggUniversals[12]}, - {"universal13:", ggUniversals[13]}, - {"universal14:", ggUniversals[14]}, - {"universal15:", ggUniversals[15]}, - {"universal16:", ggUniversals[16]}, - {"universal17:", ggUniversals[17]}, - {"universal18:", ggUniversals[18]}, - {"universal19:", ggUniversals[19]}, - {"universal20:", ggUniversals[20]}, - {"universal21:", ggUniversals[21]}, - {"universal22:", ggUniversals[22]}, - {"universal23:", ggUniversals[23]}, - {"universal24:", ggUniversals[24]}, - {"universal25:", ggUniversals[25]}, - {"universal26:", ggUniversals[26]}, - {"universal27:", ggUniversals[27]}, - {"universal28:", ggUniversals[28]}, - {"universal29:", ggUniversals[29]}, - { "inverterenable1_bt:", ggInverterEnableButtons[0] }, - { "inverterenable2_bt:", ggInverterEnableButtons[1] }, - { "inverterenable3_bt:", ggInverterEnableButtons[2] }, - { "inverterenable4_bt:", ggInverterEnableButtons[3] }, - { "inverterenable5_bt:", ggInverterEnableButtons[4] }, - { "inverterenable6_bt:", ggInverterEnableButtons[5] }, - { "inverterenable7_bt:", ggInverterEnableButtons[6] }, - { "inverterenable8_bt:", ggInverterEnableButtons[7] }, - { "inverterenable9_bt:", ggInverterEnableButtons[8] }, - { "inverterenable10_bt:", ggInverterEnableButtons[9] }, - { "inverterenable11_bt:", ggInverterEnableButtons[10] }, - { "inverterenable12_bt:", ggInverterEnableButtons[11] }, - { "inverterdisable1_bt:", ggInverterDisableButtons[0] }, - { "inverterdisable2_bt:", ggInverterDisableButtons[1] }, - { "inverterdisable3_bt:", ggInverterDisableButtons[2] }, - { "inverterdisable4_bt:", ggInverterDisableButtons[3] }, - { "inverterdisable5_bt:", ggInverterDisableButtons[4] }, - { "inverterdisable6_bt:", ggInverterDisableButtons[5] }, - { "inverterdisable7_bt:", ggInverterDisableButtons[6] }, - { "inverterdisable8_bt:", ggInverterDisableButtons[7] }, - { "inverterdisable9_bt:", ggInverterDisableButtons[8] }, - { "inverterdisable10_bt:", ggInverterDisableButtons[9] }, - { "inverterdisable11_bt:", ggInverterDisableButtons[10] }, - { "inverterdisable12_bt:", ggInverterDisableButtons[11] }, - { "invertertoggle1_bt:", ggInverterToggleButtons[0] }, - { "invertertoggle2_bt:", ggInverterToggleButtons[1] }, - { "invertertoggle3_bt:", ggInverterToggleButtons[2] }, - { "invertertoggle4_bt:", ggInverterToggleButtons[3] }, - { "invertertoggle5_bt:", ggInverterToggleButtons[4] }, - { "invertertoggle6_bt:", ggInverterToggleButtons[5] }, - { "invertertoggle7_bt:", ggInverterToggleButtons[6] }, - { "invertertoggle8_bt:", ggInverterToggleButtons[7] }, - { "invertertoggle9_bt:", ggInverterToggleButtons[8] }, - { "invertertoggle10_bt:", ggInverterToggleButtons[9] }, - { "invertertoggle11_bt:", ggInverterToggleButtons[10] }, - { "invertertoggle12_bt:", ggInverterToggleButtons[11] }, - {"pantvalvesupdate_bt:", ggPantValvesUpdate}, - {"pantvalvesoff_bt:", ggPantValvesOff}, - {"wipers_sw:", ggWiperSw} - }; - { - auto const lookup { gauges.find( Label ) }; - if( lookup != gauges.end() ) { - lookup->second.Load( Parser, DynamicObject ); - m_controlmapper.insert( lookup->second, lookup->first ); - return true; - } - } - // dedicated gauges with state-driven optional submodel - // TODO: move viable gauges here - // TODO: convert dedicated gauges to auto-allocated ones, replace dedicated references in command handlers to mapper lookups - std::unordered_map > const stategauges = { - { "tempomat_sw:", { ggScndCtrlButton, &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "tempomatoff_sw:", { ggScndCtrlOffButton, &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "speedinc_bt:", { ggSpeedControlIncreaseButton, &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "speeddec_bt:", { ggSpeedControlDecreaseButton, &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "speedctrlpowerinc_bt:", { ggSpeedControlPowerIncreaseButton, &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "speedctrlpowerdec_bt:", { ggSpeedControlPowerDecreaseButton, &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "speedbutton0:", { ggSpeedCtrlButtons[ 0 ], &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "speedbutton1:", { ggSpeedCtrlButtons[ 1 ], &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "speedbutton2:", { ggSpeedCtrlButtons[ 2 ], &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "speedbutton3:", { ggSpeedCtrlButtons[ 3 ], &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "speedbutton4:", { ggSpeedCtrlButtons[ 4 ], &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "speedbutton5:", { ggSpeedCtrlButtons[ 5 ], &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "speedbutton6:", { ggSpeedCtrlButtons[ 6 ], &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "speedbutton7:", { ggSpeedCtrlButtons[ 7 ], &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "speedbutton8:", { ggSpeedCtrlButtons[ 8 ], &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "speedbutton9:", { ggSpeedCtrlButtons[ 9 ], &mvOccupied->SpeedCtrlUnit.IsActive } }, - { "doorleftpermit_sw:", { ggDoorLeftPermitButton, &m_doorspermitleft } }, - { "doorrightpermit_sw:", { ggDoorRightPermitButton, &m_doorspermitright } }, - { "dooralloff_sw:", { ggDoorAllOffButton, &m_doors } }, - { "doorstep_sw:", { ggDoorStepButton, &mvOccupied->Doors.step_enabled } }, - { "dirforward_bt:", { ggDirForwardButton, &m_dirforward } }, - { "dirneutral_bt:", { ggDirNeutralButton, &m_dirneutral } }, - { "dirbackward_bt:", { ggDirBackwardButton, &m_dirbackward } }, - }; - { - auto const lookup { stategauges.find( Label ) }; - if( lookup != stategauges.end() ) { - auto &gauge { std::get( lookup->second ) }; - gauge.Load( Parser, DynamicObject ); - gauge.AssignState( std::get( lookup->second ) ); - m_controlmapper.insert( gauge, lookup->first ); - return true; - } - } - // TODO: move viable dedicated gauges to the automatic array - std::unordered_map const autoboolgauges = { - { "doormode_sw:", &mvOccupied->Doors.remote_only }, - { "coolingfans_sw:", &mvControlled->RVentForceOn }, - { "pantfront_sw:", &mvPantographUnit->Pantographs[end::front].valve.is_enabled }, - { "pantrear_sw:", &mvPantographUnit->Pantographs[end::rear].valve.is_enabled }, - { "pantfrontoff_sw:", &mvPantographUnit->Pantographs[end::front].valve.is_disabled }, - { "pantrearoff_sw:", &mvPantographUnit->Pantographs[end::rear].valve.is_disabled }, - { "radio_sw:", &mvOccupied->Radio }, - { "cablight_sw:", &Cabine[ iCabn ].bLight }, - { "springbraketoggle_bt:", &mvOccupied->SpringBrake.Activate }, - { "couplingdisconnect_sw:", &m_couplingdisconnect }, - { "couplingdisconnectback_sw:", &m_couplingdisconnectback }, - { "mirrors_sw:", &mvOccupied->MirrorForbidden }, - }; - { - auto lookup = autoboolgauges.find( Label ); - if( lookup != autoboolgauges.end() ) { - auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna lampka - gauge.Load( Parser, DynamicObject ); - gauge.AssignBool( lookup->second ); - m_controlmapper.insert( gauge, lookup->first ); - return true; - } - } - // TODO: move viable dedicated gauges to the automatic array - std::unordered_map const autointgauges = { - { "manualbrake:", &mvOccupied->ManualBrakePos }, - { "pantselect_sw:", &mvOccupied->PantsPreset.second[cab_to_end()] }, - }; - { - auto lookup = autointgauges.find( Label ); - if( lookup != autointgauges.end() ) { - auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna lampka - gauge.Load( Parser, DynamicObject ); - gauge.AssignInt( lookup->second ); - m_controlmapper.insert( gauge, lookup->first ); - return true; - } - } + std::unordered_map const gauges = {{"jointctrl:", ggJointCtrl}, + {"mainctrl:", ggMainCtrl}, + {"scndctrl:", ggScndCtrl}, + {"dirkey:", ggDirKey}, + {"brakectrl:", ggBrakeCtrl}, + {"localbrake:", ggLocalBrake}, + {"alarmchain:", ggAlarmChain}, + {"brakeprofile_sw:", ggBrakeProfileCtrl}, + {"brakeprofileg_sw:", ggBrakeProfileG}, + {"brakeprofiler_sw:", ggBrakeProfileR}, + {"brakeopmode_sw:", ggBrakeOperationModeCtrl}, + {"maxcurrent_sw:", ggMaxCurrentCtrl}, + {"main_off_bt:", ggMainOffButton}, + {"main_on_bt:", ggMainOnButton}, + {"security_reset_bt:", ggSecurityResetButton}, + {"shp_reset_bt:", ggSHPResetButton}, + {"releaser_bt:", ggReleaserButton}, + {"springbrakeon_bt:", ggSpringBrakeOnButton}, + {"springbrakeoff_bt:", ggSpringBrakeOffButton}, + {"universalbrake1_bt:", ggUniveralBrakeButton1}, + {"universalbrake2_bt:", ggUniveralBrakeButton2}, + {"universalbrake3_bt:", ggUniveralBrakeButton3}, + {"epbrake_bt:", ggEPFuseButton}, + {"sand_bt:", ggSandButton}, + {"autosandallow_sw:", ggAutoSandButton}, + {"antislip_bt:", ggAntiSlipButton}, + {"horn_bt:", ggHornButton}, + {"hornlow_bt:", ggHornLowButton}, + {"hornhigh_bt:", ggHornHighButton}, + {"whistle_bt:", ggWhistleButton}, + {"helper_bt:", ggHelperButton}, + {"fuse_bt:", ggFuseButton}, + {"converterfuse_bt:", ggConverterFuseButton}, + {"stlinoff_bt:", ggStLinOffButton}, + {"doorpermitpreset_sw:", ggDoorPermitPresetButton}, + {"door_left_sw:", ggDoorLeftButton}, + {"door_right_sw:", ggDoorRightButton}, + {"doorlefton_sw:", ggDoorLeftOnButton}, + {"doorrighton_sw:", ggDoorRightOnButton}, + {"doorleftoff_sw:", ggDoorLeftOffButton}, + {"doorrightoff_sw:", ggDoorRightOffButton}, + {"doorallon_sw:", ggDoorAllOnButton}, + {"departure_signal_bt:", ggDepartureSignalButton}, + {"upperlight_sw:", ggUpperLightButton}, + {"leftlight_sw:", ggLeftLightButton}, + {"rightlight_sw:", ggRightLightButton}, + {"dimheadlights_sw:", ggDimHeadlightsButton}, + {"leftend_sw:", ggLeftEndLightButton}, + {"rightend_sw:", ggRightEndLightButton}, + {"lights_sw:", ggLightsButton}, + {"moderndimmer_sw:", ggModernLightDimSw}, + {"rearupperlight_sw:", ggRearUpperLightButton}, + {"rearleftlight_sw:", ggRearLeftLightButton}, + {"rearrightlight_sw:", ggRearRightLightButton}, + {"rearleftend_sw:", ggRearLeftEndLightButton}, + {"rearrightend_sw:", ggRearRightEndLightButton}, + {"compressor_sw:", ggCompressorButton}, + {"compressorlocal_sw:", ggCompressorLocalButton}, + {"compressorlist_sw:", ggCompressorListButton}, + {"converter_sw:", ggConverterButton}, + {"converterlocal_sw:", ggConverterLocalButton}, + {"converteroff_sw:", ggConverterOffButton}, + {"main_sw:", ggMainButton}, + {"waterpumpbreaker_sw:", ggWaterPumpBreakerButton}, + {"waterpump_sw:", ggWaterPumpButton}, + {"waterheaterbreaker_sw:", ggWaterHeaterBreakerButton}, + {"waterheater_sw:", ggWaterHeaterButton}, + {"water1tempb:", ggWater1TempB}, + {"watercircuitslink_sw:", ggWaterCircuitsLinkButton}, + {"fuelpump_sw:", ggFuelPumpButton}, + {"oilpump_sw:", ggOilPumpButton}, + {"oilpressb:", ggOilPressB}, + {"motorblowersfront_sw:", ggMotorBlowersFrontButton}, + {"motorblowersrear_sw:", ggMotorBlowersRearButton}, + {"motorblowersalloff_sw:", ggMotorBlowersAllOffButton}, + {"radiochannel_sw:", ggRadioChannelSelector}, + {"radiochannelprev_sw:", ggRadioChannelPrevious}, + {"radiochannelnext_sw:", ggRadioChannelNext}, + {"radiostop_sw:", ggRadioStop}, + {"radiotest_sw:", ggRadioTest}, + {"radiocall1_sw:", ggRadioCall1}, + {"radiocall3_sw:", ggRadioCall3}, + {"radiovolume_sw:", ggRadioVolumeSelector}, + {"radiovolumeprev_sw:", ggRadioVolumePrevious}, + {"radiovolumenext_sw:", ggRadioVolumeNext}, + /* + { "pantfront_sw:", ggPantFrontButton }, + { "pantrear_sw:", ggPantRearButton }, + { "pantfrontoff_sw:", ggPantFrontButtonOff }, + { "pantrearoff_sw:", ggPantRearButtonOff }, + */ + {"pantalloff_sw:", ggPantAllDownButton}, + {"pantselected_sw:", ggPantSelectedButton}, + {"pantselectedoff_sw:", ggPantSelectedDownButton}, + {"pantvalves_sw:", ggPantValvesButton}, + {"pantcompressor_sw:", ggPantCompressorButton}, + {"pantcompressorvalve_sw:", ggPantCompressorValve}, + {"trainheating_sw:", ggTrainHeatingButton}, + {"signalling_sw:", ggSignallingButton}, + {"door_signalling_sw:", ggDoorSignallingButton}, + {"nextcurrent_sw:", ggNextCurrentButton}, + {"instrumentlight_sw:", ggInstrumentLightButton}, + {"dashboardlight_sw:", ggDashboardLightButton}, + {"timetablelight_sw:", ggTimetableLightButton}, + {"cablightdim_sw:", ggCabLightDimButton}, + {"compartmentlights_sw:", ggCompartmentLightsButton}, + {"compartmentlightson_sw:", ggCompartmentLightsOnButton}, + {"compartmentlightsoff_sw:", ggCompartmentLightsOffButton}, + {"battery_sw:", ggBatteryButton}, + {"batteryon_sw:", ggBatteryOnButton}, + {"batteryoff_sw:", ggBatteryOffButton}, + {"cabactivation_sw:", ggCabActivationButton}, + {"distancecounter_sw:", ggDistanceCounterButton}, + {"relayreset1_bt:", ggRelayResetButtons[0]}, + {"relayreset2_bt:", ggRelayResetButtons[1]}, + {"relayreset3_bt:", ggRelayResetButtons[2]}, + {"universal0:", ggUniversals[0]}, + {"universal1:", ggUniversals[1]}, + {"universal2:", ggUniversals[2]}, + {"universal3:", ggUniversals[3]}, + {"universal4:", ggUniversals[4]}, + {"universal5:", ggUniversals[5]}, + {"universal6:", ggUniversals[6]}, + {"universal7:", ggUniversals[7]}, + {"universal8:", ggUniversals[8]}, + {"universal9:", ggUniversals[9]}, + {"universal10:", ggUniversals[10]}, + {"universal11:", ggUniversals[11]}, + {"universal12:", ggUniversals[12]}, + {"universal13:", ggUniversals[13]}, + {"universal14:", ggUniversals[14]}, + {"universal15:", ggUniversals[15]}, + {"universal16:", ggUniversals[16]}, + {"universal17:", ggUniversals[17]}, + {"universal18:", ggUniversals[18]}, + {"universal19:", ggUniversals[19]}, + {"universal20:", ggUniversals[20]}, + {"universal21:", ggUniversals[21]}, + {"universal22:", ggUniversals[22]}, + {"universal23:", ggUniversals[23]}, + {"universal24:", ggUniversals[24]}, + {"universal25:", ggUniversals[25]}, + {"universal26:", ggUniversals[26]}, + {"universal27:", ggUniversals[27]}, + {"universal28:", ggUniversals[28]}, + {"universal29:", ggUniversals[29]}, + {"inverterenable1_bt:", ggInverterEnableButtons[0]}, + {"inverterenable2_bt:", ggInverterEnableButtons[1]}, + {"inverterenable3_bt:", ggInverterEnableButtons[2]}, + {"inverterenable4_bt:", ggInverterEnableButtons[3]}, + {"inverterenable5_bt:", ggInverterEnableButtons[4]}, + {"inverterenable6_bt:", ggInverterEnableButtons[5]}, + {"inverterenable7_bt:", ggInverterEnableButtons[6]}, + {"inverterenable8_bt:", ggInverterEnableButtons[7]}, + {"inverterenable9_bt:", ggInverterEnableButtons[8]}, + {"inverterenable10_bt:", ggInverterEnableButtons[9]}, + {"inverterenable11_bt:", ggInverterEnableButtons[10]}, + {"inverterenable12_bt:", ggInverterEnableButtons[11]}, + {"inverterdisable1_bt:", ggInverterDisableButtons[0]}, + {"inverterdisable2_bt:", ggInverterDisableButtons[1]}, + {"inverterdisable3_bt:", ggInverterDisableButtons[2]}, + {"inverterdisable4_bt:", ggInverterDisableButtons[3]}, + {"inverterdisable5_bt:", ggInverterDisableButtons[4]}, + {"inverterdisable6_bt:", ggInverterDisableButtons[5]}, + {"inverterdisable7_bt:", ggInverterDisableButtons[6]}, + {"inverterdisable8_bt:", ggInverterDisableButtons[7]}, + {"inverterdisable9_bt:", ggInverterDisableButtons[8]}, + {"inverterdisable10_bt:", ggInverterDisableButtons[9]}, + {"inverterdisable11_bt:", ggInverterDisableButtons[10]}, + {"inverterdisable12_bt:", ggInverterDisableButtons[11]}, + {"invertertoggle1_bt:", ggInverterToggleButtons[0]}, + {"invertertoggle2_bt:", ggInverterToggleButtons[1]}, + {"invertertoggle3_bt:", ggInverterToggleButtons[2]}, + {"invertertoggle4_bt:", ggInverterToggleButtons[3]}, + {"invertertoggle5_bt:", ggInverterToggleButtons[4]}, + {"invertertoggle6_bt:", ggInverterToggleButtons[5]}, + {"invertertoggle7_bt:", ggInverterToggleButtons[6]}, + {"invertertoggle8_bt:", ggInverterToggleButtons[7]}, + {"invertertoggle9_bt:", ggInverterToggleButtons[8]}, + {"invertertoggle10_bt:", ggInverterToggleButtons[9]}, + {"invertertoggle11_bt:", ggInverterToggleButtons[10]}, + {"invertertoggle12_bt:", ggInverterToggleButtons[11]}, + {"pantvalvesupdate_bt:", ggPantValvesUpdate}, + {"pantvalvesoff_bt:", ggPantValvesOff}, + {"wipers_sw:", ggWiperSw}}; + { + auto const lookup{gauges.find(Label)}; + if (lookup != gauges.end()) + { + lookup->second.Load(Parser, DynamicObject); + m_controlmapper.insert(lookup->second, lookup->first); + return true; + } + } + // dedicated gauges with state-driven optional submodel + // TODO: move viable gauges here + // TODO: convert dedicated gauges to auto-allocated ones, replace dedicated references in command handlers to mapper lookups + std::unordered_map> const stategauges = { + {"tempomat_sw:", {ggScndCtrlButton, &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"tempomatoff_sw:", {ggScndCtrlOffButton, &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"speedinc_bt:", {ggSpeedControlIncreaseButton, &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"speeddec_bt:", {ggSpeedControlDecreaseButton, &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"speedctrlpowerinc_bt:", {ggSpeedControlPowerIncreaseButton, &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"speedctrlpowerdec_bt:", {ggSpeedControlPowerDecreaseButton, &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"speedbutton0:", {ggSpeedCtrlButtons[0], &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"speedbutton1:", {ggSpeedCtrlButtons[1], &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"speedbutton2:", {ggSpeedCtrlButtons[2], &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"speedbutton3:", {ggSpeedCtrlButtons[3], &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"speedbutton4:", {ggSpeedCtrlButtons[4], &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"speedbutton5:", {ggSpeedCtrlButtons[5], &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"speedbutton6:", {ggSpeedCtrlButtons[6], &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"speedbutton7:", {ggSpeedCtrlButtons[7], &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"speedbutton8:", {ggSpeedCtrlButtons[8], &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"speedbutton9:", {ggSpeedCtrlButtons[9], &mvOccupied->SpeedCtrlUnit.IsActive}}, + {"doorleftpermit_sw:", {ggDoorLeftPermitButton, &m_doorspermitleft}}, + {"doorrightpermit_sw:", {ggDoorRightPermitButton, &m_doorspermitright}}, + {"dooralloff_sw:", {ggDoorAllOffButton, &m_doors}}, + {"doorstep_sw:", {ggDoorStepButton, &mvOccupied->Doors.step_enabled}}, + {"dirforward_bt:", {ggDirForwardButton, &m_dirforward}}, + {"dirneutral_bt:", {ggDirNeutralButton, &m_dirneutral}}, + {"dirbackward_bt:", {ggDirBackwardButton, &m_dirbackward}}, + }; + { + auto const lookup{stategauges.find(Label)}; + if (lookup != stategauges.end()) + { + auto &gauge{std::get(lookup->second)}; + gauge.Load(Parser, DynamicObject); + gauge.AssignState(std::get(lookup->second)); + m_controlmapper.insert(gauge, lookup->first); + return true; + } + } + // TODO: move viable dedicated gauges to the automatic array + std::unordered_map const autoboolgauges = { + {"doormode_sw:", &mvOccupied->Doors.remote_only}, + {"coolingfans_sw:", &mvControlled->RVentForceOn}, + {"pantfront_sw:", &mvPantographUnit->Pantographs[end::front].valve.is_enabled}, + {"pantrear_sw:", &mvPantographUnit->Pantographs[end::rear].valve.is_enabled}, + {"pantfrontoff_sw:", &mvPantographUnit->Pantographs[end::front].valve.is_disabled}, + {"pantrearoff_sw:", &mvPantographUnit->Pantographs[end::rear].valve.is_disabled}, + {"radio_sw:", &mvOccupied->Radio}, + {"cablight_sw:", &Cabine[iCabn].bLight}, + {"springbraketoggle_bt:", &mvOccupied->SpringBrake.Activate}, + {"couplingdisconnect_sw:", &m_couplingdisconnect}, + {"couplingdisconnectback_sw:", &m_couplingdisconnectback}, + {"mirrors_sw:", &mvOccupied->MirrorForbidden}, + }; + { + auto lookup = autoboolgauges.find(Label); + if (lookup != autoboolgauges.end()) + { + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna lampka + gauge.Load(Parser, DynamicObject); + gauge.AssignBool(lookup->second); + m_controlmapper.insert(gauge, lookup->first); + return true; + } + } + // TODO: move viable dedicated gauges to the automatic array + std::unordered_map const autointgauges = { + {"manualbrake:", &mvOccupied->ManualBrakePos}, + {"pantselect_sw:", &mvOccupied->PantsPreset.second[cab_to_end()]}, + }; + { + auto lookup = autointgauges.find(Label); + if (lookup != autointgauges.end()) + { + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna lampka + gauge.Load(Parser, DynamicObject); + gauge.AssignInt(lookup->second); + m_controlmapper.insert(gauge, lookup->first); + return true; + } + } - // ABu 090305: uniwersalne przyciski lub inne rzeczy - if( Label == "mainctrlact:" ) { - ggMainCtrlAct.Load( Parser, DynamicObject); - } - // SEKCJA WSKAZNIKOW - else if ((Label == "tachometer:") || (Label == "tachometerb:")) - { - // predkosciomierz wskaźnikowy z szarpaniem - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject); - gauge.AssignFloat(&fTachoVelocityJump); - // bind tachometer sound location to the meter - if( dsbHasler - && dsbHasler->offset() == glm::vec3() ) { - dsbHasler->offset( gauge.model_offset() ); - } - } - else if (Label == "tachometern:") - { - // predkosciomierz wskaźnikowy bez szarpania - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject); - gauge.AssignFloat(&fTachoVelocity); - // bind tachometer sound location to the meter - if( dsbHasler - && dsbHasler->offset() == glm::vec3() ) { - dsbHasler->offset( gauge.model_offset() ); - } - } - else if (Label == "tachometerd:") - { - // predkosciomierz cyfrowy - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject); - gauge.AssignFloat(&fTachoVelocity); - // bind tachometer sound location to the meter - if( dsbHasler - && dsbHasler->offset() == glm::vec3() ) { - dsbHasler->offset( gauge.model_offset() ); - } - } - else if ((Label == "hvcurrent1:") || (Label == "hvcurrent1b:")) - { - // 1szy amperomierz - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject); - gauge.AssignFloat(fHCurrent + 1); - } - else if ((Label == "hvcurrent2:") || (Label == "hvcurrent2b:")) - { - // 2gi amperomierz - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject); - gauge.AssignFloat(fHCurrent + 2); - } - else if ((Label == "hvcurrent3:") || (Label == "hvcurrent3b:")) - { - // 3ci amperomierz - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałska - gauge.Load(Parser, DynamicObject); - gauge.AssignFloat(fHCurrent + 3); - } - else if ((Label == "hvcurrent:") || (Label == "hvcurrentb:")) - { - // amperomierz calkowitego pradu - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject); - gauge.AssignFloat(fHCurrent); - } - else if (Label == "eimscreen:") - { - // amperomierz calkowitego pradu - int i, j; - Parser.getTokens(2, false); - Parser >> i >> j; - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject); - gauge.AssignFloat(&fEIMParams[i][j]); - } - else if (Label == "brakes:") - { - // specified pipe pressure of specified consist vehicle - int i, j; - Parser.getTokens(2, false); - Parser >> i >> j; - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject, 0.1); - gauge.AssignFloat(&fPress[std::clamp(i, 1, 20) - 1][std::clamp(j, 0, 3)]); - } - else if ((Label == "brakepress:") || (Label == "brakepressb:")) - { - // manometr cylindrow hamulcowych - // Ra 2014-08: przeniesione do TCab - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject, 0.1); - gauge.AssignDouble(&mvOccupied->BrakePress); - } - else if ((Label == "pipepress:") || (Label == "pipepressb:")) - { - // manometr przewodu hamulcowego - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject, 0.1); - gauge.AssignDouble(&mvOccupied->PipePress); - } - else if( Label == "scndpress:" ) { - // manometr przewodu hamulcowego - auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka - gauge.Load( Parser, DynamicObject, 0.1 ); - gauge.AssignDouble( &mvOccupied->ScndPipePress ); - } - else if (Label == "limpipepress:") - { - // manometr zbiornika sterujacego zaworu maszynisty - auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka - gauge.Load( Parser, DynamicObject, 0.1 ); - gauge.AssignDouble( &m_brakehandlecp ); - } - else if (Label == "cntrlpress:") - { - // manometr zbiornika kontrolnego/rorzďż˝du - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject, 0.1); - gauge.AssignDouble(&mvPantographUnit->PantPress); - } + // ABu 090305: uniwersalne przyciski lub inne rzeczy + if (Label == "mainctrlact:") + { + ggMainCtrlAct.Load(Parser, DynamicObject); + } + // SEKCJA WSKAZNIKOW + else if ((Label == "tachometer:") || (Label == "tachometerb:")) + { + // predkosciomierz wskaźnikowy z szarpaniem + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(&fTachoVelocityJump); + // bind tachometer sound location to the meter + if (dsbHasler && dsbHasler->offset() == glm::vec3()) + { + dsbHasler->offset(gauge.model_offset()); + } + } + else if (Label == "tachometern:") + { + // predkosciomierz wskaźnikowy bez szarpania + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(&fTachoVelocity); + // bind tachometer sound location to the meter + if (dsbHasler && dsbHasler->offset() == glm::vec3()) + { + dsbHasler->offset(gauge.model_offset()); + } + } + else if (Label == "tachometerd:") + { + // predkosciomierz cyfrowy + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(&fTachoVelocity); + // bind tachometer sound location to the meter + if (dsbHasler && dsbHasler->offset() == glm::vec3()) + { + dsbHasler->offset(gauge.model_offset()); + } + } + else if ((Label == "hvcurrent1:") || (Label == "hvcurrent1b:")) + { + // 1szy amperomierz + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(fHCurrent + 1); + } + else if ((Label == "hvcurrent2:") || (Label == "hvcurrent2b:")) + { + // 2gi amperomierz + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(fHCurrent + 2); + } + else if ((Label == "hvcurrent3:") || (Label == "hvcurrent3b:")) + { + // 3ci amperomierz + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałska + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(fHCurrent + 3); + } + else if ((Label == "hvcurrent:") || (Label == "hvcurrentb:")) + { + // amperomierz calkowitego pradu + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(fHCurrent); + } + else if (Label == "eimscreen:") + { + // amperomierz calkowitego pradu + int i, j; + Parser.getTokens(2, false); + Parser >> i >> j; + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(&fEIMParams[i][j]); + } + else if (Label == "brakes:") + { + // specified pipe pressure of specified consist vehicle + int i, j; + Parser.getTokens(2, false); + Parser >> i >> j; + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject, 0.1); + gauge.AssignFloat(&fPress[clamp(i, 1, 20) - 1][clamp(j, 0, 3)]); + } + else if ((Label == "brakepress:") || (Label == "brakepressb:")) + { + // manometr cylindrow hamulcowych + // Ra 2014-08: przeniesione do TCab + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject, 0.1); + gauge.AssignDouble(&mvOccupied->BrakePress); + } + else if ((Label == "pipepress:") || (Label == "pipepressb:")) + { + // manometr przewodu hamulcowego + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject, 0.1); + gauge.AssignDouble(&mvOccupied->PipePress); + } + else if (Label == "scndpress:") + { + // manometr przewodu hamulcowego + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject, 0.1); + gauge.AssignDouble(&mvOccupied->ScndPipePress); + } + else if (Label == "limpipepress:") + { + // manometr zbiornika sterujacego zaworu maszynisty + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject, 0.1); + gauge.AssignDouble(&m_brakehandlecp); + } + else if (Label == "cntrlpress:") + { + // manometr zbiornika kontrolnego/rorzďż˝du + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject, 0.1); + gauge.AssignDouble(&mvPantographUnit->PantPress); + } else if (Label == "springbrakepress:") { // manometr cylindra hamulca sprężynowego @@ -11017,171 +12230,184 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con gauge.Load(Parser, DynamicObject, 0.1); gauge.AssignDouble(&mvOccupied->EpForce); } - else if ((Label == "compressor:") || (Label == "compressorb:")) - { - // manometr sprezarki/zbiornika glownego - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject, 0.1); - gauge.AssignDouble(&mvOccupied->Compressor); - } - else if( Label == "oilpress:" ) { - // oil pressure - auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka - gauge.Load( Parser, DynamicObject ); - gauge.AssignFloat( &mvControlled->OilPump.pressure ); - } - else if( Label == "oiltemp:" ) { - // oil temperature - auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka - gauge.Load( Parser, DynamicObject ); - gauge.AssignFloat( &mvControlled->dizel_heat.To ); - } - else if( Label == "water1temp:" ) { - // main circuit water temperature - auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka - gauge.Load( Parser, DynamicObject ); - gauge.AssignFloat( &mvControlled->dizel_heat.temperatura1 ); - } - else if( Label == "water2temp:" ) { - // auxiliary circuit water temperature - auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka - gauge.Load( Parser, DynamicObject ); - gauge.AssignFloat( &mvControlled->dizel_heat.temperatura2 ); - } - else if( Label == "pantpress:" ) { - // pantograph tank pressure - auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka - gauge.Load( Parser, DynamicObject, 0.1 ); - gauge.AssignDouble( &mvPantographUnit->PantPress ); - } - // yB - dla drugiej sekcji - else if (Label == "hvbcurrent1:") - { - // 1szy amperomierz - ggI1B.Load(Parser, DynamicObject); - } - else if (Label == "hvbcurrent2:") - { - // 2gi amperomierz - ggI2B.Load(Parser, DynamicObject); - } - else if (Label == "hvbcurrent3:") - { - // 3ci amperomierz - ggI3B.Load(Parser, DynamicObject); - } - else if (Label == "hvbcurrent:") - { - // amperomierz calkowitego pradu - ggItotalB.Load(Parser, DynamicObject); - } - //************************************************************* - else if (Label == "clock:") - { - // zegar analogowy - if (Parser.getToken() == "analog") - { - if( DynamicObject->mdKabina ) { - // McZapkie-300302: zegarek - ggClockSInd.Init( DynamicObject->mdKabina->GetFromName( "ClockShand" ), nullptr, TGaugeAnimation::gt_Rotate, 1.0 / 60.0 ); - ggClockMInd.Init( DynamicObject->mdKabina->GetFromName( "ClockMhand" ), nullptr, TGaugeAnimation::gt_Rotate, 1.0 / 60.0 ); - ggClockHInd.Init( DynamicObject->mdKabina->GetFromName( "ClockHhand" ), nullptr, TGaugeAnimation::gt_Rotate, 1.0 / 12.0 ); - } - } - } - else if( Label == "clock_seconds:" ) { - ggClockSInd.Load( Parser, DynamicObject ); - } - else if (Label == "evoltage:") - { - // woltomierz napiecia silnikow - ggEngineVoltage.Load(Parser, DynamicObject); - } - else if (Label == "hvoltage:") - { - // woltomierz wysokiego napiecia - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject); - gauge.AssignFloat(&fHVoltage); - } - else if (Label == "lvoltage:") - { - // woltomierz niskiego napiecia - ggLVoltage.Load(Parser, DynamicObject); - } - else if (Label == "enrot1m:") - { - // obrotomierz - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject); - gauge.AssignFloat(fEngine + 1); - } // ggEnrot1m.Load(Parser,DynamicObject->mdKabina); - else if (Label == "enrot2m:") - { - // obrotomierz - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject); - gauge.AssignFloat(fEngine + 2); - } // ggEnrot2m.Load(Parser,DynamicObject->mdKabina); - else if (Label == "enrot3m:") - { // obrotomierz - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject); - gauge.AssignFloat(fEngine + 3); - } // ggEnrot3m.Load(Parser,DynamicObject->mdKabina); - else if (Label == "engageratio:") - { - // np. ciśnienie sterownika sprzęgła - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject); - gauge.AssignDouble(&mvControlled->dizel_engage); - } // ggEngageRatio.Load(Parser,DynamicObject->mdKabina); - else if (Label == "maingearstatus:") - { - // np. ciśnienie sterownika skrzyni biegów - ggMainGearStatus.Load(Parser, DynamicObject); - } - else if (Label == "ignitionkey:") - { - ggIgnitionKey.Load(Parser, DynamicObject); - } - else if (Label == "distcounter:") - { - // Ra 2014-07: licznik kilometrów - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject); - gauge.AssignDouble(&mvControlled->DistCounter); - } - else if( Label == "shuntmodepower:" ) { - // shunt mode power slider - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject); - gauge.AssignDouble(&mvControlled->AnPos); - m_controlmapper.insert( gauge, "shuntmodepower:" ); - } - else if( Label == "heatingvoltage:" ) { - if( mvControlled->HeatingPowerSource.SourceType == TPowerSource::Generator ) { - auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka - gauge.Load( Parser, DynamicObject ); - gauge.AssignDouble( &(mvControlled->HeatingPowerSource.EngineGenerator.voltage) ); - } - } - else if( Label == "heatingcurrent:" ) { - auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka - gauge.Load( Parser, DynamicObject ); - gauge.AssignDouble( &( mvControlled->TotalCurrent ) ); - } - else - { - // failed to match the label - return false; - } + else if ((Label == "compressor:") || (Label == "compressorb:")) + { + // manometr sprezarki/zbiornika glownego + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject, 0.1); + gauge.AssignDouble(&mvOccupied->Compressor); + } + else if (Label == "oilpress:") + { + // oil pressure + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(&mvControlled->OilPump.pressure); + } + else if (Label == "oiltemp:") + { + // oil temperature + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(&mvControlled->dizel_heat.To); + } + else if (Label == "water1temp:") + { + // main circuit water temperature + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(&mvControlled->dizel_heat.temperatura1); + } + else if (Label == "water2temp:") + { + // auxiliary circuit water temperature + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(&mvControlled->dizel_heat.temperatura2); + } + else if (Label == "pantpress:") + { + // pantograph tank pressure + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject, 0.1); + gauge.AssignDouble(&mvPantographUnit->PantPress); + } + // yB - dla drugiej sekcji + else if (Label == "hvbcurrent1:") + { + // 1szy amperomierz + ggI1B.Load(Parser, DynamicObject); + } + else if (Label == "hvbcurrent2:") + { + // 2gi amperomierz + ggI2B.Load(Parser, DynamicObject); + } + else if (Label == "hvbcurrent3:") + { + // 3ci amperomierz + ggI3B.Load(Parser, DynamicObject); + } + else if (Label == "hvbcurrent:") + { + // amperomierz calkowitego pradu + ggItotalB.Load(Parser, DynamicObject); + } + //************************************************************* + else if (Label == "clock:") + { + // zegar analogowy + if (Parser.getToken() == "analog") + { + if (DynamicObject->mdKabina) + { + // McZapkie-300302: zegarek + ggClockSInd.Init(DynamicObject->mdKabina->GetFromName("ClockShand"), nullptr, TGaugeAnimation::gt_Rotate, 1.0 / 60.0); + ggClockMInd.Init(DynamicObject->mdKabina->GetFromName("ClockMhand"), nullptr, TGaugeAnimation::gt_Rotate, 1.0 / 60.0); + ggClockHInd.Init(DynamicObject->mdKabina->GetFromName("ClockHhand"), nullptr, TGaugeAnimation::gt_Rotate, 1.0 / 12.0); + } + } + } + else if (Label == "clock_seconds:") + { + ggClockSInd.Load(Parser, DynamicObject); + } + else if (Label == "evoltage:") + { + // woltomierz napiecia silnikow + ggEngineVoltage.Load(Parser, DynamicObject); + } + else if (Label == "hvoltage:") + { + // woltomierz wysokiego napiecia + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(&fHVoltage); + } + else if (Label == "lvoltage:") + { + // woltomierz niskiego napiecia + ggLVoltage.Load(Parser, DynamicObject); + } + else if (Label == "enrot1m:") + { + // obrotomierz + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(fEngine + 1); + } // ggEnrot1m.Load(Parser,DynamicObject->mdKabina); + else if (Label == "enrot2m:") + { + // obrotomierz + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(fEngine + 2); + } // ggEnrot2m.Load(Parser,DynamicObject->mdKabina); + else if (Label == "enrot3m:") + { // obrotomierz + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignFloat(fEngine + 3); + } // ggEnrot3m.Load(Parser,DynamicObject->mdKabina); + else if (Label == "engageratio:") + { + // np. ciśnienie sterownika sprzęgła + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignDouble(&mvControlled->dizel_engage); + } // ggEngageRatio.Load(Parser,DynamicObject->mdKabina); + else if (Label == "maingearstatus:") + { + // np. ciśnienie sterownika skrzyni biegów + ggMainGearStatus.Load(Parser, DynamicObject); + } + else if (Label == "ignitionkey:") + { + ggIgnitionKey.Load(Parser, DynamicObject); + } + else if (Label == "distcounter:") + { + // Ra 2014-07: licznik kilometrów + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignDouble(&mvControlled->DistCounter); + } + else if (Label == "shuntmodepower:") + { + // shunt mode power slider + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignDouble(&mvControlled->AnPos); + m_controlmapper.insert(gauge, "shuntmodepower:"); + } + else if (Label == "heatingvoltage:") + { + if (mvControlled->HeatingPowerSource.SourceType == TPowerSource::Generator) + { + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignDouble(&(mvControlled->HeatingPowerSource.EngineGenerator.voltage)); + } + } + else if (Label == "heatingcurrent:") + { + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject); + gauge.AssignDouble(&(mvControlled->TotalCurrent)); + } + else + { + // failed to match the label + return false; + } - return true; + return true; } -uint16_t TTrain::id() { - if (vid == 0) { +uint16_t TTrain::id() +{ + if (vid == 0) + { vid = ++simulation::prev_train_id; WriteLog("net: assigning id " + std::to_string(vid) + " to vehicle " + Dynamic()->name(), logtype::net); } @@ -11243,40 +12469,47 @@ void train_table::updateAsync(double dt) } } - void train_table::update(double dt) { - for (TTrain *train : m_items) { + for (TTrain *train : m_items) + { if (!train) continue; train->Update(dt); - if (train->pending_delete) { + if (train->pending_delete) + { purge(train->Dynamic()->name()); if (simulation::Train == train) simulation::Train = nullptr; } // for single-player destroy non-player trains - else if (simulation::Train != train - && Global.network_servers.empty() && !Global.network_client) { + else if (simulation::Train != train && Global.network_servers.empty() && !Global.network_client) + { purge(train->Dynamic()->name()); } } } -TTrain * -train_table::find_id( std::uint16_t const Id ) const { +TTrain *train_table::find_id(std::uint16_t const Id) const +{ - if( Id == 0 ) { return nullptr; } + if (Id == 0) + { + return nullptr; + } - for( TTrain *train : m_items ) { - if( !train ) { - continue; - } - if( train->id() == Id ) { - return train; - } - } - return nullptr; + for (TTrain *train : m_items) + { + if (!train) + { + continue; + } + if (train->id() == Id) + { + return train; + } + } + return nullptr; } diff --git a/vehicle/Train.h b/vehicle/Train.h index d7c67d27..69a6c662 100644 --- a/vehicle/Train.h +++ b/vehicle/Train.h @@ -236,11 +236,19 @@ class TTrain { static void OnCommand_aidriverenable( TTrain *Train, command_data const &Command ); static void OnCommand_aidriverdisable( TTrain *Train, command_data const &Command ); static void OnCommand_jointcontrollerset( TTrain *Train, command_data const &Command ); + static void OnCommand_mastercontrollerincrease( TTrain *Train, command_data const &Command ); static void OnCommand_mastercontrollerincreasefast( TTrain *Train, command_data const &Command ); static void OnCommand_mastercontrollerdecrease( TTrain *Train, command_data const &Command ); static void OnCommand_mastercontrollerdecreasefast( TTrain *Train, command_data const &Command ); static void OnCommand_mastercontrollerset( TTrain *Train, command_data const &Command ); + + static void OnCommand_DynamicBrakeControllerIncrease( TTrain *Train, command_data const &Command ); + static void OnCommand_DynamicBrakeControllerIncreaseFast( TTrain *Train, command_data const &Command ); + static void OnCommand_DynamicBrakeControllerDecrease( TTrain *Train, command_data const &Command ); + static void OnCommand_DynamicBrakeControllerDecreaseFast( TTrain *Train, command_data const &Command ); + static void OnCommand_DynamicBrakeControllerSet( TTrain *Train, command_data const &Command ); + static void OnCommand_secondcontrollerincrease( TTrain *Train, command_data const &Command ); static void OnCommand_secondcontrollerincreasefast( TTrain *Train, command_data const &Command ); static void OnCommand_secondcontrollerdecrease( TTrain *Train, command_data const &Command );