From 4575f61cc8d8919571a72c9023b7cd584c81cba1 Mon Sep 17 00:00:00 2001 From: Piotr Warszawski Date: Fri, 4 Sep 2026 15:52:38 +0200 Subject: [PATCH 1/3] whois: add lookahead mode for the timetable entry after the next stop Dispatcher scripts that route trains at a station based on where they go afterwards (e.g. a big terminal throat with several outbound directions) have no way to read that: whois +40 only exposes the current/next timetable entry (NextStop()/IsStop()), which while the train is at that very station is that station itself. Adds flags::whois_ahead (bit 6, previously unused) plus TTrainParameters::StationNameAhead(Offset)/StationIsStopAhead(Offset), returning the raw TimeTable[] entry Offset positions past StationIndex (name and whether it's a booked stop, "none"/false past the end of the timetable). The new whois branch calls both with Offset=1, mirroring the existing +40 branch's UpdateValues()/WriteLog() shape. Logic-verified with an isolated harness mirroring the touched types (TTrainParameters/TController/TMemCell shapes and the exact function bodies); not yet build-tested against the full engine locally - relying on CI for that. --- world/Event.cpp | 31 ++++++++++++++++++++++++++++++- world/Event.h | 1 + world/mtable.cpp | 16 ++++++++++++++++ world/mtable.h | 4 ++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/world/Event.cpp b/world/Event.cpp index eb679e720..e47dbea23 100644 --- a/world/Event.cpp +++ b/world/Event.cpp @@ -1018,13 +1018,42 @@ whois_event::run_() { auto *targetcell { static_cast( std::get( target ) ) }; if( targetcell == nullptr ) { continue; } // event effect code + // +64: station after the next one, unused, stop there or passthrough // +40: next station name, unused, stop at next station (duplicate of +0 2nd numeric value) // +32: vehicle name // +24: vehicle type, consist brake level, obstacle distance // +16: load type, load amount, max load amount // +8: destination, direction, engine power // +0: train name, station count, stop on next station - if( m_input.flags & flags::whois_name ) { + if( m_input.flags & flags::whois_ahead ) { + // +64 + // the timetable entry one past the next stop, and whether the train stops there + auto const *owner { ( + m_activator->Mechanik != nullptr && m_activator->Mechanik->primary() ? + m_activator->Mechanik : + m_activator->ctOwner ) }; + auto const aheadname { ( + owner != nullptr ? + owner->TrainTimetable().StationNameAhead( 1 ) : + "none" ) }; + auto const aheadstop { ( + owner != nullptr && owner->TrainTimetable().StationIsStopAhead( 1 ) ? + 1 : + 0 ) }; + + targetcell->UpdateValues( + aheadname, // station after the next one + 0, // unused + aheadstop, // stop there or passthrough + m_input.flags & ( flags::text | flags::value1 | flags::value2 ) ); + + WriteLog( + "Type: WhoIs (" + std::to_string( m_input.flags ) + ") - " + + "[station after next: " + aheadname + "], " + + "[X], " + + "[stop there: " + ( aheadstop != 0 ? "yes" : "no" ) + "]" ); + } + else if( m_input.flags & flags::whois_name ) { // +32 or +40 // next station name if( m_input.flags & flags::mode_alt ) { diff --git a/world/Event.h b/world/Event.h index 52ee3468d..55be65de1 100644 --- a/world/Event.h +++ b/world/Event.h @@ -37,6 +37,7 @@ public: mode_alt = 1 << 3, whois_load = 1 << 4, whois_name = 1 << 5, + whois_ahead = 1 << 6, // condition values track_busy = 1 << 3, track_free = 1 << 4, diff --git a/world/mtable.cpp b/world/mtable.cpp index cec54f870..75e6c8ad0 100644 --- a/world/mtable.cpp +++ b/world/mtable.cpp @@ -77,6 +77,22 @@ bool TTrainParameters::IsLastStop() const { return StationIndex >= StationCount; } +std::string TTrainParameters::StationNameAhead( int Offset ) const +{ // nazwa wpisu rozkladu Offset pozycji za aktualnym (bez pomijania przelotow) + int const idx { StationIndex + Offset }; + if( ( idx < 1 ) || ( idx > StationCount ) ) + return "none"; + return TimeTable[idx].StationName; +} + +bool TTrainParameters::StationIsStopAhead( int Offset ) const +{ // czy wpis Offset pozycji za aktualnym to zaplanowany postoj + int const idx { StationIndex + Offset }; + if( ( idx < 1 ) || ( idx > StationCount ) ) + return false; + return TimeTable[idx].Ah >= 0; //-1 to brak postoju +} + bool TTrainParameters::IsMaintenance() const { if( StationIndex <= StationCount ) diff --git a/world/mtable.h b/world/mtable.h index c58d120ff..701b0c6ca 100644 --- a/world/mtable.h +++ b/world/mtable.h @@ -70,6 +70,10 @@ class TTrainParameters std::string ShowRelation() const; double WatchMTable(double DistCounter); std::string NextStop() const; + // nazwa wpisu rozkladu Offset pozycji za StationIndex (Offset>=1); "none" poza koncem rozkladu + std::string StationNameAhead( int Offset ) const; + // true, gdy ten wpis to zaplanowany postoj (ma godzine przyjazdu), false dla przelotu / poza koncem + bool StationIsStopAhead( int Offset ) const; sound_source next_stop_sound() const; sound_source last_stop_sound() const; bool IsStop() const; From 5705062cd29826b9bb1386eb2ccfa5be258a3204 Mon Sep 17 00:00:00 2001 From: Piotr Warszawski Date: Fri, 4 Sep 2026 20:28:28 +0200 Subject: [PATCH 2/3] whois: select the lookahead mode via +48 instead of a new bit Per review: +48 (whois_name | whois_load, mode_alt clear) was an unused combination of the existing mode bits - use that instead of claiming a new bit 6. +56 (same, with mode_alt set) stays free for a future mode. No new flags::* entry needed; mtable.h/.cpp unchanged. --- world/Event.cpp | 8 +++++--- world/Event.h | 1 - 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/world/Event.cpp b/world/Event.cpp index e47dbea23..ebfc73958 100644 --- a/world/Event.cpp +++ b/world/Event.cpp @@ -1018,15 +1018,17 @@ whois_event::run_() { auto *targetcell { static_cast( std::get( target ) ) }; if( targetcell == nullptr ) { continue; } // event effect code - // +64: station after the next one, unused, stop there or passthrough + // +48: station after the next one, unused, stop there or passthrough // +40: next station name, unused, stop at next station (duplicate of +0 2nd numeric value) // +32: vehicle name // +24: vehicle type, consist brake level, obstacle distance // +16: load type, load amount, max load amount // +8: destination, direction, engine power // +0: train name, station count, stop on next station - if( m_input.flags & flags::whois_ahead ) { - // +64 + if( ( m_input.flags & ( flags::whois_name | flags::whois_load | flags::mode_alt ) ) + == ( flags::whois_name | flags::whois_load ) ) { + // +48 (the whois_name | whois_load combination was unused; +56, same with mode_alt + // set, stays free for a future mode) // the timetable entry one past the next stop, and whether the train stops there auto const *owner { ( m_activator->Mechanik != nullptr && m_activator->Mechanik->primary() ? diff --git a/world/Event.h b/world/Event.h index 55be65de1..52ee3468d 100644 --- a/world/Event.h +++ b/world/Event.h @@ -37,7 +37,6 @@ public: mode_alt = 1 << 3, whois_load = 1 << 4, whois_name = 1 << 5, - whois_ahead = 1 << 6, // condition values track_busy = 1 << 3, track_free = 1 << 4, From 93463a3850e50f8818d12c042a6ef7e3639b84f3 Mon Sep 17 00:00:00 2001 From: Piotr Warszawski Date: Fri, 4 Sep 2026 21:24:01 +0200 Subject: [PATCH 3/3] whois: consolidate the two lookahead accessors into one Per review: StationNameAhead()/StationIsStopAhead() duplicated the same bounds check for no reason. Replaced with a single TimeTableEntryAhead(Offset) returning the TMTableLine itself; the whois branch reads .StationName/.Ah off it directly. --- world/Event.cpp | 12 +++++------- world/mtable.cpp | 17 +++++------------ world/mtable.h | 7 +++---- 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/world/Event.cpp b/world/Event.cpp index ebfc73958..319ad0591 100644 --- a/world/Event.cpp +++ b/world/Event.cpp @@ -1034,14 +1034,12 @@ whois_event::run_() { m_activator->Mechanik != nullptr && m_activator->Mechanik->primary() ? m_activator->Mechanik : m_activator->ctOwner ) }; - auto const aheadname { ( + auto const *entry { ( owner != nullptr ? - owner->TrainTimetable().StationNameAhead( 1 ) : - "none" ) }; - auto const aheadstop { ( - owner != nullptr && owner->TrainTimetable().StationIsStopAhead( 1 ) ? - 1 : - 0 ) }; + &owner->TrainTimetable().TimeTableEntryAhead( 1 ) : + nullptr ) }; + auto const aheadname { ( entry != nullptr ? entry->StationName : "none" ) }; + auto const aheadstop { ( entry != nullptr && entry->Ah >= 0 ? 1 : 0 ) }; targetcell->UpdateValues( aheadname, // station after the next one diff --git a/world/mtable.cpp b/world/mtable.cpp index 75e6c8ad0..dd84b6c23 100644 --- a/world/mtable.cpp +++ b/world/mtable.cpp @@ -77,20 +77,13 @@ bool TTrainParameters::IsLastStop() const { return StationIndex >= StationCount; } -std::string TTrainParameters::StationNameAhead( int Offset ) const -{ // nazwa wpisu rozkladu Offset pozycji za aktualnym (bez pomijania przelotow) +TMTableLine const &TTrainParameters::TimeTableEntryAhead( int Offset ) const +{ // wpis rozkladu Offset pozycji za aktualnym (bez pomijania przelotow); + // poza zakresem 1..StationCount zwraca techniczny wpis zerowy int const idx { StationIndex + Offset }; if( ( idx < 1 ) || ( idx > StationCount ) ) - return "none"; - return TimeTable[idx].StationName; -} - -bool TTrainParameters::StationIsStopAhead( int Offset ) const -{ // czy wpis Offset pozycji za aktualnym to zaplanowany postoj - int const idx { StationIndex + Offset }; - if( ( idx < 1 ) || ( idx > StationCount ) ) - return false; - return TimeTable[idx].Ah >= 0; //-1 to brak postoju + return TimeTable[0]; + return TimeTable[idx]; } diff --git a/world/mtable.h b/world/mtable.h index 701b0c6ca..2d20a27bb 100644 --- a/world/mtable.h +++ b/world/mtable.h @@ -70,10 +70,9 @@ class TTrainParameters std::string ShowRelation() const; double WatchMTable(double DistCounter); std::string NextStop() const; - // nazwa wpisu rozkladu Offset pozycji za StationIndex (Offset>=1); "none" poza koncem rozkladu - std::string StationNameAhead( int Offset ) const; - // true, gdy ten wpis to zaplanowany postoj (ma godzine przyjazdu), false dla przelotu / poza koncem - bool StationIsStopAhead( int Offset ) const; + // wpis rozkladu Offset pozycji za StationIndex (Offset>=1); poza zakresem 1..StationCount + // zwraca techniczny wpis zerowy (TimeTable[0], StationName=="nowhere", Ah==-1) + TMTableLine const &TimeTableEntryAhead( int Offset ) const; sound_source next_stop_sound() const; sound_source last_stop_sound() const; bool IsStop() const;