# Workflow — start here

This is the note to read first when picking up the NHL 94 project. It says where everything is, how we work,
the rules, and where things stand. Then read `HACKING.md` (how the game works and how to change it) and
`CHANGELOG.md` (what has been changed and measured).

## Where everything is

| What | Where |
|---|---|
| Project / working folder | `~/mount/truenas/www/dela.jdc.se/nhl94/` (public site https://dela.jdc.se/nhl94/) |
| Tools and notes | `nhl94/tools/` and `nhl94/tools/notes/` |
| The ROM jdc plays | `~/.config/retroarch/roms/claude/NHL 2026 - 94 Edition v5.1W.bin` — **always** built to this exact path, so it starts the same way every time |
| Base ROM (unpatched v5.1W) | `~/.config/retroarch/roms/claude/NHL 2026 - 94 Edition v5.1W.bin.orig.bak`, md5 8f863ecb108c1d213953bada9b98f4f2 |
| Private work files | `~/.config/retroarch/roms/claude/work/` — `sta/` saved states, `snap/` screenshots, `backups/` earlier ROMs, `old-passfix/` the first working folder |
| Website pages | `index.html` (patch notes, Teams grid, Tools), `team.html?t=XXX` (one team, reads `teams.json`), `notes.html` (these notes), `tools/index.php` (file list) |

## Rules

- **Never open a window when testing.** jdc plays on one of the screens. Run MAME only through `tools/run.sh`
  (no DISPLAY/Wayland, SDL dummy driver, `nice -n 19`). `-video none` alone is not enough.
- **Never put a ROM file in the web folder.** The site is public. Distribute changes as the IPS patch in `download/`.
- Always build from the base ROM with `tools/build.sh`; it backs up the previous ROM and installs the new one.
- Measure before installing: compare against the original with the same test, and run a full CPU game as a stability check.
- At the end of a session: add what was done, in plain words, at the top of `SESSION_LOG.md` (the summary given to jdc).
- After every change: update `CHANGELOG.md` (what and measured numbers) and `HACKING.md` (addresses, free space), run
  `python3 tools/make_site_data.py` if rosters changed, and update `index.html` if the change is visible to players.
- Notes and the website are in English. Talk to jdc in Swedish.
- Don't copy EA's graphics or sound. Screenshots of the game to explain a change are fine.

## Standard tasks

    cd ~/mount/truenas/www/dela.jdc.se/nhl94/tools
    ./build.sh                    # build + install the ROM, back up the old one, rewrite the IPS
    ./update_rosters.sh           # refresh all rosters from the NHL + DailyFaceoff, then build
    python3 make_site_data.py     # refresh teams.json for the team pages
    ./run.sh cmds.txt             # headless MAME run (see HACKING.md, Testing)

Starting a ROM for jdc to play (he asked for this, so he always tests the right file; Claude's own tests stay headless):

    cd ~/.local/share/Steam/steamapps/common/RetroArch && setsid ./retroarch.sh -L cores/genesis_plus_gx_libretro.so "<rom>" >/dev/null 2>&1 < /dev/null &

RetroArch (Steam) keeps battery saves in `~/.local/share/Steam/steamapps/common/RetroArch/saves/Genesis Plus GX/<rom name>.srm`
(16 KB, data on the odd bytes; MAME's `.nv` uses the even bytes).

A new game change: add it to `patch.py` with a flag to switch it off (pattern in HACKING.md), test with `run.sh`,
build, update the notes and the site.

A hand-made team: edit `rosters/<TEAM>.json` and set `"manual": true` so `update_rosters.sh` leaves it alone.

A single player's ratings (e.g. "he should be a star"): add him to `rosters/overrides.json` (name → 14 hex nibbles),
then `python3 gen.py rosters EDM` (EDM = the manual teams), `./build.sh`, `python3 make_site_data.py`.

## Where things stand (2026-10-21)

Installed ROM md5: see `teams.json` (`rom_md5`) or `md5sum` the ROM. Changes in it:

1. Co-op passing prefers the other human; wider receive radius for him.
2. Goalie passes are never blind and a bit softer.
3. Blue-line shots: from distance 160 (about 20 px inside the blue line) the goalie misses 15 % of shots. About 2.8 % of
   such shots score (original 0.3 %). Shootouts are unaffected.
4. The off-screen arrow (goalie in shootouts) is placed correctly (was 32 px too far left).
5. Fighting is just Off / On and the setting holds for the whole game (it used to be overwritten mid-game).
6. All 32 rosters and lines as of 2026-10-21.
7. Hand-set star ratings for Frondell and Stenberg; the hack's placeholder ratings (all 1s) replaced by model ratings.
8. No player in two lines; Fighting shows N/A when Penalties is Off.
9. **Season mode** (season ROM `~/.config/retroarch/roms/claude/MEGAdriveHARDJOB/NHL94-season.bin`, the one on the site):
   Regular Season = an 82-game season (Continue / New Season), standings by division, scoring leaders, every player's
   goals/assists/shots, simulated league. Details in `SEASON_MODE.md`.
10. Y on a 6-button pad takes your goalie (Goalie Ctrl Manual, no puck); `ygoalie.s`, assembled by `build.sh`.

### How the rosters were made

- Each team's roster comes from the NHL's official API and its lines from DailyFaceoff.
- Every trio is turned so each player plays his official NHL position.
- Each team keeps its 26 slots and its number of goalies.
- Order when picking players: dressed tonight → rest of the roster → injured → prospects. Utah and Vancouver had too few
  players, so they were filled with old ROM players who are on no NHL team.
- Players who were already in the ROM keep the hack's ratings, even if they changed teams. New players are rated from
  NHL stats with the kNN model; players with few or no NHL games get typical depth-player ratings.
- Edmonton was done by hand and approved by jdc; it is marked `"manual": true`.
- Tested: all 32 rosters read back exactly from the ROM; full CPU games with eight teams (BOS–CAR, CBJ–OTT, NSH–TOR,
  SEA–ANA) and WPG–EDM ran without errors. The Line Editor was only checked for Edmonton.

### Known gaps

- Montreal has 3 goalies in the hack although its team flag says 2; kept as it was.
- Goalie ratings are only partly mapped (weight, agility, speed, endurance known; the rest shown as numbered columns).
- Nibble 11 of skater ratings is unknown (values 1–5).
- The hack has weak-looking but real ratings for some veterans (e.g. Kulikov, Boqvist); only exact all-1 placeholders are replaced.
- The first of the 8 line entries in a team record has an unknown purpose (set like Scoring 1 with another extra skater).
- Nothing has been play-tested with real pads by Claude; jdc plays and reports.

### Ideas not done yet

- Playoffs after game 82, goalie stats in the season (see SEASON_MODE.md).

- Let player 2's skater steer toward an incoming pass like CPU players do.
- Higher fight frequency (lower threshold) if jdc wants more fights.
- A view on the site that compares two teams.
