From fadc0d6d3320c5355bd6e54290f5541a62346160 Mon Sep 17 00:00:00 2001 From: James Dansereau <106631954+jkdansereau@users.noreply.github.com> Date: Tue, 6 Oct 2026 21:20:22 -0400 Subject: [PATCH] F10: dropdown popup stays on screen (D568); Crosshair color is Original/Custom with 0-255 sliders, PD style (D569) --- docs/dev/findings-index.csv | 2 ++ docs/dev/findings.md | 28 ++++++++++++++++++++++++++++ port/src/optionsoverlay.c | 26 ++++++++++++++++---------- port/src/video.c | 32 +++++++++++++++++++++----------- 4 files changed, 67 insertions(+), 21 deletions(-) diff --git a/docs/dev/findings-index.csv b/docs/dev/findings-index.csv index c827c62d..9946cff5 100644 --- a/docs/dev/findings-index.csv +++ b/docs/dev/findings-index.csv @@ -310,6 +310,8 @@ D564,FIXED,"F10: game's own ""Look up/down"" row removed (dead for mouse and cen D565,FIXED,AI awareness followed two player render settings:,FIXED 2026-10-06 (maintainer decision: D566,FIXED,Steam Deck Game Mode showed the on-screen keyboard at every launch (SDL text input left on) —,FIXED 2026-10-06 (port only: D567,FIXED,Front-end PC Options with a pad pulled the game's crosshair to the top-left (overlay synced the cursor to the untouched OS mouse) —,FIXED 2026-10-06 (port only: +D568,FIXED,F10 dropdown popup drawn empty and misplaced for a long list on a mid-page row (negative top) —,FIXED 2026-10-06 (port only: +D569,?,Crosshair color follows the PD port:,CHANGED 2026-10-06 (maintainer request; old presets migrate to Custom RGB) D407,CLOSED,Tanks cannot be boarded/exited on PC —,CLOSED (2026-09-28 bookkeeping: D408,FIXED,Game.SkipIntro skips the post-mission failure dossier:,FIXED 2026-09-30 (SkipIntro hook gated to first boot; live dossier check owed). D415,FIXED,"Shooting a light fixture does not ""kill"" its flickering light (Bunker, Caverns):",FIXED (2026-09-29 bookkeeping: diff --git a/docs/dev/findings.md b/docs/dev/findings.md index eb5357be..2e173814 100644 --- a/docs/dev/findings.md +++ b/docs/dev/findings.md @@ -718,6 +718,8 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121). | D565 | **AI awareness followed two player render settings: Fog distance below 100 (shortened clip) and FOV (gameplay fog cull scaled by the rendered FOV)** — full `## D565` entry at file tail | FIXED 2026-10-06 (maintainer decision: Fog distance floor 100 in `video.c` + overlay; `propobj.c portSub7F054C58Gameplay` rescaled to the game's own FOV, PORT-only D466 helper; identity at defaults; build-verified) | | D566 | **Steam Deck Game Mode showed the on-screen keyboard at every launch (SDL text input left on)** — full `## D566` entry at file tail | FIXED 2026-10-06 (port only: `gfx_sdl2.cpp` SDL_ENABLE_SCREEN_KEYBOARD=0 + SDL_StopTextInput; build-verified Win/Linux; Deck Game Mode check owed) | | D567 | **Front-end PC Options with a pad pulled the game's crosshair to the top-left (overlay synced the cursor to the untouched OS mouse)** — full `## D567` entry at file tail | FIXED 2026-10-06 (port only: sync gated on `optionsOverlayMouseActive()`; build-verified Win/Linux; Deck pad check owed) | +| D568 | **F10 dropdown popup drawn empty and misplaced for a long list on a mid-page row (negative top)** — full `## D568` entry at file tail | FIXED 2026-10-06 (port only: `ddGeom` keeps the popup on screen; 1280x800 before/after capture) | +| D569 | **Crosshair color follows the PD port: Original or Custom RGB, left/right stepper, 0-255 sliders** — full `## D569` entry at file tail | CHANGED 2026-10-06 (maintainer request; old presets migrate to Custom RGB) | | D407 | **Tanks cannot be boarded/exited on PC — the v0.4.0 use/reload split (D378/D393) removed the B-button tap the engine's tank handlers in `bondview2.c` consume (user report 2026-09-28, Runway/Streets)** — full `## D407` entry at file tail | **CLOSED (2026-09-28 bookkeeping: tank board/exit accepted by the user; shipped in v0.4.0).** Earlier: PARTIAL (fix landed in v0.4.0, port-only): present `GE_CONT_B` on the use (E / pad A) rising edge only while `g_PlayerIsInTank == 1` or `g_BondCanEnterTank != 0`; E keeps its D378 no-reload-fallback semantics elsewhere, N64 layout unaffected. D407(b) same cycle: front PC Options page-edge highlight clamp + mouse-wheel / W-S paging (wheel queue consumed on the menu, D223); its wheel mapping shipped inverted and was fixed to match W/S (wheel up = step up). D407(c): board-animation lockout, menu-accept B gate in tank states, in-tank aim routed through the legacy velocity stick + `Input.TankAimScale` knob. RESOLVED 2026-09-28: all port-only (src/game zero-diff), 10 TANKDBG probes stripped, release binary verified clean, user live tank drive signed off (board + exit OK, aim feel good). | | D408 | **`Game.SkipIntro` skips the post-mission failure dossier: with it on, entering a level then aborting (watch Z+A) or dying (KIA) returns straight to the menus — no REPORT / "Mission status: KILLED IN ACTION / ABORTED" screen** (user report 2026-09-28; save/AllUnlocked ruled out) — full `## D408` entry at file tail | FIXED 2026-09-30 (SkipIntro hook gated to first boot; live dossier check owed). | | D415 | **Shooting a light fixture does not "kill" its flickering light (Bunker, Caverns): the fixture takes the hit but the flicker keeps going (community report, issue #87 comment by the reporter, 2026-09-28, 00 Agent playthrough of v0.4.0).** — full `## D415` entry at file tail | FIXED (2026-09-29 bookkeeping: root-caused and fixed as D430 + D431, user-verified vs GEPD/1964 on Caverns 2026-09-29; #119). Earlier: ROOT-CAUSED as D430 (see there); fix in tree, live check owed. | @@ -18285,3 +18287,29 @@ starts at 0 on open and becomes 1 on a mouse move or click; new accessor users get the same tracking as before. **Verify:** builds on Windows and Linux (X220); deployed to the Deck play folder 2026-10-06 21:03; maintainer pad check owed (open PC Options from file select with the pad, the crosshair stays put). + +## D568: F10 dropdown popup drawn empty and misplaced for a long list on a mid-page row — FIXED 2026-10-06 (port only) + +**Report (maintainer, Deck, 2026-10-06):** the Crosshair color dropdown opened +as an empty box with its items drawn too high. **Cause:** `optionsoverlay.c +ddGeom` opens the popup below the row, or above it when there is no room below; +with a 9-item list on a row in the middle of a scrolled page neither fits, and +the upward top went negative. The labels then drew above the screen while the +fill (negative top) ran from the row down past the bottom edge. Reproduced on +Windows at 1280x800 (Game page scrolled to Crosshair style, Custom colour), so +not Deck-specific. **Fix:** if the top is still off screen, the popup is placed +flush with the bottom margin (it always fits: at most 9 rows). Applies to every +dropdown. Verified by a 1280x800 in-level capture before/after. + +## D569: Crosshair color follows the PD port: Original or Custom RGB, left/right stepper — CHANGED 2026-10-06 (maintainer request) + +The row was a 9-entry dropdown of named presets (Green, Red, Blue, Yellow, Cyan, +Magenta, White) plus Custom, with the Custom R/G/B sliders shown as percentages +and moving one unit per press. The PD port has no presets: a colour page with +0-255 sliders. GE keeps **Original** (the authored red sprite, drawn untouched, +which no tint reproduces) and **Custom** (stored 8, the existing silhouette tint +path). The row is now a left/right (or A) stepper with no popup; Red/Green/Blue +show 0-255 and step by 5; the existing value swatch is the live preview; new tip. +**Migration (`video.c videoInit`):** an ini holding a former preset 1..7 becomes +Custom with that preset's RGB, so no saved colour changes (checked: 3 -> 8 with +64/64/255). Display-mode presets and resets still use 0 (Original). diff --git a/port/src/optionsoverlay.c b/port/src/optionsoverlay.c index 8103ba22..6c566384 100644 --- a/port/src/optionsoverlay.c +++ b/port/src/optionsoverlay.c @@ -413,9 +413,9 @@ static struct Row rows[] = { SEP(G2), { .key="Video.CrosshairHide", .label="Show crosshair", .kind=ROW_TOGGLE, .step=1, .names=kOnOffRev }, { .key="Video.CrosshairColor", .label="Crosshair color", .kind=ROW_ENUM, .step=1, .names=kCrosshairColor }, - { .key="Video.CrosshairRed", .label="Red", .kind=ROW_SLIDER, .step=1, .shownWhen="Video.CrosshairColor", .shownValue=8 }, - { .key="Video.CrosshairGreen", .label="Green", .kind=ROW_SLIDER, .step=1, .shownWhen="Video.CrosshairColor", .shownValue=8 }, - { .key="Video.CrosshairBlue", .label="Blue", .kind=ROW_SLIDER, .step=1, .shownWhen="Video.CrosshairColor", .shownValue=8 }, + { .key="Video.CrosshairRed", .label="Red", .kind=ROW_SLIDER, .step=5, .shownWhen="Video.CrosshairColor", .shownValue=8 }, + { .key="Video.CrosshairGreen", .label="Green", .kind=ROW_SLIDER, .step=5, .shownWhen="Video.CrosshairColor", .shownValue=8 }, + { .key="Video.CrosshairBlue", .label="Blue", .kind=ROW_SLIDER, .step=5, .shownWhen="Video.CrosshairColor", .shownValue=8 }, { .key="Video.CrosshairSize", .label="Crosshair size", .kind=ROW_SLIDER, .step=5, .unit="%" }, { .key="Video.CrosshairStyle", .label="Crosshair style", .kind=ROW_ENUM, .step=1, .names=kCrosshairStyle }, { .key="Video.CrosshairAlpha", .label="Crosshair opacity", .kind=ROW_SLIDER, .step=5, .unit="%" }, /* D511 */ @@ -1630,6 +1630,12 @@ static void rowAdjust(struct Row *r, int dir) rowSetStepWatch(r, (double)inputPadPresetStep((int)lround(v), dir)); break; } + if (!strcmp(r->key, "Video.CrosshairColor")) { + /* D569 (PD model): Original sprite or a Custom RGB colour; the old + * named presets (1..7) are migrated to Custom at startup (video.c). */ + rowSetStepWatch(r, (int)lround(v) == 8 ? 0.0 : 8.0); + break; + } if (!strcmp(r->key, "Video.TextureFilter")) { /* D499: menu order Nearest, Bilinear, Trilinear, 3-Point (stored * 0, 1, 3, 2: 2 stays 3-Point for existing inis and the Original @@ -1763,6 +1769,7 @@ static char s_ddLab[DD_MAX][40]; static int rowIsDropdown(const struct Row *r) { if (!r->found) return 0; + if (r->kind == ROW_ENUM && !strcmp(r->key, "Video.CrosshairColor")) return 0; /* D569: Original/Custom stepper (PD) */ if (r->kind == ROW_ENUM || r->kind == ROW_MSAA || r->kind == ROW_FPSCAP) return 1; if (r->kind == ROW_RES) return !videoIsFullscreen() && s_resFitN > 0; if (r->kind == ROW_AUDIODEV) return 1; @@ -1906,6 +1913,11 @@ static int ddGeom(s32 *x0, s32 *y0, s32 *x1, s32 *y1, int *vis) s32 H = ovH(); *y0 = rowY + OV_LINE; if (*y0 + h > H - 4) *y0 = rowY - h; /* no room below: open upward */ + /* D568: no room above either (a long list on a mid-page row): keep the whole + * popup on screen, flush with the bottom margin. A negative top used to + * draw the labels above the screen while the fill wrapped down past the + * bottom edge (an empty, misplaced box). */ + if (*y0 < 4) *y0 = (H - 4 - h > 4) ? H - 4 - h : 4; *y1 = *y0 + h; *vis = v; return 1; @@ -2947,13 +2959,6 @@ static void valueText(int i, char *out, int n) snprintf(out, n, "%sx", t); return; } - /* D506: crosshair RGB channels as a percent of full intensity. */ - if (strcmp(r->key, "Video.CrosshairRed") == 0 || - strcmp(r->key, "Video.CrosshairGreen") == 0 || - strcmp(r->key, "Video.CrosshairBlue") == 0) { - snprintf(out, n, "%d%%", (int)lround(v * 100.0 / 255.0)); - return; - } /* D346: integer sliders -- optional raw->display divide + unit suffix. */ if (r->dispDiv > 0) { v = (double)(int)lround(v / (double)r->dispDiv); @@ -3748,6 +3753,7 @@ static const struct { const char *key, *help; } kRowHelp[] = { { "__DisplayMode", "Modern, original or custom graphics presets." }, { "Video.AspectMode", "Fill window fits the picture to the whole window." }, /* D560: shown only while Fill window is selected (optionsRowHelp) */ { "Video.CrosshairHide", "When off, the crosshair stays hidden, even with Sight on screen." }, + { "Video.CrosshairColor", "Original keeps the game's red sight. Custom: set Red, Green and Blue (0-255)." }, { "Video.CrosshairHealthColor", "The crosshair shifts from green to red as your health drops." }, { "Video.WidescreenAuto", "This only applies when Native widescreen is off." }, { "Game.ScreenShakeIntensity", "Sets how strongly explosions shake the screen." }, diff --git a/port/src/video.c b/port/src/video.c index 719ab36c..61636816 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -114,8 +114,19 @@ s32 portNoHitFlash = 0; * (gunfire.c gunDrawSight, #ifdef PORT). Default keeps the original * authored red sprite; hide is opt-in. */ s32 portCrosshairHide = 0; -static int cfgCrosshairColor = 0; /* 0 = authored sprite; 1..7 = presets; 8 = custom RGB */ +static int cfgCrosshairColor = 0; /* 0 = authored sprite; 8 = custom RGB (D569: old presets 1..7 migrate to 8 at startup) */ static int cfgCrosshairRed = 255, cfgCrosshairGreen = 255, cfgCrosshairBlue = 255; +/* Former named presets (D373/D381), kept for the D569 ini migration. */ +static const unsigned char kTints[8][3] = { + { 0xFF, 0xFF, 0xFF }, /* Original red sprite (identity multiplier) */ + { 0x40, 0xFF, 0x40 }, /* Green */ + { 0xFF, 0x40, 0x40 }, /* Red */ + { 0x40, 0x40, 0xFF }, /* Blue */ + { 0xFF, 0xFF, 0x40 }, /* Yellow */ + { 0x40, 0xFF, 0xFF }, /* Cyan */ + { 0xFF, 0x40, 0xFF }, /* Magenta */ + { 0xFF, 0xFF, 0xFF }, /* Actual white, through alpha silhouette */ +}; static int cfgCrosshairSize = 100; /* 100% retains the original 32x32 drawing */ static int cfgCrosshairStyle = 0; /* 0 = original; 1 = unused beta asset */ static int cfgCrosshairAlpha = 100; /* D511: % of the original sprite alpha (0x6E); 100 = untouched */ @@ -175,16 +186,6 @@ void portCrosshairTint(s32 *r, s32 *g, s32 *b) crosshairHealthTint(portCrosshairHealthRatio(), r, g, b); return; } - static const unsigned char kTints[8][3] = { - { 0xFF, 0xFF, 0xFF }, /* Original red sprite (identity multiplier) */ - { 0x40, 0xFF, 0x40 }, /* Green */ - { 0xFF, 0x40, 0x40 }, /* Red */ - { 0x40, 0x40, 0xFF }, /* Blue */ - { 0xFF, 0xFF, 0x40 }, /* Yellow */ - { 0x40, 0xFF, 0xFF }, /* Cyan */ - { 0xFF, 0x40, 0xFF }, /* Magenta */ - { 0xFF, 0xFF, 0xFF }, /* Actual white, through alpha silhouette */ - }; if (cfgCrosshairColor == 8) { *r = cfgCrosshairRed; *g = cfgCrosshairGreen; @@ -1005,6 +1006,15 @@ static float vidAvgFPS = 0.f; int videoInit(void) { + /* D569: Crosshair color is Original (0) or Custom RGB (8), as in the PD + * port. Inis from v0.5.0 builds before this may hold a named preset 1..7: + * carry its colour into the Custom channels once, so nothing changes. */ + if (cfgCrosshairColor >= 1 && cfgCrosshairColor <= 7) { + cfgCrosshairRed = kTints[cfgCrosshairColor][0]; + cfgCrosshairGreen = kTints[cfgCrosshairColor][1]; + cfgCrosshairBlue = kTints[cfgCrosshairColor][2]; + cfgCrosshairColor = 8; + } /* D440 CLI route: -n64preset / -portpreset apply the preset * once at startup (after configLoad, before any value reaches fast3d) and * persist like an F10 press (the atexit configSave). */