From b3940d47cb069535c1d46a15ca81b297a855791c Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 27 May 2021 13:13:18 +0200 Subject: [PATCH 1/3] minor ai heater logic tweak, vehicle preparation check tweak --- Driver.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 47abcc7b..e21cc839 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2459,6 +2459,7 @@ bool TController::CheckVehicles(TOrders user) // with the order established the virtual train manager can do their work p = pVehicles[ end::front ]; ControlledEnginesCount = ( p->MoverParameters->Power > 1.0 ? 1 : 0 ); + auto hasheaters { false }; while (p) { if( p != pVehicle ) { @@ -2470,6 +2471,7 @@ bool TController::CheckVehicles(TOrders user) if( p->MoverParameters->HeatingPower > 0 ) { p->MoverParameters->HeatingAllow = true; p->MoverParameters->ConverterSwitch( true, range_t::local ); + hasheaters = true; } } else { @@ -2526,16 +2528,18 @@ bool TController::CheckVehicles(TOrders user) cue_action( locale::string::driver_hint_consistdoorlockson ); // potentially enable train heating { - // HACK: to account for su-45/46 shortcomings diesel-powered engines only activate heating in cold conditions - // TODO: take instead into account presence of converters in attached cars, once said presence is possible to specify auto const ispassengertrain { ( IsPassengerTrain ) && ( iVehicles - ControlledEnginesCount > 0 ) }; - auto const isheatingcouplingactive { pVehicles[ end::front ]->is_connected( pVehicles[ end::rear ], coupling::heating ) }; + // TODO: replace connection test with connection check between last engine and first car, specifically + auto const isheatingcouplingactive { ( + ControlledEnginesCount == 1 ? + pVehicles[ end::front ]->is_connected( pVehicles[ end::rear ], coupling::heating ) : + true ) }; auto const isheatingneeded { (is_emu() || is_dmu() ? true : -// false == isheatingcouplingactive ? false : (OrderCurrentGet() & (Obey_train | Bank)) == 0 ? false : - ispassengertrain ? (has_diesel_engine() ? (Global.AirTemperature < 10) : true) : - false)}; + false == isheatingcouplingactive ? false : + ispassengertrain ? hasheaters : + false) }; if( mvControlling->HeatingAllow != isheatingneeded ) { cue_action( isheatingneeded ? @@ -2839,6 +2843,7 @@ bool TController::PrepareEngine() && ( true == IsAnyCompressorEnabled ) && ( ( mvControlling->ScndPipePress > 4.5 ) || ( mvControlling->VeselVolume == 0.0 ) ) && ( ( static_cast( mvOccupied->fBrakeCtrlPos ) == static_cast( mvOccupied->Handle->GetPos( bh_RP ) ) ) + || ( static_cast( mvOccupied->fBrakeCtrlPos ) != static_cast( mvOccupied->Handle->GetPos( bh_NP ) ) ) || ( mvOccupied->BrakeHandle == TBrakeHandle::NoHandle ) ); } From 7b816594bac668c2ef20223eade6db1202568360 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 27 May 2021 14:23:00 +0200 Subject: [PATCH 2/3] maintenance: string search methods --- AnimModel.cpp | 8 +++--- Console/PoKeys55.cpp | 2 +- Driver.cpp | 2 +- DynObj.cpp | 32 ++++++++++++------------ Event.cpp | 33 ++++++++++++------------- Globals.cpp | 2 +- McZapkie/Mover.cpp | 12 ++++----- McZapkie/Oerlikon_ESt.cpp | 16 ++++++------ MdlMngr.cpp | 2 +- Model3d.cpp | 7 +++--- Texture.cpp | 7 +++--- audio.cpp | 8 +++--- driveruipanels.cpp | 2 +- editoruipanels.cpp | 2 +- material.cpp | 3 ++- mtable.cpp | 46 +++++++++++++++++------------------ parser.cpp | 8 +++--- scene.cpp | 2 +- scenenode.cpp | 6 ++--- simulationstateserializer.cpp | 4 +-- station.cpp | 6 ++--- utilities.cpp | 13 ++++++++++ utilities.h | 3 +++ 23 files changed, 120 insertions(+), 106 deletions(-) diff --git a/AnimModel.cpp b/AnimModel.cpp index 5b184f96..d42370a5 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -453,7 +453,7 @@ bool TAnimModel::Load(cParser *parser, bool ter) { // gdy brak modelu if (ter) // jeśli teren { - if( name.substr( name.rfind( '.' ) ) == ".t3d" ) { + if( ends_with( name, ".t3d" ) ) { name[ name.length() - 3 ] = 'e'; } #ifdef EU07_USE_OLD_TERRAINCODE @@ -959,11 +959,11 @@ TAnimModel::export_as_text_( std::ostream &Output ) const { // don't include 'textures/' in the path texturefile.erase( 0, std::string{ szTexturePath }.size() ); } - if( texturefile.find( ' ' ) == std::string::npos ) { - Output << texturefile << ' '; + if( contains( texturefile, ' ' ) ) { + Output << "\"" << texturefile << "\"" << ' '; } else { - Output << "\"" << texturefile << "\"" << ' '; + Output << texturefile << ' '; } // light submodels activation configuration if( iNumLights > 0 ) { diff --git a/Console/PoKeys55.cpp b/Console/PoKeys55.cpp index abe24616..5774947b 100644 --- a/Console/PoKeys55.cpp +++ b/Console/PoKeys55.cpp @@ -145,7 +145,7 @@ bool TPoKeys55::Connect() DeviceIDFromRegistry = ToLower( DeviceIDFromRegistry ); DeviceIDToFind = ToLower( DeviceIDToFind ); // Now check if the hardware ID we are looking at contains the correct VID/PID - MatchFound = ( DeviceIDFromRegistry.find( DeviceIDToFind ) != std::string::npos ); + MatchFound = ( contains( DeviceIDFromRegistry, DeviceIDToFind ) ); if (MatchFound == true) { // Device must have been found. Open read and write handles. In order to do this,we diff --git a/Driver.cpp b/Driver.cpp index e21cc839..7eeff552 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -5130,7 +5130,7 @@ void TController::OrdersInit(double fVel) + ", " + std::to_string(t->Dh) + ":" + std::to_string(t->Dm) + " " + t->StationWare); } - if (t->StationWare.find('@') != std::string::npos) + if ( contains( t->StationWare, '@' ) ) { // zmiana kierunku i dalsza jazda wg rozk?adu if (iDrivigFlags & movePushPull) // SZT również! SN61 zależnie od wagonów... { // jeśli skład zespolony, wystarczy zmienić kierunek jazdy diff --git a/DynObj.cpp b/DynObj.cpp index 928deef6..794abab0 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -169,7 +169,7 @@ void material_data::assign( std::string const &Replacableskin ) { // check for the pipe method first - if( Replacableskin.find( '|' ) != std::string::npos ) { + if( contains( Replacableskin, '|' ) ) { cParser nameparser( Replacableskin ); nameparser.getTokens( 4, true, "|" ); int skinindex = 0; @@ -1172,7 +1172,7 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) if( cabsection ) { // check whether we're still processing cab sections auto const §ionname { section.compartment->pName }; - cabsection &= ( ( sectionname.size() >= 4 ) && ( sectionname.substr( 0, 3 ) == "cab" ) ); + cabsection &= ( ( sectionname.size() >= 4 ) && ( starts_with( sectionname, "cab" ) ) ); } // TODO: add cablight devices auto const sectionlightlevel { section.light_level * ( cabsection ? 1.0f : MoverParameters->CompartmentLights.intensity ) }; @@ -1904,40 +1904,40 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" if (ActPar.substr(0, 1) == "B") // jesli hamulce { // sprawdzanie kolejno nastaw WriteLog("Wpis hamulca: " + ActPar); - if (ActPar.find('G') != std::string::npos) + if ( contains( ActPar, 'G') ) { MoverParameters->BrakeDelaySwitch(bdelay_G); } - if( ActPar.find( 'P' ) != std::string::npos ) + if( contains( ActPar, 'P' ) ) { MoverParameters->BrakeDelaySwitch(bdelay_P); } - if( ActPar.find( 'R' ) != std::string::npos ) + if( contains( ActPar, 'R' ) ) { MoverParameters->BrakeDelaySwitch(bdelay_R); } - if( ActPar.find( 'M' ) != std::string::npos ) + if( contains( ActPar, 'M' ) ) { MoverParameters->BrakeDelaySwitch(bdelay_R); MoverParameters->BrakeDelaySwitch(bdelay_R + bdelay_M); } // wylaczanie hamulca - if (ActPar.find("<>") != std::string::npos) // wylaczanie na probe hamowania naglego + if ( contains( ActPar, "<>") ) // wylaczanie na probe hamowania naglego { MoverParameters->Hamulec->SetBrakeStatus( MoverParameters->Hamulec->GetBrakeStatus() | b_dmg ); // wylacz } - if (ActPar.find('0') != std::string::npos) // wylaczanie na sztywno + if ( contains( ActPar, '0' ) ) // wylaczanie na sztywno { MoverParameters->Hamulec->ForceEmptiness(); MoverParameters->Hamulec->SetBrakeStatus( MoverParameters->Hamulec->GetBrakeStatus() | b_dmg ); // wylacz } - if (ActPar.find('E') != std::string::npos) // oprozniony + if ( contains( ActPar, 'E' ) ) // oprozniony { MoverParameters->Hamulec->ForceEmptiness(); MoverParameters->Pipe->CreatePress(0); MoverParameters->Pipe2->CreatePress(0); } - if (ActPar.find('Q') != std::string::npos) // oprozniony + if ( contains( ActPar, 'Q' ) ) // oprozniony { MoverParameters->Hamulec->ForceEmptiness(); MoverParameters->Pipe->CreatePress(0.0); @@ -1949,7 +1949,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" MoverParameters->CompressedVolume = 0.0; } - if (ActPar.find('1') != std::string::npos) // wylaczanie 10% + if ( contains( ActPar, '1' ) ) // wylaczanie 10% { if (Random(10) < 1) // losowanie 1/10 { @@ -1957,7 +1957,7 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" MoverParameters->Hamulec->SetBrakeStatus( MoverParameters->Hamulec->GetBrakeStatus() | b_dmg ); // wylacz } } - if (ActPar.find('X') != std::string::npos) // agonalny wylaczanie 20%, usrednienie przekladni + if ( contains( ActPar, 'X') ) // agonalny wylaczanie 20%, usrednienie przekladni { if (Random(100) < 20) // losowanie 20/100 { @@ -1990,23 +1990,23 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" } } // nastawianie ladunku - if (ActPar.find('T') != std::string::npos) // prozny + if ( contains( ActPar, 'T' ) ) // prozny { MoverParameters->DecBrakeMult(); MoverParameters->DecBrakeMult(); } // dwa razy w dol - if (ActPar.find('H') != std::string::npos) // ladowny I (dla P-Ł dalej prozny) + if ( contains( ActPar, 'H' ) ) // ladowny I (dla P-Ł dalej prozny) { MoverParameters->IncBrakeMult(); MoverParameters->IncBrakeMult(); MoverParameters->DecBrakeMult(); } // dwa razy w gore i obniz - if (ActPar.find('F') != std::string::npos) // ladowny II + if ( contains( ActPar, 'F' ) ) // ladowny II { MoverParameters->IncBrakeMult(); MoverParameters->IncBrakeMult(); } // dwa razy w gore - if (ActPar.find('N') != std::string::npos) // parametr neutralny + if ( contains( ActPar, 'N' ) ) // parametr neutralny { } } // koniec hamulce diff --git a/Event.cpp b/Event.cpp index d2bf4763..eb321f8d 100644 --- a/Event.cpp +++ b/Event.cpp @@ -297,8 +297,9 @@ basic_event::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) { Input >> token; deserialize_targets( token ); - if (m_name.substr(0, 5) == "none_") + if( starts_with( m_name, "none_" ) ) { m_ignored = true; // Ra: takie są ignorowane + } deserialize_( Input, Scratchpad ); // subclass method is expected to leave next token past its own data preloaded on its exit @@ -712,9 +713,10 @@ putvalues_event::deserialize_( cParser &Input, scene::scratch_data &Scratchpad ) Input.getTokens( 1, false ); // komendy 'case sensitive' Input >> token; // command type, previously held in param 6 - if( token.substr( 0, 19 ) == "PassengerStopPoint:" ) { - if( token.find( '#' ) != std::string::npos ) + if( starts_with( token, "PassengerStopPoint:" ) ) { + if( contains( token, '#' ) ) { token.erase( token.find( '#' ) ); // obcięcie unikatowości + } win1250_to_ascii( token ); // get rid of non-ascii chars m_input.command_type = TCommandType::cm_PassengerStopPoint; // nie do kolejki (dla SetVelocity też, ale jak jest do toru dowiązany) @@ -1224,12 +1226,12 @@ multi_event::deserialize_( cParser &Input, scene::scratch_data &Scratchpad ) { } else { // potentially valid event name - if( token.substr( 0, 5 ) != "none_" ) { + if( starts_with( token, "none_" ) ) { // eventy rozpoczynające się od "none_" są ignorowane - m_children.emplace_back( token, nullptr, ( m_conditions.has_else == false ) ); + WriteLog( "Multi-event \"" + m_name + "\" ignored link to event \"" + token + "\"" ); } else { - WriteLog( "Multi-event \"" + m_name + "\" ignored link to event \"" + token + "\"" ); + m_children.emplace_back( token, nullptr, ( m_conditions.has_else == false ) ); } } } @@ -1564,7 +1566,7 @@ animation_event::deserialize_( cParser &Input, scene::scratch_data &Scratchpad ) Input.getTokens(); Input >> token; - if( token.compare( "rotate" ) == 0 ) { // obrót względem osi + if( token == "rotate" ) { // obrót względem osi Input.getTokens(); // animation submodel, previously held in param 9 Input >> m_animationsubmodel; @@ -1578,7 +1580,7 @@ animation_event::deserialize_( cParser &Input, scene::scratch_data &Scratchpad ) >> m_animationparams[ 2 ] >> m_animationparams[ 3 ]; } - else if( token.compare( "translate" ) == 0 ) { // przesuw o wektor + else if( token == "translate" ) { // przesuw o wektor Input.getTokens(); // animation submodel, previously held in param 9 Input >> m_animationsubmodel; @@ -1592,7 +1594,7 @@ animation_event::deserialize_( cParser &Input, scene::scratch_data &Scratchpad ) >> m_animationparams[ 2 ] >> m_animationparams[ 3 ]; } - else if( token.compare( "digital" ) == 0 ) { // licznik cyfrowy + else if( token == "digital" ) { // licznik cyfrowy Input.getTokens(); // animation submodel, previously held in param 9 Input >> m_animationsubmodel; @@ -1606,7 +1608,7 @@ animation_event::deserialize_( cParser &Input, scene::scratch_data &Scratchpad ) >> m_animationparams[ 2 ] >> m_animationparams[ 3 ]; } - else if( token.substr( token.length() - 4, 4 ) == ".vmd" ) // na razie tu, może będzie inaczej + else if( ends_with( token, ".vmd" ) ) // na razie tu, może będzie inaczej { // animacja z pliku VMD { m_animationfilename = token; @@ -2227,18 +2229,15 @@ event_manager::insert( basic_event *Event ) { return false; } // tymczasowo wyjątki: - else if( ( size > 8 ) - && ( Event->m_name.substr( 0, 9 ) == "lineinfo:" ) ) { + else if( ends_with( Event->m_name, "lineinfo:" ) ) { // tymczasowa utylizacja duplikatów W5 return false; } - else if( ( size > 8 ) - && ( Event->m_name.substr( size - 8 ) == "_warning" ) ) { + else if( ends_with( Event->m_name, "_warning" ) ) { // tymczasowa utylizacja duplikatu z trąbieniem return false; } - else if( ( size > 4 ) - && ( Event->m_name.substr( size - 4 ) == "_shp" ) ) { + else if( ends_with( Event->m_name, "_shp" ) ) { // nie podlegają logowaniu // tymczasowa utylizacja duplikatu SHP return false; @@ -2263,7 +2262,7 @@ event_manager::insert( basic_event *Event ) { // if it's first event with such name, it's potential candidate for the execution queue m_eventmap.emplace( Event->m_name, m_events.size() - 1 ); if( ( Event->m_ignored != true ) - && ( Event->m_name.find( "onstart" ) != std::string::npos ) ) { + && ( contains( Event->m_name, "onstart" ) ) ) { // event uruchamiany automatycznie po starcie AddToQuery( Event, nullptr ); } diff --git a/Globals.cpp b/Globals.cpp index 0f6f1b07..e2bb3231 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -1259,7 +1259,7 @@ global_settings::export_as_text( std::ostream &Output, std::string const Key, st if( Value.empty() ) { return; } - if( Value.find( ' ' ) != std::string::npos ) { + if( contains( Value, ' ' ) ) { Output << Key << " \"" << Value << "\"\n"; } else { diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 1167c093..47b94bdc 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -9179,7 +9179,7 @@ void TMoverParameters::BrakeValveDecode( std::string const &Valve ) { TBrakeValve::Other; if( ( BrakeValve == TBrakeValve::Other ) - && ( Valve.find( "ESt" ) != std::string::npos ) ) { + && ( contains( Valve, "ESt" ) ) ) { BrakeValve = TBrakeValve::ESt3; } @@ -9276,8 +9276,8 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) inputline = fizparser.getToken( false, "\n\r" ); - bool comment = ( ( inputline.find('#') != std::string::npos ) - || ( inputline.compare( 0, 2, "//" ) == 0 ) ); + bool comment = ( ( contains( inputline, '#') ) + || ( starts_with( inputline, "//" ) ) ); if( true == comment ) { // skip commented lines continue; @@ -10530,10 +10530,10 @@ void TMoverParameters::LoadFIZ_Light( std::string const &line ) { void TMoverParameters::LoadFIZ_Security( std::string const &line ) { std::string awaresystem = extract_value( "AwareSystem", line ); - if( awaresystem.find( "Active" ) != std::string::npos ) { + if( contains( awaresystem, "Active" ) ) { SetFlag( SecuritySystem.SystemType, 1 ); } - if( awaresystem.find( "CabSignal" ) != std::string::npos ) { + if( contains( awaresystem, "CabSignal" ) ) { SetFlag( SecuritySystem.SystemType, 2 ); } @@ -11168,7 +11168,7 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir) // WriteLog("aa = " + AxleArangement + " " + std::string( Pos("o", AxleArangement)) ); - if( ( AxleArangement.find( "o" ) != std::string::npos ) && ( EngineType == TEngineType::ElectricSeriesMotor ) ) { + if( ( contains( AxleArangement, "o" ) ) && ( EngineType == TEngineType::ElectricSeriesMotor ) ) { // test poprawnosci ilosci osi indywidualnie napedzanych OK = ( ( RList[ 1 ].Bn * RList[ 1 ].Mn ) == NPoweredAxles ); // WriteLogSS("aa ok", BoolToYN(OK)); diff --git a/McZapkie/Oerlikon_ESt.cpp b/McZapkie/Oerlikon_ESt.cpp index 8ae37298..dba257ae 100644 --- a/McZapkie/Oerlikon_ESt.cpp +++ b/McZapkie/Oerlikon_ESt.cpp @@ -460,7 +460,7 @@ void TNESt3::SetSize( int const size, std::string const ¶ms ) // ustawianie static double const dOO1l = 0.907; static double const dOT1l = 0.524; - if (params.find("ESt3") != std::string::npos) + if (contains( params, "ESt3" ) ) { Podskok = 0.7; Przekladniki[1] = std::make_shared(); @@ -470,32 +470,32 @@ void TNESt3::SetSize( int const size, std::string const ¶ms ) // ustawianie { Podskok = -1.0; Przekladniki[1] = std::make_shared(); - if (params.find("-s216") != std::string::npos) + if (contains( params, "-s216" ) ) Przekladniki[1]->SetRapidParams(2, 16); else Przekladniki[1]->SetRapidParams(2, 0); Przekladniki[3] = std::make_shared(); - if (params.find("-ED") != std::string::npos) + if (contains( params,"-ED") ) { Przekladniki[1]->SetRapidParams(2, 18); Przekladniki[3] = std::make_shared(); } } - if (params.find("AL2") != std::string::npos) + if (contains(params,"AL2") ) Przekladniki[2] = std::make_shared(); - else if (params.find("PZZ") != std::string::npos) + else if (contains(params,"PZZ") ) Przekladniki[2] = std::make_shared(); else Przekladniki[2] = std::make_shared(); - if( ( params.find( "3d" ) != std::string::npos ) - || ( params.find( "4d" ) != std::string::npos ) ) { + if( ( contains( params, "3d" ) ) + || ( contains( params, "4d" ) ) ) { autom = false; } else autom = true; - if ((params.find("HBG300") != std::string::npos)) + if ((contains( params,"HBG300"))) HBG300 = 1.0; else HBG300 = 0.0; diff --git a/MdlMngr.cpp b/MdlMngr.cpp index 6f025dbf..fddddc75 100644 --- a/MdlMngr.cpp +++ b/MdlMngr.cpp @@ -82,7 +82,7 @@ TModelsManager::GetModel(std::string const &Name, bool const Dynamic, bool const std::string const buftp { Global.asCurrentTexturePath }; // zapamiętanie aktualnej ścieżki do tekstur, std::string filename { Name }; if( ( false == Dynamic ) - && ( Name.find( '/' ) != std::string::npos ) ) { + && ( contains( Name, '/' ) ) ) { // pobieranie tekstur z katalogu, w którym jest model // when loading vehicles the path is set by the calling routine, so we can skip it here Global.asCurrentTexturePath += Name; diff --git a/Model3d.cpp b/Model3d.cpp index 7a7b3837..82c8fd3b 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -2016,14 +2016,13 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector *t, if (!pName.empty()) { // jeśli dany submodel jest zgaszonym światłem, to // domyślnie go ukrywamy - if ((pName.size() >= 8) && (pName.substr(0, 8) == "Light_On")) + if (starts_with( pName, "Light_On" )) { // jeśli jest światłem numerowanym - iVisible = 0; // to domyślnie wyłączyć, żeby się nie nakładało z + iVisible = 0; // to domyślnie wyłączyć, żeby się nie nakładało z obiektem "Light_Off" } - // obiektem "Light_Off" else if (dynamic) { // inaczej wyłączało smugę w latarniach - if ((pName.size() >= 3) && (pName.substr(pName.size() - 3, 3) == "_on")) { + if (ends_with( pName, "_on")) { // jeśli jest kontrolką w stanie zapalonym to domyślnie wyłączyć, // żeby się nie nakładało z obiektem "_off" iVisible = 0; diff --git a/Texture.cpp b/Texture.cpp index 8500e2e4..c607a67e 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -1141,8 +1141,9 @@ texture_manager::unit( GLint const Textureunit ) { texture_handle texture_manager::create( std::string Filename, bool const Loadnow, GLint Formathint ) { - if( Filename.find( '|' ) != std::string::npos ) + if( contains( Filename, '|' ) ) { Filename.erase( Filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury + } std::pair locator; // resource name, resource type std::string traits; @@ -1181,8 +1182,8 @@ texture_manager::create( std::string Filename, bool const Loadnow, GLint Formath replace_slashes( Filename ); erase_leading_slashes( Filename ); // temporary code for legacy assets -- textures with names beginning with # are to be sharpened - if( ( Filename.front() == '#' ) - || ( Filename.find( "/#" ) != std::string::npos ) ) { + if( ( starts_with( Filename, "#" ) ) + || ( contains( Filename, "/#" ) ) ) { traits += '#'; } } diff --git a/audio.cpp b/audio.cpp index 24e5b9ad..36d5627d 100644 --- a/audio.cpp +++ b/audio.cpp @@ -31,7 +31,7 @@ openal_buffer::openal_buffer( std::string const &Filename ) : ::alGenBuffers( 1, &id ); // fetch audio data - if( Filename.substr( Filename.rfind( '.' ) ) == ".wav" ) { + if( ends_with( Filename, ".wav" ) ) { // .wav audio data file auto *file { drwav_open_file( Filename.c_str() ) }; if( file != nullptr ) { @@ -53,7 +53,7 @@ openal_buffer::openal_buffer( std::string const &Filename ) : // we're done with the disk data drwav_close( file ); } - else if( Filename.substr( Filename.rfind( '.' ) ) == ".flac" ) { + else if( ends_with( Filename, ".flac" ) ) { // .flac audio data file auto *file { drflac_open_file( Filename.c_str() ) }; if( file != nullptr ) { @@ -75,7 +75,7 @@ openal_buffer::openal_buffer( std::string const &Filename ) : // we're done with the disk data drflac_close( file ); } - else if( Filename.substr( Filename.rfind( '.' ) ) == ".ogg" ) { + else if( ends_with( Filename, ".ogg" ) ) { // vorbis .ogg audio data file // TBD, TODO: customized vorbis_decode to avoid unnecessary shuffling around of the decoded data int channels, samplerate; @@ -173,7 +173,7 @@ buffer_manager::create( std::string const &Filename ) { return emplace( filelookup ); } } - if( filename.find( '/' ) != std::string::npos ) { + if( contains( filename, '/' ) ) { // if the filename includes path, try to use it directly lookup = find_buffer( filename ); if( lookup != null_handle ) { diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 771053fa..8b44da15 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -1257,7 +1257,7 @@ debug_panel::update_section_eventqueue( std::vector &Output ) { auto const label { event->m_name + ( event->m_activator ? " (by: " + event->m_activator->asName + ")" : "" ) }; if( ( false == searchfilter.empty() ) - && ( label.find( searchfilter ) == std::string::npos ) ) { + && ( false == contains( label, searchfilter ) ) ) { event = event->m_next; continue; } diff --git a/editoruipanels.cpp b/editoruipanels.cpp index 66f58283..98ce04f4 100644 --- a/editoruipanels.cpp +++ b/editoruipanels.cpp @@ -394,7 +394,7 @@ nodebank_panel::render() { continue; } if( ( false == searchfilter.empty() ) - && ( entry.first.find( searchfilter ) == std::string::npos ) ) { + && ( false == contains( entry.first, searchfilter ) ) ) { continue; } auto const label { " " + entry.first + "##" + std::to_string( idx ) }; diff --git a/material.cpp b/material.cpp index f4ef9120..06a9634f 100644 --- a/material.cpp +++ b/material.cpp @@ -456,8 +456,9 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) { auto filename { Filename }; - if( filename.find( '|' ) != std::string::npos ) + if( contains( filename, '|' ) ) { filename.erase( filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury + } // discern references to textures generated by a script // TBD: support file: for file resources? diff --git a/mtable.cpp b/mtable.cpp index 19078968..09d04abd 100644 --- a/mtable.cpp +++ b/mtable.cpp @@ -287,7 +287,7 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax) while (fin.good() && !((ConversionError != 0) || EndTable)) { std::getline(fin, lines); /*wczytanie linii*/ - if (lines.find("___________________") != std::string::npos) /*linia pozioma górna*/ + if (contains( lines, "___________________") ) /*linia pozioma górna*/ { fin >> s; if (s == "[") /*lewy pion*/ @@ -312,7 +312,7 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax) TrainName = s; // nadanie nazwy z pliku TXT (bez ścieżki do pliku) while (fin >> s || fin.bad()) { - if (s.find("_______|") != std::string::npos) + if (contains( s,"_______|") ) { break; } @@ -393,7 +393,7 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax) do { fin >> s; - } while (!(s.find("[______________") != std::string::npos || fin.bad())); + } while (!(contains( s,"[______________" ) || fin.bad())); auto activeradiochannel{ -1 }; while (!fin.bad() && !EndTable) { @@ -408,21 +408,20 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax) fin >> s; else ConversionError = -4; - if (s.find("|") == std::string::npos) + if (false == contains( s,"|") ) { record->km = atof(s.c_str()); fin >> s; } - if (s.find("|_____|") != - std::string::npos) /*zmiana predkosci szlakowej*/ + if (contains( s,"|_____|")) /*zmiana predkosci szlakowej*/ UpdateVelocity(StationCount, vActual); else { fin >> s; - if (s.find("|") == std::string::npos) + if (false == contains(s,"|")) vActual = atof(s.c_str()); } - while (s.find("|") == std::string::npos) + while (false == contains( s,"|")) fin >> s; fin >> record->StationName; // get rid of non-ascii chars. TODO: run correct version based on locale @@ -435,7 +434,7 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax) fin >> s; if (s != "|") { - if (s.find(hrsd) != std::string::npos) + if (contains( s, hrsd) ) { record->Ah = atoi( s.substr(0, s.find(hrsd)).c_str()); // godzina przyjazdu record->Am = atof(s.substr(s.find(hrsd) + 1, s.length()).c_str()); // minuta przyjazdu @@ -457,7 +456,7 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax) fin >> s; } while (!((s == "[") || fin.bad())); fin >> s; - if (s.find("|") == std::string::npos) + if (false == contains(s,"|")) { /*tu s moze byc miejscem zmiany predkosci szlakowej*/ fin >> s; @@ -468,10 +467,10 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax) else { fin >> s; - if (s.find("|") == std::string::npos) + if (false == contains(s,"|")) vActual = atof(s.c_str()); } - while (s.find("|") == std::string::npos) + while (false == contains(s,"|")) fin >> s; // stationware. added fix for empty entry fin >> s; @@ -482,7 +481,7 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax) fin >> s; } // cache relevant station data - record->is_maintenance = ( s.find( "pt" ) != std::string::npos ); + record->is_maintenance = ( contains( s, "pt" ) ); { auto const stationware { Split( record->StationWare, ',' ) }; for( auto const &entry : stationware ) { @@ -510,7 +509,7 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax) fin >> s; if (s != "|") { - if (s.find(hrsd) != std::string::npos) + if (contains( s, hrsd) ) { record->Dh = atoi(s.substr(0, s.find(hrsd)).c_str()); // godzina odjazdu record->Dm = atof(s.substr(s.find(hrsd) + 1, s.length()).c_str()); // minuta odjazdu @@ -535,28 +534,27 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax) do { fin >> s; - } while (!((s.find("[") != std::string::npos) || fin.bad())); - if (s.find("_|_") == std::string::npos) + } while (!(contains( s, "[" ) || fin.bad())); + if (false == contains( s, "_|_")) fin >> s; - if (s.find("|") == std::string::npos) + if (false == contains( s, "|")) { /*tu s moze byc miejscem zmiany predkosci szlakowej*/ fin >> s; } - if (s.find("|_____|") != - std::string::npos) /*zmiana predkosci szlakowej*/ + if (contains( s, "|_____|") ) /*zmiana predkosci szlakowej*/ UpdateVelocity(StationCount, vActual); else { fin >> s; - if (s.find("|") == std::string::npos) + if (false == contains( s, "|")) vActual = atof(s.c_str()); } - while (s.find("|") == std::string::npos) + while (false == contains( s, "|" ) ) fin >> s; - while ((s.find("]") == std::string::npos)) + while ((false == contains( s,"]") )) fin >> s; - if (s.find("_|_") != std::string::npos) + if (contains( s,"_|_") ) EndTable = true; } /*timetableline*/ } @@ -633,7 +631,7 @@ bool TTrainParameters::DirectionChange() // sprawdzenie, czy po zatrzymaniu wykonać kolejne komendy { if ((StationIndex > 0) && (StationIndex < StationCount)) // dla ostatniej stacji nie - if (TimeTable[StationIndex].StationWare.find('@') != std::string::npos) + if (contains( TimeTable[StationIndex].StationWare, '@') ) return true; return false; } diff --git a/parser.cpp b/parser.cpp index 9d1dd943..f6fe3806 100644 --- a/parser.cpp +++ b/parser.cpp @@ -246,8 +246,8 @@ std::string cParser::readToken( bool ToLower, const char *Break ) { if( token == "include" ) { std::string includefile = readToken(ToLower); // nazwa pliku if( ( true == LoadTraction ) - || ( ( includefile.find( "tr/" ) == std::string::npos ) - && ( includefile.find( "tra/" ) == std::string::npos ) ) ) { + || ( ( false == contains( includefile, "tr/" ) ) + && ( false == contains( includefile, "tra/" ) ) ) ) { mIncludeParser = std::make_shared( includefile, buffer_FILE, mPath, LoadTraction, readParameters( *this ) ); mIncludeParser->autoclear( m_autoclear ); if( mIncludeParser->mSize <= 0 ) { @@ -266,8 +266,8 @@ std::string cParser::readToken( bool ToLower, const char *Break ) { cParser includeparser( token.substr( 7 ) ); std::string includefile = includeparser.readToken( ToLower ); // nazwa pliku if( ( true == LoadTraction ) - || ( ( includefile.find( "tr/" ) == std::string::npos ) - && ( includefile.find( "tra/" ) == std::string::npos ) ) ) { + || ( ( false == contains( includefile, "tr/" ) ) + && ( false == contains( includefile, "tra/" ) ) ) ) { mIncludeParser = std::make_shared( includefile, buffer_FILE, mPath, LoadTraction, readParameters( includeparser ) ); mIncludeParser->autoclear( m_autoclear ); if( mIncludeParser->mSize <= 0 ) { diff --git a/scene.cpp b/scene.cpp index e67f9798..2d0c776a 100644 --- a/scene.cpp +++ b/scene.cpp @@ -1190,7 +1190,7 @@ basic_region::insert( shape_node Shape, scratch_data &Scratchpad, bool const Tra auto const materialname{ GfxRenderer->Material( Shape.data().material ).name }; for( auto const &switchtrackbedtexture : switchtrackbedtextures ) { - if( materialname.find( switchtrackbedtexture ) != std::string::npos ) { + if( contains( materialname, switchtrackbedtexture ) ) { // geometry with blacklisted texture, part of old switch trackbed; ignore it return; } diff --git a/scenenode.cpp b/scenenode.cpp index 9769989f..6342db76 100644 --- a/scenenode.cpp +++ b/scenenode.cpp @@ -208,17 +208,17 @@ shape_node::import( cParser &Input, scene::node_data const &Nodedata ) { opengl_texture() ); // dirty workaround for lack of better api bool const clamps = ( texturehandle ? - texture.traits.find( 's' ) != std::string::npos : + contains( texture.traits, 's' ) : false ); bool const clampt = ( texturehandle ? - texture.traits.find( 't' ) != std::string::npos : + contains( texture.traits, 't' ) : false ); // remainder of legacy 'problend' system -- geometry assigned a texture with '@' in its name is treated as translucent, opaque otherwise if( texturehandle != null_handle ) { m_data.translucent = ( - ( ( texture.name.find( '@' ) != std::string::npos ) + ( ( contains( texture.name, '@' ) ) && ( true == texture.has_alpha ) ) ? true : false ); diff --git a/simulationstateserializer.cpp b/simulationstateserializer.cpp index eec2a2f7..97e53694 100644 --- a/simulationstateserializer.cpp +++ b/simulationstateserializer.cpp @@ -497,8 +497,8 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch // crude way to detect fixed switch trackbed geometry || ( ( true == Global.CreateSwitchTrackbeds ) && ( Input.Name().size() >= 15 ) - && ( Input.Name().substr( 0, 11 ) == "scenery/zwr" ) - && ( Input.Name().substr( Input.Name().size() - 4 ) == ".inc" ) ) }; + && ( starts_with( Input.Name(), "scenery/zwr" ) ) + && ( ends_with( Input.Name(), ".inc" ) ) ) }; if( false == skip ) { diff --git a/station.cpp b/station.cpp index 328ee4ce..8c6f2e57 100644 --- a/station.cpp +++ b/station.cpp @@ -30,9 +30,9 @@ basic_station::update_load( TDynamicObject *First, Mtable::TTrainParameters &Sch auto const stationname { Schedule.TimeTable[ Schedule.StationIndex ].StationName }; auto const stationequipment { Schedule.TimeTable[ Schedule.StationIndex ].StationWare }; auto const trainstop { ( - ( ( stationname.size() >= 2 ) && ( stationname.substr( stationname.size() - 2 ) == "po" ) ) - || ( stationequipment.find( "po" ) != std::string::npos ) ) }; - auto const maintenancestop { ( stationequipment.find( "pt" ) != std::string::npos ) }; + ( ends_with( stationname, "po" ) ) + || ( contains( stationequipment, "po" ) ) ) }; + auto const maintenancestop { ( contains( stationequipment, "pt" ) ) }; // train stops exchange smaller groups than regular stations // NOTE: this is crude and unaccurate, but for now will do auto const stationsizemodifier { ( trainstop ? 1.0 : 2.0 ) }; diff --git a/utilities.cpp b/utilities.cpp index a2e389d2..5be04bb5 100644 --- a/utilities.cpp +++ b/utilities.cpp @@ -475,6 +475,19 @@ starts_with( std::string_view const String, std::string_view Prefix ) { && ( 0 == String.compare( 0, Prefix.size(), Prefix ) ); } +// returns true if provided string contains another provided string +bool +contains( std::string_view const String, std::string_view Substring ) { + + return ( String.find( Substring ) != std::string::npos ); +} + +bool +contains( std::string_view const String, char Character ) { + + return ( String.find( Character ) != std::string::npos ); +} + // helper, restores content of a 3d vector from provided input stream // TODO: review and clean up the helper routines, there's likely some redundant ones glm::dvec3 LoadPoint( cParser &Input ) { diff --git a/utilities.h b/utilities.h index c1f1d3c9..579949e9 100644 --- a/utilities.h +++ b/utilities.h @@ -216,6 +216,9 @@ std::ptrdiff_t len_common_prefix( std::string const &Left, std::string const &Ri bool ends_with( std::string_view String, std::string_view Suffix ); // returns true if provided string begins with another provided string bool starts_with( std::string_view String, std::string_view Prefix ); +// returns true if provided string contains another provided string +bool contains( std::string_view const String, std::string_view Substring ); +bool contains( std::string_view const String, char Character ); template void SafeDelete( Type_ &Pointer ) { From 2e86b3a5e9623d93e015bdfadf35b3047a1e24f4 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 5 Jun 2021 21:30:53 +0200 Subject: [PATCH 3/3] ai braking test, motor overload relay threshold logic enhancement, vehicle max load parameter --- Driver.cpp | 408 ++++++++++++++++++++++++++++++++----------- Driver.h | 16 +- DynObj.cpp | 22 +++ McZapkie/MOVER.h | 4 +- McZapkie/Mover.cpp | 96 +++++----- McZapkie/hamulce.cpp | 36 +++- McZapkie/hamulce.h | 10 +- Train.cpp | 26 +-- driverhints.cpp | 2 +- driveruipanels.cpp | 8 +- utilities.h | 13 +- 11 files changed, 472 insertions(+), 169 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 7eeff552..7e4693b3 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -885,7 +885,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN IsScheduledPassengerStopVisible = false; mvOccupied->SecuritySystem.SHPLock = false; // te flagi są ustawiane tutaj, w razie potrzeby - iDrivigFlags &= ~(moveTrackEnd | moveSwitchFound | moveSemaphorFound | /*moveSpeedLimitFound*/ moveStopPointFound ); + iDrivigFlags &= ~(moveTrackEnd | moveSwitchFound | moveSignalFound | /*moveSpeedLimitFound*/ moveStopPointFound ); for( std::size_t idx = 0; idx < sSpeedTable.size(); ++idx ) { // o ile dana pozycja tabelki jest istotna @@ -1064,7 +1064,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN // jeśli mieliśmy ograniczenie z semafora i nie ma przed nami if( ( VelSignalLast >= 0.0 ) - && ( ( iDrivigFlags & ( moveSemaphorFound | moveSwitchFound | moveStopPointFound ) ) == 0 ) + && ( ( iDrivigFlags & ( moveSignalFound | moveSwitchFound | moveStopPointFound ) ) == 0 ) && ( true == TestFlag( OrderCurrentGet(), Obey_train ) ) ) { VelSignalLast = -1.0; } @@ -1557,7 +1557,7 @@ TController::TableUpdateEvent( double &Velocity, TCommandType &Command, TSpeedPo } else { //jeśli z przodu to dajemy flagę, że jest - iDrivigFlags |= moveSemaphorFound; + iDrivigFlags |= moveSignalFound; Signaldistance = std::min( Point.fDist, Signaldistance ); // if there's another vehicle closer to the signal, then it's likely its intended recipient // HACK: if so, make it a stop point, to prevent non-signals farther down affect us @@ -1854,23 +1854,23 @@ void TController::TableSort() { //--------------------------------------------------------------------------- -TController::TController(bool AI, TDynamicObject *NewControll, bool InitPsyche, bool primary) :// czy ma aktywnie prowadzić? +TController::TController(bool AI, TDynamicObject *NewControll, bool InitPsyche, bool Primary) :// czy ma aktywnie prowadzić? AIControllFlag( AI ), pVehicle( NewControll ) { - ControllingSet(); // utworzenie połączenia do sterowanego pojazdu if( pVehicle != nullptr ) { - pVehicles[ 0 ] = pVehicle->GetFirstDynamic( 0 ); // pierwszy w kierunku jazdy (Np. Pc1) - pVehicles[ 1 ] = pVehicle->GetFirstDynamic( 1 ); // ostatni w kierunku jazdy (końcówki) + pVehicles[ end::front ] = pVehicle->GetFirstDynamic( end::front ); // pierwszy w kierunku jazdy (Np. Pc1) + pVehicles[ end::rear ] = pVehicle->GetFirstDynamic( end::rear ); // ostatni w kierunku jazdy (końcówki) } else { - pVehicles[ 0 ] = nullptr; - pVehicles[ 1 ] = nullptr; + pVehicles[ end::front ] = nullptr; + pVehicles[ end::rear ] = nullptr; } + ControllingSet(); // utworzenie połączenia do sterowanego pojazdu if( mvOccupied != nullptr ) { iDirectionOrder = mvOccupied->CabActive; // 1=do przodu (w kierunku sprzęgu 0) VehicleName = mvOccupied->Name; - if( mvOccupied->CategoryFlag & 2 ) { // samochody: na podst. http://www.prawko-kwartnik.info/hamowanie.html + if( is_car() ) { // samochody: na podst. http://www.prawko-kwartnik.info/hamowanie.html // fDriverBraking=0.0065; //mnożone przez (v^2+40*v) [km/h] daje prawie drogę hamowania [m] fDriverBraking = 0.03; // coś nie hamują te samochody zbyt dobrze fDriverDist = 5.0; // 5m - zachowywany odstęp przed kolizją @@ -1907,7 +1907,7 @@ TController::TController(bool AI, TDynamicObject *NewControll, bool InitPsyche, // OrderValue=0; OrdersClear(); - if( true == primary ) { + if( true == Primary ) { iDrivigFlags |= movePrimary; // aktywnie prowadzące pojazd } @@ -2105,8 +2105,8 @@ void TController::Activation() { // jeśli zmieniony został pojazd prowadzony ControllingSet(); // utworzenie połączenia do sterowanego pojazdu (może się zmienić) - silnikowy dla EZT if( ( mvOccupied->BrakeCtrlPosNo > 0 ) - && ( ( mvOccupied->BrakeSystem == TBrakeSystem::Pneumatic ) - || ( mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ) ) ) { + && ( ( BrakeSystem == TBrakeSystem::Pneumatic ) + || ( BrakeSystem == TBrakeSystem::ElectroPneumatic ) ) ) { mvOccupied->LimPipePress = mvOccupied->PipePress; mvOccupied->ActFlowSpeed = 0; } @@ -2242,6 +2242,7 @@ void TController::AutoRewident() } // potentially release manual brake d->MoverParameters->DecManualBrakeLevel( ManualBrakePosNo ); + d->MoverParameters->SpringBrake.Activate = false; } d = d->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła) } @@ -2276,6 +2277,9 @@ void TController::AutoRewident() fNominalAccThreshold = fAccThreshold; } + BrakeSystem = consist_brake_system(); + mvOccupied->EpFuseSwitch( BrakeSystem == TBrakeSystem::ElectroPneumatic ); + if( OrderCurrentGet() & ( Obey_train | Bank ) ) { // 4. Przeliczanie siły hamowania double const velstep = ( mvOccupied->Vmax*0.5 ) / BrakeAccTableSize; @@ -2310,12 +2314,13 @@ void TController::AutoRewident() 0.25 ); if( is_emu() ) { + auto ep_factor { ( BrakeSystem == TBrakeSystem::ElectroPneumatic ? 8 : 4 ) }; if( mvControlling->EngineType == TEngineType::ElectricInductionMotor ) { // HACK: emu with induction motors need to start their braking a bit sooner than the ones with series motors - fNominalAccThreshold = std::max( -0.60, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] ); + fNominalAccThreshold = std::max( -0.60, -fBrake_a0[ BrakeAccTableSize ] - ep_factor * fBrake_a1[ BrakeAccTableSize ] ); } else { - fNominalAccThreshold = std::max( -0.75, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] ); + fNominalAccThreshold = std::max( -0.75, -fBrake_a0[ BrakeAccTableSize ] - ep_factor * fBrake_a1[ BrakeAccTableSize ] ); } fBrakeReaction = 0.25; } @@ -2503,6 +2508,18 @@ bool TController::CheckVehicles(TOrders user) } } + // kasowanie pamieci hamowania kontrolnego + if (OrderCurrentGet() & (Shunt | Loose_shunt | Disconnect | Connect | Change_direction)) { + DynamicBrakeTest = 0; + DBT_VelocityBrake + = DBT_VelocityRelease + = DBT_VelocityFinish + = DBT_BrakingTime + = DBT_ReleasingTime + = DBT_MidPointAcc + = 0; + } + // HACK: ensure vehicle lights are active from the beginning, if it had pre-activated battery if( mvOccupied->LightsPosNo > 0 ) { pVehicle->SetLights(); @@ -2608,6 +2625,31 @@ void TController::DirectionChange() { } } +TBrakeSystem TController::consist_brake_system() const { + + if( mvOccupied->BrakeSystem != TBrakeSystem::ElectroPneumatic ) { return mvOccupied->BrakeSystem; } + + auto isepcapable = true; + if( pVehicles[ end::front ] != pVehicles[ end::rear ] ) { + // more detailed version, will use manual braking also for coupled sets of controlled vehicles + auto *vehicle = pVehicles[ end::front ]; // start from first + while( ( true == isepcapable ) + && ( vehicle != nullptr ) ) { + // NOTE: we could simplify this by doing only check of the rear coupler, but this can be quite tricky in itself + // TODO: add easier ways to access front/rear coupler taking into account vehicle's direction + isepcapable = ( + ( ( vehicle->MoverParameters->Couplers[ end::front ].Connected == nullptr ) + || ( ( vehicle->MoverParameters->Couplers[ end::front ].CouplingFlag & coupling::control ) + && ( vehicle->MoverParameters->Couplers[ end::front ].Connected->Power > -1 ) ) ) + && ( ( vehicle->MoverParameters->Couplers[ end::rear ].Connected == nullptr ) + || ( ( vehicle->MoverParameters->Couplers[ end::rear ].CouplingFlag & coupling::control ) + && ( vehicle->MoverParameters->Couplers[ end::rear ].Connected->Power > -1 ) ) ) ); + vehicle = vehicle->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła) + } + } + return ( isepcapable ? TBrakeSystem::ElectroPneumatic : TBrakeSystem::Pneumatic ); +} + int TController::OrderDirectionChange(int newdir, TMoverParameters *Vehicle) { // zmiana kierunku jazdy, niezależnie od kabiny int testd = newdir; @@ -2961,8 +3003,12 @@ bool TController::ReleaseEngine() { bool TController::IncBrake() { // zwiększenie hamowania - bool OK = false; - switch( mvOccupied->BrakeSystem ) { + auto OK { false }; + auto const bs { + ( ( BrakeSystem == TBrakeSystem::ElectroPneumatic ) && ( ForcePNBrake ) ) ? + TBrakeSystem::Pneumatic : + BrakeSystem }; + switch( bs ) { case TBrakeSystem::Individual: { if( mvOccupied->LocalBrake == TLocalBrake::ManualBrake ) { OK = mvOccupied->IncManualBrakeLevel( 1 + static_cast( std::floor( 0.5 + std::fabs( AccDesired ) ) ) ); @@ -2973,8 +3019,15 @@ bool TController::IncBrake() break; } case TBrakeSystem::Pneumatic: { + if (bs != mvOccupied->BrakeSystem) + { + while (mvOccupied->BrakeOpModeFlag > bom_PN) + { + mvOccupied->BrakeOpModeFlag >>= 1; + } + } // NOTE: can't perform just test whether connected vehicle == nullptr, due to virtual couplers formed with nearby vehicles - bool standalone { true }; + auto standalone { true }; if( ( mvOccupied->TrainType == dt_ET41 ) || ( mvOccupied->TrainType == dt_ET42 ) ) { // NOTE: we're doing simplified checks full of presuptions here. @@ -3024,7 +3077,7 @@ bool TController::IncBrake() //standalone = standalone && ( mvControlling->EIMCtrlType == 0 ); - if( true == standalone ) { + if( ( true == standalone ) && ( false == ForcePNBrake ) ) { if( mvControlling->EIMCtrlType > 0 ) { OK = IncBrakeEIM(); } @@ -3101,6 +3154,9 @@ bool TController::IncBrake() break; } case TBrakeSystem::ElectroPneumatic: { + while( ( mvOccupied->BrakeOpModeFlag << 1 ) <= mvOccupied->BrakeOpModes ) { + mvOccupied->BrakeOpModeFlag <<= 1; + } if( mvOccupied->EngineType == TEngineType::ElectricInductionMotor ) { if (mvOccupied->BrakeHandle == TBrakeHandle::MHZ_EN57) { if (mvOccupied->BrakeCtrlPos < mvOccupied->Handle->GetPos(bh_FB)) @@ -3188,8 +3244,11 @@ bool TController::IncBrakeEIM() bool TController::DecBrake() { auto OK { false }; - - switch( mvOccupied->BrakeSystem ) { + auto const bs { + ( ( BrakeSystem == TBrakeSystem::ElectroPneumatic ) && ( ForcePNBrake ) ) ? + TBrakeSystem::Pneumatic : + BrakeSystem }; + switch( bs ) { case TBrakeSystem::Individual: { auto const positionchange { 1 + std::floor( 0.5 + std::abs( AccDesired ) ) }; OK = ( @@ -3357,12 +3416,24 @@ bool TController::IncSpeed() || (mvControlling->StLinFlag)) { // youBy polecił dodać 2012-09-08 v367 // na pozycji 0 przejdzie, a na pozostałych będzie czekać, aż się załączą liniowe (zgaśnie DelayCtrlFlag) if (Ready || (iDrivigFlags & movePress)) { + auto const usehighoverloadrelaythreshold { + ( mvControlling->TrainType != dt_ET42 ) // ET42 uses these variables for different purpose. TODO: fix this + && ( mvControlling->ImaxHi > mvControlling->ImaxLo ) + && ( mvOccupied->Vel < ( mvControlling->IsMotorOverloadRelayHighThresholdOn() ? 30.0 : 20.0 ) ) + && ( iVehicles - ControlledEnginesCount > 0 ) +// && ( std::fabs( mvControlling->Im ) > 0.85 * mvControlling->Imax ) + && ( ( mvControlling->Imax * mvControlling->EngineVoltage * ControlledEnginesCount ) + / ( fMass * ( + fAccGravity == 0.025 ? + -0.01 : // prevent div/0 + fAccGravity - 0.025 ) ) + < -2.8 ) }; // use series mode: // if high threshold is set for motor overload relay, // if the power station is heavily burdened, // if it generates enough traction force // to build up speed to 30/40 km/h for passenger/cargo train (10 km/h less if going uphill) - auto const sufficienttractionforce { std::abs( mvControlling->Ft ) > ( IsHeavyCargoTrain ? 75 : 50 ) * 1000.0 }; + auto const sufficienttractionforce { std::abs( mvControlling->Ft ) * ControlledEnginesCount > ( IsHeavyCargoTrain ? 75 : 50 ) * 1000.0 }; auto const sufficientacceleration { AbsAccS >= ( IsHeavyCargoTrain ? 0.03 : IsCargoTrain ? 0.06 : 0.09 ) }; auto const seriesmodefieldshunting { ( mvControlling->ScndCtrlPos > 0 ) && ( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn == 1 ) }; auto const parallelmodefieldshunting { ( mvControlling->ScndCtrlPos > 0 ) && ( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn > 1 ) }; @@ -3373,6 +3444,7 @@ bool TController::IncSpeed() ( IsHeavyCargoTrain ? 0.35 : 0.40 ) ) }; auto const useseriesmode = ( ( mvControlling->Imax > mvControlling->ImaxLo ) + || ( true == usehighoverloadrelaythreshold ) || ( fVoltage < useseriesmodevoltage ) || ( ( true == sufficientacceleration ) && ( true == sufficienttractionforce ) @@ -3390,6 +3462,32 @@ bool TController::IncSpeed() mvControlling->RList[ mvControlling->MainCtrlPos ].Bn > 1 : mvControlling->MainCtrlPos == mvControlling->MainCtrlPosNo ) ) ); + // if needed enable high threshold for overload relay... + if( mvControlling->TrainType != dt_ET42 ) { // ET42 uses these variables for different purpose. TODO: fix this + if( usehighoverloadrelaythreshold ) { + if( mvControlling->Imax < mvControlling->ImaxHi ) { + // to enable this setting we'll typically need the main controller in series mode (which is not guaranteed) + if( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn > 1 ) { + if( false == mvControlling->IsScndCtrlNoPowerPos() ) { + mvControlling->DecScndCtrl( 2 ); + } + while( ( false == mvControlling->IsMainCtrlNoPowerPos() ) + && ( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn > 1 ) ) { + mvControlling->DecMainCtrl( 1 ); // kręcimy nastawnik jazdy o 1 wstecz + } + } + mvControlling->CurrentSwitch( true ); // rozruch wysoki (za to może się ślizgać) + } + } + // ...or disable high threshold for overload relay if no longer needed + else { + if( ( mvControlling->IsMotorOverloadRelayHighThresholdOn() ) + && ( std::fabs( mvControlling->Im ) < mvControlling->ImaxLo ) ) { + mvControlling->CurrentSwitch( false ); // rozruch wysoki wyłącz + } + } + } + double Vs = 99999; if( usefieldshunting ? ( mvControlling->ScndCtrlPos < mvControlling->ScndCtrlPosNo ) : @@ -3677,21 +3775,36 @@ bool TController::IncSpeedEIM() { bool TController::DecSpeedEIM( int const Amount ) { // zmniejszenie prędkości (ale nie hamowanie) bool OK = false; // domyślnie false, aby wyszło z pętli while - switch (mvControlling->EIMCtrlType) - { - case 0: - OK = mvControlling->DecMainCtrl( Amount ); - break; - case 1: - OK = mvControlling->MainCtrlPos > 4; - if (OK) - mvControlling->MainCtrlPos = 4; - break; - case 2: - OK = mvControlling->MainCtrlPos > 2; - if (OK) - mvControlling->MainCtrlPos = 2; - break; + switch( mvControlling->EIMCtrlType ) { + case 0: { + OK = mvControlling->DecMainCtrl( Amount ); + break; + } + case 1: { + OK = mvControlling->MainCtrlPos > 4; + if( OK ) { + mvControlling->MainCtrlPos = 4; + } + break; + } + case 2: { + if( ( AccDesired > 0 ) + && ( mvControlling->SpeedCtrlUnit.IsActive ) + && ( mvControlling->SpeedCtrlUnit.PowerStep > 0 ) + && ( mvControlling->SpeedCtrlUnit.DesiredPower > mvControlling->SpeedCtrlUnit.MinPower ) ) { + mvControlling->SpeedCtrlPowerDec(); + } + else { + OK = mvControlling->MainCtrlPos > 2; + if( OK ) { + mvControlling->MainCtrlPos = 2; + } + } + break; + } + default: { + break; + } } return OK; } @@ -3785,56 +3898,51 @@ void TController::SpeedSet() { break; } case TEngineType::ElectricSeriesMotor: { +/* if (Ready || (iDrivigFlags & movePress)) { // o ile może jechać - if (fAccGravity < -0.10) // i jedzie pod górę większą niż 10 promil +// if (fAccGravity < -0.10) // i jedzie pod górę większą niż 10 promil { // procedura wjeżdżania na ekstremalne wzniesienia - if (fabs(mvControlling->Im) > 0.85 * mvControlling->Imax) // a prąd jest większy niż 85% nadmiarowego - if (mvControlling->Imax * mvControlling->EngineVoltage / (fMass * fAccGravity) < -2.8) // a na niskim się za szybko nie pojedzie + if( std::fabs( mvControlling->Im ) > 0.85 * mvControlling->Imax ) { // a prąd jest większy niż 85% nadmiarowego + if( mvControlling->Imax * mvControlling->EngineVoltage / ( fMass * fAccGravity ) < -2.8 ) // a na niskim się za szybko nie pojedzie { // włączenie wysokiego rozruchu; // (I*U)[A*V=W=kg*m*m/sss]/(m[kg]*a[m/ss])=v[m/s]; 2.8m/ss=10km/h - if (mvControlling->RList[mvControlling->MainCtrlPos].Bn > 1) - { // jeśli jedzie na równoległym, to zbijamy do szeregowego, aby włączyć - // wysoki rozruch - if (mvControlling->ScndCtrlPos > 0) // jeżeli jest bocznik - mvControlling->DecScndCtrl(2); // wyłączyć bocznik, bo może blokować skręcenie NJ - do // skręcanie do bezoporowej na szeregowym - mvControlling->DecMainCtrl(1); // kręcimy nastawnik jazdy o 1 wstecz - while (mvControlling->MainCtrlPos ? - mvControlling->RList[mvControlling->MainCtrlPos].Bn > 1 : - false); // oporowa zapętla + if( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn > 1 ) { // jeśli jedzie na równoległym, to zbijamy do szeregowego, aby włączyć wysoki rozruch + if( mvControlling->ScndCtrlPos > 0 ) { // jeżeli jest bocznik + mvControlling->DecScndCtrl( 2 ); // wyłączyć bocznik, bo może blokować skręcenie NJ + } + do { // skręcanie do bezoporowej na szeregowym + mvControlling->DecMainCtrl( 1 ); // kręcimy nastawnik jazdy o 1 wstecz + } + while( ( false == mvControlling->IsMainCtrlNoPowerPos() ) + && ( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn > 1 ) ); // oporowa zapętla } - if (mvControlling->Imax < mvControlling->ImaxHi) // jeśli da się na wysokim - mvControlling->CurrentSwitch(true); // rozruch wysoki (za to może się ślizgać) - if (ReactionTime > 0.1) + if( mvControlling->Imax < mvControlling->ImaxHi ) { // jeśli da się na wysokim + mvControlling->CurrentSwitch( true ); // rozruch wysoki (za to może się ślizgać) + } + if( ReactionTime > 0.1 ) { ReactionTime = 0.1; // orientuj się szybciej + } } // if (Im>Imin) - // NOTE: this step is likely to conflict with directive to operate sandbox based on the state of slipping wheels - // TODO: gather all sandbox operating logic in one place - if( fabs( mvControlling->Im ) > 0.75 * mvControlling->ImaxHi ) { - // jeśli prąd jest duży - mvControlling->Sandbox( true ); // piaskujemy tory, coby się nie ślizgać } - else { - // otherwise we switch the sander off, if it's active - if( mvControlling->SandDose ) { - mvControlling->Sandbox( false ); + if( std::fabs( mvControlling->Im ) > 0.96 * mvControlling->Imax ) {// jeśli prąd jest duży (można 690 na 750) + if( mvControlling->ScndCtrlPos > 0 ) { // jeżeli jest bocznik + mvControlling->DecScndCtrl( 2 ); // zmniejszyć bocznik + } + else { + mvControlling->DecMainCtrl( 1 ); // kręcimy nastawnik jazdy o 1 wstecz } } - if ((fabs(mvControlling->Im) > 0.96 * mvControlling->Imax) || - mvControlling->SlippingWheels) // jeśli prąd jest duży (można 690 na 750) - if (mvControlling->ScndCtrlPos > 0) // jeżeli jest bocznik - mvControlling->DecScndCtrl(2); // zmniejszyć bocznik - else - mvControlling->DecMainCtrl(1); // kręcimy nastawnik jazdy o 1 wstecz } - else // gdy nie jedzie ambitnie pod górę +// else // gdy nie jedzie ambitnie pod górę { // sprawdzenie, czy rozruch wysoki jest potrzebny - if (mvControlling->Imax > mvControlling->ImaxLo) - if (mvOccupied->Vel >= 30.0) // jak się rozpędził - if (fAccGravity > -0.02) // a i pochylenie mnijsze niż 2‰ - mvControlling->CurrentSwitch(false); // rozruch wysoki wyłącz + if( ( mvControlling->Imax > mvControlling->ImaxLo ) + && ( mvOccupied->Vel >= 30.0 ) ) { // jak się rozpędził +// if (fAccGravity > -0.02) // a i pochylenie mnijsze niż 2‰ + mvControlling->CurrentSwitch( false ); // rozruch wysoki wyłącz + } } } +*/ break; } case TEngineType::Dumb: { @@ -3926,13 +4034,14 @@ void TController::SetTimeControllers() if( false == AIControllFlag ) { return; } //1. Check the type of Main Brake Handle - if (mvOccupied->BrakeSystem == TBrakeSystem::Pneumatic) - { + if( BrakeSystem == TBrakeSystem::Pneumatic || ForcePNBrake ) + { if (mvOccupied->Handle->Time) { - if ((BrakeCtrlPosition > 0) && (mvOccupied->Handle->GetCP() - 0.05 > mvOccupied->HighPipePress - BrakeCtrlPosition*0.25*mvOccupied->DeltaPipePress)) + auto const pressuredifference { mvOccupied->Handle->GetCP() - ( mvOccupied->HighPipePress - BrakeCtrlPosition * 0.25*mvOccupied->DeltaPipePress ) }; + if ((BrakeCtrlPosition > 0) && (pressuredifference > 0.05)) mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_FB)); - else if ((BrakeCtrlPosition > 0) && (mvOccupied->Handle->GetCP() + 0.05 < mvOccupied->HighPipePress - BrakeCtrlPosition*0.25*mvOccupied->DeltaPipePress)) + else if ((BrakeCtrlPosition > 0) && (pressuredifference < -0.05)) mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_RP)); else if (BrakeCtrlPosition == 0) mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_RP)); @@ -3941,21 +4050,29 @@ void TController::SetTimeControllers() else if (BrakeCtrlPosition == -2) mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_NP)); } - if (mvOccupied->BrakeHandle == TBrakeHandle::FV4a) mvOccupied->BrakeLevelSet(BrakeCtrlPosition); - if (mvOccupied->BrakeHandle == TBrakeHandle::MHZ_K8P) - { - if (BrakeCtrlPosition == 0) - mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_RP)); - else if (BrakeCtrlPosition == -1) - mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_FS)); - else if (BrakeCtrlPosition == -2) - mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_NP)); - else if (BrakeCtrlPosition > 4.5) - mvOccupied->BrakeLevelSet(10); - else if (BrakeCtrlPosition > 3.70) - mvOccupied->BrakeLevelSet(9); - else - mvOccupied->BrakeLevelSet(round((BrakeCtrlPosition * 0.4 - 0.1) / 0.15)); + if( mvOccupied->BrakeHandle == TBrakeHandle::FV4a ) { + mvOccupied->BrakeLevelSet( BrakeCtrlPosition ); + } + if( ( mvOccupied->BrakeHandle == TBrakeHandle::MHZ_K8P ) + || ( mvOccupied->BrakeHandle == TBrakeHandle::MHZ_EN57 ) ) { + if( BrakeCtrlPosition == 0 ) { + mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_RP ) ); + } + else if( BrakeCtrlPosition == -1 ) { + mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_FS ) ); + } + else if( BrakeCtrlPosition == -2 ) { + mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_NP ) ); + } + else if( BrakeCtrlPosition > 4.5 ) { + mvOccupied->BrakeLevelSet( 10 ); + } + else if( BrakeCtrlPosition > 3.70 ) { + mvOccupied->BrakeLevelSet( 9 ); + } + else { + mvOccupied->BrakeLevelSet( round( ( BrakeCtrlPosition * 0.4 - 0.1 ) / 0.15 ) ); + } } } //2. Check the type of Secondary Brake Handle @@ -4130,12 +4247,12 @@ void TController::CheckTimeControllers() if( false == AIControllFlag ) { return; } //1. Check the type of Main Brake Handle - if (mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic && mvOccupied->Handle->TimeEP) - { + if( BrakeSystem == TBrakeSystem::ElectroPneumatic && mvOccupied->Handle->TimeEP && !ForcePNBrake ) + { mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EPN)); } - if (mvOccupied->BrakeSystem == TBrakeSystem::Pneumatic && mvOccupied->Handle->Time) - { + if( ( BrakeSystem == TBrakeSystem::Pneumatic || ForcePNBrake ) && mvOccupied->Handle->Time ) + { if (BrakeCtrlPosition > 0) mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_MB)); else @@ -5754,6 +5871,7 @@ void TController::ControllingSet() lookup->MoverParameters : mvControlling ); } + BrakeSystem = consist_brake_system(); }; std::string TController::TableText( std::size_t const Index ) const @@ -5872,7 +5990,7 @@ TController::determine_consist_state() { Ready = true; // wstępnie gotowy fReady = 0.0; // założenie, że odhamowany IsConsistBraked = ( - mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ? + ( ( mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ) && ( false == ForcePNBrake ) ) ? mvOccupied->BrakePress > 2.0 : mvOccupied->PipePress < std::max( 3.9, mvOccupied->BrakePressureActual.PipePressureVal ) + 0.1 ); fAccGravity = 0.0; // przyspieszenie wynikające z pochylenia @@ -5888,8 +6006,10 @@ TController::determine_consist_state() { auto const bp { std::max( 0.0, vehicle->BrakePress - ( vehicle->SpeedCtrlUnit.Parking ? vehicle->MaxBrakePress[ 0 ] * vehicle->StopBrakeDecc : 0.0 ) ) }; if (Ready) { // bo jak coś nie odhamowane, to dalej nie ma co sprawdzać - if( ( TestFlag( vehicle->Hamulec->GetBrakeStatus(), b_hld ) ) - || ( ( vehicle->Vel < 1.0 ) && ( bp > 0.4 ) ) ) { // ensure the brakes are sufficiently released when starting to move + if( ( TestFlagAny( vehicle->Hamulec->GetBrakeStatus(), ( b_hld | b_on ) ) ) + || ( ( vehicle->Vel < 1.0 ? + ( bp > 0.4 ) : // ensure the brakes are sufficiently released when starting to move + ( vehicle->Fb * 0.001 > 10.0 ) ) ) ) { // once in motion we can make a more lenient check Ready = false; } // Ra: odluźnianie przeładowanych lokomotyw, ciągniętych na zimno - prowizorka... @@ -6028,6 +6148,9 @@ TController::control_wheelslip() { cue_action( locale::string::driver_hint_antislip ); ++iDriverFailCount; } + else if( std::fabs( mvControlling->Im ) > 0.75 * mvControlling->ImaxHi ) { + cue_action( locale::string::driver_hint_sandingon ); // piaskujemy tory, coby się nie ślizgać + } else { // deactivate sandbox if we aren't slipping if( mvControlling->SandDose ) { @@ -6970,7 +7093,7 @@ TController::UpdateDisconnect() { else { WriteLog( "Uncoupling [" + mvOccupied->Name + "]: direction change" ); /* // TODO: test if this block is needed - if( mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ) { + if( BrakeSystem == TBrakeSystem::ElectroPneumatic ) { // wyłączenie EP, gdy wystarczy (może nie być potrzebne, bo na początku jest) mvOccupied->BrakeLevelSet( 0 ); } @@ -7159,6 +7282,7 @@ TController::pick_optimal_speed( double const Range ) { adjust_desired_speed_for_limits(); adjust_desired_speed_for_target_speed( Range ); adjust_desired_speed_for_current_speed(); + adjust_desired_speed_for_braking_test(); // Ra 2F1I: wyłączyć kiedyś to uśrednianie i przeanalizować skanowanie, czemu migocze if( AccDesired > EU07_AI_NOACCELERATION ) { // hamowania lepeiej nie uśredniać @@ -7619,6 +7743,82 @@ TController::adjust_desired_speed_for_current_speed() { } } +// hamowanie kontrolne +void +TController::adjust_desired_speed_for_braking_test() { + +// if( false == Global.DynamicBrakeTest ) { return; } + if( DynamicBrakeTest >= 5 ) { return; } // all done + if( false == is_train() ) { return; } // not applicable + if( false == TestFlag( OrderCurrentGet(), Obey_train ) ) { return; } // not applicable + if( false == AIControllFlag ) { return; } // TBD: add notification about braking test and enable it for human driver as well? + + auto const vel { DirectionalVel() }; + + switch( DynamicBrakeTest ) { + case 0: { + if( ( primary() ) + && ( vel < VelDesired ) + && ( fAccGravity >= 0.0 ) // not if going uphill + && ( AccDesired >= EU07_AI_ACCELERATION ) + && ( TrainParams.TTVmax >= 10.0 ) + && ( vel > std::min( TrainParams.TTVmax, 60.0 ) - 2.0 ) ) { + DynamicBrakeTest = 1; + DBT_BrakingTime = ElapsedTime; + DBT_VelocityBrake = vel; + } + break; + } + case 1: { + AccDesired = EU07_AI_BRAKINGTESTACCELERATION; + VelDesired = DBT_VelocityBrake; + if( ElapsedTime - DBT_BrakingTime > 1 ) { + ForcePNBrake = true; + mvOccupied->EpFuseSwitch( false ); + DynamicBrakeTest = 2; + } + break; + } + case 2: { + AccDesired = EU07_AI_BRAKINGTESTACCELERATION; + VelDesired = DBT_VelocityBrake; + if( ElapsedTime - DBT_BrakingTime > 2 ) { + DBT_BrakingTime = ElapsedTime; + DBT_VelocityBrake = vel; + DBT_VelocityRelease = vel - 8.0; + DynamicBrakeTest = 3; + } + break; + } + case 3: { + AccDesired = clamp( -AbsAccS, fAccThreshold * 1.01, fAccThreshold * 1.21 ); + VelDesired = DBT_VelocityBrake; + if( vel <= DBT_VelocityRelease ) { + DynamicBrakeTest = 4; + DBT_BrakingTime = ElapsedTime - DBT_BrakingTime; + DBT_MidPointAcc = AbsAccS; + DBT_ReleasingTime = ElapsedTime; + } + break; + } + case 4: { + if( Ready ) { + if( BrakeSystem == TBrakeSystem::ElectroPneumatic ) { + mvOccupied->EpFuseSwitch( true ); + } + ForcePNBrake = false; + DynamicBrakeTest = 5; + DBT_ReleasingTime = ElapsedTime - DBT_ReleasingTime; + DBT_VelocityFinish = vel; + } + break; + } + default: { + break; + } + } +} + void TController::control_tractive_and_braking_force() { @@ -7701,7 +7901,7 @@ void TController::control_tractive_force() { auto const velocity { DirectionalVel() }; // jeśli przyspieszenie pojazdu jest mniejsze niż żądane oraz... if( ( AccDesired > EU07_AI_NOACCELERATION ) // don't add power if not asked for actual speed-up - && (( AbsAccS < AccDesired /* - 0.05 */ ) || (mvOccupied->SpeedCtrlUnit.IsActive && velocity < mvOccupied->SpeedCtrlUnit.FullPowerVelocity)) + && (( AbsAccS < AccDesired - std::min( 0.05, 0.01 * iDriverFailCount ) ) || (mvOccupied->SpeedCtrlUnit.IsActive && velocity < mvOccupied->SpeedCtrlUnit.FullPowerVelocity)) && ( false == TestFlag( iDrivigFlags, movePress ) ) ) { // ...jeśli prędkość w kierunku czoła jest mniejsza od dozwolonej o margines... if( velocity < ( @@ -7780,7 +7980,7 @@ void TController::control_braking_force() { } } - if( is_emu() ) { + if( is_emu() && ( !ForcePNBrake ) ) { // właściwie, to warunek powinien być na działający EP // Ra: to dobrze hamuje EP w EZT auto const accthreshold { ( @@ -7896,7 +8096,7 @@ void TController::control_releaser() { if( ( mvOccupied->Vel < 1.0 ) && ( fActionTime < 0.0 ) ) { return; } // TODO: combine all releaser handling in single decision tree instead of having bits all over the place // TODO: replace handle and system conditions with flag indicating releaser presence - if( mvOccupied->BrakeSystem != TBrakeSystem::Pneumatic ) { return; } + if( BrakeSystem != TBrakeSystem::Pneumatic ) { return; } auto const hasreleaser { ( false == ( is_dmu() || is_emu() ) ) // TODO: a more refined test than rejecting these types wholesale @@ -7964,7 +8164,7 @@ void TController::control_main_pipe() { } // napełnianie uderzeniowe - if( mvOccupied->BrakeSystem != TBrakeSystem::Pneumatic ) { return; } + if( BrakeSystem != TBrakeSystem::Pneumatic ) { return; } if( ( mvOccupied->BrakeHandle == TBrakeHandle::FV4a ) || ( mvOccupied->BrakeHandle == TBrakeHandle::MHZ_6P ) diff --git a/Driver.h b/Driver.h index 9431c1e7..7e9e4be3 100644 --- a/Driver.h +++ b/Driver.h @@ -17,7 +17,9 @@ http://mozilla.org/MPL/2.0/. #include "mtable.h" #include "translation.h" +auto const EU07_AI_ACCELERATION = 0.05; auto const EU07_AI_NOACCELERATION = -0.05; +auto const EU07_AI_BRAKINGTESTACCELERATION = -0.06; auto const EU07_AI_NOMOVEMENT = 0.05; // standstill velocity threshold auto const EU07_AI_MOVEMENT = 1.0; // deliberate movement velocity threshold auto const EU07_AI_SPEEDLIMITEXTENDSBEYONDSCANRANGE = 10000.0; @@ -61,7 +63,7 @@ enum TMovementStatus moveVisibility = 0x10000, // jazda na widoczność po przejechaniu S1 na SBL moveDoorOpened = 0x20000, // drzwi zostały otwarte - doliczyć czas na zamknięcie movePushPull = 0x40000, // zmiana czoła przez zmianę kabiny - nie odczepiać przy zmianie kierunku - moveSemaphorFound = 0x80000, // na drodze skanowania został znaleziony semafor + moveSignalFound = 0x80000, // na drodze skanowania został znaleziony semafor moveStopPointFound = 0x100000 // stop point detected ahead /* moveSemaphorWasElapsed = 0x100000, // minięty został semafor @@ -250,6 +252,7 @@ public: return ( ( mvControlling->EngineType == TEngineType::DieselElectric ) || ( mvControlling->EngineType == TEngineType::DieselEngine ) ); } + TBrakeSystem consist_brake_system() const; private: void Activation(); // umieszczenie obsady w odpowiednim członie void ControllingSet(); // znajduje człon do sterowania @@ -327,6 +330,7 @@ private: void adjust_desired_speed_for_limits(); void adjust_desired_speed_for_target_speed( double const Range ); void adjust_desired_speed_for_current_speed(); + void adjust_desired_speed_for_braking_test(); void control_tractive_and_braking_force(); void control_releaser(); void control_main_pipe(); @@ -431,6 +435,16 @@ private: double ReactionTime = 0.0; // czas reakcji Ra: czego i na co? świadomości AI double fBrakeTime = 0.0; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca double BrakeChargingCooldown{}; // prevents the ai from trying to charge the train brake too frequently + TBrakeSystem BrakeSystem = TBrakeSystem::Individual; //type of main brake + bool ForcePNBrake = false; //is it necessary to use PN brake instead of EP brake + int DynamicBrakeTest = 0; //is it necessary to make brake test while driving + double DBT_VelocityBrake = 0; + double DBT_VelocityRelease = 0; + double DBT_VelocityFinish = 0; + double DBT_BrakingTime = 0; + double DBT_ReleasingTime = 0; + double DBT_MidPointAcc = 0; + int StaticBrakeTest = 0; //is it necessary to make brake test while standing double LastReactionTime = 0.0; double fActionTime = 0.0; // czas używany przy regulacji prędkości i zamykaniu drzwi double m_radiocontroltime{ 0.0 }; // timer used to control speed of radio operations diff --git a/DynObj.cpp b/DynObj.cpp index 794abab0..c68a4dda 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -2093,6 +2093,28 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" MoverParameters->dizel_HeatSet( Global.AirTemperature ); } } // temperature + else if( ( ActPar.size() >= 2 ) + && ( ActPar.front() == 'L' ) ) { + // load + ActPar.erase( 0, 1 ); + // immediately followed by max load override + // TBD: make it instead an optional sub-parameter? + { + auto const indexstart { 0 }; + auto const indexend { ActPar.find_first_not_of( "1234567890", indexstart ) }; + MoverParameters->MaxLoad = std::atoi( ActPar.substr( indexstart, indexend ).c_str() ); + ActPar.erase( 0, indexend ); + } + while( false == ActPar.empty() ) { + switch( ActPar.front() ) { + default: { + // unrecognized key + ActPar.erase( 0, 1 ); + break; + } + } + } + } // load /* else if (ActPar.substr(0, 1) == "") // tu mozna wpisac inny prefiks i inne rzeczy { // jakies inne prefiksy diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index c3dc62b0..7246ab39 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1193,6 +1193,7 @@ public: int IminLo = 0; int IminHi = 0; /*prady przelacznika automatycznego rozruchu, uzywane tez przez ai_driver*/ int ImaxLo = 0; // maksymalny prad niskiego rozruchu int ImaxHi = 0; // maksymalny prad wysokiego rozruchu + bool MotorOverloadRelayHighThreshold { false }; double nmax = 0.0; /*maksymalna dop. ilosc obrotow /s*/ double InitialCtrlDelay = 0.0; double CtrlDelay = 0.0; /* -//- -//- miedzy kolejnymi poz.*/ double CtrlDownDelay = 0.0; /* -//- -//- przy schodzeniu z poz.*/ /*hunter-101012*/ @@ -1675,6 +1676,7 @@ public: bool DecBrakeLevel(); bool ChangeCab(int direction); bool CurrentSwitch(bool const State); + bool IsMotorOverloadRelayHighThresholdOn() const; void UpdateBatteryVoltage(double dt); double ComputeMovement(double dt, double dt1, const TTrackShape &Shape, TTrackParam &Track, TTractionParam &ElectricTraction, TLocation const &NewLoc, TRotation const &NewRot); //oblicza przesuniecie pojazdu double FastComputeMovement(double dt, const TTrackShape &Shape, TTrackParam &Track, TLocation const &NewLoc, TRotation const &NewRot); //oblicza przesuniecie pojazdu - wersja zoptymalizowana @@ -1841,7 +1843,7 @@ public: bool CutOffEngine(void); //odlaczenie udszkodzonych silnikow /*funkcje automatycznego rozruchu np EN57*/ - bool MaxCurrentSwitch(bool State); //przelacznik pradu wysokiego rozruchu + bool MaxCurrentSwitch(bool State, range_t const Notify = range_t::consist ); //przelacznik pradu wysokiego rozruchu bool MinCurrentSwitch(bool State); //przelacznik pradu automatycznego rozruchu bool AutoRelaySwitch(bool State); //przelacznik automatycznego rozruchu bool AutoRelayCheck();//symulacja automatycznego rozruchu diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 47b94bdc..7dc41f8b 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -674,6 +674,12 @@ TMoverParameters::CurrentSwitch(bool const State) { return false; }; +bool +TMoverParameters::IsMotorOverloadRelayHighThresholdOn() const { + + return ( ( ImaxHi > ImaxLo ) && ( Imax > ImaxLo ) ); +} + // KURS90 - sprężarka pantografów; Ra 2014-07: teraz jest to zbiornik rozrządu, chociaż to jeszcze nie tak void TMoverParameters::UpdatePantVolume(double dt) { // check the pantograph compressor while at it @@ -1419,6 +1425,23 @@ void TMoverParameters::compute_movement_( double const Deltatime ) { RunInternalCommand(); + // relay settings + if( EngineType == TEngineType::ElectricSeriesMotor ) { + // adjust motor overload relay threshold + if( ImaxHi > ImaxLo ) { + if( MotorOverloadRelayHighThreshold ) { // set high threshold + if( ( TrainType != dt_ET42 ) ? ( RList[ MainCtrlPos ].Bn < 2 ) : ( MainCtrlPos == 0 ) ) { + Imax = ImaxHi; + } + } + else { // set low threshold + if( ( TrainType != dt_ET42 ) || ( MainCtrlPos == 0 ) ) { + Imax = ImaxLo; + } + } + } + } + // automatyczny rozruch if( EngineType == TEngineType::ElectricSeriesMotor ) { if( AutoRelayCheck() ) { @@ -2233,14 +2256,12 @@ bool TMoverParameters::IncMainCtrl(int CtrlSpeed) OK = true; if( Imax == ImaxHi ) { if( RList[ MainCtrlPos ].Bn > 1 ) { +/* NOTE: disabled, relay configuration was moved to compute_movement_ if( true == MaxCurrentSwitch( false )) { // wylaczanie wysokiego rozruchu SetFlag( SoundFlag, sound::relay ); - } // Q TODO: - // if (EngineType=ElectricSeriesMotor) and (MainCtrlPos=1) - // then - // MainCtrlActualPos:=1; - // + } +*/ if( TrainType == dt_ET42 ) { --MainCtrlPos; OK = false; @@ -3957,7 +3978,7 @@ bool TMoverParameters::SwitchEPBrake(int state) if ((BrakeHandle == TBrakeHandle::St113) && (CabOccupied != 0)) { if (state > 0) - temp = Handle->GetCP(); // TODO: przetlumaczyc + temp = Handle->GetEP(); // TODO: przetlumaczyc else temp = 0; Hamulec->SetEPS(temp); @@ -4519,7 +4540,7 @@ void TMoverParameters::UpdatePipePressure(double dt) && (DirActive != 0) && (EpFuse)) // tu powinien byc jeszcze bezpiecznik EP i baterie - // temp = (Handle as TFVel6).GetCP - temp = Handle->GetCP(); + temp = Handle->GetEP(); else temp = 0.0; @@ -6571,33 +6592,23 @@ bool TMoverParameters::CutOffEngine(void) // Q: 20160713 // Przełączenie wysoki / niski prąd rozruchu // ************************************************************************************************* -bool TMoverParameters::MaxCurrentSwitch(bool State) +bool TMoverParameters::MaxCurrentSwitch(bool State, range_t const Notify ) { - bool MCS = false; - if (EngineType == TEngineType::ElectricSeriesMotor) - if (ImaxHi > ImaxLo) - { - if (State && (Imax == ImaxLo) && (RList[MainCtrlPos].Bn < 2) && - !((TrainType == dt_ET42) && (MainCtrlPos > 0))) - { + auto const initialstate { MotorOverloadRelayHighThreshold }; - Imax = ImaxHi; - MCS = true; - if (CabActive != 0) - SendCtrlToNext("MaxCurrentSwitch", 1, CabActive); - } - if (!State) + MotorOverloadRelayHighThreshold = State; - if (Imax == ImaxHi) - if (!((TrainType == dt_ET42) && (MainCtrlPos > 0))) - { - Imax = ImaxLo; - MCS = true; - if (CabActive != 0) - SendCtrlToNext("MaxCurrentSwitch", 0, CabActive); - } - } - return MCS; + if( Notify != range_t::local ) { + SendCtrlToNext( + "MaxCurrentSwitch", + ( State ? 1 : 0 ), + CabActive, + ( Notify == range_t::unit ? + coupling::control | coupling::permanent : + coupling::control ) ); + } + + return State != initialstate; } // ************************************************************************************************* @@ -6739,19 +6750,24 @@ bool TMoverParameters::AutoRelayCheck(void) } else { // zmieniaj mainctrlactualpos - if ((DirActive < 0) && (TrainType != dt_PseudoDiesel)) - if (RList[MainCtrlActualPos + 1].Bn > 1) - { + if( ( DirActive < 0 ) && ( TrainType != dt_PseudoDiesel ) ) { + if( RList[ MainCtrlActualPos + 1 ].Bn > 1 ) { return false; // nie poprawiamy przy konwersji - // return ARC;// bbylo exit; //Ra: to powoduje, że EN57 nie wyłącza się przy - // IminLo + // return ARC;// bbylo exit; //Ra: to powoduje, że EN57 nie wyłącza się przy IminLo } + } // main bez samoczynnego rozruchu if( ( MainCtrlActualPos < ( sizeof( RList ) / sizeof( TScheme ) - 1 ) ) // crude guard against running out of current fixed table && ( ( RList[ MainCtrlActualPos ].Relay < MainCtrlPos ) || ( ( RList[ MainCtrlActualPos + 1 ].Relay == MainCtrlPos ) && ( MainCtrlActualPos < RlistSize ) ) || ( ( TrainType == dt_ET22 ) && ( DelayCtrlFlag ) ) ) ) { + // prevent switch to parallel mode if motor overload relay is set to high threshold mode + if( ( IsMotorOverloadRelayHighThresholdOn() ) + && ( RList[ MainCtrlActualPos + 1 ].Bn > 1 ) ) { + return false; + } + if( ( RList[MainCtrlPos].R == 0 ) && ( MainCtrlPos > 0 ) && ( MainCtrlPos != MainCtrlPosNo ) @@ -11994,10 +12010,10 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C DropAllPantographs( CValue1 == 1, range_t::local ); OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } - else if (Command == "MaxCurrentSwitch") - { - OK = MaxCurrentSwitch(CValue1 == 1); - } + else if (Command == "MaxCurrentSwitch") { + MaxCurrentSwitch( CValue1 == 1, range_t::local ); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); + } else if (Command == "MinCurrentSwitch") { OK = MinCurrentSwitch(CValue1 == 1); diff --git a/McZapkie/hamulce.cpp b/McZapkie/hamulce.cpp index 75b498b3..b2ff9cd0 100644 --- a/McZapkie/hamulce.cpp +++ b/McZapkie/hamulce.cpp @@ -2282,6 +2282,11 @@ double TDriverHandle::GetCP() return 0; } +double TDriverHandle::GetEP() +{ + return 0; +} + double TDriverHandle::GetSound(int i) { return 0; @@ -2814,8 +2819,8 @@ double TMHZ_K5P::GetPF(double i_bcp, double PP, double HP, double dt, double ep) void TMHZ_K5P::Init(double Press) { CP = Press; - Time = true; - TimeEP = true; + Time = true; + TimeEP = true; } void TMHZ_K5P::SetReductor(double nAdj) @@ -3133,9 +3138,11 @@ double TSt113::GetPF(double i_bcp, double PP, double HP, double dt, double ep) double ActFlowSpeed; int BCP; + CP = PP; + BCP = lround(i_bcp); - EPS = BEP_K[BCP+1]; + EPS = BEP_K[BCP]; if (BCP > 0) BCP = BCP - 1; @@ -3169,7 +3176,12 @@ double TSt113::GetPF(double i_bcp, double PP, double HP, double dt, double ep) double TSt113::GetCP() { - return EPS; + return CP; +} + +double TSt113::GetEP() +{ + return EPS; } double TSt113::GetPos(int i) @@ -3301,6 +3313,8 @@ double TFVel6::GetPF(double i_bcp, double PP, double HP, double dt, double ep) double dpMainValve; double ActFlowSpeed; + CP = PP; + LimPP = Min0R(5 * int(i_bcp < 3.5), HP); if ((i_bcp >= 3.5) && ((i_bcp < 4.3) || (i_bcp > 5.5))) ActFlowSpeed = 0; @@ -3334,7 +3348,12 @@ double TFVel6::GetPF(double i_bcp, double PP, double HP, double dt, double ep) double TFVel6::GetCP() { - return EPS; + return CP; +} + +double TFVel6::GetEP() +{ + return EPS; } double TFVel6::GetPos(int i) @@ -3366,6 +3385,8 @@ double TFVE408::GetPF(double i_bcp, double PP, double HP, double dt, double ep) double dpMainValve; double ActFlowSpeed; + CP = PP; + LimPP = Min0R(5 * int(i_bcp < 6.5), HP); if ((i_bcp >= 6.5) && ((i_bcp < 7.5) || (i_bcp > 9.5))) ActFlowSpeed = 0; @@ -3398,6 +3419,11 @@ double TFVE408::GetPF(double i_bcp, double PP, double HP, double dt, double ep) } double TFVE408::GetCP() +{ + return CP; +} + +double TFVE408::GetEP() { return EPS; } diff --git a/McZapkie/hamulce.h b/McZapkie/hamulce.h index 851c1fb0..b0d6eff4 100644 --- a/McZapkie/hamulce.h +++ b/McZapkie/hamulce.h @@ -541,6 +541,7 @@ class TDriverHandle { virtual double GetPF(double i_bcp, double PP, double HP, double dt, double ep); virtual void Init(double Press); virtual double GetCP(); + virtual double GetEP(); virtual void SetReductor(double nAdj); //korekcja pozycji reduktora cisnienia virtual double GetSound(int i); //pobranie glosnosci wybranego dzwieku virtual double GetPos(int i); //pobranie numeru pozycji o zadanym kodzie (funkcji) @@ -617,7 +618,7 @@ class TMHZ_EN57 : public TDriverHandle { double GetSound(int i)/*override*/; double GetPos(int i)/*override*/; double GetCP()/*override*/; - double GetEP(double pos); + double GetEP(double pos); void SetParams(bool AO, bool MO, double OverP, double, double OMP, double OPD); inline TMHZ_EN57(void) : TDriverHandle() @@ -762,10 +763,11 @@ class TSt113 : public TH14K1 { static double const BPT_K[/*?*/ /*-1..4*/ (4) - (-1) + 1][2]; static double const BEP_K[/*?*/ /*-1..5*/ (5) - (-1) + 1]; static double const pos_table[11]; // = {-1, 5, -1, 0, 2, 3, 4, 5, 0, 0, 1}; - + double CP = 0; public: double GetPF(double i_bcp, double PP, double HP, double dt, double ep)/*override*/; double GetCP()/*override*/; + double GetEP()/*override*/; double GetPos(int i)/*override*/; void Init(double Press)/*override*/; @@ -830,10 +832,12 @@ class TFVel6 : public TDriverHandle { private: double EPS = 0.0; static double const pos_table[ 11 ]; // = {-1, 6, -1, 0, 6, 4, 4.7, 5, -1, 0, 1}; + double CP = 0.0; public: double GetPF(double i_bcp, double PP, double HP, double dt, double ep)/*override*/; double GetCP()/*override*/; + double GetEP()/*override*/; double GetPos(int i)/*override*/; double GetSound(int i)/*override*/; void Init(double Press)/*override*/; @@ -848,10 +852,12 @@ class TFVE408 : public TDriverHandle { private: double EPS = 0.0; static double const pos_table[11]; // = {-1, 6, -1, 0, 6, 4, 4.7, 5, -1, 0, 1}; + double CP = 0.0; public: double GetPF(double i_bcp, double PP, double HP, double dt, double ep)/*override*/; double GetCP()/*override*/; + double GetEP()/*override*/; double GetPos(int i)/*override*/; double GetSound(int i)/*override*/; void Init(double Press)/*override*/; diff --git a/Train.cpp b/Train.cpp index fcd0d114..697715f2 100644 --- a/Train.cpp +++ b/Train.cpp @@ -3823,7 +3823,7 @@ void TTrain::OnCommand_motoroverloadrelaythresholdtoggle( TTrain *Train, command // only reacting to press, so the switch doesn't flip back and forth if key is held down if( ( true == Train->mvControlled->ShuntModeAllow ? ( false == Train->mvControlled->ShuntMode ) : - ( Train->mvControlled->Imax < Train->mvControlled->ImaxHi ) ) ) { + ( false == Train->mvControlled->MotorOverloadRelayHighThreshold ) ) ) { // turn on OnCommand_motoroverloadrelaythresholdsethigh( Train, Command ); } @@ -3838,10 +3838,9 @@ void TTrain::OnCommand_motoroverloadrelaythresholdsetlow( TTrain *Train, 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( true == Train->mvControlled->CurrentSwitch( false ) ) { - // visual feedback - Train->ggMaxCurrentCtrl.UpdateValue( 0.0, Train->dsbSwitch ); - } + Train->mvControlled->CurrentSwitch( false ); + // visual feedback + Train->ggMaxCurrentCtrl.UpdateValue( Train->mvControlled->MotorOverloadRelayHighThreshold ? 1 : 0, Train->dsbSwitch ); } } @@ -3849,10 +3848,9 @@ void TTrain::OnCommand_motoroverloadrelaythresholdsethigh( TTrain *Train, comman if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down - if( true == Train->mvControlled->CurrentSwitch( true ) ) { - // visual feedback - Train->ggMaxCurrentCtrl.UpdateValue( 1.0, Train->dsbSwitch ); - } + Train->mvControlled->CurrentSwitch( true ); + // visual feedback + Train->ggMaxCurrentCtrl.UpdateValue( Train->mvControlled->MotorOverloadRelayHighThreshold ? 1 : 0, Train->dsbSwitch ); } } @@ -7223,6 +7221,14 @@ bool TTrain::Update( double const Deltatime ) ggBrakeProfileG.Update(); ggBrakeProfileR.Update(); ggBrakeOperationModeCtrl.Update(); + ggMaxCurrentCtrl.UpdateValue( + ( true == mvControlled->ShuntModeAllow ? + ( true == mvControlled->ShuntMode ? + 1.f : + 0.f ) : + ( mvControlled->MotorOverloadRelayHighThreshold ? + 1.f : + 0.f ) ) ); ggMaxCurrentCtrl.Update(); // NBMX wrzesien 2003 - drzwi ggDoorLeftPermitButton.Update( lowvoltagepower ); @@ -8873,7 +8879,7 @@ void TTrain::set_cab_controls( int const Cab ) { ( true == mvControlled->ShuntMode ? 1.f : 0.f ) : - ( mvControlled->Imax == mvControlled->ImaxHi ? + ( mvControlled->MotorOverloadRelayHighThreshold ? 1.f : 0.f ) ) ); // lights diff --git a/driverhints.cpp b/driverhints.cpp index e9e16ce0..2a485092 100644 --- a/driverhints.cpp +++ b/driverhints.cpp @@ -783,7 +783,7 @@ TController::cue_action( locale::string const Action, float const Actionparamete case locale::string::driver_hint_trainbrakeapply: { if( AIControllFlag ) { // za radą yB ustawiamy pozycję 3 kranu (ruszanie kranem w innych miejscach powino zostać wyłączone) - if( mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ) { + if( ( BrakeSystem == TBrakeSystem::ElectroPneumatic ) && ( false == ForcePNBrake ) ) { mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_EPB ) ); } else { diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 8b44da15..10ac02e4 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -1171,7 +1171,11 @@ debug_panel::update_section_ai( std::vector &Output ) { "Brakes:\n highest pressure: " + to_string( mechanik.fReady, 2 ) + ( mechanik.Ready ? " (all brakes released)" : "" ) + "\n activation threshold: " + to_string( mechanik.fAccThreshold, 2 ) + ", delays: " + to_string( mechanik.fBrake_a0[ 0 ], 2 ) + " + " + to_string( mechanik.fBrake_a1[ 0 ], 2 ) - + "\n virtual brake position: " + to_string( mechanik.BrakeCtrlPosition, 2 ); + + "\n virtual brake position: " + to_string( mechanik.BrakeCtrlPosition, 2 ) + + "\n test stage: " + to_string( mechanik.DynamicBrakeTest ) + + ", applied at: " + to_string( mechanik.DBT_VelocityBrake, 0 ) + + ", release at: " + to_string( mechanik.DBT_VelocityRelease, 0 ) + + ", done at: " + to_string( mechanik.DBT_VelocityFinish, 0 ); Output.emplace_back( textline, Global.UITextColor ); @@ -1179,7 +1183,7 @@ debug_panel::update_section_ai( std::vector &Output ) { std::vector const drivingflagnames { "StopCloser", "StopPoint", "Active", "Press", "Connect", "Primary", "Late", "StopHere", "StartHorn", "StartHornNow", "StartHornDone", "Oerlikons", "IncSpeed", "TrackEnd", "SwitchFound", "GuardSignal", - "Visibility", "DoorOpened", "PushPull", "SemaphorFound", "StopPointFound" /*"SemaphorWasElapsed", "TrainInsideStation", "SpeedLimitFound"*/ }; + "Visibility", "DoorOpened", "PushPull", "SignalFound", "StopPointFound" /*"SemaphorWasElapsed", "TrainInsideStation", "SpeedLimitFound"*/ }; textline = "Driving flags:"; for( int idx = 0, flagbit = 1; idx < drivingflagnames.size(); ++idx, flagbit <<= 1 ) { diff --git a/utilities.h b/utilities.h index 579949e9..dd2685b4 100644 --- a/utilities.h +++ b/utilities.h @@ -90,7 +90,14 @@ std::string Now(); double CompareTime( double t1h, double t1m, double t2h, double t2m ); /*funkcje logiczne*/ -inline bool TestFlag( int const Flag, int const Value ) { return ( ( Flag & Value ) == Value ); } +inline +bool TestFlag( int const Flag, int const Value ) { + return ( ( Flag & Value ) == Value ); +} +inline +bool TestFlagAny( int const Flag, int const Value ) { + return ( ( Flag & Value ) != 0 ); +} bool SetFlag( int &Flag, int const Value); bool ClearFlag(int &Flag, int const Value); @@ -117,8 +124,8 @@ std::string to_string(double Value, int precision, int width); std::string to_hex_str( int const Value, int const width = 4 ); std::string to_minutes_str( float const Minutes, bool const Leadingzero, int const Width ); -inline std::string to_string(bool Value) { - +inline +std::string to_string(bool Value) { return ( Value == true ? "true" : "false" ); }