v0.4.0 final review: D404 pad-centred aim (N64-parity quadratic curve) + full campaign-playtest sign-off bookkeeping

- input.c: padDirectCompute() — pad twin of the mouse Centred aim; the natural
  pitch path routes AIMMODE_CENTRED through it, AIMMODE_N64 keeps classic
  stick-deflection behavior. Parity pass uses bondview2's verbatim N64
  quadratic curve (sign(v)*clamp(defl/70,+-1)^2 * fov/60 * 3.5 deg/poll), so
  full-stick Centred matches N64's top rate exactly.
- optionsoverlay: aim rows device-neutral (Aim style / Aim range).
- findings.md: D404 RESOLVED (user-validated on Steam Deck, both passes);
  21 sign-off status updates from the user's full campaign playtest
  (D175/D224/D235/D236/D240/D241/D245/D249/D281/D286/D287/D289/D291/D294/
  D303/D306/D307/D308/D311/D320/D322/D75/D387/D395/D396/D399/D400); stale
  options-wave rows closed (D346-D391 batch); D383/D394 kept PARTIAL with
  v0.5.0 scopes; D281 root cause -> v0.5.0; D258 -> NTSC-only for v0.4.0.
- README: Known issues = the true residual set (D318, D75 Rareware logo,
  AllUnlocked EXPERIMENTAL, NTSC-only); stale v0.3.0 clause removed.
- AGENTS.md: native-reexec guard status re-confirmed for 2026-09-28.
This commit is contained in:
James Dansereau committed 2026-09-28 01:02:09 -04:00
1 parent 39d1fd381e
commit 4b7cae63f9
38 files changed
+433620 -108

No files matched your search

