From bb87a63eed9d23e44a54cf7dbb0fba07775f5ad0 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 18 Apr 2018 15:04:04 +0200 Subject: [PATCH] varying scale cab control animation types, basic shunt mode power slider cab control, minor ai logic tweaks, minor bug fixes --- Driver.cpp | 22 +++- EU07.cpp | 4 +- Gauge.cpp | 275 ++++++++++++++++++++++++--------------------- Gauge.h | 38 ++++--- McZapkie/Mover.cpp | 23 ++-- Train.cpp | 20 +++- Train.h | 1 + 7 files changed, 224 insertions(+), 159 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 1c2522ef..6af63776 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2223,13 +2223,15 @@ bool TController::PrepareEngine() voltfront = true; } } + auto workingtemperature { true }; if (AIControllFlag) { // część wykonawcza dla sterowania przez komputer mvOccupied->BatterySwitch( true ); if( ( mvControlling->EngineType == DieselElectric ) || ( mvControlling->EngineType == DieselEngine ) ) { mvControlling->OilPumpSwitch( true ); - if( true == UpdateHeating() ) { + workingtemperature = UpdateHeating(); + if( true == workingtemperature ) { mvControlling->FuelPumpSwitch( true ); } } @@ -2339,7 +2341,7 @@ bool TController::PrepareEngine() else OK = false; - OK = OK && (mvOccupied->ActiveDir != 0) && (mvControlling->CompressorAllow); + OK = OK && (mvOccupied->ActiveDir != 0) && (mvControlling->CompressorAllow) && (workingtemperature); if (OK) { if (eStopReason == stopSleep) // jeśli dotychczas spał @@ -2378,6 +2380,7 @@ bool TController::ReleaseEngine() mvControlling->PantFront(false); mvControlling->PantRear(false); } + // line breaker OK = mvControlling->MainSwitch(false); } else @@ -2410,7 +2413,20 @@ bool TController::ReleaseEngine() eAction = actSleep; //śpi (wygaszony) if (AIControllFlag) { - Lights(0, 0); // gasimy światła + if( ( mvControlling->EngineType == DieselElectric ) + || ( mvControlling->EngineType == DieselEngine ) ) { + // heating/cooling subsystem + mvControlling->WaterHeaterSwitch( false ); + // optionally turn off the water pump as well + if( mvControlling->WaterPump.start_type != start::battery ) { + mvControlling->WaterPumpSwitch( false ); + } + // fuel and oil subsystems + mvControlling->FuelPumpSwitch( false ); + mvControlling->OilPumpSwitch( false ); + } + // gasimy światła + Lights(0, 0); mvOccupied->BatterySwitch(false); } OrderNext(Wait_for_orders); //żeby nie próbował coś robić dalej diff --git a/EU07.cpp b/EU07.cpp index f1f1c90b..ff276ba6 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -412,7 +412,9 @@ int main(int argc, char *argv[]) return -1; } - audio::renderer.init(); + if( Global.bSoundEnabled ) { + Global.bSoundEnabled &= audio::renderer.init(); + } input::Keyboard.init(); input::Mouse.init(); diff --git a/Gauge.cpp b/Gauge.cpp index 75bf2e05..cb1b8440 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -21,46 +21,54 @@ http://mozilla.org/MPL/2.0/. #include "logs.h" #include "renderer.h" -void TGauge::Init(TSubModel *NewSubModel, TGaugeType eNewType, double fNewScale, double fNewOffset, double fNewFriction, double fNewValue) +void TGauge::Init(TSubModel *Submodel, TGaugeType Type, float Scale, float Offset, float Friction, float Value, float const Endvalue, float const Endscale, bool const Interpolatescale ) { // ustawienie parametrów animacji submodelu - if (NewSubModel) { - // warunek na wszelki wypadek, gdyby się submodel nie podłączył - fFriction = fNewFriction; - fValue = fNewValue; - fOffset = fNewOffset; - fScale = fNewScale; - SubModel = NewSubModel; - eType = eNewType; - if (eType == gt_Digital) { + SubModel = Submodel; + m_value = Value; + m_type = Type; + m_scale = Scale; + m_offset = Offset; + m_friction = Friction; + m_interpolatescale = Interpolatescale; + m_endvalue = Endvalue; + m_endscale = Endscale; - TSubModel *sm = SubModel->ChildGet(); - 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') - if (sm->pName[0] <= '9') - sm->WillBeAnimated(); // wyłączenie optymalizacji - } - sm = sm->NextGet(); - } while (sm); - } - else // a banan może być z optymalizacją? - NewSubModel->WillBeAnimated(); // wyłączenie ignowania jedynkowego transformu - // pass submodel location to defined sounds - auto const offset { model_offset() }; - m_soundfxincrease.offset( offset ); - m_soundfxdecrease.offset( offset ); - for( auto &soundfxrecord : m_soundfxvalues ) { - soundfxrecord.second.offset( offset ); - } + if( Submodel == nullptr ) { + // warunek na wszelki wypadek, gdyby się submodel nie podłączył + return; + } + + if( m_type == gt_Digital ) { + + TSubModel *sm = SubModel->ChildGet(); + 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' ) + if( sm->pName[ 0 ] <= '9' ) + sm->WillBeAnimated(); // wyłączenie optymalizacji + } + sm = sm->NextGet(); + } while( sm ); + } + else // a banan może być z optymalizacją? + Submodel->WillBeAnimated(); // wyłączenie ignowania jedynkowego transformu + // pass submodel location to defined sounds + auto const offset{ model_offset() }; + m_soundfxincrease.offset( offset ); + m_soundfxdecrease.offset( offset ); + for( auto &soundfxrecord : m_soundfxvalues ) { + soundfxrecord.second.offset( offset ); } }; bool TGauge::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *md1, TModel3d *md2, double mul ) { std::string submodelname, gaugetypename; - double scale, offset, friction; + float scale, endscale, endvalue, offset, friction; + endscale = -1; + endvalue = -1; + bool interpolatescale { false }; Parser.getTokens(); if( Parser.peek() != "{" ) { @@ -72,6 +80,14 @@ bool TGauge::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *md1, >> scale >> offset >> friction; + if( ( gaugetypename == "rotvar" ) + || ( gaugetypename == "movvar" ) ) { + interpolatescale = true; + Parser.getTokens( 2, false ); + Parser + >> endvalue + >> endscale; + } } else { // new, block type config @@ -83,6 +99,14 @@ bool TGauge::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *md1, >> scale >> offset >> friction; + if( ( gaugetypename == "rotvar" ) + || ( gaugetypename == "movvar" ) ) { + interpolatescale = true; + Parser.getTokens( 2, false ); + Parser + >> endvalue + >> endscale; + } // new, variable length section while( true == Load_mapping( Parser ) ) { ; // all work done by while() @@ -97,11 +121,10 @@ bool TGauge::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *md1, } scale *= mul; - TSubModel *submodel = md1->GetFromName( submodelname ); - if( scale == 0.0 ) { - ErrorLog( "Bad model: scale of 0.0 defined for sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\". Forcing scale of 1.0 to prevent division by 0", logtype::model ); - scale = 1.0; + if( interpolatescale ) { + endscale *= mul; } + TSubModel *submodel = md1->GetFromName( submodelname ); if (submodel) // jeśli nie znaleziony md2 = nullptr; // informacja, że znaleziony else if (md2) // a jest podany drugi model (np. zewnętrzny) @@ -111,7 +134,10 @@ bool TGauge::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *md1, } std::map gaugetypes { + { "rot", gt_Rotate }, + { "rotvar", gt_Rotate }, { "mov", gt_Move }, + { "movvar", gt_Move }, { "wip", gt_Wiper }, { "dgt", gt_Digital } }; @@ -119,8 +145,9 @@ bool TGauge::Load( cParser &Parser, TDynamicObject const *Owner, TModel3d *md1, auto const type = ( lookup != gaugetypes.end() ? lookup->second : - gt_Rotate ); - Init(submodel, type, scale, offset, friction); + gt_Unknown ); + + Init( submodel, type, scale, offset, friction, 0, endvalue, endscale, interpolatescale ); return md2 != nullptr; // true, gdy podany model zewnętrzny, a w kabinie nie było }; @@ -151,51 +178,27 @@ TGauge::Load_mapping( cParser &Input ) { return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized } -void TGauge::PermIncValue(double fNewDesired) -{ - fDesiredValue = fDesiredValue + fNewDesired * fScale + fOffset; - if (fDesiredValue - fOffset > 360 / fScale) - { - fDesiredValue = fDesiredValue - (360 / fScale); - fValue = fValue - (360 / fScale); - } -}; - -void TGauge::IncValue(double fNewDesired) -{ // używane tylko dla uniwersali - fDesiredValue = fDesiredValue + fNewDesired * fScale + fOffset; - if (fDesiredValue > fScale + fOffset) - fDesiredValue = fScale + fOffset; -}; - -void TGauge::DecValue(double fNewDesired) -{ // używane tylko dla uniwersali - fDesiredValue = fDesiredValue - fNewDesired * fScale + fOffset; - if (fDesiredValue < 0) - fDesiredValue = 0; -}; - void -TGauge::UpdateValue( double fNewDesired ) { +TGauge::UpdateValue( float fNewDesired ) { return UpdateValue( fNewDesired, nullptr ); } void -TGauge::UpdateValue( double fNewDesired, sound_source &Fallbacksound ) { +TGauge::UpdateValue( float fNewDesired, sound_source &Fallbacksound ) { return UpdateValue( fNewDesired, &Fallbacksound ); } // ustawienie wartości docelowej. plays provided fallback sound, if no sound was defined in the control itself void -TGauge::UpdateValue( double fNewDesired, sound_source *Fallbacksound ) { +TGauge::UpdateValue( float fNewDesired, sound_source *Fallbacksound ) { auto const desiredtimes100 = static_cast( std::round( 100.0 * fNewDesired ) ); - if( static_cast( std::round( 100.0 * ( fDesiredValue - fOffset ) / fScale ) ) == desiredtimes100 ) { + if( desiredtimes100 == static_cast( 100.0 * m_targetvalue ) ) { return; } - fDesiredValue = fNewDesired * fScale + fOffset; + m_targetvalue = fNewDesired; // if there's any sound associated with new requested value, play it // check value-specific table first... if( desiredtimes100 % 100 == 0 ) { @@ -224,115 +227,137 @@ TGauge::UpdateValue( double fNewDesired, sound_source *Fallbacksound ) { } }; -void TGauge::PutValue(double fNewDesired) +void TGauge::PutValue(float fNewDesired) { // McZapkie-281102: natychmiastowe wpisanie wartosci - fDesiredValue = fNewDesired * fScale + fOffset; - fValue = fDesiredValue; + m_targetvalue = fNewDesired; + m_value = m_targetvalue; }; -double TGauge::GetValue() const { +float TGauge::GetValue() const { // we feed value in range 0-1 so we should be getting it reported in the same range - return ( fValue - fOffset ) / fScale; + return m_value; } -double TGauge::GetDesiredValue() const { +float TGauge::GetDesiredValue() const { // we feed value in range 0-1 so we should be getting it reported in the same range - return ( fDesiredValue - fOffset ) / fScale; + return m_targetvalue; } void TGauge::Update() { - if( fValue != fDesiredValue ) { + if( m_value != m_targetvalue ) { float dt = Timer::GetDeltaTime(); - if( ( fFriction > 0 ) && ( dt < 0.5 * fFriction ) ) { + if( ( m_friction > 0 ) && ( dt < 0.5 * m_friction ) ) { // McZapkie-281102: zabezpieczenie przed oscylacjami dla dlugich czasow - fValue += dt * ( fDesiredValue - fValue ) / fFriction; - if( std::abs( fDesiredValue - fValue ) <= 0.0001 ) { + m_value += dt * ( m_targetvalue - m_value ) / m_friction; + if( std::abs( m_targetvalue - m_value ) <= 0.0001 ) { // close enough, we can stop updating the model - fValue = fDesiredValue; // set it exactly as requested just in case it matters + m_value = m_targetvalue; // set it exactly as requested just in case it matters } } else { - fValue = fDesiredValue; + m_value = m_targetvalue; } } if( SubModel ) { // warunek na wszelki wypadek, gdyby się submodel nie podłączył - TSubModel *sm; - switch (eType) - { - case gt_Rotate: - SubModel->SetRotate(float3(0, 1, 0), fValue * 360.0); - break; - case gt_Move: - SubModel->SetTranslate(float3(0, 0, fValue)); - break; - case gt_Wiper: - SubModel->SetRotate(float3(0, 1, 0), fValue * 360.0); - sm = SubModel->ChildGet(); - if (sm) - { - sm->SetRotate(float3(0, 1, 0), fValue * 360.0); - sm = sm->ChildGet(); - if (sm) - sm->SetRotate(float3(0, 1, 0), fValue * 360.0); + switch (m_type) { + case gt_Rotate: { + SubModel->SetRotate( float3( 0, 1, 0 ), GetScaledValue() * 360.0 ); + break; } - break; - case gt_Digital: // Ra 2014-07: licznik cyfrowy - 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( fValue ) ) ) ); - 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' ) ); - } + case gt_Move: { + SubModel->SetTranslate( float3( 0, 0, GetScaledValue() ) ); + break; + } + case 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 ); } - sm = sm->NextGet(); - } while (sm); - break; + break; + } + case 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; + } } } }; void TGauge::AssignFloat(float *fValue) { - cDataType = 'f'; + m_datatype = 'f'; fData = fValue; }; + void TGauge::AssignDouble(double *dValue) { - cDataType = 'd'; + m_datatype = 'd'; dData = dValue; }; + void TGauge::AssignInt(int *iValue) { - cDataType = 'i'; + m_datatype = 'i'; iData = iValue; }; + void TGauge::UpdateValue() { // ustawienie wartości docelowej z parametru - switch (cDataType) + switch (m_datatype) { // to nie jest zbyt optymalne, można by zrobić osobne funkcje case 'f': - fDesiredValue = (*fData) * fScale + fOffset; + m_targetvalue = (*fData); break; case 'd': - fDesiredValue = (*dData) * fScale + fOffset; + m_targetvalue = (*dData); break; case 'i': - fDesiredValue = (*iData) * fScale + fOffset; + m_targetvalue = (*iData); break; } }; +float TGauge::GetScaledValue() const { + + return ( + ( false == m_interpolatescale ) ? + m_value * m_scale + m_offset : + m_value + * interpolate( + m_scale, m_endscale, + clamp( + m_value / m_endvalue, + 0.f, 1.f ) ) + + m_offset ); +} + // 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 adb105e6..40f82cca 100644 --- a/Gauge.h +++ b/Gauge.h @@ -29,16 +29,13 @@ public: TGauge() = default; inline void Clear() { *this = TGauge(); } - void Init(TSubModel *NewSubModel, TGaugeType eNewTyp, double fNewScale = 1, double fNewOffset = 0, double fNewFriction = 0, double fNewValue = 0); + void Init(TSubModel *Submodel, TGaugeType 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 ); bool Load(cParser &Parser, TDynamicObject const *Owner, TModel3d *md1, TModel3d *md2 = nullptr, double mul = 1.0); - void PermIncValue(double fNewDesired); - void IncValue(double fNewDesired); - void DecValue(double fNewDesired); - void UpdateValue( double fNewDesired ); - void UpdateValue( double fNewDesired, sound_source &Fallbacksound ); - void PutValue(double fNewDesired); - double GetValue() const; - double GetDesiredValue() const; + void UpdateValue( float fNewDesired ); + void UpdateValue( float fNewDesired, sound_source &Fallbacksound ); + void PutValue(float fNewDesired); + float GetValue() const; + float GetDesiredValue() const; void Update(); void AssignFloat(float *fValue); void AssignDouble(double *dValue); @@ -54,15 +51,22 @@ private: // imports member data pair from the config file bool Load_mapping( cParser &Input ); - void UpdateValue( double fNewDesired, sound_source *Fallbacksound ); + void + UpdateValue( float fNewDesired, sound_source *Fallbacksound ); + float + GetScaledValue() const; + // members - TGaugeType eType { gt_Unknown }; // typ ruchu - double fFriction { 0.0 }; // hamowanie przy zliżaniu się do zadanej wartości - double fDesiredValue { 0.0 }; // wartość docelowa - double fValue { 0.0 }; // wartość obecna - double fOffset { 0.0 }; // wartość początkowa ("0") - double fScale { 1.0 }; // wartość końcowa ("1") - char cDataType; // typ zmiennej parametru: f-float, d-double, i-int + TGaugeType m_type { gt_Unknown }; // typ ruchu + float m_friction { 0.f }; // hamowanie przy zliżaniu się do zadanej wartości + float m_targetvalue { 0.f }; // wartość docelowa + float m_value { 0.f }; // wartość obecna + float m_offset { 0.f }; // wartość początkowa ("0") + float m_scale { 1.f }; // scale applied to the value at the start of accepted value range + float m_endscale { -1.f }; // scale applied to the value at the end of accepted value range + float m_endvalue { -1.f }; // end value of accepted value range + bool m_interpolatescale { false }; + char m_datatype; // typ zmiennej parametru: f-float, d-double, i-int union { // wskaźnik na parametr pokazywany przez animację float *fData; diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 3fbbf0c3..e65ae1f2 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1572,7 +1572,7 @@ void TMoverParameters::WaterHeaterCheck( double const Timestep ) { && ( true == Battery ) && ( true == WaterHeater.is_enabled ) && ( true == WaterHeater.breaker ) - && ( ( WaterHeater.config.temp_min < 0 ) || ( dizel_heat.temperatura1 < WaterHeater.config.temp_min ) ) ); + && ( ( WaterHeater.is_active ) || ( WaterHeater.config.temp_min < 0 ) || ( dizel_heat.temperatura1 < WaterHeater.config.temp_min ) ) ); if( ( WaterHeater.config.temp_max > 0 ) && ( dizel_heat.temperatura1 > WaterHeater.config.temp_max ) ) { @@ -4555,7 +4555,7 @@ double TMoverParameters::TractionForce(double dt) // TBD, TODO: currently ignores RVentType, fix this? RventRot += clamp( enrot - RventRot, -100.0, 50.0 ) * dt; dizel_heat.rpmw += clamp( dizel_heat.rpmwz - dizel_heat.rpmw, -100.f, 50.f ) * dt; - dizel_heat.rpmw += clamp( dizel_heat.rpmwz - dizel_heat.rpmw, -100.f, 50.f ) * dt; + dizel_heat.rpmw2 += clamp( dizel_heat.rpmwz2 - dizel_heat.rpmw2, -100.f, 50.f ) * dt; } else { RventRot *= std::max( 0.0, 1.0 - RVentSpeed * dt ); @@ -4569,7 +4569,7 @@ double TMoverParameters::TractionForce(double dt) // NOTE: we update only radiator fans, as vehicles with diesel engine don't have other ventilators if( true == Mains ) { dizel_heat.rpmw += clamp( dizel_heat.rpmwz - dizel_heat.rpmw, -100.f, 50.f ) * dt; - dizel_heat.rpmw += clamp( dizel_heat.rpmwz - dizel_heat.rpmw, -100.f, 50.f ) * dt; + dizel_heat.rpmw2 += clamp( dizel_heat.rpmwz2 - dizel_heat.rpmw2, -100.f, 50.f ) * dt; } else { dizel_heat.rpmw *= std::max( 0.0, 1.0 - dizel_heat.rpmw * dt ); @@ -4703,11 +4703,18 @@ double TMoverParameters::TractionForce(double dt) // tmpV:=V*CabNo*ActiveDir; auto const tmpV { nrot * Pirazy2 * 0.5 * WheelDiameter * DirAbsolute }; //*CabNo*ActiveDir; // jazda manewrowa - if (ShuntMode) - { - Voltage = (SST[MainCtrlPos].Umax * AnPos) + (SST[MainCtrlPos].Umin * (1.0 - AnPos)); - tmp = (SST[MainCtrlPos].Pmax * AnPos) + (SST[MainCtrlPos].Pmin * (1.0 - AnPos)); - Ft = tmp * 1000.0 / (abs(tmpV) + 1.6); + if( true == ShuntMode ) { + if( ( true == Mains ) && ( MainCtrlPos > 0 ) ) { + Voltage = ( SST[ MainCtrlPos ].Umax * AnPos ) + ( SST[ MainCtrlPos ].Umin * ( 1.0 - AnPos ) ); + // NOTE: very crude way to approximate power generated at current rpm instead of instant top output + auto const rpmratio { 60.0 * enrot / DElist[ MainCtrlPos ].RPM }; + tmp = rpmratio * ( SST[ MainCtrlPos ].Pmax * AnPos ) + ( SST[ MainCtrlPos ].Pmin * ( 1.0 - AnPos ) ); + Ft = tmp * 1000.0 / ( abs( tmpV ) + 1.6 ); + } + else { + Voltage = 0; + Ft = 0; + } PosRatio = 1; } else // jazda ciapongowa diff --git a/Train.cpp b/Train.cpp index 9a991709..2855f13c 100644 --- a/Train.cpp +++ b/Train.cpp @@ -757,7 +757,7 @@ void TTrain::OnCommand_secondcontrollerincrease( TTrain *Train, command_data con // on press or hold if( Train->mvControlled->ShuntMode ) { Train->mvControlled->AnPos = clamp( - Train->mvControlled->AnPos + ( Command.time_delta * 1.0f ), + Train->mvControlled->AnPos + ( Command.time_delta * 2.0 ), 0.0, 1.0 ); } else { @@ -818,7 +818,7 @@ void TTrain::OnCommand_secondcontrollerdecrease( TTrain *Train, command_data con // on press or hold if( Train->mvControlled->ShuntMode ) { Train->mvControlled->AnPos = clamp( - Train->mvControlled->AnPos - ( Command.time_delta * 1.0f ), + Train->mvControlled->AnPos - ( Command.time_delta * 2.0 ), 0.0, 1.0 ); } Train->mvControlled->DecScndCtrl( 1 ); @@ -4867,6 +4867,7 @@ bool TTrain::Update( double const Deltatime ) btLampkaNadmPrzetwB.Turn( tmp->MoverParameters->ConvOvldFlag ); // nadmiarowy przetwornicy? btLampkaPrzetwB.Turn( tmp->MoverParameters->ConverterFlag ); // zalaczenie przetwornicy btLampkaPrzetwBOff.Turn( false == tmp->MoverParameters->ConverterFlag ); + btLampkaMalfunctionB.Turn( tmp->MoverParameters->dizel_heat.PA ); } else // wylaczone { @@ -4881,6 +4882,7 @@ bool TTrain::Update( double const Deltatime ) btLampkaNadmPrzetwB.Turn( false ); btLampkaPrzetwB.Turn( false ); btLampkaPrzetwBOff.Turn( false ); + btLampkaMalfunctionB.Turn( false ); } } @@ -6306,6 +6308,7 @@ void TTrain::clear_cab_controls() btCabLight.Clear(); // hunter-171012 // others btLampkaMalfunction.Clear(); + btLampkaMalfunctionB.Clear(); btLampkaMotorBlowers.Clear(); ggLeftLightButton.Clear(); @@ -6615,6 +6618,7 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co { "i-contactorsb:", btLampkaStycznB }, { "i-conv_ovldb:", btLampkaNadmPrzetwB }, { "i-malfunction:", btLampkaMalfunction }, + { "i-malfunctionb:", btLampkaMalfunctionB }, { "i-forward:", btLampkaForward }, { "i-backward:", btLampkaBackward }, { "i-upperlight:", btLampkaUpperLight }, @@ -6937,9 +6941,9 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con if (Parser.getToken() == "analog") { // McZapkie-300302: zegarek - ggClockSInd.Init(DynamicObject->mdKabina->GetFromName("ClockShand"), gt_Rotate, 1.0/60.0, 0, 0); - ggClockMInd.Init(DynamicObject->mdKabina->GetFromName("ClockMhand"), gt_Rotate, 1.0/60.0, 0, 0); - ggClockHInd.Init(DynamicObject->mdKabina->GetFromName("ClockHhand"), gt_Rotate, 1.0/12.0, 0, 0); + ggClockSInd.Init(DynamicObject->mdKabina->GetFromName("ClockShand"), gt_Rotate, 1.0/60.0); + ggClockMInd.Init(DynamicObject->mdKabina->GetFromName("ClockMhand"), gt_Rotate, 1.0/60.0); + ggClockHInd.Init(DynamicObject->mdKabina->GetFromName("ClockHhand"), gt_Rotate, 1.0/12.0); } } else if (Label == "evoltage:") @@ -7002,6 +7006,12 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina); 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, DynamicObject->mdKabina); + gauge.AssignDouble(&mvControlled->AnPos); + } else { // failed to match the label diff --git a/Train.h b/Train.h index 60636020..46b51400 100644 --- a/Train.h +++ b/Train.h @@ -512,6 +512,7 @@ public: // reszta może by?publiczna TButton btLampkaRearRightEndLight; // other TButton btLampkaMalfunction; + TButton btLampkaMalfunctionB; TButton btLampkaMotorBlowers; TButton btCabLight; // hunter-171012: lampa oswietlajaca kabine