mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-24 00:02:45 +02:00
input: fix reticule jitter in aim mode — adopt the PD mouse-aim model (D332, PR #96)
Opt-in Input.PdMouseAim (F10 "PD mouse aim"): in aim mode the port only accumulates the mouse position and the game's own crosshair integrator is driven by it with PD's mouse damp (0.01), instead of GEPD's per-poll overwrite fighting the weapon's ~0.8 per-tick damp (write*damp^k jitter). Hook: #ifdef PORT block in sub_GAME_7F067FBC (aim-mode branch only), identity when off; Rule-2 sign-off given by the maintainer. Integrated locally from PR #96 with review fixes: finding renumbered D337 -> D332; GE_PDMOUSEAIM lookup cached (GE_ENVSTR; it ran every poll and aim tick); "live env" comments corrected. Windows build clean; bunker1 golden 3/3. Feel A/B owed.
This commit is contained in:
1 parent
3a7c5d06c5
commit
05e5525db9
5 files changed
+173
-21
No files matched your search
@@ -209,3 +209,4 @@ D328,CLOSED,"Mod support is viable and D327's ""ruled out"" was wrong:",CLOSED a
|
||||
D329,FIXED,The D318/D320 guard anim pin is a tick-granularity divergence:,"FIXED — Rule-2 high-FPS fix in model.c; clk=1 no longer pins (WSL + native Windows), 0 triggers at clk=2; bunker1 golden failure predates it (on/off A/B); user playtest confirms N64-matching Ourumov…"
|
||||
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) —
|
||||
|
@@ -617,6 +617,7 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
|
||||
| D329 | **The D318/D320 guard anim pin is a tick-granularity divergence: it exists only at 1 sim tick per rendered frame (port at 60 fps); at 2+ ticks/frame (GE's normal N64 regime) it cannot persist (lockstep A/B, 2026-09-23).** — full `## D329` entry at file tail | FIXED — Rule-2 high-FPS fix in model.c; clk=1 no longer pins (WSL + native Windows), 0 triggers at clk=2; bunker1 golden failure predates it (on/off A/B); user playtest confirms N64-matching Ourumov timing; watchdog stays shipped for now. |
|
||||
| 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.** |
|
||||
|
||||
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
|
||||
@@ -13211,3 +13212,25 @@ So a player sets Auto-Aim ON with a key, touches the mouse, and it snaps back OF
|
||||
## D331 — Ejected shell casings never rendered on PC (D264 pattern, third site) (2026-09-23)
|
||||
|
||||
Found by the sibling-site sweep that D290 prompted (porting-notes §B "one layout bug often has sibling call sites"); never user-reported, likely because a missing casing is easy to overlook. `sub_GAME_7F068EC4` (`gunfire.c`, casing draw) initialises its render data with `*(ModelRenderData *)g_DefaultCasingModelRenderData`, where the global is `u32[15] = {0, 1, 3, 0…}` (`gun.c`): the N64 template basemtx NULL, zbufferenabled TRUE, flags 3. On PC `basemtx` is 8 bytes, so the words shift: zbufferenabled = 3, **flags = 0**, and `subdraw()` gates off every node. The copy also reads past the 60-byte array into whatever the linker put next. **Fix (`#ifdef PORT`, ABI/layout class, no Rule-2):** the explicit template, as in D264/D290. **Verified (native Windows, headless):** `-level_09`, `GE_INPUTSCRIPT="1000:Z;1020:Z"`, `GE_PCDUMP=850-1000:3`, shots at frames ~970/991. Before: impact sparks only, no casing. After: a brass casing ejects right of the PP7 and tumbles across frames 973–979. Bunker 1 golden 3/3; Windows + Linux builds clean. Sweep status: every `*(ModelRenderData *)` read in `src/game` is now covered (D215 :1592, D264, D290, D331). Cross-ref: D264, D290, porting-notes §A1/§B.
|
||||
|
||||
## D332 — Reticule jitter in aim mode (RMB): the drawn crosshair steps because the game damps once per tick and we write once per poll
|
||||
**Symptom.** Holding RMB (precision aim), the reticule jumps around. Reported in issue #89 as "mouse movement is not uniform", and independently as a jitter that is worst under uneven frame pacing.
|
||||
**Root cause, measured from live captures.** `caclulate_gun_crosshair_position_rotation` (`src/game/gunfire.c`) runs once per **sim tick** and does `crosshair_x_pos = crosshair_x_pos * guncrossdamp + turn_x`. The GEPD aim path (`port/src/input.c`, `aimGepdCompute`) *overwrites* `crosshair_x_pos` once per **input poll**. So the value the game displays is `write * damp^k`, where `k` is the number of ticks between two of our writes — and `k` varies, because the poll cadence (per VI retrace) and the tick cadence drift in phase.
|
||||
|
||||
Measured over 1266 aim frames from two captures, with the mouse still and the accumulator constant, `game/cross` took exactly three values (`damp^0`, `damp^1`, `damp^2`); `game = cross * damp^k` fits within 0.02 on 814/834 frames:
|
||||
```
|
||||
k=0: 72 k=1: 664 k=2: 89 k=3: 5 k=5: 3 k=6: 1
|
||||
ct=1 -> k=1 (226), k=0 (7) ct=2 -> k=2 (77), k=0 (68)
|
||||
```
|
||||
The drawn offset is that times `(1 - damp)`, so at `damp = 0.8` the reticule steps **20%** whenever `k` changes — on 16.5% of frames. (Diagnosed with `GE_INPUTLOG=1`, which logs the port's accumulator, the game's residue, `ct`, and the damp.)
|
||||
**Ruled out by the same capture:** auto-aim (`aa=0` throughout), stick turn (`st/sv=0`), camera edge-scroll (`cam` constant), and damp changes (only 5 KISSY/HONEY flips in 839 frames — real, each a ~43% rescale jump, but far too rare to be the main effect).
|
||||
**Two fixes tried and reverted.**
|
||||
- *Removing the D194(b) dt-normalisation* from the GEPD accumulator. Theoretically right — a position integral wants raw displacement, not a rate — but it did not stop the jitter.
|
||||
- *Pre-compensating `damp^k` with a predicted `k`.* Made it **worse**. `k` is not predictable at write time, and using the observed previous `k` is worse than doing nothing: simulating properly against the captures gives no compensation `mean|step| 0.0066`, lagged compensation `0.0170`, ideal `0.0005`. The first validation of this attempt was **circular** — it used `ct` as the number of damps, the very assumption the data contradicts.
|
||||
**Fix — adopt the Perfect Dark port's model.** `fgsfdsfgs/perfect_dark`'s aim code is structurally identical to GE's (`crosspossum` == `crosshair_x_pos`, `screenx` == `turn_x`, `crossdamp` == `guncrossdamp`, the same rescale block and display formula), but PD chooses the damp **per input device**: its mouse path calls `bgunSwivelWithDamp(x, y, 0.01f)` while its stick path uses `~0.945`. GE has one damp for both, and the weapon's `CrosshairSpeed` (~0.8) is a stick value — the integrator is what smooths a stick. At 0.01 the input dominates and `k` stops mattering.
|
||||
|
||||
Implemented as `Input.PdMouseAim` (**default off**, because it changes aim feel): the port only accumulates (`aimGepdAccumulate`, shared with GEPD's model) and a `#ifdef PORT` block in `sub_GAME_7F067FBC` takes the port-supplied turn and sets `guncrossdamp = 0.01f`. It is an F10 overlay row ("PD mouse aim"), which is live — toggling it in game takes effect on the next poll, no restart — plus a `GE_PDMOUSEAIM` launch-time override for A/B runs without editing the ini. PD does the same thing from its own game files (`bondmove.c`/`bondgun.c`/`player.c`, behind `#ifndef PLATFORM_N64`) calling port functions, so a platform-guarded game hook is the reference's own approach.
|
||||
**Also fixed here:** the first cut of PD mode skipped `aimGepdCompute` entirely, which is where the camera **edge-scroll** lived, so dragging the crosshair to the screen edge stopped moving the camera. The edge-scroll belongs to the aim position, not to whichever model owns the crosshair — it is now `aimGepdEdgeScroll()`, called from both paths.
|
||||
**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).
|
||||
|
||||
+115
-21
@@ -79,6 +79,7 @@
|
||||
#include "system.h"
|
||||
#include "config.h"
|
||||
#include "input.h"
|
||||
#include "envflag.h"
|
||||
#include "optionsoverlay.h"
|
||||
/* D194 absolute aim: read-only access to the live camera (struct player).
|
||||
* Game header pulled in through the same shim path every other compiled game
|
||||
@@ -336,6 +337,38 @@ static int mouseDirectLook = 1; /* WI-1 (GEPD-INPUT-PLAN.md #89): 1 = hipfir
|
||||
* as aim mode; 0 = legacy stick-curve path
|
||||
* (MOUSE_TURN_GAIN), kept as an escape hatch. */
|
||||
|
||||
/* Input.PdMouseAim -- use the Perfect Dark port's mouse-aim model instead of
|
||||
* GEPD's. Mirrors fgsfdsfgs/perfect_dark exactly (bondmove.c/bondgun.c): PD
|
||||
* accumulates the mouse delta into a position (`swivelpos`, clamped [-1,1])
|
||||
* and then pushes that POSITION into the game's crosshair integrator as its
|
||||
* INPUT, with a near-zero crosshair damp (`bgunSwivelWithDamp(x, y, 0.01f)`).
|
||||
*
|
||||
* The near-zero damp is the whole point. GE's aim path uses the weapon's
|
||||
* CrosshairSpeed (~0.8) -- a value chosen for the analog stick, where the
|
||||
* integrator does the smoothing. With a mouse that slow integrator is what
|
||||
* makes the drawn crosshair step: the port writes once per input poll while
|
||||
* the game damps once per sim tick, so the displayed value is write*damp^k
|
||||
* with k varying (findings D332). At damp 0.01 the input dominates and k stops
|
||||
* mattering -- PD never had this bug because it never gave the mouse a slow
|
||||
* damp.
|
||||
*
|
||||
* In this mode the port only ACCUMULATES; the game's own integrator does the
|
||||
* rest, driven by the port-supplied turn through a #ifdef PORT hook in
|
||||
* sub_GAME_7F067FBC (gunfire.c). Default off: it changes aim feel, so it is
|
||||
* opt-in. */
|
||||
static int pdMouseAim = 0;
|
||||
|
||||
/* GE_PDMOUSEAIM, when set, overrides the ini for launch-time A/B runs without
|
||||
* editing ge007.ini. A process's environment is fixed once it starts, so the
|
||||
* 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. */
|
||||
static int pdMouseAimEnabled(void)
|
||||
{
|
||||
const char *e = GE_ENVSTR("GE_PDMOUSEAIM");
|
||||
return e ? (atoi(e) != 0) : (pdMouseAim != 0);
|
||||
}
|
||||
|
||||
/* D194 GEPD-aim state. Touched ONLY in inputComputePad (game thread), the
|
||||
* same confinement as every other static here. The per-poll grabbed delta
|
||||
* drives the view, so there is no free-running angle accumulator for
|
||||
@@ -348,6 +381,8 @@ static int mouseDirectLook = 1; /* WI-1 (GEPD-INPUT-PLAN.md #89): 1 = hipfir
|
||||
* overwritten each tick (GEPD model, D194). */
|
||||
static double s_gepdCrossX = 0.0, s_gepdCrossY = 0.0;
|
||||
static int s_gepdHeldPrev = 0; /* aim held last tick -> adopt on entry */
|
||||
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);
|
||||
/* D194: bondview2's "look-ahead" pitch centreing (docentreupdown) arms during
|
||||
@@ -1032,7 +1067,16 @@ 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 (!aimGepdCompute(edx * lookDtScale, dyLook * lookDtScale)) {
|
||||
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). */
|
||||
aimGepdAccumulate(edx, dyLook);
|
||||
/* Edge-scroll belongs to the aim position, not to the
|
||||
* crosshair model -- without this the camera stops
|
||||
* following the crosshair at the screen edge. */
|
||||
aimGepdEdgeScroll();
|
||||
} else if (!aimGepdCompute(edx * lookDtScale, dyLook * lookDtScale)) {
|
||||
double aimEdx = edx * lookDtScale, aimDyLook = dyLook * lookDtScale;
|
||||
double aimSens = (mouseAimSpeed / 100.0) * (mouseSensitivity / 100.0);
|
||||
double gamma = aimCurveGamma / 100.0;
|
||||
@@ -1428,12 +1472,16 @@ int inputGetNumControllers(void)
|
||||
* Returns 1 if it handled this poll (callers must NOT emit a look stick);
|
||||
* 0 means fall back to the legacy velocity stick.
|
||||
*/
|
||||
static int aimGepdCompute(double dxPx, double dyLook)
|
||||
/* Accumulate this poll's mouse delta into the aim position. Shared by both
|
||||
* aim models: GEPD pushes the result into crosshair_x/y_pos itself, PD feeds
|
||||
* it to the game's integrator as the turn (see Input.PdMouseAim). Returns 0
|
||||
* if aim is not usable this poll. */
|
||||
static int aimGepdAccumulate(double dxPx, double dyLook)
|
||||
{
|
||||
struct player *p = g_CurrentPlayer;
|
||||
|
||||
/* Needs the grabbed-cursor relative deltas (capture mode, locked in a
|
||||
* stage) and a live player. dxPx/dyLook are this poll's dt-scaled px. */
|
||||
* stage) and a live player. dxPx/dyLook are this poll's px. */
|
||||
if (!aimAbsolute || !mouseGrabbed || p == NULL)
|
||||
return 0;
|
||||
|
||||
@@ -1457,27 +1505,19 @@ static int aimGepdCompute(double dxPx, double dyLook)
|
||||
if (s_gepdCrossX < -GEPD_CROSSHAIR_LIMIT) s_gepdCrossX = -GEPD_CROSSHAIR_LIMIT;
|
||||
if (s_gepdCrossY > GEPD_CROSSHAIR_LIMIT) s_gepdCrossY = GEPD_CROSSHAIR_LIMIT;
|
||||
if (s_gepdCrossY < -GEPD_CROSSHAIR_LIMIT) s_gepdCrossY = -GEPD_CROSSHAIR_LIMIT;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Camera edge-scroll: past GEPD_EDGE_THRESHOLD (72%) of the way to the
|
||||
* crosshair limit, scroll the view proportionally to the overshoot, scaled by
|
||||
* zoom like GEPD's (fov/basefov). This belongs to the aim POSITION, not to
|
||||
* whichever model owns the crosshair, so both call it -- PD's model needs it
|
||||
* too, or dragging the crosshair to the edge no longer moves the camera. */
|
||||
static void aimGepdEdgeScroll(void)
|
||||
{
|
||||
struct player *p = g_CurrentPlayer;
|
||||
f32 fov = viGetFovY();
|
||||
f32 fovratio = (fov > 0.0f) ? fov / GEPD_BASE_FOV : 1.0f;
|
||||
|
||||
/* Pre-overwrite residue: what last tick's damped update left behind
|
||||
* (crosshair_pos = pos*damp + turn, gunfire.c caclulate_gun_crosshair_...
|
||||
* runs AFTER our write each tick). The gap between this and our write
|
||||
* below is the game-side turn term (autoaimx/y or speedtheta*0.3) --
|
||||
* logged for the D194 spazz diagnosis. */
|
||||
double resX = (double) p->crosshair_x_pos;
|
||||
double resY = (double) p->crosshair_y_pos;
|
||||
|
||||
/* Crosshair + gun/arm pose (GEPD formulas, RATIOFACTOR=1 for our 4:3
|
||||
* viewport; failsafe weapon offsets 0.15/0 as in goldeneye.c). */
|
||||
p->crosshair_x_pos = (f32) s_gepdCrossX;
|
||||
p->crosshair_y_pos = (f32) s_gepdCrossY;
|
||||
p->gun_azimuth_angle = (f32) (s_gepdCrossX * (1.11f + 0.15f * 1.5f) + fovratio - 1.0f);
|
||||
p->gun_azimuth_turning = (f32) (s_gepdCrossY * 1.11f + fovratio - 1.0f);
|
||||
|
||||
/* Edge scroll: only past 72% of the way to the edge, proportional to
|
||||
* overshoot; scaled by zoom like GEPD's (fov/basefov). */
|
||||
double rX = s_gepdCrossX / GEPD_CROSSHAIR_LIMIT;
|
||||
double rY = s_gepdCrossY / GEPD_CROSSHAIR_LIMIT;
|
||||
double aimx = 0.0, aimy = 0.0;
|
||||
@@ -1501,6 +1541,34 @@ static int aimGepdCompute(double dxPx, double dyLook)
|
||||
if (p->vv_verta > 90.0f) p->vv_verta = 90.0f;
|
||||
if (p->vv_verta < -90.0f) p->vv_verta = -90.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static int aimGepdCompute(double dxPx, double dyLook)
|
||||
{
|
||||
struct player *p = g_CurrentPlayer;
|
||||
|
||||
if (!aimGepdAccumulate(dxPx, dyLook))
|
||||
return 0;
|
||||
|
||||
f32 fov = viGetFovY();
|
||||
f32 fovratio = (fov > 0.0f) ? fov / GEPD_BASE_FOV : 1.0f;
|
||||
|
||||
/* Pre-overwrite residue: what last tick's damped update left behind
|
||||
* (crosshair_pos = pos*damp + turn, gunfire.c caclulate_gun_crosshair_...
|
||||
* runs AFTER our write each tick). The gap between this and our write
|
||||
* below is the game-side turn term (autoaimx/y or speedtheta*0.3) --
|
||||
* logged for the D194 spazz diagnosis. */
|
||||
double resX = (double) p->crosshair_x_pos;
|
||||
double resY = (double) p->crosshair_y_pos;
|
||||
|
||||
/* Crosshair + gun/arm pose (GEPD formulas, RATIOFACTOR=1 for our 4:3
|
||||
* viewport; failsafe weapon offsets 0.15/0 as in goldeneye.c). */
|
||||
p->crosshair_x_pos = (f32) s_gepdCrossX;
|
||||
p->crosshair_y_pos = (f32) s_gepdCrossY;
|
||||
p->gun_azimuth_angle = (f32) (s_gepdCrossX * (1.11f + 0.15f * 1.5f) + fovratio - 1.0f);
|
||||
p->gun_azimuth_turning = (f32) (s_gepdCrossY * 1.11f + fovratio - 1.0f);
|
||||
|
||||
aimGepdEdgeScroll();
|
||||
|
||||
if (configGetInputLog()) {
|
||||
/* ct = g_ClockTimer: game ticks batched into this poll. If the
|
||||
@@ -1592,10 +1660,36 @@ static int hipDirectCompute(double dxPx, double dyLook)
|
||||
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
|
||||
* the port supplying the input; we mirror that with `#ifdef PORT` hooks in
|
||||
* GE's aim path (sub_GAME_7F067FBC, gunfire.c).
|
||||
*
|
||||
* The port accumulates the mouse delta (aimGepdAccumulate, shared with GEPD's
|
||||
* model) and the game's own crosshair integrator does the rest. PD's range is
|
||||
* swivelpos in [-1,1] == the screen edge, which is what the game's display
|
||||
* formula maps to half a screen width; GEPD's crosshair limit is that same
|
||||
* edge in its own units, so dividing by it gives PD's units. */
|
||||
int portMouseAimPdActive(void)
|
||||
{
|
||||
return pdMouseAimEnabled() && mouseGrabbed;
|
||||
}
|
||||
|
||||
int portMouseAimPdGetTurn(f32 *tx, f32 *ty)
|
||||
{
|
||||
if (!portMouseAimPdActive() || g_CurrentPlayer == NULL)
|
||||
return 0;
|
||||
if (tx) *tx = (f32) (s_gepdCrossX / GEPD_CROSSHAIR_LIMIT);
|
||||
if (ty) *ty = (f32) (s_gepdCrossY / GEPD_CROSSHAIR_LIMIT);
|
||||
return 1;
|
||||
}
|
||||
|
||||
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.AimAbsolute", &aimAbsolute, 0, 1); /* D194 */
|
||||
configRegisterInt("Input.MouseDirectLook", &mouseDirectLook, 0, 1); /* WI-1 */
|
||||
/* D194: renamed Input.GepdSens -> Input.AimModeSens (community name for
|
||||
|
||||
@@ -163,6 +163,13 @@ static struct Row rows[] = {
|
||||
/* { "Input.SensLink", "Link aim/turn sens",ROW_TOGGLE,1, kOnOff, 0, 0, 0, 0,0,0,0,0 }, */
|
||||
{ "Input.MouseSensitivity", "Mouse sensitivity",ROW_SLIDER, 5, NULL, 0, 0, 0, 0,0,0,0,0 },
|
||||
{ "Input.MouseInvertY", "Mouse invert Y", ROW_TOGGLE, 1, kOnOff, 0, 0, 0, 0,0,0,0,0 },
|
||||
/* Input.PdMouseAim (findings D332): the Perfect Dark port's mouse-aim
|
||||
* model. The port only accumulates the mouse; the game's own crosshair
|
||||
* integrator is driven by the port-supplied turn with PD's near-zero damp
|
||||
* (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 },
|
||||
/* 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
|
||||
|
||||
@@ -4961,6 +4961,33 @@ void sub_GAME_7F067FBC(f32 turn_x, f32 turn_y)
|
||||
gunaimdamp = item_stats->AimLockSpeed;
|
||||
#endif
|
||||
|
||||
#ifdef PORT
|
||||
/* Defined in port/src/input.c. Declared here rather than including
|
||||
* port/include/input.h, which pulls in SDL types game code cannot see --
|
||||
* the same pattern other game files use for port functions. */
|
||||
extern int portMouseAimPdGetTurn(f32 *tx, f32 *ty);
|
||||
|
||||
/* Input.PdMouseAim (findings D332): PD's mouse-aim model.
|
||||
*
|
||||
* PD chooses its crosshair damp PER INPUT DEVICE -- its mouse path calls
|
||||
* bgunSwivelWithDamp(x, y, 0.01f) while its stick path uses ~0.945. GE has
|
||||
* one damp for both, and the weapon's CrosshairSpeed (~0.8) is a stick
|
||||
* value: the integrator is what smooths a stick. With a mouse that slow
|
||||
* integrator is what makes the drawn crosshair step, because the port
|
||||
* writes once per input poll while the game damps once per sim tick -- the
|
||||
* displayed value is write*damp^k with k varying (D332). At 0.01 the input
|
||||
* dominates and k stops mattering.
|
||||
*
|
||||
* The port supplies the turn; PD does the same from its own game files
|
||||
* (bondmove.c/bondgun.c, behind #ifndef PLATFORM_N64) calling port
|
||||
* functions. Identity when Input.PdMouseAim is off, and the N64 build
|
||||
* never sees any of it. Behavioural hook, not the ABI exception:
|
||||
* Rule-2 sign-off given by the maintainer 2026-09-23. */
|
||||
if (portMouseAimPdGetTurn(&turn_x, &turn_y)) {
|
||||
guncrossdamp = 0.01f;
|
||||
}
|
||||
#endif
|
||||
|
||||
caclulate_gun_crosshair_position_rotation(turn_x, turn_y, guncrossdamp, gunaimdamp);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user