Files
gen1recomp/docs/game3/location-previews.md
Shane McGovern 38a7e03f13 Show retail location previews for every FireRed map section
Most map sections never showed a Location Preview because the preview
artwork and the region-map GUIDE text were hand-authored placeholders:
only a handful of sections had art and none of it came from the ROM.

Read the real tables out of the dump instead.

Extraction (new):
- src/import/gba/region_map_tables.lua locates and validates
  sMapPreviewScreenData. The pinned offset from versions.lua is tried
  first and a bounded +/-0x8000 scan is only a guard. Validation is
  structural (mapsec in 88..196, type 0/1, three in-range ROM pointers,
  and the shipped invariant that the palette block is the first 0x40
  bytes of the tile block) so all 28 entries must hold.
- src/import/gba/map_preview_extract.lua bakes 21 deduplicated 240x160
  RGBA artworks (28 entries reuse art: Pattern Bush and the six Tanoby
  chambers), 109 mapsec names verified against sRegionMapSectionIdToName,
  and the 19 sDungeonInfo entries. Palette banks 13/14; bank-0 tilemap
  refs only occur in off-screen padding columns.
- src/import/gba/bg_bake.lua holds the shared 4bpp BG baking helpers;
  berry_pouch_extract.lua is refactored onto them (-94 lines).

Runtime:
- src/ui/game3/map_preview_screen.lua ports
  Task_RunMapPreviewScreenForest: 120-frame first-visit hold, 40-frame
  revisit, 48-frame fade-out, artwork and name window composited into one
  canvas so they fade together. Only MPS_TYPE_FOREST (8 sections) takes
  over the screen; the 20 MPS_TYPE_CAVE sections only change the warp
  fade colour, matching pret.
- src/core/game3/map.lua gives a changed section with a forest preview
  precedence over the map name popup (overworld.c state 12).
- src/core/game3/warp.lua routes every fade through warpFadeModes,
  applying WarpFadeOutScreen/WarpFadeInScreen: a section change into a
  cave-preview map forces FADE_TO_BLACK, otherwise MapTransitionIsEnter/
  IsExit decide white vs black on MAP_TYPE_UNDERGROUND.
- setworldmapflag feeds the transient visit flag; the HUD ticks and
  dismisses the screen; the dataset installs the cache on hydrate.
- region_map.lua's GUIDE panel uses the retail geometry, tint ramp and
  delayed text, and ROM names/dungeon text overlay the hand-authored
  fallbacks via ensureGenerated().

Two retail quirks are tolerated: MPS_ROCKET_WAREHOUSE and Berry Forest
share flagId 2231 (as do the six Tanoby chambers), and the Tanoby mapsec
is spelled MAPSEC_DILFORD_CHAMBER.

CACHE_VERSION 99 -> 100.

Verified: tests/game3_map_preview_extract_test.lua (new; ROM-gated, all
28 entries, 8 forest / 20 cave, 21 artworks, 109 names, 19 dungeons, the
shared flag, Pattern Bush art reuse), tests/game3_town_map_test.lua,
tests/run_engine.lua 587/587, scripts/test.sh --quick all tiers,
luacheck src 0 warnings / 0 errors.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-09-19 14:21:30 +01:00

