Author SHA1 Message Date
CydandClaude Opus 4.8 b14b37b13d document BT_RIO_PROTRUDE in the generated environ.ini
The button-protrusion dial shipped with no player-facing documentation -- it
lived only in the source comment and the KB, so a tester who found the buttons
too long (or wanted them longer) had no way to discover the knob.

Adds a block to the self-documenting default environ.ini, at the end of the
cockpit section beside the other display-shaping options (BT_MFD_SCALE,
BT_RADAR_SCALE, BT_RADAR_POS, BT_COCKPIT_TINT): what it does, that it is a
LONGER bar rather than a wider button (press target and imagery unchanged),
that it touches only the red MFD and yellow map buttons, the 10 default, 0 for
the original look, the 1-200 range, and the gotcha that it takes a NUMBER --
'on' parses to 0 and turns it off.

Verified by generating a fresh environ.ini from this build and reading the
block back as a player would see it.  The loader has no allowlist and refuses
only BT_JOYCONFIG, so the key applies from the file; a real env var still wins
over it, per the file's own contract.

NB the default is only written when environ.ini is ABSENT (and only beside
BTL4.RES), so existing installs keep their file and will not gain this text --
the handout/KB remain the channel for testers who already have one.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-14 13:50:20 -05:00
CydandClaude Opus 4.8 8ae74cd2f1 bigger RIO buttons: the red + yellow lamps clear the glass by +10px
Player request: more of the RIO buttons should protrude from the displays so a
FLASHING lamp is easier to notice.  BTRioBankMetricsFor now adds a flat +10px
to `strip` -- the lamp bar -- AFTER the scale; BT_RIO_PROTRUDE=<px> tunes it
and 0 restores the pre-2026-08-14 geometry.

FLAT, not scaled, deliberately: the ask is on-screen noticeability, and the
surround runs the glass at HALF scale where the strip lands on the 6px floor --
a scaled bonus would give the least help exactly where the lamps are smallest.
The floor above it already trades strict proportionality for legibility on this
field; this is the same trade, sized by the players.

Scope falls out of the geometry -- only `strip` moves, so:
  - RED MFD buttons and YELLOW radar buttons (+ the radar foot row) grow;
  - they grow OUTWARD ONLY (the layout anchors the inboard edge), so
    under-glass depth, button WIDTH and every press target are unchanged --
    this is a LONGER bar, not a fatter face;
  - BLUE flight cells lay out from cellW/cellH and never see it.

Verified [T2] by BT_RIOBANK_LOG A/B + surround screenshots: Heat MFD top button
y 21->11, h 126->136 with its bottom edge FIXED at 147; bank bounds 252->272
tall (all five MFDs), radar 252->272 wide; flight-bank bounds byte-identical;
no negative coordinates on any bank; imagery still wins every pixel it covers.
The exploded glass windows size their client to bank.bounds, so they simply
grow with it.