+75 -2
View File
@@ -496,6 +496,7 @@ static int aimGepdAccumulate(double dxPx, double dyLook);
static void aimGepdEdgeScroll(void);
static int aimGepdCompute(double dxPx, double dyLook);
static int hipDirectCompute(double dxPx, double dyLook);
static int padDirectCompute(int dx, int dy); /* D404: pad twin of the above */
/* D194: bondview2's "look-ahead" pitch centreing (docentreupdown) arms during
* hip-fire walking whenever the pitch strays from the horizon target, and --
* once armed -- keeps pulling vv_verta back to it even in aim mode, EXCEPT
@@ -1973,8 +1974,22 @@ unsigned inputComputePad(int idx, signed char *stick_x, signed char *stick_y)
rys = (int)lround(padSmSY[idx]);
}
if (padLookInvertY) rys = -rys;
if (rxs) sx = rxs;
if (rys) sy = rys;
if (aimModeGet() == AIMMODE_CENTRED && padDirectCompute(rxs, rys)) {
/* D404 (resolved by implementation, 2026-09-28): pad CENTRED
* aim -- the stick drives the camera directly (crosshair
* pinned at centre), the pad-side twin of the mouse CENTRED
* branch above, so the Aim-style toggle is no longer inert
* on a pad. No look stick is emitted this poll; when
* padDirectCompute declines (dead/watch/pause/cutscene) the
* legacy stick emission below runs, as the mouse branch
* falls back to its legacy path. AIMMODE_N64 keeps today's
* behaviour: the deflection feeds the game's crosshair
* integrator (travel + edge scroll + spring-back -- the
* original controller feel). */
} else {
if (rxs) sx = rxs;
if (rys) sy = rys;
}
} else {
int px = scaleAxis(lx, padDeadzoneL);
int py = -scaleAxis(ly, padDeadzoneL); /* SDL up = negative -> N64 up = positive */
@@ -2550,6 +2565,64 @@ static int hipDirectCompute(double dxPx, double dyLook)
return 1;
}
/* D404 (resolved by implementation, 2026-09-28): the pad-side twin of
* hipDirectCompute's CENTRED path -- the right stick drives the camera
* directly and the crosshair stays pinned at centre, so the Aim-style
* toggle is no longer inert on a pad (it used to be: the pad always
* emitted deflection into the game's N64 crosshair integrator, i.e. it
* was *always in N64 mode*). Same safety gates as hipDirectCompute
* (dead / watch / pause / scripted camera); the mouseDirectLook/
* mouseGrabbed gate is dropped -- it is meaningless for a pad. Input
* units are stick deflection (STICK_MAX = full, the same unit the N64
* path feeds the game's integrator).
*
* Gain = the N64 natural-turn curve VERBATIM (bondview2.c, canNaturalTurn
* / canNaturalPitch branches): v = clamp(deflection/70, \u00b11); v =
* sign(v)\u00b7v\u00b2; camera += v \u00b7 (fov/60) \u00b7 3.5 deg/poll. First pass used a
* linear 2.0 deg/poll \u00b7 (fov/GEPD_BASE_FOV) gain, which the user measured
* as a dramatic sensitivity loss in Centred mode (linear vs quadratic
* curve, and the 60-vs-90 FOV base compounded it to ~2.6\u00d7 slower at full
* stick). With the verbatim curve, full-stick Centred turns at exactly
* the N64 path's top rate -- switching modes changes the crosshair
* behaviour, not the feel. */
static int padDirectCompute(int dx, int dy)
{
struct player *p = g_CurrentPlayer;
if (p == NULL)
return 0;
if (p->bonddead || !p->outside_watch_menu || p->pause_state != 0)
return 0;
if (gameScriptedCameraActive())
return 0;
if (dx == 0 && dy == 0)
return 1; /* nothing to turn; caller simply emits no stick */
f32 fov = viGetFovY();
double k = (fov > 0.0f) ? (double)fov / 60.0 : 1.0; /* bondview2's base */
double v;
v = (double)dx / 70.0; /* analogTurn = raw stick \u00b1 5, /70 -- bondview2.c:6222 */
if (v > 1.0) v = 1.0; else if (v < -1.0) v = -1.0;
if (v >= 0.0) v *= v; else v = -v * v;
p->vv_theta += (f32) (v * k * 3.5);
v = (double)dy / 70.0; /* analogPitch, /70 -- bondview2.c:6161 */
if (v > 1.0) v = 1.0; else if (v < -1.0) v = -1.0;
if (v >= 0.0) v *= v; else v = -v * v;
p->vv_verta -= (f32) (v * k * 3.5); /* game: speedverta = -v\u00b7(fov/60) */
if (p->vv_verta > 90.0f) p->vv_verta = 90.0f;
if (p->vv_verta < -90.0f) p->vv_verta = -90.0f;
if (configGetInputLog()) {
sysLogPrintf(LOG_NOTE,
"GE_INPUTLOG paddirect d=(%d,%d) cam=(%.1f,%.1f)",
dx, dy, (double)p->vv_theta, (double)p->vv_verta);
}
return 1;
}
/* --- Input.PdMouseAim: the port side of PD's mouse-aim model ----------------
* See the flag's comment above for the design. PD's own implementation lives
* in its GAME files (bondmove.c/bondgun.c) behind `#ifndef PLATFORM_N64`, with
+12 -5
View File
@@ -207,8 +207,15 @@ static struct Row rows[] = {
* overrides it at launch for A/B runs. */
/* D337: N64 = the N64 aim model (crosshair travels, camera edge-scrolls)
* with the mouse fed through the game's integrator at PD's mouse damp --
* the default. CENTRED (PC) = opt-in FPS-style aim (#104), not N64. Applies
* to every aim input (RMB, Shift, Q/L, pad trigger, Toggle mode). */
* the default. CENTRED (PC) = opt-in FPS-style aim (#104), not N64.
* Device-neutral (D404, resolved by implementation 2026-09-28): mouse --
* N64 feeds the game's integrator, CENTRED drives the camera directly
* (hipDirectCompute); pad -- N64 emits right-stick deflection into the
* same integrator (the original controller feel: crosshair travel +
* edge scroll + spring-back), CENTRED drives the camera directly from
* the stick (padDirectCompute, crosshair pinned at centre). Applies to
* every aim input (RMB, Shift, Q/L, Toggle mode, pad right stick in
* natural-pitch mode). */
{ .key="Input.AimMode", .label="Aim style", .kind=ROW_ENUM, .step=1, .names=kAimMode },
/* D338: how far the N64-style crosshair travels. PC = to the screen edge
* (GEPD / mouse-injector feel, default); N64 = the original stick limits
@@ -222,9 +229,9 @@ static struct Row rows[] = {
* (natural-pitch) feel options, identity at their defaults. All port-layer. */
{ .key="Input.PadDeadzoneL", .label="Deadzone (left stick)", .kind=ROW_SLIDER, .step=500 },
{ .key="Input.PadDeadzoneR", .label="Deadzone (right stick)", .kind=ROW_SLIDER, .step=500 },
{ .key="Input.PadLookSensX", .label="X axis look sensitivity", .kind=ROW_SLIDER, .step=5 },
{ .key="Input.PadLookSensY", .label="Y axis look sensitivity", .kind=ROW_SLIDER, .step=5 },
{ .key="Input.PadLookSmooth", .label="Look smoothing", .kind=ROW_SLIDER, .step=1, .dispMax=10 },
{ .key="Input.PadLookSensX", .label="X axis look sensitivity (controller)", .kind=ROW_SLIDER, .step=5 },
{ .key="Input.PadLookSensY", .label="Y axis look sensitivity (controller)", .kind=ROW_SLIDER, .step=5 },
{ .key="Input.PadLookSmooth", .label="Look smoothing (controller)", .kind=ROW_SLIDER, .step=1, .dispMax=10 },
{ .key="Input.PadSouthpaw", .label="Southpaw", .kind=ROW_TOGGLE, .step=1, .names=kOnOff },
{ .key="Input.PadTriggerPct", .label="Trigger threshold", .kind=ROW_SLIDER, .step=1 },
/* D401 item 3 (docs/dev/RUMBLE-PLAN.md): Rumble Pak strength (D224