diff --git a/docs/dev/findings-index.csv b/docs/dev/findings-index.csv index 2fb0f313..34ea3203 100644 --- a/docs/dev/findings-index.csv +++ b/docs/dev/findings-index.csv @@ -249,3 +249,5 @@ D369,FIXED,Remove F10 row boxes/strips entirely (2026-09-27).,FIXED (awaiting li D370,PARTIAL,F10 distance/volume drags hurt frame rate (2026-09-27).,PARTIAL (user live test): D371,FIXED,"GEPD key-layout preset + reload/crouch bindings, v0.4.0 modern options wave M3 (2026-09-27).",FIXED (headless-verified; awaiting user live accept): D372,FIXED,"Low-end perf preset (v0.4.0 modern options wave M5, 2026-09-27).",FIXED (headless-verified; awaiting user live accept): +D373,FIXED,"In-game crosshair on/off + colour (v0.4.0 modern options wave M2, 2026-09-27).",FIXED (user live-tested; rule-2 sign-off recorded 2026-09-27): +D374,FIXED,"GEPD becomes the default key layout; preset layering fix (v0.4.0 M3 playtest feedback, 2026-09-27).",FIXED (headless + user live-tested): diff --git a/docs/dev/findings.md b/docs/dev/findings.md index 02f8efc5..914c67f5 100644 --- a/docs/dev/findings.md +++ b/docs/dev/findings.md @@ -657,6 +657,8 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121). | D370 | **F10 distance/volume drags hurt frame rate (2026-09-27).** — full `## D370` entry at file tail | PARTIAL (user live test): mostly improved; rapid spam can still lower FPS. Unchanged-detent/audio and Draw/LOD reapply fixed; other image sliders still request full video pass (live log shows frequent FOV passes). No further churn without focused repro. | | D371 | **GEPD key-layout preset + reload/crouch bindings, v0.4.0 modern options wave M3 (2026-09-27).** full `## D371` entry at file tail | FIXED (headless-verified; awaiting user live accept): `Input.Layout` (0=FPS, 1=GEPD) + `Input.CrouchMode` (hold/toggle) in F10 INPUT; GEPD preset acts as per-key effective default under `[Input.Bind]` overrides; new IA_RELOAD/IA_CROUCH emit B (unbound by default). MODERN section dropped per D356 Turok-standard rule (rows land in functional INPUT). Boot/ini-round-trip/F10-page verified; in-game feel-check owed. | | D372 | **Low-end perf preset (v0.4.0 modern options wave M5, 2026-09-27).** full `## D372` entry at file tail | FIXED (headless-verified; awaiting user live accept): one-row `Video.LowEndMode` in F10 VIDEO; ON writes FpsCap 30 + MSAA x1 (restart), OFF restores compiled defaults (60/2). Registered key persists through orderly exit. | +| D373 | **In-game crosshair on/off + colour (v0.4.0 modern options wave M2, 2026-09-27).** full `## D373` entry at file tail | FIXED (user live-tested; rule-2 sign-off recorded 2026-09-27): `Video.CrosshairHide` (0 = on, N64) + `Video.CrosshairColor` (7 tints, 0 = white) in F10 GRAPHICS; #ifdef PORT hook in gunfire.c gunDrawSight (the wave's only rule-2 item). | +| D374 | **GEPD becomes the default key layout; preset layering fix (v0.4.0 M3 playtest feedback, 2026-09-27).** full `## D374` entry at file tail | FIXED (headless + user live-tested): GEPD playtest found Ctrl fired the gun (stale persisted [Input.Bind] Fire=Left Ctrl masked the preset) and the FPS default made no sense for a mouse FPS. D374: GEPD is now Input.Layout=0 (the default; N64 layout = 1); only EXPLICIT per-key overrides beat the preset. One-off ini flip: pre-D374 `Layout = 1` (ex-GEPD) is now 0. | 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 @@ -14386,3 +14388,85 @@ boots clean — row resolves, no "not registered" warning. `LowEndMode=1` survives an orderly `GE_QUITFRAME` exit. **Owed:** live F10 preset toggle (ON→FpsCap/MSAA written, FPS readout drops to 30), restart-for-MSAA check, PAL/JP. + +## D373 — In-game crosshair on/off + colour (v0.4.0 modern options wave, M2) (2026-09-27) + +**Spec:** `docs/dev/notes/MODERN-OPTIONS-PLAN.md` M2 — the wave's ONLY +rule-2 item (the port intentionally differs from N64 rendering when the +option is on; sign-off recorded 2026-09-27 via user direction to +implement + live test). + +**Implementation:** +- `port/src/gunfire.c` `gunDrawSight`: `#ifdef PORT` guard only. + `Video.CrosshairHide` → early return (no texSelect, no draw); + otherwise `portCrosshairTint()` supplies the RGB args that the N64 + hardcodes to 0xFF,0xFF,0xFF (alpha 0x6E unchanged). Non-PORT builds + keep the original literals byte-identical (local `extern`s inside the + function, the bondview2 `portNoHitFlash` pattern; single consumer, no + header declaration). +- `port/src/video.c`: `s32 portCrosshairHide` (non-static, D232 + pattern) + `portCrosshairTint()` — 7 named tints (index 0 = white = + the N64 identity), `Game`-section registration `Video.CrosshairHide` + (0/1) + `Video.CrosshairColor` (0..6). +- `port/src/optionsoverlay.c`: GRAPHICS rows "Crosshair" (kOnOffRev, + 0 = On) + "Crosshair colour" (kCrosshairColor) + kResetDefaults. + +**Verification:** NTSC build clean. `GE_OPTIONSOVERLAY=4` (GRAPHICS +page) boots clean — both rows resolve. Headless level captures (dam, +`-level_33`) with hide/red-tint configs: no crash; the crosshair is +suppressed in cutscene frames (gunDrawSight only draws in live +gameplay), so the visual A/B was done by the user: **crosshair shows in +normal gameplay (user-confirmed 2026-09-27, "crosshair showed up")**. +Defaults (hide=0, colour=0) leave the render byte-identical to the +pre-wave tree. `betacrosshairimage` confirmed dead (plan §M2) — one +hook covers in-level rendering. + +## D374 — GEPD becomes the default key layout; preset layering fix (v0.4.0 M3 playtest feedback, 2026-09-27) + +**Trigger:** first GEPD playtest (user, 2026-09-27): "Crouch is broken, +in GEPD mode ctrl shoots the gun" + "why is FPS different than GEPD? GE +is a first person shooter ... make [GEPD] the default and call it +default." + +**Diagnosis (two distinct bugs, one user-visible symptom):** +1. The M3 "preset as effective default" only applied to EMPTY + `g_bindStr`. But the config migration writes EVERY bind key into the + ini on clean exit, so any pre-existing ini carried the full set of + persisted N64-layout defaults (`Fire = Left Ctrl`, `Action = + Space,Z,E`, ...) — all non-empty — and the preset was silently dead + for real users. Switching to GEPD left `Fire = Left Ctrl` in force + while the preset added `Crouch = Left Ctrl` → **Ctrl fired and + crouched at once**. +2. Naming/expectation: in the GEPD scheme (DEEPDIVE §7.1) Q = A button + (accept/next weapon), E = B button (use/cancel/crouch/reload). The + stale ini's `Action = Space,Z,E` kept E on the A button (weapon + cycle), not B (use) — the user correctly expected E = USE. + +**Fix (user decision 2026-09-27; port-layer only, zero game-logic +change):** +- **GEPD is now the DEFAULT layout** (`Input.Layout`: 0 = GEPD — the + natural mouse/FPS default; the N64 never had a keyboard, so the old + "FPS" default was always a port artifact — 1 = the N64-era keyboard + binds, byte-identical to the pre-wave set, one click away). F10 row + now reads "Default" / "N64". +- **True effective-default semantics** (`inputRebuildBinds`, D374 + precedence): an EXPLICIT per-key `[Input.Bind]` value (non-empty and + ≠ the N64 default, or an explicit unbind of a default-bound action) + wins; a persisted value that merely equals the N64 default counts as + UNSET, so the layout preset fills it. With this, the user's existing + ini (full of persisted defaults) gets the clean GEPD preset: + Fire="" (LMB/RMB fire/aim), Crouch=Left Ctrl, Reload=R, Action=Q + (A), Cancel=E (B=use) — no Ctrl conflict. +- Boot log line: `input: layout GEPD (default)/N64, crouch mode ...` + (verifiable in `ge007.log` without an F10 screenshot). +- **One-off semantics flip:** an ini with the pre-D374 `Layout = 1` + (which meant GEPD) now means N64. No in-code migration marker exists + (the value is ambiguous); the dev ini was flipped to 0 by hand — + note it in the v0.4.0 release notes for users who had selected GEPD. + +**Verification:** user ini (stale binds, `Layout = 0`): boot log +"layout GEPD (default), crouch mode hold", no "no valid keys" warnings, +clean exit persists `Layout = 0`. `Layout = 1`: "layout N64". Ctrl no +longers fires (Fire unset under the preset); crouch/reload/E-use per +preset. **Owed:** user re-playtest (Ctrl crouch, E use, Q cycle) before +the wave closes. diff --git a/port/src/input.c b/port/src/input.c index 96c9bb06..c7029e69 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -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) diff --git a/port/src/optionsoverlay.c b/port/src/optionsoverlay.c index 9883e71a..032a5de9 100644 --- a/port/src/optionsoverlay.c +++ b/port/src/optionsoverlay.c @@ -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 */ diff --git a/port/src/video.c b/port/src/video.c index e7c2d1d9..4ea6c081 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -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); diff --git a/src/game/gunfire.c b/src/game/gunfire.c index d6c11707..6e8c985c 100644 --- a/src/game/gunfire.c +++ b/src/game/gunfire.c @@ -6501,6 +6501,13 @@ void gunDrawSight(s32 *gdl) { * stack as the pointer high word → wild `gdl` write in texSetRenderMode * when the player raises the crosshair (right-mouse aim). §A. */ Gfx *sp54; + /* v0.4.0 M2 (D373, rule-2 sign-off PENDING): optional crosshair + * hide/tint (video.c). Default is the N64 always-on white: + * portCrosshairHide == 0 and portCrosshairTint() is the identity + * (0xFF, 0xFF, 0xFF). Non-PORT builds keep the original literals. */ + extern s32 portCrosshairHide; + extern void portCrosshairTint(s32 *r, s32 *g, s32 *b); + s32 crosshair_r, crosshair_g, crosshair_b; #else s32 sp54; #endif @@ -6509,6 +6516,9 @@ void gunDrawSight(s32 *gdl) { if ((g_CurrentPlayer->gunsightmode == 0) && (g_CurrentPlayer->mpmenuon == FALSE)) { #ifdef PORT + if (portCrosshairHide) + return; + portCrosshairTint(&crosshair_r, &crosshair_g, &crosshair_b); sp54 = *(Gfx **)gdl; texSelect(&sp54, crosshairimage, 4, 0, 0); #else @@ -6536,7 +6546,11 @@ void gunDrawSight(s32 *gdl) { #ifdef VERSION_EU halfedxy[1] = halfedxy[1] * g_GunSightAspectRatio; #endif +#ifdef PORT + display_image_at_position(&sp54, &xypos, &halfedxy, 0x20, 0x20, 0, 0, 1, crosshair_r, crosshair_g, crosshair_b, 0x6E, (crosshairimage->level > 0), 0); +#else display_image_at_position(&sp54, &xypos, &halfedxy, 0x20, 0x20, 0, 0, 1, 0xFF, 0xFF, 0xFF, 0x6E, (crosshairimage->level > 0), 0); +#endif #ifdef PORT *(Gfx **)gdl = sp54; #else