Relation to #172: the alert RING (BT_ALERT_RING, default off) answered the same
night-16 miss after a "+8px grown-face bloom" was rejected on the bench as "the
button got fat".  This is a different shape -- the lamp keeps its width and
shows more of its own bar -- so the ring stays optional.  Desktop-glass
affordance; the pod's buttons are physical and backlit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-14 13:23:17 -05:00
9 changed files with 91 additions and 133 deletions
+18 -21
View File
@@ -115,27 +115,24 @@ 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).
**Protrusion bonus — `BT_RIO_PROTRUDE` (2026-08-14, player request) [T2 receipt+screenshot].**
Players asked for more of the RIO buttons to clear the glass so a FLASHING lamp is easier to
notice. `BTRioBankMetricsFor` now adds a flat **+10px** to `strip` AFTER the scale, so the bar
reaches that much further out on every renderer; `BT_RIO_PROTRUDE=<px>` tunes it (`0` restores
the pre-2026-08-14 geometry). Deliberately FLAT, not scaled: the surround runs the glass at half
scale where the strip sits on the 6px floor — a scaled bonus would help least exactly where the
lamps are smallest — and that floor already trades proportionality for legibility. Because only
`strip` moves, this touches exactly the **red MFD** and **yellow radar** buttons (+ the radar
foot row) and grows them **outward only**: the layout anchors the inboard edge, so under-glass
depth, button WIDTH and the press targets are unchanged. The **blue flight cells** are laid out
from `cellW/cellH` and never see it (receipt: their bank bounds are byte-identical). Verified by
`BT_RIOBANK_LOG` A/B — e.g. Heat MFD top button `y 21→11, h 126→136` with its bottom edge fixed
at 147, bank bounds `252→272` tall, no negative coordinates — plus a surround screenshot pair.
Relation to **#172**: the alert RING (`BT_ALERT_RING`, default off) answered the same night-16
complaint after a *"+8px grown-face bloom"* was rejected on the bench as "the button got fat";
this is a different shape — the lamp keeps its width and simply shows more of its own bar — so
the ring stays optional. Desktop-glass affordance only; the pod's buttons are physical and
backlit and never had this problem.
## Sticky window placement — BT_GLASS_LAYOUT (2026-07-28) [T2 round-trip-verified]
+8 -11
View File
@@ -72,16 +72,13 @@ 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 -- 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.
#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.
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
@@ -203,7 +200,7 @@ G. INTERNAL ENGINEERING BACKLOG (nothing to test)
=============================================================================
End of list. 57 open issues total:
16 verify (3 headliners), 12 reproduce, 6 era questions, 3 design calls,
17 verify (3 headliners), 12 reproduce, 6 era questions, 2 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
+3 -10
View File
@@ -1472,21 +1472,14 @@ static void
const GButton &b = w->buttons[i];
const RECT &r = b.rect;
int held = (b.address == pressedAddress) || latched[b.address & 0x7F];
int lampState = PadRIO::GetLampState(b.address);
int shade = LampBrightnessOf(lampState, tick);
int shade = LampBrightnessOf(PadRIO::GetLampState(b.address), 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) ? radarBrightRGB
fill = (shade == 3) ? RGB(245, 210, 60)
: (shade != 0) ? RGB(140, 118, 38)
: RGB(70, 60, 24);
text_color = RGB(0, 0, 0);
@@ -1508,7 +1501,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) ? radarBrightRGB
COLORREF bright = (b.color == ClrYellow) ? RGB(245, 210, 60)
: (b.color == ClrBlue) ? RGB(205, 228, 255)
: RGB(230, 70, 70);
HBRUSH face = CreateSolidBrush(fill);
+2 -9
View File
@@ -290,21 +290,14 @@ static void
// commanded lamp state (with flash phase) decides.
//
int shade = 0;
int lampState = 0;
if (lamp_capable)
{
lampState = PadRIO::GetLampState(cell.address);
shade = LampBrightnessOf(lampState, tick);
shade = LampBrightnessOf(PadRIO::GetLampState(cell.address), 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;
@@ -315,7 +308,7 @@ static void
}
else if (yellow)
{
fill = (shade == 3) ? radarBrightRGB
fill = (shade == 3) ? RGB(245, 210, 60)
: (shade != 0) ? RGB(140, 118, 38)
: RGB(70, 60, 24);
text_color = RGB(0, 0, 0);
-24
View File
@@ -1282,30 +1282,6 @@ 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;
+41
View File
@@ -25,6 +25,46 @@ namespace
const int minimumStrip = 6;
const int defaultGap = 4;
//-------------------------------------------------------------------
// PROTRUSION BONUS (2026-08-14, player request). Flat pixels added to
// the lamp strip AFTER the scale, so the visible bar reaches this much
// further out of the glass on EVERY renderer.
//
// WHY FLAT, not scaled: the ask is on-screen noticeability of a
// FLASHING lamp, and the surround runs the glass at half scale, where
// the strip lands on the `minimumStrip` floor (~6px) -- a scaled bonus
// would give the surround half the help exactly where the lamps are
// smallest. The floor above already establishes legibility over strict
// proportionality for this field; this is the same trade, sized by the
// players. It is a DESKTOP-GLASS affordance: the pod's buttons are
// physical and backlit and have never had this problem.
//
// Scope: only the strip -- so only the RED MFD buttons and the YELLOW
// radar buttons/foot row grow, and they grow OUTWARD ONLY (the layout
// anchors the inboard edge; under-glass depth is unchanged). The BLUE
// flight cells are laid out from cellW/cellH and never see this.
//
// Relation to #172: the alert RING (BT_ALERT_RING, default off) was the
// answer to the same night-16 complaint after a "+8px grown-face bloom"
// was rejected on the bench as "the button got fat". This is a
// different shape -- the lamp keeps its width and simply shows more of
// its own bar -- and it is unconditional, so the ring stays optional.
//-------------------------------------------------------------------
const int defaultProtrude = 10;
int ProtrudeBonus()
{
static int cached = -1;
if (cached < 0)
{
const char *e = getenv("BT_RIO_PROTRUDE"); // tune by eye; 0 = pre-2026-08-14
cached = (e != 0) ? atoi(e) : defaultProtrude;
if (cached < 0) cached = 0;
if (cached > 200) cached = 200;
}
return cached;
}
//-------------------------------------------------------------------
// Per-column horizontal nudge for the 4 MFD buttons, left->right, so
// they line up with the (unevenly spaced) DISPLAY / PROGRAM / ...
@@ -111,6 +151,7 @@ void
int strip = Scaled(nativeStrip, shortAxis, nativeShortAxis);
if (strip < minimumStrip) strip = minimumStrip;
strip += ProtrudeBonus(); // player-requested reach (see above)
out->strip = strip;
out->gap = defaultGap;
+6 -11
View File
@@ -1028,17 +1028,12 @@ 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,
int lampState = 0)
static void CkLampColors(int colorClass, int shade, int inert, D3DCOLOR *fill, D3DCOLOR *border)
{
if (colorClass == 1) // yellow (radar) -- RED while flashing (see L4VB16.h)
if (colorClass == 1) // yellow (radar)
{
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
*border = D3DCOLOR_XRGB(245, 210, 60);
*fill = (shade == 3) ? D3DCOLOR_XRGB(245, 210, 60)
: (shade != 0) ? D3DCOLOR_XRGB(140, 118, 38)
: D3DCOLOR_XRGB(70, 60, 24);
}
@@ -1223,7 +1218,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, state);
CkLampColors(b.colorClass, 3 /*bright*/, b.inert, &fill, &border);
int rx = b.x - kRingGap - kRingWidth;
int ry = b.y - kRingGap - kRingWidth;
int rw = b.w + 2 * (kRingGap + kRingWidth);
@@ -1244,7 +1239,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, state);
CkLampColors(b.colorClass, shade, b.inert, &fill, &border);
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,46 +110,6 @@ 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 ###########################
//########################################################################
+13 -7
View File
@@ -394,13 +394,19 @@ 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"
"# How far the lit RIO buttons reach out past the edge of a display, in pixels.\n"
"# The pod's buttons were physical and backlit; on glass they are a thin bar\n"
"# along the display edge, and a FLASHING one is easy to miss. This is how much\n"
"# more of that bar shows -- a LONGER bar, not a wider button: the button keeps\n"
"# its width, the display picture still covers everything it did before, and the\n"
"# whole display stays clickable. Red (MFD) and yellow (map) buttons only; the\n"
"# blue flight block has no glass to hide behind, so it never changes.\n"
"# 10 the default\n"
"# 0 back to the original thin bar\n"
"# 1-200 anything in between\n"
"# Give it a NUMBER -- a word like 'on' counts as 0 and turns it off. In the\n"
"# exploded view (BT_GLASS_PANELS) the windows grow to fit the longer buttons.\n"
"#BT_RIO_PROTRUDE=10\n"
"\n"
"# ---- Display ----------------------------------------------------------------\n"
"\n"