16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-18 00:49:19 +02:00

cab controls active state visualization support, cab control initialization on cab change fix

This commit is contained in:
tmj-fstate
2019-10-20 13:52:37 +02:00
parent d3797c67df
commit 5a85786a42
5 changed files with 276 additions and 151 deletions

View File

@@ -124,6 +124,7 @@ TButton::Turn( bool const State ) {
} }
void TButton::Update( bool const Power ) { 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 ) }; auto const state { Power && ( bData ? *bData : m_state ) };

220
Gauge.cpp
View File

@@ -27,11 +27,14 @@ TGauge::TGauge( sound_source const &Soundtemplate ) :
{ {
m_soundfxincrease = m_soundtemplate; m_soundfxincrease = m_soundtemplate;
m_soundfxdecrease = 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 { // ustawienie parametrów animacji submodelu
SubModel = Submodel; SubModel = Submodel;
SubModelOn = Submodelon;
m_value = Value; m_value = Value;
m_animation = Type; m_animation = Type;
m_scale = Scale; m_scale = Scale;
@@ -41,38 +44,53 @@ void TGauge::Init(TSubModel *Submodel, TGaugeAnimation Type, float Scale, float
m_endvalue = Endvalue; m_endvalue = Endvalue;
m_endscale = Endscale; m_endscale = Endscale;
if( Submodel == nullptr ) {
// warunek na wszelki wypadek, gdyby się submodel nie podłączył
return;
}
if( m_animation == TGaugeAnimation::gt_Digital ) { if( m_animation == TGaugeAnimation::gt_Digital ) {
TSubModel *sm = SubModel->ChildGet(); auto *sm { ( SubModel ? SubModel->ChildGet() : nullptr ) };
do { while( sm != nullptr ) {
// pętla po submodelach potomnych i obracanie ich o kąt zależy od cyfry w (fValue) // 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.size() )// musi mieć niepustą nazwę
if( sm->pName[ 0 ] >= '0' ) && ( std::isdigit( sm->pName[ 0 ] ) ) ) {
if( sm->pName[ 0 ] <= '9' ) sm->WillBeAnimated(); // wyłączenie optymalizacji
sm->WillBeAnimated(); // wyłączenie optymalizacji
} }
sm = sm->NextGet(); 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 // pass submodel location to defined sounds
auto const nulloffset { glm::vec3{} }; auto const nulloffset { glm::vec3{} };
auto const offset{ model_offset() }; auto const offset { model_offset() };
if( m_soundfxincrease.offset() == nulloffset ) { {
m_soundfxincrease.offset( offset ); std::vector<sound_source *> 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 ) { for( auto &soundfx : m_soundfxvalues ) {
m_soundfxdecrease.offset( offset ); if( soundfx.second.offset() == nulloffset ) {
} soundfx.second.offset( offset );
for( auto &soundfxrecord : m_soundfxvalues ) {
if( soundfxrecord.second.offset() == nulloffset ) {
soundfxrecord.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 // bind defined sounds with the button owner
m_soundfxincrease.owner( Owner ); m_soundfxincrease.owner( Owner );
m_soundfxdecrease.owner( Owner ); m_soundfxdecrease.owner( Owner );
m_soundfxon.owner( Owner );
m_soundfxoff.owner( Owner );
for( auto &soundfxrecord : m_soundfxvalues ) { for( auto &soundfxrecord : m_soundfxvalues ) {
soundfxrecord.second.owner( Owner ); 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 // got what we wanted, bail out
break; 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 ) { if( submodel == nullptr ) {
ErrorLog( "Bad model: failed to locate sub-model \"" + submodelname + "\" in 3d model(s) of \"" + Owner->name() + "\"", logtype::model ); 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<std::string, TGaugeAnimation> gaugetypes { std::map<std::string, TGaugeAnimation> gaugetypes {
{ "rot", TGaugeAnimation::gt_Rotate }, { "rot", TGaugeAnimation::gt_Rotate },
@@ -166,7 +201,7 @@ void TGauge::Load( cParser &Parser, TDynamicObject const *Owner, double const mu
lookup->second : lookup->second :
TGaugeAnimation::gt_Unknown ); 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 // 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:" ) { else if( key == "sounddec:" ) {
m_soundfxdecrease.deserialize( Input, sound_type::single ); 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<std::size_t>( key.size(), 5 ), "sound" ) == 0 ) { else if( key.compare( 0, std::min<std::size_t>( key.size(), 5 ), "sound" ) == 0 ) {
// sounds assigned to specific gauge values, defined by key soundFoo: where Foo = value // sounds assigned to specific gauge values, defined by key soundFoo: where Foo = value
auto const indexstart { key.find_first_of( "-1234567890" ) }; 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... // ...and if there isn't any, fall back on the basic set...
auto const currentvalue = GetValue(); auto const currentvalue = GetValue();
// HACK: crude way to discern controls with continuous and quantized value range // HACK: crude way to discern controls with continuous and quantized value range
if( ( currentvalue < fNewDesired ) if( currentvalue < fNewDesired ) {
&& ( false == m_soundfxincrease.empty() ) ) {
// shift up // shift up
m_soundfxincrease.play( m_soundtype ); m_soundfxincrease.play( m_soundtype );
} }
else if( ( currentvalue > fNewDesired ) else if( currentvalue > fNewDesired ) {
&& ( false == m_soundfxdecrease.empty() ) ) {
// shift down // shift down
m_soundfxdecrease.play( m_soundtype ); m_soundfxdecrease.play( m_soundtype );
} }
@@ -276,8 +315,9 @@ float TGauge::GetDesiredValue() const {
return m_targetvalue; 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 ) { if( m_value != m_targetvalue ) {
float dt = Timer::GetDeltaTime(); float dt = Timer::GetDeltaTime();
if( ( m_friction > 0 ) && ( dt < 0.5 * m_friction ) ) { if( ( m_friction > 0 ) && ( dt < 0.5 * m_friction ) ) {
@@ -292,55 +332,25 @@ void TGauge::Update() {
m_value = m_targetvalue; m_value = m_targetvalue;
} }
} }
if( SubModel ) // update submodel visibility
{ // warunek na wszelki wypadek, gdyby się submodel nie podłączył auto const state { Power && ( m_stateinput ? *m_stateinput : false ) };
switch (m_animation) { if( state != m_state ) {
case TGaugeAnimation::gt_Rotate: { // on state change play assigned sound
SubModel->SetRotate( float3( 0, 1, 0 ), GetScaledValue() * 360.0 ); if( true == state ) { m_soundfxon.play(); }
break; else { m_soundfxoff.play(); }
} }
case TGaugeAnimation::gt_Move: { m_state = state;
SubModel->SetTranslate( float3( 0, 0, GetScaledValue() ) ); // toggle submodel visibility only if the active state submodel is present,
break; // keep the default model always visible otherwise
} if( SubModelOn != nullptr ) {
case TGaugeAnimation::gt_Wiper: { SubModelOn->iVisible = m_state;
auto const scaledvalue { GetScaledValue() }; if( SubModel != nullptr ) {
SubModel->SetRotate( float3( 0, 1, 0 ), scaledvalue * 360.0 ); SubModel->iVisible = ( !m_state );
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<int>( 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 animations
UpdateAnimation( SubModel );
UpdateAnimation( SubModelOn );
}; };
void TGauge::AssignFloat(float *fValue) 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 { float TGauge::GetScaledValue() const {
return ( return (
@@ -407,6 +422,55 @@ float TGauge::GetScaledValue() const {
+ m_offset ); + 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<int>( 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 // returns offset of submodel associated with the button from the model centre
glm::vec3 glm::vec3
TGauge::model_offset() const { TGauge::model_offset() const {

14
Gauge.h
View File

@@ -38,24 +38,26 @@ public:
inline inline
void Clear() { void Clear() {
*this = TGauge(); } *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 Load(cParser &Parser, TDynamicObject const *Owner, double const mul = 1.0);
void UpdateValue( float fNewDesired ); void UpdateValue( float fNewDesired );
void UpdateValue( float fNewDesired, sound_source &Fallbacksound ); void UpdateValue( float fNewDesired, sound_source &Fallbacksound );
void PutValue(float fNewDesired); void PutValue(float fNewDesired);
float GetValue() const; float GetValue() const;
float GetDesiredValue() const; float GetDesiredValue() const;
void Update(); void Update( bool const Power = true );
void AssignFloat(float *fValue); void AssignFloat(float *fValue);
void AssignDouble(double *dValue); void AssignDouble(double *dValue);
void AssignInt(int *iValue); void AssignInt(int *iValue);
void AssignBool(bool *bValue); void AssignBool(bool *bValue);
void UpdateValue(); void UpdateValue();
void AssignState( bool const *State );
// returns offset of submodel associated with the button from the model centre // returns offset of submodel associated with the button from the model centre
glm::vec3 model_offset() const; glm::vec3 model_offset() const;
TGaugeType type() const; TGaugeType type() const;
// members // 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: private:
// methods // methods
@@ -66,6 +68,8 @@ private:
UpdateValue( float fNewDesired, sound_source *Fallbacksound ); UpdateValue( float fNewDesired, sound_source *Fallbacksound );
float float
GetScaledValue() const; GetScaledValue() const;
void
UpdateAnimation( TSubModel *Submodel );
// members // members
TGaugeAnimation m_animation { TGaugeAnimation::gt_Unknown }; // typ ruchu TGaugeAnimation m_animation { TGaugeAnimation::gt_Unknown }; // typ ruchu
@@ -86,8 +90,12 @@ private:
int *iData; int *iData;
bool *bData; 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 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_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_soundfxincrease { m_soundtemplate }; // sound associated with increasing control's value
sound_source m_soundfxdecrease { m_soundtemplate }; // sound associated with decreasing control's value sound_source m_soundfxdecrease { m_soundtemplate }; // sound associated with decreasing control's value
std::map<int, sound_source> m_soundfxvalues; // sounds associated with specific values std::map<int, sound_source> m_soundfxvalues; // sounds associated with specific values

185
Train.cpp
View File

@@ -42,10 +42,8 @@ extern user_command command;
void void
control_mapper::insert( TGauge const &Gauge, std::string const &Label ) { control_mapper::insert( TGauge const &Gauge, std::string const &Label ) {
auto const submodel = Gauge.SubModel; if( Gauge.SubModel != nullptr ) { m_controlnames.emplace( Gauge.SubModel, Label ); }
if( submodel != nullptr ) { if( Gauge.SubModelOn != nullptr ) { m_controlnames.emplace( Gauge.SubModelOn, Label ); }
m_controlnames.emplace( submodel, Label );
}
} }
std::string 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 ) { void TTrain::OnCommand_pantographlowerall( TTrain *Train, command_data const &Command ) {
if( Command.action == GLFW_REPEAT ) { return; }
if( ( Train->ggPantAllDownButton.SubModel == nullptr ) if( ( Train->ggPantAllDownButton.SubModel == nullptr )
&& ( Train->ggPantSelectedDownButton.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 // 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; return;
} }
if( Command.action == GLFW_PRESS ) {
// press the button if( Train->ggPantAllDownButton.type() == TGaugeType::push ) {
// since we're just lowering all potential pantographs we don't need to test for state and effect // impulse switch
// front... if( Command.action == GLFW_PRESS ) {
Train->mvControlled->PantFrontSP = false; // press the button
Train->mvControlled->PantFront( false ); // since we're just lowering all potential pantographs we don't need to test for state and effect
// ...and rear // front...
Train->mvControlled->PantRearSP = false; Train->mvControlled->PantFrontSP = false;
Train->mvControlled->PantRear( false ); Train->mvControlled->PantFront( false );
// visual feedback // ...and rear
if( Train->ggPantAllDownButton.SubModel ) Train->mvControlled->PantRearSP = false;
Train->ggPantAllDownButton.UpdateValue( 1.0, Train->dsbSwitch ); Train->mvControlled->PantRear( false );
if( Train->ggPantSelectedDownButton.SubModel ) { // visual feedback
Train->ggPantSelectedDownButton.UpdateValue( 1.0, Train->dsbSwitch ); 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 ) { else {
// release the button // two-state switch, only cares about press events
// visual feedback if( Command.action == GLFW_PRESS ) {
if( Train->ggPantAllDownButton.SubModel ) // HACK: use current switch position to determine (intended) state
Train->ggPantAllDownButton.UpdateValue( 0.0 ); if( Train->ggPantAllDownButton.GetDesiredValue() < 0.05 ) {
if( Train->ggPantSelectedDownButton.SubModel ) { // currenty inactive, activate it
Train->ggPantSelectedDownButton.UpdateValue( 0.0 ); // 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->EngineType == TEngineType::ElectricSeriesMotor) ||
(mvControlled->TrainType == dt_EZT)) && (mvControlled->TrainType == dt_EZT)) &&
(DynamicObject->Controller == Humandriver)) // hunter-110212: poprawka dla EZT (DynamicObject->Controller == Humandriver)) // hunter-110212: poprawka dla EZT
{ // hunter-091012: poprawka (zmiana warunku z CompressorPower /rozne od { // hunter-091012: poprawka (zmiana warunku z CompressorPower /rozne od 0/ na /rowne 1/)
// 0/ na /rowne 1/)
if (fConverterTimer < fConverterPrzekaznik) if (fConverterTimer < fConverterPrzekaznik)
{ {
mvControlled->ConvOvldFlag = true; mvControlled->ConvOvldFlag = true;
@@ -5851,6 +5885,7 @@ bool TTrain::Update( double const Deltatime )
else else
fConverterTimer = 0; fConverterTimer = 0;
//------------------ //------------------
auto const lowvoltagepower { mvControlled->Battery || mvControlled->ConverterFlag };
// youBy - prad w drugim czlonie: galaz lub calosc // youBy - prad w drugim czlonie: galaz lub calosc
{ {
@@ -5903,7 +5938,7 @@ bool TTrain::Update( double const Deltatime )
ggClockHInd.Update(); 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) if (ggZbS.SubModel)
{ {
ggZbS.UpdateValue(mvOccupied->Handle->GetCP()); ggZbS.UpdateValue(mvOccupied->Handle->GetCP());
@@ -6012,7 +6047,7 @@ bool TTrain::Update( double const Deltatime )
btLampkaNadmSil.Turn( false ); btLampkaNadmSil.Turn( false );
} }
if (mvControlled->Battery || mvControlled->ConverterFlag) { if( true == lowvoltagepower ) {
// alerter test // alerter test
if( true == CAflag ) { if( true == CAflag ) {
if( ggSecurityResetButton.GetDesiredValue() > 0.95 ) { if( ggSecurityResetButton.GetDesiredValue() > 0.95 ) {
@@ -6199,7 +6234,7 @@ bool TTrain::Update( double const Deltatime )
btLampkaMalfunction.Turn( mvControlled->dizel_heat.PA ); btLampkaMalfunction.Turn( mvControlled->dizel_heat.PA );
btLampkaMotorBlowers.Turn( ( mvControlled->MotorBlowers[ end::front ].is_active ) && ( mvControlled->MotorBlowers[ end::rear ].is_active ) ); btLampkaMotorBlowers.Turn( ( mvControlled->MotorBlowers[ end::front ].is_active ) && ( mvControlled->MotorBlowers[ end::rear ].is_active ) );
btLampkaCoolingFans.Turn( mvControlled->RventRot > 1.0 ); btLampkaCoolingFans.Turn( mvControlled->RventRot > 1.0 );
btLampkaTempomat.Turn( mvControlled->ScndCtrlPos > 0 ); btLampkaTempomat.Turn( mvOccupied->SpeedCtrlUnit.IsActive );
btLampkaDistanceCounter.Turn( m_distancecounter >= 0.f ); btLampkaDistanceCounter.Turn( m_distancecounter >= 0.f );
// universal devices state indicators // universal devices state indicators
for( auto idx = 0; idx < btUniversals.size(); ++idx ) { for( auto idx = 0; idx < btUniversals.size(); ++idx ) {
@@ -6282,32 +6317,32 @@ bool TTrain::Update( double const Deltatime )
(mvOccupied->ActiveCab < 0)) (mvOccupied->ActiveCab < 0))
tmp = DynamicObject->PrevConnected(); tmp = DynamicObject->PrevConnected();
if (tmp) if( tmp ) {
if ( mvControlled->Battery || mvControlled->ConverterFlag ) { if( lowvoltagepower ) {
auto const *mover { tmp->MoverParameters }; auto const *mover{ tmp->MoverParameters };
btLampkaWylSzybkiB.Turn( mover->Mains ); btLampkaWylSzybkiB.Turn( mover->Mains );
btLampkaWylSzybkiBOff.Turn( btLampkaWylSzybkiBOff.Turn(
( false == mover->Mains ) ( false == mover->Mains )
&& ( mover->MainsInitTimeCountdown <= 0.0 ) && ( mover->MainsInitTimeCountdown <= 0.0 )
/*&& ( fHVoltage != 0.0 )*/ ); /*&& ( fHVoltage != 0.0 )*/ );
btLampkaOporyB.Turn(mover->ResistorsFlagCheck()); btLampkaOporyB.Turn( mover->ResistorsFlagCheck() );
btLampkaBezoporowaB.Turn( btLampkaBezoporowaB.Turn(
( true == mover->ResistorsFlagCheck() ) ( true == mover->ResistorsFlagCheck() )
|| ( mover->MainCtrlActualPos == 0 ) ); // do EU04 || ( mover->MainCtrlActualPos == 0 ) ); // do EU04
if( ( mover->StLinFlag ) if( ( mover->StLinFlag )
|| ( mover->BrakePress > 2.0 ) || ( mover->BrakePress > 2.0 )
|| ( mover->PipePress < 0.36 ) ) { || ( mover->PipePress < 0.36 ) ) {
btLampkaStycznB.Turn( false ); btLampkaStycznB.Turn( false );
} }
else if( mover->BrakePress < 1.0 ) { else if( mover->BrakePress < 1.0 ) {
btLampkaStycznB.Turn( true ); // mozna prowadzic rozruch btLampkaStycznB.Turn( true ); // mozna prowadzic rozruch
} }
// hunter-271211: sygnalizacja poslizgu w pierwszym pojezdzie, gdy wystapi w drugim // 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 btLampkaSprezarkaB.Turn( mover->CompressorFlag ); // mutopsitka dziala
btLampkaSprezarkaBOff.Turn( false == mover->CompressorFlag ); btLampkaSprezarkaBOff.Turn( false == mover->CompressorFlag );
@@ -6348,6 +6383,7 @@ bool TTrain::Update( double const Deltatime )
btLampkaHVoltageB.Turn( false ); btLampkaHVoltageB.Turn( false );
btLampkaMalfunctionB.Turn( false ); btLampkaMalfunctionB.Turn( false );
} }
}
} }
// McZapkie-080602: obroty (albo translacje) regulatorow // McZapkie-080602: obroty (albo translacje) regulatorow
if( ggJointCtrl.SubModel != nullptr ) { if( ggJointCtrl.SubModel != nullptr ) {
@@ -6408,7 +6444,7 @@ bool TTrain::Update( double const Deltatime )
dsbNastawnikBocz ); dsbNastawnikBocz );
ggScndCtrl.Update(); ggScndCtrl.Update();
} }
ggScndCtrlButton.Update(); ggScndCtrlButton.Update( lowvoltagepower );
ggDistanceCounterButton.Update(); ggDistanceCounterButton.Update();
if (ggDirKey.SubModel) { if (ggDirKey.SubModel) {
if (mvControlled->TrainType != dt_EZT) if (mvControlled->TrainType != dt_EZT)
@@ -6600,12 +6636,12 @@ bool TTrain::Update( double const Deltatime )
} }
ggHelperButton.Update(); ggHelperButton.Update();
ggSpeedControlIncreaseButton.Update(); ggSpeedControlIncreaseButton.Update( lowvoltagepower );
ggSpeedControlDecreaseButton.Update(); ggSpeedControlDecreaseButton.Update( lowvoltagepower );
ggSpeedControlPowerIncreaseButton.Update(); ggSpeedControlPowerIncreaseButton.Update( lowvoltagepower );
ggSpeedControlPowerDecreaseButton.Update(); ggSpeedControlPowerDecreaseButton.Update( lowvoltagepower );
for (auto &speedctrlbutton : ggSpeedCtrlButtons) { for (auto &speedctrlbutton : ggSpeedCtrlButtons) {
speedctrlbutton.Update(); speedctrlbutton.Update( lowvoltagepower );
} }
for( auto &universal : ggUniversals ) { for( auto &universal : ggUniversals ) {
@@ -8102,7 +8138,7 @@ void TTrain::set_cab_controls( int const Cab ) {
// lights // lights
ggLightsButton.PutValue( mvOccupied->LightsPos - 1 ); 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 ) { if( ( DynamicObject->iLights[ vehicleend ] & light::headlight_left ) != 0 ) {
ggLeftLightButton.PutValue( 1.f ); ggLeftLightButton.PutValue( 1.f );
@@ -8559,7 +8595,6 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
{ "cablight_sw:", ggCabLightButton }, { "cablight_sw:", ggCabLightButton },
{ "cablightdim_sw:", ggCabLightDimButton }, { "cablightdim_sw:", ggCabLightDimButton },
{ "battery_sw:", ggBatteryButton }, { "battery_sw:", ggBatteryButton },
{ "tempomat_sw:", ggScndCtrlButton },
{ "distancecounter_sw:", ggDistanceCounterButton }, { "distancecounter_sw:", ggDistanceCounterButton },
{ "universal0:", ggUniversals[ 0 ] }, { "universal0:", ggUniversals[ 0 ] },
{ "universal1:", ggUniversals[ 1 ] }, { "universal1:", ggUniversals[ 1 ] },
@@ -8570,30 +8605,44 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
{ "universal6:", ggUniversals[ 6 ] }, { "universal6:", ggUniversals[ 6 ] },
{ "universal7:", ggUniversals[ 7 ] }, { "universal7:", ggUniversals[ 7 ] },
{ "universal8:", ggUniversals[ 8 ] }, { "universal8:", ggUniversals[ 8 ] },
{ "universal9:", ggUniversals[ 9 ] }, { "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 ] }
};
{ {
auto lookup = gauges.find( Label ); auto const lookup { gauges.find( Label ) };
if( lookup != gauges.end() ) { if( lookup != gauges.end() ) {
lookup->second.Load( Parser, DynamicObject ); lookup->second.Load( Parser, DynamicObject );
m_controlmapper.insert( lookup->second, lookup->first ); m_controlmapper.insert( lookup->second, lookup->first );
return true; return true;
} }
} }
// TODO: move viable gauges to the state driven array
std::unordered_map<std::string, std::tuple<TGauge &, bool const *> > 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<TGauge &>( lookup->second ) };
gauge.Load( Parser, DynamicObject );
gauge.AssignState( std::get<bool const *>( lookup->second ) );
m_controlmapper.insert( gauge, lookup->first );
return true;
}
}
// TODO: move viable dedicated gauges to the automatic array // TODO: move viable dedicated gauges to the automatic array
std::unordered_map<std::string, bool *> const autoboolgauges = { std::unordered_map<std::string, bool *> const autoboolgauges = {
{ "doormode_sw:", &mvOccupied->Doors.remote_only }, { "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 ) { if( DynamicObject->mdKabina ) {
// McZapkie-300302: zegarek // McZapkie-300302: zegarek
ggClockSInd.Init( DynamicObject->mdKabina->GetFromName( "ClockShand" ), TGaugeAnimation::gt_Rotate, 1.0 / 60.0 ); ggClockSInd.Init( DynamicObject->mdKabina->GetFromName( "ClockShand" ), nullptr, TGaugeAnimation::gt_Rotate, 1.0 / 60.0 );
ggClockMInd.Init( DynamicObject->mdKabina->GetFromName( "ClockMhand" ), 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" ), TGaugeAnimation::gt_Rotate, 1.0 / 12.0 ); ggClockHInd.Init( DynamicObject->mdKabina->GetFromName( "ClockHhand" ), nullptr, TGaugeAnimation::gt_Rotate, 1.0 / 12.0 );
} }
} }
} }

View File

@@ -158,11 +158,14 @@ class TTrain {
void update_sounds_runningnoise( sound_source &Sound ); void update_sounds_runningnoise( sound_source &Sound );
void update_sounds_radio(); void update_sounds_radio();
inline inline
end cab_to_end() const { end cab_to_end( int const End ) const {
return ( return (
iCabn == 2 ? End == 2 ?
end::rear : end::rear :
end::front ); } end::front ); }
inline
end cab_to_end() const {
return cab_to_end( iCabn ); }
// command handlers // 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 // 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