diff --git a/data/scripts/celadon_eevee.lua b/data/scripts/celadon_eevee.lua index 4b6a78de..d7982e97 100644 --- a/data/scripts/celadon_eevee.lua +++ b/data/scripts/celadon_eevee.lua @@ -25,8 +25,10 @@ local Menu = require("src.ui.Menu") local TextBox = require("src.render.TextBox") --- TMNotebookText (data/text/text_2.asm) has no leading underscore, so the --- extractor never collects it and the pamphlet's text is inlined. +-- TMNotebookText (data/text/text_2.asm) has no leading underscore, but the +-- extractor now collects any top-level label in a dedicated text file +-- regardless (tools/extract/text.py), so this is the real ROM label -- +-- the literal below is only the fallback for a catalog without it. local TM_NOTEBOOK_TEXT = "It's a pamphlet\non TMs.\f...\f" .. "There are 50 TMs\nin all.\f" .. "There are also 5\nHMs that can be\vused repeatedly.\f" @@ -70,7 +72,8 @@ return { return true end if fx == 3 and fy == 4 then - game.stack:push(TextBox.new(game, TM_NOTEBOOK_TEXT)) + local text = game.data.text or {} + game.stack:push(TextBox.new(game, text.TMNotebookText or TM_NOTEBOOK_TEXT)) return true end return false diff --git a/data/scripts/flavor/ss_anne_kitchen.lua b/data/scripts/flavor/ss_anne_kitchen.lua index f3180ce6..981c8dc5 100644 --- a/data/scripts/flavor/ss_anne_kitchen.lua +++ b/data/scripts/flavor/ss_anne_kitchen.lua @@ -15,10 +15,10 @@ return { -- pick the dish: bit 7 set (~50%) -> Salmon du Salad, else bit 4 -- set (~25%) -> Eels au Barbecue, else (~25%) -> Prime Beef Steak. -- The three dish texts (SSAnneKitchenCook7SalmonDuSaladText / - -- ...EelsAuBarbecueText / ...PrimeBeefSteakText) aren't extracted - -- into data/generated/text.lua (no leading underscore in - -- pokered/text/SSAnneKitchen.asm), so their literal strings are - -- ported here verbatim. + -- ...EelsAuBarbecueText / ...PrimeBeefSteakText) have no leading + -- underscore in pokered/text/SSAnneKitchen.asm, but the extractor + -- collects them regardless (tools/extract/text.py); the literals + -- below are only the fallback for a catalog without them. TEXT_SSANNEKITCHEN_COOK7 = function(game, ow, npc, done) local t = game.data.text push(game, t._SSAnneKitchenCook7MainCourseIsText @@ -27,13 +27,16 @@ return { local dish if roll <= 2 then -- bit 7 of hRandomAdd set (~50%) - dish = "Salmon du Salad!\fLes guests may\ngripe it's fish\vagain, however!" + dish = t.SSAnneKitchenCook7SalmonDuSaladText + or "Salmon du Salad!\fLes guests may\ngripe it's fish\vagain, however!" elseif roll == 3 then -- bit 4 set, bit 7 clear (~25%) - dish = "Eels au Barbecue!\fLes guests will\nmutiny, I fear." + dish = t.SSAnneKitchenCook7EelsAuBarbecueText + or "Eels au Barbecue!\fLes guests will\nmutiny, I fear." else -- neither bit set (~25%) - dish = "Prime Beef Steak!\fBut, have I enough\nfillets du beef?" + dish = t.SSAnneKitchenCook7PrimeBeefSteakText + or "Prime Beef Steak!\fBut, have I enough\nfillets du beef?" end push(game, dish, done) end) diff --git a/data/scripts/flavor/viridian_city.lua b/data/scripts/flavor/viridian_city.lua index f78626f8..9213bb6c 100644 --- a/data/scripts/flavor/viridian_city.lua +++ b/data/scripts/flavor/viridian_city.lua @@ -60,22 +60,23 @@ M.VIRIDIAN_CITY = { -- you want to know about the two kinds of caterpillar Pokemon; -- YES -> CATERPIE/WEEDLE description, NO -> "Oh, OK then!". -- ViridianCityYoungster2OkThenText and - -- ViridianCityYoungster2CaterpieAndWeedleDescriptionText are - -- defined without a leading underscore in pokered/text/ViridianCity.asm - -- and aren't present in data/generated/text.lua, so we fall back to - -- the literal strings from pokered. Those fallbacks have to carry the - -- extractor's markers, not plain newlines: line -> \n, cont -> \v, - -- para -> \f. Spelling cont/para as \n and \n\n put all six lines on - -- one page with nothing to wait on, so the whole speech scrolled past - -- without a button press (#250). + -- ViridianCityYoungster2CaterpieAndWeedleDescriptionText are defined + -- without a leading underscore in pokered/text/ViridianCity.asm, but + -- tools/extract/text.py now collects them regardless -- the literal + -- strings below are only the fallback for a catalog without them. + -- Those fallbacks have to carry the extractor's markers, not plain + -- newlines: line -> \n, cont -> \v, para -> \f. Spelling cont/para as + -- \n and \n\n put all six lines on one page with nothing to wait on, + -- so the whole speech scrolled past without a button press (#250). TEXT_VIRIDIANCITY_YOUNGSTER2 = function(game, ow, npc, done) local t = text(game) ask(game, t._ViridianCityYoungster2YouWantToKnowAboutText or "You want to know\nabout the 2 kinds\vof caterpillar\vPOKéMON?", function(yes) if yes then - push(game, "CATERPIE has no\npoison, but\vWEEDLE does.\fWatch out for its\nPOISON STING!", done) + push(game, t.ViridianCityYoungster2CaterpieAndWeedleDescriptionText + or "CATERPIE has no\npoison, but\vWEEDLE does.\fWatch out for its\nPOISON STING!", done) else - push(game, "Oh, OK then!", done) + push(game, t.ViridianCityYoungster2OkThenText or "Oh, OK then!", done) end end) end, diff --git a/data/scripts/story5.lua b/data/scripts/story5.lua index 67002652..6f42068c 100644 --- a/data/scripts/story5.lua +++ b/data/scripts/story5.lua @@ -122,9 +122,8 @@ M.CINNABAR_LAB_METRONOME_ROOM = { -- TM42 Dream Eater (scripts/ViridianCity.asm, the fisher). The fisher's -- YouCanHaveThisText prints before GiveItem, so this gift needs a pre -- text (#775). Like the SilphCo2F worker (#393) that label carries no --- leading underscore, and on Red it sits outside the extractor's symbol --- set, so the literal from text/ViridianCity.asm rides along as the --- fallback; Yellow resolves the ROM string instead. +-- leading underscore; tools/extract/text.py now collects it regardless, +-- so preFallback below is just the safety net for a catalog without it. M.VIRIDIAN_CITY = { talk = { TEXT_VIRIDIANCITY_FISHER = gift({ @@ -146,9 +145,11 @@ M.SILPH_CO_2F = { talk = { TEXT_SILPHCO2F_SILPH_WORKER_F = gift({ flag = "EVENT_GOT_TM36", item = "TM_SELFDESTRUCT", - -- the label carries no leading underscore: pokered keeps this one in - -- the script bank, not the far-text bank (#393) + -- the label carries no leading underscore (#393); collected like any + -- other text/*.asm label now, preFallback is just the safety net pre = "SilphCo2FSilphWorkerFPleaseTakeThisText", + preFallback = "Eeek!\nNo! Stop! Help!\fOh, you're not\nwith TEAM ROCKET." + .. "\vI thought...\vI'm sorry. Here,\vplease take this!", received = "_SilphCo2FSilphWorkerFReceivedTM36Text", explain = "_SilphCo2FSilphWorkerFTM36ExplanationText", noRoom = "_SilphCo2FSilphWorkerFTM36NoRoomText", diff --git a/scripts/test.sh b/scripts/test.sh index b41b683d..fffa984c 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -67,6 +67,7 @@ run_tier() { # ------- ROM-free tiers: these are what CI runs run_tier "T0 ROM builder version routing" python3 tests/build_rom_data_cli_test.py +run_tier "T0 ROM manifest generator pin/overrides" python3 tests/rom_manifest_generator_test.py run_tier "T0 switch CI workflow content gate" "$LUA" tests/switch_ci_workflows_test.lua run_tier "T0 switch transfer docs gate" "$LUA" tests/switch_transfer_docs_test.lua # NX Blue/Yellow asset overlay: ROM-free, must run on every checkout so a diff --git a/tests/rom_manifest_generator_test.py b/tests/rom_manifest_generator_test.py new file mode 100644 index 00000000..07a88d1c --- /dev/null +++ b/tests/rom_manifest_generator_test.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +"""ROM-free regression tests for the manifest generator's version pin and +its documented, deliberate overrides. No pokered checkout or ROM needed.""" + +from pathlib import Path +from unittest import TestCase, main, mock + +import sys + +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "tools")) +import make_rom_manifest # noqa: E402 + + +class CheckPokeredRevisionTest(TestCase): + def test_matching_revision_is_silent(self): + with mock.patch.object( + make_rom_manifest, "_checkout_revision", return_value="abc"): + make_rom_manifest.check_pokered_revision("/pokered", "abc") + + def test_mismatched_revision_raises(self): + with mock.patch.object( + make_rom_manifest, "_checkout_revision", return_value="abc"): + with self.assertRaises(SystemExit): + make_rom_manifest.check_pokered_revision("/pokered", "def") + + def test_allow_mismatch_bypasses_the_raise(self): + with mock.patch.object( + make_rom_manifest, "_checkout_revision", return_value="abc"): + make_rom_manifest.check_pokered_revision( + "/pokered", "def", allow_mismatch=True) + + def test_unresolvable_checkout_is_silent(self): + # _checkout_revision returns None for a non-git directory; nothing + # to compare against, so this must not block generation. + with mock.patch.object( + make_rom_manifest, "_checkout_revision", return_value=None): + make_rom_manifest.check_pokered_revision("/pokered", "abc") + + +class ApplyKnownNonreproducibleOverridesTest(TestCase): + def fixtures(self): + texts = {"trainerHeaders": {}} + field_data = { + "seafoam": { + "SEAFOAM_ISLANDS_B3F": { + "pluggedByHolesOn": { + "holes": [{"showObject": "X"}, {"showObject": "Y"}], + }, + }, + }, + "tradeArt": {"bubble": "assets/generated/trade/bubble.png"}, + } + return texts, field_data + + def test_mtmoonb2f_super_nerd_slot_is_pinned(self): + texts, field_data = self.fixtures() + make_rom_manifest.apply_known_nonreproducible_overrides( + texts, field_data) + + self.assertEqual(texts["trainerHeaders"]["MtMoonB2F"][1], { + "after": "_MtMoonB2FSuperNerdTheresAPokemonLabText", + "battle": "_MtMoonB2FSuperNerdTheyreBothMineText", + "event": "EVENT_BEAT_MT_MOON_3_SUPER_NERD", + "won": "_MtMoonB2FSuperNerdOkIllShareText", + }) + + def test_mtmoonb2f_survives_a_populated_map_entry(self): + # A fresh extraction already fills in the map's other slots (2-5); + # the override must add slot 1 alongside them, not replace them. + texts, field_data = self.fixtures() + texts["trainerHeaders"]["MtMoonB2F"] = {2: {"event": "EVENT_OTHER"}} + make_rom_manifest.apply_known_nonreproducible_overrides( + texts, field_data) + + self.assertIn(1, texts["trainerHeaders"]["MtMoonB2F"]) + self.assertEqual( + texts["trainerHeaders"]["MtMoonB2F"][2], {"event": "EVENT_OTHER"}) + + def test_seafoam_boulder_toggle_ids_are_pinned(self): + texts, field_data = self.fixtures() + make_rom_manifest.apply_known_nonreproducible_overrides( + texts, field_data) + + holes = field_data["seafoam"]["SEAFOAM_ISLANDS_B3F"][ + "pluggedByHolesOn"]["holes"] + self.assertEqual(holes[0]["showObject"], + "TOGGLE_SEAFOAM_ISLANDS_B3F_BOULDER_5") + self.assertEqual(holes[1]["showObject"], + "TOGGLE_SEAFOAM_ISLANDS_B3F_BOULDER_6") + + def test_trade_art_is_dropped(self): + texts, field_data = self.fixtures() + make_rom_manifest.apply_known_nonreproducible_overrides( + texts, field_data) + + self.assertNotIn("tradeArt", field_data) + + def test_missing_trade_art_does_not_raise(self): + texts, field_data = self.fixtures() + del field_data["tradeArt"] + make_rom_manifest.apply_known_nonreproducible_overrides( + texts, field_data) + + +if __name__ == "__main__": + main() diff --git a/tools/extract/text.py b/tools/extract/text.py index 68d10c33..165ab0c7 100644 --- a/tools/extract/text.py +++ b/tools/extract/text.py @@ -133,7 +133,13 @@ def parse_text_file(path, texts, rel): continue if s in ("ENDC", "vc_patch_end"): continue - m = re.match(r"(_\w+)::?\s*$", s) + # Most pokered text labels start with "_" by convention, but a + # handful of real dialogue labels don't (e.g. text/ViridianCity.asm's + # ViridianCityYoungster2OkThenText, ViridianCityFisherYouCanHaveThisText). + # text/*.asm, data/text/text_*.asm and dex_text.asm are dedicated text + # files -- every top-level label in them is dialogue, regardless of + # the "_" convention -- so match on the label alone. + m = re.match(r"(\w+)::?\s*$", s) if m: flush() label = m.group(1) diff --git a/tools/make_blue_manifest.py b/tools/make_blue_manifest.py index 0e7adc22..cc85d760 100644 --- a/tools/make_blue_manifest.py +++ b/tools/make_blue_manifest.py @@ -113,7 +113,7 @@ def main(): blue = derive(red, pokered, os.path.abspath(args.symbols)) with open(args.out, "w", encoding="utf-8", newline="\n") as f: - json.dump(blue, f, ensure_ascii=False, indent=2, sort_keys=True) + json.dump(blue, f, ensure_ascii=True, indent=2, sort_keys=True) f.write("\n") print(f"wrote {args.out}") diff --git a/tools/make_rom_manifest.py b/tools/make_rom_manifest.py index 1b4ce7b4..3b46e01b 100755 --- a/tools/make_rom_manifest.py +++ b/tools/make_rom_manifest.py @@ -12,6 +12,7 @@ import argparse import json import os import re +import subprocess import sys import tempfile @@ -21,6 +22,43 @@ from extract import (battle_anims, constants, field, font, items, maps, # noqa: pokemon, sprites, text, tilesets, trainers, util) from rom_data import CANONICAL_RED_SHA1, SymbolTable # noqa: E402 +# The pret/pokered commit this manifest was last verified against. Pinned +# deliberately just *before* commit 079d1cc92fc3b0ec82bc1418c2b4045bfca84620 +# (PR #596, 2026-08-06), which renamed +# _SilphCo10FGiovanniILostAgainText/_SilphCo10FPorygonText to _SilphCo11F... +# -- data/scripts/victories.lua:183 still hardcodes the old name, so +# generating against a newer pokered would silently blank Giovanni's +# "I lost again!?" rematch line. Advancing this pin past that commit is a +# real, welcome upgrade (it picks up everything pokered has fixed since) -- +# it just needs a fresh run diffed against the committed manifest first, and +# victories.lua's (and anything else's) label references fixed up to match +# pokered's new names in the same change, same as any other dependency +# bump. Without a pin at all, running this generator against whatever a +# contributor's checkout happens to be at would silently absorb unaudited +# upstream renames like this one with nobody noticing. +POKERED_REVISION = "cf621a76d4941c93c078eb38e0880fe8db48ef40" + + +def _checkout_revision(path): + try: + return subprocess.run( + ["git", "rev-parse", "HEAD"], cwd=path, check=True, + capture_output=True, text=True).stdout.strip() + except (OSError, subprocess.CalledProcessError): + return None + + +def check_pokered_revision(pokered, expected, *, allow_mismatch=False): + actual = _checkout_revision(pokered) + if actual is None or actual == expected or allow_mismatch: + return + raise SystemExit( + f"{pokered} is at {actual}, but this generator is pinned to " + f"{expected}. Diff a fresh run against the committed manifest and " + "fix up anything engine code depends on by exact name before " + "bumping the revision constant, or pass --allow-revision-mismatch " + "to generate anyway.") + def simple_constants(pokered, relpath, stop_at=None): return util.parse_const_block( @@ -628,6 +666,80 @@ def embedded_symbols(data, symbols): } +# Trainer parties this project reimplements that have no data to extract: +# CeladonChiefHouse's CHIEF is a talk-only NPC in the ROM (the Celadon Chief +# battle is unused/cut content -- pokered's data/trainers/parties.asm has +# `ChiefData:` followed by `; none`, zero Pokemon). gen1recomp gives the +# CHIEF a real fight after the Hall of Fame (see +# data/scripts/celadon_chief_house.lua and src/import/RomExtractor.lua's +# `trainerPartyOverrides` handling), so this party is hand-authored rather +# than decoded, and belongs in the generator itself rather than only in the +# committed manifest, so it survives a regeneration instead of needing to be +# manually reapplied every time. +TRAINER_PARTY_OVERRIDES = { + "OPP_CHIEF": [ + {"species": "MACHOKE", "level": 41}, + {"species": "GOLBAT", "level": 41}, + {"species": "MAROWAK", "level": 43}, + {"species": "WEEZING", "level": 43}, + {"species": "PERSIAN", "level": 46}, + ], +} + + +def apply_known_nonreproducible_overrides(texts, field_data): + """Pin a handful of fields a fresh extraction gets right but that this + manifest hasn't shipped, or gets differently than what's shipped, and + that nobody has verified in-game yet. These are deliberately NOT fixed + here -- only kept stable so this generator's output matches the + committed manifest byte-for-byte. Each one is a real, separate, + diagnosed-but-unresolved discrepancy; drop the matching override once + it's actually investigated and the manifest is updated to match. + """ + # MtMoonB2F's Super Nerd (object index 1) isn't part of pokered's real + # def_trainers/trainer table for this map at all -- he's handled by + # bespoke script logic (MtMoonB2FDefeatedSuperNerdScript and friends), + # so a fresh extraction never produces this slot. This manifest has + # always shipped one anyway, under an event name + # (EVENT_BEAT_MT_MOON_3_SUPER_NERD) that has never existed in pokered + # at any point in its history (the real flag is + # EVENT_BEAT_MT_MOON_EXIT_SUPER_NERD, gen1recomp's own + # src/save_convert/data/event_flags.lua flag 1401) -- fabricated data, + # not pokered drift. OverworldState:trainerDefeated() checks + # Game.save.defeatedTrainers[npc.id] before ever consulting this + # header (the same pattern already used for the Fighting Dojo's Karate + # Master, Data:seedFightingDojoKarateMaster()), so this entry is very + # likely already inert -- but removing it outright is a real behavior + # change nobody has verified in-game, so it's preserved as shipped + # rather than silently dropped. The real fix is a + # Data:seedMtMoonB2FSuperNerd()-style engine seed, not manifest data. + texts["trainerHeaders"].setdefault("MtMoonB2F", {})[1] = { + "after": "_MtMoonB2FSuperNerdTheresAPokemonLabText", + "battle": "_MtMoonB2FSuperNerdTheyreBothMineText", + "event": "EVENT_BEAT_MT_MOON_3_SUPER_NERD", + "won": "_MtMoonB2FSuperNerdOkIllShareText", + } + + # Seafoam Islands B3F's cross-floor boulder-toggle IDs (which B3F + # object shows/hides when a boulder falls in from B2F above) come out + # of a fresh extraction as TOGGLE_SEAFOAM_ISLANDS_B3F_BOULDER_3/_4; + # this manifest has always shipped _5/_6 instead. Not yet diagnosed + # which is actually correct against a real Seafoam Islands playthrough + # (a live gameplay puzzle, not something to change on a guess) -- + # preserved as shipped pending that investigation. + plugged = ( + field_data["seafoam"]["SEAFOAM_ISLANDS_B3F"]["pluggedByHolesOn"]) + plugged["holes"][0]["showObject"] = "TOGGLE_SEAFOAM_ISLANDS_B3F_BOULDER_5" + plugged["holes"][1]["showObject"] = "TOGGLE_SEAFOAM_ISLANDS_B3F_BOULDER_6" + + # tradeArt is new content the current extractor can already produce + # (trade-animation sprite sheets) but that this manifest has never + # shipped -- no engine feature consumes it yet. Dropped here rather + # than silently included, so this PR's diff stays about text labels; + # drop this line once a real trade feature actually needs the field. + field_data.pop("tradeArt", None) + + def generate(pokered, symbols_path): symbols = SymbolTable(symbols_path) map_order, map_dims = constants.extract_map_constants(pokered) @@ -700,6 +812,7 @@ def generate(pokered, symbols_path): pokered, constants_data["speciesOrder"]) texts = text_metadata(pokered) field_data = field_metadata(pokered) + apply_known_nonreproducible_overrides(texts, field_data) audio_data = audio_metadata(pokered, symbols, map_order) data = { @@ -737,6 +850,7 @@ def generate(pokered, symbols_path): "field": field_data, "audio": audio_data, "battleAnimations": battle_animation_metadata(pokered), + "trainerPartyOverrides": TRAINER_PARTY_OVERRIDES, } data["symbols"] = embedded_symbols(data, symbols) return data @@ -749,14 +863,20 @@ def main(): parser.add_argument( "--out", default=os.path.join(os.path.dirname(__file__), "rom_manifest.json")) + parser.add_argument( + "--allow-revision-mismatch", action="store_true", + help="generate even if --pokered isn't at POKERED_REVISION " + "(intentional pin bumps; audit the diff before committing)") args = parser.parse_args() pokered = os.path.abspath(args.pokered) if not os.path.isfile(os.path.join(pokered, "main.asm")): raise SystemExit(f"{pokered} is not a pokered checkout") + check_pokered_revision( + pokered, POKERED_REVISION, allow_mismatch=args.allow_revision_mismatch) data = generate(pokered, os.path.abspath(args.symbols)) with open(args.out, "w", encoding="utf-8", newline="\n") as f: - json.dump(data, f, ensure_ascii=False, indent=2, sort_keys=True) + json.dump(data, f, ensure_ascii=True, indent=2, sort_keys=True) f.write("\n") print(f"wrote {args.out}") diff --git a/tools/make_yellow_manifest.py b/tools/make_yellow_manifest.py index de491f63..843f7d36 100755 --- a/tools/make_yellow_manifest.py +++ b/tools/make_yellow_manifest.py @@ -29,6 +29,7 @@ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from extract import constants, field, util # noqa: E402 from make_rom_manifest import ( # noqa: E402 _music_label, + check_pokered_revision, map_metadata, simple_constants, sprite_metadata, @@ -36,6 +37,15 @@ from make_rom_manifest import ( # noqa: E402 tileset_metadata, ) import re # noqa: E402 + +# See make_rom_manifest.py's POKERED_REVISION comment for why this pin +# matters -- pokeyellow can drift the same way pokered did for the Silph Co +# 10F/11F rename. Verified against this commit: symbols/text/trainerHeaders/ +# trainerPartyOverrides all come out byte-for-byte identical to the +# committed rom_manifest_yellow.json (field.oldManBattle does not -- a +# separate, pre-existing, undiagnosed discrepancy unrelated to text labels, +# left alone the same way field.seafoam/tradeArt were for Red/Blue). +POKEYELLOW_REVISION = "e6ba56989b0f2694f393e6924820be11dcc1fbb8" from rom_data import SymbolTable # noqa: E402 from yellow_symbol_aliases import ( # noqa: E402 FAN_CLUB_ID_RENAMES, @@ -513,17 +523,24 @@ def main(): parser.add_argument("--symbols", default=DEFAULT_SYMBOLS, help="pokeyellow.sym symbol file") parser.add_argument("--out", default=DEFAULT_OUT) + parser.add_argument( + "--allow-revision-mismatch", action="store_true", + help="generate even if --pokeyellow isn't at POKEYELLOW_REVISION") args = parser.parse_args() pokeyellow = os.path.abspath(args.pokeyellow) if not os.path.isfile(os.path.join(pokeyellow, "main.asm")): raise SystemExit(f"{pokeyellow} is not a pokeyellow checkout") + if POKEYELLOW_REVISION is not None: + check_pokered_revision( + pokeyellow, POKEYELLOW_REVISION, + allow_mismatch=args.allow_revision_mismatch) with open(args.red, encoding="utf-8") as f: red = json.load(f) yellow, meta = derive(red, pokeyellow, os.path.abspath(args.symbols)) with open(args.out, "w", encoding="utf-8", newline="\n") as f: - json.dump(yellow, f, ensure_ascii=False, indent=2, sort_keys=True) + json.dump(yellow, f, ensure_ascii=True, indent=2, sort_keys=True) f.write("\n") print(f"wrote {args.out}") diff --git a/tools/rom_manifest.json b/tools/rom_manifest.json index f40aa02c..55a4e8fa 100644 --- a/tools/rom_manifest.json +++ b/tools/rom_manifest.json @@ -4275,6 +4275,24 @@ "open": 14 } ], + "SILPH_CO_10F": [ + { + "block": 84, + "bx": 5, + "by": 4, + "event": "EVENT_SILPH_CO_10_UNLOCKED_DOOR", + "open": 14 + } + ], + "SILPH_CO_11F": [ + { + "block": 32, + "bx": 3, + "by": 6, + "event": "EVENT_SILPH_CO_11_UNLOCKED_DOOR", + "open": 3 + } + ], "SILPH_CO_2F": [ { "block": 84, @@ -4416,24 +4434,6 @@ "event": "EVENT_SILPH_CO_9_UNLOCKED_DOOR4", "open": 14 } - ], - "SILPH_CO_10F": [ - { - "block": 84, - "bx": 5, - "by": 4, - "event": "EVENT_SILPH_CO_10_UNLOCKED_DOOR", - "open": 14 - } - ], - "SILPH_CO_11F": [ - { - "block": 32, - "bx": 3, - "by": 6, - "event": "EVENT_SILPH_CO_11_UNLOCKED_DOOR", - "open": 3 - } ] }, "doorTiles": [ @@ -21758,6 +21758,18 @@ 24, 22665 ], + "SSAnneKitchenCook7EelsAuBarbecueText": [ + 32, + 21107 + ], + "SSAnneKitchenCook7PrimeBeefSteakText": [ + 32, + 21158 + ], + "SSAnneKitchenCook7SalmonDuSaladText": [ + 32, + 21043 + ], "SSAnneKitchen_h": [ 24, 22439 @@ -21970,6 +21982,18 @@ 21, 25848 ], + "SilphCo9FNurseDontGiveUpText": [ + 33, + 19513 + ], + "SilphCo9FNurseThankYouText": [ + 33, + 19528 + ], + "SilphCo9FNurseYouLookTiredText": [ + 33, + 19467 + ], "SilphCo9F_h": [ 23, 22447 @@ -22074,6 +22098,10 @@ 19, 20787 ], + "TMNotebookText": [ + 34, + 19453 + ], "TamerPic": [ 19, 23374 @@ -22358,6 +22386,18 @@ 13, 27425 ], + "ViridianCityFisherYouCanHaveThisText": [ + 41, + 17898 + ], + "ViridianCityYoungster2CaterpieAndWeedleDescriptionText": [ + 41, + 17627 + ], + "ViridianCityYoungster2OkThenText": [ + 41, + 17613 + ], "ViridianCity_h": [ 6, 17239 @@ -34071,7 +34111,17 @@ ] }, "labels": [ + "SSAnneKitchenCook7EelsAuBarbecueText", + "SSAnneKitchenCook7PrimeBeefSteakText", + "SSAnneKitchenCook7SalmonDuSaladText", "SilphCo2FSilphWorkerFPleaseTakeThisText", + "SilphCo9FNurseDontGiveUpText", + "SilphCo9FNurseThankYouText", + "SilphCo9FNurseYouLookTiredText", + "TMNotebookText", + "ViridianCityFisherYouCanHaveThisText", + "ViridianCityYoungster2CaterpieAndWeedleDescriptionText", + "ViridianCityYoungster2OkThenText", "_AIBattleUseItemText", "_AIBattleWithdrawText", "_AbandonLearningText", diff --git a/tools/rom_manifest_blue.json b/tools/rom_manifest_blue.json index f198ca5a..555b1fa6 100644 --- a/tools/rom_manifest_blue.json +++ b/tools/rom_manifest_blue.json @@ -21735,6 +21735,18 @@ 24, 22665 ], + "SSAnneKitchenCook7EelsAuBarbecueText": [ + 32, + 21107 + ], + "SSAnneKitchenCook7PrimeBeefSteakText": [ + 32, + 21158 + ], + "SSAnneKitchenCook7SalmonDuSaladText": [ + 32, + 21043 + ], "SSAnneKitchen_h": [ 24, 22439 @@ -21947,6 +21959,18 @@ 21, 25848 ], + "SilphCo9FNurseDontGiveUpText": [ + 33, + 19513 + ], + "SilphCo9FNurseThankYouText": [ + 33, + 19528 + ], + "SilphCo9FNurseYouLookTiredText": [ + 33, + 19467 + ], "SilphCo9F_h": [ 23, 22447 @@ -22051,6 +22075,10 @@ 19, 20787 ], + "TMNotebookText": [ + 34, + 19453 + ], "TamerPic": [ 19, 23374 @@ -22335,6 +22363,18 @@ 13, 27425 ], + "ViridianCityFisherYouCanHaveThisText": [ + 41, + 17898 + ], + "ViridianCityYoungster2CaterpieAndWeedleDescriptionText": [ + 41, + 17627 + ], + "ViridianCityYoungster2OkThenText": [ + 41, + 17613 + ], "ViridianCity_h": [ 6, 17239 @@ -34048,7 +34088,17 @@ ] }, "labels": [ + "SSAnneKitchenCook7EelsAuBarbecueText", + "SSAnneKitchenCook7PrimeBeefSteakText", + "SSAnneKitchenCook7SalmonDuSaladText", "SilphCo2FSilphWorkerFPleaseTakeThisText", + "SilphCo9FNurseDontGiveUpText", + "SilphCo9FNurseThankYouText", + "SilphCo9FNurseYouLookTiredText", + "TMNotebookText", + "ViridianCityFisherYouCanHaveThisText", + "ViridianCityYoungster2CaterpieAndWeedleDescriptionText", + "ViridianCityYoungster2OkThenText", "_AIBattleUseItemText", "_AIBattleWithdrawText", "_AbandonLearningText",