From 5a85786a42169ef17c8bf68688eaaf1f2cebfcc5 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 20 Oct 2019 13:52:37 +0200 Subject: [PATCH] cab controls active state visualization support, cab control initialization on cab change fix --- Button.cpp | 1 + Gauge.cpp | 220 ++++++++++++++++++++++++++++++++++------------------- Gauge.h | 14 +++- Train.cpp | 185 +++++++++++++++++++++++++++----------------- Train.h | 7 +- 5 files changed, 276 insertions(+), 151 deletions(-) diff --git a/Button.cpp b/Button.cpp index 24644d24..1236f0b5 100644 --- a/Button.cpp +++ b/Button.cpp @@ -124,6 +124,7 @@ TButton::Turn( bool const State ) { } void TButton::Update( bool const Power ) { + // TODO: remove passing manually power state when LD is in place auto const state { Power && ( bData ? *bData : m_state ) }; diff --git a/Gauge.cpp b/Gauge.cpp index c135e18f..a283c3bc 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -27,11 +27,14 @@ TGauge::TGauge( sound_source const &Soundtemplate ) : { m_soundfxincrease = m_soundtemplate; m_soundfxdecrease = m_soundtemplate; + m_soundfxon = m_soundtemplate; + m_soundfxoff = m_soundtemplate; } -void TGauge::Init(TSubModel *Submodel, TGaugeAnimation Type, float Scale, float Offset, float Friction, float Value, float const Endvalue, float const Endscale, bool const Interpolatescale ) +void TGauge::Init(TSubModel *Submodel, TSubModel *Submodelon, TGaugeAnimation Type, float Scale, float Offset, float Friction, float Value, float const Endvalue, float const Endscale, bool const Interpolatescale ) { // ustawienie parametrów animacji submodelu SubModel = Submodel; + SubModelOn = Submodelon; m_value = Value; m_animation = Type; m_scale = Scale; @@ -41,38 +44,53 @@ void TGauge::Init(TSubModel *Submodel, TGaugeAnimation Type, float Scale, float m_endvalue = Endvalue; m_endscale = Endscale; - if( Submodel == nullptr ) { - // warunek na wszelki wypadek, gdyby się submodel nie podłączył - return; - } - if( m_animation == TGaugeAnimation::gt_Digital ) { - TSubModel *sm = SubModel->ChildGet(); - do { + auto *sm { ( SubModel ? SubModel->ChildGet() : nullptr ) }; + while( sm != nullptr ) { // pętla po submodelach potomnych i obracanie ich o kąt zależy od cyfry w (fValue) - if( sm->pName.size() ) { // musi mieć niepustą nazwę - if( sm->pName[ 0 ] >= '0' ) - if( sm->pName[ 0 ] <= '9' ) - sm->WillBeAnimated(); // wyłączenie optymalizacji + if( ( sm->pName.size() )// musi mieć niepustą nazwę + && ( std::isdigit( sm->pName[ 0 ] ) ) ) { + sm->WillBeAnimated(); // wyłączenie optymalizacji } sm = sm->NextGet(); - } while( sm ); + } + // do the same for the active version + sm = ( SubModelOn ? SubModelOn->ChildGet() : nullptr ); + while( sm != nullptr ) { + // pętla po submodelach potomnych i obracanie ich o kąt zależy od cyfry w (fValue) + if( ( sm->pName.size() )// musi mieć niepustą nazwę + && ( std::isdigit( sm->pName[ 0 ] ) ) ) { + sm->WillBeAnimated(); // wyłączenie optymalizacji + } + sm = sm->NextGet(); + } + } + else { + // wyłączenie ignowania jedynkowego transformu + // a banan może być z optymalizacją? + if( SubModel != nullptr ) { SubModel->WillBeAnimated(); } + if( SubModelOn != nullptr ) { SubModelOn->WillBeAnimated(); } } - else // a banan może być z optymalizacją? - Submodel->WillBeAnimated(); // wyłączenie ignowania jedynkowego transformu // pass submodel location to defined sounds auto const nulloffset { glm::vec3{} }; - auto const offset{ model_offset() }; - if( m_soundfxincrease.offset() == nulloffset ) { - m_soundfxincrease.offset( offset ); + auto const offset { model_offset() }; + { + std::vector soundfxs = { + &m_soundfxincrease, + &m_soundfxdecrease, + &m_soundfxon, + &m_soundfxoff + }; + for( auto *soundfx : soundfxs ) { + if( soundfx->offset() == nulloffset ) { + soundfx->offset( offset ); + } + } } - if( m_soundfxdecrease.offset() == nulloffset ) { - m_soundfxdecrease.offset( offset ); - } - for( auto &soundfxrecord : m_soundfxvalues ) { - if( soundfxrecord.second.offset() == nulloffset ) { - soundfxrecord.second.offset( offset ); + for( auto &soundfx : m_soundfxvalues ) { + if( soundfx.second.offset() == nulloffset ) { + soundfx.second.offset( offset ); } } }; @@ -131,6 +149,8 @@ void TGauge::Load( cParser &Parser, TDynamicObject const *Owner, double const mu // bind defined sounds with the button owner m_soundfxincrease.owner( Owner ); m_soundfxdecrease.owner( Owner ); + m_soundfxon.owner( Owner ); + m_soundfxoff.owner( Owner ); for( auto &soundfxrecord : m_soundfxvalues ) { soundfxrecord.second.owner( Owner ); } @@ -147,10 +167,25 @@ void TGauge::Load( cParser &Parser, TDynamicObject const *Owner, double const mu // got what we wanted, bail out break; } + // there's a possibility the default submodel was named with _off suffix + if( ( source != nullptr ) + && ( submodel = source->GetFromName( submodelname + "_off" ) ) != nullptr ) { + // got what we wanted, bail out + break; + } } if( submodel == nullptr ) { ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model(s) of \"" + Owner->name() + "\"", logtype::model ); } + // see if we can locate optional submodel for active state, with _on suffix + TSubModel *submodelon { nullptr }; + for( auto const *source : sources ) { + if( ( source != nullptr ) + && ( submodelon = source->GetFromName( submodelname + "_on" ) ) != nullptr ) { + // got what we wanted, bail out + break; + } + } std::map gaugetypes { { "rot", TGaugeAnimation::gt_Rotate }, @@ -166,7 +201,7 @@ void TGauge::Load( cParser &Parser, TDynamicObject const *Owner, double const mu lookup->second : TGaugeAnimation::gt_Unknown ); - Init( submodel, type, scale, offset, friction, 0, endvalue, endscale, interpolatescale ); + Init( submodel, submodelon, type, scale, offset, friction, 0, endvalue, endscale, interpolatescale ); // return md2 != nullptr; // true, gdy podany model zewnętrzny, a w kabinie nie było }; @@ -192,6 +227,12 @@ TGauge::Load_mapping( cParser &Input ) { else if( key == "sounddec:" ) { m_soundfxdecrease.deserialize( Input, sound_type::single ); } + else if( key == "soundon:" ) { + m_soundfxon.deserialize( Input, sound_type::single ); + } + else if( key == "soundoff:" ) { + m_soundfxoff.deserialize( Input, sound_type::single ); + } else if( key.compare( 0, std::min( key.size(), 5 ), "sound" ) == 0 ) { // sounds assigned to specific gauge values, defined by key soundFoo: where Foo = value auto const indexstart { key.find_first_of( "-1234567890" ) }; @@ -244,13 +285,11 @@ TGauge::UpdateValue( float fNewDesired, sound_source *Fallbacksound ) { // ...and if there isn't any, fall back on the basic set... auto const currentvalue = GetValue(); // HACK: crude way to discern controls with continuous and quantized value range - if( ( currentvalue < fNewDesired ) - && ( false == m_soundfxincrease.empty() ) ) { + if( currentvalue < fNewDesired ) { // shift up m_soundfxincrease.play( m_soundtype ); } - else if( ( currentvalue > fNewDesired ) - && ( false == m_soundfxdecrease.empty() ) ) { + else if( currentvalue > fNewDesired ) { // shift down m_soundfxdecrease.play( m_soundtype ); } @@ -276,8 +315,9 @@ float TGauge::GetDesiredValue() const { return m_targetvalue; } -void TGauge::Update() { - +void TGauge::Update( bool const Power ) { + // update value + // TODO: remove passing manually power state when LD is in place if( m_value != m_targetvalue ) { float dt = Timer::GetDeltaTime(); if( ( m_friction > 0 ) && ( dt < 0.5 * m_friction ) ) { @@ -292,55 +332,25 @@ void TGauge::Update() { m_value = m_targetvalue; } } - if( SubModel ) - { // warunek na wszelki wypadek, gdyby się submodel nie podłączył - switch (m_animation) { - case TGaugeAnimation::gt_Rotate: { - SubModel->SetRotate( float3( 0, 1, 0 ), GetScaledValue() * 360.0 ); - break; - } - case TGaugeAnimation::gt_Move: { - SubModel->SetTranslate( float3( 0, 0, GetScaledValue() ) ); - break; - } - case TGaugeAnimation::gt_Wiper: { - auto const scaledvalue { GetScaledValue() }; - SubModel->SetRotate( float3( 0, 1, 0 ), scaledvalue * 360.0 ); - auto *sm = SubModel->ChildGet(); - if( sm ) { - sm->SetRotate( float3( 0, 1, 0 ), scaledvalue * 360.0 ); - sm = sm->ChildGet(); - if( sm ) - sm->SetRotate( float3( 0, 1, 0 ), scaledvalue * 360.0 ); - } - break; - } - case TGaugeAnimation::gt_Digital: { - // Ra 2014-07: licznik cyfrowy - auto *sm = SubModel->ChildGet(); -/* std::string n = FormatFloat( "0000000000", floor( fValue ) ); // na razie tak trochę bez sensu -*/ std::string n( "000000000" + std::to_string( static_cast( std::floor( GetScaledValue() ) ) ) ); - if( n.length() > 10 ) { n.erase( 0, n.length() - 10 ); } // also dumb but should work for now - do { // pętla po submodelach potomnych i obracanie ich o kąt zależy od cyfry w (fValue) - if( sm->pName.size() ) { - // musi mieć niepustą nazwę - if( ( sm->pName[ 0 ] >= '0' ) - && ( sm->pName[ 0 ] <= '9' ) ) { - - sm->SetRotate( - float3( 0, 1, 0 ), - -36.0 * ( n[ '0' + 9 - sm->pName[ 0 ] ] - '0' ) ); - } - } - sm = sm->NextGet(); - } while( sm ); - break; - } - default: { - break; - } + // update submodel visibility + auto const state { Power && ( m_stateinput ? *m_stateinput : false ) }; + if( state != m_state ) { + // on state change play assigned sound + if( true == state ) { m_soundfxon.play(); } + else { m_soundfxoff.play(); } + } + m_state = state; + // toggle submodel visibility only if the active state submodel is present, + // keep the default model always visible otherwise + if( SubModelOn != nullptr ) { + SubModelOn->iVisible = m_state; + if( SubModel != nullptr ) { + SubModel->iVisible = ( !m_state ); } } + // update submodel animations + UpdateAnimation( SubModel ); + UpdateAnimation( SubModelOn ); }; void TGauge::AssignFloat(float *fValue) @@ -393,6 +403,11 @@ void TGauge::UpdateValue() } }; +void TGauge::AssignState( bool const *State ) { + + m_stateinput = State; +} + float TGauge::GetScaledValue() const { return ( @@ -407,6 +422,55 @@ float TGauge::GetScaledValue() const { + m_offset ); } +void +TGauge::UpdateAnimation( TSubModel *Submodel ) { + + if( Submodel == nullptr ) { return; } + + switch (m_animation) { + case TGaugeAnimation::gt_Rotate: { + Submodel->SetRotate( float3( 0, 1, 0 ), GetScaledValue() * 360.0 ); + break; + } + case TGaugeAnimation::gt_Move: { + Submodel->SetTranslate( float3( 0, 0, GetScaledValue() ) ); + break; + } + case TGaugeAnimation::gt_Wiper: { + auto const scaledvalue { GetScaledValue() }; + Submodel->SetRotate( float3( 0, 1, 0 ), scaledvalue * 360.0 ); + auto *sm = Submodel->ChildGet(); + if( sm ) { + sm->SetRotate( float3( 0, 1, 0 ), scaledvalue * 360.0 ); + sm = sm->ChildGet(); + if( sm ) + sm->SetRotate( float3( 0, 1, 0 ), scaledvalue * 360.0 ); + } + break; + } + case TGaugeAnimation::gt_Digital: { + // Ra 2014-07: licznik cyfrowy + auto *sm = Submodel->ChildGet(); +/* std::string n = FormatFloat( "0000000000", floor( fValue ) ); // na razie tak trochę bez sensu +*/ std::string n( "000000000" + std::to_string( static_cast( std::floor( GetScaledValue() ) ) ) ); + if( n.length() > 10 ) { n.erase( 0, n.length() - 10 ); } // also dumb but should work for now + do { // pętla po submodelach potomnych i obracanie ich o kąt zależy od cyfry w (fValue) + if( ( sm->pName.size() ) + && ( std::isdigit( sm->pName[ 0 ] ) ) ) { + sm->SetRotate( + float3( 0, 1, 0 ), + -36.0 * ( n[ '0' + 9 - sm->pName[ 0 ] ] - '0' ) ); + } + sm = sm->NextGet(); + } while( sm ); + break; + } + default: { + break; + } + } +} + // returns offset of submodel associated with the button from the model centre glm::vec3 TGauge::model_offset() const { diff --git a/Gauge.h b/Gauge.h index 6d36b67c..f14bd129 100644 --- a/Gauge.h +++ b/Gauge.h @@ -38,24 +38,26 @@ public: inline void Clear() { *this = TGauge(); } - void Init(TSubModel *Submodel, TGaugeAnimation Type, float Scale = 1, float Offset = 0, float Friction = 0, float Value = 0, float const Endvalue = -1.0, float const Endscale = -1.0, bool const Interpolate = false ); + void Init(TSubModel *Submodel, TSubModel *Submodelon, TGaugeAnimation Type, float Scale = 1, float Offset = 0, float Friction = 0, float Value = 0, float const Endvalue = -1.0, float const Endscale = -1.0, bool const Interpolate = false ); void Load(cParser &Parser, TDynamicObject const *Owner, double const mul = 1.0); void UpdateValue( float fNewDesired ); void UpdateValue( float fNewDesired, sound_source &Fallbacksound ); void PutValue(float fNewDesired); float GetValue() const; float GetDesiredValue() const; - void Update(); + void Update( bool const Power = true ); void AssignFloat(float *fValue); void AssignDouble(double *dValue); void AssignInt(int *iValue); void AssignBool(bool *bValue); void UpdateValue(); + void AssignState( bool const *State ); // returns offset of submodel associated with the button from the model centre glm::vec3 model_offset() const; TGaugeType type() const; // members - TSubModel *SubModel { nullptr }; // McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie + TSubModel *SubModel { nullptr }, // McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie + *SubModelOn { nullptr }; // optional submodel visible when the state input is set private: // methods @@ -66,6 +68,8 @@ private: UpdateValue( float fNewDesired, sound_source *Fallbacksound ); float GetScaledValue() const; + void + UpdateAnimation( TSubModel *Submodel ); // members TGaugeAnimation m_animation { TGaugeAnimation::gt_Unknown }; // typ ruchu @@ -86,8 +90,12 @@ private: int *iData; bool *bData; }; + bool m_state { false }; // visibility of the control's submodel(s); false : default, true: active + bool const *m_stateinput { nullptr }; // bound variable determining visibility of the control's submodel(s) int m_soundtype { 0 }; // toggle between exclusive and multiple sound generation sound_source m_soundtemplate { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // shared properties for control's sounds + sound_source m_soundfxon { m_soundtemplate }; // sound associated with switching the control to active state + sound_source m_soundfxoff { m_soundtemplate }; // sound associated with switching the control to default state sound_source m_soundfxincrease { m_soundtemplate }; // sound associated with increasing control's value sound_source m_soundfxdecrease { m_soundtemplate }; // sound associated with decreasing control's value std::map m_soundfxvalues; // sounds associated with specific values diff --git a/Train.cpp b/Train.cpp index 06676a16..660550dd 100644 --- a/Train.cpp +++ b/Train.cpp @@ -42,10 +42,8 @@ extern user_command command; void control_mapper::insert( TGauge const &Gauge, std::string const &Label ) { - auto const submodel = Gauge.SubModel; - if( submodel != nullptr ) { - m_controlnames.emplace( submodel, Label ); - } + if( Gauge.SubModel != nullptr ) { m_controlnames.emplace( Gauge.SubModel, Label ); } + if( Gauge.SubModelOn != nullptr ) { m_controlnames.emplace( Gauge.SubModelOn, Label ); } } std::string @@ -2179,6 +2177,8 @@ void TTrain::OnCommand_pantographlowerrear( TTrain *Train, command_data const &C void TTrain::OnCommand_pantographlowerall( TTrain *Train, command_data const &Command ) { + if( Command.action == GLFW_REPEAT ) { return; } + if( ( Train->ggPantAllDownButton.SubModel == nullptr ) && ( Train->ggPantSelectedDownButton.SubModel == nullptr ) ) { // TODO: expand definition of cab controls so we can know if the control is present without testing for presence of 3d switch @@ -2187,29 +2187,64 @@ void TTrain::OnCommand_pantographlowerall( TTrain *Train, command_data const &Co } return; } - if( Command.action == GLFW_PRESS ) { - // press the button - // since we're just lowering all potential pantographs we don't need to test for state and effect - // front... - Train->mvControlled->PantFrontSP = false; - Train->mvControlled->PantFront( false ); - // ...and rear - Train->mvControlled->PantRearSP = false; - Train->mvControlled->PantRear( false ); - // visual feedback - if( Train->ggPantAllDownButton.SubModel ) - Train->ggPantAllDownButton.UpdateValue( 1.0, Train->dsbSwitch ); - if( Train->ggPantSelectedDownButton.SubModel ) { - Train->ggPantSelectedDownButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( Train->ggPantAllDownButton.type() == TGaugeType::push ) { + // impulse switch + if( Command.action == GLFW_PRESS ) { + // press the button + // since we're just lowering all potential pantographs we don't need to test for state and effect + // front... + Train->mvControlled->PantFrontSP = false; + Train->mvControlled->PantFront( false ); + // ...and rear + Train->mvControlled->PantRearSP = false; + Train->mvControlled->PantRear( false ); + // visual feedback + if( Train->ggPantAllDownButton.SubModel ) + Train->ggPantAllDownButton.UpdateValue( 1.0, Train->dsbSwitch ); + if( Train->ggPantSelectedDownButton.SubModel ) { + Train->ggPantSelectedDownButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + } + else if( Command.action == GLFW_RELEASE ) { + // release the button + // visual feedback + if( Train->ggPantAllDownButton.SubModel ) + Train->ggPantAllDownButton.UpdateValue( 0.0 ); + if( Train->ggPantSelectedDownButton.SubModel ) { + Train->ggPantSelectedDownButton.UpdateValue( 0.0 ); + } } } - else if( Command.action == GLFW_RELEASE ) { - // release the button - // visual feedback - if( Train->ggPantAllDownButton.SubModel ) - Train->ggPantAllDownButton.UpdateValue( 0.0 ); - if( Train->ggPantSelectedDownButton.SubModel ) { - Train->ggPantSelectedDownButton.UpdateValue( 0.0 ); + else { + // two-state switch, only cares about press events + if( Command.action == GLFW_PRESS ) { + // HACK: use current switch position to determine (intended) state + if( Train->ggPantAllDownButton.GetDesiredValue() < 0.05 ) { + // currenty inactive, activate it + // since we're just lowering all potential pantographs we don't need to test for state and effect + // front... + Train->mvControlled->PantFrontSP = false; + Train->mvControlled->PantFront( false ); + // ...and rear + Train->mvControlled->PantRearSP = false; + Train->mvControlled->PantRear( false ); + // visual feedback + if( Train->ggPantAllDownButton.SubModel ) + Train->ggPantAllDownButton.UpdateValue( 1.0, Train->dsbSwitch ); + if( Train->ggPantSelectedDownButton.SubModel ) { + Train->ggPantSelectedDownButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + } + else { + // currently active, move it back to neutral position + // visual feedback + if( Train->ggPantAllDownButton.SubModel ) + Train->ggPantAllDownButton.UpdateValue( 0.0 ); + if( Train->ggPantSelectedDownButton.SubModel ) { + Train->ggPantSelectedDownButton.UpdateValue( 0.0 ); + } + } } } } @@ -5834,8 +5869,7 @@ bool TTrain::Update( double const Deltatime ) ((mvControlled->EngineType == TEngineType::ElectricSeriesMotor) || (mvControlled->TrainType == dt_EZT)) && (DynamicObject->Controller == Humandriver)) // hunter-110212: poprawka dla EZT - { // hunter-091012: poprawka (zmiana warunku z CompressorPower /rozne od - // 0/ na /rowne 1/) + { // hunter-091012: poprawka (zmiana warunku z CompressorPower /rozne od 0/ na /rowne 1/) if (fConverterTimer < fConverterPrzekaznik) { mvControlled->ConvOvldFlag = true; @@ -5851,6 +5885,7 @@ bool TTrain::Update( double const Deltatime ) else fConverterTimer = 0; //------------------ + auto const lowvoltagepower { mvControlled->Battery || mvControlled->ConverterFlag }; // youBy - prad w drugim czlonie: galaz lub calosc { @@ -5903,7 +5938,7 @@ bool TTrain::Update( double const Deltatime ) ggClockHInd.Update(); } - Cabine[iCabn].Update( mvControlled->Battery || mvControlled->ConverterFlag ); // nowy sposób ustawienia animacji + Cabine[iCabn].Update( lowvoltagepower ); // nowy sposób ustawienia animacji if (ggZbS.SubModel) { ggZbS.UpdateValue(mvOccupied->Handle->GetCP()); @@ -6012,7 +6047,7 @@ bool TTrain::Update( double const Deltatime ) btLampkaNadmSil.Turn( false ); } - if (mvControlled->Battery || mvControlled->ConverterFlag) { + if( true == lowvoltagepower ) { // alerter test if( true == CAflag ) { if( ggSecurityResetButton.GetDesiredValue() > 0.95 ) { @@ -6199,7 +6234,7 @@ bool TTrain::Update( double const Deltatime ) btLampkaMalfunction.Turn( mvControlled->dizel_heat.PA ); btLampkaMotorBlowers.Turn( ( mvControlled->MotorBlowers[ end::front ].is_active ) && ( mvControlled->MotorBlowers[ end::rear ].is_active ) ); btLampkaCoolingFans.Turn( mvControlled->RventRot > 1.0 ); - btLampkaTempomat.Turn( mvControlled->ScndCtrlPos > 0 ); + btLampkaTempomat.Turn( mvOccupied->SpeedCtrlUnit.IsActive ); btLampkaDistanceCounter.Turn( m_distancecounter >= 0.f ); // universal devices state indicators for( auto idx = 0; idx < btUniversals.size(); ++idx ) { @@ -6282,32 +6317,32 @@ bool TTrain::Update( double const Deltatime ) (mvOccupied->ActiveCab < 0)) tmp = DynamicObject->PrevConnected(); - if (tmp) - if ( mvControlled->Battery || mvControlled->ConverterFlag ) { + if( tmp ) { + if( lowvoltagepower ) { - auto const *mover { tmp->MoverParameters }; + auto const *mover{ tmp->MoverParameters }; btLampkaWylSzybkiB.Turn( mover->Mains ); btLampkaWylSzybkiBOff.Turn( ( false == mover->Mains ) - && ( mover->MainsInitTimeCountdown <= 0.0 ) - /*&& ( fHVoltage != 0.0 )*/ ); + && ( mover->MainsInitTimeCountdown <= 0.0 ) + /*&& ( fHVoltage != 0.0 )*/ ); - btLampkaOporyB.Turn(mover->ResistorsFlagCheck()); + btLampkaOporyB.Turn( mover->ResistorsFlagCheck() ); btLampkaBezoporowaB.Turn( ( true == mover->ResistorsFlagCheck() ) - || ( mover->MainCtrlActualPos == 0 ) ); // do EU04 + || ( mover->MainCtrlActualPos == 0 ) ); // do EU04 if( ( mover->StLinFlag ) - || ( mover->BrakePress > 2.0 ) - || ( mover->PipePress < 0.36 ) ) { + || ( mover->BrakePress > 2.0 ) + || ( mover->PipePress < 0.36 ) ) { btLampkaStycznB.Turn( false ); } else if( mover->BrakePress < 1.0 ) { btLampkaStycznB.Turn( true ); // mozna prowadzic rozruch } // hunter-271211: sygnalizacja poslizgu w pierwszym pojezdzie, gdy wystapi w drugim - btLampkaPoslizg.Turn(mover->SlippingWheels); + btLampkaPoslizg.Turn( mover->SlippingWheels ); btLampkaSprezarkaB.Turn( mover->CompressorFlag ); // mutopsitka dziala btLampkaSprezarkaBOff.Turn( false == mover->CompressorFlag ); @@ -6348,6 +6383,7 @@ bool TTrain::Update( double const Deltatime ) btLampkaHVoltageB.Turn( false ); btLampkaMalfunctionB.Turn( false ); } + } } // McZapkie-080602: obroty (albo translacje) regulatorow if( ggJointCtrl.SubModel != nullptr ) { @@ -6408,7 +6444,7 @@ bool TTrain::Update( double const Deltatime ) dsbNastawnikBocz ); ggScndCtrl.Update(); } - ggScndCtrlButton.Update(); + ggScndCtrlButton.Update( lowvoltagepower ); ggDistanceCounterButton.Update(); if (ggDirKey.SubModel) { if (mvControlled->TrainType != dt_EZT) @@ -6600,12 +6636,12 @@ bool TTrain::Update( double const Deltatime ) } ggHelperButton.Update(); - ggSpeedControlIncreaseButton.Update(); - ggSpeedControlDecreaseButton.Update(); - ggSpeedControlPowerIncreaseButton.Update(); - ggSpeedControlPowerDecreaseButton.Update(); + ggSpeedControlIncreaseButton.Update( lowvoltagepower ); + ggSpeedControlDecreaseButton.Update( lowvoltagepower ); + ggSpeedControlPowerIncreaseButton.Update( lowvoltagepower ); + ggSpeedControlPowerDecreaseButton.Update( lowvoltagepower ); for (auto &speedctrlbutton : ggSpeedCtrlButtons) { - speedctrlbutton.Update(); + speedctrlbutton.Update( lowvoltagepower ); } for( auto &universal : ggUniversals ) { @@ -8102,7 +8138,7 @@ void TTrain::set_cab_controls( int const Cab ) { // lights ggLightsButton.PutValue( mvOccupied->LightsPos - 1 ); - auto const vehicleend { cab_to_end() }; + auto const vehicleend { cab_to_end( Cab ) }; if( ( DynamicObject->iLights[ vehicleend ] & light::headlight_left ) != 0 ) { ggLeftLightButton.PutValue( 1.f ); @@ -8559,7 +8595,6 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "cablight_sw:", ggCabLightButton }, { "cablightdim_sw:", ggCabLightDimButton }, { "battery_sw:", ggBatteryButton }, - { "tempomat_sw:", ggScndCtrlButton }, { "distancecounter_sw:", ggDistanceCounterButton }, { "universal0:", ggUniversals[ 0 ] }, { "universal1:", ggUniversals[ 1 ] }, @@ -8570,30 +8605,44 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "universal6:", ggUniversals[ 6 ] }, { "universal7:", ggUniversals[ 7 ] }, { "universal8:", ggUniversals[ 8 ] }, - { "universal9:", ggUniversals[ 9 ] }, - { "speedinc_bt:", ggSpeedControlIncreaseButton }, - { "speeddec_bt:", ggSpeedControlDecreaseButton }, - { "speedctrlpowerinc_bt:", ggSpeedControlPowerIncreaseButton }, - { "speedctrlpowerdec_bt:", ggSpeedControlPowerDecreaseButton }, - { "speedbutton0:", ggSpeedCtrlButtons[ 0 ] }, - { "speedbutton1:", ggSpeedCtrlButtons[ 1 ] }, - { "speedbutton2:", ggSpeedCtrlButtons[ 2 ] }, - { "speedbutton3:", ggSpeedCtrlButtons[ 3 ] }, - { "speedbutton4:", ggSpeedCtrlButtons[ 4 ] }, - { "speedbutton5:", ggSpeedCtrlButtons[ 5 ] }, - { "speedbutton6:", ggSpeedCtrlButtons[ 6 ] }, - { "speedbutton7:", ggSpeedCtrlButtons[ 7 ] }, - { "speedbutton8:", ggSpeedCtrlButtons[ 8 ] }, - { "speedbutton9:", ggSpeedCtrlButtons[ 9 ] } - }; + { "universal9:", ggUniversals[ 9 ] } + }; { - auto lookup = gauges.find( Label ); + auto const lookup { gauges.find( Label ) }; if( lookup != gauges.end() ) { lookup->second.Load( Parser, DynamicObject ); m_controlmapper.insert( lookup->second, lookup->first ); return true; } } + // TODO: move viable gauges to the state driven array + std::unordered_map > const stategauges = { + { "tempomat_sw:", { ggScndCtrlButton, &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 } } + }; + { + 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 }, @@ -8803,9 +8852,9 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { if( DynamicObject->mdKabina ) { // McZapkie-300302: zegarek - ggClockSInd.Init( DynamicObject->mdKabina->GetFromName( "ClockShand" ), TGaugeAnimation::gt_Rotate, 1.0 / 60.0 ); - ggClockMInd.Init( DynamicObject->mdKabina->GetFromName( "ClockMhand" ), TGaugeAnimation::gt_Rotate, 1.0 / 60.0 ); - ggClockHInd.Init( DynamicObject->mdKabina->GetFromName( "ClockHhand" ), TGaugeAnimation::gt_Rotate, 1.0 / 12.0 ); + 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 ); } } } diff --git a/Train.h b/Train.h index cc5b949d..e4a20388 100644 --- a/Train.h +++ b/Train.h @@ -158,11 +158,14 @@ class TTrain { void update_sounds_runningnoise( sound_source &Sound ); void update_sounds_radio(); inline - end cab_to_end() const { + end cab_to_end( int const End ) const { return ( - iCabn == 2 ? + End == 2 ? end::rear : end::front ); } + inline + end cab_to_end() const { + return cab_to_end( iCabn ); } // command handlers // 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