16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-09-01 15:09:18 +02:00

refactor: train setup/sounds/state split

This commit is contained in:
jerrrrycho
2026-08-01 18:56:55 +02:00
parent 0c191d5f48
commit 019095a80e
5 changed files with 3577 additions and 3499 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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 <future>
#include <cmath>
#include <algorithm>
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<float>(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<float>(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<sound_source>(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();
}

View File

@@ -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 <future>
#include <cmath>
#include <algorithm>
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<std::string>(true, "\n\r\t ,;[]")};
if (true == key.empty() || key == "}")
{
return false;
}
if (key == "{")
{
script = Input.getToken<std::string>();
}
else if (key == "target:")
{
target = Input.getToken<std::string>();
}
else if (key == "updatetime:")
{
updatetime = Input.getToken<int>();
}
else if (key == "parameters:")
{
parameters = dictionary_source(Input.getToken<std::string>());
}
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<std::string>();
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<std::string> 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<dictionary_source> TTrain::GetTrainState(dictionary_source const &Extraparameters)
{
if (mvOccupied == nullptr || mvControlled == nullptr)
{
return nullptr;
}
auto dict = std::make_shared<dictionary_source>(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<TLSt *>(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<int>(simulation::Time.data().wHour));
dict->insert("minutes", static_cast<int>(simulation::Time.data().wMinute));
dict->insert("seconds", static_cast<int>(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<std::uint8_t>(iCabn),
btHaslerBrakes.GetValue(),
btHaslerCurrent.GetValue(),
mvOccupied->SecuritySystem.is_beeping(),
btLampkaHVoltageB.GetValue(),
fTachoVelocity,
static_cast<float>(mvOccupied->Compressor),
static_cast<float>(mvOccupied->PipePress),
static_cast<float>(mvOccupied->BrakePress),
static_cast<float>(mvPantographUnit->PantPress),
fHVoltage,
{fHCurrent[mvControlled->TrainType & dt_EZT ? 0 : 1], fHCurrent[2], fHCurrent[3]},
ggLVoltage.GetValue(),
mvOccupied->DistCounter,
static_cast<std::uint8_t>(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(),
};
}