mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-10-07 17:31:35 -04:00
c93f035359
- Hidden Items & Itemfinder (fixes #2314): * Extract BG_EVENT_HIDDEN_ITEM (kind 7) from GBA ROM with proper flag calculation (0x3E8 + id), underfoot flags, and quantities. * Implement overworld Itemfinder scan logic (7-tile radius, directional response, underfoot detection, SFX 65, and OEM text). * Wire up Bag Menu Itemfinder dispatch to overworld field runtime. - Opponent Battle HUD Caught Marker (fixes #2313): * Add authentic Pokédex caught Poké Ball icon (B_INTERFACE_GFX_BALL_CAUGHT / tile 70) to opponent healthbox. * Match pokefirered parity in TryAddPokeballIconToHealthbox (wild encounters only, non-tutorial, non-ghost, checked against Dex). * Ensure status ailment icons (PSN, PAR, SLP, FRZ, BRN) take rendering priority over the caught ball marker. - Level-Up Learnset & Movepool Assignment (fixes #2315): * Fix wild and generated Pokémon moveset assignment to assign the 4 most recent level-up moves up to the current level instead of getting stuck on basic moves (e.g. Tackle). - Easy Chat / Profile Quick Chat: * Extract full word groups, categories, and dictionary entries from ROM. * Build Easy Chat interface with group selection, paginated word lists, and alphabetized filtering. * Fix dialog text overflowing when exiting profile / quick chat prompts. - Nurse Joy & PC Storage / Map Polishing: * Implement Nurse Joy healing tray animation flow and audio cues in standard scripts. * Fix PC storage box header/wallpaper rendering and storage data extraction. * Correct Sevii Islands / Island 1 map section lookups and region map coordinate handling. * Fix circular dependency in battle residual handlers (partialTrap). fixes #2325 fixes #2322 fixes #2315 fixes #2314 fixes #2313
513 lines
18 KiB
Lua
513 lines
18 KiB
Lua
#!/usr/bin/env luajit
|
|
-- Offline FRLG extract → CacheFS (Love firered save dir), never mod-tree.
|
|
-- Usage (from repo root):
|
|
-- luajit src/import/gba/cli_extract.lua [path/to/firered.gba]
|
|
-- luajit src/import/gba/cli_extract.lua --native-only [rom]
|
|
-- Override output with GBA_CACHE_ROOT=/path/to/firered (contains data/generated/gba).
|
|
|
|
package.path = package.path
|
|
.. ";./?.lua;./?/init.lua"
|
|
.. ";mods/Kanto-Reforged/?.lua;mods/Kanto-Reforged/?/init.lua"
|
|
|
|
-- Allow running from inside the mod directory.
|
|
local function add_path(p)
|
|
package.path = p .. "/?.lua;" .. p .. "/?/init.lua;" .. package.path
|
|
end
|
|
add_path(".")
|
|
add_path("..")
|
|
add_path("../..")
|
|
add_path("../../..")
|
|
|
|
-- Map mods.Kanto-Reforged.* → local sevii when running inside mod tree.
|
|
local real_require = require
|
|
table.insert(package.searchers or package.loaders, 1, function(name)
|
|
local prefix = "mods.Kanto-Reforged."
|
|
if name:sub(1, #prefix) == prefix then
|
|
local rel = name:sub(#prefix + 1):gsub("%.", "/")
|
|
local candidates = {
|
|
rel .. ".lua",
|
|
"./" .. rel .. ".lua",
|
|
}
|
|
for _, c in ipairs(candidates) do
|
|
local f = io.open(c, "r")
|
|
if f then
|
|
f:close()
|
|
return assert(loadfile(c))
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
local FileIO = require("src.import.gba.file_io")
|
|
local Extract = require("src.import.gba.extract_island1")
|
|
|
|
local nativeOnly = false
|
|
local pokemonOnly = false
|
|
local battleMovesOnly = false
|
|
local encountersOnly = false
|
|
local namingOnly = false
|
|
local introOnly = false
|
|
local battleAnimsOnly = false
|
|
local battleAiOnly = false
|
|
local battleTransitionsOnly = false
|
|
local trainersOnly = false
|
|
local itemsOnly = false
|
|
local pokedexOnly = false
|
|
local mapTreeOnly = false
|
|
local martsOnly = false
|
|
local scriptsOnly = false
|
|
local bagChromeOnly = false
|
|
local storageChromeOnly = false
|
|
local dumpMid = nil -- { pair, mid, outPath }
|
|
local romPath = nil
|
|
local ai = 1
|
|
while ai <= #arg do
|
|
if arg[ai] == "--native-only" then
|
|
nativeOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--pokemon" then
|
|
pokemonOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--items" then
|
|
itemsOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--pokedex" then
|
|
pokedexOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--marts" then
|
|
martsOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--scripts" then
|
|
scriptsOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--bag-chrome" then
|
|
bagChromeOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--storage-chrome" or arg[ai] == "--storage" then
|
|
storageChromeOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--map-tree" then
|
|
mapTreeOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--battle-moves" then
|
|
battleMovesOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--battle-anims" then
|
|
battleAnimsOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--battle-ai" then
|
|
battleAiOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--battle-transitions" then
|
|
battleTransitionsOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--trainers" then
|
|
trainersOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--encounters" then
|
|
encountersOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--naming" then
|
|
namingOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--intro" then
|
|
introOnly = true
|
|
ai = ai + 1
|
|
elseif arg[ai] == "--dump-mid" and arg[ai + 3] then
|
|
dumpMid = { pair = arg[ai + 1], mid = tonumber(arg[ai + 2]), out = arg[ai + 3] }
|
|
ai = ai + 4
|
|
elseif not romPath and arg[ai]:sub(1, 1) ~= "-" then
|
|
romPath = arg[ai]
|
|
ai = ai + 1
|
|
else
|
|
ai = ai + 1
|
|
end
|
|
end
|
|
|
|
if not romPath then
|
|
-- Default: FireRed dump in mod root (gitignored).
|
|
local here = debug.getinfo(1, "S").source:match("@(.*)/") or "."
|
|
romPath = here .. "/../../1636 - Pokemon Fire Red (U)(Squirrels).gba"
|
|
if not io.open(romPath, "rb") then
|
|
romPath = "1636 - Pokemon Fire Red (U)(Squirrels).gba"
|
|
end
|
|
end
|
|
|
|
local md5
|
|
do
|
|
-- Engine identity is SHA-1; fall back to md5sum (Versions.BY_MD5 aliases).
|
|
local q = "'" .. romPath:gsub("'", "'\\''") .. "'"
|
|
local p = io.popen("sha1sum " .. q .. " 2>/dev/null || shasum -a 1 " .. q)
|
|
local line = p and p:read("*l")
|
|
if p then p:close() end
|
|
md5 = line and line:match("^(%x+)")
|
|
if not md5 then
|
|
p = io.popen("md5sum " .. q)
|
|
line = p and p:read("*l")
|
|
if p then p:close() end
|
|
md5 = line and line:match("^(%x+)")
|
|
end
|
|
md5 = md5 or "41cb23d8dccc8ebd7c649cd8fbb58eeace6e2fdc"
|
|
end
|
|
|
|
print("ROM:", romPath)
|
|
print("SHA1:", md5)
|
|
|
|
local imports = FileIO.makeImports(romPath, md5, "firered")
|
|
-- CacheFS root: Love firered save dir (data/generated/gba lives underneath).
|
|
local outDir = os.getenv("GBA_CACHE_ROOT")
|
|
or ((os.getenv("HOME") or ".") .. "/.local/share/love/pokemon-love2d/firered")
|
|
Extract.CACHE_ROOT = "data/generated/gba"
|
|
Extract.NATIVE_ROOT = "data/generated/gba/native"
|
|
local cache = FileIO.makeCache(outDir)
|
|
print("CacheFS:", outDir .. "/" .. Extract.CACHE_ROOT)
|
|
|
|
if dumpMid then
|
|
local Rom = require("src.import.gba.rom")
|
|
local Versions = require("src.import.gba.versions")
|
|
local Tileset = require("src.import.gba.tileset")
|
|
local Metatile = require("src.import.gba.metatile")
|
|
local NativePack = require("src.import.gba.native_pack")
|
|
local version = assert(Versions.lookup(md5))
|
|
local rom = assert(Rom.open(imports, "firered"))
|
|
local bundle = assert(Tileset.loadPair(rom, version, dumpMid.pair))
|
|
local idx = Metatile.compositeIndexed(bundle, dumpMid.mid)
|
|
local rgb = NativePack.palsToRgb8(bundle.mapPals)
|
|
local fake = {
|
|
midCount = 1, atlasCols = 1, atlasRows = 1, midIds = { dumpMid.mid }, pixels = idx,
|
|
}
|
|
local rgba = NativePack.bakeRgba(fake, rgb)
|
|
local f = assert(io.open(dumpMid.out, "wb"))
|
|
f:write("P6\n16 16\n255\n")
|
|
for i = 1, 16 * 16 do
|
|
local o = (i - 1) * 4 + 1
|
|
f:write(string.char(rgba:byte(o), rgba:byte(o + 1), rgba:byte(o + 2)))
|
|
end
|
|
f:close()
|
|
print("Wrote", dumpMid.out)
|
|
imports:_close()
|
|
os.exit(0)
|
|
end
|
|
|
|
if namingOnly or introOnly then
|
|
print("NOTE: --naming/--intro require Love2D image encoders; use RomExtractorGen3 or love runner.")
|
|
print("Offsets live in Versions.NAMING / Versions.INTRO.")
|
|
os.exit(0)
|
|
end
|
|
|
|
if battleMovesOnly then
|
|
local Rom = require("src.import.gba.rom")
|
|
local BattleMovesExtract = require("src.import.gba.battle_moves_extract")
|
|
local outRoot = os.getenv("HOME")
|
|
and (os.getenv("HOME") .. "/.local/share/love/pokemon-love2d/firered")
|
|
or "."
|
|
local packCache = FileIO.makeCache(outRoot)
|
|
local rom = assert(Rom.open(imports, "firered"))
|
|
print("Extracting gBattleMoves →", outRoot .. "/data/generated/gba/pokemon")
|
|
local detail = BattleMovesExtract.run(rom, packCache, { cacheRoot = "data/generated/gba" })
|
|
rom:clearCache()
|
|
imports:_close()
|
|
print("OK battle moves", detail.pack.count, "→", detail.path)
|
|
os.exit(0)
|
|
end
|
|
|
|
if encountersOnly then
|
|
local Rom = require("src.import.gba.rom")
|
|
local Versions = require("src.import.gba.versions")
|
|
local EncExtract = require("src.import.gba.encounters_extract")
|
|
local outRoot = os.getenv("HOME")
|
|
and (os.getenv("HOME") .. "/.local/share/love/pokemon-love2d/firered")
|
|
or "."
|
|
local packCache = FileIO.makeCache(outRoot)
|
|
local version = assert(Versions.lookup(md5))
|
|
local rom = assert(Rom.open(imports, "firered"))
|
|
print("Extracting gWildMonHeaders →", outRoot .. "/data/generated/gba/encounters.lua")
|
|
local detail = assert(EncExtract.writeExtract(rom, packCache, "data/generated/gba", version))
|
|
rom:clearCache()
|
|
imports:_close()
|
|
print("OK encounters", detail.headers, "headers,", detail.aliases, "aliases")
|
|
os.exit(0)
|
|
end
|
|
|
|
if battleAnimsOnly then
|
|
local Rom = require("src.import.gba.rom")
|
|
local AnimExtract = require("src.import.gba.battle_anim_extract")
|
|
local outRoot = outDir
|
|
local packCache = cache
|
|
local rom = assert(Rom.open(imports, "firered"))
|
|
print("Extracting battle anim IR →", outRoot .. "/data/generated/gba/pokemon/battle_anims")
|
|
local animCache = {
|
|
write = function(_, rel, bytes)
|
|
local path = rel
|
|
if not path:match("^data/") then
|
|
path = "data/generated/gba/" .. path
|
|
end
|
|
return packCache:write(path, bytes)
|
|
end,
|
|
exists = function(_, rel) return packCache.exists and packCache:exists(rel) end,
|
|
read = function(_, rel) return packCache.read and packCache:read(rel) end,
|
|
}
|
|
local detail = assert(AnimExtract.run(rom, animCache, { cacheRoot = "data/generated/gba", force = true }))
|
|
rom:clearCache()
|
|
imports:_close()
|
|
print("OK battle anims", detail.moveCount, "→", detail.path)
|
|
os.exit(0)
|
|
end
|
|
|
|
if battleAiOnly then
|
|
local AiExtract = require("src.import.gba.battle_ai_extract")
|
|
local outRoot = os.getenv("HOME")
|
|
and (os.getenv("HOME") .. "/.local/share/love/pokemon-love2d/firered")
|
|
or "."
|
|
local packCache = FileIO.makeCache(outRoot)
|
|
print("Extracting battle AI scripts →", outRoot .. "/data/generated/gba/battle_ai")
|
|
local detail = assert(AiExtract.run({
|
|
cache = packCache,
|
|
cacheRoot = "data/generated/gba",
|
|
pretRoot = os.getenv("POKEFIRERED"),
|
|
}))
|
|
imports:_close()
|
|
print("OK battle AI", detail.scriptCount or "?", "scripts →", detail.path or detail.root)
|
|
os.exit(0)
|
|
end
|
|
|
|
if battleTransitionsOnly then
|
|
local Rom = require("src.import.gba.rom")
|
|
local BattleTransitionExtract = require("src.import.gba.battle_transition_extract")
|
|
local outRoot = os.getenv("HOME")
|
|
and (os.getenv("HOME") .. "/.local/share/love/pokemon-love2d/firered")
|
|
or "."
|
|
local packCache = FileIO.makeCache(outRoot)
|
|
local rom = assert(Rom.open(imports, "firered"))
|
|
print("Extracting battle transitions →", outRoot .. "/data/generated/gba/pokemon/battle_transition")
|
|
local detail = assert(BattleTransitionExtract.run(rom, packCache, {
|
|
cacheRoot = "data/generated/gba",
|
|
}))
|
|
rom:clearCache()
|
|
imports:_close()
|
|
print("OK battle transition →", detail.root,
|
|
detail.bigW .. "x" .. detail.bigH, "big_pokeball")
|
|
os.exit(0)
|
|
end
|
|
|
|
if trainersOnly then
|
|
local Rom = require("src.import.gba.rom")
|
|
local TrainerExtract = require("src.import.gba.trainer_extract")
|
|
local outRoot = os.getenv("HOME")
|
|
and (os.getenv("HOME") .. "/.local/share/love/pokemon-love2d/firered")
|
|
or "."
|
|
local packCache = FileIO.makeCache(outRoot)
|
|
local rom = assert(Rom.open(imports, "firered"))
|
|
print("Extracting trainers →", outRoot .. "/data/generated/gba/trainers.lua")
|
|
local detail = TrainerExtract.run(rom, packCache, { cacheRoot = "data/generated/gba" })
|
|
rom:clearCache()
|
|
imports:_close()
|
|
print("OK trainers", detail.pack.trainerCount, "→", detail.root)
|
|
os.exit(0)
|
|
end
|
|
|
|
if pokemonOnly then
|
|
local Rom = require("src.import.gba.rom")
|
|
local PokemonExtract = require("src.import.gba.pokemon_extract")
|
|
-- Standalone FireRed cache (never sevii). Prefer LOVE save dir when present.
|
|
local outRoot = os.getenv("HOME")
|
|
and (os.getenv("HOME") .. "/.local/share/love/pokemon-love2d/firered")
|
|
or "."
|
|
local packCache = FileIO.makeCache(outRoot)
|
|
local rom = assert(Rom.open(imports, "firered"))
|
|
print("Extracting Pokémon pack →", outRoot .. "/data/generated/gba/pokemon")
|
|
local detail = PokemonExtract.run(rom, packCache, {
|
|
cacheRoot = "data/generated/gba",
|
|
progress = function(stage, cur, total)
|
|
if cur % 50 == 0 or cur + 1 >= total then
|
|
print(string.format(" [%s] %d/%d", stage, cur, total))
|
|
end
|
|
end,
|
|
})
|
|
rom:clearCache()
|
|
imports:_close()
|
|
print("OK pokemon", detail.numSpecies, "species →", detail.root)
|
|
if detail.partyChrome then
|
|
print("OK party chrome →", detail.partyChrome.root)
|
|
end
|
|
if detail.battleChrome then
|
|
print("OK battle chrome →", detail.battleChrome.root,
|
|
detail.battleChrome.textboxW, "x", detail.battleChrome.textboxH)
|
|
end
|
|
if detail.stats and detail.stats[1] then
|
|
local s = detail.stats[1]
|
|
print(string.format(" Bulbasaur stats hp=%d atk=%d def=%d spe=%d spa=%d spd=%d",
|
|
s.hp, s.atk, s.def, s.spe, s.spa, s.spd))
|
|
end
|
|
if detail.abilityNames and detail.abilityNames[1] then
|
|
print(" ability 1 =", detail.abilityNames[1])
|
|
end
|
|
if detail.learnsets and detail.learnsets[1] then
|
|
local parts = {}
|
|
for _, e in ipairs(detail.learnsets[1]) do
|
|
local name = detail.moveNames and detail.moveNames[e.move] or tostring(e.move)
|
|
parts[#parts + 1] = string.format("Lv%d %s", e.level, name)
|
|
end
|
|
print(" Bulbasaur learnset:", table.concat(parts, ", "))
|
|
end
|
|
if detail.battleMoves and detail.battleMoves.moves and detail.battleMoves.moves[33] then
|
|
local t = detail.battleMoves.moves[33]
|
|
print(string.format(" TACKLE pp=%d power=%d", t.pp, t.power))
|
|
end
|
|
os.exit(0)
|
|
end
|
|
|
|
if itemsOnly then
|
|
local Rom = require("src.import.gba.rom")
|
|
local ItemsExtract = require("src.import.gba.items_extract")
|
|
local outRoot = os.getenv("HOME")
|
|
and (os.getenv("HOME") .. "/.local/share/love/pokemon-love2d/firered")
|
|
or "."
|
|
local packCache = FileIO.makeCache(outRoot)
|
|
local rom = assert(Rom.open(imports, "firered"))
|
|
print("Extracting items pack →", outRoot .. "/data/generated/gba/items")
|
|
local detail = ItemsExtract.run(rom, packCache, { cacheRoot = "data/generated/gba" })
|
|
rom:clearCache()
|
|
imports:_close()
|
|
print("OK items", detail and detail.count or "?", "→", detail and detail.path or outRoot)
|
|
os.exit(0)
|
|
end
|
|
|
|
if pokedexOnly then
|
|
local Rom = require("src.import.gba.rom")
|
|
local PokedexExtract = require("src.import.gba.pokedex_chrome_extract")
|
|
local outRoot = os.getenv("HOME")
|
|
and (os.getenv("HOME") .. "/.local/share/love/pokemon-love2d/firered")
|
|
or "."
|
|
local packCache = FileIO.makeCache(outRoot)
|
|
local rom = assert(Rom.open(imports, "firered"))
|
|
print("Extracting Pokédex data from ROM →", outRoot .. "/data/generated/gba/pokemon/pokedex")
|
|
local ok = PokedexExtract.run(rom, packCache, {
|
|
cacheRoot = "data/generated/gba",
|
|
force = true,
|
|
progress = function(stage, cur, total)
|
|
print(string.format(" [%s] %d/%d", stage, cur, total))
|
|
end,
|
|
})
|
|
rom:clearCache()
|
|
imports:_close()
|
|
print("OK pokedex entries, categories, and orders extracted from ROM")
|
|
os.exit(0)
|
|
end
|
|
|
|
if martsOnly then
|
|
local Rom = require("src.import.gba.rom")
|
|
local MartsExtract = require("src.import.gba.marts_extract")
|
|
local outRoot = outDir
|
|
local packCache = cache
|
|
local rom = assert(Rom.open(imports, "firered"))
|
|
print("Extracting pokemart lists →", outRoot .. "/data/generated/gba/scripts/marts.lua")
|
|
local detail, err = MartsExtract.run(rom, packCache, { cacheRoot = Extract.CACHE_ROOT })
|
|
rom:clearCache()
|
|
imports:_close()
|
|
if not detail then
|
|
io.stderr:write("FAIL marts: " .. tostring(err) .. "\n")
|
|
os.exit(1)
|
|
end
|
|
print("OK marts", detail.listCount, "lists from", detail.ptrCount, "ptrs →", detail.path)
|
|
os.exit(0)
|
|
end
|
|
|
|
if scriptsOnly then
|
|
local Rom = require("src.import.gba.rom")
|
|
local ExtractScripts = require("src.import.gba.extract_scripts")
|
|
local Versions = require("src.import.gba.versions")
|
|
local outRoot = outDir
|
|
local packCache = cache
|
|
local rom = assert(Rom.open(imports, "firered"))
|
|
local version = Versions.lookup(rom.md5)
|
|
print("Extracting scripts bundle →", outRoot .. "/data/generated/gba/scripts")
|
|
local bundle = ExtractScripts.writeBundleFromRom(rom, packCache, Extract.CACHE_ROOT, version)
|
|
rom:clearCache()
|
|
imports:_close()
|
|
print("OK scripts", bundle.scriptCount, "scripts →", Extract.CACHE_ROOT .. "/scripts")
|
|
os.exit(0)
|
|
end
|
|
|
|
if bagChromeOnly then
|
|
local Rom = require("src.import.gba.rom")
|
|
local BagChromeExtract = require("src.import.gba.bag_chrome_extract")
|
|
local rom = assert(Rom.open(imports, "firered"))
|
|
print("Extracting bag chrome + icons →", outDir .. "/data/generated/gba/items/bag")
|
|
local detail = BagChromeExtract.run(rom, cache, {
|
|
cacheRoot = Extract.CACHE_ROOT,
|
|
progress = function(stage, cur, total)
|
|
if cur % 50 == 0 or cur + 1 >= total then
|
|
print(string.format(" [%s] %d/%d", stage, cur, total))
|
|
end
|
|
end,
|
|
})
|
|
rom:clearCache()
|
|
imports:_close()
|
|
print("OK bag-chrome icons=", detail.iconsBaked, "→", detail.root)
|
|
os.exit(0)
|
|
end
|
|
|
|
if storageChromeOnly then
|
|
local Rom = require("src.import.gba.rom")
|
|
local StorageChromeExtract = require("src.import.gba.storage_chrome_extract")
|
|
local rom = assert(Rom.open(imports, "firered"))
|
|
print("Extracting storage chrome + wallpapers →", outDir .. "/data/generated/gba/pokemon/storage")
|
|
local detail = StorageChromeExtract.run(rom, cache, {
|
|
cacheRoot = Extract.CACHE_ROOT,
|
|
force = true,
|
|
})
|
|
rom:clearCache()
|
|
imports:_close()
|
|
print("OK storage-chrome assets=", detail.count or "?", "→", detail.root or (Extract.CACHE_ROOT .. "/pokemon/storage"))
|
|
os.exit(0)
|
|
end
|
|
|
|
if mapTreeOnly then
|
|
local Rom = require("src.import.gba.rom")
|
|
local Versions = require("src.import.gba.versions")
|
|
local MapTreeExtract = require("src.import.gba.map_tree_extract")
|
|
local outRoot = os.getenv("HOME")
|
|
and (os.getenv("HOME") .. "/.local/share/love/pokemon-love2d/firered")
|
|
or "."
|
|
local packCache = FileIO.makeCache(outRoot)
|
|
local version = assert(Versions.lookup(md5))
|
|
local rom = assert(Rom.open(imports, "firered"))
|
|
print("Walking gMapGroups →", outRoot .. "/data/generated/gba/map_tree")
|
|
local ok, detail = MapTreeExtract.run(rom, packCache, {
|
|
version = version,
|
|
progress = function(name, cur, total)
|
|
if cur % 50 == 0 or cur + 1 >= total then
|
|
print(string.format(" %s %d/%d", name, cur, total))
|
|
end
|
|
end,
|
|
})
|
|
rom:clearCache()
|
|
imports:_close()
|
|
if not ok then
|
|
io.stderr:write("FAIL map-tree: " .. tostring(detail) .. "\n")
|
|
os.exit(1)
|
|
end
|
|
print("OK map-tree", detail.map_count, "maps", detail.tileset_count, "tilesets")
|
|
print(" →", outRoot .. "/" .. detail.root)
|
|
os.exit(0)
|
|
end
|
|
|
|
local runner = nativeOnly and Extract.runNativeOnly or Extract.run
|
|
local ok, detail = runner(imports, cache, function(stage, n, name, cur, total)
|
|
print(string.format(" [%d/%d] %s %s/%s", stage, n, name, tostring(cur), tostring(total)))
|
|
end)
|
|
imports:_close()
|
|
|
|
if not ok then
|
|
io.stderr:write("FAIL: " .. tostring(detail) .. "\n")
|
|
os.exit(1)
|
|
end
|
|
if detail.native_only then
|
|
print("OK native-only", detail.md5,
|
|
"pairs=" .. tostring(detail.pairs), "maps=" .. tostring(detail.maps))
|
|
else
|
|
print("OK", detail.tile_count, "tiles", detail.block_count, "blocks", detail.mid_count, "mids")
|
|
end
|
|
print("Wrote CacheFS", outDir .. "/" .. Extract.CACHE_ROOT)
|