mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-06 15:08:36 +01:00
Keep one primary per consist and let a secondary AI claim it.
A driver without movePrimary no longer just idles. UpdateSecondary() cuts BrakeValveActive so a secondary AI stops fighting the primary over the brake pipe, and - as long as no driver in the consist has iEngineActive - keeps scanning ahead of CabOccupied, so it can take movePrimary and start the engine once a signal permits. scan_route() orients by CabOccupied when DirActive is 0, and ClaimConsistPrimary() clears movePrimary on every other driver in the consist, then calls TableClear() and CheckVehicles(), so sSpeedTable is rebuilt for the new front and ctOwner follows it. - walk the consist with FirstFind()/Neighbour() instead of Next()/Prev(), which stopped at the starting vehicle and mishandled reversed members; - ReassignConsistPrimary() picks a single driver after any coupling change, both from TDynamicObject::couple() and from the AI path; - IsOccupiedByAnotherConsist() decides membership with BelongsToConsist() and takes a signed distance, so a consist left behind no longer cuts the scan short. DistanceToAnotherConsist() hands back the gap it already computes, so OtherConsistAtSignal() counts a foreign vehicle only while it stands closer than the signal itself, instead of comparing track starts; - TSpeedPos::Set() marks an entry with spNotOurShuntSignal when a spShuntSemaphor was already permitting as the entry was added. A shunting signal does not address its permission to a particular consist, so a dormant driver does not wake up on a permission it did not see light up; the flag drops once the signal shows stop, so its own turn is never blocked. spSemaphor is excluded: a semaphore sets a route for us and permits us even when found already lit. The check reads SemPermitIndex - the entry that produced the permitting command - because SemNextIndex can point at an earlier signal. The flag is also stamped whenever the permission turns out to belong to a consist standing in front of us - both where TableUpdateEvent() already knows the signal is for the vehicle ahead, and in check_route_ahead() - so the addressee pulling away does not hand the still-lit signal over to whoever waited behind it; - the scantable debug panel lists the flags by name (spNotOurShuntSignal shows as not-ours) and folds the nearest vehicle ahead into the table by its own distance.
This commit is contained in:
@@ -24,6 +24,7 @@ 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_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
|
||||
@@ -144,10 +145,36 @@ enum TSpeedPosFlag
|
||||
spSemaphor = 0x4000, // semafor pociągowy
|
||||
spRoadVel = 0x8000, // zadanie prędkości drogowej
|
||||
spSectionVel = 0x20000, // odcinek z ograniczeniem
|
||||
spProximityVelocity = 0x40000 // odcinek z ograniczeniem i podaną jego długościa
|
||||
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
|
||||
};
|
||||
|
||||
// names of speed table entry flags, for the debug panel; spEnabled is skipped, every visible entry has it
|
||||
struct TSpeedPosFlagDescription {
|
||||
int flag;
|
||||
char const *name;
|
||||
};
|
||||
|
||||
inline constexpr TSpeedPosFlagDescription SpeedPosFlagDescriptions[] {
|
||||
{ spSemaphor, "semaphore" },
|
||||
{ spShuntSemaphor, "shunt" },
|
||||
{ spPassengerStopPoint, "W4" },
|
||||
{ spOutsideStation, "W5" },
|
||||
{ spSwitch, "switch" },
|
||||
{ spSwitchStatus, "diverging" },
|
||||
{ spTrack, "track" },
|
||||
{ spCurve, "curve" },
|
||||
{ spEnd, "end" },
|
||||
{ spSectionVel, "section" },
|
||||
{ spProximityVelocity, "proximity" },
|
||||
{ spRoadVel, "road" },
|
||||
{ spStopOnSBL, "SBL" },
|
||||
{ spReverse, "reverse" },
|
||||
{ spElapsed, "passed" },
|
||||
{ spCommandSent, "sent" },
|
||||
{ spNotOurShuntSignal, "not-ours" } };
|
||||
|
||||
class TSpeedPos
|
||||
{ // pozycja tabeli prędkości dla AI
|
||||
public:
|
||||
@@ -181,6 +208,8 @@ 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;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -222,13 +251,15 @@ public:
|
||||
void Update( double dt ); // uruchamiac przynajmniej raz na sekundę
|
||||
void MoveTo( TDynamicObject *to );
|
||||
void TakeControl( bool const Aidriver, bool const Forcevehiclecheck = false );
|
||||
inline
|
||||
bool primary( bool const Primary ) {
|
||||
SetFlag( iDrivigFlags, Primary ? movePrimary : -movePrimary );
|
||||
return primary(); }
|
||||
void ReleaseTransientControls(); // clears the warning signal and the sandbox on a change of primary
|
||||
bool primary( bool const Primary );
|
||||
inline
|
||||
bool primary() const {
|
||||
return (iDrivigFlags & movePrimary) != 0; };
|
||||
// drops primary from the others in the consist and takes the lead (valve / scan table)
|
||||
void ClaimConsistPrimary();
|
||||
// a primary with iEngineActive in the consist; nullptr = free to take the lead
|
||||
TController *ActiveEnginePrimary() const;
|
||||
inline
|
||||
TMoverParameters const *Controlling() const {
|
||||
return mvControlling; }
|
||||
@@ -317,7 +348,12 @@ 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 SettleSecondaryAI(); // drops force and brake, keeps vigilance quiet
|
||||
void control_wheelslip();
|
||||
void control_pantographs();
|
||||
void control_horns( double const Timedelta );
|
||||
@@ -355,6 +391,13 @@ 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
|
||||
void check_route_behind( double const Range );
|
||||
void UpdateBrakingHelper();
|
||||
void hint( driver_hint const Value, hintpredicate const Predicate, float const Predicateparameter = 0.f );
|
||||
@@ -477,6 +520,8 @@ public:
|
||||
std::string OrderCurrent() const;
|
||||
private:
|
||||
void RecognizeCommand(); // odczytuje komende przekazana lokomotywie
|
||||
// whether the command wakes a secondary crew up to lead (a driving or startup order)
|
||||
static bool CommandClaimsPrimary( std::string const &Command, double const Value );
|
||||
void JumpToNextOrder( bool const Skipmergedchangedirection = false );
|
||||
void JumpToFirstOrder();
|
||||
void OrderPush( TOrders NewOrder );
|
||||
@@ -526,12 +571,18 @@ 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 );
|
||||
bool IsOccupiedByAnotherConsist( TTrack *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;
|
||||
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 );
|
||||
void SetProximityVelocity( double dist, double vel, glm::dvec3 const *pos );
|
||||
TCommandType BackwardScan( double const Range );
|
||||
std::string TableText( std::size_t const Index ) const;
|
||||
double TableDistance( std::size_t const Index ) const; // distance of the entry; max when out of range
|
||||
// scan table row describing the nearest vehicle on the route; empty when the way is clear
|
||||
std::string ObstacleText() const;
|
||||
/*
|
||||
void RouteSwitch(int d);
|
||||
*/
|
||||
@@ -544,6 +595,8 @@ private:
|
||||
basic_event *eSignSkip = nullptr; // można pominąć ten SBL po zatrzymaniu
|
||||
std::size_t SemNextIndex{ std::size_t( -1 ) };
|
||||
std::size_t SemNextStopIndex{ std::size_t( -1 ) };
|
||||
// entry that produced the permitting command; SemNextIndex can point at a different one
|
||||
std::size_t SemPermitIndex{ std::size_t( -1 ) };
|
||||
double dMoveLen = 0.0; // odległość przejechana od ostatniego sprawdzenia tabelki
|
||||
basic_event *eSignNext = nullptr; // sygnał zmieniający prędkość, do pokazania na [F2]
|
||||
neighbour_data Obstacle; // nearest vehicle detected ahead on current route
|
||||
|
||||
Reference in New Issue
Block a user