Files
gen1recomp/src/import/gba/berry_pouch_extract.lua
T
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

123 lines
3.9 KiB
Lua

-- Bake FRLG Berry Pouch chrome from ROM into CacheFS (data/generated/gba/items/berry_pouch/).
-- Source: pret graphics/berry_pouch/ (background.4bpp.lz, background.bin.lz, background.gbapal.lz, background_female.gbapal.lz, berry_pouch.4bpp.lz, berry_pouch.gbapal.lz).
local Versions = require("src.import.gba.versions")
local Lz77 = require("src.import.gba.lz77")
local BgBake = require("src.import.gba.bg_bake")
local BerryPouchExtract = {}
BerryPouchExtract.CACHE_SUB = "items/berry_pouch"
BerryPouchExtract.FORMAT_VERSION = 1
local function default_cache_root()
local ok, Extract = pcall(require, "src.import.gba.extract_island1")
if ok and Extract and Extract.CACHE_ROOT then
return Extract.CACHE_ROOT
end
return "data/generated/gba"
end
local bgr555_to_rgb8 = BgBake.bgr555ToRgb8
local byte_len = BgBake.byteLen
local decode_tile_4bpp = BgBake.decodeTile4bpp
local load_pal_banks = BgBake.loadPalBanks
local bake_bg_rgba = BgBake.bakeBgRgba
--- Render 64x64 Berry Pouch animated sprite.
local function bake_pouch_sprite_rgba(gfx, palBytes)
local W, H = 64, 64
local banks = load_pal_banks(palBytes, 1)
local pal = banks[0] or {}
local tileCount = math.floor(byte_len(gfx) / 32)
local pixels = {}
for i = 1, W * H do pixels[i] = 0 end
local ti = 0
for ty = 0, 7 do
for tx = 0, 7 do
if ti < tileCount then
local tile = {}
local base = ti * 32
for i = 1, 32 do tile[i] = gfx[base + i] or 0 end
decode_tile_4bpp(tile, pixels, tx * 8, ty * 8, W, false, false)
end
ti = ti + 1
end
end
local chunks = {}
for i = 1, W * H do
local idx = pixels[i] or 0
if idx == 0 then
chunks[i] = string.char(0, 0, 0, 0)
else
local r, g, b = bgr555_to_rgb8(pal[idx] or 0)
chunks[i] = string.char(r, g, b, 255)
end
end
return table.concat(chunks)
end
function BerryPouchExtract.run(rom, cache, opts)
opts = opts or {}
local cacheRoot = opts.cacheRoot or default_cache_root()
local root = cacheRoot .. "/" .. BerryPouchExtract.CACHE_SUB
local W = opts.width or 240
local H = opts.height or 160
local function get(i) return rom:get(i) end
local gfx = Lz77.decompress(get, Versions.BERRY_POUCH_BG_GFX)
local map = Lz77.decompress(get, Versions.BERRY_POUCH_BG_TILEMAP)
local palMale = Lz77.decompress(get, Versions.BERRY_POUCH_BG_PAL)
local palFemaleOverride = Lz77.decompress(get, Versions.BERRY_POUCH_BG_PAL_FEMALE)
local maleBanks = load_pal_banks(palMale, 3)
local femaleBanks = load_pal_banks(palMale, 3)
local overrideBank = load_pal_banks(palFemaleOverride, 1)[0]
if overrideBank then
femaleBanks[0] = overrideBank
end
-- 1. Backgrounds
local rgbaMale = bake_bg_rgba(gfx, maleBanks, map, W, H)
local rgbaFemale = bake_bg_rgba(gfx, femaleBanks, map, W, H)
cache:write(root .. "/bg_male.rgba", rgbaMale)
cache:write(root .. "/bg_female.rgba", rgbaFemale)
-- 2. Berry Pouch Sprite (64x64)
local spriteGfx = Lz77.decompress(get, Versions.BERRY_POUCH_SPRITE_GFX)
local spritePal = Lz77.decompress(get, Versions.BERRY_POUCH_SPRITE_PAL)
local pouchRgba = bake_pouch_sprite_rgba(spriteGfx, spritePal)
cache:write(root .. "/pouch.rgba", pouchRgba)
local manifest = string.format([[
return {
format_version = %d,
width = %d,
height = %d,
pouchW = 64,
pouchH = 64,
}
]], BerryPouchExtract.FORMAT_VERSION, W, H)
cache:write(root .. "/manifest.lua", manifest)
print(string.format("[berry_pouch_extract] Berry Pouch chrome baked (2 backgrounds, 64x64 pouch sprite) -> %s", root))
return {
root = root,
width = W,
height = H,
}
end
function BerryPouchExtract.ready(cache, cacheRoot)
local root = (cacheRoot or default_cache_root()) .. "/" .. BerryPouchExtract.CACHE_SUB
if cache and cache.exists then
return cache:exists(root .. "/bg_male.rgba") and cache:exists(root .. "/pouch.rgba")
end
return false
end
return BerryPouchExtract