v0.5.0 final pass: AI and Deck fixes (D565-D567), docs and site refresh

Fixes:
- D565: AI awareness no longer follows two player render settings. Fog
  distance is floored at 100 (below it the shortened clip hid guards from
  AI on-screen checks); the D466 gameplay fog cull is rescaled to the game's
  own FOV (identity at defaults).
- D566: Steam Deck Game Mode no longer shows the on-screen keyboard at
  launch (SDL text input stopped; screen-keyboard hint off).
- D567: opening PC Options from the front end with a pad no longer drags
  the game's crosshair to the top-left corner.

Docs and site:
- README News/Status/Features/controls brought up to date; the unpublished
  v0.4.1 work is folded into v0.5.0 everywhere; stats to v0.5.0.
- Release notes reordered: player-facing highlights first, finding labels
  and verification at the bottom.
- Site status rewritten; favicon is now the exe icon (make_icon.py writes
  docs/favicon.ico).
- ROADMAP: AI review results, update-check follow-up, stale rows closed.

Verified: Windows + Linux builds; Windows pixel gate Surface 1 PASS;
Deck build deployed for the maintainer's Game Mode checks.
This commit is contained in:
James Dansereau committed 2026-10-06 21:06:48 -04:00
1 parent 4b710728bf
commit 1d15e5695a
17 files changed
+418 -242

No files matched your search

