diff --git a/restoration/source410/BT/HEAT.HPP b/restoration/source410/BT/HEAT.HPP index e465ddb7..de7b7c0b 100644 --- a/restoration/source410/BT/HEAT.HPP +++ b/restoration/source410/BT/HEAT.HPP @@ -259,6 +259,26 @@ protected: SubsystemConnection watchedLink; + + public: + // + // THE WATCH BIND (5.3.132). The streamed `watchedSubsystem` index + // has been read since this class landed, but nothing ever turned it + // into the link `UpdateWatch` resolves -- so every watcher in the + // mech resolved NULL and reported its target dead. The Mech ctor + // binds these in a post-walk pass: a watcher can legally watch a + // subsystem with a HIGHER roster id, which does not exist yet while + // the segment walk is still building, so the bind cannot live in + // this ctor. + // + int + WatchedSubsystemIndex() const + { Check(this); return watchedSubsystem; } + void + BindWatchedSubsystem(Subsystem *watched) + { Check(this); watchedLink.Add(watched); } + + protected: int watchedSubsystem; Scalar degradationTemperature; Scalar failureTemperature; diff --git a/restoration/source410/BT/MECH.CPP b/restoration/source410/BT/MECH.CPP index c98cb293..73393b4b 100644 --- a/restoration/source410/BT/MECH.CPP +++ b/restoration/source410/BT/MECH.CPP @@ -598,6 +598,51 @@ Mech::Mech( } RedistributeCoolantShares(); + // + //----------------------------------------------------------------------- + // THE WATCH BINDS (5.3.132). Every HeatWatcher descendant -- which is + // the whole watcher family, PowerWatcher and the Gyroscope / Torso / HUD + // leaves included -- streams the roster index of the subsystem it + // watches, and `UpdateWatch` resolves a link built from it. Nothing + // ever built that link, so every watcher resolved NULL and reported its + // target unpowered / stone cold. + // + // This runs POST-WALK, not in the watcher ctor: a watcher may legally + // watch a subsystem with a higher roster id, which does not exist yet + // while the walk is still building. Out-of-range and self-referencing + // indices are skipped rather than trusted. + //----------------------------------------------------------------------- + // + { + for (int wb = 2; wb < subsystemCount; ++wb) + { + Subsystem *watcher = subsystemArray[wb]; + if ( + watcher == NULL || + !watcher->IsDerivedFrom(HeatWatcher::ClassDerivations) + ) + { + continue; + } + + int index = ((HeatWatcher *)watcher)->WatchedSubsystemIndex(); + Subsystem *watched = + (index >= 2 && index < subsystemCount && index != wb) + ? subsystemArray[index] + : NULL; + + ((HeatWatcher *)watcher)->BindWatchedSubsystem(watched); + + if (getenv("BT_MECH_LOG")) + { + DEBUG_STREAM << "[watch] '" << watcher->GetName() + << "' watches index " << index << " -> " + << ((watched != NULL) ? watched->GetName() : "(unbound)") + << endl << flush; + } + } + } + // //----------------------------------------------------------------------- // THE MYOMER CHAIN (binary ctor sweep, part_012.c:15871: the mech+0x7ac diff --git a/restoration/source410/BT/MECH4.NOTES.md b/restoration/source410/BT/MECH4.NOTES.md index ebe0c969..a5bdbcd2 100644 --- a/restoration/source410/BT/MECH4.NOTES.md +++ b/restoration/source410/BT/MECH4.NOTES.md @@ -519,3 +519,41 @@ The fix needs the streamed watch index out of the watcher resource plus the ctor bind, in the shape the crit-table binding already uses. That is a proper brick, not a guess, and guessing a binding is exactly what this project's rules forbid -- so it is recorded here for the next sitting. + +## 5.3.132 -- THE WATCHERS ARE BOUND (the family stops being inert) + +The missing piece found in 5.3.131 is landed. `HeatWatcher` has always +streamed `watchedSubsystem` and read it into a member; nothing ever turned +that index into the link `UpdateWatch` resolves. The Mech ctor now binds +them in a POST-WALK pass -- necessarily post-walk, because a watcher may +watch a subsystem with a HIGHER roster id, which does not exist yet while +the segment walk is still running -- with out-of-range and self-reference +skipped rather than trusted. + +THE BINDINGS PROVE THEMSELVES. Every index resolves to a semantically +right target on bhk1, which a wrong offset could not do: + + Gyroscope -> Avionics HUD -> Avionics + Torso -> Myomers Searchlight -> Avionics + AmmoBinAFC100 -> AFC100 AmmoBinLRM15_1 -> LRM15_1 + AmmoBinLRM15_2 -> LRM15_2 + +The gyro and HUD watch the avionics bus, the torso watches the muscles +that move it, and every ammo bin watches its own gun. + +### The next question, now sharply posed + +With the link live the gyro's watchdog moved 0 -> 1, so it is no longer +the NULL fallback. But 1 is not Ready (4), and `UpdateWatch` can produce +1 two ways: the watched subsystem reporting NoVoltage, or the BROWNOUT +branch (watched Ready, but its generator's measured voltage at or below +`minVoltage * RatedVoltage`). + +Avionics is classID 3011 -- a SENSOR instance, named "Avionics" in the art +-- and the roster-live line reports a Sensor at voltState 4. So the +watched subsystem looks READY, which points at the BROWNOUT branch firing +persistently. Next sitting: is `minVoltage` authored/read correctly on +these watchers, or is the reconstructed generator genuinely sitting at the +brownout threshold? Log the watched level and the measured/rated pair +side by side to separate them -- do not adjust a threshold to make an +alarm quiet.