mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-21 05:00:43 +02:00
Pokemon Silver as a full launcher version, plus launcher mods-list and title-tempo fixes
Silver: derived import manifest (tools/make_silver_manifest.py re-resolves the Gold manifest's symbols from pokesilver.sym), silver GameVersion row, generation-keyed extractor routing, required-files override, edition save stamping (a Silver playthrough no longer writes into the Gold save), checkver-driven edition data, SILVER/KAMON/OSCAR/MAX presets, GOLD rival default, edition credits banner, Lugia title screen (OAM layouts, bob, trail, palettes as title.lua data keys with Gold defaults so old caches need no re-import), packaging for every build target, docs, and tests. Launcher: the installed-mods list is one continuous scroll (rows culled to the viewport) instead of a pager with an inner scroll viewport; the pad cursor's edge-scroll no longer runs it to the bottom. The game dropdown shows just the initial and caret. Find-tab behavior unchanged. Title tempo: a sprite-anim frame shows duration+1 ticks (engine/sprite_anims/core.asm GetSpriteAnimFrame), which locks both editions' 64-tick wing beat to the 64-tick sine bob; the title screens no longer run fast and out of phase.
This commit is contained in:
@@ -25,6 +25,7 @@ SHELL_COLORS = {
|
||||
"blue": {"main": (35, 125, 235), "dark": (20, 85, 175), "light": (80, 165, 255)},
|
||||
"yellow": {"main": (255, 205, 10), "dark": (210, 160, 0), "light": (255, 230, 80)},
|
||||
"gold": {"main": (225, 170, 40), "dark": (170, 120, 20), "light": (245, 200, 80)},
|
||||
"silver": {"main": (185, 190, 200), "dark": (130, 135, 145), "light": (225, 230, 240)},
|
||||
}
|
||||
|
||||
def extract_cleaned_love_emblem():
|
||||
@@ -186,7 +187,7 @@ def main():
|
||||
fg = create_adaptive_foreground(sizes["adaptive"])
|
||||
fg.save(os.path.join(drawable_dir, "ic_launcher_foreground.png"), "PNG")
|
||||
|
||||
for ver in ("red", "blue", "yellow", "gold"):
|
||||
for ver in ("red", "blue", "yellow", "gold", "silver"):
|
||||
cart = render_3d_cartridge(ver, sizes["shortcut"])
|
||||
cart.save(os.path.join(drawable_dir, f"ic_shortcut_{ver}.png"), "PNG")
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Derive the Pokemon Silver import manifest from the shipped Gold manifest.
|
||||
|
||||
Gold and Silver are assembled from one pokegold source tree; every constant
|
||||
block, charmap entry, map id, and symbol NAME is identical between the two
|
||||
builds, and the edition differences (wild encounter tables, the alternate
|
||||
front pics in gfx/pics_silver.asm, the title screen art, preset player
|
||||
names, a handful of map texts) are all ROM data that the importer decodes
|
||||
from the Silver cart at import time. So rather than re-parsing pokegold
|
||||
from scratch like tools/make_gold_manifest.py does, this takes the shipped
|
||||
Gold manifest verbatim and overrides only what genuinely differs:
|
||||
|
||||
* romSha1 -- Silver's ROM hash (pret/pokegold's byte-exact build).
|
||||
* symbols -- every symbol re-resolved from pokesilver.sym, because the
|
||||
edition-selected data blocks have different sizes and shift
|
||||
their neighbours (e.g. the compressed front pics).
|
||||
|
||||
Usage: python3 tools/make_silver_manifest.py
|
||||
Default paths: Gold manifest beside this script; symbols at
|
||||
/Users/bryanbassett/Documents/development/pokegold-symbols/pokesilver.sym
|
||||
(a pokegold checkout's own `make silver` build emits an identical one).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from rom_data import CANONICAL_SILVER_SHA1, SymbolTable # noqa: E402
|
||||
|
||||
DEV = "/Users/bryanbassett/Documents/development"
|
||||
DEFAULT_GOLD = os.path.join(os.path.dirname(__file__), "rom_manifest_gold.json")
|
||||
DEFAULT_OUT = os.path.join(
|
||||
os.path.dirname(__file__), "rom_manifest_silver.json")
|
||||
DEFAULT_SYMBOLS = os.path.join(DEV, "pokegold-symbols/pokesilver.sym")
|
||||
|
||||
|
||||
def derive(gold, symbols_path):
|
||||
"""Return the Silver manifest derived from the Gold manifest dict."""
|
||||
silver = copy.deepcopy(gold)
|
||||
silver["romSha1"] = CANONICAL_SILVER_SHA1
|
||||
|
||||
silver_symbols = SymbolTable(symbols_path)
|
||||
resolved, missing = {}, []
|
||||
for name in gold["symbols"]:
|
||||
symbol = silver_symbols.by_name.get(name)
|
||||
if symbol is None:
|
||||
missing.append(name)
|
||||
continue
|
||||
resolved[name] = [symbol.bank, symbol.address]
|
||||
if missing:
|
||||
raise SystemExit(
|
||||
"pokesilver.sym is missing symbols the manifest needs: "
|
||||
+ ", ".join(sorted(missing)[:10])
|
||||
+ (" ..." if len(missing) > 10 else ""))
|
||||
silver["symbols"] = resolved
|
||||
|
||||
# Sanity: the edition pic banks must actually have moved something. If
|
||||
# every address matches Gold's, the --symbols file is almost certainly
|
||||
# pokegold.sym, and the import would decode Gold data out of a Silver ROM.
|
||||
if all(resolved[n] == gold["symbols"][n] for n in resolved):
|
||||
raise SystemExit(
|
||||
f"{symbols_path} resolves every symbol to Gold's address; "
|
||||
"is it really pokesilver.sym?")
|
||||
|
||||
return silver
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--gold", default=DEFAULT_GOLD,
|
||||
help="shipped Gold manifest to derive from")
|
||||
parser.add_argument("--symbols", default=DEFAULT_SYMBOLS,
|
||||
help="pokesilver.sym symbol file")
|
||||
parser.add_argument("--out", default=DEFAULT_OUT)
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(args.gold, encoding="utf-8") as f:
|
||||
gold = json.load(f)
|
||||
|
||||
silver = derive(gold, os.path.abspath(args.symbols))
|
||||
with open(args.out, "w", encoding="utf-8", newline="\n") as f:
|
||||
json.dump(silver, f, ensure_ascii=False, indent=2, sort_keys=True)
|
||||
f.write("\n")
|
||||
print(f"wrote {args.out}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+3
-2
@@ -741,7 +741,7 @@ def imported_data_dir(repo):
|
||||
return path if _generated_data_dir_ok(path) else None
|
||||
|
||||
version = (os.environ.get("POKEPORT_VERSION") or "red").lower()
|
||||
if version not in ("red", "blue", "yellow"):
|
||||
if version not in ("red", "blue", "yellow", "gold", "silver"):
|
||||
version = "red"
|
||||
|
||||
candidates = [
|
||||
@@ -2393,7 +2393,8 @@ UPVALUE_CALL = re.compile(
|
||||
UPVALUE_ARGS = re.compile(
|
||||
r"""^\s*([A-Za-z_]\w*)\s*\.\s*(\w+)\s*,\s*["'](\w+)["']""")
|
||||
VERSION_MATCH = re.compile(
|
||||
r"""[=~]=\s*["'](red|blue|yellow)["']|["'](red|blue|yellow)["']\s*[=~]=""")
|
||||
r"""[=~]=\s*["'](red|blue|yellow|gold|silver)["']"""
|
||||
r"""|["'](red|blue|yellow|gold|silver)["']\s*[=~]=""")
|
||||
|
||||
|
||||
def _line_of(body, offset):
|
||||
|
||||
+2
-1
@@ -11,8 +11,9 @@ from dataclasses import dataclass
|
||||
CANONICAL_RED_SHA1 = "ea9bcae617fdf159b045185467ae58b2e4a48b9a"
|
||||
CANONICAL_BLUE_SHA1 = "d7037c83e1ae5b39bde3c30787637ba1d4c48ce2"
|
||||
CANONICAL_YELLOW_SHA1 = "cc7d03262ebfaf2f06772c1a480c7d9d5f4a38e1"
|
||||
# Gold is Gen 2: a 2 MiB cart, twice the size of the Gen 1 ROMs above.
|
||||
# Gold and Silver are Gen 2: 2 MiB carts, twice the size of the Gen 1 ROMs above.
|
||||
CANONICAL_GOLD_SHA1 = "d8b8a3600a465308c9953dfa04f0081c05bdcb94"
|
||||
CANONICAL_SILVER_SHA1 = "49b163f7e57702bc939d642a18f591de55d92dae"
|
||||
ROM_BANK_SIZE = 0x4000
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user