From 4f47233a89e3ab3693dc2be4db604430f135bb4a Mon Sep 17 00:00:00 2001
From: Piotr Warszawski
Date: Fri, 4 Sep 2026 21:01:33 +0200
Subject: [PATCH 1/3] whois: fall back to the consist owner in the +0/+7 mode
too
The +8/+16/+24/+32/+40 (and the new +48) modes all pick the reporting
vehicle the same way: the activator's own Mechanik if it's the primary
driver, otherwise the consist's controlling vehicle (ctOwner) - so the
event still resolves correctly if a wagon happens to trigger it ahead
of its locomotive.
+0 (train name / stations left / stop flag) predates that pattern and
never got it: it required m_activator->Mechanik directly and silently
wrote nothing otherwise. A whois hook placed where the loco doesn't
necessarily lead (e.g. a train that reverses direction, or one being
propelled) can have a wagon trigger the event first and the memcell
stays empty, with no error - hard to diagnose from scenery side.
Same owner-selection, same guard semantics (still nothing written if
neither the activator nor its consist has a controller), only the
source of the vehicle it reads from is widened.
---
world/Event.cpp | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/world/Event.cpp b/world/Event.cpp
index eb679e72..09afec61 100644
--- a/world/Event.cpp
+++ b/world/Event.cpp
@@ -1129,20 +1129,28 @@ whois_event::run_() {
+ "[engine power: " + to_string( m_activator->MoverParameters->Power, 2 ) + "]" );
}
// +0
- else if( m_activator->Mechanik ) {
- if( m_activator->Mechanik->primary() ) { // tylko jeśli ktoś tam siedzi - nie powinno dotyczyć pasażera!
+ else {
+ // same owner selection as the +8/+16/+24/+32/+40/+48 branches above: fall back to
+ // the consist's controlling vehicle if the activator itself isn't one (e.g. a wagon
+ // triggered the event ahead of its locomotive) - +0 used to require the activator's
+ // own Mechanik and silently produce nothing for a wagon-triggered whois
+ auto const *owner { (
+ m_activator->Mechanik != nullptr && m_activator->Mechanik->primary() ?
+ m_activator->Mechanik :
+ m_activator->ctOwner ) };
+ if( owner != nullptr ) {
targetcell->UpdateValues(
- m_activator->Mechanik->TrainName(),
- m_activator->Mechanik->StationCount() - m_activator->Mechanik->StationIndex(), // ile przystanków do końca
- m_activator->Mechanik->IsStop() ?
+ owner->TrainName(),
+ owner->StationCount() - owner->StationIndex(), // ile przystanków do końca
+ owner->IsStop() ?
1 :
0, // 1, gdy ma tu zatrzymanie
m_input.flags & ( flags::text | flags::value1 | flags::value2 ) );
WriteLog(
"Type: WhoIs (" + std::to_string( m_input.flags ) + ") - "
- + "[train: " + m_activator->Mechanik->TrainName() + "], "
- + "[stations left: " + std::to_string( m_activator->Mechanik->StationCount() - m_activator->Mechanik->StationIndex() ) + "], "
- + "[stop at next station: " + ( m_activator->Mechanik->IsStop() ? "yes" : "no") + "]" );
+ + "[train: " + owner->TrainName() + "], "
+ + "[stations left: " + std::to_string( owner->StationCount() - owner->StationIndex() ) + "], "
+ + "[stop at next station: " + ( owner->IsStop() ? "yes" : "no") + "]" );
}
}
}
From 7ead4f11b4d87384a5894947c0efe440bed80642 Mon Sep 17 00:00:00 2001
From: Piotr Warszawski
Date: Fri, 4 Sep 2026 22:09:23 +0200
Subject: [PATCH 2/3] whois: guard against a null activator
whois_event::run_() dereferenced m_activator unconditionally in every
branch (this predates this PR). getvalues_event::run_() and
putvalues_event::run_() already guard the same way elsewhere in this
file; whois_event was missing it. Single early return covers every
branch, old and new.
---
world/Event.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/world/Event.cpp b/world/Event.cpp
index 09afec61..73f10592 100644
--- a/world/Event.cpp
+++ b/world/Event.cpp
@@ -1014,6 +1014,8 @@ whois_event::deserialize_( cParser &Input, scene::scratch_data &Scratchpad ) {
void
whois_event::run_() {
+ if( m_activator == nullptr ) { return; }
+
for( auto &target : m_targets ) {
auto *targetcell { static_cast( std::get( target ) ) };
if( targetcell == nullptr ) { continue; }
From 1ce576c0c602ebe0bf8629279fd75177fa4f8e80 Mon Sep 17 00:00:00 2001
From: Piotr Warszawski
Date: Fri, 4 Sep 2026 22:22:25 +0200
Subject: [PATCH 3/3] whois: log the no-activator case instead of failing
silently
A whois with no triggering vehicle previously just wrote nothing to
the target cell with no trace in the log, which is a real pain to
diagnose from the scenery side (this is exactly the kind of thing that
cost real debugging time on a station script recently).
Co-Authored-By: Claude Sonnet 5
---
world/Event.cpp | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/world/Event.cpp b/world/Event.cpp
index 73f10592..8e89740e 100644
--- a/world/Event.cpp
+++ b/world/Event.cpp
@@ -1014,7 +1014,12 @@ whois_event::deserialize_( cParser &Input, scene::scratch_data &Scratchpad ) {
void
whois_event::run_() {
- if( m_activator == nullptr ) { return; }
+ if( m_activator == nullptr ) {
+ // no triggering vehicle to report on - most likely whois was launched from a
+ // scenery event chain rather than a track/isolation crossing
+ WriteLog( "Type: WhoIs (" + std::to_string( m_input.flags ) + ") - no activator, event ignored" );
+ return;
+ }
for( auto &target : m_targets ) {
auto *targetcell { static_cast( std::get( target ) ) };