mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
3252a3f2c9
game3 prints every string with the US cart's Latin font, and FrlgFont has
no glyph for a kana, so a Japanese translation of FireRed would print
blank. The US cart still carries its Japanese fonts, which its text
printer draws for a string in Japanese mode (pokefirered/src/text.c:141,
:227): pret builds them into the US ROM, with the normal font's width
table.
The font extractor now bakes both, the normal font from its eight-to-a-row
layout (DecompressGlyph_Normal, text.c:1452) with its widths and the small
one sixteen to a row (DecompressGlyph_Small, text.c:1372), as
chrome/fonts/japanese_{normal,small}_{fg,shadow}.rgba and
japanese_widths.lua. LeafGreen's addresses follow the same -0x24 shift as
the rest of text.o. Cache version 120 re-imports existing caches.
FrlgFont numbers a Japanese character by its byte in the Japanese block of
pokefirered/charmap.txt (kana 01-A0, the full-width space, !?。ー), plus
the symbols the font keeps at the Latin block's codes in their full-width
forms (digits, letters, 『』「」, 円, /, :), offset past the Latin
glyphs. A character with no Latin glyph draws from the Japanese sheet, at
the width the cart gives it (the table for the normal font, 8px for the
small one). Latin text is drawn as before.
151 lines
5.3 KiB
Lua
151 lines
5.3 KiB
Lua
#!/usr/bin/env luajit
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local failed = 0
|
|
local function check(cond, msg)
|
|
if cond then
|
|
print("[ok] " .. msg)
|
|
else
|
|
failed = failed + 1
|
|
print("[FAIL] " .. msg)
|
|
end
|
|
end
|
|
|
|
local function finish()
|
|
if failed > 0 then
|
|
print("[test] FAILED " .. failed)
|
|
os.exit(1)
|
|
end
|
|
print("[test] all passed")
|
|
os.exit(0)
|
|
end
|
|
|
|
local Versions = require("src.import.gba.versions")
|
|
local CacheContract = require("src.import.CacheContract")
|
|
|
|
local ROUND_KEYS = {
|
|
"data/generated/gba/scripts/multichoice.lua",
|
|
"data/generated/gba/pokemon/battle/terrain_grass.rgba",
|
|
"data/generated/gba/pokemon/battle/terrain_cave.rgba",
|
|
"data/generated/gba/pokemon/battle/terrain_water.rgba",
|
|
"data/generated/gba/pokemon/battle/terrain_champion.rgba",
|
|
"data/generated/gba/pokemon/battle/terrain_bg_cave.rgba",
|
|
"data/generated/gba/pokemon/pokedex/paper_bg.rgba",
|
|
"data/generated/gba/pokemon/pokedex/footprints/1.rgba",
|
|
"data/generated/gba/pokemon/pokedex/footprints/bulbasaur.rgba",
|
|
"data/generated/gba/pokemon/pokedex/footprints/question_mark.rgba",
|
|
"data/generated/gba/chrome/fonts/japanese_normal_fg.rgba",
|
|
"data/generated/gba/chrome/fonts/japanese_small_fg.rgba",
|
|
"data/generated/gba/chrome/fonts/japanese_widths.lua",
|
|
"data/generated/gba/chrome/fonts/braille_fg.rgba",
|
|
"data/generated/gba/chrome/fonts/braille_shadow.rgba",
|
|
"data/generated/gba/chrome/fonts/braille.lua",
|
|
"data/generated/gba/seagallop/manifest.lua",
|
|
"data/generated/gba/seagallop/water.4bpp",
|
|
"data/generated/gba/seagallop/ferry.4bpp",
|
|
"data/generated/gba/seagallop/wake.4bpp",
|
|
"data/generated/gba/seagallop/wb_tilemap.bin",
|
|
"data/generated/gba/seagallop/eb_tilemap.bin",
|
|
"data/generated/gba/seagallop/wb.rgba",
|
|
"data/generated/gba/seagallop/eb.rgba",
|
|
}
|
|
|
|
print("[test] 1. the cache version carries this round's importer output")
|
|
local CURRENT = Versions.CACHE_VERSION
|
|
check(type(CURRENT) == "number" and CURRENT >= 106,
|
|
"Versions.CACHE_VERSION carries the round (" .. tostring(CURRENT) .. ")")
|
|
|
|
print("[test] 2. every key this round added is in the firered required list")
|
|
local required, isOverride = CacheContract.requiredFilesFor("firered")
|
|
check(isOverride == true, "firered has its own required list")
|
|
local have = {}
|
|
for _, path in ipairs(required) do have[path] = true end
|
|
for _, path in ipairs(ROUND_KEYS) do
|
|
check(have[path] == true, "the firered contract requires " .. path)
|
|
end
|
|
|
|
print("[test] 3. a cache missing one of them is incomplete")
|
|
for _, path in ipairs(ROUND_KEYS) do
|
|
local fs = {
|
|
prefix = "",
|
|
exists = function(candidate) return candidate ~= path end,
|
|
}
|
|
local complete, missing = CacheContract.allRequiredFilesExist("firered", fs)
|
|
check(complete == false and missing == path,
|
|
"a cache without " .. path .. " is incomplete (" .. tostring(missing) .. ")")
|
|
end
|
|
|
|
print("[test] 4. the staleness gate rejects an older cache")
|
|
local META = "data/generated/gba/meta.json"
|
|
local stamp = CURRENT
|
|
local stampFs = {
|
|
prefix = "",
|
|
exists = function() return true end,
|
|
read = function(rel)
|
|
if rel == CacheContract.MARKER_PATH then return CacheContract.markerFor("firered") end
|
|
if rel == META then
|
|
return '{"md5":"x","cache_version":' .. tostring(stamp) .. ',"native_version":6}'
|
|
end
|
|
return nil
|
|
end,
|
|
}
|
|
check(CacheContract.cacheVersionCurrent("firered", stampFs) == true,
|
|
"a current meta.json is current")
|
|
check(CacheContract.isReady("firered", stampFs) == true,
|
|
"a complete current cache is ready")
|
|
stamp = CURRENT - 1
|
|
check(CacheContract.cacheVersionCurrent("firered", stampFs) == false,
|
|
"a meta.json one version back is stale")
|
|
check(CacheContract.isReady("firered", stampFs) == false,
|
|
"a complete cache one version back is not ready, so it re-imports")
|
|
stamp = CURRENT - 2
|
|
check(CacheContract.isReady("firered", stampFs) == false,
|
|
"a complete cache two versions back is not ready either")
|
|
stamp = CURRENT
|
|
|
|
print("[test] 5. an imported cache walks the whole required list")
|
|
local Cache = require("tests.game3_cache")
|
|
local root = Cache.root("meta.json")
|
|
if not root then
|
|
print("[skip] cache walk: " .. tostring(Cache.reason))
|
|
finish()
|
|
end
|
|
print("[info] FireRed cache at " .. root)
|
|
|
|
local function readFile(rel)
|
|
local f = io.open(root .. "/" .. rel, "rb")
|
|
if not f then return nil end
|
|
local data = f:read("*a")
|
|
f:close()
|
|
return data
|
|
end
|
|
|
|
local metaRaw = readFile("meta.json") or ""
|
|
check(metaRaw:find('"cache_version"%s*:%s*' .. tostring(CURRENT)) ~= nil,
|
|
"the imported cache is stamped " .. tostring(CURRENT))
|
|
|
|
local base = root:gsub("/data/generated/gba$", "")
|
|
check(base ~= root, "the cache root sits under a version directory (" .. base .. ")")
|
|
|
|
local function present(rel)
|
|
local f = io.open(base .. "/" .. rel, "rb")
|
|
if f then f:close(); return true end
|
|
return false
|
|
end
|
|
|
|
local missing, walked = {}, 0
|
|
for _, path in ipairs(required) do
|
|
walked = walked + 1
|
|
if not present(path) then missing[#missing + 1] = path end
|
|
end
|
|
check(walked >= 100, "the walk covered the whole firered contract (" .. walked .. ")")
|
|
check(#missing == 0, "no required key is missing (" .. (missing[1] or "none") .. ")")
|
|
|
|
local liveFs = { prefix = "", exists = present }
|
|
local complete, firstMissing = CacheContract.allRequiredFilesExist("firered", liveFs)
|
|
check(complete == true,
|
|
"CacheContract calls the imported cache complete (" .. tostring(firstMissing) .. ")")
|
|
|
|
finish()
|