diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index cdb74894..3fdceb46 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -4479,11 +4479,10 @@ double TMoverParameters::GetDPMainValve(double dt, double hp) const auto const caboccupied{CabOccupied != 0}; - auto const use_handle{ - (BrakeOpModes & bom_PS) == 0 - || (caboccupied && BrakeOpModeFlag != bom_PS)}; - - if (!use_handle) + if (auto const use_handle{ + (BrakeOpModes & bom_PS) == 0 + || (caboccupied && BrakeOpModeFlag != bom_PS)}; + !use_handle) { if (BrakeCtrlPos == Handle->GetPos(bh_EB)) { @@ -4492,12 +4491,11 @@ double TMoverParameters::GetDPMainValve(double dt, double hp) const return 0.0; } - auto const mhzepidle{ - BrakeOpModeFlag >= bom_EP - && BrakeCtrlPosR <= Handle->GetPos(bh_EB) - 0.5 - && (BrakeHandle == TBrakeHandle::MHZ_EN57 || BrakeHandle == TBrakeHandle::MHZ_K8P)}; - - if (mhzepidle) + if (auto const mhzepidle{ + BrakeOpModeFlag >= bom_EP + && BrakeCtrlPosR <= Handle->GetPos(bh_EB) - 0.5 + && (BrakeHandle == TBrakeHandle::MHZ_EN57 || BrakeHandle == TBrakeHandle::MHZ_K8P)}; + mhzepidle) { return Handle->GetPF(0, PipePress, hp, dt, EqvtPipePress); } diff --git a/simulation/simulationstateserializer.cpp b/simulation/simulationstateserializer.cpp index 11a63c86..044c6311 100644 --- a/simulation/simulationstateserializer.cpp +++ b/simulation/simulationstateserializer.cpp @@ -852,8 +852,8 @@ TDynamicObject *select_trainset_driver( trainset_data &trainset ) if( vehicle->Mechanik == nullptr || !vehicle->Mechanik->primary() ) { continue; } - auto const lookup { trainset.assignment.find( Global.asLang ) }; - if( lookup != trainset.assignment.end() ) { + if( auto const lookup { trainset.assignment.find( Global.asLang ) }; + lookup != trainset.assignment.end() ) { vehicle->Mechanik->assignment() = lookup->second; } return vehicle; diff --git a/vehicle/Driver.cpp b/vehicle/Driver.cpp index 5cbe0385..b68ac224 100644 --- a/vehicle/Driver.cpp +++ b/vehicle/Driver.cpp @@ -339,9 +339,6 @@ bool TSpeedPos::Update() // odczyt komórki pamięci najlepiej by było zrobić jako notyfikację, // czyli zmiana komórki wywoła jakąś podaną funkcję CommandCheck(); // sprawdzenie typu komendy w evencie i określenie prędkości - if( fVelNext == 0.0 ) { - iFlags &= ~spNotOurShuntSignal; // saw "stop" - the next permission will light up with us here - } } } return false; @@ -399,14 +396,6 @@ bool TSpeedPos::IsProperSemaphor(TOrders order) return false; // true gdy zatrzymanie, wtedy nie ma po co skanować dalej } -bool TSpeedPos::AllowsDeparture() const -{ // signal ahead permits - a dormant AI may start without waiting for a change - if( fDist <= 0.0 ) { return false; } - if( ( iFlags & spEnabled ) == 0 ) { return false; } - if( ( iFlags & ( spSemaphor | spShuntSemaphor ) ) == 0 ) { return false; } - return fVelNext < 0.0 || fVelNext >= 1.0; -} - bool TSpeedPos::Set(basic_event *event, double dist, double length, TOrders order) { // zapamiętanie zdarzenia fDist = dist; @@ -420,11 +409,6 @@ bool TSpeedPos::Set(basic_event *event, double dist, double length, TOrders orde } iFlags |= spEnabled; CommandCheck(); // sprawdzenie typu komendy w evencie i określenie prędkości - if( ( iFlags & spShuntSemaphor ) != 0 - && fVelNext != 0.0 ) { - // a shunting signal addresses nobody in particular; a semaphore sets a route for us - iFlags |= spNotOurShuntSignal; // permission found already lit - we did not see who it was given to - } // zależnie od trybu sprawdzenie czy jest tutaj gdzieś semafor lub tarcza manewrowa // jeśli wskazuje stop wtedy wystawiamy true jako koniec sprawdzania // WriteLog("EventSet: Vel=" + AnsiString(fVelNext) + " iFlags=" + AnsiString(iFlags) + " order="+AnsiString(order)); @@ -532,9 +516,8 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) double fLastDir{ 0.0 }; // with no direction set (dormant AI) we scan by the occupied cab - int const scandirection{ iDirection != 0 ? iDirection : mvOccupied->CabOccupied }; - - if (iTableDirection != scandirection ) { + if( int const scandirection{ iDirection != 0 ? iDirection : mvOccupied->CabOccupied }; + iTableDirection != scandirection ) { // jeśli zmiana kierunku, zaczynamy od toru ze wskazanym pojazdem TableClear(); /* @@ -675,10 +658,6 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) + ")"); } } - if( iEngineActive ) { - // only a dormant driver acts on it, so do not tag it for anybody else - newspeedpoint.iFlags &= ~spNotOurShuntSignal; - } } } } // event dodajemy najpierw, żeby móc sprawdzić, czy tor został dodany po odczytaniu prędkości następnego @@ -1593,13 +1572,6 @@ TController::TableUpdateEvent( double &Velocity, TCommandType &Command, TSpeedPo if( isforsomeoneelse ) { VelSignalNext = 0.0; Velocity = 0.0; - // it permits, but for the vehicle standing in front of us. Record that now - - // once it pulls away the signal alone no longer says whose permission it was - if( false == iEngineActive - && ( Point.iFlags & spShuntSemaphor ) - && Point.fVelNext != 0.0 ) { - Point.iFlags |= spNotOurShuntSignal; - } } else { VelSignalNext = Point.fVelNext; @@ -1607,16 +1579,6 @@ TController::TableUpdateEvent( double &Velocity, TCommandType &Command, TSpeedPo Velocity = fVelMax; VelSignal = fVelMax; } - if( Command == TCommandType::cm_Unknown && Point.AllowsDeparture() ) { - // already permitting as it entered the FOV - wake up without waiting for a change - Command = ( Point.iFlags & spShuntSemaphor ) != 0 ? - TCommandType::cm_ShuntVelocity : - TCommandType::cm_SetVelocity; - SemPermitIndex = Pointindex; - if( std::fabs( VelSignal ) < 1.0 ) { - VelSignal = Point.fVelNext < 0.0 ? -1.0 : Point.fVelNext; - } - } } } } @@ -2459,23 +2421,22 @@ bool TController::CheckVehicles(TOrders user) // Ra 2014-09: ustawić moveMultiControl, jeśli wszystkie są w ukrotnieniu (i skrajne mają kabinę?) while (p) { // sprawdzanie, czy jest głównym sterującym, żeby nie było konfliktu + // a tamten ma priorytet + // TODO: take into account drivers' operating modes, one or more of them might be on banking duty if( p->Mechanik // jeśli ma obsadę - && p->Mechanik != this ) { // ale chodzi o inny pojazd, niż aktualnie sprawdzający - if( p->Mechanik->primary() ) { - // a tamten ma priorytet - // TODO: take into account drivers' operating modes, one or more of them might be on banking duty - if( primary() - && mvOccupied->DirAbsolute - && mvOccupied->BrakeCtrlPos >= -1 ) { - // jeśli rządzi i ma kierunek - p->Mechanik->primary( false ); - p->Mechanik->ZeroLocalBrake(); - p->MoverParameters->BrakeLevelSet( p->MoverParameters->Handle->GetPos( bh_NP ) ); // odcięcie na zaworze maszynisty - p->Mechanik->BrakeLevelSet( p->MoverParameters->BrakeCtrlPos ); //ustawienie zmiennej GBH - } - else { - main = false; // nici z rządzenia - } + && p->Mechanik != this // ale chodzi o inny pojazd, niż aktualnie sprawdzający + && p->Mechanik->primary() ) { + if( primary() + && mvOccupied->DirAbsolute + && mvOccupied->BrakeCtrlPos >= -1 ) { + // jeśli rządzi i ma kierunek + p->Mechanik->primary( false ); + p->Mechanik->ZeroLocalBrake(); + p->MoverParameters->BrakeLevelSet( p->MoverParameters->Handle->GetPos( bh_NP ) ); // odcięcie na zaworze maszynisty + p->Mechanik->BrakeLevelSet( p->MoverParameters->BrakeCtrlPos ); //ustawienie zmiennej GBH + } + else { + main = false; // nici z rządzenia } } ++iVehicles; // jest jeden pojazd więcej @@ -2662,13 +2623,15 @@ void TController::DirectionInitial() mvOccupied->CabActivisationAuto(); if( mvOccupied->Vel >= EU07_AI_MOVEMENT ) { // actually moving - direction from the sign of V - iDirection = iDirectionOrder = mvOccupied->V > 0 ? 1 : -1; + iDirection = mvOccupied->V > 0 ? 1 : -1; + iDirectionOrder = iDirection; DirectionForward( mvOccupied->V * mvOccupied->CabActive >= 0.0 ); } else { // standing: reverser forward relative to the cab, not from the sign of a micro V DirectionForward( true ); - iDirection = iDirectionOrder = CheckDirection(); + iDirection = CheckDirection(); + iDirectionOrder = iDirection; } CheckVehicles(); }; @@ -4489,14 +4452,11 @@ void TController::PutCommand(std::string NewCommand, double NewValue1, double Ne bool TController::CommandClaimsPrimary( std::string const &Command, double const Value ) { // a driving/startup order wakes a secondary crew up to lead, otherwise nobody moves the consist auto const isdrivingorder = [&Command]( std::initializer_list const names ) { - for( auto const *name : names ) { - if( Command == name ) { return true; } - } - return false; + return std::ranges::any_of( + names, [&Command]( char const *name ) { return Command == name; } ); }; return Command.compare( 0, 10, "Timetable:" ) == 0 - || ( Command == "SetVelocity" && Value != 0.0 ) || isdrivingorder( { "Prepare_engine", "ShuntVelocity", "Obey_train", "Bank", "Shunt", "Loose_shunt" } ); } @@ -4549,11 +4509,11 @@ TController::ActiveEnginePrimary() const { ForEachInConsist( pVehicle, [&active]( TDynamicObject *Vehicle ) { - auto *driver { Vehicle->Mechanik }; - if( driver != nullptr - && driver->primary() - && driver->iEngineActive ) { - active = driver; + if( auto *vehicledriver { Vehicle->Mechanik }; + vehicledriver != nullptr + && vehicledriver->primary() + && vehicledriver->iEngineActive ) { + active = vehicledriver; return false; } return true; @@ -4563,12 +4523,13 @@ TController::ActiveEnginePrimary() const { bool TController::PutCommand( std::string NewCommand, double NewValue1, double NewValue2, glm::dvec3 const *NewLocation, TStopReason reason ) { // analiza komendy - auto const shouldtakeprimary{ - AIControllFlag - && !primary() - && CommandClaimsPrimary( NewCommand, NewValue1 ) - && ActiveEnginePrimary() == nullptr }; // steal only while the engines are down - if( shouldtakeprimary ) { + // steal only while the engines are down + if( auto const shouldtakeprimary{ + AIControllFlag + && !primary() + && CommandClaimsPrimary( NewCommand, NewValue1 ) + && ActiveEnginePrimary() == nullptr }; + shouldtakeprimary ) { ClaimConsistPrimary(); if( mvOccupied->CabActive == 0 ) { mvOccupied->CabActivisationAuto(); @@ -4648,7 +4609,6 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N asNextStop = TrainParams.NextStop(); m_lastannouncement = announcement_t::idle; primary( true ); -// NewCommand = Global.asCurrentSceneryPath + NewCommand; auto lookup = FileExists( { Global.asCurrentSceneryPath + NewCommand, paths::sounds + NewCommand }, @@ -5088,8 +5048,8 @@ TController::SettleSecondaryAI() { } void -TController::UpdateSecondary( double const Awarenessrange ) { - // does not drive; scans while the consist is shut down (wake-up / taking over on a signal) +TController::UpdateSecondary() { + // does not drive; only keeps its own vehicle settled while the consist is shut down if( AIControllFlag ) { SettleSecondaryAI(); } @@ -5097,28 +5057,6 @@ TController::UpdateSecondary( double const Awarenessrange ) { // a human sits in the cab - they handle it themselves mvOccupied->BrakeValveActive = true; } - if( pVehicle->ctOwner != nullptr - && pVehicle->ctOwner != this - && pVehicle->ctOwner->iEngineActive ) { - return; // the consist runs under an active primary - do not duplicate the scan - } - // a secondary needs no responsiveness - scans rarely, cheap with many shut down consists - auto const scaninterval{ std::max( ReactionTime, EU07_AI_SECONDARYSCANINTERVAL ) }; - if( LastReactionTime < scaninterval ) { return; } - LastReactionTime -= scaninterval; - OrientScanToCab(); - scan_route( Awarenessrange ); - // no obstacles - a dormant driver only waits for a signal; the primary computes them later - ScanForWakeup( Awarenessrange ); -} - -void -TController::ScanForWakeup( double const Range ) { - // a permission may wake a dormant AI up (Prepare_engine in the mask) - if( AIControllFlag - && ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Obey_train | Bank | Prepare_engine ) ) == 0 ) { - check_route_ahead( Range ); - } } void @@ -5136,7 +5074,7 @@ TController::Update( double const Timedelta ) { 30.0 * fDriverDist ) }; if( !primary() ) { - UpdateSecondary( awarenessrange ); + UpdateSecondary(); return; } @@ -5522,11 +5460,11 @@ bool TController::BelongsToConsist( TDynamicObject const *Vehicle ) const return pVehicle->is_connected( Vehicle ); // with no owner settled, the coupling is all that is left } -double TController::DistanceToAnotherConsist( TTrack *Track, double const Distance ) const +double TController::DistanceToAnotherConsist( TTrack const *Track, double const Distance ) const { // Distance is signed by the scan direction and reaches the far end of the track auto nearest { -1.0 }; auto const scandirection { Distance > 0 ? 1 : -1 }; // positive value means scan towards point2 end of the track - for( auto *dynamic : Track->Dynamics ) { + for( auto const *dynamic : Track->Dynamics ) { if( BelongsToConsist( dynamic ) ) { continue; } // how far the foreign vehicle sits from that same far end auto const obstaclelocation { scandirection > 0 ? Track->Length() - dynamic->RaTranslationGet() : dynamic->RaTranslationGet() }; @@ -5541,15 +5479,14 @@ double TController::DistanceToAnotherConsist( TTrack *Track, double const Distan return nearest; } -bool TController::IsOccupiedByAnotherConsist( TTrack *Track, double const Distance ) const +bool TController::IsOccupiedByAnotherConsist( TTrack const *Track, double const Distance ) const { // whether the track carries vehicles of another consist if( Track->Dynamics.empty() ) { return false; } if( Distance == 0.0 ) { // no scan reference given - any foreign vehicle on the track counts - for( auto *dynamic : Track->Dynamics ) { - if( false == BelongsToConsist( dynamic ) ) { return true; } - } - return false; + return std::ranges::any_of( + Track->Dynamics, + [this]( TDynamicObject const *dynamic ) { return false == BelongsToConsist( dynamic ); } ); } return DistanceToAnotherConsist( Track, Distance ) >= 0.0; }; @@ -6867,18 +6804,19 @@ TController::scan_obstacles( double const Range ) { // members for an obstacle and missing the consist standing ahead auto const scandirection { iDirection != 0 ? iDirection : mvOccupied->CabOccupied }; - int routescandirection; // for moving vehicle determine heading from velocity; for standing fall back on the set direction - if( std::abs(frontvehicle->MoverParameters->V) > 0.5 ? // ignore potential micro-stutters in oposite direction during "almost stop" - frontvehicle->MoverParameters->V > 0.0 : - pVehicle->DirectionGet() == frontvehicle->DirectionGet() ? scandirection >= 0 : scandirection <= 0 ) { - // towards coupler 0 - routescandirection = end::front; + bool towardcoupler0; + if( std::abs( frontvehicle->MoverParameters->V ) > 0.5 ) { + // ignore potential micro-stutters in oposite direction during "almost stop" + towardcoupler0 = frontvehicle->MoverParameters->V > 0.0; + } + else if( pVehicle->DirectionGet() == frontvehicle->DirectionGet() ) { + towardcoupler0 = scandirection >= 0; } else { - // towards coupler 1 - routescandirection = end::rear; + towardcoupler0 = scandirection <= 0; } + int const routescandirection { towardcoupler0 ? end::front : end::rear }; /* if( pVehicle->MoverParameters->CabOccupied < 0 ) { // flip the scan direction in the rear cab @@ -7584,8 +7522,8 @@ TController::pick_optimal_speed( double const Range ) { SwitchClearDist = -1; ActualProximityDist = Range; // funkcja Update() może pozostawić wartości bez zmian + // if we're idling bail out early if( false == is_active() ) { - ScanForWakeup( Range ); VelDesired = 0.0; VelNext = 0.0; AccDesired = std::min( AccDesired, EU07_AI_NOACCELERATION ); @@ -8546,65 +8484,19 @@ bool TController::SignalPermissionIsOurs( bool const Signalgivesgo ) const { // the permission belongs to the consist standing closest to the signal if( false == Signalgivesgo ) { return true; } - // a shunting permission found already lit was handed to whoever stood here before us; it only - // keeps a dormant driver from waking up, and drops as soon as the signal shows stop - if( false == iEngineActive - && SemPermitIndex < sSpeedTable.size() // std::size_t( -1 ) never is - && ( sSpeedTable[ SemPermitIndex ].iFlags & spNotOurShuntSignal ) ) { - return false; - } // the addressee usually cuts the scan short and the signal never makes it into the table; // this closes the case where it did, with the addressee still standing in front of it return false == OtherConsistAtSignal(); } -TController * -TController::DepartureDriver() const { - // after OrientScanToCab / CheckVehicles the front of the consist is pVehicles[front] - if( pVehicles[ end::front ] != nullptr - && pVehicles[ end::front ]->Mechanik != nullptr ) { - return pVehicles[ end::front ]->Mechanik; - } - return const_cast( this ); -} - -void -TController::WakeForDeparture( std::string const &Command, double const Value1, double const Value2 ) { - // the primary already has the engine running - we do not steal, we just pass the order on - if( auto *active { ActiveEnginePrimary() } ) { - active->PutCommand( Command, Value1, Value2, nullptr ); - return; - } - // engines down - the lead goes to the driver at the front (scanning direction) - auto *target { primary() ? this : DepartureDriver() }; - if( target == nullptr ) { - target = this; - } - if( target != this ) { - if( false == target->primary() ) { - target->ClaimConsistPrimary(); - } - target->PutCommand( Command, Value1, Value2, nullptr ); - return; - } - PutCommand( Command, Value1, Value2, nullptr ); -} - void TController::check_route_ahead( double const Range ) { auto const comm { TableUpdate( VelDesired, ActualProximityDist, VelNext, AccDesired ) }; - auto const signalpermits { comm == TCommandType::cm_SetVelocity || comm == TCommandType::cm_ShuntVelocity }; - if( false == SignalPermissionIsOurs( signalpermits ) ) { - // the permission was given to another consist, we wait for our own. Remember it on the - // entry, so the addressee pulling away does not hand the signal over to us; the flag is - // dropped when it shows stop, and only a dormant driver ever carries one - if( false == iEngineActive - && SemPermitIndex < sSpeedTable.size() - && ( sSpeedTable[ SemPermitIndex ].iFlags & spShuntSemaphor ) ) { - sSpeedTable[ SemPermitIndex ].iFlags |= spNotOurShuntSignal; - } + if( auto const signalpermits { comm == TCommandType::cm_SetVelocity || comm == TCommandType::cm_ShuntVelocity }; + false == SignalPermissionIsOurs( signalpermits ) ) { + // the permission was given to another consist, we wait for our own return; } @@ -8622,17 +8514,17 @@ TController::check_route_ahead( double const Range ) { } break; } - case TCommandType::cm_SetVelocity: { - if( ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Obey_train | Bank | Prepare_engine ) ) == 0 ) { + case TCommandType::cm_SetVelocity: { // od wersji 357 semafor nie budzi wyłączonej lokomotywy + if( ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Obey_train | Bank ) ) == 0 ) { if( std::fabs( VelSignal ) >= 1.0 ) { // 0.1 nie wysyła się do samochodow, bo potem nie ruszą - WakeForDeparture( "SetVelocity", VelSignal, VelNext ); + PutCommand( "SetVelocity", VelSignal, VelNext, nullptr ); // komenda robi dodatkowe operacje } } break; } - case TCommandType::cm_ShuntVelocity: { - if( ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Obey_train | Bank | Prepare_engine ) ) == 0 ) { - WakeForDeparture( "ShuntVelocity", VelSignal, VelNext ); + case TCommandType::cm_ShuntVelocity: { // od wersji 357 Tm nie budzi wyłączonej lokomotywy + if( ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Obey_train | Bank ) ) == 0 ) { + PutCommand( "ShuntVelocity", VelSignal, VelNext, nullptr ); } else if( iCoupler ) { // jeśli jedzie w celu połączenia SetVelocity( VelSignal, VelNext ); @@ -8640,7 +8532,7 @@ TController::check_route_ahead( double const Range ) { break; } case TCommandType::cm_Command: { // komenda z komórki - if( ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Obey_train | Bank | Prepare_engine ) ) == 0 ) { + if( ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Obey_train | Bank ) ) == 0 ) { if( mvOccupied->Vel < 0.1 ) { // dopiero jak stanie /* diff --git a/vehicle/Driver.h b/vehicle/Driver.h index 27b19bea..4943611e 100644 --- a/vehicle/Driver.h +++ b/vehicle/Driver.h @@ -25,7 +25,6 @@ auto const EU07_AI_BRAKINGTESTACCELERATION = -0.06; auto const EU07_AI_NOMOVEMENT = 0.05; // standstill velocity threshold auto const EU07_AI_OVERCHARGETIME = 3.0; // [s] auto const EU07_AI_MOVEMENT = 1.0; // deliberate movement velocity threshold -auto const EU07_AI_SECONDARYSCANINTERVAL = 5.0; // s - a secondary scans for a wake-up less often than the primary auto const EU07_AI_SPEEDLIMITEXTENDSBEYONDSCANRANGE = 10000.0; enum TOrders @@ -147,7 +146,6 @@ enum TSpeedPosFlag spRoadVel = 0x8000, // zadanie prędkości drogowej spSectionVel = 0x20000, // odcinek z ograniczeniem spProximityVelocity = 0x40000, // odcinek z ograniczeniem i podaną jego długościa - spNotOurShuntSignal = 0x80000 // shunting signal a dormant driver found already permitting - not for us // spDontApplySpeedLimit = 0x10000 // this point won't apply its speed limit. potentially set by the scanning vehicle }; @@ -157,7 +155,7 @@ struct TSpeedPosFlagDescription { char const *name; }; -inline constexpr TSpeedPosFlagDescription SpeedPosFlagDescriptions[] { +inline constexpr std::array SpeedPosFlagDescriptions {{ { spSemaphor, "semaphore" }, { spShuntSemaphor, "shunt" }, { spPassengerStopPoint, "W4" }, @@ -174,7 +172,7 @@ inline constexpr TSpeedPosFlagDescription SpeedPosFlagDescriptions[] { { spReverse, "reverse" }, { spElapsed, "passed" }, { spCommandSent, "sent" }, - { spNotOurShuntSignal, "not-ours" } }; +}}; class TSpeedPos { // pozycja tabeli prędkości dla AI @@ -209,8 +207,6 @@ class TSpeedPos std::string TableText() const; std::string GetName() const; bool IsProperSemaphor(TOrders order = Wait_for_orders); - // signal ahead permits - wakes a dormant AI without waiting for the next change - bool AllowsDeparture() const; }; //---------------------------------------------------------------------------- @@ -349,11 +345,10 @@ private: void determine_braking_distance(); void determine_proximity_ranges(); void scan_route( double const Range ); - void ScanForWakeup( double const Range ); // dormant/secondary AI: checks the signal ahead for a wake-up // front/rear/fLength per CheckDirection, CabOccupied fallback; no CheckVehicles side effects void OrientScanToCab(); void scan_obstacles( double const Range ); - void UpdateSecondary( double const Awarenessrange ); // scans for a wake-up, does not drive + void UpdateSecondary(); // a secondary does not drive, it only settles its own vehicle void SettleSecondaryAI(); // drops force and brake, keeps vigilance quiet void control_wheelslip(); void control_pantographs(); @@ -392,10 +387,6 @@ private: void control_braking_force(); void apply_independent_brake_only(); void check_route_ahead( double const Range ); - // the driver at the front (scanning direction) - the signal hands the lead to them - TController *DepartureDriver() const; - // engines down: primary for the front; running: the order goes to the current primary - void WakeForDeparture( std::string const &Command, double const Value1, double const Value2 ); // false when the permission at the nearest signal was given to another consist bool SignalPermissionIsOurs( bool const Signalgivesgo ) const; bool OtherConsistAtSignal() const; // another consist in front of the signal = the addressee of the permission @@ -572,9 +563,9 @@ private: void TableClear(); int TableDirection() { return iTableDirection; } // Ra: stare funkcje skanujące, używane do szukania sygnalizatora z tyłu - bool IsOccupiedByAnotherConsist( TTrack *Track, double const Distance = 0.0 ) const; + bool IsOccupiedByAnotherConsist( TTrack const *Track, double const Distance = 0.0 ) const; // distance to the nearest vehicle of another consist ahead on the track; -1.0 when there is none - double DistanceToAnotherConsist( TTrack *Track, double const Distance ) const; + double DistanceToAnotherConsist( TTrack const *Track, double const Distance ) const; bool BelongsToConsist( TDynamicObject const *Vehicle ) const; // whether the vehicle is part of our consist basic_event *CheckTrackEventBackward( double fDirection, TTrack *Track, TDynamicObject *Vehicle, int const Eventdirection = 1, end const End = end::rear ); TTrack *BackwardTraceRoute( double &fDistance, double &fDirection, TDynamicObject *Vehicle, basic_event *&Event, int const Eventdirection = 1, end const End = end::rear, bool const Untiloccupied = true ); diff --git a/vehicle/DynObj.cpp b/vehicle/DynObj.cpp index 2e95a7ad..63c110b1 100644 --- a/vehicle/DynObj.cpp +++ b/vehicle/DynObj.cpp @@ -1646,11 +1646,11 @@ void TDynamicObject::ReassignConsistPrimary() int primarycount = 0; // walk from the front; Next()/Prev() are not enough, reversed members need the coupler side flipped int side { end::front }; - auto *front { FirstFind( side ) }; - if( front == nullptr ) { front = this; } + auto *headvehicle { FirstFind( side ) }; + if( headvehicle == nullptr ) { headvehicle = this; } auto dir { 1 - side }; - auto *farend { front }; - for( auto *d = front; d != nullptr; d = d->Neighbour( dir ) ) + auto *farend { headvehicle }; + for( auto *d = headvehicle; d != nullptr; d = d->Neighbour( dir ) ) { if( d->Mechanik != nullptr ) { @@ -1664,17 +1664,14 @@ void TDynamicObject::ReassignConsistPrimary() } if( drivers.empty() ) { return; } // a human-driven cab takes priority, so the AI does not take the consist from them - TController *humandriver = nullptr; - for( auto *drv : drivers ) { - if( false == drv->AIControllFlag ) { humandriver = drv; break; } - } + auto const human { std::ranges::find_if( + drivers, []( TController const *drv ) { return false == drv->AIControllFlag; } ) }; // with a single primary it stays; otherwise: the human, the end vehicles, the first on the list - TController *newprimary = - ( primarycount == 1 ) ? existingprimary : - ( humandriver != nullptr ) ? humandriver : - ( front->Mechanik != nullptr ) ? front->Mechanik : - ( farend->Mechanik != nullptr ) ? farend->Mechanik : - drivers.front(); + TController *newprimary { drivers.front() }; + if( primarycount == 1 ) { newprimary = existingprimary; } + else if( human != drivers.end() ) { newprimary = *human; } + else if( headvehicle->Mechanik != nullptr ) { newprimary = headvehicle->Mechanik; } + else if( farend->Mechanik != nullptr ) { newprimary = farend->Mechanik; } newprimary->ClaimConsistPrimary(); }