+195 -169
View File
@@ -12,66 +12,191 @@
Platforms: **Windows x86-64** and **Linux x86-64 (including Steam Deck)**.
Region: **NTSC-U (US) only**. See [Known issues](#known-issues).
Played on Windows and Steam Deck: campaign spot-checks, 2-4 player
split-screen and controller-only sessions.
## Highlights
The headline is **one real options system**: both options
screens merged into a single menu, laid out like the Perfect Dark PC port's,
with the game's own N64 control styles as a per-seat preset, emulator save
files that load directly, and a scalable HUD overlay. A round of fidelity
fixes, checked frame-by-frame against the N64 game, rounds out the feature
list.
This is the first release since v0.4.0. It includes everything that was
staged as v0.4.1, which was never published on its own.
- **2-4 player split-screen.** The game's multiplayer runs with a pad per
player, on every map, with each seat keeping its own controls.
- **One options menu.** The file-select **PC Options** entry and the F10 overlay
are now the same menu, laid out like the Perfect Dark PC port's, with
checkboxes, sliders and dropdowns. The game's own crosshair is the mouse
pointer, long pages scroll, and a tip explains the selected option.
- **The game's N64 control styles, per player.** Pick **Original** to use the
game's own styles 1.1-2.4; each seat keeps its own, saved with the Bond file.
- **Emulator saves load directly.** Copy a Project64, mupen or 1964 save in as
`data/ge007.eep` and it is converted on first launch.
- **Fog and haze closer to the N64.** Ground fog no longer chunks away tile by
tile, the sky fades into fog at the horizon, and the haze around Bond stays
steady as he moves. A new **Fog distance** setting (100-800%, 100% = N64) is separate
from Draw distance, and both apply live.
- **Fixes you can see:** the Dam ending camera swivels onto Bond as on the N64,
and rockets no longer pass
through the ground.
- **New settings:** fullscreen mode, center window, crosshair opacity and
crosshair colour by health, a scalable HUD overlay, and an optional update
check (off by default).
Played on Windows and Steam Deck: campaign spot-checks, 2-4 player split-screen
and controller-only sessions.
---
## New features
## What's new
### One options menu, PD-style layout (D504, D519)
### Options menu
- The file-select **PC Options** entry now opens the same menu the F10 overlay
shows — there is only one options UI, one place to learn (D519).
- Options are grouped into six sections in the Perfect Dark port's order
(Video, Sound, Controls, Game, …), with **checkboxes, sliders and dropdowns**
instead of the old numbered rows (D504).
- **Display mode** is a dropdown; **Backspace** goes back, matching the rest of
the game's menus (D504 follow-up).
- Six sections in the Perfect Dark port's order: Video, Audio, Mouse,
Controller, Key Bindings and Game. **Display mode** is a dropdown; **Backspace** goes back.
- The F10 overlay and FPS counter are the same on-screen size in the front end
and in a level, and **Game.HudScale** scales them with the in-game HUD.
Sliders and arrows are drawn smooth at any window size.
- The OS cursor stays visible over the overlay (no main-menu flicker),
right-click goes back, and the tip follows the hovered row.
- Clearer wording: 27 menu-wording edits, sliders with real units (percent,
frames, seconds, pixels), wrapped tips, one `Key: Action` hint style and
consistent names (Original / Extended, "Original layout"). *Skip intro* and
*All unlocked* are no longer marked experimental, and *All unlocked* applies
live. The game's own *Look up/down* row is gone; use *Invert look* on the
Mouse and Controller pages.
### Control styles: the game's own N64 layouts (D513, D516, D518)
### Controls
- **Control style** offers **Ext** (this port's scheme, unchanged) and
**Original**, which shows the game's own N64 styles 1.1–2.4 (D513, D516).
- The style is chosen **per seat** and saved with the Bond file, so each player
keeps their own (D518, D516).
- The Xbox-release presets (1.1 Jinx, 1.2 Christmas, 1.3 Frost, 1.4 Elektra) and
Custom rebinding from v0.4.x are unchanged. Preset names refer to the Xbox
- **Control style:** **Ext** (this port's scheme, unchanged) or **Original**
(the game's N64 styles 1.1-2.4), chosen per seat.
- The Xbox-release presets (1.1 Jinx, 1.2 Christmas, 1.3 Frost, 1.4 Elektra)
and Custom rebinding carry over. Preset names refer to the Xbox
release's control styles; this project is not affiliated with Microsoft or Rare.
- Here the right stick aims and the D-pad strafes, as on the N64; the Xbox
- The right stick aims and the D-pad strafes, as on the N64; the Xbox
release's "left stick aims the crosshair" and "D-pad copies the left stick"
behaviours are not reproduced.
- New profiles default to Crouch Toggle and Look ahead off (it fights mouse look
on PC). Existing untouched empty save folders get the same on first play;
played or customised profiles are not changed.
### Emulator save files load directly (D514)
### Saves
- An emulator-format `ge007.eep` sitting next to the executable is read on first
launch, so a save from Project64, mupen or 1964 continues in the port without
conversion. (Live playtest owed; the converter `eep_convert.py` still does
explicit two-way conversion.)
- An emulator-format `data/ge007.eep` is converted on first launch (the
original is kept as `ge007.eep.emulator.bak`). The converter `eep_convert.py` still does explicit two-way conversion.
(Live playtest owed.)
### HUD and overlay scaling (D510, D512)
### Picture and settings
- The F10 overlay and the FPS counter are now the **same on-screen size** on the
front end and inside a level (D510).
- **Game.HudScale** scales the F10 overlay and FPS counter along with the in-game
HUD (D512).
- Fog and near-plane clipping closer to the N64 (details under the technical
section below). Forced aspect ratios letterbox/pillarbox without re-cropping
the play area.
- Draw and LOD distance default to 2.0x (N64 = 1.0x), stick deadzone to 25%,
mouse sensitivity maximum is 4x. **FOV** is vertical degrees, 30-90, with
60 = the N64 view. "Guard AI uses full wide view" is now **Gameplay view
area** (Original / Extended). Old values migrate once; existing `ge007.ini`
files still load.
### New settings (D511)
### Window and updates
- **Fullscreen mode**, **Center window**, **crosshair opacity** and
**crosshair colour by health** — the four settings the Perfect Dark port has
that this port was missing.
- The title bar is static (the FPS readout is still in the F10 overlay) and
the window/taskbar icon is a new project mark.
- **Check for updates** (Game, **off by default**): when on, one HTTPS request
to GitHub per launch and an "Update available" row linking to the releases page.
### Also new since v0.4.0
- **Split-screen multiplayer** for 2-4 players, played live in 2P on every
multiplayer map and in 4P on Temple.
- Controller presets and rebinding, PlayStation and Nintendo button names,
master volume and audio-device selection.
- A steady 60 fps on low-end GPUs (tested on an Intel HD 3000 laptop).
- Fidelity fixes checked against the N64 game: AI visibility at long draw
distances, sniper zoom, turret pacing, Dam/Caverns water, weapons.
- Fixes for reported issues: fire rate (#114), the tank-crush sound loop
(#115), tank movement (#116), weapon sway (#117), recoil on some GPUs (#118)
and light fixtures that didn't react to shots (#119).
---
## Fidelity and stability fixes
## Install and upgrade
### Downloads
| File | Platform |
|---|---|
| `goldeneye-pc-port-<version>-win64.zip` | Windows x86-64 |
| `goldeneye-pc-port-<version>-linux-x86_64.tar.gz` | Linux x86-64 (incl. Steam Deck) |
Each contains the engine executable, a README, license texts, and the
one-time asset tool. **No ROM, no game assets.** The Windows bundle carries
its runtime DLLs and the Linux bundle carries SDL2, so nothing needs to be
installed first.
### Running it
You need your own **GoldenEye 007 N64 ROM** (US version, `.z64`).
1. Unpack the archive.
2. Make a `data/` folder next to the executable and put the ROM in it, named
`ge007.ntsc-final.z64`.
3. Run the executable from that folder. The first start takes a few extra
seconds while it generates its asset files from your ROM.
**Updating from an earlier version:** unpack into a new folder and copy your
ROM, `ge007.eep` (your progress) and `ge007.ini` (your settings) into its
`data/` folder. Don't copy the old `pcmodels-*` / `pccg-*` folders: the new
version makes its own.
**Steam Deck:** do the steps above on the Deck, then add the executable as a
non-Steam game. The options overlay opens with **Select** and is fully
controller-driven.
Full steps, controls and troubleshooting are in the bundled `README.md`.
---
## Known issues
| Issue | Impact | Workaround |
|---|---|---|
| PAL and JP ROMs aren't supported in release packages | NTSC-U only | Use an NTSC-U ROM. Both regions convert, build and boot from source; packaging is still open |
| Changing aspect ratio inside a level can briefly glitch the gun/hand model, rarely | Cosmetic, one-off | Change the ratio from the front-end PC Options, or accept it |
| No macOS or ARM builds | Platform | — |
| Saves from v0.4.0 and earlier can hold fake unlocks from `All unlocked` | Save data | Not repaired automatically. Since v0.5.0 the option never writes the save; keep a backup of `data/ge007.eep` from before you used it |
| The first frame of a level takes a little longer while its textures upload | Brief FPS-counter dip | None needed |
| Far objects almost fully in fog are now hidden as on the N64, except in widescreen where a faint distant building edge can still show (e.g. Surface's dish from the start area); 4:3 matches the N64 | Cosmetic | Higher Draw/LOD distance shows more |
The full list, with workarounds, is the
[known-issues table](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/docs/ROADMAP.md#known-issues).
---
## Fixes and changes, with finding labels
Menu and settings work:
- One options UI: the file-select entry opens the F10 menu (D519). Six
PD-ordered sections with checkboxes, sliders and dropdowns (D504); display
mode dropdown and Backspace-back (D504 follow-up).
- Control styles: Ext / Original with the N64 styles 1.1-2.4 (D513, D516),
chosen per seat and saved with the Bond file (D518, D516).
- Emulator `ge007.eep` import (D514).
- F10 overlay and FPS counter match in size front-end vs level (D510); HudScale
covers them (D512).
- Fullscreen mode, Center window, crosshair opacity and crosshair colour by
health: the four settings the Perfect Dark port had that this port lacked (D511).
- Wording, units, tips and spelling: D505, D506, D507; settings wording pass
and tip wrapping (D554); Look up/down row removed (D564).
- Settings standardised: defaults, FOV in vertical degrees, Gameplay view area (D546).
- Optional update check (D551). All unlocked applies live (D547).
- Crosshair mouse pointer and scrollbar (D555, D556); long tips no longer cut
off inside a level (D558). New defaults: Crouch Toggle, Look ahead off (D556,
D557); same for untouched empty save folders (D559).
- F10 overlay mouse behaviour (D544). Static title bar and new icon (D550).
- Overlay slider wedges, markers and dropdown arrows used to step in whole
canvas pixels and grew visibly at large window sizes; now smooth (D520).
Holding left/right on a Bond settings row no longer drops the FPS counter (D517).
- Watch menu: closing the in-level **Watch** menu saves the watch's own screen
size and ratio, which no longer fight the front-end **Aspect ratio** setting;
the earlier findings-log note was corrected (D349).
Rendering and gameplay fidelity:
- **Dam ending camera:** the first shot of the ending cutscene swivels up onto
Bond again, as on the N64; an old port workaround snapped it straight onto
@@ -98,114 +223,48 @@ list.
hold-off on menu A/B/Start and a single back action per press are now in
place. This is a mitigation: the exact cause is unconfirmed (the Deck
re-check passed) (D541).
- **Fog:** objects far in fog are hidden as on the N64 (fog snap); in widescreen
- **Fog snap:** objects far in fog are hidden as on the N64; in widescreen
the wider view can still show a faint distant building edge (e.g. Surface's
dish from the start area) — 4:3 matches the N64 (D503).
- **Aspect ratio:** forced ratios now letterbox/pillarbox without re-cropping the
dish from the start area); 4:3 matches the N64 (D503).
- **Aspect ratio:** forced ratios letterbox/pillarbox without re-cropping the
play area (D508); the rare gun/hand model glitch after changing ratio
mid-level is largely fixed, a rare remainder is logged (D509).
- **Watch menu:** closing the in-level **Watch** menu now saves the watch's own
screen size and ratio, and they no longer fight the front-end **Aspect ratio**
setting; the earlier note in the findings log was corrected (D349).
- **Overlay controls:** slider wedges, slider markers and dropdown arrows no
longer step in whole canvas pixels (which grew visibly at large window sizes);
they are drawn smooth at every size (D520).
- **FPS counter:** holding left/right on a Bond settings row no longer drops the
FPS counter (D517).
- **Build:** a fresh build directory no longer produces an untagged executable
name (D515).
- **Tooling:** the asset converter's argument quoting and sidecar size check are
tightened; the CI cache actions no longer carry stale ROM paths. The
reference-frame tooling is now non-destructive and drift-free: a verification sweep used to
overwrite your own `data/ge007.ini` and leave the previous level's save file
behind, and now pins both idempotently (your ini and save are restored whatever
the run does); the capture helper reads its frame windows out of the gate instead
of a hardcoded copy that had gone stale (D524). The gate's recipe was re-based
too: per-level windows that sit in settled gameplay rather than inside the intro
flyby, and the save file pinned present (D522, D523).
- **Harness:** the debug capture/launch env vars are documented — `GE_PCDUMP` must be
`first-last:step` (a colon where the dash belongs silently dumps every frame, D527),
and a `GE_STARTMENU` boot skips the EEPROM import, so the imported-save test must run
from a normal boot (D528). A per-triangle draw-state census probe
(`GE_D526`/`GE_D526BOX`/`GE_D526MAX`) is available for transparency/texture triage
(D526; the P13 Dam-ending grate show-through it targeted was confirmed faithful N64
behaviour on 1964/GEPD, so no change shipped).
---
Build, tooling and harness:
## The small stuff
- A fresh build directory no longer produces an untagged executable name (D515).
- The asset converter's argument quoting and sidecar size check are
tightened; the CI cache actions no longer carry stale ROM paths.
- The reference-frame tooling is non-destructive and drift-free: a verification
sweep used to overwrite your own `data/ge007.ini` and leave the previous
level's save file behind, and now pins both idempotently (your ini and save
are restored whatever the run does); the capture helper reads its frame
windows out of the gate instead of a stale hardcoded copy (D524). The gate's
recipe was re-based: per-level windows in settled gameplay rather than the
intro flyby, and the save file pinned present (D522, D523).
- Debug env vars are documented: `GE_PCDUMP` must be `first-last:step` (a colon
where the dash belongs silently dumps every frame, D527), and a
`GE_STARTMENU` boot skips the EEPROM import, so the imported-save test must
run from a normal boot (D528). A per-triangle draw-state census probe
(`GE_D526`/`GE_D526BOX`/`GE_D526MAX`) is available for transparency/texture
triage (D526; the P13 Dam-ending grate show-through it targeted was confirmed
faithful N64 behaviour on 1964/GEPD, so no change shipped).
27 menu-wording edits across both menus (option names say what they do, not
what the internal variable is called, D505); sliders carrying **real units** —
percent, frames, seconds, pixels — standardised across the two menus (D506);
a **one-line description** of the selected option in the same menu (D507);
and menu spelling standardised to one convention across both menus.
- **Settings standardised (D546):** Draw and LOD distance default to 2.0x
(N64 = 1.0x), stick deadzone to 25%, and the mouse sensitivity maximum is 4x.
**FOV** is now vertical degrees, 30-90, with 60 = the N64 view. The old
"Guard AI uses full wide view" row is now **Gameplay view area**
(Original / Extended). Untouched old values migrate once; existing
`ge007.ini` files still load.
- **Optional update check (D551):** a new **Check for updates** option in Game,
**off by default**. When on, it makes one HTTPS request to GitHub per launch
and shows an "Update available" row linking to the releases page.
- **Settings menu wording pass (D554):** clearer tips that wrap to two lines
instead of being cut off, one `Key: Action` style for the control hints,
consistent casing and names (Original / Extended, "Original layout").
*Skip intro* and *All unlocked* are no longer marked experimental.
The game's own *Look up/down* option is gone from the menu; use *Invert look*
on the Mouse and Controller pages (D564).
- **Crosshair mouse pointer and scrollbar in the settings menu (D555, D556):**
the game's own crosshair is the pointer while F10 / PC Options is open (Mouse →
Crosshair pointer to turn it off), long pages get a draggable scrollbar, and
tips are kept only where a setting needs explaining. Long tips are no longer
cut off inside a level (D558).
- **New defaults (D556, D557):** Crouch mode defaults to Toggle (new installs and
Reset to defaults), and new profiles start with Look ahead off, which fights
mouse look on PC; an existing save's untouched empty folders (no progress,
factory options) get the same when first played (D559). Played or
customised profiles and existing settings are not changed.
- **All unlocked** now applies live from the options menu, with no restart
(D547).
- **F10 overlay mouse:** the OS cursor is always shown (no more flicker on the
main menu), right-click goes back, and the tip line follows the hovered row
(D544).
- **Window:** the title bar is now static (no per-second "NN fps" refresh; the
FPS readout is still in the F10 overlay), and the window and taskbar icon is a
new project mark instead of a game still (D550). Live icon/title check owed.
---
## Known issues
| Issue | Impact | Workaround |
|---|---|---|
| PAL and JP ROMs aren't supported in release packages | NTSC-U only | Use an NTSC-U ROM. Both regions convert, build and boot from source; packaging is still open |
| Changing aspect ratio inside a level can briefly glitch the gun/hand model, rarely | Cosmetic, one-off | Change the ratio from the front-end PC Options, or accept it |
| No macOS or ARM builds | Platform | — |
| Saves from builds before v0.4.1 can hold fake unlocks from `All unlocked` | Save data | Not repaired automatically. Since v0.4.1 the option never writes the save; keep a backup of `data/ge007.eep` from before you used it |
| The first frame of a level takes a little longer while its textures upload | Brief FPS-counter dip | None needed |
| Far objects almost fully in fog are now hidden as on the N64, except in widescreen where a faint distant building edge can still show (e.g. Surface's dish from the start area); 4:3 matches the N64 | Cosmetic | Higher Draw/LOD distance shows more |
The full list, with workarounds, is the
[known-issues table](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/docs/ROADMAP.md#known-issues).
## Verification
**Reference-frame gate for this release:** Windows, Linux and Steam Deck each
carry the full 21-level reference-frame set (63 frames each) at the same stems,
re-captured for this release's fog and near-plane changes and confirmed by two
independent capture passes per platform. The full pixel gate is green on all
three against their own goldens on the final build: Windows 21/21, Linux
(Intel HD 3000) 21/21 and Steam Deck 21/21. The recipe pins the run for you: the save file's
CONTENT is pinned (the gate installs its own canonical save per level, the same
way it pins the display ini — D529) and the PRNG seed is hard-pinned (a stray
`GE_RSEED` in your environment warns and is ignored rather than re-seeding the
gate — D532), so a gate run and a capture run see the same starting state. The
cross-platform spread on the shipped sets (0.188-4.553% of pixels over tol 2 on
the 20 non-Cuba levels) is informational only — it is not a cross-platform
pixel-parity claim.
---
(Intel HD 3000) 21/21 and Steam Deck 21/21. The recipe pins the run for you: the
save file's CONTENT is pinned (the gate installs its own canonical save per
level, the same way it pins the display ini — D529) and the PRNG seed is
hard-pinned (a stray `GE_RSEED` in your environment warns and is ignored rather
than re-seeding the gate — D532), so a gate run and a capture run see the same
starting state. The cross-platform spread on the shipped sets (0.188-4.553% of
pixels over tol 2 on the 20 non-Cuba levels) is informational only — it is not
a cross-platform pixel-parity claim.
## Thanks
@@ -214,39 +273,6 @@ Outside contributions merged for this release: dolent (PRs #120–#122), MST246
TenebrusoM (DexDrive / the D514 save-format sample), plus reporter credits on
the issue numbers named above.
## Downloads
| File | Platform |
|---|---|
| `goldeneye-pc-port-<version>-win64.zip` | Windows x86-64 |
| `goldeneye-pc-port-<version>-linux-x86_64.tar.gz` | Linux x86-64 (incl. Steam Deck) |
Each contains the engine executable, a README, license texts, and the
one-time asset tool. **No ROM, no game assets.** The Windows bundle carries
its runtime DLLs and the Linux bundle carries SDL2, so nothing needs to be
installed first.
## Running it
You need your own **GoldenEye 007 N64 ROM** (US version, `.z64`).
1. Unpack the archive.
2. Make a `data/` folder next to the executable and put the ROM in it, named
`ge007.ntsc-final.z64`.
3. Run the executable from that folder. The first start takes a few extra
seconds while it generates its asset files from your ROM.
**Updating from an earlier version:** unpack into a new folder and copy your
ROM, `ge007.eep` (your progress) and `ge007.ini` (your settings) into its
`data/` folder. Don't copy the old `pcmodels-*` / `pccg-*` folders: the new
version makes its own.
**Steam Deck:** do the steps above on the Deck, then add the executable as a
non-Steam game. The options overlay opens with **Select** and is fully
controller-driven.
Full steps, controls and troubleshooting are in the bundled `README.md`.
## Verify the download
```
+51 -39
View File
@@ -1,7 +1,5 @@
# GoldenEye 007 PC Port
<p align="center"><img src="docs/img/icon/ge007-icon.png" width="96" alt="project mark: a generic version of the game's default aim cross -- a circle with N/S/E/W lines crossing its edge (original generated art, see tools_pc/make_icon.py -- no game content)"></p>
[![CI](https://github.com/jkdansereau/goldeneye-pc-port/actions/workflows/ci.yml/badge.svg)](https://github.com/jkdansereau/goldeneye-pc-port/actions/workflows/ci.yml)
[![Latest release](https://img.shields.io/github/v/release/jkdansereau/goldeneye-pc-port?include_prereleases&label=download)](https://github.com/jkdansereau/goldeneye-pc-port/releases)
![Platforms](https://img.shields.io/badge/platforms-Windows%20%7C%20Linux%20%7C%20Steam%20Deck-blue)
@@ -50,23 +48,30 @@ project is as much a study of that process as it is a port. See
## News
- **2026-10-05** — **v0.5.0**: one real options system: a
single menu (laid out like the Perfect Dark port's) covering every setting,
the game's own N64 control styles as a per-seat preset, and your emulator
saves loading directly; a scalable HUD overlay; fullscreen, window-centring
and crosshair settings; and a fidelity round checked frame-by-frame against
the N64 game (fog, aspect-ratio letterboxing, the Watch menu's own
settings). The reference-frame gate was re-based on both platforms (21
levels, 63 frames each). Plus the small stuff: a menu wording, units and
help-text pass, standardised menu spelling, and antialiased overlay
controls.
[Release notes](https://github.com/jkdansereau/goldeneye-pc-port/releases/tag/v0.5.0).
- **v0.4.1**: 2–4 player split-screen multiplayer, controller presets and
rebinding, PlayStation/Nintendo button names, master volume and audio
device selection, a steady 60 fps on low-end GPUs, and fidelity fixes
checked against the N64 game (AI visibility at long draw distances, sniper
zoom, turret pacing, Dam/Caverns water, weapons).
[Release notes](https://github.com/jkdansereau/goldeneye-pc-port/releases).
- **2026-10-06** — **v0.5.0** ([release notes](https://github.com/jkdansereau/goldeneye-pc-port/releases/tag/v0.5.0)), the first release
since v0.4.0; it includes the v0.4.1 work, which was never published on
its own:
- **2–4 player split-screen multiplayer** on every multiplayer map, each
player with their own pad, controls and aim settings.
- **One options menu** for every setting, laid out like the Perfect Dark
port's, with the game's own crosshair as the mouse pointer. Pick the
game's own N64 control styles (1.1–2.4) per player, or the Xbox release's
presets with per-player pad rebinding; PlayStation and Nintendo pads show
their own button names.
- **Closer to the N64:** fog and haze (Surface 2's ground fog, the sky at
the horizon), automatic-weapon fire rate, sniper and camera zoom, Dam and
Caverns water, the Jungle boss fight's timing, guard visibility in
widescreen, and the Dam ending camera.
- **Fewer crashes and glitches:** a multiplayer crash with the crouched
rifle, rockets passing through the ground, and broken geometry around
Aztec's shuttle.
- **A steady 60 fps on low-end GPUs** (tested on an Intel HD 3000 laptop),
with lighter first-launch defaults on Atom/Celeron-class graphics.
- **Emulator saves load directly:** copy a 1964 or Project64 save in as
`data/ge007.eep` and it is converted on first launch.
- Also: more audio, video and control settings (master volume, audio device,
trilinear filtering, draw distance up to 800%, PC-friendly crouch and
look-ahead defaults), and controllers are picked up again when replugged.
- **2026-09-28** — **v0.4.0**: native widescreen, a complete aim system for
mouse and controller, in-game key rebinding, crosshair customization,
rumble-pak haptics, a rebuilt options overlay, and a broad fidelity-fix
@@ -136,7 +141,7 @@ resolution is wrong, set it under F10 → *Video → Resolution*.
| Aim mode | Right mouse / `LShift` | Left trigger / LB |
| Use / interact | `E` | A |
| Reload | `R` | X |
| Crouch | `LCtrl` | Left or right stick click |
| Crouch (toggles) | `LCtrl` | Left or right stick click |
| Cycle owned gadgets | Watch inventory | B |
| Next weapon | Mouse wheel down / `Q` | Y |
| Previous weapon | Mouse wheel up | — |
@@ -184,9 +189,11 @@ changes this). A controller unplugged mid-match keeps its player when
plugged back in.
**Options overlay with a controller** (also how it works on the Deck):
**Select** opens it, the D-pad or left stick moves between options, **A**
steps the selected option forward, **B** steps it back, and **Start** (or
Select again) closes. With a keyboard, use `F10` and the arrow keys/Enter.
**Select** opens it, the D-pad or left stick moves between rows and
left/right adjusts the selected value, **A** opens a page or toggles a row,
**B** goes back one page (and closes from the top), and **Start** (or Select
again) closes. With a keyboard, use `F10`, the arrow keys, Enter and
Backspace.
## Features
@@ -217,29 +224,33 @@ Select again) closes. With a keyboard, use `F10` and the arrow keys/Enter.
- **Full audio:** in-level music and sound effects, with music, FX and master
volume and a choice of output device.
- **An in-game options overlay** (F10 / pad Select) for all of the above,
saved automatically.
saved automatically; the game's crosshair is the mouse pointer, and
each page has a *Reset to defaults* row.
- **Faithful N64 progression by default.** Opt-in extras: *Skip intro* and
*All unlocked* (every level, 007 mode and the full cheat menu, without
touching your save), and *Check for updates* (off
by default; one request to GitHub per launch when on, see Security).
- **Saves in a plain file** next to the game, so backing up is a file copy.
- **Saves in a plain file** next to the game, so backing up is a file copy;
1964 and Project64 saves load directly ([details](#using-an-emulator-save)).
## Status
**Fully playable, with a small set of known caveats.** All 20 solo missions
and the end-of-campaign credits load, render and run crash-free; the full
campaign was playtested end to end at Agent difficulty on Windows, Linux and
real Steam Deck hardware for v0.4.0. Split-screen multiplayer was played live
in 2P on every MP map and in 4P on Temple.
<!-- MAINTAINER: after the v0.5.0 play session, add what it covered here. -->
and the end-of-campaign credits load, render and run crash-free. v0.5.0 was
played on Windows and Steam Deck (campaign spot-checks, 2–4 player
split-screen and controller-only sessions), and every level's reference
frames were compared pixel by pixel on Windows, Linux and Steam Deck. The
full campaign was last played end to end, at Agent difficulty on all three
platforms, for v0.4.0. Split-screen was played live in 2P on every
multiplayer map and in 4P on Temple.
**Known issues:** see the **[known-issues table](docs/ROADMAP.md#known-issues)**
(what you'll notice, impact, workarounds). The short version: NTSC-U ROMs
only in the release packages, and no macOS/ARM builds yet.
> ***All unlocked* never changes your save** since v0.4.1: it unlocks every
> ***All unlocked* never changes your save** since v0.5.0: it unlocks every
> level and cheat in memory only, and switching it off shows your real
> progress. Builds before v0.4.1 could write fake unlocks into the save, and
> progress. v0.4.0 and earlier could write fake unlocks into the save, and
> those are not repaired; if you used it on an older build, keep a backup of
> `data/ge007.eep`.
@@ -257,7 +268,7 @@ carries a GitHub build-provenance attestation you can check with
**Options overlay:** press **F10** (pad: **Select**) in game or in the menus.
Changes are saved automatically. Most settings live in `ge007.ini`; the
ones that come from the game's own watch menu (look up/down, auto-aim, aim
ones that come from the game's own watch menu (auto-aim, aim
control, sight, look ahead, ammo on screen, screen size, screen ratio, music
and FX volume) are part of your save, as on the N64. Screen size (Full / Wide /
Cinema) and screen ratio (Normal / 16:9) combine with the PC **Aspect ratio**
@@ -294,7 +305,7 @@ MSAA = 2
TextureFilter = 1
NativeWidescreen = 1
FovScale = 100
DrawDistance = 250
DrawDistance = 200
[Audio]
MasterVolume = 100
@@ -412,11 +423,12 @@ The port was built by two coding agents, directed by one person part-time.
A local open-weight model (`unsloth/Qwen3.8-27B-GGUF` on one RTX 5090, via the
[pi](https://github.com/earendil-works/pi) agent) did the groundwork: build, boot chain,
software-RSP integration, asset pipeline, first frames. **Claude Code**
(Sonnet 5, Opus 5 for the hardest bugs) joined for the collaborative phase:
(Sonnet 5 and Opus 5, now 5.5; Opus for the hardest bugs) joined for the collaborative phase:
the 21-level sweep, the ABI finding catalog, SDL input, front end. The two
handed work back and forth through shared written notes. Up to v0.4.0: 43
days (16 Aug – 28 Sep), 1005 commits, 286 findings root-caused and logged
(`D1`–`D408`).
handed work back and forth through shared written notes. Up to v0.5.0: 51
days (16 Aug – 6 Oct), 1,537 commits (the public history squashes the
v0.4.1–v0.5.0 work into 17), and 419 findings root-caused and logged
(`D1`–`D564`).
The full write-up (timeline, handoff mechanism, effort breakdown, an honest
"what worked / what didn't"): [`docs/dev/agentic-development.md`](docs/dev/agentic-development.md).
@@ -685,4 +697,4 @@ is covered by [`NOTICE`](NOTICE), not by that license.
---
*Last updated 2026-10-05 — v0.5.0 · <a href="https://github.com/jkdansereau/goldeneye-pc-port">GitHub</a> · <a href="https://github.com/jkdansereau/goldeneye-pc-port/releases">Releases</a>*
*Last updated 2026-10-06 — v0.5.0 · <a href="https://github.com/jkdansereau/goldeneye-pc-port">GitHub</a> · <a href="https://github.com/jkdansereau/goldeneye-pc-port/releases">Releases</a>*
+4 -3
View File
@@ -119,7 +119,7 @@ below).
| PAL and JP ROMs aren't supported in release packages | NTSC-U only | Use an NTSC-U ROM. Both regions convert, build and boot from source (D258, D487, D488; see `docs/building.md`); packaging (per-region exe, CI matrix, converter region check) is still open | D258, #85, §1 |
| Changing Aspect ratio in a level (mostly Fill window to Original or a forced ratio) can briefly glitch the gun / hand model, rarely | Cosmetic, one-off | Change the ratio from the front-end PC Options, or accept it | D509 (frame hold fixed the common case; the rare remainder is logged, not investigated) |
| No macOS or ARM builds | Platform | — | #88, #95, #101, §4 |
| Saves from builds before v0.4.1 can hold fake unlocks from `All unlocked` | Save data | Not repaired automatically. Since v0.4.1 the option never writes the save; keep a backup of `data/ge007.eep` from before you used it | D442, D387 |
| Saves from v0.4.0 and earlier can hold fake unlocks from `All unlocked` | Save data | Not repaired automatically. Since v0.5.0 the option never writes the save; keep a backup of `data/ge007.eep` from before you used it | D442, D387 |
| The first frame of a level takes a little longer while its textures upload | Brief FPS-counter dip | None needed | D475, D480 |
| Far objects almost fully in fog are now hidden as on the N64, except in widescreen, where the wider view can still show a faint distant building edge (e.g. Surface's dish from the start area). 4:3 matches the N64 | Cosmetic | None; higher Draw/LOD distance shows more | D503, §5c |
@@ -139,6 +139,7 @@ below).
| Item | Status | Refs | Notes |
|---|---|---|---|
| Third-person Bond offset residual | partial; intro puppet explained (2026-10-02) | D173, D292 | Mostly fixed. On the level-start puppet the variance is tick/PRNG-dependent idle timing (D13 class, faithful, no sign-off requested); one 1-frame first-tick Y transient is untraced. If the residual is seen elsewhere (cutscene body model), the maintainer should note where. |
| AI awareness follows two non-default render settings | fixed 2026-10-06 (D565: Fog distance floor 100; AI fog cull rescaled to the game's FOV) | D565, D466, D468, D540, D222 | AI review of v0.4.0..v0.5.0 (interpreter, movement/timing, visibility/combat): no regression at shipped settings (Draw 2.0x, Fog 1.0x, FOV 60, native widescreen). Two leaks of player render settings into AI awareness remain: **(1) `Video.FogDistance` below 100** shrinks the far clip (`bgfog.c fogLoadCurrentEnvironment`, clip = FarFog x min(Fog, Draw)). AI on-screen checks require the render `PROPFLAG_ONSCREEN` (`drawdistgameplay.c portPropGameplayOnScreen`), so guards beyond the shortened clip stop counting as on screen; at Draw 1.0x `portD466Active()` is off and sight range (`fogGetScaledFarFogIntensitySquared`) shrinks too. Effect: guards notice Bond / on-screen triggers fire later than the N64. Fix: treat Fog < 1.0 as D466-active and keep the authored room/fog pass independent of the render clip. **(2) FOV other than 60 (`Video.FovScale` != 100, or native widescreen off at a wide aspect)**: the gameplay fog-cull `propobj.c portSub7F054C58Gameplay` uses `getPlayer_c_lodscalez()`, which grows with the rendered FOV (D222), so at a wider FOV far fogged positions drop out of the AI on-screen verdict sooner (narrower: later). Fix: divide out the port FOV factor (as `portFovYScaleFactor`), keeping the game's own zoom FOV changes. Minor at defaults: the D466 verdict reuses the extended pass's room screen bbox (`posIsOnScreen`); at Fog 1.0x the clip is the authored far, so the two passes match. D491 (room-list portal seeds) and D431 (light-fixture hit scoring) were checked: both restore N64 data reads and only move AI toward the N64. |
| Dam ending cutscene | done (2026-10-06) | D526, D552 | Railing/grate transparency faithful (D526); first-shot swivel restored (D552, maintainer-verified). |
| Title-screen attract demo runs too fast; F10 box rescales while it plays | backlogged (after v0.5.0, maintainer 2026-10-04) | D87 (ramrom file struct); timing: D13, D248, D427, D451, D486 | **Reported 2026-10-04 (live pass):** attract plays visibly too fast; not investigated. Lead: it is a ramrom demo replay whose recordings carry a per-frame tick count, which the port's 60 fps / 1-tick pacing may override. Rule out PC causes, then compare with 1964. Same pass: the F10 box briefly rescaled during the demo (not reproduced; candidate fix = overlay reads fast3d's native viewport, parked locally). |
| Sniper rifle: zoom level and speed vs 1964 | verify | #136, D484, D485, D494 | Crouch: **D494** (2026-10-03) makes the PC crouch key crouch/stand freely with the sniper, as GEPD does (superseding D483's freeze); maintainer-verified. Zoom level (D484, 20 -> 7 degrees) and speed (D485, tick-scaled, Rule-2) fixed 2026-10-02. **Owed:** 1964 A/B of zoom level and speed; close #136 after it. |
@@ -220,7 +221,7 @@ Background research lives in the maintainer's local notes (gitignored):
| Emulator saves load directly in the game (no tool for import) | verify | D514, D492; `port/src/eepimport.c` called from `geEepromLoad`; D297 `legacycrc.c` same pattern | **Landed 2026-10-04 (D514).** Copying a 1964/Project64 `.eep` in as `data/ge007.eep` works: on first launch each region that validates in emulator format and not port format is converted in place (same rules as `eep_convert.py`); regions invalid in both are left to the game's wipe; port saves untouched; the original is backed up to `ge007.eep.emulator.bak`. Export stays with `eep_convert.py`. Headless verify 6/6 byte-identical to the reference. **Owed:** by-eye mission select after importing a real 1964 save. |
| DexDrive / GameFAQs `.n64` saves | idea (easy, post-1.0) | D514; sample `scratch/eepinv/gamefaqs_dexdrive_2001.eep` (local) | **Noted 2026-10-04.** Old GameFAQs GoldenEye saves are DexDrive Controller Pak dumps (`123-456-STD` header, then a 32 KB pak) whose note (game code `3BADD1E5`, 2 pages) holds the 512-byte cartridge EEPROM. Extracting it and zero-padding to 2048 bytes gives a valid emulator-format save (TenebrusoM sample: all 6 CRCs OK). Support = walk the note table, pull the note, pad, hand to the D514 importer (or an `eep_convert.py dexdrive-to-pc` subcommand). Not tested in game. |
| Title bar and window icon (no FPS counter; static "GoldenEye 007" title + GE-crosshair window icon) | done (v0.5.0 polish) | maintainer request 2026-10-17; D550; `port/src/video.c`, `port/fast3d/gfx_sdl2.cpp`, `cmake/icon/ge007.rc`; icon art = `docs/img/icon/ge007-icon.png` (`tools_pc/make_icon.py`) | **DONE 2026-10-17 (D550):** static title bar (live FPS stays on F10), `SDL_SetWindowIcon` from a generated 32x32 header, exe icon via `ge007.rc`. Original generated mark, no game imagery. Build-verified; maintainer live window/taskbar check owed. |
| Opt-in update check (`Game.CheckUpdates`, off by default) | verify | D551; `port/src/updatecheck.c` | **Landed 2026-10-06:** Game-page toggle; one HTTPS GET per launch to `/releases/latest` (no pre-releases); Windows loads `winhttp.dll` at runtime only. Live-verified (Win/Linux/Deck), security-reviewed. |
| Opt-in update check (`Game.CheckUpdates`, off by default) | verify | D551; `port/src/updatecheck.c` | **Landed 2026-10-06:** Game-page toggle; one HTTPS GET per launch to `/releases/latest` (no pre-releases); Windows loads `winhttp.dll` at runtime only. Live-verified (Win/Linux/Deck), security-reviewed. **Follow-up PR (2026-10-06):** (1) the Linux/Deck `curl` path reads into a 64 KB buffer and treats `curl`'s exit code as failure, so a `/releases/latest` response over 64 KB (long notes, many assets) silently gives no result even though `tag_name` is in the first ~1.5 KB; raise the cap and accept a full buffer (v0.4.0's response is 27 KB, so v0.5.0 is safe). (2) Validation matrix: offline harness for `versionNewer`/`extractTag` edge cases; throwaway builds with `GE007_VERSION` set to 0.3.0/0.4.0 against the live endpoint, Windows + Deck; a pre-release never prompts; after a publish, an older-version build shows the F10 row and opens the releases page; network-off and setting-off runs. |
### 5b. GE+ / Dab's-mod gameplay options (opt-in; touch game code)
@@ -278,7 +279,7 @@ and a stage loader.
| Flicker scan (A/B/A frame alternation) | parked (2026-10-03: tooling, nothing blocked on it; local spec `scratch/birdman64-rows-investigation.md` §4) | `GE_PCDUMP`, `GE_INPUTSCRIPT` | Dump **every** frame of a scripted run at low resolution and flag frame n when it differs from n-1 but matches n-2. For any old-vs-new pixel diff outside the golden gate, run a same-commit control first. Reference: Birdman64 `tools/flicker_scan.py`. |
| Release build-provenance attestation | verify | `.github/workflows/ci.yml` release job; `.github/SECURITY.md`; README Status section | **Implemented 2026-10-04:** SHA-pinned `actions/attest-build-provenance` attests `dist/*.zip[.sha256]` + `dist/*.tar.gz[.sha256]` in the tag-only release job (`id-token: write` + `attestations: write` on that job only). Backs SECURITY.md's "unsigned, but reproducible" stance with `gh attestation verify <file> --repo jkdansereau/goldeneye-pc-port`; documented in SECURITY.md and the README. **Owed:** the v0.5.0 tag build is the first real run; confirm the step passes and verification succeeds on a downloaded asset, then delete this row. |
| Self-hosted CI runner link failure | open | D244 | Needs a `pacman -Syu` on the runner (maintainer-only access). Release tag builds use GitHub runners, so it doesn't block a release. |
| Remove temporary scaffolding before a release | partial | [`dev/GE-ENV-PROBES.md`](dev/GE-ENV-PROBES.md), D302 | Passes 2026-09-30 to 2026-10-03 removed the closed-finding probe suites (registry in `GE-ENV-PROBES.md`, `gen_env_probes.py --check` passing); TEMP probes `GE_TESTSTYLE` / `GE_D516` removed 2026-10-04. **Left:** D104 (kept while D294 is in verify); the M-183/M-185 clamps, **in scope 2026-10-03 (maintainer)**: re-verify all scripted-camera cutscenes with the clamps compiled out (intro flyover, per-level endings incl. the Dam abseil), then delete both blocks in `model.c`. |
| Remove temporary scaffolding before a release | partial | [`dev/GE-ENV-PROBES.md`](dev/GE-ENV-PROBES.md), D302 | Passes 2026-09-30 to 2026-10-03 removed the closed-finding probe suites (registry in `GE-ENV-PROBES.md`, `gen_env_probes.py --check` passing); TEMP probes `GE_TESTSTYLE` / `GE_D516` removed 2026-10-04. **Left:** D104 (kept while D294 is in verify); the M-183/M-185 clamps were **deleted 2026-10-04** (`879f879a`, `model.c` pure decomp again; the M-189 root fix stays) and the cutscene re-check was covered by the 2026-10-05 Deck campaign playthrough on rc1 (level intros, endings incl. Facility and Dam, credits). |
| P12 U5 review of `tools_pc/**` (release-diff, B10) | partial | D531/D532/D533 | Reviewed 2026-10-05 (the unit that owed the P7 merge). **Blocker found + fixed (D531):** `capture_p7.sh`'s per-level re-pin restored the local save (see Golden baselines). **Should-fixes applied as D532 (tooling-only):** `verify.sh`'s `pin_ini_640x480` fails closed like `pin_eep`; `GOLDEN_SEED` hard-pinned with a warning for a stray `GE_RSEED`; `audiodebug.ps1`'s dead `-AB`/`-Old` switches removed. Box pixel verify done 2026-10-06 (see Golden baselines). |
| Findings log and doc size | partial | `tools_pc/docs_budget.py` | Budget checker (per-file and tier-1 token budgets; `--toc FILE`). `findings.md` is still about 2 MB (~500k tokens), so agents must keep using the index. Nothing blocks; trim only when a budget check fails. |
| Branch and PR housekeeping | open | — | 30 landed local branches pruned 2026-09-30 (tips in `prune-branches-2026-09-30.txt`, notes archive). **On hold by the maintainer (do not prune yet):** probe-only `d243-verify-local`, `investigate/d243-cutscene-race`, `park/d236-probes-m139`. Local `main` and `release/v0.4.1` are deliberately not pushed. PR #62 (mouse dt-decouple) stays held until mouse feel is fundamentally better. |
+5 -2
View File
@@ -13,7 +13,10 @@
<meta name="robots" content="max-image-preview:large">
<!-- Favicon: the project's own crosshair mark (tools_pc/make_icon.py),
not a game still -- original art, no derivative-work exposure. -->
<link rel="icon" type="image/png" href="{{ '/img/icon/ge007-icon.png' | relative_url }}">
<!-- favicon.ico is a byte copy of cmake/icon/ge007.ico (the exe icon, with
the hand-tuned 16/24/32 px variants); a browser-downscaled 512 px PNG
washes out at tab size. Re-copy it after running make_icon.py. -->
<link rel="icon" href="{{ '/favicon.ico' | relative_url }}" sizes="16x16 24x24 32x32 48x48 64x64 128x128 256x256">
<link rel="apple-touch-icon" sizes="512x512" href="{{ '/img/icon/ge007-icon.png' | relative_url }}">
<!-- Entity disambiguation: the maintainer behind every page. -->
<link rel="me" href="https://github.com/jkdansereau">
@@ -52,7 +55,7 @@
<footer class="site-footer">
<div class="footer-stamp">
<a href="https://github.com/jkdansereau">maintained by jkdansereau</a>
&nbsp;&middot;&nbsp; last updated: 2026-10-05 &middot; v0.5.0
&nbsp;&middot;&nbsp; last updated: 2026-10-06 &middot; v0.5.0
&nbsp;&middot;&nbsp; <a href="https://github.com/jkdansereau/goldeneye-pc-port">GitHub</a>
&nbsp;&middot;&nbsp; <a href="https://github.com/jkdansereau/goldeneye-pc-port/releases">releases</a>
</div>
+3
View File
@@ -307,6 +307,9 @@ D561,FIXED,"F10: ""Menu pointer"" row removed (front-end-only legacy option; con
D562,FIXED,F10 crosshair pointer hidden while a pad/keyboard drives the menu —,FIXED 2026-10-06 (drawCrosshairPointer draws only while s_mouseActive)
D563,FIXED,F10 root hub: Left/Right no longer open pages; held nav inputs latched on open/page change —,FIXED 2026-10-06
D564,FIXED,"F10: game's own ""Look up/down"" row removed (dead for mouse and centred pad, stacked with Invert look); value pinned to factory; tip polish —","FIXED 2026-10-06 (port only; Mouse / Controller ""Invert look"" are the inversion controls)"
D565,FIXED,AI awareness followed two player render settings:,FIXED 2026-10-06 (maintainer decision:
D566,FIXED,Steam Deck Game Mode showed the on-screen keyboard at every launch (SDL text input left on) —,FIXED 2026-10-06 (port only:
D567,FIXED,Front-end PC Options with a pad pulled the game's crosshair to the top-left (overlay synced the cursor to the untouched OS mouse) —,FIXED 2026-10-06 (port only:
D407,CLOSED,Tanks cannot be boarded/exited on PC —,CLOSED (2026-09-28 bookkeeping:
D408,FIXED,Game.SkipIntro skips the post-mission failure dossier:,FIXED 2026-09-30 (SkipIntro hook gated to first boot; live dossier check owed).
D415,FIXED,"Shooting a light fixture does not ""kill"" its flickering light (Bunker, Caverns):",FIXED (2026-09-29 bookkeeping:
1 # GENERATED by tools_pc/gen_findings_index.py -- do not hand-edit.
307 D562
308 D563
309 D564
310 D565
311 D566
312 D567
313 D407
314 D408
315 D415
+80
View File
@@ -715,6 +715,9 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
| D562 | **F10 crosshair pointer hidden while a pad/keyboard drives the menu** — full `## D562` entry at file tail | FIXED 2026-10-06 (`drawCrosshairPointer` draws only while `s_mouseActive`) |
| D563 | **F10 root hub: Left/Right no longer open pages; held nav inputs latched on open/page change** — full `## D563` entry at file tail | FIXED 2026-10-06 |
| D564 | **F10: game's own "Look up/down" row removed (dead for mouse and centred pad, stacked with Invert look); value pinned to factory; tip polish** — full `## D564` entry at file tail | FIXED 2026-10-06 (port only; Mouse / Controller "Invert look" are the inversion controls) |
| D565 | **AI awareness followed two player render settings: Fog distance below 100 (shortened clip) and FOV (gameplay fog cull scaled by the rendered FOV)** — full `## D565` entry at file tail | FIXED 2026-10-06 (maintainer decision: Fog distance floor 100 in `video.c` + overlay; `propobj.c portSub7F054C58Gameplay` rescaled to the game's own FOV, PORT-only D466 helper; identity at defaults; build-verified) |
| D566 | **Steam Deck Game Mode showed the on-screen keyboard at every launch (SDL text input left on)** — full `## D566` entry at file tail | FIXED 2026-10-06 (port only: `gfx_sdl2.cpp` SDL_ENABLE_SCREEN_KEYBOARD=0 + SDL_StopTextInput; build-verified Win/Linux; Deck Game Mode check owed) |
| D567 | **Front-end PC Options with a pad pulled the game's crosshair to the top-left (overlay synced the cursor to the untouched OS mouse)** — full `## D567` entry at file tail | FIXED 2026-10-06 (port only: sync gated on `optionsOverlayMouseActive()`; build-verified Win/Linux; Deck pad check owed) |
| D407 | **Tanks cannot be boarded/exited on PC — the v0.4.0 use/reload split (D378/D393) removed the B-button tap the engine's tank handlers in `bondview2.c` consume (user report 2026-09-28, Runway/Streets)** — full `## D407` entry at file tail | **CLOSED (2026-09-28 bookkeeping: tank board/exit accepted by the user; shipped in v0.4.0).** Earlier: PARTIAL (fix landed in v0.4.0, port-only): present `GE_CONT_B` on the use (E / pad A) rising edge only while `g_PlayerIsInTank == 1` or `g_BondCanEnterTank != 0`; E keeps its D378 no-reload-fallback semantics elsewhere, N64 layout unaffected. D407(b) same cycle: front PC Options page-edge highlight clamp + mouse-wheel / W-S paging (wheel queue consumed on the menu, D223); its wheel mapping shipped inverted and was fixed to match W/S (wheel up = step up). D407(c): board-animation lockout, menu-accept B gate in tank states, in-tank aim routed through the legacy velocity stick + `Input.TankAimScale` knob. RESOLVED 2026-09-28: all port-only (src/game zero-diff), 10 TANKDBG probes stripped, release binary verified clean, user live tank drive signed off (board + exit OK, aim feel good). |
| D408 | **`Game.SkipIntro` skips the post-mission failure dossier: with it on, entering a level then aborting (watch Z+A) or dying (KIA) returns straight to the menus — no REPORT / "Mission status: KILLED IN ACTION / ABORTED" screen** (user report 2026-09-28; save/AllUnlocked ruled out) — full `## D408` entry at file tail | FIXED 2026-09-30 (SkipIntro hook gated to first boot; live dossier check owed). |
| D415 | **Shooting a light fixture does not "kill" its flickering light (Bunker, Caverns): the fixture takes the hit but the flicker keeps going (community report, issue #87 comment by the reporter, 2026-09-28, 00 Agent playthrough of v0.4.0).** — full `## D415` entry at file tail | FIXED (2026-09-29 bookkeeping: root-caused and fixed as D430 + D431, user-verified vs GEPD/1964 on Caverns 2026-09-29; #119). Earlier: ROOT-CAUSED as D430 (see there); fix in tree, live check owed. |
@@ -18205,3 +18208,80 @@ polish: All unlocked "Unlocks all levels, 007 mode and every cheat.", Show
crosshair, FOV and Aim style tips rewritten as plain sentences. Verified: both
TUs compile (link was blocked by a running game; full build + re-cut follow).
## D565: AI awareness followed two player render settings (Fog distance < 100, FOV) — FIXED 2026-10-06 (maintainer decision)
**Found by** the v0.4.0..v0.5.0 AI regression review (interpreter, movement/timing,
visibility/combat; three read-only reviewers, lead re-checked every flag in code).
No regression at the shipped settings (Draw 2.0x, Fog 1.0x, FovScale 100, native
widescreen). Two leaks of render-only settings into AI awareness (the D466/D468
class) at non-default settings:
1. **`Video.FogDistance` below 100.** `bgfog.c fogLoadCurrentEnvironment` sets the
far clip to `FarFog x min(Fog, Draw)` (D540), so Fog < 1.0 shortens it below the
authored distance. AI on-screen checks require the render `PROPFLAG_ONSCREEN`
(`port/src/drawdistgameplay.c portPropGameplayOnScreen`), so guards beyond the
shortened clip stopped counting as on screen; at Draw 1.0x `portD466Active()` is
off and the sight range (`fogGetScaledFarFogIntensitySquared`) shrank as well.
Guards would notice Bond, and on-screen triggers fire, later than on the N64.
**Fix (maintainer: block it):** the setting's floor is now 100
(`port/src/video.c` registration, so an ini value of 50/75 clamps to 100 on
load; `port/src/optionsoverlay.c` slider `uiMin` 100). 100-800 keeps the D540
extension, which D466 already keeps off gameplay.
2. **FOV other than the game's (`Video.FovScale` != 100, or the stretch-era
`WidescreenAuto` boost with native widescreen off).** The D466 gameplay fog cull
`src/game/propobj.c portSub7F054C58Gameplay` scales by `c_lodscalez`, which is
tan(fovy/2)-proportional and built from the rendered fovy (D222 `frCullFovY`), so
a wider FOV dropped far fogged positions out of the AI on-screen verdict sooner
(narrower: later). **Fix:** inside that `#ifdef PORT` D466 helper, rescale
`scalez` by tan(own/2)/tan(eff/2) with `own = c_perspfovy / portFovYScaleFactor()`
(the D468 recovery of the game's own fovy; the game's zoom FOVs are kept).
Identity when the factor is 1 (the defaults). Port-feature leak fix in an
existing PORT-only helper (D466 sign-off class); maintainer asked for the fix
2026-10-06.
Checked and left (no AI harm): the D466 verdict reuses the extended pass's room
screen bbox (`posIsOnScreen`), but at Fog 1.0x the clip is the authored far, so the
passes match; D491 (portal bbox seeds) and D431 (light-fixture texnum in ray
scoring) restore N64 data reads; D417, D468 and the M-183/M-185 clamp removal are
signed off and play-covered. Also corrected: a watchdog `pin signature detected ...
confirmation window` line that clears on its own is the normal post-D329 pattern
(the 2026-09-23 D329 sign-off log had three); only `anim pin CONFIRMED` / `pin still
held` indicates a regression. The maintainer's 2026-10-06 Deck Facility run logged
four self-clearing detections and no confirmation.
**Verify:** build; defaults are bit-identical (both changes are no-ops at Fog 100 /
factor 1), so the golden gate is unaffected. By eye (optional): FovScale 150 on a
fogged level (Surface 1, Dam), guards at fog range react as at FovScale 100.
## D566: Steam Deck Game Mode showed the on-screen keyboard at every launch — FIXED 2026-10-06 (port only)
**Report (maintainer, Deck, Game Mode, 2026-10-06):** the Steam virtual keyboard
popped up every time the game started. **Cause:** SDL2 starts with text input
enabled and the port never turned it off (it reads keys only as `SDL_KEYDOWN`;
nothing in `port/` consumes `SDL_TEXTINPUT`/`SDL_TEXTEDITING`). With text input
active, Steam's Game Mode treats the window as wanting its keyboard. Observed with
the Deck's system SDL (`sdl2-compat` on SDL3; the Steam shortcut pointed at the
exe, so the bundled SDL2 2.32 next to it was not loaded); not checked whether the
release tarball's `$ORIGIN` SDL2 shows it too, and the fix covers both.
**Fix (`port/fast3d/gfx_sdl2.cpp`):** set the `SDL_ENABLE_SCREEN_KEYBOARD` hint to
`0` before `SDL_Init` (literal name; ignored where unknown) and call
`SDL_StopTextInput()` right after `SDL_ShowWindow`. No game code touched.
**Verify:** builds on Windows and Linux (X220); deployed to the Deck play folder
2026-10-06 21:00; maintainer Game Mode launch owed (expect no keyboard).
## D567: Front-end PC Options with a pad pulled the game's crosshair to the top-left corner — FIXED 2026-10-06 (port only)
**Report (maintainer, Deck, 2026-10-06):** opening *PC Options* from the main
menu with a controller moved the front end's own crosshair cursor to the top
left. **Cause:** while the F10 overlay is open over the front end,
`port/src/input.c` called `overlayFrontEndCrosshair()` every frame (D519/D555:
the game cursor tracks the OS mouse so the overlay pointer sits exactly on it).
With a pad the OS pointer is never moved and reads 0,0, so the game cursor was
clamped to the top-left corner of the screen box. **Fix:** the sync runs only
while the mouse is the active input in the overlay (`s_mouseActive`, which
starts at 0 on open and becomes 1 on a mouse move or click; new accessor
`optionsOverlayMouseActive()`). With a pad the cursor stays where it was; mouse
users get the same tracking as before. **Verify:** builds on Windows and Linux
(X220); deployed to the Deck play folder 2026-10-06 21:03; maintainer pad check
owed (open PC Options from file select with the pad, the crosshair stays put).
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

+26 -23
View File
@@ -9,7 +9,7 @@ description: >-
# and the WebPage JSON-LD dates). Keep these equal to the last real content
# change of THIS page, not to the last release.
date: '2026-10-05'
modified_time: '2026-10-05'
modified_time: '2026-10-06'
locale: en_US
# The masthead is this page's title, so its first content h2 must NOT get the
# amber page-title look (double header). See the .flat-title rule in
@@ -32,26 +32,29 @@ Rare "Indy" engine family, one hardware generation apart.
<div class="cblock">
### v0.5.0 (2026-10-05) — the campaign and split-screen both run end to end.
### v0.5.0 (2026-10-06) — split-screen multiplayer, one options menu, closer to the N64.
- **Single-player campaign complete.** All 20 missions plus the
ending-credits sequence, completable end to end at a steady 60 fps.
- **2–4 player split-screen multiplayer.** Supported on every multiplayer
map; playtested on Windows, Linux and Steam Deck.
- **One real options system.** A single menu, laid out like the Perfect
Dark port's — plain-English wording, real-unit sliders, a one-line
description per option — with the game's own **N64 control styles as a
per-seat preset**.
- **Emulator save files load directly.** Copy a 1964 / Project64 save into
`data/` and it is converted on first launch.
- **A scalable HUD overlay**, fullscreen and window-centring controls, and
antialiased overlay controls.
- **A fidelity round checked frame-by-frame against the N64 game** (fog,
aspect-ratio letterboxing, the Watch menu's own settings), with the
reference-frame gate re-based on both platforms (21 levels, 63 frames
each).
- The small stuff: a menu wording, units and help-text pass, and
standardised menu spelling.
- **2–4 player split-screen multiplayer** on every multiplayer map, each
player with their own pad, controls and aim settings.
- **One options menu** for every setting, laid out like the Perfect Dark
port's, with the game's own crosshair as the mouse pointer. Pick the game's
own N64 control styles (1.1–2.4) per player, or the Xbox release's presets
with per-player pad rebinding; PlayStation and Nintendo pads show their own
button names.
- **Closer to the N64:** fog and haze (Surface 2's ground fog, the sky at the
horizon), automatic-weapon fire rate, sniper and camera zoom, Dam and
Caverns water, the Jungle boss fight's timing, guard visibility in
widescreen, and the Dam ending camera.
- **Fewer crashes and glitches:** a multiplayer crash with the crouched rifle,
rockets passing through the ground, and broken geometry around Aztec's
shuttle.
- **A steady 60 fps on low-end GPUs** (tested on an Intel HD 3000 laptop),
with lighter first-launch defaults on Atom/Celeron-class graphics.
- **Emulator saves load directly:** copy a 1964 or Project64 save in as
`data/ge007.eep` and it is converted on first launch.
- Also: more audio, video and control settings (master volume, audio device,
trilinear filtering, draw distance up to 800%, PC-friendly crouch and
look-ahead defaults), and controllers are picked up again when replugged.
</div>
@@ -72,7 +75,7 @@ single tracker for what comes next.
<li><strong>NTSC-U ROMs only in the release packages.</strong> PAL and JP ROMs convert, build and run from source, but release packages ship the US (NTSC-U) ROM. On the roadmap.</li>
<li><strong>Changing the aspect ratio in a level can briefly glitch the gun/hand model</strong> (cosmetic, one-off). Change the ratio from the front-end PC Options, or accept it (D509).</li>
<li><strong>No macOS or ARM builds yet.</strong> Today the release ships Windows, Linux and Steam Deck (keyboard, mouse and controller-button rebinding are all supported, defaults in the <a href="https://github.com/jkdansereau/goldeneye-pc-port#controls">README's Controls section</a>); macOS and ARM are on the roadmap.</li>
<li><strong>Saves from builds before v0.4.1 can hold fake unlocks from <code>All unlocked</code></strong> — <code>All unlocked</code> has not written your save since v0.4.1, but saves made while it was on in builds before v0.4.1 can hold fake unlocks and are not repaired; back up <code>data/ge007.eep</code> if you used it on an older build (D442, D387).</li>
<li><strong>Saves from v0.4.0 and earlier can hold fake unlocks from <code>All unlocked</code></strong> — <code>All unlocked</code> has not written your save since v0.5.0, but saves made while it was on in v0.4.0 and earlier can hold fake unlocks and are not repaired; back up <code>data/ge007.eep</code> if you used it on an older build (D442, D387).</li>
<li><strong>The first frame of a level takes a little longer</strong> while its textures upload — a brief FPS-counter dip; nothing to fix (D475, D480).</li>
<li><strong>In widescreen, far objects almost fully in fog can still show a faint distant building edge</strong> (4:3 matches the N64). Cosmetic (D503).</li>
</ul>
@@ -85,7 +88,7 @@ single tracker for what comes next.
<p class="warn"><strong>Warning:</strong> always use the latest release — earlier builds are kept in the release history for reference only; they lack the features and fixes of newer versions, so don't install an older release.</p>
<ul>
<li><strong>2026-10-05 — v0.5.0</strong>: what it adds is the Status list above. <a href="https://github.com/jkdansereau/goldeneye-pc-port/releases/tag/v0.5.0">Release notes</a>.</li>
<li><strong>2026-10-06 — v0.5.0</strong>: what it adds is the Status list above. <a href="https://github.com/jkdansereau/goldeneye-pc-port/releases/tag/v0.5.0">Release notes</a>.</li>
<li><strong>2026-09-28 — v0.4.0</strong>: native widescreen, a complete aim system for mouse and controller, in-game key rebinding, crosshair customization, rumble-pak haptics, a rebuilt options overlay, and a broad fidelity-fix pass. <a href="https://github.com/jkdansereau/goldeneye-pc-port/releases/tag/v0.4.0">Release notes</a>.</li>
<li><strong>2026-09-20 — v0.3.0</strong>: the first release with the complete campaign playable end to end at 60 fps on Windows, Linux, and Steam Deck. <a href="https://github.com/jkdansereau/goldeneye-pc-port/releases/tag/v0.3.0">Release notes</a>.</li>
<li><strong>2026-09-04 → 2026-09-16 — v0.1.0 – v0.2.2</strong>: the alpha and beta cycle — build chain, software RSP, first rendered frames, front end, and per-level stabilization across the campaign.</li>
@@ -234,7 +237,7 @@ architecture, the N64→PC bug catalogue, and how the project is developed.
"description": "A native PC build of GoldenEye 007 (Rare, 1997, Nintendo 64), compiled from the n64decomp/007 decompilation with the N64's RSP emulated in software. Ships no ROM and no game assets; you supply your own.",
"softwareVersion": "0.5.0",
"datePublished": "2026-10-05",
"dateModified": "2026-10-05",
"dateModified": "2026-10-06",
"operatingSystem": ["Windows", "Linux", "Steam Deck"],
"downloadUrl": "https://github.com/jkdansereau/goldeneye-pc-port/releases",
"distributionType": "Software-Offline",
+6
View File
@@ -22,5 +22,11 @@ PlayStation/Nintendo button names. **Everything is rebindable** — keyboard,
mouse and each controller — in the F10 options overlay. Split-screen needs one
controller per extra player.
**Control style** offers **Ext** (this port's scheme) or **Original**, the
game's own N64 styles 1.1–2.4, chosen per seat. New profiles start with
**Look ahead** off (it fights mouse look) and **Crouch** on Toggle; the
game's own Look up/down row was removed in favour of **Invert look** on the
Mouse and Controller pages.
*More: [internals](internals.md) §7 (input & saves); the aim model's
provenance is the D194 lineage in `port/src/input.c`.*
+3 -2
View File
@@ -17,8 +17,9 @@ A few details:
- The **PFS / Memory-Pak and motor (Rumble Pak) code** is only for accessory
detection and is stubbed to report "no accessory," so the game proceeds
without a Memory Pak.
- **Emulator saves can be imported** — copy a `GOLDENEYE-usa.eep` in as
`data/ge007.eep` (see the README's *Using an emulator save*).
- **Emulator saves load directly** — an emulator-format `ge007.eep` placed
in `data/` is converted on first launch, so a Project64, mupen or 1964
save continues in the port (see the README's *Using an emulator save*).
- The save's **checksum is part of the file format**. The PRNG/CRC the save
depends on is kept byte-stable, because changing it would silently
invalidate existing saves — a porting-notes finding (D9).
+9
View File
@@ -101,6 +101,11 @@ static void gfx_sdl_init(const struct GfxWindowInitSettings *set) {
}
#endif
// D566: the port never takes text input, so never ask for an on-screen
// keyboard (Steam Deck Game Mode popped one at every launch). Literal
// hint name: older SDL2 headers lack the macro; unknown hints are ignored.
SDL_SetHint("SDL_ENABLE_SCREEN_KEYBOARD", "0");
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
sysFatalError("Could not init SDL:\n%s", SDL_GetError());
}
@@ -256,6 +261,10 @@ static void gfx_sdl_init(const struct GfxWindowInitSettings *set) {
}
SDL_ShowWindow(wnd);
// D566: SDL2 starts with text input enabled; with it on, Steam's Game Mode
// treats the window as wanting its virtual keyboard. Keys still arrive as
// SDL_KEYDOWN (bindings, menus), which is all the port reads.
SDL_StopTextInput();
qpc_freq = SDL_GetPerformanceFrequency();
}
+4
View File
@@ -42,6 +42,10 @@ void optionsOverlayBack(void);
/* 1 while the overlay is on screen. */
int optionsOverlayIsOpen(void);
/* D567: 1 once the mouse moved or clicked since the overlay opened or the
* last pad/keyboard navigation (the pointer is then the active input). */
int optionsOverlayMouseActive(void);
/* Called from inputComputePad(0) while open: reads SDL keyboard edges and
* drives the cursor / value adjustments. */
void optionsOverlayHandleInput(void);
+5 -1
View File
@@ -2194,7 +2194,11 @@ static unsigned inputComputePadSlot(int idx, signed char *stick_x, signed char *
if (closeNow) optionsOverlayToggle();
}
optionsOverlayHandleInput();
if (mouseEnabled && current_menu != GE_MENU_RUN_STAGE && current_menu != GE_MENU_INVALID) {
/* D567: only while the mouse is the active input -- with a pad (Deck) the
* untouched OS pointer sits at 0,0 and dragged the front end's own
* crosshair to the top-left corner; it now stays where it was. */
if (mouseEnabled && current_menu != GE_MENU_RUN_STAGE && current_menu != GE_MENU_INVALID &&
optionsOverlayMouseActive()) {
overlayFrontEndCrosshair(); /* D519: the game cursor tracks the mouse (D555: the overlay pointer is drawn exactly over it) */
/* D544: the OS cursor stays visible (inputSuspendForOverlay) -- the crosshair
* draws under the overlay box, so it alone could not point at F10 rows. */
+3 -1
View File
@@ -265,7 +265,7 @@ static struct Row rows[] = {
{ .key="Video.DrawDistance", .label="Draw distance", .kind=ROW_SLIDER, .step=25, .uiMin=100, .uiMax=800 },
/* D540: fog start/end as a multiple of the level's own (N64) fog;
* capped at the draw distance. 0.5x..8.0x, 1.0x default. */
{ .key="Video.FogDistance", .label="Fog distance", .kind=ROW_SLIDER, .step=25, .uiMin=50, .uiMax=800 },
{ .key="Video.FogDistance", .label="Fog distance", .kind=ROW_SLIDER, .step=25, .uiMin=100, .uiMax=800 } /* D565: no < 100 */,
{ .key="Video.LodDistance", .label="LOD distance", .kind=ROW_SLIDER, .step=25, .uiMin=100, .uiMax=800 },
SEP(V5),
/* D181 re-exposed (PD "Explosion shake"): named for what it scales (explosions only). */
@@ -2289,6 +2289,8 @@ void optionsOverlayBack(void)
if (s_open) SDL_AtomicSet(&s_backPending, 1);
}
int optionsOverlayMouseActive(void) { return s_mouseActive; } /* D567 */
int optionsOverlayIsOpen(void)
{
if (!s_inited) {
+4 -1
View File
@@ -547,7 +547,10 @@ PD_CONSTRUCTOR static void videoConfigInit(void)
configRegisterInt("Video.NativeWidescreen", &cfgNativeWidescreen, 0, 1); /* D334 */
configRegisterInt("Game.HudScale", &cfgHudScale, 75, 150); /* D226: capped at 150 (user: little benefit above) */
configRegisterInt("Video.DrawDistance", &cfgDrawDistance, 100, 800);
configRegisterInt("Video.FogDistance", &cfgFogDistance, 50, 800); /* D540 */
/* D565: floor 100 -- below the authored fog the shortened far clip also
* shrinks what AI awareness counts as on screen / in sight (D466 keeps
* gameplay on the authored distance only for extensions). */
configRegisterInt("Video.FogDistance", &cfgFogDistance, 100, 800); /* D540 */
configRegisterInt("Video.DrawDistanceAutoFov", &cfgDrawDistanceAutoFov, 0, 1);
configRegisterInt("Video.LodDistance", &cfgLodDistance, 25, 800);
configRegisterInt("Video.LodDistanceAutoFov", &cfgLodDistanceAutoFov, 0, 1);
+15
View File
@@ -13662,6 +13662,21 @@ static bool portSub7F054C58Gameplay(coord3d *coord, f32 arg1)
if (sp20 > ptr->z)
{
f32 scalez = getPlayer_c_lodscalez();
/* D565: c_lodscalez is tan(fovy/2)-proportional and is built from
* the RENDERED fovy (D222 frCullFovY: FovScale / stretch-era
* widescreen boost), so a wider player FOV made far fogged
* positions drop out of AI awareness sooner. Rescale to the
* game's own fovy (zoom kept); identity at the defaults. */
{
extern f32 portFovYScaleFactor(void);
f32 k = portFovYScaleFactor();
if (k != 1.0f && g_CurrentPlayer->c_perspfovy > 0.0f) {
f32 eff = g_CurrentPlayer->c_perspfovy;
f32 own = eff / k;
scalez *= (sinf(mDegToHalfRad(own)) / cosf(mDegToHalfRad(own)))
/ (sinf(mDegToHalfRad(eff)) / cosf(mDegToHalfRad(eff)));
}
}
sp20 = ((sp20 - ptr->z) * 100 / arg1 + ptr->z) * scalez;
if (sp20 >= ptr->y)
+5 -1
View File
@@ -13,6 +13,7 @@ must not be derivative game content).
Outputs (all regenerated byte-identically; deterministic):
docs/img/icon/ge007-icon.png 512x512 favicon / README icon
cmake/icon/ge007.ico multi-size Windows exe icon (16..256)
docs/favicon.ico byte copy of ge007.ico (site favicon)
port/fast3d/ge007_icon.h 32x32 RGBA array for the SDL window icon
(SDL_SetWindowIcon, see gfx_sdl2.cpp)
@@ -40,6 +41,7 @@ ROOT = Path(__file__).resolve().parent.parent
OUT_ICON = ROOT / "docs" / "img" / "icon" / "ge007-icon.png"
OUT_ICO = ROOT / "cmake" / "icon" / "ge007.ico"
OUT_HEADER = ROOT / "port" / "fast3d" / "ge007_icon.h"
OUT_FAVICON = ROOT / "docs" / "favicon.ico"
# --- palette -----------------------------------------------------------------
BG = (5, 6, 7) # site near-black
@@ -141,6 +143,7 @@ def make_ico() -> None:
offset += len(png)
data += png
OUT_ICO.write_bytes(struct.pack("<HHH", 0, 1, n) + dirs + data)
OUT_FAVICON.write_bytes(OUT_ICO.read_bytes()) # site favicon = exe icon
def make_header() -> None:
@@ -197,9 +200,10 @@ def main() -> int:
make_header()
print(f"wrote {OUT_ICON.relative_to(ROOT)}")
print(f"wrote {OUT_ICO.relative_to(ROOT)}")
print(f"wrote {OUT_FAVICON.relative_to(ROOT)}")
print(f"wrote {OUT_HEADER.relative_to(ROOT)}")
return 0
stale = [p for p in (OUT_ICON, OUT_ICO, OUT_HEADER) if not p.exists()]
stale = [p for p in (OUT_ICON, OUT_ICO, OUT_HEADER, OUT_FAVICON) if not p.exists()]
if stale:
for p in stale:
print(f"stale/missing: {p.relative_to(ROOT)}")