110 lines
5.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Location Previews
Entering a FireRed map section that owns a preview now shows the retail
full-screen artwork and location-name window during the warp transition, and
the Town Map GUIDE panel shows the retail artwork and flavour text instead of
the hand-authored placeholders. Before this, only a handful of sections had
art, and none of it came from the ROM.
## What the ROM provides
`src/import/gba/map_preview_extract.lua` reads two tables straight from the
user's dump and bakes them into the cache:
| Table | Source | Contents |
| --- | --- | --- |
| `sMapPreviewScreenData` | `src/map_preview_screen.c` | 28 entries: `mapsec`, `type`, `flagId`, `tilesptr`, `tilemapptr`, `palptr` |
| `sMapsecName_*` | `src/region_map.c` | 109 display names for mapsec 88..196 |
| `sDungeonInfo` | `src/region_map.c` | 19 dungeon GUIDE entries: name + pre-wrapped flavour text |
`src/import/gba/region_map_tables.lua` locates `sMapPreviewScreenData` by
validating the pinned offset from `versions.lua` and only then falling back to a
bounded ±0x8000 scan. Validation is structural, not a magic byte match: every
one of the 28 entries must have a mapsec in range, a type of 0 or 1, three
in-range ROM pointers, and satisfy the shipped invariant that the palette block
is physically the first 0x40 bytes of the tile block.
Artwork is deduplicated by its `tiles:tilemap:palette` key, so 28 entries bake
21 images. Pattern Bush and the six Tanoby chambers reuse another section's art,
exactly as the retail table does. Each image is 240×160 RGBA at 4bpp using
palette banks 13 and 14.
`src/import/gba/bg_bake.lua` holds the shared 4bpp BG baking helpers
(`bgr555ToRgb8`, `decodeTile4bpp`, `loadPalBanks`, `bakeBgRgba`); the Berry Pouch
extractor was refactored onto them.
### Cache files
```
<root>/map_preview/manifest.lua entries, by_mapsec index, name-window colours
<root>/map_preview/<mapsec>.rgba 240x160 RGBA artwork, deduplicated
<root>/region_map/names.lua mapsec 88..196 display names
<root>/region_map/dungeon_info.lua sDungeonInfo name + flavour text
```
`versions.lua` `CACHE_VERSION` is bumped when any of these change shape.
## Two ROM quirks the importer tolerates
* `MPS_ROCKET_WAREHOUSE` (mapsec 178) and Berry Forest (mapsec 176) share
`flagId = 2231`, so the first one the player visits marks both as seen. The
six Tanoby chambers likewise share one flag. This is retail behaviour.
* The Tanoby chamber mapsec is spelled `MAPSEC_DILFORD_CHAMBER` (not
`DILFORD`) in the name table.
## Runtime behaviour
`src/ui/game3/map_preview_screen.lua` ports `Task_RunMapPreviewScreenForest`.
Only `MPS_TYPE_FOREST` sections (8 of them) take over the screen; the other 20
are `MPS_TYPE_CAVE` and only change the warp fade colour. The artwork and the
name window are composited into one canvas so they fade out together, matching
the retail BG0/BLDALPHA blend.
* Hold: 120 frames on a first visit, 40 on a revisit. Caves key off their own
world-map flag; forests key off the transient `sHasVisitedMapBefore` global
that `ScrCmd_setworldmapflag` refreshes (`MapPreviewScreen.setVisitedFlag`
captures the pre-visit state).
* Fade-out: 48 frames.
Wiring:
* `src/core/game3/map.lua` — a changed section with a forest preview wins over
the map-name popup (mirrors `overworld.c` state 12). Suppressed for seamless
warps.
* `src/core/game3/gfx.lua` — a running preview suppresses `MapNamePopup`.
* `src/core/game3/warp.lua` — `warpFadeModes` applies
`WarpFadeOutScreen`/`WarpFadeInScreen`: a section change into a cave-preview
map forces `FADE_TO_BLACK`, otherwise `MapTransitionIsEnter`/`IsExit` decide
white-vs-black using `MAP_TYPE_UNDERGROUND`.
* `src/core/game3/scripting/ops_a.lua` — `setworldmapflag` feeds the visit flag.
* `src/ui/game3/hud.lua` — ticks and dismisses the screen on menu open.
* `src/core/game3/dataset.lua` — installs the cache during hydrate.
* `src/ui/game3/region_map.lua` — GUIDE panel geometry, tint ramp and delayed
text now follow the retail timings; ROM names and dungeon text overlay the
hand-authored `map_sections_extract.SECTIONS` / `region_map_extract` fallbacks
via `ensureGenerated()`.
## Verification
Run from the project root:
```sh
luajit tests/game3_map_preview_extract_test.lua
luajit tests/game3_town_map_test.lua
luajit tests/run_engine.lua
luacheck src -q --codes --only 0 1 511
```
`tests/game3_map_preview_extract_test.lua` covers the pinned offsets, the
BGR555→RGB8 conversion, the manifest/screen logic against a synthetic cache
(so it runs without a ROM), and — when a FireRed dump is present at the repo
root — the full extraction: 28 entries, 8 forest / 20 cave, 21 deduplicated
240×160×4 artworks, 109 verified mapsec names, 19 dungeon entries, the shared
2231 flag, and Pattern Bush reusing Viridian Forest's artwork.
The `tests/game3_*` suites are run manually; they are not wired into a CI
workflow. Extraction was additionally checked against a real FireRed 1.0 dump
(all 28 entries and 109 names decode, `sMapsecName_*` pointers match
`sRegionMapSectionIdToName`). Timing was reasoned against pret source; no
in-game visual capture has been performed.