Author SHA1 Message Date
CydandClaude Opus 4.8 fe49fd5eba document BT_RADAR_FLASH_RED in the generated environ.ini
The red-flash knob shipped documented in the KB and the source comment but not
in the player-facing settings file -- an inconsistency with its sibling
BT_RIO_PROTRUDE, which does carry a block there.  It is a persistent player
preference, so environ.ini is exactly where it belongs.

Placed in the cockpit section after BT_COCKPIT_TINT, written as
'#BT_RADAR_FLASH_RED=0' -- commented, showing the OFF value, since the feature
is on by default and turning it off is the action a player would take.

NB BT_LAMPTEST is deliberately NOT added: environ.ini's own contract excludes
test/debug hooks ("they would silently persist across every session").  It
stays documented in context/glass-cockpit.md and at its source.

Verified: the block reads back out of the freshly built btl4.exe verbatim.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-14 14:40:00 -05:00
CydandClaude Opus 4.8 2f9c1146a3 red radar: a FLASHING radar button goes red instead of yellow
Player request.  The radar's buttons are the yellow class, so an alerting lamp
pulsed yellow among yellows -- a brightness change only, which is the night-16
miss that already produced the #172 alert ring and the protrusion bonus.  The
bright colour of a FLASHING radar button now becomes the house red
(230,70,70 -- the MFD family), so an alert reads as a COLOUR change.

Only the bright phase moves: dim and off keep the yellow family, so a radar
button that is not alerting looks exactly as before.  Flashing is bits 0-1 of
the lamp word (0 = solid), i.e. the pod's own way of saying alert -- no new
state, just a different colour for the state it already had.

ONE decode, BTRadarLampBright(lampState) in L4VB16.h beside BTLampBrightnessOf,
consumed by all THREE desktop renderers -- CkLampColors (surround), PaintGlass
(exploded windows) and L4PADPANEL -- so they cannot drift apart the way the
button GEOMETRY did before L4RIOBANK.  BT_RADAR_FLASH_RED=0 restores the yellow
bright.

GLASS-ONLY DEVIATION (#154-class): the pod's buttons are single-colour backlit
hardware and cannot change colour.  This lives entirely in the three desktop
renderers; the serial RIO lamp path is untouched, so a real pod is unaffected
by construction.

Also adds the bench hook this needed: BT_LAMPTEST=<addr>[,<state>] forces one
lamp's state at PadRIO::GetLampState -- the single read point all three
renderers share -- so lamp rendering can be checked without inducing the fault
that would raise it.  Default 0x33 is the Panic lamp's alert shape (flashFast +
state1Off + state2Bright).

