diff --git a/Globals.cpp b/Globals.cpp index 97b1e3c3..8684f5d3 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -308,6 +308,11 @@ global_settings::ConfigParse(cParser &Parser) { // max 8 lights per opengl specs, minus one used for sun. at least one light for controlled vehicle DynamicLightCount = clamp( DynamicLightCount, 1, 7 ); } + else if( token == "scenario.time.offset" ) { + // shift (in hours) applied to train timetables + Parser.getTokens( 1, false ); + Parser >> ScenarioTimeOffset; + } else if( token == "scalespeculars" ) { // whether strength of specular highlights should be adjusted (generally needed for legacy 3d models) Parser.getTokens(); diff --git a/Globals.h b/Globals.h index cfa502ab..1480847a 100644 --- a/Globals.h +++ b/Globals.h @@ -79,6 +79,7 @@ struct global_settings { bool FakeLight{ false }; // toggle between fixed and dynamic daylight double fTimeSpeed{ 1.0 }; // przyspieszenie czasu, zmienna do testów double fLatitudeDeg{ 52.0 }; // szerokość geograficzna + float ScenarioTimeOffset { 0.f }; // time shift (in hours) applied to train timetables bool bInactivePause{ true }; // automatyczna pauza, gdy okno nieaktywne int iSlowMotionMask{ -1 }; // maska wyłączanych właściwości bool bHideConsole{ false }; // hunter-271211: ukrywanie konsoli diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 2ae53a80..1958bd0a 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -3080,89 +3080,175 @@ void TMoverParameters::UpdateBrakePressure(double dt) // Q: 20160712 // Obliczanie pracy sprężarki // ************************************************************************************************* +// TODO: clean the method up, a lot of the code is redundant void TMoverParameters::CompressorCheck(double dt) { + if( VeselVolume == 0.0 ) { return; } + CompressedVolume = std::max( 0.0, CompressedVolume - dt * AirLeakRate * 0.1 ); // nieszczelności: 0.001=1l/s - // if (CompressorSpeed>0.0) then //ten warunek został sprawdzony przy wywołaniu funkcji - if (VeselVolume > 0) - { - if (MaxCompressor - MinCompressor < 0.0001) - { - // if (Mains && (MainCtrlPos > 1)) - if (CompressorAllow && CompressorAllowLocal && Mains && (MainCtrlPos > 0)) - { - if (Compressor < MaxCompressor) - if ((EngineType == DieselElectric) && (CompressorPower > 0)) - CompressedVolume += dt * CompressorSpeed * - (2.0 * MaxCompressor - Compressor) / MaxCompressor * - (DElist[MainCtrlPos].RPM / DElist[MainCtrlPosNo].RPM); - else - { - CompressedVolume += - dt * CompressorSpeed * (2.0 * MaxCompressor - Compressor) / MaxCompressor; - TotalCurrent += 0.0015 - * Voltage; // tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę - } + if( ( true == CompressorGovernorLock ) + && ( Compressor < MinCompressor ) ) { + // if the pressure drops below the cut-in level, we can reset compressor governor + // TBD, TODO: don't operate the lock without battery power? + CompressorGovernorLock = false; + } + + if (MaxCompressor - MinCompressor < 0.0001) { + // TODO: investigate purpose of this branch and whether it can be removed as it duplicates later code + if( ( true == CompressorAllow ) + && ( true == CompressorAllowLocal ) + && ( true == Mains ) + && ( MainCtrlPos > 0 ) ) { + if( Compressor < MaxCompressor ) { + if( ( EngineType == DieselElectric ) + && ( CompressorPower > 0 ) ) { + CompressedVolume += + CompressorSpeed + * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor + * ( DElist[ MainCtrlPos ].RPM / DElist[ MainCtrlPosNo ].RPM ) + * dt; + } + else { + CompressedVolume += + CompressorSpeed + * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor + * dt; + TotalCurrent += 0.0015 * Voltage; // tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę + } + } + else { + CompressedVolume = CompressedVolume * 0.8; + SetFlag(SoundFlag, sound::relay | sound::loud); + } + } + } + else { + if( ( ( CompressorPower == 0 ) + || ( CompressorPower == 3 ) ) + && ( ( EngineType == DieselEngine ) + || ( EngineType == DieselElectric ) ) ) { + // experimental: make sure compressor coupled with diesel engine is always ready for work + CompressorAllow = true; + } + if (CompressorFlag) // jeśli sprężarka załączona + { // sprawdzić możliwe warunki wyłączenia sprężarki + if (CompressorPower == 5) // jeśli zasilanie z sąsiedniego członu + { // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) + if (Couplers[1].Connected != NULL) + CompressorFlag = + ( Couplers[ 1 ].Connected->CompressorAllow + && Couplers[ 1 ].Connected->CompressorAllowLocal + && Couplers[ 1 ].Connected->Mains + && Couplers[ 1 ].Connected->ConverterFlag ); else - { - CompressedVolume = CompressedVolume * 0.8; - SetFlag(SoundFlag, sound::relay | sound::loud); - // SetFlag(SoundFlag, sound::loud); + CompressorFlag = false; // bez tamtego członu nie zadziała + } + else if (CompressorPower == 4) // jeśli zasilanie z poprzedniego członu + { // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) + if (Couplers[0].Connected != NULL) + CompressorFlag = + ( Couplers[ 0 ].Connected->CompressorAllow + && Couplers[ 0 ].Connected->CompressorAllowLocal + && Couplers[ 0 ].Connected->Mains + && Couplers[ 0 ].Connected->ConverterFlag ); + else + CompressorFlag = false; // bez tamtego członu nie zadziała + } + else + CompressorFlag = + ( ( CompressorAllow ) + && ( CompressorAllowLocal ) + && ( Mains ) + && ( ( ConverterFlag ) + || ( CompressorPower == 0 ) + || ( CompressorPower == 3 ) ) ); + + if( Compressor > MaxCompressor ) { + // wyłącznik ciśnieniowy jest niezależny od sposobu zasilania + // TBD, TODO: don't operate the lock without battery power? + if( ( CompressorPower == 0 ) + || ( CompressorPower == 3 ) ) { + // if the compressor is powered directly by the engine the lock can't turn it off and instead just changes the output + if( false == CompressorGovernorLock ) { + // emit relay sound when the lock engages (the state change itself is below) and presumably changes where the air goes + SetFlag( SoundFlag, sound::relay | sound::loud ); + } + } + else { + // if the compressor isn't coupled with the engine the lock can control its state freely + CompressorFlag = false; + } + CompressorGovernorLock = true; // prevent manual activation until the pressure goes below cut-in level + } + + if( ( TrainType == dt_ET41 ) + || ( TrainType == dt_ET42 ) ) { + // for these multi-unit engines compressors turn off whenever any of them was affected by the governor + // NOTE: this is crude implementation, TODO: re-implement when a more elegant/flexible system is in place + if( ( Couplers[ 1 ].Connected != nullptr ) + && ( true == TestFlag( Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) { + // the first unit isn't allowed to start its compressor until second unit can start its own as well + CompressorFlag &= ( Couplers[ 1 ].Connected->CompressorGovernorLock == false ); + } + if( ( Couplers[ 0 ].Connected != nullptr ) + && ( true == TestFlag( Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) { + // the second unit isn't allowed to start its compressor until first unit can start its own as well + CompressorFlag &= ( Couplers[ 0 ].Connected->CompressorGovernorLock == false ); } } } - else - { - if( ( CompressorPower == 0 ) - && ( ( EngineType == DieselEngine ) - || ( EngineType == DieselElectric ) ) ) { - // experimental: make sure compressor coupled with diesel engine is always ready for work - CompressorAllow = true; - } - if (CompressorFlag) // jeśli sprężarka załączona - { // sprawdzić możliwe warunki wyłączenia sprężarki - if (CompressorPower == 5) // jeśli zasilanie z sąsiedniego członu + else { + // jeśli nie załączona + if( ( LastSwitchingTime > CtrlDelay ) + && ( ( Compressor < MinCompressor ) + || ( ( Compressor < MaxCompressor ) + && ( false == CompressorGovernorLock ) ) ) ) { + // załączenie przy małym ciśnieniu + // jeśli nie załączona, a ciśnienie za małe + // or if the switch is on and the pressure isn't maxed + if( CompressorPower == 5 ) // jeśli zasilanie z następnego członu { // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) - if (Couplers[1].Connected != NULL) + if( Couplers[ 1 ].Connected != nullptr ) { CompressorFlag = ( Couplers[ 1 ].Connected->CompressorAllow && Couplers[ 1 ].Connected->CompressorAllowLocal && Couplers[ 1 ].Connected->Mains && Couplers[ 1 ].Connected->ConverterFlag ); - else + } + else { CompressorFlag = false; // bez tamtego członu nie zadziała + } } - else if (CompressorPower == 4) // jeśli zasilanie z poprzedniego członu + else if( CompressorPower == 4 ) // jeśli zasilanie z poprzedniego członu { // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) - if (Couplers[0].Connected != NULL) + if( Couplers[ 0 ].Connected != nullptr ) { CompressorFlag = ( Couplers[ 0 ].Connected->CompressorAllow && Couplers[ 0 ].Connected->CompressorAllowLocal && Couplers[ 0 ].Connected->Mains && Couplers[ 0 ].Connected->ConverterFlag ); - else + } + else { CompressorFlag = false; // bez tamtego członu nie zadziała + } } - else + else { CompressorFlag = - ( ( CompressorAllow ) + ( ( CompressorAllow ) && ( CompressorAllowLocal ) && ( Mains ) && ( ( ConverterFlag ) - || ( CompressorPower == 0 ) ) ); - - if( Compressor > MaxCompressor ) { - // wyłącznik ciśnieniowy jest niezależny od sposobu zasilania - CompressorFlag = false; - CompressorGovernorLock = true; // prevent manual activation until the pressure goes below cut-in level + || ( CompressorPower == 0 ) + || ( CompressorPower == 3 ) ) ); } + // NOTE: crude way to enforce simultaneous activation of compressors in multi-unit setups + // TODO: replace this with a more universal activation system down the road if( ( TrainType == dt_ET41 ) || ( TrainType == dt_ET42 ) ) { - // for these multi-unit engines compressors turn off whenever any of them was affected by the governor - // NOTE: this is crude implementation, TODO: re-implement when a more elegant/flexible system is in place - if( ( Couplers[ 1 ].Connected != nullptr ) + + if( ( Couplers[1].Connected != nullptr ) && ( true == TestFlag( Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) { // the first unit isn't allowed to start its compressor until second unit can start its own as well CompressorFlag &= ( Couplers[ 1 ].Connected->CompressorGovernorLock == false ); @@ -3173,110 +3259,67 @@ void TMoverParameters::CompressorCheck(double dt) CompressorFlag &= ( Couplers[ 0 ].Connected->CompressorGovernorLock == false ); } } - } - else { - // jeśli nie załączona - if( Compressor < MinCompressor ) { - // if the pressure drops below the cut-in level, we can reset compressor governor - CompressorGovernorLock = false; - } - if( ( ( Compressor < MinCompressor ) - || ( ( Compressor < MaxCompressor ) - && ( false == CompressorGovernorLock ) ) ) - && ( LastSwitchingTime > CtrlDelay ) ) { - // załączenie przy małym ciśnieniu - // jeśli nie załączona, a ciśnienie za małe - // or if the switch is on and the pressure isn't maxed - if( CompressorPower == 5 ) // jeśli zasilanie z następnego członu - { // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) - if( Couplers[ 1 ].Connected != nullptr ) { - CompressorFlag = - ( Couplers[ 1 ].Connected->CompressorAllow - && Couplers[ 1 ].Connected->CompressorAllowLocal - && Couplers[ 1 ].Connected->Mains - && Couplers[ 1 ].Connected->ConverterFlag ); - } - else { - CompressorFlag = false; // bez tamtego członu nie zadziała - } - } - else if( CompressorPower == 4 ) // jeśli zasilanie z poprzedniego członu - { // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) - if( Couplers[ 0 ].Connected != nullptr ) { - CompressorFlag = - ( Couplers[ 0 ].Connected->CompressorAllow - && Couplers[ 0 ].Connected->CompressorAllowLocal - && Couplers[ 0 ].Connected->Mains - && Couplers[ 0 ].Connected->ConverterFlag ); - } - else { - CompressorFlag = false; // bez tamtego członu nie zadziała - } - } - else { - CompressorFlag = - ( ( CompressorAllow ) - && ( CompressorAllowLocal ) - && ( Mains ) - && ( ( ConverterFlag ) - || ( CompressorPower == 0 ) ) ); - } - - // NOTE: crude way to enforce simultaneous activation of compressors in multi-unit setups - // TODO: replace this with a more universal activation system down the road - if( ( TrainType == dt_ET41 ) - || ( TrainType == dt_ET42 ) ) { - - if( ( Couplers[1].Connected != nullptr ) - && ( true == TestFlag( Couplers[ 1 ].CouplingFlag, coupling::permanent ) ) ) { - // the first unit isn't allowed to start its compressor until second unit can start its own as well - CompressorFlag &= ( Couplers[ 1 ].Connected->CompressorGovernorLock == false ); - } - if( ( Couplers[ 0 ].Connected != nullptr ) - && ( true == TestFlag( Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) { - // the second unit isn't allowed to start its compressor until first unit can start its own as well - CompressorFlag &= ( Couplers[ 0 ].Connected->CompressorGovernorLock == false ); - } - } - - if( CompressorFlag ) { - // jeśli została załączona - LastSwitchingTime = 0; // to trzeba ograniczyć ponowne włączenie - } + if( CompressorFlag ) { + // jeśli została załączona + LastSwitchingTime = 0; // to trzeba ograniczyć ponowne włączenie } } + } - if( CompressorFlag ) { - if( ( EngineType == DieselElectric ) && ( CompressorPower > 0 ) ) { + if( CompressorFlag ) { + if( ( EngineType == DieselElectric ) + && ( ( CompressorPower == 0 ) + || ( CompressorPower == 3 ) ) ) { + if( false == CompressorGovernorLock ) { CompressedVolume += - dt * CompressorSpeed + CompressorSpeed * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor - * ( DElist[ MainCtrlPos ].RPM / DElist[ MainCtrlPosNo ].RPM ); + * ( DElist[ MainCtrlPos ].RPM / DElist[ MainCtrlPosNo ].RPM ) + * dt; } - else if( ( EngineType == DieselEngine ) && ( CompressorPower == 0 ) ) { +/* + else { + // the lock is active, air is being vented out + CompressedVolume -= 0.1 * dt; + } +*/ + } + else if( ( EngineType == DieselEngine ) + && ( ( CompressorPower == 0 ) + || ( CompressorPower == 3 ) ) ) { + if( false == CompressorGovernorLock ) { // experimental: compressor coupled with diesel engine, output scaled by current engine rotational speed CompressedVolume += - dt * CompressorSpeed + CompressorSpeed * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor - * ( std::abs( enrot ) / nmax ); + * ( std::abs( enrot ) / nmax ) + * dt; + } +/* + else { + // the lock is active, air is being vented out + CompressedVolume -= 0.1 * dt; + } +*/ + } + else { + CompressedVolume += + CompressorSpeed + * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor + * dt; + + if( ( CompressorPower == 5 ) && ( Couplers[ 1 ].Connected != NULL ) ) { + // tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę + Couplers[ 1 ].Connected->TotalCurrent += 0.0015 * Couplers[ 1 ].Connected->Voltage; + } + else if( ( CompressorPower == 4 ) && ( Couplers[ 0 ].Connected != NULL ) ) { + // tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę + Couplers[ 0 ].Connected->TotalCurrent += 0.0015 * Couplers[ 0 ].Connected->Voltage; } else { - CompressedVolume += - dt * CompressorSpeed * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor; - if( ( CompressorPower == 5 ) && ( Couplers[ 1 ].Connected != NULL ) ) - Couplers[ 1 ].Connected->TotalCurrent += - 0.0015 * Couplers[ 1 ].Connected->Voltage; // tymczasowo tylko obciążenie - // sprężarki, tak z 5A na - // sprężarkę - else if( ( CompressorPower == 4 ) && ( Couplers[ 0 ].Connected != NULL ) ) - Couplers[ 0 ].Connected->TotalCurrent += - 0.0015 * Couplers[ 0 ].Connected->Voltage; // tymczasowo tylko obciążenie - // sprężarki, tak z 5A na - // sprężarkę - else - TotalCurrent += 0.0015 * - Voltage; // tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę + // tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę + TotalCurrent += 0.0015 * Voltage; } } } @@ -7287,11 +7330,12 @@ void TMoverParameters::LoadFIZ_Brake( std::string const &line ) { extract_value( CompressorSpeed, "CompressorSpeed", line, "" ); { std::map compressorpowers{ + { "Main", 0 }, + // 1: default, powered by converter, with manual state control { "Converter", 2 }, - { "Engine", 3 }, + { "Engine", 3 }, // equivalent of 0, TODO: separate 'main' and 'engine' in the code { "Coupler1", 4 },//włączana w silnikowym EZT z przodu - { "Coupler2", 5 },//włączana w silnikowym EZT z tyłu - { "Main", 0 } + { "Coupler2", 5 } //włączana w silnikowym EZT z tyłu }; auto lookup = compressorpowers.find( extract_value( "CompressorPower", line ) ); CompressorPower = diff --git a/Train.cpp b/Train.cpp index 92f5e435..350da7de 100644 --- a/Train.cpp +++ b/Train.cpp @@ -222,6 +222,9 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { 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::convertertoggle, &TTrain::OnCommand_convertertoggle }, { user_command::converterenable, &TTrain::OnCommand_converterenable }, { user_command::converterdisable, &TTrain::OnCommand_converterdisable }, @@ -1996,6 +1999,45 @@ void TTrain::OnCommand_linebreakerclose( TTrain *Train, command_data const &Comm } } +void TTrain::OnCommand_fuelpumptoggle( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( false == Train->mvControlled->FuelPump.is_enabled ) { + // turn on + OnCommand_fuelpumpenable( Train, Command ); + } + else { + //turn off + OnCommand_fuelpumpdisable( Train, Command ); + } + } +} + +void TTrain::OnCommand_fuelpumpenable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggFuelPumpButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( true == Train->mvControlled->FuelPump.is_enabled ) { return; } // already enabled + + Train->mvControlled->FuelPumpSwitch( true ); + } +} + +void TTrain::OnCommand_fuelpumpdisable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggFuelPumpButton.UpdateValue( 0.0, Train->dsbSwitch ); + + if( false == Train->mvControlled->FuelPump.is_enabled ) { return; } // already disabled + + Train->mvControlled->FuelPumpSwitch( false ); + } +} + void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Command ) { if( Command.action == GLFW_PRESS ) { @@ -3856,12 +3898,6 @@ bool TTrain::Update( double const Deltatime ) } } if( m_linebreakerstate == 1 ) { - if( ( mvControlled->EngineType == DieselElectric ) - && ( false == mvControlled->ConverterFlag ) ) { - // converter acts as a make-believe fuel pump so if it's off, kill the engine - // TODO: implement actual fuel system and move this check to the mover update - mvControlled->MainSwitch( false ); - } if( false == mvControlled->Mains ) { // crude way to catch cases where the main was knocked out and the user is trying to restart it // because the state of the line breaker isn't changed to match, we need to do it here manually @@ -3909,6 +3945,9 @@ bool TTrain::Update( double const Deltatime ) // finalize state change of the line breaker m_linebreakerstate = 1; } + else { + m_linebreakerstate = 0; + } } } @@ -3946,6 +3985,23 @@ bool TTrain::Update( double const Deltatime ) if (DynamicObject->mdKabina) { // Ra: TODO: odczyty klawiatury/pulpitu nie powinny być uzależnione od istnienia modelu kabiny + + if( ( DynamicObject->Mechanik != nullptr ) + && ( false == DynamicObject->Mechanik->AIControllFlag ) // nie blokujemy AI + && ( ( mvOccupied->TrainType == dt_ET40 ) + || ( mvOccupied->TrainType == dt_EP05 ) ) ) { + // dla ET40 i EU05 automatyczne cofanie nastawnika - i tak nie będzie to działać dobrze... + // TODO: remove direct keyboard check, use deltatime to stabilize speed + if( ( glfwGetKey( Global.window, GLFW_KEY_KP_ADD ) != GLFW_TRUE ) + && ( mvOccupied->MainCtrlPos > mvOccupied->MainCtrlActualPos ) ) { + mvOccupied->DecMainCtrl( 1 ); + } + if( ( glfwGetKey( Global.window, GLFW_KEY_KP_SUBTRACT ) != GLFW_TRUE ) + && ( mvOccupied->MainCtrlPos < mvOccupied->MainCtrlActualPos ) ) { + mvOccupied->IncMainCtrl( 1 ); // Ra 15-01: a to nie miało być tylko cofanie? + } + } + tor = DynamicObject->GetTrack(); // McZapkie-180203 // McZapkie: predkosc wyswietlana na tachometrze brana jest z obrotow kol float maxtacho = 3; @@ -4430,6 +4486,7 @@ bool TTrain::Update( double const Deltatime ) btLampkaNapNastHam.Turn(mvControlled->ActiveDir != 0); // napiecie na nastawniku hamulcowym btLampkaSprezarka.Turn(mvControlled->CompressorFlag); // mutopsitka dziala btLampkaSprezarkaOff.Turn( false == mvControlled->CompressorFlag ); + btLampkaFuelPumpOff.Turn( false == mvControlled->FuelPump.is_active ); // boczniki unsigned char scp; // Ra: dopisałem "unsigned" // Ra: w SU45 boczniki wchodzą na MainCtrlPos, a nie na MainCtrlActualPos @@ -4469,6 +4526,7 @@ bool TTrain::Update( double const Deltatime ) btLampkaNadmPrzetw.Turn( false ); btLampkaSprezarka.Turn( false ); btLampkaSprezarkaOff.Turn( false ); + btLampkaFuelPumpOff.Turn( false ); btLampkaBezoporowa.Turn( false ); } if (mvControlled->Signalling == true) { @@ -4874,6 +4932,8 @@ bool TTrain::Update( double const Deltatime ) ggCabLightButton.Update(); ggCabLightDimButton.Update(); ggBatteryButton.Update(); + + ggFuelPumpButton.Update(); //------ pyScreens.update(); } @@ -5157,15 +5217,22 @@ TTrain::update_sounds( double const Deltatime ) { volume *= 1 + 0.125 * brakeforceratio; } // scale volume by track quality - volume *= ( 20.0 + DynamicObject->MyTrack->iDamageFlag ) / 21; - // scale volume with vehicle speed - // TBD, TODO: disable the scaling for sounds combined from speed-based samples? + // TODO: track quality and/or environment factors as separate subroutine volume *= interpolate( - 0.0, 1.0, + 0.8, 1.2, clamp( - mvOccupied->Vel / 40.0, + DynamicObject->MyTrack->iQualityFlag / 20.0, 0.0, 1.0 ) ); + // for single sample sounds muffle the playback at low speeds + if( false == rsRunningNoise.is_combined() ) { + volume *= + interpolate( + 0.0, 1.0, + clamp( + mvOccupied->Vel / 40.0, + 0.0, 1.0 ) ); + } if( volume > 0.05 ) { rsRunningNoise @@ -5911,6 +5978,8 @@ void TTrain::clear_cab_controls() ggMainGearStatus.Clear(); ggIgnitionKey.Clear(); + ggFuelPumpButton.Clear(); + btLampkaPrzetw.Clear(); btLampkaPrzetwB.Clear(); btLampkaPrzetwBOff.Clear(); @@ -5950,6 +6019,7 @@ void TTrain::clear_cab_controls() btLampkaSprezarkaB.Clear(); btLampkaSprezarkaOff.Clear(); btLampkaSprezarkaBOff.Clear(); + btLampkaFuelPumpOff.Clear(); btLampkaNapNastHam.Clear(); btLampkaStycznB.Clear(); btLampkaHamowanie1zes.Clear(); @@ -6072,9 +6142,14 @@ void TTrain::set_cab_controls() { 1.0 : 0.0 ); // motor overload relay threshold / shunt mode - if( mvControlled->Imax == mvControlled->ImaxHi ) { - ggMaxCurrentCtrl.PutValue( 1.0 ); - } + ggMaxCurrentCtrl.PutValue( + ( true == mvControlled->ShuntModeAllow ? + ( true == mvControlled->ShuntMode ? + 1.0 : + 0.0 ) : + ( mvControlled->Imax == mvControlled->ImaxHi ? + 1.0 : + 0.0 ) ) ); // lights ggLightsButton.PutValue( mvOccupied->LightsPos - 1 ); @@ -6169,6 +6244,11 @@ void TTrain::set_cab_controls() { ShowNextCurrent ? 1.0 : 0.0 ); + // fuel pump + ggFuelPumpButton.PutValue( + mvOccupied->FuelPump.is_enabled ? + 1.0 : + 0.0 ); // we reset all indicators, as they're set during the update pass // TODO: when cleaning up break setting indicator state into a separate function, so we can reuse it @@ -6232,6 +6312,7 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co { "i-compressorb:", btLampkaSprezarkaB }, { "i-compressoroff:", btLampkaSprezarkaOff }, { "i-compressorboff:", btLampkaSprezarkaBOff }, + { "i-fuelpumpoff:", btLampkaFuelPumpOff }, { "i-voltbrake:", btLampkaNapNastHam }, { "i-resistorsb:", btLampkaOporyB }, { "i-contactorsb:", btLampkaStycznB }, @@ -6332,6 +6413,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "converterlocal_sw:", ggConverterLocalButton }, { "converteroff_sw:", ggConverterOffButton }, { "main_sw:", ggMainButton }, + { "fuelpump_sw:", ggFuelPumpButton }, { "radio_sw:", ggRadioButton }, { "radiochannel_sw:", ggRadioChannelSelector }, { "radiochannelprev_sw:", ggRadioChannelPrevious }, diff --git a/Train.h b/Train.h index 9b530afc..b255c784 100644 --- a/Train.h +++ b/Train.h @@ -452,6 +452,7 @@ public: // reszta może by?publiczna TButton btLampkaSprezarkaB; TButton btLampkaSprezarkaOff; TButton btLampkaSprezarkaBOff; + TButton btLampkaFuelPumpOff; TButton btLampkaBocznik1; TButton btLampkaBocznik2; TButton btLampkaBocznik3; diff --git a/World.cpp b/World.cpp index 23b6793b..1cb15127 100644 --- a/World.cpp +++ b/World.cpp @@ -61,10 +61,11 @@ simulation_time::init() { { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; ::memcpy( m_monthdaycounts, monthdaycounts, sizeof( monthdaycounts ) ); + // potentially adjust scenario clock + auto const requestedtime { clamp_circular( m_time.wHour * 60 + m_time.wMinute + Global.ScenarioTimeOffset * 60, 1440 ) }; + auto const requestedhour { ( requestedtime / 60 ) % 60 }; + auto const requestedminute { requestedtime % 60 }; // cache requested elements, if any - WORD const requestedhour = m_time.wHour; - WORD const requestedminute = m_time.wMinute; - ::GetLocalTime( &m_time ); if( Global.fMoveLight > 0.0 ) { @@ -72,10 +73,11 @@ simulation_time::init() { daymonth( m_time.wDay, m_time.wMonth, m_time.wYear, static_cast( Global.fMoveLight ) ); } - if( requestedhour != (WORD)-1 ) { m_time.wHour = clamp( requestedhour, static_cast( 0 ), static_cast( 23 ) ); } - if( requestedminute != (WORD)-1 ) { m_time.wMinute = clamp( requestedminute, static_cast( 0 ), static_cast( 59 ) ); } + if( requestedhour != -1 ) { m_time.wHour = static_cast( clamp( requestedhour, 0, 23 ) ); } + if( requestedminute != -1 ) { m_time.wMinute = static_cast( clamp( requestedminute, 0, 59 ) ); } // if the time is taken from the local clock leave the seconds intact, otherwise set them to zero - if( ( requestedhour != (WORD)-1 ) || ( requestedminute != (WORD)-1 ) ) { + if( ( requestedhour != -1 ) + || ( requestedminute != 1 ) ) { m_time.wSecond = 0; } diff --git a/mtable.cpp b/mtable.cpp index 3cc1b0fd..a5109fd8 100644 --- a/mtable.cpp +++ b/mtable.cpp @@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "mtable.h" +#include "globals.h" #include "world.h" #include "utilities.h" @@ -521,20 +522,21 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax) // NextStationName:=TimeTable[1].StationName; /* TTVmax:=TimeTable[1].vmax; */ } - if ((iPlus != 0)) // jeżeli jest przesunięcie rozkładu + auto const timeoffset { static_cast( Global.ScenarioTimeOffset * 60 ) + iPlus }; + if( timeoffset != 0.0 ) // jeżeli jest przesunięcie rozkładu { long i_end = StationCount + 1; for (i = 1; i < i_end; ++i) // bez with, bo ciężko się przenosi na C++ { if ((TimeTable[i].Ah >= 0)) { - time = iPlus + TimeTable[i].Ah * 60 + TimeTable[i].Am; // nowe minuty + time = clamp_circular( TimeTable[i].Ah * 60 + TimeTable[i].Am + timeoffset, 1440 ); // nowe minuty TimeTable[i].Am = time % 60; TimeTable[i].Ah = (time /*div*/ / 60) % 60; } if ((TimeTable[i].Dh >= 0)) { - time = iPlus + TimeTable[i].Dh * 60 + TimeTable[i].Dm; // nowe minuty + time = clamp_circular( TimeTable[i].Dh * 60 + TimeTable[i].Dm + timeoffset, 1440 ); // nowe minuty TimeTable[i].Dm = time % 60; TimeTable[i].Dh = (time /*div*/ / 60) % 60; } diff --git a/version.h b/version.h index bc9715f3..91b2b070 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 18 -#define VERSION_MINOR 326 +#define VERSION_MINOR 329 #define VERSION_REVISION 0