#87 dig closure: host response is linear (raw decomp re-read); the pixel curve was div-card firmware
Re-read the material damage watcher RAW (@004573e4 ctor / @00457784 change-push): 16 floats snapshotted, damaged = pristine x 0.1 (literal at the MakeMechRenderables call site, watching zone+0x158), linear lerp, 13 floats written back, then FUN_0048d4d4 -- which is "flush_material": a dpl command-stream marshal (opcode 100) to the i860 division card. The material->ramp->texel response curve was CARD firmware and is not in BTL4OPT.EXE; logged as an open question (ask: firmware/DIV docs/period screenshots). Field reconciliation, measured live: one 25-pt hit (ERLG class) snaps a 77-pt arm 0 -> 0.3247 in a frame -- "a single missile leaves visible armor damage" holds under the linear curve for heavy hits; 2-pt ERS creep (the leg-audit weapon) is the invisible case. Bench additions: BT_WALK_ZONES=<name-list> walker filter (concentrated per-region audits, scratchpad/night10/legwalk.sh) + BindArmourDamage ORPHAN inventory under BT_ARMOR_LOG (proved every drawn op is zone-claimed on the full tree). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
fe48accb6b
commit
440cee1e4f
@@ -1044,12 +1044,24 @@ both sides).
|
||||
|
||||
Render-path note (gotcha #23 discharged): the tint itself was pixel-proven with
|
||||
`BT_ARMOR_FORCE` A/B captures -- all-zones 1.0 renders the hull charcoal (0.1x
|
||||
floor), so "no discoloration" was never the renderer. Solo/master-side
|
||||
perception is the authentic ECONOMY: 2-25 pt laser events vs 68-185 pt zone
|
||||
pools = single-digit % levels = a 2-10% darkening + a doll tick of a few color
|
||||
indices. The cockpit doll maps all 28 zones (L4GAUGE.CFG:4788-4814 cmArmor
|
||||
lines -- feet + lower legs included); a "leg shots never show" report is those
|
||||
zones' levels peaking ~0.08-0.13, not a wiring gap.
|
||||
floor), forced 0.4 reads visibly grey at close range on a light skin, so "no
|
||||
discoloration" was never the renderer. Solo/master-side perception is the
|
||||
authentic ECONOMY: 2-25 pt laser events vs 68-185 pt zone pools. The eye
|
||||
catches SNAPS, not creep: a single heavy hit (ERLG large laser / missile
|
||||
class, amt=25) jumps a 77-pt arm 0 -> 0.3247 in one frame (measured live) =
|
||||
the pod veterans' "a single missile leaves visible armor damage"; 2-pt ERS
|
||||
fire creeps ~1.6%/hit and stays visually silent for a dozen hits (the
|
||||
"legs never show" reports -- their levels peak ~0.08-0.13). The cockpit doll
|
||||
maps all 28 zones (L4GAUGE.CFG:4788-4814 cmArmor lines -- feet + lower legs
|
||||
included); nothing is unwired (orphan audit 2026-08-03: every drawn op with a
|
||||
material name is claimed by a zone).
|
||||
|
||||
Fidelity boundary [T1]: the HOST binary's response is LINEAR (watcher
|
||||
@004573e4/@00457784: 13 material floats lerped toward x0.1 by level, then
|
||||
"flush_material" to the division card). The CARD-side material->ramp->texel
|
||||
curve is i860 firmware absent from BTL4OPT.EXE -- see [[open-questions]]
|
||||
"i860 DIVISION-CARD firmware". If pod darkening was perceptually steeper at
|
||||
mid levels, that steepness lived there.
|
||||
|
||||
## The hit-location CYLINDER -- raw-bytes audit + chassis->table map (2026-08-02) [T1]
|
||||
|
||||
|
||||
@@ -22,6 +22,20 @@ authentic path scoped.
|
||||
further assets exist; the runtime `BTL4.RES` with 8 maps + full anim set is the master we have).
|
||||
- Pod specifics for Phase 8: the 7-monitor driver setup, the RIO cockpit I/O protocol, current
|
||||
Win10+wrapper pod config. Status: OPEN.
|
||||
- **The i860 DIVISION-CARD firmware / DIV render docs (the material→pixel response curve).**
|
||||
Established 2026-08-03 (#87 dig): the HOST binary lerps 13 material colour floats linearly
|
||||
toward ×0.1 by zone damageLevel (watcher @004573e4/@00457784, 0.1 literal at the
|
||||
MakeMechRenderables call site) and then just **marshals the material to the card**
|
||||
(`FUN_0048d4d4` = "flush_material", dpl command opcode 100 — siblings flush_ramp/flush_texture).
|
||||
The card-side shading (how material colour selected/scaled the 256-row material ramps → final
|
||||
texels) is i860 firmware, NOT in BTL4OPT.EXE — so the PERCEPTUAL damage-darkening curve of the
|
||||
1995 pods cannot be recovered from this binary. Our port applies the host's linear factor at
|
||||
draw (TFACTOR modulate, L4D3D). Field testimony ("a single missile leaves visible armor
|
||||
damage") is arithmetically consistent with the linear curve — one 25-pt hit snaps a 68-90-pt
|
||||
zone by 0.28-0.37 (measured live: amt=25 → rarm 0→0.3247) — but if the card's ramp mapping was
|
||||
steeper than linear, mid-level creep damage read stronger on the pods than in the port.
|
||||
ASK: div-card firmware image, DIV/dpl render docs, or period screenshots showing a
|
||||
known-damage-level mech. Status: OPEN.
|
||||
- **Did the pod throttle quadrant have MECHANICAL detents** (how many / lever positions)? The
|
||||
software path is notch-free [T1, [[pod-hardware]]], but the gait SM's walk/run dead band
|
||||
([[locomotion]]) only makes sense if the hardware discouraged parking the lever mid-band —
|
||||
|
||||
@@ -1451,9 +1451,36 @@ void
|
||||
}
|
||||
|
||||
if (log)
|
||||
{
|
||||
DEBUG_STREAM << "[armor] entity " << (void *)entity << " skel="
|
||||
<< tree.skeletonType << ": " << tree.dmgBinds.size()
|
||||
<< " material binding(s)\n" << std::flush;
|
||||
// ORPHAN inventory: drawn ops NO zone claimed. These panels never
|
||||
// darken -- if the big hull materials land here (a .DZM name the mesh
|
||||
// doesn't carry, or per-zone material instancing collapsed at load),
|
||||
// the mech reads "no darkening" live even while every bound op logs
|
||||
// perfectly (the #87 visibility gap).
|
||||
for (std::map<int, MechRenderTree::SegPick>::iterator si = tree.segPick.begin();
|
||||
si != tree.segPick.end(); ++si)
|
||||
{
|
||||
d3d_OBJECT *obj = si->second.obj;
|
||||
if (obj == NULL)
|
||||
continue;
|
||||
for (int op = 0; op < obj->GetDrawOpCount(); ++op)
|
||||
{
|
||||
L4DRAWOP *draw_op = obj->GetDrawOp(op);
|
||||
if (draw_op->dzMatName[0] == '\0')
|
||||
continue;
|
||||
int claimed = 0;
|
||||
for (size_t b = 0; b < tree.dmgBinds.size() && !claimed; ++b)
|
||||
if (tree.dmgBinds[b].obj == obj && tree.dmgBinds[b].op == op)
|
||||
claimed = 1;
|
||||
if (!claimed)
|
||||
DEBUG_STREAM << "[armor] ORPHAN op seg=" << si->first
|
||||
<< " '" << draw_op->dzMatName << "'\n" << std::flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6025,6 +6025,19 @@ void
|
||||
static float s_zwT = 1.0e9f;
|
||||
static int s_zwZone = -1;
|
||||
static int s_zwShots = 0;
|
||||
// BT_WALK_ZONES=<comma-list>: restrict the walk to zones whose NAME
|
||||
// contains one of the tokens (e.g. "leg,foot,hip" -- the concentrated
|
||||
// per-region audit; repeated passes pile damage into few zones so the
|
||||
// doll movement is unmistakable). Empty/absent = walk everything.
|
||||
static const char *s_zwFilter = 0;
|
||||
static int s_zwFilterInit = 0;
|
||||
if (!s_zwFilterInit)
|
||||
{
|
||||
s_zwFilterInit = 1;
|
||||
s_zwFilter = getenv("BT_WALK_ZONES");
|
||||
if (s_zwFilter != 0 && *s_zwFilter == '\0')
|
||||
s_zwFilter = 0;
|
||||
}
|
||||
if (s_zwPeriod <= 0.0f)
|
||||
{
|
||||
s_zwPeriod = (float)atof(getenv("BT_ZONE_WALK"));
|
||||
@@ -6119,8 +6132,32 @@ void
|
||||
s_zwZone = -1; // wrap
|
||||
continue;
|
||||
}
|
||||
if (segIdx >= 0)
|
||||
break;
|
||||
if (segIdx < 0)
|
||||
continue;
|
||||
if (s_zwFilter != 0) // BT_WALK_ZONES name filter
|
||||
{
|
||||
int match = 0;
|
||||
const char *tok = s_zwFilter;
|
||||
while (*tok != '\0' && !match)
|
||||
{
|
||||
const char *end = tok;
|
||||
while (*end != '\0' && *end != ',')
|
||||
++end;
|
||||
char buf[64];
|
||||
int len = (int)(end - tok);
|
||||
if (len > 0 && len < (int)sizeof(buf))
|
||||
{
|
||||
memcpy(buf, tok, len);
|
||||
buf[len] = '\0';
|
||||
if (strstr(zname, buf) != 0)
|
||||
match = 1;
|
||||
}
|
||||
tok = (*end == ',') ? end + 1 : end;
|
||||
}
|
||||
if (!match)
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
DEBUG_STREAM << "[walk] ZONE " << s_zwZone << " '" << zname
|
||||
<< "' seg=" << segIdx << " target="
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
# LEG/FOOT AUDIT -- the zone-walk restricted to the six leg/foot zones
|
||||
# (BT_WALK_ZONES name filter), so repeated passes concentrate fire and the
|
||||
# victim's ARMOR DAMAGE doll movement is unmistakable. Node B captures its
|
||||
# OWN screen every ~10 s (zwB_*.png) -- the doll's climb is in the pixel
|
||||
# record; node A's captures (zwA_*.png) record the hull darkening the
|
||||
# observer now receives (the fe48acc level-crossing send).
|
||||
# READ: python scratchpad/night10/digest_walk.py (zw_a/zw_b logs as usual)
|
||||
set -x
|
||||
. /c/git/bt411/scratchpad/night6/bench_common.sh
|
||||
cd /c/git/bt411/content || exit 1
|
||||
bt_assert_player_env
|
||||
taskkill //F //IM btl4.exe > /dev/null 2>&1
|
||||
sleep 2
|
||||
rm -f zw_a.log zw_b.log zwA_*.png zwB_*.png
|
||||
bt_expert_egg MP.EGG ZW.EGG
|
||||
sed -i "s/^map=.*/map=grass/; s/^time=.*/time=day/; 0,/^vehicle=.*/s//vehicle=madcat/" ZW.EGG
|
||||
|
||||
# TARGET first (right/back window): spins, logs every damage application,
|
||||
# films its own cockpit (the doll is bottom-center of every zwB frame).
|
||||
BT_SPIN_SELF=15 BT_DMG_LOG=1 BT_DEATH_LOG=1 BT_MP_LOG=1 BT_MATCHLOG=1 \
|
||||
BT_SHOT_EVERY=300 BT_SHOT_PREFIX=zwB \
|
||||
bt_launch zw_b.log ZW.EGG 0x0C -net 1601
|
||||
sleep 2
|
||||
# SHOOTER second (foreground -- owns the pick focus): legs + feet only,
|
||||
# 5 s per zone => a full 6-zone cycle every ~30 s.
|
||||
BT_ZONE_WALK=5 BT_WALK_ZONES=leg,foot BT_PICK_LOG=1 \
|
||||
BT_GOTO=enemy BT_GOTO_STOP=90 BT_KEY_NOFOCUS=1 \
|
||||
BT_DMG_LOG=1 BT_RANGE_LOG=1 BT_MP_LOG=1 BT_MATCHLOG=1 \
|
||||
BT_ARMOR_LOG=1 BT_SHOT_EVERY=300 BT_SHOT_PREFIX=zwA \
|
||||
bt_launch zw_a.log ZW.EGG 0x03 -net 1501
|
||||
sleep 5
|
||||
python ../tools/btconsole.py ZW.EGG 127.0.0.1:1501 127.0.0.1:1601 > zw_relay.log 2>&1 &
|
||||
sleep 3600 # session stays up for observation
|
||||
Reference in New Issue
Block a user