Verified [T2] by pixel tally of the radar window with BT_LAMPTEST=0x1b
(GeneratorB's lamp, the night-16 one): 620 house-red px with the feature on, 0
with BT_RADAR_FLASH_RED=0, and the radar-yellow count falling by exactly that
many (2820 -> 2196).  Screenshot: the one flashing lamp is red, every other
radar button still yellow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-14 14:36:31 -05:00
Joe DiPrimaandClaude Fable 5 ccfa875b65 handout correction (#151): my 'expect ~zero on eject' line RETRACTED -- the ticket's own 2026-08-10 bench decode (unread in yesterday's body-only triage, the exact failure the new read-ticket-threads memory records) proves -499 is the machine's arithmetic: suicide (-CalcKillScore ~999) + death cost (-500) from 1000, three ejects benched, never doubled, #162 uninvolved. Entry rewritten as the correction + the restored design call (authentic ~-1500 swing vs house-rule); counts 16 verify / 3 design calls. Tracker #151 comment 1848 carries the retraction; #104 comment 1850 holds the NARC rename (the 360dps receipts say the label may be truthful about the round profile).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bw71WVsccjwW7uKRg4aWD
2026-08-14 13:39:23 -05:00
8 changed files with 135 additions and 19 deletions
+22
View File
@@ -115,6 +115,28 @@ each, so they cover the foot band too, and the hit test takes the first match
what keeps 0x16/0x17/0x1F/0x1E reachable. That class of bug is why the verification below tests
first-hit reachability, not mere presence.
**A FLASHING radar button goes RED — `BT_RADAR_FLASH_RED` (2026-08-14, player request)
[T2 pixel-measured]. GLASS-ONLY DEVIATION (#154-class).** The radar's buttons are the yellow
class, so an alerting lamp pulsed *yellow among yellows* — a brightness change only, and the
night-16 miss that also produced the #172 ring and the protrusion bonus. The three desktop
renderers now swap the **bright** colour of a **flashing** radar button to the house red
(230,70,70 — the MFD family), so an alert reads as a *colour* change. Only the bright phase
moves; dim/off keep the yellow family, so a non-alerting radar button is unchanged. One
decode, `BTRadarLampBright(lampState)` in `L4VB16.h` beside `BTLampBrightnessOf`, consumed by
all three renderers (`CkLampColors` in the surround, `PaintGlass` in the exploded windows,
`L4PADPANEL`) so they cannot drift — the lesson of the L4RIOBANK geometry split. `=0` restores
the yellow bright. The pod's own buttons are single-colour backlit hardware and cannot do this;
the serial RIO lamp path is untouched, so this is desktop-only by construction.
**Bench hook `BT_LAMPTEST=<addr>[,<state>]` (2026-08-14).** Forces ONE lamp's state at
`PadRIO::GetLampState` — the single read point all three desktop renderers share — so lamp
rendering can be checked without inducing the fault that would raise it (a generator trip, an
ammo alarm). Default state `0x33` = the Panic lamp's alert shape (flashFast + state1Off +
state2Bright, a hard dark/bright pulse); addresses and states take `0x` hex. This is how the
red-flash change above was verified: `BT_LAMPTEST=0x1b` (GeneratorB's radar lamp, the night-16
one) then a pixel tally of the radar window — **620 house-red px with the feature on, 0 with
`BT_RADAR_FLASH_RED=0`**, and the yellow count falling by exactly that many (2820 → 2196).
## Sticky window placement — BT_GLASS_LAYOUT (2026-07-28) [T2 round-trip-verified]
The `BT_GLASS_PANELS` windows self-place in a pod-faithful ring around the main window
+11 -8
View File
@@ -72,13 +72,16 @@ A. FIXED THIS BUILD -- PLEASE VERIFY (headliners first)
The Nova spawned showing its REAR laser's range pips in the forward
view. The HUD now commits the forward view at spawn. (Only the pips
were wrong -- rear weapons never actually fired forward.)
#151 (Oracle) Panic eject scored -499
Solved, and the machine agrees with YOUR math: eject = your mech
self-destructs (scored as self-damage, ~-500) + the death cost
(-500) = about -1000, i.e. 1000 points -> roughly ZERO. The extra
-500 you saw was the #162 double-death bug, fixed on testing night.
TEST: repeat the maneuver -- you should land within a few points
of zero, not hundreds below.
#151 (Oracle) Panic eject scored -499 -- CORRECTION: -499 IS the machine
Our line here was wrong (we mis-read our own ticket history; the
correct decode was already on the ticket). Bench-verified: eject
is scored as SUICIDE (about -999, the kill value of your own
mech) PLUS the death cost (-500). 1000 - 999 - 500 = -499
exactly -- the original's own arithmetic, reproduced three times
on the bench, never doubled. If you eject tonight and land at
-499 again, the machine is RIGHT, not broken.
DESIGN CALL (restored): keep the authentic ~-1500 swing, or
house-rule a flat eject cost? Opinions to the thread.
FEEL Three more fixes on the original's clock (same bug class as #173):
the cockpit HIT-SHAKE (was bouncing ~2x too fast -- hits now rock
you at the pod's pace with less rebound), the FOOTSTEP loudness
@@ -200,7 +203,7 @@ G. INTERNAL ENGINEERING BACKLOG (nothing to test)
=============================================================================
End of list. 57 open issues total:
17 verify (3 headliners), 12 reproduce, 6 era questions, 2 design calls,
16 verify (3 headliners), 12 reproduce, 6 era questions, 3 design calls,
10 known gaps, 11 internal -- plus 4 "not bugs" that are the real machine.
Since Wednesday: 15 fixes fielded, 4 tickets closed by evidence alone, and
Oracle's questionnaire + soundboard find settled five more. Your reports
+10 -3
View File
@@ -1472,14 +1472,21 @@ static void
const GButton &b = w->buttons[i];
const RECT &r = b.rect;
int held = (b.address == pressedAddress) || latched[b.address & 0x7F];
int shade = LampBrightnessOf(PadRIO::GetLampState(b.address), tick);
int lampState = PadRIO::GetLampState(b.address);
int shade = LampBrightnessOf(lampState, tick);
if (held)
shade = 3;
// A FLASHING radar button goes RED at its bright phase (L4VB16.h).
unsigned long radarBright = BTRadarLampBright(lampState);
COLORREF radarBrightRGB = RGB((radarBright >> 16) & 0xFF,
(radarBright >> 8) & 0xFF,
radarBright & 0xFF);
COLORREF fill, text_color;
if (b.color == ClrYellow)
{
fill = (shade == 3) ? RGB(245, 210, 60)
fill = (shade == 3) ? radarBrightRGB
: (shade != 0) ? RGB(140, 118, 38)
: RGB(70, 60, 24);
text_color = RGB(0, 0, 0);
@@ -1501,7 +1508,7 @@ static void
// Solid lamp fill + a bright border. Under the imagery, only the protruding
// edge shows once the surface is blitted on top.
{
COLORREF bright = (b.color == ClrYellow) ? RGB(245, 210, 60)
COLORREF bright = (b.color == ClrYellow) ? radarBrightRGB
: (b.color == ClrBlue) ? RGB(205, 228, 255)
: RGB(230, 70, 70);
HBRUSH face = CreateSolidBrush(fill);
+9 -2
View File
@@ -290,14 +290,21 @@ static void
// commanded lamp state (with flash phase) decides.
//
int shade = 0;
int lampState = 0;
if (lamp_capable)
{
shade = LampBrightnessOf(PadRIO::GetLampState(cell.address), tick);
lampState = PadRIO::GetLampState(cell.address);
shade = LampBrightnessOf(lampState, tick);
}
if (held)
{
shade = 3;
}
// A FLASHING radar/Sec button goes RED at its bright phase (L4VB16.h).
unsigned long radarBright = BTRadarLampBright(lampState);
COLORREF radarBrightRGB = RGB((radarBright >> 16) & 0xFF,
(radarBright >> 8) & 0xFF,
radarBright & 0xFF);
COLORREF fill;
COLORREF text_color;
@@ -308,7 +315,7 @@ static void
}
else if (yellow)
{
fill = (shade == 3) ? RGB(245, 210, 60)
fill = (shade == 3) ? radarBrightRGB
: (shade != 0) ? RGB(140, 118, 38)
: RGB(70, 60, 24);
text_color = RGB(0, 0, 0);
+24
View File
@@ -1282,6 +1282,30 @@ int BTPadRIOActive(void)
int
PadRIO::GetLampState(int unit)
{
//
// BENCH HOOK (2026-08-14): BT_LAMPTEST=<addr>[,<state>] forces ONE lamp's
// state, so the desktop lamp rendering can be checked without inducing the
// fault that would raise it (a generator trip, an ammo alarm, ...). The
// default state is the alert shape the Panic lamp uses -- flashFast +
// state1Off + state2Bright (0x33), a hard dark/bright pulse. Addresses and
// states take 0x hex. Read once; every desktop renderer reads its lamps
// through here, so one hook covers the surround, the exploded windows and
// the pad panel alike.
//
static int s_testAddr = -2;
static int s_testState = 0x33;
if (s_testAddr == -2)
{
s_testAddr = -1;
const char *e = getenv("BT_LAMPTEST");
if (e != NULL)
sscanf(e, "%i,%i", &s_testAddr, &s_testState);
}
if (s_testAddr >= 0 && unit == s_testAddr)
{
return s_testState;
}
if (activeInstance == NULL || unit < 0 || unit >= LampCount)
{
return 0;
+11 -6
View File
@@ -1028,12 +1028,17 @@ static void CkFill(LPDIRECT3DDEVICE9 dev, int x, int y, int w, int h, D3DCOLOR c
}
// Lamp fill + border for a button, from the glass PaintGlass color ramps.
static void CkLampColors(int colorClass, int shade, int inert, D3DCOLOR *fill, D3DCOLOR *border)
static void CkLampColors(int colorClass, int shade, int inert, D3DCOLOR *fill, D3DCOLOR *border,
int lampState = 0)
{
if (colorClass == 1) // yellow (radar)
if (colorClass == 1) // yellow (radar) -- RED while flashing (see L4VB16.h)
{
*border = D3DCOLOR_XRGB(245, 210, 60);
*fill = (shade == 3) ? D3DCOLOR_XRGB(245, 210, 60)
unsigned long bright = BTRadarLampBright(lampState);
D3DCOLOR brightC = D3DCOLOR_XRGB((int)((bright >> 16) & 0xFF),
(int)((bright >> 8) & 0xFF),
(int)( bright & 0xFF));
*border = brightC;
*fill = (shade == 3) ? brightC
: (shade != 0) ? D3DCOLOR_XRGB(140, 118, 38)
: D3DCOLOR_XRGB(70, 60, 24);
}
@@ -1218,7 +1223,7 @@ void BTDrawCockpitPanels(LPDIRECT3DDEVICE9 device)
int shade = BTLampBrightnessOf(state, tick);
if (shade < 2) continue; // dark half-cycle: no ring
D3DCOLOR fill, border;
CkLampColors(b.colorClass, 3 /*bright*/, b.inert, &fill, &border);
CkLampColors(b.colorClass, 3 /*bright*/, b.inert, &fill, &border, state);
int rx = b.x - kRingGap - kRingWidth;
int ry = b.y - kRingGap - kRingWidth;
int rw = b.w + 2 * (kRingGap + kRingWidth);
@@ -1239,7 +1244,7 @@ void BTDrawCockpitPanels(LPDIRECT3DDEVICE9 device)
int shade = BTLampBrightnessOf(state, tick);
if (gCkPressed == b.address || gCkLatched[b.address & 0x7F]) shade = 3;
D3DCOLOR fill, border;
CkLampColors(b.colorClass, shade, b.inert, &fill, &border);
CkLampColors(b.colorClass, shade, b.inert, &fill, &border, state);
CkFill(device, b.x, b.y, b.w, b.h, border);
CkFill(device, b.x + 1, b.y + 1, b.w - 2, b.h - 2, fill);
+40
View File
@@ -110,6 +110,46 @@ inline int BTLampBrightnessOf(int state, unsigned long tick)
return ((tick / half) & 1) ? level2 : level1;
}
//
// Is this lamp FLASHING rather than solid? Bits 0-1 of the wire word are the
// flash mode (0 = solid, 1/2/3 = slow/med/fast), so any non-zero value means
// the lamp is pulsing -- which is the pod's own way of saying ALERT.
//
// RADAR FLASH = RED (2026-08-14, player request; GLASS-ONLY DEVIATION). The
// radar's buttons are the yellow class, and a yellow lamp pulsing among other
// yellow lamps is easy to miss -- the night-16 miss that also produced the
// #172 ring and the protrusion bonus. The desktop renderers therefore swap
// the BRIGHT colour of a FLASHING radar button to the red family, so an alert
// reads as a colour change and not just a brightness change. The pod's own
// buttons are physical bicolour-less lamps and cannot do this, so it is a
// desktop affordance only -- and it is confined to the three desktop
// renderers (surround, exploded windows, pad panel); the serial RIO lamp
// path is untouched. BT_RADAR_FLASH_RED=0 restores the yellow bright.
//
inline int BTLampIsFlashing(int state)
{
return (state & 0x3) != 0;
}
//
// The bright colour a radar (yellow-class) button should use right now: the
// red family while the lamp is flashing, its own yellow otherwise. ONE
// definition, consumed by all three desktop renderers so they cannot drift
// (the lesson of the L4RIOBANK geometry split). Returns 0x00RRGGBB.
//
inline unsigned long BTRadarLampBright(int lampState)
{
static int enabled = -1;
if (enabled < 0)
{
const char *e = getenv("BT_RADAR_FLASH_RED");
enabled = (e != 0 && e[0] == '0') ? 0 : 1; // default ON
}
return (enabled && BTLampIsFlashing(lampState))
? 0x00E64646ul // 230,70,70 -- the house red (MFD family)
: 0x00F5D23Cul; // 245,210,60 -- the radar's own yellow
}
//########################################################################
//######################### Video16BitBuffered ###########################
//########################################################################
+8
View File
@@ -394,6 +394,14 @@ static const char *kEnvironIniDefault =
"# Phosphor colour of the mono MFDs, RRGGBB. Default is a green tube.\n"
"#BT_COCKPIT_TINT=21FF42\n"
"\n"
"# A FLASHING button on the radar turns RED instead of yellow. The radar's\n"
"# buttons are all yellow, so a lamp calling for attention used to change only\n"
"# in BRIGHTNESS -- easy to miss with eleven other yellow buttons around it.\n"
"# Now the bright half of its flash is red, so an alert changes COLOUR. Only\n"
"# a flashing button is affected: a radar button doing nothing looks exactly as\n"
"# it always did. 1 = on (the default), 0 = keep the yellow.\n"
"#BT_RADAR_FLASH_RED=0\n"
"\n"
"# ---- Display ----------------------------------------------------------------\n"
"\n"
"# The cockpit is fitted into the window at ONE uniform scale, centred, with\n"