#183 FIXED: the ENG-page BAY FIRE icon could never light -- the gauge cluster's ammo-bin link was a RAW-OFFSET walk that resolved to NULL. Oracle reported no bay-fire icon where the jam icon shows. Everything upstream was already correct and #47-verified: the AmmoBin arms cookOffArmed on the authentic gate (heat alarm FAILURE + rounds remaining), counts a fixed 10s fuse and detonates; the widget exists (btefire.pcc, TwoState) and its coordinates are BYTE-FAITHFUL to the binary (jam 0xa0,0xb2 / fire 0x121,0xb6, part_014.c:6510-6522 -- note the machine puts them in DIFFERENT places, so the report's 'same place as the jam icon' premise is wrong). The break was BallisticWeaponCluster::Execute resolving the bin with ResolveLink(subsystem + 0x43c) -- the BINARY's layout applied to our compiled ProjectileWeapon, i.e. the databinding trap the conventions forbid. It returned NULL, so BTAmmoBinCookOffArmed(NULL) read 0 forever and the icon had no input. The typed bridge already existed: BTWeaponAmmoBin (projweap.cpp) was written in July for this exact trap when the ammo DIGITS failed to bind the same way -- these two call sites were simply missed. Both now use it; TestInstance's raw bin+0x180 round-count read replaced with a new typed BTAmmoBinRoundCount. Rig added (BT_BAYFIRE_TEST=<seconds> drives the AUTHENTIC arming condition, same hook family as BT_VALVE/BT_FLUSH_TEST) plus an edge-only [gau-fire] receipt. Measured: before, bin=00000000 cookOffArmed=0 on every cluster; after, each cluster binds a real bin and the burning rack alone reports cookOffArmed 0->1->0 across arm and detonation while its neighbours stay 0. NOTE #47's fix was correct but only 'data path rig-verified' with the pixels left to the field -- this is why that gap mattered.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
4457a8503c
commit
86c1f54644
@@ -250,6 +250,13 @@ int BTAmmoBinCookOffTime(void *bin)
|
||||
{
|
||||
return (bin != 0) ? ((AmmoBin *)bin)->cookOffTime : 0;
|
||||
}
|
||||
// #183: the round count, for the gauge cluster's TestInstance gate. Same
|
||||
// databinding rule as the two above -- the caller used to raw-read bin+0x180,
|
||||
// which is the BINARY's offset and garbage on our compiled AmmoBin.
|
||||
int BTAmmoBinRoundCount(void *bin)
|
||||
{
|
||||
return (bin != 0) ? ((AmmoBin *)bin)->GetAmmoCount() : 0;
|
||||
}
|
||||
|
||||
// The round's GameModel resource ID (ammoModelFile @0x1E8, word 0x7A). In the
|
||||
// arcade the MissileLauncher seeds each spawned Missile's model from AmmoBin+0x1e8
|
||||
@@ -353,6 +360,32 @@ void AmmoBin::AmmoBinSimulation(Scalar time_slice)
|
||||
{
|
||||
WatchSimulation(time_slice); // FUN_004aeac4(this) -- drive this+0x140
|
||||
|
||||
// #183 VERIFICATION HOOK (BT_BAYFIRE_TEST=<seconds>, off by default).
|
||||
// #47 fixed the fire icon's DATA PATH and asked the field to "confirm the
|
||||
// pixels"; Oracle reports no icon, so the pixels need a rig rather than a
|
||||
// playtest. Forcing a real bay fire in play takes sustained ballistic heat
|
||||
// on a specific bin -- this drives the AUTHENTIC arming condition instead
|
||||
// (heat alarm -> FAILURE on a non-empty bin) at a scripted time, so
|
||||
// everything downstream (cookOffArmed, the countdown, the icon, the
|
||||
// detonation) runs exactly as it does in a match. Same hook family as
|
||||
// BT_VALVE / BT_POWER_DETACH_TEST / BT_FLUSH_TEST.
|
||||
{
|
||||
static const char *s_bfEnv = getenv("BT_BAYFIRE_TEST");
|
||||
if (s_bfEnv != 0 && *s_bfEnv != '\0' && ammoCount > 0)
|
||||
{
|
||||
static Scalar s_bfClock = 0.0f;
|
||||
static int s_bfFired = 0;
|
||||
s_bfClock += time_slice;
|
||||
if (!s_bfFired && s_bfClock >= (Scalar)atof(s_bfEnv))
|
||||
{
|
||||
s_bfFired = 1;
|
||||
heatAlarm.SetLevel(2); // FAILURE -- the authentic arm gate
|
||||
DEBUG_STREAM << "[bayfire-test] forced heat FAILURE on " << GetName()
|
||||
<< " (" << ammoCount << " rounds)\n" << std::flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (simulationState == 1) // this+0x40 (destroyed)
|
||||
ammoAlarm.SetLevel(Empty);
|
||||
|
||||
|
||||
@@ -1831,6 +1831,7 @@ WeaponCluster::WeaponCluster(
|
||||
// weapon's name so the Execute probe can attribute its readings; tag the
|
||||
// recharge arc with the same name for its own [arc] probe.
|
||||
diagWeaponName = (subsystem_in != 0) ? subsystem_in->GetName() : "?";
|
||||
lastLoggedBayFire = -1; // #183 diagnostic edge tracker
|
||||
((SegmentArc270 *)rechargeArc)->diagName = diagWeaponName;
|
||||
}
|
||||
|
||||
@@ -2081,11 +2082,37 @@ void BallisticWeaponCluster::BecameActive()
|
||||
void BallisticWeaponCluster::Execute()
|
||||
{
|
||||
jammed = (*(int *)((char *)subsystem + 0x364) == 5); // BEST-EFFORT raw (weaponAlarm==Jammed)
|
||||
void *ammoBin = ResolveLink((char *)subsystem + 0x43c); // FUN_00417ab4
|
||||
// #183 DATABINDING FIX (gotcha: never raw-read a compiled object's offsets).
|
||||
// The hand-rolled walk `ResolveLink(subsystem + 0x43c)` is the BINARY's
|
||||
// layout; on our compiled ProjectileWeapon it resolved to NULL, so
|
||||
// cookOffArmed always read 0 and the bay-fire icon could never light --
|
||||
// which is exactly the "no icon" the field reports (#183), even though #47
|
||||
// had correctly fixed the flag this reads. The typed bridge already
|
||||
// existed: BTWeaponAmmoBin (projweap.cpp) was written in July for this same
|
||||
// trap, when the ammo DIGITS failed to bind for the same reason; these two
|
||||
// call sites were missed.
|
||||
extern void *BTWeaponAmmoBin(void *weapon); // projweap.cpp (typed link)
|
||||
void *ammoBin = BTWeaponAmmoBin(subsystem);
|
||||
extern int BTAmmoBinCookOffArmed(void *bin); // bin+0x18C (complete-type bridge)
|
||||
extern int BTAmmoBinCookOffTime(void *bin); // bin+0x190
|
||||
int bayFire = BTAmmoBinCookOffArmed(ammoBin);
|
||||
firing = bayFire; // the btefire TwoState input
|
||||
// #183 probe: #47 fixed this data path but the pixels were never confirmed
|
||||
// and the field reports no icon. Print what the CLUSTER sees, so a rig can
|
||||
// separate "flag never arrives" from "flag arrives, lamp does not draw".
|
||||
if (getenv("BT_BAYFIRE_LOG"))
|
||||
{
|
||||
// edge-only per cluster: a bay fire burns for 10s at gauge rate, and
|
||||
// a per-frame line buries the transition we care about.
|
||||
if (bayFire != lastLoggedBayFire)
|
||||
{
|
||||
lastLoggedBayFire = bayFire;
|
||||
DEBUG_STREAM << "[gau-fire] cluster '"
|
||||
<< (diagWeaponName ? diagWeaponName : "?")
|
||||
<< "' bin=" << ammoBin << " cookOffArmed=" << bayFire
|
||||
<< " fireLamp=" << (void *)fireLamp << "\n" << std::flush;
|
||||
}
|
||||
}
|
||||
if (bayFire == 0)
|
||||
{
|
||||
reloading = 0;
|
||||
@@ -2127,8 +2154,10 @@ void BallisticWeaponCluster::DrawWarningLamp(int on)
|
||||
//
|
||||
Logical BallisticWeaponCluster::TestInstance() const
|
||||
{
|
||||
void *ammoBin = ResolveLink((char *)subsystem + 0x43c);
|
||||
if (ammoBin == NULL || *(int *)((char *)ammoBin + 0x180) == 0)
|
||||
extern void *BTWeaponAmmoBin(void *weapon); // projweap.cpp (typed link)
|
||||
extern int BTAmmoBinRoundCount(void *bin); // ammobin.cpp (typed count)
|
||||
void *ammoBin = BTWeaponAmmoBin(subsystem);
|
||||
if (ammoBin == NULL || BTAmmoBinRoundCount(ammoBin) == 0)
|
||||
return True;
|
||||
if (jammed != 0)
|
||||
return True;
|
||||
|
||||
@@ -509,6 +509,7 @@
|
||||
int warningCenterY; // @0xE0 this[0x38]
|
||||
int warningState; // @0xE4 this[0x39]
|
||||
const char *diagWeaponName; // PORT diagnostic (appended; clusters are plain-new)
|
||||
int lastLoggedBayFire; // PORT diagnostic (#183): edge-only [gau-fire] logging
|
||||
};
|
||||
|
||||
class EnergyWeaponCluster : // @004c93b0
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
# =========================================================================
|
||||
# #183 -- does the ENG-page BAY FIRE icon light?
|
||||
# #47 fixed the data path and asked the field to "confirm the pixels";
|
||||
# Oracle reports no icon. Force a real bay fire with BT_BAYFIRE_TEST and
|
||||
# watch the whole chain:
|
||||
# [bayfire-test] forced heat FAILURE ... the rig armed it
|
||||
# [ammo] ... BAY FIRE: cook-off armed ... the AUTHENTIC arm fired
|
||||
# [gau-fire] ... what the ENG cluster sees
|
||||
# A solo expert madcat (ballistic bins) on grass.
|
||||
# usage: bayfire183.sh [seconds-before-arming]
|
||||
# =========================================================================
|
||||
set -x
|
||||
. /c/git/bt411/scratchpad/night6/bench_common.sh
|
||||
cd /c/git/bt411/content || exit 1
|
||||
taskkill //F //IM btl4.exe > /dev/null 2>&1
|
||||
sleep 2
|
||||
|
||||
AT=${1:-20}
|
||||
bt_expert_egg MP.EGG BF183.EGG
|
||||
sed -i "s/^map=.*/map=grass/; s/^time=.*/time=day/; 0,/^vehicle=.*/s//vehicle=madcat/" BF183.EGG
|
||||
LOG=bayfire183.log
|
||||
rm -f "$LOG"
|
||||
( export BT_BAYFIRE_TEST=$AT BT_DEATH_LOG=1 BT_BAYFIRE_LOG=1 BT_DEV_GAUGES=1
|
||||
bt_launch "$LOG" BF183.EGG 0x03 )
|
||||
sleep 55
|
||||
bt_kill_ours
|
||||
sleep 2
|
||||
taskkill //F //IM btl4.exe > /dev/null 2>&1
|
||||
echo "=== the chain ==="
|
||||
grep -a "bayfire-test\|BAY FIRE\|EXTINGUISH\|gau-fire" "$LOG" | head -20
|
||||
Reference in New Issue
Block a user