v0.4.0 M2 (D373): crosshair on/off + colour; D374: GEPD becomes the default key layout

M2 (the wave's only rule-2 item, sign-off recorded via user direction):
#ifdef PORT hook in gunfire.c gunDrawSight -- Video.CrosshairHide skips
the draw, Video.CrosshairColor tints the RGB (7 named tints, 0 = the
N64 white); non-PORT builds keep the original literals. F10 GRAPHICS
rows + kResetDefaults.

D374 (M3 playtest fix, user decision): GEPD is now the DEFAULT key
layout (Input.Layout 0 = GEPD, 1 = N64-era binds; a mouse FPS layout is
the natural default and the N64 never had a keyboard). The preset is
now the true effective default: only EXPLICIT per-key [Input.Bind]
overrides beat it; persisted values equal to the N64 defaults count as
unset. This fixes the playtest bug where a stale persisted
Fire=Left Ctrl masked the GEPD preset and made Ctrl fire+crouch at the
same time. Boot log reports the applied layout. One-off: pre-D374
Layout=1 (ex-GEPD) inis mean N64 now -- flip to 0 (release note).
This commit is contained in:
James Dansereau committed 2026-09-27 16:43:04 -04:00
1 parent b95b54ecc7
commit fca07bdd9a
6 files changed
+192 -24

No files matched your search

+48 -18
View File
@@ -763,6 +763,9 @@ static unsigned scriptApply(unsigned button)
static void inputRebuildBinds(void); /* D214; defined below with keyDown() */
static int keyLayout = 0; /* v0.4.0 D374: 0 = GEPD (the default), 1 = N64 layout */
static int crouchMode = 0; /* 0 = hold, 1 = toggle (latched B) */
int inputInit(void)
{
if (!SDL_WasInit(SDL_INIT_GAMECONTROLLER)) {
@@ -779,6 +782,9 @@ int inputInit(void)
inputRebuildBinds(); /* D214: parse [Bind] now that configLoad() has run */
sysLogPrintf(LOG_INFO, "input: layout %s, crouch mode %s (rebuild after configLoad, D214/D374)",
keyLayout ? "N64" : "GEPD (default)", crouchMode ? "toggle" : "hold");
/* Relative mouse mode for mouse-look. Click-to-lock: we start released
* and wait for a click in the window (video.c -> inputNotifyClick). */
mouseGrabbed = 0;
@@ -893,13 +899,18 @@ static const struct { const char *key; const char *def; } kBindDefs[IA_COUNT] =
[IA_CROUCH] = { "Input.Bind.Crouch", "" },
};
/* v0.4.0 M3: GEPD key-layout preset (docs/dev/notes/GEPORT-REFERENCE-
* DEEPDIVE.md section 7.3). The preset is the EFFECTIVE DEFAULT for any action
* the user has not overridden per-key in [Bind]; a per-key ini value
* layers on top, so switching layouts never clobbers explicit binds.
* Fire loses its Left Ctrl key in this layout (LMB fires, RMB aims;
* Ctrl becomes crouch); LeanLeft is unbound (lean is GEPD-removed).
* NULL entries keep the FPS default. */
/* v0.4.0 M3 (D371) / D374: the GEPD key-layout preset -- now the DEFAULT
* layout (docs/dev/notes/GEPORT-REFERENCE-DEEPDIVE.md section 7.1: Q = A
* button (accept/next weapon), E = B button (use/cancel/crouch/reload),
* R = dedicated reload, Ctrl = crouch). The preset is the effective default
* for any action the user has not EXPLICITLY overridden in [Input.Bind];
* an ini value equal to the N64-layout default (the migration pass writes
* every key on clean exit) counts as "unset", so a pre-wave ini file gets
* the preset, not its stale persisted defaults (D374: the stale
* Fire=Left Ctrl persisted default is exactly what made Ctrl fire the gun
* in the first GEPD playtest). Fire loses its Left Ctrl key (LMB fires,
* RMB aims; Ctrl is crouch); LeanLeft is unbound (lean is GEPD-removed).
* NULL entries keep the N64 default. */
static const char *const kGepdPreset[IA_COUNT] = {
[IA_FIRE] = "",
[IA_ACTION] = "Q",
@@ -908,8 +919,6 @@ static const char *const kGepdPreset[IA_COUNT] = {
[IA_RELOAD] = "R",
[IA_CROUCH] = "Left Ctrl",
};
static int keyLayout = 0; /* 0 = FPS defaults, 1 = GEPD preset */
static int crouchMode = 0; /* 0 = hold, 1 = toggle (latched B) */
static int s_crouchLatch = 0;
static int s_crouchHeldPrev = 0;
@@ -923,18 +932,39 @@ static void inputRebuildBinds(void)
for (int k = 0; k < BIND_MAX_KEYS; k++) {
g_bind[a][k] = SDL_SCANCODE_UNKNOWN;
}
/* v0.4.0 M3: the GEPD preset fills the actions the user has not
* individually overridden (empty g_bindStr); FPS layout = the
* kBindDefs defaults, byte-identical to the pre-wave binds. */
const char *def = kBindDefs[a].def;
if (keyLayout == 1) {
/* v0.4.0 D374: resolve the effective string for this action.
* Precedence: an EXPLICIT per-key [Input.Bind] value (non-empty and
* different from the N64-layout default, or an explicit unbind of a
* bound-by-default action) wins over everything. Otherwise the
* layout preset is the effective default: GEPD (Input.Layout=0, the
* shipped default) or the N64-layout kBindDefs defaults (Layout=1,
* byte-identical to the pre-wave binds). A persisted ini value that
* merely equals the N64 default counts as "unset" -- the config
* migration writes every key on clean exit, so without this rule a
* pre-wave ini would mask the preset with its stale defaults. */
const char *src = NULL;
if (g_bindStr[a][0] != 0) {
if (strcmp(g_bindStr[a], kBindDefs[a].def) != 0)
src = g_bindStr[a]; /* explicit user bind */
} else if (kBindDefs[a].def[0] != 0) {
src = g_bindStr[a]; /* explicit unbind of a default-bound action */
}
const char *def;
if (src) {
def = src;
} else if (keyLayout == 1) {
def = kBindDefs[a].def; /* N64 layout */
} else {
const char *preset = kGepdPreset[a];
if (preset) def = preset;
def = preset ? preset : kBindDefs[a].def;
}
char buf[64];
strncpy(buf, g_bindStr[a][0] ? g_bindStr[a] : def, sizeof(buf) - 1);
strncpy(buf, def, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = 0;
int hadInput = (buf[0] != 0); /* before strtok clobbers buf */
/* Warn only for an explicitly-provided string (g_bindStr) that
* yields no valid keys; intentionally-empty preset/default strings
* (GEPD Fire, unbound Reload/Crouch in the N64 layout) are silent. */
int hadInput = (def == g_bindStr[a] && g_bindStr[a][0] != 0);
int n = 0;
for (char *tok = strtok(buf, ","); tok && n < BIND_MAX_KEYS; tok = strtok(NULL, ",")) {
@@ -973,7 +1003,7 @@ void inputLayoutApply(void)
s_crouchHeldPrev = 0;
inputRebuildBinds();
sysLogPrintf(LOG_INFO, "input: key layout %s, crouch %s applied",
keyLayout ? "GEPD" : "FPS", crouchMode ? "toggle" : "hold");
keyLayout ? "N64" : "GEPD (default)", crouchMode ? "toggle" : "hold");
}
static int actHeld(const Uint8 *ks, int act)
+16 -6
View File
@@ -99,9 +99,10 @@ static const char *const kCrosshairColor[] = {
"White", "Green", "Red", "Blue", "Yellow", "Cyan", "Magenta",
NULL,
};
/* M3: key-layout preset (0 = the FPS default binds, byte-identical to the
* current defaults; 1 = the GEPD mouse-injector layout) + crouch bind mode */
static const char *const kKeyLayout[] = { "FPS (default)", "GEPD", NULL };
/* D374: key-layout preset -- 0 = the GEPD layout (the default: it is the
* natural mouse/FPS layout and the N64 never had a keyboard), 1 = the
* N64-era keyboard binds (byte-identical to the pre-wave defaults) */
static const char *const kKeyLayout[] = { "Default", "N64", NULL };
/* 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
* throttle down from there, never past it, and throttling it below 30
@@ -203,9 +204,10 @@ static struct Row rows[] = {
{ .key="Input.PadTriggerPct", .label="Trigger threshold", .kind=ROW_SLIDER, .step=1 },
/* v0.4.0 M3 (modern options wave, D371): the GEPD mouse-injector
* key-layout preset (docs/dev/notes/GEPORT-REFERENCE-DEEPDIVE.md
* section 7.3) + the crouch bind's fire mode. Turok standard: these are
* section 7.1) + the crouch bind's fire mode. Turok standard: these are
* control bindings, so they live in INPUT -- no provenance bucket.
* Defaults are the N64-original FPS layout / hold. */
* D374: the GEPD layout is the default (a mouse FPS layout is the
* natural default; the N64 had no keyboard); crouch defaults to hold. */
{ .key="Input.Layout", .label="Key layout", .kind=ROW_ENUM, .step=1, .names=kKeyLayout },
{ .key="Input.CrouchMode", .label="Crouch mode", .kind=ROW_ENUM, .step=1, .names=kHold },
{ .key="__ResetInput", .label="Reset to defaults", .kind=ROW_ACTION },
@@ -271,6 +273,12 @@ static struct Row rows[] = {
* Legacy AutoFov ini keys remain supported but no longer hide sliders. */
{ .key="Video.DrawDistance", .label="Draw distance", .kind=ROW_SLIDER, .step=25, .uiMin=100, .uiMax=400 },
{ .key="Video.LodDistance", .label="LOD distance", .kind=ROW_SLIDER, .step=25, .uiMin=100, .uiMax=400 },
/* v0.4.0 M2 (D373, rule-2 sign-off PENDING): in-game crosshair
* on/off + tint (gunfire.c gunDrawSight, #ifdef PORT). 0/white =
* the N64 always-on crosshair (default); off and the tints are
* opt-in. */
{ .key="Video.CrosshairHide", .label="Crosshair", .kind=ROW_TOGGLE, .step=1, .names=kOnOffRev },
{ .key="Video.CrosshairColor", .label="Crosshair colour", .kind=ROW_ENUM, .step=1, .names=kCrosshairColor },
/* D304: the per-mode aim/turn-sensitivity sliders and the "Link" toggle
* that papered over their decoupling risk were pulled from the menu
* (user feedback after the D304 widening); the ONE master
@@ -912,7 +920,7 @@ static const struct { const char *key; double def; } kResetDefaults[] = {
{ "Input.PadLookInvertY", 0 }, /* = 0 */
{ "Input.PadDeadzone", 7000 },/* = STICK_DEADZONE (7000) */
{ "Input.PadTriggerPct", 23 }, /* = 23 */
{ "Input.Layout", 0 }, /* = 0 (FPS defaults) */
{ "Input.Layout", 0 }, /* = 0 (GEPD default layout, D374) */
{ "Input.CrouchMode", 0 }, /* = 0 (hold) */
/* GRAPHICS (port/src/video.c initializers) */
{ "Video.MSAA", 2 }, /* = 2 */
@@ -925,6 +933,8 @@ static const struct { const char *key; double def; } kResetDefaults[] = {
{ "Video.SafeAreaCrop", 1 }, /* = 1 */
{ "Video.DrawDistance", 250 }, /* midpoint: 50/100 */
{ "Video.LodDistance", 250 }, /* midpoint: 50/100 */
{ "Video.CrosshairHide", 0 }, /* = 0 (on, N64) */
{ "Video.CrosshairColor", 0 }, /* = 0 (white) */
/* GAMEPLAY ini rows (port/src/video.c initializers) */
{ "Game.SkipIntro", 0 }, /* = 0 */
{ "Game.NoHitFlash", 0 }, /* = 0 */
+28
View File
@@ -103,6 +103,32 @@ s32 portSkipIntro = 0;
* original damage flash. */
s32 portNoHitFlash = 0;
/* v0.4.0 M2 (D373, rule-2 sign-off PENDING): in-game crosshair on/off +
* tint (gunfire.c gunDrawSight, #ifdef PORT). 0 = the N64 always-on
* white crosshair (default); hide is the opt-in off state. */
s32 portCrosshairHide = 0;
static int cfgCrosshairColor = 0; /* 0 = white (identity) .. 6, see kTints */
/* Port-provided crosshair tint for gunfire.c (M2). Index 0 is the
* N64 white (0xFF, 0xFF, 0xFF) so the default render is untouched. */
void portCrosshairTint(s32 *r, s32 *g, s32 *b)
{
static const unsigned char kTints[7][3] = {
{ 0xFF, 0xFF, 0xFF }, /* White (N64) */
{ 0x40, 0xFF, 0x40 }, /* Green */
{ 0xFF, 0x40, 0x40 }, /* Red */
{ 0x40, 0x40, 0xFF }, /* Blue */
{ 0xFF, 0xFF, 0x40 }, /* Yellow */
{ 0x40, 0xFF, 0xFF }, /* Cyan */
{ 0xFF, 0x40, 0xFF }, /* Magenta */
};
if (cfgCrosshairColor < 0 || cfgCrosshairColor > 6)
cfgCrosshairColor = 0;
*r = (s32)kTints[cfgCrosshairColor][0];
*g = (s32)kTints[cfgCrosshairColor][1];
*b = (s32)kTints[cfgCrosshairColor][2];
}
/* D257: Game.AllUnlocked — everything-unlocked goodie, OFF by default
* (faithful N64 progression: levels unlock as you complete them). Consumed
* once at startup by main.c, which sets the game's own RAM unlock flags
@@ -346,6 +372,8 @@ PD_CONSTRUCTOR static void videoConfigInit(void)
configRegisterFloat("Game.ScreenShakeIntensity", &portScreenShakeScale, 0.0f, 10.0f);
configRegisterInt("Game.SkipIntro", &portSkipIntro, 0, 1);
configRegisterInt("Game.NoHitFlash", &portNoHitFlash, 0, 1);
configRegisterInt("Video.CrosshairHide", &portCrosshairHide, 0, 1); /* v0.4.0 M2 (D373) */
configRegisterInt("Video.CrosshairColor", &cfgCrosshairColor, 0, 6); /* v0.4.0 M2 (D373) */
configRegisterInt("Game.AllUnlocked", &portAllUnlocked, 0, 1);
configRegisterInt("Video.VSync", &cfgVSync, 0, 1);
configRegisterInt("Video.FpsCap", &cfgFpsCap, 0, 1000);