diff --git a/docs/dev/findings-index.csv b/docs/dev/findings-index.csv index cebc6191..5db26423 100644 --- a/docs/dev/findings-index.csv +++ b/docs/dev/findings-index.csv @@ -210,3 +210,4 @@ D329,FIXED,The D318/D320 guard anim pin is a tick-granularity divergence:,"FIXED D330,FIXED,"#103 (v0.3.0, Win 11):","FIXED (port/src/input.c), build clean, bunker1 golden 3/3; mouse feel-check owed (a human must run it:" D331,FIXED,Ejected shell casings never rendered on PC:,"FIXED (gunfire.c #ifdef PORT, explicit template); PP7 casing verified on native Windows (before:" D332,FIXED,Reticule jitter in aim mode (RMB) —,FIXED (fix/mouse-pd-model) — +D333,OPEN,"#104 (v0.3.0, Linux):","IMPLEMENTED (port/src/input.c + optionsoverlay.c, port-only); default N64 = unchanged; build + golden clean; feel check owed." diff --git a/docs/dev/findings.md b/docs/dev/findings.md index 9faa4a88..4b92a46d 100644 --- a/docs/dev/findings.md +++ b/docs/dev/findings.md @@ -618,6 +618,7 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121). | D330 | **#103 (v0.3.0, Win 11): Auto-Aim / Look Ahead "won't stay on" in the in-game watch options: the mouse drove the analog stick inside the watch, and a small leftward flick selected OFF.** — full `## D330` entry at file tail | FIXED (port/src/input.c), build clean, bunker1 golden 3/3; mouse feel-check owed (a human must run it: select Auto-Aim, set ON, move the mouse; it must stay ON). | | D331 | **Ejected shell casings never rendered on PC: `g_DefaultCasingModelRenderData` (u32[15] template) read as the wider PC `ModelRenderData` gave flags 0 (third instance of the D264 pattern; found by the D290 sibling sweep, never user-reported).** — full `## D331` entry at file tail | FIXED (gunfire.c `#ifdef PORT`, explicit template); PP7 casing verified on native Windows (before: none; after: brass casing ejects and tumbles); golden 3/3; Win + Linux builds clean. | | D332 | **Reticule jitter in aim mode (RMB) — ROOT-CAUSED from live captures; fixed by adopting the Perfect Dark port's mouse-aim model behind `Input.PdMouseAim`.** The game's damped crosshair update runs once per SIM TICK while the port's GEPD overwrite runs once per input POLL, so the value displayed is `write * damp^k` with k varying (k=1 66%, k=2 18%, k=0 17% of frames). At damp 0.8 that stepped the drawn reticule 20% whenever k changed | **FIXED (`fix/mouse-pd-model`)** — `Input.PdMouseAim` (default off, live via `GE_PDMOUSEAim`): the port accumulates only and the game's integrator is driven by the port-supplied turn with PD's near-zero damp (0.01), via a `#ifdef PORT` hook in `sub_GAME_7F067FBC`. Two earlier fixes were tried and reverted (see the `## D332` entry). **Awaiting feel-test.** | +| D333 | **#104 (v0.3.0, Linux): FPS-style centred aim on RMB, delivered as `Input.AimStyle` (F10 "RMB aim style": N64 / PD DAMP / CENTRED), folding in D332's toggle.** — full `## D333` entry at file tail | IMPLEMENTED (port/src/input.c + optionsoverlay.c, port-only); default N64 = unchanged; build + golden clean; feel check owed. | Phase 2 replaced the Phase-1 demo loop with the real `mainproc()` on real OS threads, compiled GE's real `src/sched.c`, and brought in PD's fast3d software @@ -13234,3 +13235,11 @@ Implemented as `Input.PdMouseAim` (**default off**, because it changes aim feel) **Owed:** sensitivity tuning (PD's 0.01 against GEPD's accumulator scale may not match PD's own calibration; `Input.AimModeSens` is the knob). **Integrated locally on `release/v0.4.0` (2026-09-23), from PR #96 (danturn; authorship kept).** Changes on integration: renumbered D337 → D332 (next free label); `GE_PDMOUSEAIM` lookup cached via `GE_ENVSTR` (it ran every input poll and every aim tick; see the getenv sweep `d9d7cd35`), and the "live env A/B without restart" comments corrected (a running process's env is fixed; the live toggle is the F10 row); the `gunfire.c` hook is a behavioural `#ifdef PORT` hook and got the maintainer's **Rule-2 sign-off 2026-09-23**. Scope checked: the hooked `sub_GAME_7F067FBC` runs only on the aim-mode (KISSY) branch of `bondview2.c`, so hipfire and auto-aim are unaffected. Windows build clean; golden 3/3 (default off). **Owed:** hands-on feel A/B (F10 → "PD mouse aim" on/off while holding RMB). +## D333 — #104: FPS-style centred aim on RMB → `Input.AimStyle` selector (2026-09-23) + +**Request (#104):** with mouse and keyboard, RMB gives N64-style aim (crosshair travels, camera edge-scrolls). The reporter found that holding Q (bound to the game's L button) gives "PC FPS-style" aim, with the crosshair centred and the mouse turning the camera, and wanted that on RMB. **Why Q behaves that way:** Q sends `GE_CONT_L`, so the game enters its sight mode, but the port's `aimHeld` is RMB/`IA_AIM` only, so `inputComputePad` stays on the hipfire direct-look path (`hipDirectCompute`, WI-1). No stick is emitted, and the aim integrator (`pos = pos*damp + turn`, gunfire.c via the KISSY branch) settles the crosshair at 0 (centre). + +**Implementation (port-only, no game-code change):** one setting, `Input.AimStyle` 0–2, replaces D332's boolean in the F10 overlay ("RMB aim style"). 0 = **N64** (GEPD mirror, D194; default, unchanged). 1 = **PD DAMP** (D332). 2 = **CENTRED**: inside the RMB `aimHeld` branch, the mouse goes to `hipDirectCompute` (FOV-scaled, so zoomed weapons turn slower; the same watch/pause/cutscene gates) and no aim stick is emitted, which is exactly the Q behaviour on RMB. `Input.PdMouseAim=1` from PR-#96 builds migrates to style 1 on first use. `GE_PDMOUSEAIM` still forces PD on or off at launch. + +**Verified:** Windows + Linux builds clean; bunker1 golden 3/3 (default style 0). Not verifiable headlessly: the scripted input source has no mouse, and the overlay row sits below the fold at every window size (it uses the same `ROW_ENUM` machinery as Texture filter). **Owed (user):** F10 → RMB aim style → CENTRED, hold RMB and move the mouse: the camera turns, the crosshair stays centred, and zoomed weapons turn slower. Also compare PD DAMP against N64 for D332's jitter fix. + diff --git a/port/src/input.c b/port/src/input.c index cfa044de..9b9aedef 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -363,10 +363,33 @@ static int pdMouseAim = 0; * lookup is cached (GE_ENVSTR): this runs every input poll and every aim tick * (D250/D302 hot-path class). The live, no-restart toggle is the ini key via * the F10 "PD mouse aim" row. */ +/* Input.AimStyle (D333, #104 + #96): what RMB aim does with the mouse. + * 0 = N64/GEPD (default): crosshair moves across the screen, camera + * edge-scrolls (D194, GEPD mirror). + * 1 = PD damp: same N64-style crosshair, driven through the game's own + * integrator with PD's mouse damp (D332, PR #96). + * 2 = Centred: FPS-style -- the mouse turns the camera directly (the + * hipfire WI-1 path, FOV-scaled so zoom slows it) and the crosshair + * stays centred: with no stick input the game's aim integrator + * (pos = pos*damp + turn, gunfire.c) settles at 0. This is what + * holding the game's L button (Q) already did; #104 asked for it on RMB. + * The legacy Input.PdMouseAim=1 (PR #96 builds) is migrated to style 1. */ +enum { AIMSTYLE_GEPD = 0, AIMSTYLE_PD = 1, AIMSTYLE_CENTRED = 2 }; +static int aimStyle = AIMSTYLE_GEPD; + +static int aimStyleGet(void) +{ + if (pdMouseAim && aimStyle == AIMSTYLE_GEPD) { /* one-time migration */ + aimStyle = AIMSTYLE_PD; + pdMouseAim = 0; + } + return aimStyle; +} + static int pdMouseAimEnabled(void) { const char *e = GE_ENVSTR("GE_PDMOUSEAIM"); - return e ? (atoi(e) != 0) : (pdMouseAim != 0); + return e ? (atoi(e) != 0) : (aimStyleGet() == AIMSTYLE_PD); } /* D194 GEPD-aim state. Touched ONLY in inputComputePad (game thread), the @@ -1067,7 +1090,13 @@ unsigned inputComputePad(int idx, signed char *stick_x, signed char *stick_y) * look stick (see aimGepdCompute). Keyboard turn (sx/sy set * above) still works. Otherwise fall through to the legacy * velocity stick below. */ - if (pdMouseAimEnabled()) { + if (aimStyleGet() == AIMSTYLE_CENTRED) { + /* D333: FPS-style centred aim -- the camera takes the + * mouse (same path as hipfire, which also declines on + * the watch/pause/cutscene gates) and no stick is + * emitted, so the crosshair settles at centre. */ + hipDirectCompute(edx * lookDtScale, dyLook * lookDtScale); + } else if (pdMouseAimEnabled()) { /* PD model: accumulate only. The game's own integrator is * driven by the port-supplied turn through the * sub_GAME_7F067FBC hook (see Input.PdMouseAim above). */ @@ -1689,7 +1718,8 @@ PD_CONSTRUCTOR static void inputConfigInit(void) { configRegisterInt("Input.MouseEnabled", &mouseEnabled, 0, 1); configRegisterInt("Input.MouseAimSpeed", &mouseAimSpeed, 1, 500); - configRegisterInt("Input.PdMouseAim", &pdMouseAim, 0, 1); + configRegisterInt("Input.PdMouseAim", &pdMouseAim, 0, 1); /* legacy -> AimStyle 1 */ + configRegisterInt("Input.AimStyle", &aimStyle, 0, 2); /* D333 */ configRegisterInt("Input.AimAbsolute", &aimAbsolute, 0, 1); /* D194 */ configRegisterInt("Input.MouseDirectLook", &mouseDirectLook, 0, 1); /* WI-1 */ /* D194: renamed Input.GepdSens -> Input.AimModeSens (community name for diff --git a/port/src/optionsoverlay.c b/port/src/optionsoverlay.c index 36178837..12b1996a 100644 --- a/port/src/optionsoverlay.c +++ b/port/src/optionsoverlay.c @@ -67,6 +67,7 @@ enum { ROW_TOGGLE, ROW_SLIDER, ROW_ENUM, ROW_MSAA, ROW_RES, ROW_ACTION, ROW_FPSC static const char *const kOnOff[] = { "OFF", "ON", NULL }; static const char *const kTexFilter[] = { "NEAREST", "BILINEAR", "3-POINT", NULL }; +static const char *const kAimStyle[] = { "N64", "PD DAMP", "CENTRED", NULL }; /* D333 */ static const int kMsaaSeq[] = { 1, 2, 4, 8 }; /* D186: the sim's own tick pacemaker is hardcoded to the console's native VI * rate (60Hz NTSC / 50Hz PAL, port/src/libultra.c) -- Video.FpsCap can only @@ -169,7 +170,11 @@ static struct Row rows[] = { * (0.01), instead of GEPD's overwrite with the weapon's ~0.8 -- which is * what made the reticule step. Changes aim feel, so opt-in. GE_PDMOUSEAIM=0/1 * overrides it at launch for A/B runs. */ - { "Input.PdMouseAim", "PD mouse aim", ROW_TOGGLE, 1, kOnOff, 0, 0, 0, 0,0,0,0,0 }, + /* D333: one selector for what RMB aim does (#104 asked for centred, + * FPS-style aim on RMB): N64 = GEPD crosshair + edge scroll (default), + * PD DAMP = the PD model above, CENTRED = mouse turns the camera and the + * crosshair stays centred. Input.PdMouseAim=1 migrates to PD DAMP. */ + { "Input.AimStyle", "RMB aim style", ROW_ENUM, 1, kAimStyle, 0, 0, 0, 0,0,0,0,0 }, /* D181/Game.ScreenShakeIntensity: user testing (v0.2.1) found the slider * "basically useless" -- viShake() is only called from explosion.c, so it * scales explosion shake alone; it never touches the always-on walking