#142 crouch: duckState is a THREE-state posture -- the strip is an animation

Operator confirmed on screen: bduck.pcc is a real duck ANIMATION, and stepping
duckState 0->1->2 plays it.  So the attribute is not a flag:

    0 = standing        1 = moving between        2 = crouched

Everything else was already right -- asset, element (OneOfSeveralPixInt
@004c5204), factory registration, L4GAUGE.CFG:5001, and the attribute binding
(new [gauge] receipt confirms 'bduck.pcc' frames=3x1 attr=BOUND).  We were
writing a two-value flag into a three-frame strip, so frame 2 was unreachable
and the cockpit saw a snap: "it lights up and sticks, no animation".

The handler is back to the binary's exact write (duckState = 1, @0049fa00).
That value now MEANS the middle frame, so the press gives immediate visual
feedback and the earlier toggle divergence is retired.

Needed a separate duckRequest cell, which I tried twice to avoid:
  * duckState cannot be both the request and the display.  Settling it to the
    real posture destroys the request, so on the frame the squat clip parked
    the consumer read "crouched + pending" and issued the opposite direction --
    69 transitions from 2 presses, benched, twice.
  * reading the CACHED legAnimationState instead of the alarm made it worse:
    the cache refreshes only at the top of AdvanceLegAnimation, so right after
    SetLegAnimation it still reads the old state.  Read the alarm.
duckRequest is port-only, appended, never read by offset.

Also fixes a silent failure in the gauge factory: the missing-image path used
DebugStream -- the no-op ReconStream (project gotcha) -- so a strip that failed
to load reported NOTHING.  Now DEBUG_STREAM, plus an ungated one-line receipt
per element naming the image, frame grid, port and whether the attribute BOUND
or came back NULL.  That receipt is what proved the element was healthy and
sent me looking at the value instead of the plumbing.

Benched (crouch142.sh, madcat): 2 presses -> exactly 2 transitions,
SQUAT -> parked (settles to 2) then RISE (settles to 0).  Refusal while moving
still holds (posture=0, authentic per Lynx).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NCJQkvq6G2JNrpVbA75tVZ
This commit is contained in:
Joe DiPrima
2026-08-07 23:35:37 -05:00
co-authored by Claude Opus 5
parent fcd1a0ca8d
commit 03c4d55672
4 changed files with 95 additions and 48 deletions
+18 -1
View File
@@ -1744,10 +1744,27 @@ Logical
L4Warehouse *warehouse = (L4Warehouse *)gauge_renderer->warehousePointer;
if (warehouse->pixelMap8Bin.Get(p[2].data.string) == NULL) // FUN_00442d2b
{
DebugStream << "OneOfSeveralPixInt: Missing image '" << p[2].data.string << "'\n";
// WAS DebugStream -- the no-op ReconStream (gotcha: use DEBUG_STREAM).
// A missing strip therefore failed COMPLETELY SILENTLY, which is
// exactly the state #142 was stuck in: the crouch symbol never drew and
// nothing anywhere said why.
DEBUG_STREAM << "[gauge] oneOfSeveralPixInt: MISSING IMAGE '"
<< p[2].data.string << "' -- element not created\n" << std::flush;
return False;
}
warehouse->pixelMap8Bin.Release(p[2].data.string); // FUN_00442e51
// #142 receipt (ungated, one line per element): does this strip exist, and
// did its integer attribute actually RESOLVE? A NULL attributePointer
// leaves the connection reading nothing, so the strip pins to frame 0 and
// looks like "no animation at all" -- indistinguishable, from outside, from
// a missing image or an unbuilt page.
DEBUG_STREAM << "[gauge] oneOfSeveralPixInt '" << p[2].data.string
<< "' frames=" << p[3].data.integer << "x" << p[4].data.integer
<< " port=" << display_port_index
<< " at(" << position.x << "," << position.y << ")"
<< " attr=" << (p[5].data.attributePointer != 0 ? "BOUND" : "NULL !!")
<< "\n" << std::flush;
return True;
}