diff --git a/CMakeLists.txt b/CMakeLists.txt index c05b2505..e2e4a1b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,6 +98,7 @@ set(SOURCES "world/Traction.cpp" "world/TractionPower.cpp" "vehicle/train/Train.cpp" +"vehicle/train/TrainCabSetup.cpp" "vehicle/train/TrainCommandsAuxiliary.cpp" "vehicle/train/TrainCommandsBrakes.cpp" "vehicle/train/TrainCommandsControls.cpp" @@ -106,6 +107,8 @@ set(SOURCES "vehicle/train/TrainCommandsLights.cpp" "vehicle/train/TrainCommandsMisc.cpp" "vehicle/train/TrainCommandsRadio.cpp" +"vehicle/train/TrainSounds.cpp" +"vehicle/train/TrainState.cpp" "world/TrkFoll.cpp" "vehicle/AirCoupler.cpp" "model/AnimModel.cpp" diff --git a/vehicle/train/Train.cpp b/vehicle/train/Train.cpp index c5dfc971..dbeff168 100644 --- a/vehicle/train/Train.cpp +++ b/vehicle/train/Train.cpp @@ -19,14 +19,10 @@ http://mozilla.org/MPL/2.0/. #include "simulation/simulation.h" #include "world/Event.h" #include "simulation/simulationtime.h" -#include "vehicle/Camera.h" #include "utilities/Logs.h" -#include "model/MdlMngr.h" #include "model/Model3d.h" -#include "utilities/Timer.h" #include "vehicle/Driver.h" #include "vehicle/DynObj.h" -#include "world/mtable.h" #include "Console.h" #include "application/application.h" #include "rendering/renderer.h" @@ -85,895 +81,6 @@ bool control_mapper::contains(std::string const Control) const return m_names.find(Control) != m_names.end(); } -void TTrain::screen_entry::deserialize(cParser &Input) -{ - - 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 ,;[]")}; - - if (true == key.empty() || key == "}") - { - return false; - } - - 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; - } - - 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(); - - 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; -} - -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]; - } -}; - -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]; - } -}; - -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 &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::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::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::generictoggle0, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle1, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle2, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle3, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle4, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle5, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle6, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle7, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle8, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle9, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle10, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle11, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle12, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle13, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle14, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle15, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle16, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle17, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle18, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle19, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle20, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle21, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle22, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle23, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle24, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle25, &TTrain::OnCommand_generictoggle}, - {user_command::generictoggle26, &TTrain::OnCommand_generictoggle}, - {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}, -}; - -std::vector const TTrain::fPress_labels = { - - "ch1: ", "ch2: ", "ch3: ", "ch4: ", "ch5: ", "ch6: ", "ch7: ", "ch8: ", "ch9: ", "ch0: "}; - -TTrain::TTrain() -{ - - ShowNextCurrent = false; - // McZapkie-240302 - przyda sie do tachometru - fTachoVelocity = 0; - fTachoCount = 0; - fPPress = fNPress = 0; - - // asMessage=""; - pMechOffset = glm::dvec3(0, 0, 0); - fBlinkTimer = 0; - fHaslerTimer = 0; - DynamicSet(nullptr); // ustawia wszystkie mv* - //----- - pMechSittingPosition = glm::dvec3(0, 0, 0); // ABu: 180404 - 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; - } - bCompressors.clear(); - 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 j = 0; j < 7; ++j) - fPress[i][j] = 0.0; - bBrakes[i][0] = bBrakes[i][1] = false; - } -} - -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); - } - - DynamicSet(NewDynamicObject); - if (!e3d) - if (DynamicObject->Mechanik == nullptr) - return false; - - DynamicObject->MechInside = true; - - fMainRelayTimer = 0; // Hunter, do k...y nędzy, ustawiaj wartości początkowe zmiennych! - - iCabn = mvOccupied->CabOccupied > 0 ? 1 : mvOccupied->CabOccupied < 0 ? 2 : 0; - - { - Global.CurrentMaxTextureSize = Global.iMaxCabTextureSize; - - auto const filename{mvOccupied->TypeName + ".mmd"}; - LoadMMediaFile(filename); - InitializeCab(mvOccupied->CabOccupied, filename); - - Global.CurrentMaxTextureSize = Global.iMaxTextureSize; - - 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(); - } - - return true; -} - -std::shared_ptr TTrain::GetTrainState(dictionary_source const &Extraparameters) -{ - - if (mvOccupied == nullptr || mvControlled == 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("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)) - { - - 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); - - // 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_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()); - 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])); - 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; - while (p && in < 8) - { - if (p->MoverParameters->eimc[eimc_p_Pmax] > 1) - { - in++; - dict->insert("eimp_c" + std::to_string(in) + "_invno", p->MoverParameters->InvertersNo); - 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); - } - } - 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]); - } - } - // 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)}; - - 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; -} - -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(), - }; -} bool TTrain::is_eztoer() const { @@ -1088,26 +195,6 @@ TDynamicObject *TTrain::find_nearest_consist_vehicle(bool freefly, glm::vec3 pos return vehicle; } - -// cab movement update, fixed step part -void TTrain::UpdateCab() -{ - - // 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)) - { - - InitializeCab(mvOccupied->CabOccupied, mvOccupied->TypeName + ".mmd"); - } - } - iCabn = mvOccupied->CabOccupied == -1 ? 2 : mvOccupied->CabOccupied; -} - bool TTrain::Update(double const Deltatime) { // train state update @@ -2481,501 +1568,6 @@ void TTrain::SetupDirectionRelays() Dynamic()->sDirectionRelayN.play(); } -void TTrain::update_sounds(double const Deltatime) -{ - - 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(); - } - } - } - - // 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(); - } - } - } - 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) - { - - 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); - } - - 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) - { - if (!FreeFlyModeFlag && !Global.CabWindowOpen && DynamicObject->GetVelocity() > 0.5) - update_sounds_resonancenoise(*rsWindSound); - else - rsWindSound->stop(FreeFlyModeFlag); - } - - // dzwiek rezonansu (taki drugi runningnoise w sumie) - if (rsResonanceNoise) - { - if (!FreeFlyModeFlag && !Global.CabWindowOpen && DynamicObject->GetVelocity() > 0.5) - { - - update_sounds_resonancenoise(*rsResonanceNoise); - } - else - rsResonanceNoise->stop(FreeFlyModeFlag); - } - - // 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(*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(); - } - } - - 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) - { - - // 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()) - { - 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); -#ifdef _WIN32 - Console::BitsSet(1 << 14); // ustawienie bitu 16 na PoKeys -#endif - } - } - else - { - if (dsbBuzzer && true == dsbBuzzer->is_playing()) - { - dsbBuzzer->stop(); -#ifdef _WIN32 - 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(); -#ifdef _WIN32 - Console::BitsClear(1 << 14); // ustawienie bitu 16 na PoKeys -#endif - } - } - - if (dsbBuzzerShp && dsbBuzzerShp->is_playing()) - { - dsbBuzzerShp->stop(); - } - { - } - - if (m_distancecounterclear) - { - m_distancecounterclear->stop(); - } - } - - update_sounds_radio(); -} - -void TTrain::update_sounds_resonancenoise(sound_source &Sound) -{ - // frequency calculation - auto const normalizer{mvOccupied->Vmax * 0.01f}; - 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 (volume > 0.05) - { - Sound.pitch(frequency).gain(volume).play(sound_flags::exclusive | sound_flags::looping); - } - else - { - Sound.stop(); - } -} - -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 *= 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)); - } - - if (volume > 0.05) - { - Sound.pitch(frequency).gain(volume).play(sound_flags::exclusive | sound_flags::looping); - } - else - { - Sound.stop(); - } -} - -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); - 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); - radio_message_played |= true; - } - 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; - - if (screen.updatetimecounter <= screen.updatetime) - continue; - - screen.updatetimecounter = screen.updatetime > 0 ? 0 : -1; - - auto state_dict = GetTrainState(screen.parameters); - - state_dict->insert("touches", *screen.touch_list); - screen.touch_list->clear(); - - Application.request({screen.script, state_dict, screen.rt}); - } -} - void TTrain::add_distance(double const Distance) { @@ -2991,2097 +1583,6 @@ void TTrain::add_distance(double const Distance) } } -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 -} - -// 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 &, 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:"); - - if (token == "internaldata:") - { - - do - { - token = ""; - parser.getTokens(); - parser >> token; - - 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 != ""); - - // 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) - { - 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()}; - 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()) - { - CabSoundLocations.emplace_back(sound, sound.get()->offset()); - } - } - - 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) - { - sound.first.get()->offset(sound.second); - } - } - // reset view angles - pMechViewAngle = {0.0, 0.0}; - - 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; - - 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); - - 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; - - 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; - } - // 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; - } - - 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->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; - - 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:"); - for (auto &screen : m_screens) - { - if (screen.updatetime > 0) - { - screen.updatetime = std::max((int)screen.updatetime, Global.PythonScreenUpdateRate) * 0.001; - } - if (screen.updatetime == 0) - { - screen.updatetime = std::max(Global.PythonScreenUpdateRate, ScreenUpdateRate) * 0.001; - } - if (screen.updatetime < -1) - { - screen.updatetime = -screen.updatetime * 0.001; - } - } - } - 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"); -*/ - 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)}; - - 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); -}; - -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 - - if (DynamicObject == nullptr) - { - return; - } - - mvControlled = DynamicObject->FindPowered()->MoverParameters; - mvSecond = nullptr; // 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) -{ - // > 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) - { - // let's try to destroy this TTrain and move to already existing one - - 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; - Dynamic()->Controller = AIdriver; - - Dynamic()->bDisplayCab = false; - Dynamic()->ABuSetModelShake({}); - - 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->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 - { - target_train->Dynamic()->bDisplayCab = false; - target_train->Dynamic()->ABuSetModelShake({}); - } - - target_train->Dynamic()->ABuSetModelShake({}); // zerowanie przesunięcia przed powrotem? - - // potentially move player - 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; - } - - // delete this TTrain - pending_delete = true; - } - 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) - { - // 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; - Dynamic()->Controller = AIdriver; - - Dynamic()->bDisplayCab = false; - Dynamic()->ABuSetModelShake({}); - - if (Dynamic()->Mechanik) - Dynamic()->Mechanik->MoveTo(target); - - DynamicSet(target); - - 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 - { - Dynamic()->bDisplayCab = false; - Dynamic()->ABuSetModelShake({}); - - DynamicSet(target); - } - - { - auto const filename{Occupied()->TypeName + ".mmd"}; - LoadMMediaFile(filename); - InitializeCab(Occupied()->CabActive, filename); - } - - 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; - } - - // add it back with updated dynamic name - simulation::Trains.insert(this); - } -} - -// checks whether specified point is within boundaries of the active cab -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; -} - -glm::dvec3 TTrain::clamp_inside(glm::dvec3 const &Point) const -{ - - 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)}; -} - -const TTrain::screenentry_sequence &TTrain::get_screens() -{ - update_screens(Timer::GetDeltaTime()); - return m_screens; -} - -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(); -} - -// 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 - - // 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(); - 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(); - ggHelperButton.Clear(); - ggNextCurrentButton.Clear(); - ggSpeedControlIncreaseButton.Clear(); - ggSpeedControlDecreaseButton.Clear(); - ggSpeedControlPowerIncreaseButton.Clear(); - ggSpeedControlPowerDecreaseButton.Clear(); - for (auto &speedctrlbutton : ggSpeedCtrlButtons) - { - speedctrlbutton.Clear(); - } - for (auto &universal : ggUniversals) - { - universal.Clear(); - } - for (auto &item : ggInverterEnableButtons) - { - item.Clear(); - } - for (auto &item : ggInverterDisableButtons) - { - item.Clear(); - } - 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(); - ggCabActivationButton.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(); - - ggPantValvesOff.Clear(); - ggPantValvesUpdate.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(); - - 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(); - 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(); - btLampkaGear1.Clear(); - btLampkaGear2.Clear(); - btLampkaHydroLockup.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(); - 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(); - - 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(); -} - -// 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); - // 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); - } - - if (ggModernLightDimSw.SubModel != nullptr) - { - mvOccupied->modernDimmerPosition = mvOccupied->modernDimmerDefaultPosition; - ggModernLightDimSw.PutValue(mvOccupied->modernDimmerDefaultPosition); - } - - // Init separate buttons - if (ggPantValvesUpdate.SubModel != nullptr) - { - ggPantValvesUpdate.PutValue(0.f); - } - 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); - } - - 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); - 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); - - 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) - { - 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); - } - - if (ggWiperSw.SubModel != nullptr) - { - ggWiperSw.PutValue(mvOccupied->wiperSwitchPos); - } - - 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); - - // 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 - { - int itemindex = itemstart; - itemstart++; - TDynamicObject *p = DynamicObject->GetFirstDynamic(mvOccupied->CabOccupied < 0 ? end::rear : end::front, flag); - while (p) - { - if (p->MoverParameters->eimc[eimc_p_Pmax] > 1) - { - if (itemindex < p->MoverParameters->InvertersNo) - { - // visual feedback - 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 -} - -// 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) -{ - - 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-gear1:", btLampkaGear1}, - {"i-gear2:", btLampkaGear2}, - {"i-hydrolockup:", btLampkaHydroLockup}, - {"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; -} - -// 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) -{ - - 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); - } - else if (Label == "springbrakepress:") - { - // manometr cylindra hamulca sprężynowego - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - gauge.Load(Parser, DynamicObject, 0.1); - gauge.AssignDouble(&mvOccupied->SpringBrake.SBP); - } - else if (Label == "epctrlvalue:") - { - // wskazowka sterowania sila hamulca ep - auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka - 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; - } - - return true; -} - uint16_t TTrain::id() { if (vid == 0) diff --git a/vehicle/train/TrainCabSetup.cpp b/vehicle/train/TrainCabSetup.cpp new file mode 100644 index 00000000..58595a3a --- /dev/null +++ b/vehicle/train/TrainCabSetup.cpp @@ -0,0 +1,2143 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "vehicle/train/Train.h" + +#include "utilities/Globals.h" +#include "simulation/simulation.h" +#include "world/Event.h" +#include "simulation/simulationtime.h" +#include "vehicle/Camera.h" +#include "utilities/Logs.h" +#include "model/MdlMngr.h" +#include "model/Model3d.h" +#include "utilities/Timer.h" +#include "vehicle/Driver.h" +#include "vehicle/DynObj.h" +#include "application/application.h" +#include "rendering/renderer.h" +#include +#include +#include + + + +// cab movement update, fixed step part +void TTrain::UpdateCab() +{ + + // 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)) + { + + InitializeCab(mvOccupied->CabOccupied, mvOccupied->TypeName + ".mmd"); + } + } + iCabn = mvOccupied->CabOccupied == -1 ? 2 : mvOccupied->CabOccupied; +} + +void TTrain::update_screens(double dt) +{ + for (auto &screen : m_screens) + { + if (screen.updatetimecounter >= 0) + screen.updatetimecounter += dt; + + if (screen.updatetimecounter <= screen.updatetime) + continue; + + screen.updatetimecounter = screen.updatetime > 0 ? 0 : -1; + + auto state_dict = GetTrainState(screen.parameters); + + state_dict->insert("touches", *screen.touch_list); + screen.touch_list->clear(); + + Application.request({screen.script, state_dict, screen.rt}); + } +} + +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 +} + +// 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 &, 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:"); + + if (token == "internaldata:") + { + + do + { + token = ""; + parser.getTokens(); + parser >> token; + + 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 != ""); + + // 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) + { + 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()}; + 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()) + { + CabSoundLocations.emplace_back(sound, sound.get()->offset()); + } + } + + 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) + { + sound.first.get()->offset(sound.second); + } + } + // reset view angles + pMechViewAngle = {0.0, 0.0}; + + 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; + + 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); + + 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; + + 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; + } + // 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; + } + + 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->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; + + 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:"); + for (auto &screen : m_screens) + { + if (screen.updatetime > 0) + { + screen.updatetime = std::max((int)screen.updatetime, Global.PythonScreenUpdateRate) * 0.001; + } + if (screen.updatetime == 0) + { + screen.updatetime = std::max(Global.PythonScreenUpdateRate, ScreenUpdateRate) * 0.001; + } + if (screen.updatetime < -1) + { + screen.updatetime = -screen.updatetime * 0.001; + } + } + } + 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"); +*/ + 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)}; + + 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); +}; + +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 + + if (DynamicObject == nullptr) + { + return; + } + + mvControlled = DynamicObject->FindPowered()->MoverParameters; + mvSecond = nullptr; // 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) +{ + // > 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) + { + // let's try to destroy this TTrain and move to already existing one + + 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; + Dynamic()->Controller = AIdriver; + + Dynamic()->bDisplayCab = false; + Dynamic()->ABuSetModelShake({}); + + 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->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 + { + target_train->Dynamic()->bDisplayCab = false; + target_train->Dynamic()->ABuSetModelShake({}); + } + + target_train->Dynamic()->ABuSetModelShake({}); // zerowanie przesunięcia przed powrotem? + + // potentially move player + 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; + } + + // delete this TTrain + pending_delete = true; + } + 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) + { + // 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; + Dynamic()->Controller = AIdriver; + + Dynamic()->bDisplayCab = false; + Dynamic()->ABuSetModelShake({}); + + if (Dynamic()->Mechanik) + Dynamic()->Mechanik->MoveTo(target); + + DynamicSet(target); + + 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 + { + Dynamic()->bDisplayCab = false; + Dynamic()->ABuSetModelShake({}); + + DynamicSet(target); + } + + { + auto const filename{Occupied()->TypeName + ".mmd"}; + LoadMMediaFile(filename); + InitializeCab(Occupied()->CabActive, filename); + } + + 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; + } + + // add it back with updated dynamic name + simulation::Trains.insert(this); + } +} + +// checks whether specified point is within boundaries of the active cab +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; +} + +glm::dvec3 TTrain::clamp_inside(glm::dvec3 const &Point) const +{ + + 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)}; +} + +const TTrain::screenentry_sequence &TTrain::get_screens() +{ + update_screens(Timer::GetDeltaTime()); + return m_screens; +} + +// 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 + + // 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(); + 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(); + ggHelperButton.Clear(); + ggNextCurrentButton.Clear(); + ggSpeedControlIncreaseButton.Clear(); + ggSpeedControlDecreaseButton.Clear(); + ggSpeedControlPowerIncreaseButton.Clear(); + ggSpeedControlPowerDecreaseButton.Clear(); + for (auto &speedctrlbutton : ggSpeedCtrlButtons) + { + speedctrlbutton.Clear(); + } + for (auto &universal : ggUniversals) + { + universal.Clear(); + } + for (auto &item : ggInverterEnableButtons) + { + item.Clear(); + } + for (auto &item : ggInverterDisableButtons) + { + item.Clear(); + } + 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(); + ggCabActivationButton.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(); + + ggPantValvesOff.Clear(); + ggPantValvesUpdate.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(); + + 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(); + 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(); + btLampkaGear1.Clear(); + btLampkaGear2.Clear(); + btLampkaHydroLockup.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(); + 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(); + + 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(); +} + +// 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); + // 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); + } + + if (ggModernLightDimSw.SubModel != nullptr) + { + mvOccupied->modernDimmerPosition = mvOccupied->modernDimmerDefaultPosition; + ggModernLightDimSw.PutValue(mvOccupied->modernDimmerDefaultPosition); + } + + // Init separate buttons + if (ggPantValvesUpdate.SubModel != nullptr) + { + ggPantValvesUpdate.PutValue(0.f); + } + 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); + } + + 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); + 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); + + 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) + { + 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); + } + + if (ggWiperSw.SubModel != nullptr) + { + ggWiperSw.PutValue(mvOccupied->wiperSwitchPos); + } + + 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); + + // 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 + { + int itemindex = itemstart; + itemstart++; + TDynamicObject *p = DynamicObject->GetFirstDynamic(mvOccupied->CabOccupied < 0 ? end::rear : end::front, flag); + while (p) + { + if (p->MoverParameters->eimc[eimc_p_Pmax] > 1) + { + if (itemindex < p->MoverParameters->InvertersNo) + { + // visual feedback + 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 +} + +// 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) +{ + + 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-gear1:", btLampkaGear1}, + {"i-gear2:", btLampkaGear2}, + {"i-hydrolockup:", btLampkaHydroLockup}, + {"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; +} + +// 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) +{ + + 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); + } + else if (Label == "springbrakepress:") + { + // manometr cylindra hamulca sprężynowego + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + gauge.Load(Parser, DynamicObject, 0.1); + gauge.AssignDouble(&mvOccupied->SpringBrake.SBP); + } + else if (Label == "epctrlvalue:") + { + // wskazowka sterowania sila hamulca ep + auto &gauge = Cabine[Cabindex].Gauge(-1); // pierwsza wolna gałka + 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; + } + + return true; +} diff --git a/vehicle/train/TrainSounds.cpp b/vehicle/train/TrainSounds.cpp new file mode 100644 index 00000000..df514446 --- /dev/null +++ b/vehicle/train/TrainSounds.cpp @@ -0,0 +1,516 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "vehicle/train/Train.h" + +#include "utilities/Globals.h" +#include "world/Event.h" +#include "simulation/simulationtime.h" +#include "model/Model3d.h" +#include "vehicle/Driver.h" +#include "vehicle/DynObj.h" +#include "Console.h" +#include "rendering/renderer.h" +#include +#include +#include + + +void TTrain::update_sounds(double const Deltatime) +{ + + 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(); + } + } + } + + // 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(); + } + } + } + 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) + { + + 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); + } + + 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) + { + if (!FreeFlyModeFlag && !Global.CabWindowOpen && DynamicObject->GetVelocity() > 0.5) + update_sounds_resonancenoise(*rsWindSound); + else + rsWindSound->stop(FreeFlyModeFlag); + } + + // dzwiek rezonansu (taki drugi runningnoise w sumie) + if (rsResonanceNoise) + { + if (!FreeFlyModeFlag && !Global.CabWindowOpen && DynamicObject->GetVelocity() > 0.5) + { + + update_sounds_resonancenoise(*rsResonanceNoise); + } + else + rsResonanceNoise->stop(FreeFlyModeFlag); + } + + // 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(*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(); + } + } + + 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) + { + + // 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()) + { + 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); +#ifdef _WIN32 + Console::BitsSet(1 << 14); // ustawienie bitu 16 na PoKeys +#endif + } + } + else + { + if (dsbBuzzer && true == dsbBuzzer->is_playing()) + { + dsbBuzzer->stop(); +#ifdef _WIN32 + 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(); +#ifdef _WIN32 + Console::BitsClear(1 << 14); // ustawienie bitu 16 na PoKeys +#endif + } + } + + if (dsbBuzzerShp && dsbBuzzerShp->is_playing()) + { + dsbBuzzerShp->stop(); + } + { + } + + if (m_distancecounterclear) + { + m_distancecounterclear->stop(); + } + } + + update_sounds_radio(); +} + +void TTrain::update_sounds_resonancenoise(sound_source &Sound) +{ + // frequency calculation + auto const normalizer{mvOccupied->Vmax * 0.01f}; + 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 (volume > 0.05) + { + Sound.pitch(frequency).gain(volume).play(sound_flags::exclusive | sound_flags::looping); + } + else + { + Sound.stop(); + } +} + +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 *= 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)); + } + + if (volume > 0.05) + { + Sound.pitch(frequency).gain(volume).play(sound_flags::exclusive | sound_flags::looping); + } + else + { + Sound.stop(); + } +} + +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); + 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); + radio_message_played |= true; + } + else + { + m_radiostop->stop(); + } + } + if (radio_message_played) + { + btLampkaRadioMessage.gain(m_radiovolume); + } +} + +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(); +} diff --git a/vehicle/train/TrainState.cpp b/vehicle/train/TrainState.cpp new file mode 100644 index 00000000..a6508680 --- /dev/null +++ b/vehicle/train/TrainState.cpp @@ -0,0 +1,915 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "vehicle/train/Train.h" + +#include "utilities/Globals.h" +#include "simulation/simulation.h" +#include "world/Event.h" +#include "simulation/simulationtime.h" +#include "model/Model3d.h" +#include "vehicle/Driver.h" +#include "vehicle/DynObj.h" +#include "world/mtable.h" +#include "application/application.h" +#include "rendering/renderer.h" +#include +#include +#include + +void TTrain::screen_entry::deserialize(cParser &Input) +{ + + 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 ,;[]")}; + + if (true == key.empty() || key == "}") + { + return false; + } + + 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; + } + + 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(); + + 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; +} + +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]; + } +}; + +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]; + } +}; + +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 &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::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::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::generictoggle0, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle1, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle2, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle3, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle4, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle5, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle6, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle7, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle8, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle9, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle10, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle11, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle12, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle13, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle14, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle15, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle16, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle17, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle18, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle19, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle20, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle21, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle22, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle23, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle24, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle25, &TTrain::OnCommand_generictoggle}, + {user_command::generictoggle26, &TTrain::OnCommand_generictoggle}, + {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}, +}; + +std::vector const TTrain::fPress_labels = { + + "ch1: ", "ch2: ", "ch3: ", "ch4: ", "ch5: ", "ch6: ", "ch7: ", "ch8: ", "ch9: ", "ch0: "}; + +TTrain::TTrain() +{ + + ShowNextCurrent = false; + // McZapkie-240302 - przyda sie do tachometru + fTachoVelocity = 0; + fTachoCount = 0; + fPPress = fNPress = 0; + + // asMessage=""; + pMechOffset = glm::dvec3(0, 0, 0); + fBlinkTimer = 0; + fHaslerTimer = 0; + DynamicSet(nullptr); // ustawia wszystkie mv* + //----- + pMechSittingPosition = glm::dvec3(0, 0, 0); // ABu: 180404 + 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; + } + bCompressors.clear(); + 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 j = 0; j < 7; ++j) + fPress[i][j] = 0.0; + bBrakes[i][0] = bBrakes[i][1] = false; + } +} + +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); + } + + DynamicSet(NewDynamicObject); + if (!e3d) + if (DynamicObject->Mechanik == nullptr) + return false; + + DynamicObject->MechInside = true; + + fMainRelayTimer = 0; // Hunter, do k...y nędzy, ustawiaj wartości początkowe zmiennych! + + iCabn = mvOccupied->CabOccupied > 0 ? 1 : mvOccupied->CabOccupied < 0 ? 2 : 0; + + { + Global.CurrentMaxTextureSize = Global.iMaxCabTextureSize; + + auto const filename{mvOccupied->TypeName + ".mmd"}; + LoadMMediaFile(filename); + InitializeCab(mvOccupied->CabOccupied, filename); + + Global.CurrentMaxTextureSize = Global.iMaxTextureSize; + + 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(); + } + + return true; +} + +std::shared_ptr TTrain::GetTrainState(dictionary_source const &Extraparameters) +{ + + if (mvOccupied == nullptr || mvControlled == 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("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)) + { + + 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); + + // 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_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()); + 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])); + 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; + while (p && in < 8) + { + if (p->MoverParameters->eimc[eimc_p_Pmax] > 1) + { + in++; + dict->insert("eimp_c" + std::to_string(in) + "_invno", p->MoverParameters->InvertersNo); + 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); + } + } + 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]); + } + } + // 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)}; + + 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; +} + +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(), + }; +}