build-pc.sh Windows temp-dir re-exec fixes; CI pin actions and no-cache ROM handling; original-N64 and Deck presets; D440 preset labelling; D442 All unlocked as a RAM/query-time override; D443 settings values (MSAA 16x, Restart game); D444 front-end Previous/Next paging; D447 Original-aspect pillarbox/letterbox. Outside contributions by dolent: PRs #120 and #121 (relabelled D445, D446), merged as dolent's original commits. Refs: D440 D441 D442 D443 D444 D445 D446 D447 D387 D283 #120 #121
12 KiB
D357 — Settings thresholds & values: align display units/defaults with the PD port + Turok PC
Status: IMPLEMENTED 2026-09-30 (findings D443) for mouse sens ×, deadzone whole-%, volume step, FOV degrees, MSAA 16×, Restart game; texture filter unchanged by decision; frame-rate cap deferred (§0 presets + custom = separate project). Approved with changes; see §0. Proposal dated 2026-09-27. Baselines: the PD port
checkout (C:\Users\james\Source\Repos\pd_port, port/src/optionsmenu.c +
input.c/video.c config registrations), the Turok PC (Nightdive) list from
the maintainer's notes (docs/dev/notes/OPTIONS-MENU-PLAN.md §6 — taken from
user notes, not checked independently), and the N64 watch (ground truth for
the Bond.* rows only). Triggered by maintainer report: the current values
are "a bit confusing".
Companion change landed with this doc's review: the terminology settled on "Profile" as the end-user term for a per-player game file -- the front top row reads Profile, the per-file row tag reads "(per profile)" and the F10 unavailable value reads "Select a profile" (§4).
0. Sign-off (2026-09-30) — these override §3 where they differ
- FOV: display in degrees (the PC standard). Storage stays unchanged.
- Frame rate cap: presets 30 / 60 / 90 / 120 / 144 / 240 / Uncapped, plus an arbitrary custom value. This keeps the ini's free range and adds a custom entry in the menu, instead of the plan's presets-only grid.
- MSAA: add 16×.
- Mouse invert: stays a separate On/Off toggle.
- Texture filter: do NOT rename. The §3 premise ("3-point is trilinear") is wrong. 3-point is the N64's own 3-sample bilinear approximation, and "Linear" and "Bilinear" name the same thing. Keep "N64 3-point" and check the current enum strings before touching them.
- Refresh §3's "Now" column before implementing. The stick deadzone is already split L/R, and the draw/LOD defaults are 250, not 150.
- Related QoL, tracked separately in ROADMAP §5a: a Restart game action next to Quit to desktop, for restart-flagged rows such as MSAA.
1. Problem
The D356 regroup fixed the layout; the values still mix three unit families with no consistent rule:
- raw internal units shown as-is:
Input.MouseSensitivity(1–500, 100 = 1× — the "100" is a % of a 1.0 multiplier, not a count),Input.PadDeadzone(raw 0–30000,dispDiv=300→ "23%" but the step of 500 raw is 1.67 display-%, so the slider lands on 23, 25, 26…),Bond.Music/Bond.FX(0–32767,dispDiv=328, step 128 = 0.39 display-%); - N64-era vocabulary on PC rows: texture filter "Nearest / Bilinear / 3-Point" (the N64 watch term for trilinear), "FOV scale %" instead of degrees;
- defaults that don't read as defaults: MSAA shows "4x" fine, but
FpsCap0–1000 with step 1 invites 117 FPS;Video.LodDistancedefault 150% vsDrawDistance150% with a 25-step grid (100/125/150/175…).
The PD port is the house style to copy: per-stick sensitivity as a ±10
multiplier (default 1.0, negatives invert) (input.c:1537), mouse speed
-30..30 (default 2.5), deadzone raw 0–32767 per stick+axis, rumble
0–1, MSAA as a 2x/4x/8x/16x dropdown, frame cap as "N FPS",
volumes as 0–100 %. Turok's (user's list) conventions: single mouse
sensitivity knob, per-section resets (landed, D356), master/sound/music
volume trio (master still M3-backlog).
2. Principles
- Display, don't rescale the world. Every change is port-only (row
table,
dispDiv/step/unitfields, value-text,kResetDefaults): nosrc/gamechange, and config storage units are kept wherever a change would migrate existing ini files (principle 3). - Human units in the value column:
%on a 0–100 grid,×multipliers with 1.0 as the default,N FPS,Off/2x/4x/8x,Unlimited. A slider step must map to a whole display unit (the deadzone 1.67%-step bug is the canonical example to fix). - Ini stability: renaming a config key's storage unit is a migration.
Where the plan needs it, register a new key (e.g.
Input.PadDeadzonePct) and keep the old key as a read-once legacy alias — the D333Input.AimMode→Input.AimStylealias pattern (input.c:1962). Each migration gets a findings note. kResetDefaultsstays in lockstep with the config C initializers (D356 Gate E): every default change in this plan updates the table inoptionsoverlay.cin the same commit; theGE_WSPROBE_RESETprobe re-verifies.- Defaults = the config C initializers, never a new menu-only default.
3. Row-by-row audit & proposal
Current state from optionsoverlay.c rows[] + the configRegister*
ranges (2026-09-27). "Display" = what the value column shows today.
Implemented 2026-09-30 (D443) -- refreshed "Now" vs. result
The per-row tables below keep the 2026-09-27 audit text for history. Actual
pre-change state and what shipped (all port-only; no default or storage change,
so kResetDefaults is untouched and GE_WSPROBE_RESET stays failures=0):
| Row | Actual "Now" (pre-D443) | Shipped |
|---|---|---|
| Mouse horizontal sensitivity | 1-500 · step 5 · shown as calibrated N/100 (50/100 at raw 100) |
UI range 10-300, step 10, shown %.1fx (raw/100), linear bar; left the calibrated mapping |
| Stick deadzone L / R | already split Input.PadDeadzoneL/R 0-30000 · step 500 · calibrated N/100 |
step 300 + dispDiv=300 % (whole-% grid, no key migration); left the calibrated mapping |
| Music / FX volume | step 128, /328 |
step 328 (1 display-%) |
| FOV | Video.FovScale 50-150 · step 5 · % |
row "Field of view", horizontal degrees (see D443 formula); key/storage unchanged, step walks the displayed degree |
| Anti-aliasing | 1/2/4/8 · default 2 (C initialiser) | + 16x; range 1-16 (GL clamps to GL_MAX_SAMPLES) |
| Texture filter | Nearest / Bilinear / 3-Point | unchanged (decision §0) |
| Frame-rate cap | 30/60 toggle (sim ticks at 60 Hz) | unchanged this round |
| Restart game | -- | new action row after Quit to desktop (both UIs, shared table) |
INPUT
| Row | Now (default · range · step · display) | PD port | Turok (notes) | Proposal |
|---|---|---|---|---|
| Mouse sensitivity | 100 · 1–500 · 5 · raw 100 |
MouseSpeedX/Y float −30..30, def 2.5 (sign = invert) |
single knob | Display as a × multiplier: keep storage (100 = 1.0×), value text %.1f× (v/100); range 10–300 (0.1–3.0×), step 10 (0.1×). Label stays "Mouse sensitivity". |
| Invert look (mouse) | Off/On | folded into the −/× sign of MouseSpeed | — | Keep On/Off (PD's negative-multiplier style is an alternative; a separate invert is simpler next to the × slider). Decision: confirm. |
| Aim style / Aim range | N64/Centred (PC) · PC/N64 | — (GE-only, D337/D338) | — | Keep as-is (GE-specific; hiddenIfOn already sane). |
| Invert look (controller) | Off/On | sign of stick scale | — | Keep. |
| Stick deadzone | 7000 raw · 0–30000 · 500 · ÷300 → 23% (1.67%-steps) |
raw 0–32767 per stick+axis, DEFAULT_DEADZONE |
MISSING | New key Input.PadDeadzonePct 0–100, step 1, default 23 (7000/30000×100); input.c scales back to raw at apply; old key becomes a legacy alias (principle 3). Display N% on a whole-% grid. |
| Trigger threshold | 23 · 1–99 · 1 · % |
— (GE extra) | — | Keep. |
GAMEPLAY
| Row | Now | Baseline | Proposal |
|---|---|---|---|
| Auto-aim / Sight / Look ahead / Ammo (profile) | Off/On (N64 watch 0/1) | N64 watch = ground truth | Keep; tag now reads (profile) (this doc's companion change). |
| Skip intro / No hit flash / All unlocked | Off/On | Turok: screen-shake/hit-flash family | Keep. |
| HUD scale | 100 · 75–150 · 5 · % |
— | Keep (whole-% grid already; range cap D226). |
GRAPHICS
| Row | Now | Baseline | Proposal |
|---|---|---|---|
| Anti-aliasing | 1/2/4/8, def 4, shows None/2x/4x/8x, restart |
PD dropdown 2x/4x/8x/16x, def 4x | Add 16x to the sequence (kMsaaSeq, range clamp 1–16) — SDL/GL supports it; PD has it. Decision: perf cost on mid GPUs (restart already flagged). |
| Texture filter | Nearest / Bilinear / 3-Point | PC convention: Nearest/Linear/Bilinear | Rename the enum names to Nearest / Linear / Bilinear (3-point is trilinear; the N64 term is the last one left on a PC row). Storage 0/1/2 unchanged. |
| Anisotropic filtering | 4 · 1–16 · 1 · x |
Turok 1–16 | Keep; dim/disable when filter = Nearest (anisotropy only applies to filtered sampling) — hiddenIfOff-style guard, UI-only. |
| FOV scale | 100 · 50–150 · 5 · % |
Turok 3: 60–120° slider | Display in degrees: the 100% baseline is the N64 vertical FOV scaled to the port's widescreen math — value text N° (v/100 × baseline, 1 decimal); storage unchanged. Decision: degrees vs % (Turok uses degrees; % is the existing mental model — pick one, recommend degrees). |
| Native widescreen / Widescreen auto FOV / Crop overscan | Off/On | — | Keep. |
| Draw distance | 150 · 100–400 · 25 · % (hidden under auto-FOV) |
Turok: draw-distance row | Keep the % grid (25% steps read fine); step 25 → display already whole-%. No change. |
| LOD distance | 150 · 25–400 · 25 · % |
— | Keep; note default 150 vs DrawDistance 150 is intentional parity. |
AUDIO
| Row | Now | Baseline | Proposal |
|---|---|---|---|
| Music volume (profile) | 32767 · 0–32767 · 128 · ÷328 → 0.39%-steps | Turok: 0–100% | step 128 → 328 (exactly 1 display-%; 32767/328 = 99.9 ≈ "100%"). Storage unchanged (N64 VOLUME_MAX semantics). |
| FX volume (profile) | same | same | same. |
| (master volume) | — | Turok trio | M3-backlog, out of scope (shape the section for it, D356 note). |
VIDEO
| Row | Now | Baseline | Proposal |
|---|---|---|---|
| Fullscreen | Off/On | Turok: window mode (borderless missing) | Keep; borderless = separate backlog item. |
| Resolution | action row (presets) | both | Keep. |
| VSync | On/Off | both | Keep. |
| Frame rate cap | 60 · 0–1000 · 1 · Uncapped/N FPS |
Turok: "up to 120 FPS" / uncapped | Preset grid: 0/30/60/120/144 (step = next preset, wraps to Uncapped); value text already N FPS/Uncapped. Decision: preset grid vs free 1-step (recommend presets; 117 FPS has no purpose). |
| Show FPS | Off/On | both | Keep. |
4. Terminology (end-user term = "Profile")
Decision (2026-09-27, UX review): the end-user term for a per-player game file is "Profile" — the per-player bundle of progress + per-file settings. Rejected: "game file" (the instruction manual's current term) reads, in modern PC usage, as the program's own files ("Verify integrity of game files"), not the user's save; "Save" was the fallback (universally understood) but reads as a verb in the row tag and as progress-only, which these files are not. "Profile" covers both and fits the dossier styling of the screen.
Final string set (both UIs: front options + F10 overlay):
| String | Where |
|---|---|
"Profile" + value N |
front options top row (was "Save file: File N") |
| "(Profile N)" / "(none)" | section-title annotation on save-scoped sections (was "(File N)"/"(no file)") |
| "(per profile)" | per-file row tag (was "(save)", then "(profile)", then "(game file)") |
| "Select a profile" | F10 unavailable value (was "Select file") |
Manual sync TODO: the instruction manual's "game file" should be updated to "profile" (the manual is a port document we own).
"Bond file" remains in code identifiers/config keys (Bond.* rows,
watchSettingsChooseFile, ini keys) only -- never user-visible.
5. Gates
- Port-only per principle 1; the deadzone key migration (principle 3) is the only config-surface change and follows the D333 alias pattern.
kResetDefaultsupdated in the same commit as every default/range change;GE_WSPROBE_RESET(front +-level_33) re-run, all sectionsfailures=0.- Build via
build-pc-cmd.bat(the pi-shell MSYS env gap, D356 note). - Visual check owed (maintainer): front options screen + F10 in all five sections; the overlap fix from the same session (the level-1 save-file row no longer paints under the first content row).
6. Out of scope
- Key rebinding (Phase 4), master volume (M3), output-device selection, borderless window, per-axis controller sensitivity (PD-style four-knob — GE's one-knob design is D238/D304).
- Any
src/gamechange; the N64 watch keeps its own values and wording.