diff --git a/scripts/build-vault-mocs.py b/scripts/build-vault-mocs.py index d2a9356..a17ccec 100644 --- a/scripts/build-vault-mocs.py +++ b/scripts/build-vault-mocs.py @@ -91,6 +91,12 @@ def types_cell(types): def key(r): return r["stem"].casefold() + +def wikilink(stem: str) -> str: + """Obsidian-safe wikilink for note stems that contain [ or ].""" + escaped = stem.replace("[", "\\[").replace("]", "\\]") + return f"[[{escaped}]]" + # ---------------------------------------------------------------- MOC config # Logical hardware order for human-facing lists. @@ -152,7 +158,7 @@ BASE_MOCS = { def platform_static_table(recs): head = "| Hack | Base | Version | Status | Type |\n|---|---|---|---|---|" rows = [ - f"| [[{r['stem']}]] | {cell(r['base'])} | {cell(r['version'])} | " + f"| {wikilink(r['stem'])} | {cell(r['base'])} | {cell(r['version'])} | " f"{cell(r['status'])} | {types_cell(r['type'])} |" for r in sorted(recs, key=key) ] @@ -162,14 +168,14 @@ def base_static_table(recs, with_base): if with_base: head = "| Hack | Base | Version | Dev | Engine | Type |\n|---|---|---|---|---|---|" rows = [ - f"| [[{r['stem']}]] | {cell(r['base'])} | {cell(r['version'])} | " + f"| {wikilink(r['stem'])} | {cell(r['base'])} | {cell(r['version'])} | " f"{cell(r['status'])} | {cell(r['engine'])} | {types_cell(r['type'])} |" for r in sorted(recs, key=key) ] else: head = "| Hack | Version | Dev | Engine | Type |\n|---|---|---|---|---|" rows = [ - f"| [[{r['stem']}]] | {cell(r['version'])} | {cell(r['status'])} | " + f"| {wikilink(r['stem'])} | {cell(r['version'])} | {cell(r['status'])} | " f"{cell(r['engine'])} | {types_cell(r['type'])} |" for r in sorted(recs, key=key) ] @@ -236,7 +242,7 @@ def index_directory_table(recs): "|---|---|---|---|---|---|") order = {p: i for i, p in enumerate(PLATFORM_ORDER)} rows = [ - f"| [[{r['stem']}]] | {cell(r['platform'])} | {cell(r['base'])} | " + f"| {wikilink(r['stem'])} | {cell(r['platform'])} | {cell(r['base'])} | " f"{cell(r['version'])} | {cell(r['status'])} | {types_cell(r['type'])} |" for r in sorted(recs, key=lambda r: (order.get(r["platform"], 99), key(r))) ] diff --git a/scripts/list-acquire-from-urls.py b/scripts/list-acquire-from-urls.py new file mode 100644 index 0000000..cfc8988 --- /dev/null +++ b/scripts/list-acquire-from-urls.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +"""Diff URL-list hacks against placed library + attempt direct downloads.""" +import json, os, re, shutil, subprocess, sys, tempfile, unicodedata, urllib.request +from pathlib import Path + +CATALOG = Path(__file__).resolve().parents[1] / "wiki" / "catalog.json" +INCOMING = "/storage1/igir/romhacks/incoming/list-import" +UA = "Mozilla/5.0 (homelab personal archival)" + +# Unique games from the 7 source lists with best-known download URL (None = manual only). +ACQUIRE = [ + # --- direct-download candidates --- + ("Coral", "rom", "https://raw.githubusercontent.com/vbaemulator/GBC-Roms/main/Pokemon%20Coral%20Version%20v1.2.zip", "pokecommunity"), + ("Poketale", "zip", "https://www.mediafire.com/file/n6yzxnclf2uys7c/Poketale.zip/file", "mediafire"), + ("Vanguard", "archive", "https://www.mediafire.com/file/w9gy3qldi29imhk/Vanguard+3.0.12.7z/file", "mediafire"), + ("Bizarre", "zip", "https://www.mediafire.com/file/lox59f4nubxflw6/Pokemon_Bizarre_ENGLISH.zip/file", "mediafire"), + ("Spades and Clubs", "page", "https://senta-storage-system.neocities.org/main", "neocities"), + ("Dreamstone Mysteries", "github", "https://github.com/dsmyst/dreamstone-mysteries", "github"), + ("Giratina Strikes Back", "staging", None, "pokecommunity"), + # --- catalog-only / gated (reported, not fetched) --- + ("Abstract", "manual", "https://www.pokecommunity.com/threads/pokémon-abstract-version.527324/", "pokecommunity"), + ("Alchemist", "manual", "https://www.pokecommunity.com/threads/pokémon-alchemist.378280/", "pokecommunity"), + ("Awakening", "manual", "https://mega.nz/221fb646-0a04-4316-a163-f9b532c89197", "mega"), + ("AfricanVs", "have", None, "mega"), + ("Bushido", "have", None, "eeveeexpo"), + ("Consonancia", "manual", "https://www.pokecommunity.com/threads/pokémon-consonancia-full-game.537329/", "pokecommunity"), + ("Concealed", "manual", "https://www.pokecommunity.com/threads/concealed.527325/", "pokecommunity"), + ("Crown", "manual", "https://www.pokecommunity.com/threads/pokémon-crown.463821", "pokecommunity"), + ("Decay", "have", None, "eeveeexpo"), + ("Deserted", "have", None, "eeveeexpo"), + ("Eon Guardians", "manual", "https://www.pokecommunity.com/threads/pokémon-eon-guardians.527913/", "pokecommunity"), + ("Fire Ash", "manual", "https://www.pokecommunity.com/threads/pokémon-fire-ash.399096/", "pokecommunity"), + ("Floral Tempus", "manual", "https://www.pokecommunity.com/threads/pokémon-floral-tempus-ex-1-9-4-released-12-gym-badges-elite-4-champion.409175/", "pokecommunity"), + ("Hero Legacy", "manual", "https://www.pokecommunity.com/threads/pokémon-hero-legacy-eng-de-now-with-new-game-mode.538518/", "pokecommunity"), + ("HGSS Sevii", "manual", "https://www.pokecommunity.com/threads/pokémon-hgss-sevii-islands-hoenn-postgame.434636/", "pokecommunity"), + ("Itinerant", "manual", "https://www.pokecommunity.com/threads/pokemon-itinerant.528218/", "pokecommunity"), + ("Jam Festival", "manual", "https://www.pokecommunity.com/threads/pkmn-jam-festival.536702/", "pokecommunity"), + ("Legends of the Arena", "manual", "https://www.pokecommunity.com/threads/pokémon-legends-of-the-arena.298738/", "pokecommunity"), + ("Mega Adventures", "manual", "https://www.pokecommunity.com/threads/pokemon-mega-adventure.362058/", "pokecommunity"), + ("Nightmare", "manual", "https://www.pokecommunity.com/threads/pokémon-nightmare.504856/", "pokecommunity"), + ("Odyssey II", "discord", None, "discord"), + ("Legacy Edition", "discord", None, "discord"), + ("Iridium", "discord", None, "discord"), + ("Light Platinum DS", "manual", None, "twitter"), + ("Prisme", "manual", "https://pokemonprisme.com", "website"), + ("Relict", "manual", "https://phiongames.blogspot.com/2025/12/descarga-pokemon-relict.html", "blogspot"), + ("Reminiscencia", "manual", "https://mega.nz/file/5oNDGI5R#0b_7aQ3fMlUCo6Gwo8dVLXEXnW-seV-o_OanYqxVdRg", "mega"), + ("Reloaded", "manual", "https://pokemon-reloaded.blogspot.com", "blogspot"), + ("Shattered Light", "manual", "https://eeveeexpo.com/shattered-light/", "eeveeexpo"), + ("Sienna", "manual", "https://www.pokecommunity.com/threads/hack-of-the-year-2010-pokémon-sienna-complete-version-released.202372/", "pokecommunity"), + ("Tectonic", "manual", "https://www.tectonic-game.com", "website"), + ("Uranium", "manual", "https://mega.nz/file/gh82ST6S#makZr_hsZAcMOIKSEPUwejVJ_N4OW7Mk9wEBlWIoIG0", "mega"), + ("Vega Fairy EX", "manual", "https://www.pokecommunity.com/threads/pokemon-vega-fairy-edition-ex-minus-v1-4-balance-updates-and-skarmory-evo.475538/", "pokecommunity"), + ("Xenoverse", "staging", None, "mega"), + ("Zeta", "staging", None, "website"), + ("Insurgence", "have", None, "website"), + ("Infinite Fusion", "have", None, "pokecommunity"), + ("Reborn", "have", None, "website"), + ("Rejuvenation", "have", None, "website"), + ("Pokerogue", "web", "https://pokerogue.net", "browser"), + ("Emerald Seaglass", "manual", "https://ko-fi.com/s/4a1535f351", "ko-fi"), + ("Lazarus", "have", "https://ko-fi.com/nemo622", "ko-fi"), +] + + +def norm(s): + s = unicodedata.normalize("NFKD", s).encode("ascii", "ignore").decode().lower() + s = re.sub(r"^pokemon\s+", "", s) + s = re.sub(r"[^a-z0-9]+", " ", s).strip() + return s + + +def load_placed(): + """Read placed library basenames from stdin (piped ssh find output).""" + placed = set() + for line in sys.stdin: + line = line.strip() + if not line: + continue + m = re.match(r"Pokemon - (.+?) \(Hack\)", line, re.I) + if m: + placed.add(norm(m.group(1))) + return placed + + +def download(url, dest): + req = urllib.request.Request(url, headers={"User-Agent": UA}) + with urllib.request.urlopen(req, timeout=120) as r, open(dest, "wb") as f: + shutil.copyfileobj(r, f) + return os.path.getsize(dest) + + +def main(): + placed = load_placed() + catalog = {norm(h.get("title", h.get("stem", ""))): h for h in json.loads(CATALOG.read_text(encoding="utf-8"))["hacks"]} + os.makedirs(INCOMING, exist_ok=True) + rows = [] + for name, kind, url, host in ACQUIRE: + key = norm(name) + in_cat = key in catalog or any(key in ck or ck in key for ck in catalog) + in_lib = any(key in p or p in key for p in placed) + status = "HAVE" if in_lib or kind == "have" else "MISSING" + if kind == "staging" and not in_lib: + status = "STAGING" + dl = "" + if status in ("MISSING", "STAGING") and kind in ("rom", "zip", "archive", "github", "page") and url: + dest = os.path.join(INCOMING, re.sub(r"[^\w.\- ]", "_", name)) + try: + if kind == "github": + # release asset lookup would need gh api; skip for now + dl = "SKIP(github-release)" + elif kind == "page": + dl = "SKIP(scrape-neocities)" + else: + ext = ".zip" if kind in ("rom", "zip") else ".7z" + dest += ext + sz = download(url, dest) + dl = f"OK {sz:,}b -> {dest}" + status = "DOWNLOADED" + except Exception as e: + dl = f"FAIL: {e}" + rows.append((status, name, "catalog" if in_cat else "NEW", host, url or "—", dl)) + print(f"Placed library entries: {len(placed)}") + print(f"\n{'STATUS':12} {'NAME':28} {'CAT':5} {'HOST':12} URL") + for st, name, cat, host, url, dl in sorted(rows, key=lambda r: (r[0], r[1])): + print(f"{st:12} {name:28} {cat:5} {host:12} {url[:60]}") + if dl: + print(f"{'':12} {dl}") + + +if __name__ == "__main__": + main() diff --git a/scripts/list-import-from-urls.py b/scripts/list-import-from-urls.py new file mode 100644 index 0000000..eb9d914 --- /dev/null +++ b/scripts/list-import-from-urls.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python3 +"""Parse curated URL lists, diff against wiki/catalog.json, report gaps.""" +import json, re, unicodedata +from pathlib import Path + +CATALOG = Path(__file__).resolve().parents[1] / "wiki" / "catalog.json" + +# Games extracted from the 7 source lists (deduped, normalized keys). +LIST_ENTRIES = [ + # UfzGCYzA + ("Abstract", "https://www.pokecommunity.com/threads/pokémon-abstract-version.527324/"), + ("Alchemist", "https://www.pokecommunity.com/threads/pokémon-alchemist.378280/"), + ("AfricanVs", "https://mega.nz/file/UgZj3BCQ#Xc6243i1iMfBTTJR7NfEsA7mFgfCFj37e7_u_B1EvMM"), + ("Awakening", "https://www.pokecommunity.com/threads/pokémon-awakening.535910/"), + ("Bizarre", "https://drive.google.com/file/d/1NXXr96vzeMD8sGplV1sWZFSph2vZijaK/view"), + ("Bushido", "https://eeveeexpo.com/bushido/"), + ("Empyrean", "https://www.pokecommunity.com/threads/pokémon-empyrean-v1-1-final-arc-released.411322/"), + ("Eon Guardians", "https://www.pokecommunity.com/threads/pokémon-eon-guardians.527913/"), + ("Floral Tempus", "https://www.pokecommunity.com/threads/pokémon-floral-tempus-ex-1-9-4-released-12-gym-badges-elite-4-champion.409175/"), + ("HGSS Sevii", "https://www.pokecommunity.com/threads/pokémon-hgss-sevii-islands-hoenn-postgame.434636/"), + ("Infinity", "https://eeveeexpo.com/infinity/"), + ("Insurgence", "https://p-insurgence.com"), + ("Itinerant", "https://www.pokecommunity.com/threads/pokemon-itinerant.528218/"), + ("Infinite Fusion", "https://www.pokecommunity.com/threads/v6-4-pokémon-infinite-fusion-new-pokémon-character-customization-and-more.347883/"), + ("Legends of the Arena", "https://www.pokecommunity.com/threads/pokémon-legends-of-the-arena.298738/"), + ("Mega Adventures", "https://www.pokecommunity.com/threads/pokemon-mega-adventure.362058/"), + ("Nightmare", "https://www.pokecommunity.com/threads/pokémon-nightmare.504856/"), + ("Pokerogue", "https://pokerogue.net"), + ("Poketale", "https://www.mediafire.com/file/n6yzxnclf2uys7c/Poketale.zip/file"), + ("Realidea System", "https://www.pokecommunity.com/threads/pokémon-realidea-system-now-playable-in-english.481090/"), + ("Reborn", "https://www.rebornevo.com/pr/index.html/"), + ("Reloaded", "https://pokemon-reloaded.blogspot.com"), + ("Reminiscencia", "https://www.pokecommunity.com/threads/pokémon-reminiscencia-full-release-spa-en-translation-complete.529202/"), + ("Shattered Light", "https://eeveeexpo.com/shattered-light/"), + ("Solar Light Lunar Dark", "https://pokemonsolarlightlunardark.fandom.com/wiki/Pokémon_Solar_Light_%26_Lunar_Dark_Wiki"), + ("Tectonic", "https://www.tectonic-game.com"), + ("Uranium", "https://pokemon-uranium.fandom.com/wiki/Main_Page"), + ("Xenoverse", "https://mega.nz/file/FbBgiTTK#qJpzZeUb5XqO5rLt6meW5_tOXeQ3K6y3_mslGNUf41M"), + ("Zeta", "https://zo.p-insurgence.com"), + ("Atlas", None), ("Unbreakable Ties", None), ("Bioterror", None), ("Fuso Meteor", None), + ("Comet", None), ("Ruckus", None), ("Island", None), ("Impetu", None), + ("Slowpoke Shack", None), ("Empire", None), ("Flux", None), + # S1CSW465 + ("Consonancia", "https://www.pokecommunity.com/threads/pokémon-consonancia-full-game.537329/"), + ("Concealed", "https://www.pokecommunity.com/threads/concealed.527325/"), + ("Chaos in Vesita", "https://www.pokecommunity.com/threads/pokémon-chaos-in-vesita-new-version-out-now-eng-ger.491767/"), + ("Dark Horizon", "https://eeveeexpo.com/threads/9332/"), + ("Decay", "https://eeveeexpo.com/decay/"), + ("Fire Ash", "https://www.pokecommunity.com/threads/pokémon-fire-ash.399096/"), + ("Gaidr Deluxe", "https://www.pokecommunity.com/threads/pokémon-gadir-deluxe-complete-v-1-3.539451/"), + ("Hero Legacy", "https://www.pokecommunity.com/threads/pokémon-hero-legacy-eng-de-now-with-new-game-mode.538518/"), + ("Hollow Woods", "https://www.pokecommunity.com/threads/pokémon-hollow-woods.525865/"), + ("Hydro Bliss", "https://eeveeexpo.com/threads/9100/"), + ("Jam Festival", "https://www.pokecommunity.com/threads/pkmn-jam-festival.536702/"), + ("Keishou", "https://www.pokecommunity.com/threads/pokémon-keishou-v2-06-1.504806/"), + ("Prisme", "https://pokemonprisme.com"), + ("Re:Union", "https://projetreunion.com"), + ("Relict", "https://phiongames.blogspot.com/2025/12/descarga-pokemon-relict.html"), + # 6wPjUcrE + ("Spades and Clubs", "https://senta-storage-system.neocities.org/main"), + ("Giratina's Legend", "https://www.pokecommunity.com/threads/pokemon-giratinas-legend-07-01-24.289561"), + ("Crown", "https://www.pokecommunity.com/threads/pokémon-crown.463821"), + ("Odyssey II", None), # Discord only + ("Coral", "https://www.pokecommunity.com/threads/pokémon-coral-version-2022-demo-out-now.402361"), + ("DarkFire", "https://www.pokecommunity.com/threads/new-2024-beta-2-1-out-now-pokémon-darkfire.421395/"), + ("Sovereign of the Skies", "https://www.pokecommunity.com/threads/sovereign-of-the-skies-new-beta-2-0-0-version-released-06-10-2021.292651/"), + ("Legacy Edition", None), # Discord only + ("Iridium", None), # Discord only + ("Light Platinum DS", None), # Twitter only + # ZwA8ng8E + ("Deserted", "https://eeveeexpo.com/threads/5344/"), + # 1S4acLQA + ("Saiph", "https://www.pokecommunity.com/threads/pokémon-saiph-the-vytroverse-part-1-full-game-released.420990"), + ("Sors", "https://www.pokecommunity.com/threads/pokémon-sors-the-vytroverse-part-2-full-game-v1-3-available-now.433238"), + ("Saiph 2", "https://www.pokecommunity.com/threads/pokémon-saiph-2-the-vytroverse-part-3-full-game-v1-4-0-update-available.458509"), + ("Sors 2", "https://www.pokecommunity.com/threads/pokémon-sors-2-the-vytroverse-part-4-tech-demo-available.526108"), + ("Victory Fire", "https://www.pokecommunity.com/threads/pokemon-victory-fire-version-2-75-released.285031/"), + ("Resolute", "https://www.pokecommunity.com/threads/pokemon-resolute-version-version-2-97-released.294565/"), + ("Mega Power", "https://www.pokecommunity.com/threads/pokemon-mega-power-completed-beta-5-73-released.325422/"), + ("Nameless", "https://www.pokecommunity.com/threads/pokemon-nameless-version-complete-beta-5-35-released-with-darker-future-episode.419717/"), + ("Ruby Destiny", None), + ("ROWE", "https://www.pokecommunity.com/threads/pokemon-r-o-w-e-2-0-an-open-world-version-of-pokémon-emerald-gen-9-16-badges-sevii-islands-following-pokémon-costumes-and-much-more.442592/"), + ("Gaia", "https://www.pokecommunity.com/threads/pokémon-gaia-version.326118/"), + ("Vanguard", None), + # tARt0w7x + ("Adventure Red", "https://www.pokecommunity.com/threads/pokémon-adventure-red-chapter-new-beta-expansion.298920/"), + ("AshGray", "https://www.pokecommunity.com/threads/pokémon-ashgray-version-beta-4-5-released.180722/"), + ("Azure Horizons", "https://hacksrepairman.blogspot.com/2020/03/pokemon-azure-horizons-fixed-beta2.html"), + ("Crystal Clear", "https://shockslayer.com/crystal-clear/"), + ("Dark Violet", "https://www.pokecommunity.com/threads/pokémon-darkviolet-full-version-released.291789/"), + ("Dreams", "https://www.pokecommunity.com/threads/dreams-completed-version-1-5-1-now-available.443298/"), + ("Elite Redux", "https://www.pokecommunity.com/threads/pokémon-elite-redux-v2-1-complete-—-unique-multi-ability-difficulty-hack.499227/"), + ("Emerald Rogue", "https://www.pokecommunity.com/threads/pokemon-emerald-rogue.479406/"), + ("Emerald Seaglass", "https://ko-fi.com/s/4a1535f351"), + ("Elysium", "https://www.pokecommunity.com/threads/pokémon-elysium-gba.502953/"), + ("Fire Red Extended", "https://www.pokecommunity.com/threads/pokémon-fire-red-extended-version.466535/"), + ("Flora Sky", "https://www.pokemoncoders.com/pokemon-flora-sky/"), + ("Glazed", "https://www.pokemoncoders.com/pokemon-glazed/"), + ("Light Platinum", "https://www.pokemoncoders.com/pokemon-light-platinum-rom-hack/"), + ("Liquid Crystal", "https://www.pokecommunity.com/threads/pokémon-liquid-crystal-3-3-xxxxx-live-beta.242023/"), + ("Mariomon", "https://www.pokecommunity.com/threads/super-mariomon.535764/"), + ("Odyssey", "https://www.pokecommunity.com/threads/pokémon-odyssey-complete-v4-0-1.488536/"), + ("Pisces", "https://pebblerplatoon.miraheze.org/wiki/Pisces_Download"), + ("Prism", "https://rainbowdevs.com/"), + ("Polished Crystal", "https://www.pokecommunity.com/threads/pokémon-polished-crystal-update-3-1-1.373172/"), + ("Radical Red", "https://www.pokecommunity.com/threads/pokémon-radical-red-version-4-1-released-gen-9-dlc-pokemon-character-customization-now-available.437688/"), + ("Recharged Series", "https://jaizu.moe"), + ("FireRed Rocket Edition", "https://www.pokecommunity.com/threads/pokémon-firered-rocket-edition-completed.360725/"), + ("Scorched Silver", "https://www.pokecommunity.com/threads/pokémon-scorched-silver-v1-3-complete.529230/"), + ("Sienna", "https://www.pokecommunity.com/threads/hack-of-the-year-2010-pokémon-sienna-complete-version-released.202372/"), + ("Snakewood", "https://www.pokecommunity.com/threads/pokémon-snakewood-version.235371/"), + ("Team Rocket Edition", "https://www.pokecommunity.com/threads/pokémon-team-rocket-edition-dragonsden-version-kanto-sevii-johto-next-release-dlc-season-4.527368/"), + ("The Pit", "https://www.pokecommunity.com/threads/the-pit-v2-roguelite-style-hack.528423/"), + ("Unbound", "https://www.pokecommunity.com/threads/pokémon-unbound-completed.382178/"), + ("Vega", "https://www.pokecommunity.com/threads/pokémon-vega-and-altair-sirius-english-version.365959/"), + ("Vega Fairy EX", "https://www.pokecommunity.com/threads/pokemon-vega-fairy-edition-ex-minus-v1-4-balance-updates-and-skarmory-evo.475538/"), + # Google Doc + ("Lazarus", "https://ko-fi.com/nemo622"), + ("Renegade Platinum", "https://projectpokemon.org/home/forums/topic/52294-pokémon-renegade-platinum/"), + ("Heart n Soul", "https://www.hackdex.app/hack/pokemon-heart-and-soul"), + ("Dreamstone Mysteries", "https://github.com/dsmyst/dreamstone-mysteries"), + ("Rejuvenation", None), +] + +ALIASES = { + "adventure red": "adventure red chapter", + "ashgray": "ash gray", + "ash gray": "ashgray", + "firered rocket edition": "firered rocket edition", + "fire red extended": "fire red extended", + "darkfire": "dark fire", + "gaidr deluxe": "gadir deluxe", + "reunion": "re union", + "re:union": "re union", + "re union dx": "re union", + "rowe": "r o w e", + "r.o.w.e": "r o w e", + "itinerant": "iternant", + "keishou": "kieshou", + "giratina's legend": "giratina", + "vega fairy ex": "vega fairy", + "team rocket edition": "team rocket edition", + "mega adventures": "mega adventure", + "reminiscencia": "reminiscensia", + "spades and clubs": "spades", + "odyssey ii": "odyssey 2", + "heroes of lemuria": "odyssey 2", + "light platinum ds": "light platinum ds", + "heart n soul": "heart and soul", + "recharged series": "recharged", +} + + +def norm(s: str) -> str: + s = unicodedata.normalize("NFKD", s).encode("ascii", "ignore").decode().lower() + s = re.sub(r"^pok[eé]mon\s+", "", s) + s = re.sub(r"[^a-z0-9]+", " ", s).strip() + return ALIASES.get(s, s) + + +def load_catalog(): + data = json.loads(CATALOG.read_text(encoding="utf-8")) + by_norm = {} + for h in data["hacks"]: + title = h.get("title") or h.get("stem", "") + key = norm(title) + by_norm.setdefault(key, []).append(h) + if h.get("stem"): + by_norm.setdefault(norm(h["stem"]), []).append(h) + return by_norm + + +def match_catalog(name, catalog): + key = norm(name) + hits = catalog.get(key, []) + if hits: + return hits[0] + # fuzzy: substring + for ck, hits in catalog.items(): + if key in ck or ck in key: + return hits[0] + return None + + +def main(): + catalog = load_catalog() + seen = set() + rows = [] + for name, url in LIST_ENTRIES: + nk = norm(name) + if nk in seen: + continue + seen.add(nk) + hit = match_catalog(name, catalog) + rows.append({ + "name": name, + "url": url, + "in_catalog": hit is not None, + "catalog_title": hit["title"] if hit else None, + "platform": hit.get("platform") if hit else None, + "library_path": hit.get("library_path") if hit else None, + }) + + missing_cat = [r for r in rows if not r["in_catalog"]] + in_cat = [r for r in rows if r["in_catalog"]] + + print(f"Total unique list entries: {len(rows)}") + print(f"In catalog: {len(in_cat)}") + print(f"NOT in catalog: {len(missing_cat)}") + print("\n=== NOT IN CATALOG ===") + for r in sorted(missing_cat, key=lambda x: x["name"].lower()): + print(f" {r['name']:30} {r['url'] or '(no URL)'}") + + print("\n=== IN CATALOG (for library check) ===") + for r in sorted(in_cat, key=lambda x: x["name"].lower()): + lp = r["library_path"] or "—" + print(f" {r['name']:30} | {r['platform'] or '?':5} | {lp}") + + +if __name__ == "__main__": + main() diff --git a/scripts/list-import-vault-notes.py b/scripts/list-import-vault-notes.py new file mode 100644 index 0000000..711bdd5 --- /dev/null +++ b/scripts/list-import-vault-notes.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +"""Create vault notes for list-import hacks missing from catalog.""" +import json, re, textwrap, unicodedata +from datetime import date +from pathlib import Path + +VAULT = Path(r"C:\Users\MattC\Documents\Obsidian Vault\Pokémon ROM Hacks\Hacks") +CATALOG = Path(__file__).resolve().parents[1] / "wiki" / "catalog.json" + +NEW = [ + ("Alchemist", "GBA", "FireRed", "Complete", "https://www.pokecommunity.com/threads/pokémon-alchemist.378280/"), + ("Concealed", "PC", None, "Complete", "https://www.pokecommunity.com/threads/concealed.527325/"), + ("Consonancia", "PC", None, "Complete", "https://www.pokecommunity.com/threads/pokémon-consonancia-full-game.537329/"), + ("Crown", "PC", None, "Ongoing", "https://www.pokecommunity.com/threads/pokémon-crown.463821/"), + ("Eon Guardians", "GBA", "Emerald", "Complete", "https://www.pokecommunity.com/threads/pokémon-eon-guardians.527913/"), + ("Fire Ash", "GBA", "FireRed", "Complete", "https://www.pokecommunity.com/threads/pokémon-fire-ash.399096/"), + ("Floral Tempus", "GBA", "Emerald", "Complete", "https://www.pokecommunity.com/threads/pokémon-floral-tempus-ex-1-9-4-released-12-gym-badges-elite-4-champion.409175/"), + ("Hero Legacy", "PC", None, "Complete", "https://www.pokecommunity.com/threads/pokémon-hero-legacy-eng-de-now-with-new-game-mode.538518/"), + ("HGSS Sevii", "NDS", "HeartGold", "Complete", "https://www.pokecommunity.com/threads/pokémon-hgss-sevii-islands-hoenn-postgame.434636/"), + ("Itinerant", "GBA", "FireRed", "Ongoing", "https://www.pokecommunity.com/threads/pokemon-itinerant.528218/"), + ("Jam Festival", "PC", None, "Complete", "https://www.pokecommunity.com/threads/pkmn-jam-festival.536702/"), + ("Legends of the Arena", "GBA", "Emerald", "Complete", "https://www.pokecommunity.com/threads/pokémon-legends-of-the-arena.298738/"), + ("Mega Adventures", "GBA", "Ruby", "Complete", "https://www.pokecommunity.com/threads/pokemon-mega-adventure.362058/"), + ("Nightmare", "PC", None, "Complete", "https://www.pokecommunity.com/threads/pokémon-nightmare.504856/"), + ("Poketale", "PC", None, "Complete", "https://www.mediafire.com/file/n6yzxnclf2uys7c/Poketale.zip/file"), + ("Relict", "PC", None, "Complete", "https://phiongames.blogspot.com/2025/12/descarga-pokemon-relict.html"), + ("Shattered Light", "PC", None, "Ongoing", "https://eeveeexpo.com/shattered-light/"), + ("Sienna", "GBA", "Ruby", "Complete", "https://www.pokecommunity.com/threads/hack-of-the-year-2010-pokémon-sienna-complete-version-released.202372/"), + ("Spades and Clubs", "GBA", "FireRed", "Beta", "https://senta-storage-system.neocities.org/patchrelease"), + ("Tectonic", "PC", None, "Ongoing", "https://www.tectonic-game.com"), + ("Vega Fairy EX", "GBA", "FireRed", "Complete", "https://www.pokecommunity.com/threads/pokemon-vega-fairy-edition-ex-minus-v1-4-balance-updates-and-skarmory-evo.475538/"), +] + +UPDATES = { + "Coral": "roms/gbc/Hacks/Pokemon - Coral (Hack).gbc", + "Giratina Strikes Back": "roms/gba/Hacks/Pokemon - Giratina Strikes Back Full (Hack).gba", +} + + +def norm(s): + s = unicodedata.normalize("NFKD", s).encode("ascii", "ignore").decode().lower() + s = re.sub(r"^pokemon\s+", "", s) + return re.sub(r"[^a-z0-9]+", " ", s).strip() + + +def yaml_quote(s): + if s is None: + return '"—"' + if any(c in s for c in ':"\\#[]{}'): + return json.dumps(s) + return s + + +def note_body(title, source): + return textwrap.dedent(f"""\ + # {title} + + > [!info] From curated YouTube/pastebin list import (2026-06-23) + > Added to catalog from community recommendation lists. Download may be gated — see [[Wanted]]. + + ## Summary + + Surfaced from external recommendation lists (pastebin / Google Doc). Not yet in the RomM library unless noted in frontmatter. + + ## Links + + - Info / thread: {source} + + ## In the library + + > [!note] See `library_path` in frontmatter. + + [[Index|← back to directory]] + """) + + +def patch_library_path(path: Path, lp: str): + text = path.read_text(encoding="utf-8") + text = re.sub(r"^library_path:.*$", f'library_path: "{lp}"', text, count=1, flags=re.M) + path.write_text(text, encoding="utf-8") + + +def main(): + existing = {norm(p.stem) for p in VAULT.glob("*.md")} + today = date.today().isoformat() + created = [] + for name, platform, base, status, source in NEW: + if norm(name) in existing: + continue + title = f"Pokémon {name}" + tags = ["hack", f"platform/{platform.lower()}", f"status/{status.lower().replace(' ', '-')}"] + if base: + tags.append(f"base/{base.lower().replace(' ', '-')}") + fm = [ + "---", + f"title: {title}", + f'platform: {platform}', + f'base: {base or "—"}', + 'version: "—"', + f"status: {status}", + "type: [New Experience]", + 'generation: "—"', + 'library_path: "—"', + f"source: {json.dumps(source)}", + f"added: {today}", + "play_status: Unplayed", + "tags:", + ] + fm += [f" - {t}" for t in tags] + fm.append("---") + body = note_body(title, source) + out = VAULT / f"{name}.md" + out.write_text("\n".join(fm) + "\n" + body, encoding="utf-8") + created.append(name) + for stem, lp in UPDATES.items(): + p = VAULT / f"{stem}.md" + if p.exists(): + patch_library_path(p, lp) + print(f"Created {len(created)} notes: {', '.join(created)}") + print(f"Updated library_path: {', '.join(UPDATES)}") + + +if __name__ == "__main__": + main() diff --git a/scripts/push-downloads-to-valhalla.ps1 b/scripts/push-downloads-to-valhalla.ps1 new file mode 100644 index 0000000..7675931 --- /dev/null +++ b/scripts/push-downloads-to-valhalla.ps1 @@ -0,0 +1,90 @@ +# Push Downloads batch to valhalla for romhack import. +# Primary Windows builds + alternate platform variants (Linux/macOS/Joiplay/Android). +$ErrorActionPreference = "Continue" +$dl = Join-Path $env:USERPROFILE "Downloads" +$remote = "valhalla:/storage1/igir/romhacks/incoming/downloads-batch" + +$files = @( + # --- PC fan-games (Windows primary) --- + "Alchemist.rar", + "Concealed 2.1.rar", + "Pokemon Consonancia 1.2.rar", + "Pokemon Eon Guardians.zip", + "Pokemon Fire Ash 3.4.zip", + "FT EX.zip", + "Pokemon HGSS Sevii Islands - Final 1.0.zip", + "Pokemon Hero Legacy 3.0.7.zip", + "Itinerant v7.9.4.zip", + "PKMN Jam Festival v1.4.rar", + "Legends of the Arena 1.4.1.zip", + "Pokemon Nightmare 1.3.0.zip", + "Poketale.zip", + "Vanguard 3.0.12.7z", + "Pokemon Awakening ENG.rar", + "Pokemon Bizarre ENGLISH.zip", + "ReminiscenciaV2_3.zip", + "Pokemon Uranium 1.2.5.zip", + "Pokemon Tectonic 3.4.1.zip", + "Pokemon Shattered Light.zip", + "Relict V1.2.1.zip", + "Xenoverse-Source-main.zip", + "PokemonPrismeInstaller.exe", + "infinitefusion-e18-6.7.zip", + "InfiniteFusion.zip", + "Reborn-19.5.0-windows.zip", + "Rejuvenation-13.5.0-windows.zip", + # --- Alternate platform builds (separate RomM entries) --- + "Pokemon Hero Legacy 3.0.7 Mac.dmg", + "Pokemon Hero Legacy 3.0.7 Joiplay.zip", + "Itinerant v7.9.4 (Android).zip", + "Reborn-19.5.0-linux.zip", + "Reborn-19.5.0-macos.zip", + "Reborn-19.5.0-joiplay.jgp", + "Rejuvenation-13.5.0-linux.zip", + "Rejuvenation-13.5.0-macos.zip", + "Rejuvenation - Where Love Lies.zip", + # --- ROMs / patches --- + "LightPlatinumV022.zip", + "Azure Horizons True Continued Beta 2.ips", + "Pokemon Vega Fairy Edition EX 1.4.ups", + "Pokemon - Fire Red (J) (V1.0).gba", + "Sienna Complete Version.ips", + "EmeraldSeaglass_v3.0 (1).ips", + "emerald_cross_2_0_5.bps", + "re_rebalanced_version_2.2.8.bps", + "recharged_emerald_version_2.2.8.bps" +) + +$extras = @( + (Get-ChildItem $dl -Filter "*Mega Adventure*" -File | Select-Object -First 1).FullName, + (Get-ChildItem $dl -Filter "*Abstract*" -File | Select-Object -First 1).FullName, + (Get-ChildItem $dl -Filter "*Odyssey COMPLETE*" -File | Select-Object -First 1).FullName +) | Where-Object { $_ } + +ssh valhalla "mkdir -p /storage1/igir/romhacks/incoming/downloads-batch" + +$queued = @() +foreach ($f in $files) { + $p = Join-Path $dl $f + if (Test-Path $p) { $queued += $p } else { Write-Warning "SKIP missing: $f" } +} +foreach ($p in $extras) { + if ($p -and (Test-Path $p) -and $queued -notcontains $p) { $queued += $p } +} + +# Skip files already on valhalla (resume-friendly) +$remoteList = ssh valhalla "ls -1 /storage1/igir/romhacks/incoming/downloads-batch/ 2>/dev/null" 2>$null +$remoteSet = [System.Collections.Generic.HashSet[string]]::new([string[]]$remoteList) +$todo = @($queued | Where-Object { -not $remoteSet.Contains((Split-Path $_ -Leaf)) }) + +$total = ($todo | ForEach-Object { (Get-Item $_).Length } | Measure-Object -Sum).Sum +Write-Host ("Uploading {0} files ({1:N1} GB); {2} already on server" -f $todo.Count, ($total/1GB), ($queued.Count - $todo.Count)) + +$ok = 0; $fail = 0 +foreach ($p in $todo) { + $name = Split-Path $p -Leaf + Write-Host " -> $name" + scp $p "${remote}/" + if ($LASTEXITCODE -eq 0) { $ok++ } else { $fail++; Write-Warning "FAILED: $name" } +} +Write-Host "Upload complete: $ok ok, $fail failed, $($queued.Count - $todo.Count) skipped (already present)" diff --git a/scripts/romhack-import.py b/scripts/romhack-import.py index 3ade9cb..2482a46 100644 --- a/scripts/romhack-import.py +++ b/scripts/romhack-import.py @@ -21,6 +21,7 @@ import sys, os, re, zlib, shutil, subprocess, zipfile, unicodedata, tempfile ROMS = "/storage1/Emulation/roms" PATCHES = "/storage1/igir/romhacks/patches" APPLY = "/storage1/igir/romhacks/tools/apply.py" +WIN_DEST = "/storage1/Emulation/roms/windows" BASES = { "crystal_rev1": f"{ROMS}/gbc/Pokemon - Crystal Version (USA, Europe) (Rev 1).gbc", @@ -31,17 +32,20 @@ BASES = { "emerald": f"{ROMS}/gba/Pokemon - Emerald Version (USA, Europe).gba", "firered": f"{ROMS}/gba/Pokemon - FireRed Version (USA, Europe).gba", "leafgreen": f"{ROMS}/gba/Pokemon - LeafGreen Version (USA, Europe).gba", + "firered_jp": f"{ROMS}/gba/Pokemon - Fire Red (J) (V1.0).gba", "red": f"{ROMS}/gb/Pokemon - Red Version (USA, Europe) (SGB Enhanced).gb", } # candidate bases to try per target platform (order = preference) CANDIDATES = { - "gba": ["emerald", "firered", "leafgreen", "ruby", "sapphire"], + "gba": ["firered_jp", "emerald", "firered", "leafgreen", "ruby", "sapphire"], "gbc": ["crystal_rev1", "gold", "silver"], "gb": ["red"], } # IPS patches (no checksum) need an explicit base by name substring IPS_BASE_MAP = [ - ("seaglass", "emerald", "gba"), + ("emeraldseaglass", "emerald", "gba"), + ("azure horizons", "firered", "gba"), + ("sienna", "ruby", "gba"), ("crystal kaizo", "crystal_rev1", "gbc"), ("kaizo", "crystal_rev1", "gbc"), # fallback for crystal kaizo rar ] @@ -57,6 +61,23 @@ ARCHIVE_EXT = {".zip", ".rar", ".7z"} NAME_OVERRIDES = [ ("emeraldseaglass", "Emerald Seaglass"), ("emerald seaglass", "Emerald Seaglass"), + ("azure horizons", "Azure Horizons"), + ("vega fairy", "Vega Fairy EX"), + ("spades", "Spades and Clubs"), + ("ft ex", "Floral Tempus"), + ("floral tempus", "Floral Tempus"), + ("hero legacy", "Hero Legacy"), + ("mega adventure", "Mega Adventures"), + ("hgss sevii", "HGSS Sevii"), + ("jam festival", "Jam Festival"), + ("legends of the arena", "Legends of the Arena"), + ("fire ash", "Fire Ash"), + ("eon guardians", "Eon Guardians"), + ("shattered light", "Shattered Light"), + ("lightplatinum", "Light Platinum DS"), + ("reminiscencia", "Reminiscencia"), + ("xenoverse", "Xenoverse"), + ("prisme", "Prisme"), ("lazarus", "Lazarus"), ("saiph 2", "Saiph 2"), ("saiph2", "Saiph 2"), ("saiph", "Saiph"), @@ -68,12 +89,51 @@ NAME_OVERRIDES = [ ] # Files we will NOT auto-place (unidentified / need user to name). Reported instead. SKIP_NAME_SUBSTR = ["beta 15 + expansion"] +# Known base ROMs in a drop folder — place under roms//, not Hacks/ +BASE_ROM_FILES = [ + ("fire red (j)", "gba", "Pokemon - Fire Red (J) (V1.0).gba"), +] +# Filename hints -> RomM variant tag (separate catalog/download entries). +VARIANT_RULES = [ + (r"joiplay|\.jgp\b", "[Joiplay]"), + (r"android", "[Android]"), + (r"linux", "[Linux]"), + (r"macos|\.dmg\b", "[macOS]"), + (r"installer", "[Installer]"), + (r"where love lies", "[DLC]"), + (r"infinitefusion\.zip$", "[Full]"), # 4 GB build vs e18 primary +] PLACE = False report = [] ARCH_SUBDIR = "" # set while recursing an archive, groups its docs under _docs// +def detect_variant(filename): + low = os.path.basename(filename).lower() + for pat, tag in VARIANT_RULES: + if re.search(pat, low): + return tag + return None + + +def pc_dest_dir(variant): + if variant == "[Linux]": + return os.path.join(ROMS, "linux") + if variant == "[macOS]": + return os.path.join(ROMS, "macintosh") + return WIN_DEST + + +def is_pc_fan_game(root): + """RPG-Maker / Essentials tree — Game.exe, Game.ini, or mkxp port.""" + for walk_root, _, files in os.walk(root): + low = {f.lower() for f in files} + if "game.exe" in low or "game.ini" in low or "mkxp.json" in low: + return True + return False + + def strip_trailing_groups(name): """Remove trailing (...) / [...] groups that look like version/variant junk.""" verkw = re.compile(r"(\d|version|hotfix|bug.?fix|final|anniversary|classic\+|" @@ -187,6 +247,17 @@ def place_patch(patch, origin): if not ok: report.append(("PATCH", "FAIL", origin, f"ips/{bk}: {msg[:50]}", "")); return place_rom(tmp_out, plat, hackname, origin); return + if ext == ".ups" and "vega" in patch.lower(): + # Vega Fairy EX UPS targets 32 MB FireRed (US/EU); JP 1.0 is 16 MB. + for base_key in ("firered", "firered_jp"): + if not os.path.exists(BASES[base_key]): + continue + ok, msg = try_apply(patch, base_key, tmp_out) + if ok: + place_rom(tmp_out, "gba", hackname, origin + f" [base={base_key}]") + return + report.append(("PATCH", "FAIL", origin, f"vega ups: {msg[:50]}", "")) + return if ext == ".xdelta": report.append(("PATCH", "SKIP", origin, "xdelta: handle via xdelta tool", "")); return # BPS / UPS: auto-detect base across all platforms (CRC-verified) @@ -208,8 +279,20 @@ def archive_doc(path, origin): report.append(("DOC", "OK", origin, f"{os.path.getsize(path):,}b", rel)) +def place_base_rom(src, plat, out_name, origin): + if PLACE: + d = os.path.join(ROMS, plat); os.makedirs(d, exist_ok=True) + shutil.copy2(src, os.path.join(d, out_name)) + report.append(("BASE", "OK", origin, f"{os.path.getsize(src):,}b", f"{plat}/{out_name}")) + + def process_file(path, origin=None): origin = origin or os.path.basename(path) + base = os.path.basename(path).lower() + for sub, plat, out_name in BASE_ROM_FILES: + if sub in base: + place_base_rom(path, plat, out_name, origin) + return ext = os.path.splitext(path)[1].lower() if ext in ROM_EXT: place_rom(path, ROM_EXT[ext], clean_name(path), origin) @@ -219,10 +302,70 @@ def process_file(path, origin=None): archive_doc(path, origin) elif ext in ARCHIVE_EXT: process_archive(path, origin) + elif ext == ".exe": + place_pc_installer(path, clean_name(path), origin) + elif ext == ".dmg": + place_pc_archive(path, clean_name(path), origin) + elif ext == ".jgp": + place_pc_archive(path, clean_name(path), origin, variant="[Joiplay]") else: report.append(("SKIP", "?", origin, f"unknown ext {ext}", "")) +def place_pc_archive(path, hackname, origin, variant=None): + tag = variant or detect_variant(path) or "" + suffix = f" {tag}" if tag else "" + out_name = f"Pokemon - {hackname} (Hack){suffix}.zip" + dest_dir = pc_dest_dir(tag) + dest = os.path.join(dest_dir, out_name) + ext = os.path.splitext(path)[1].lower() + if ext == ".zip": + if PLACE: + os.makedirs(dest_dir, exist_ok=True) + shutil.copy2(path, dest) + report.append(("PC", "OK", origin, f"{os.path.getsize(path):,}b zip", f"{dest_dir.split('/')[-1]}/{out_name}")) + return + if ext == ".dmg": + # Repack macOS disk image -> zip for RomM download (extract with bsdtar). + ext = ".dmg" + tmp = tempfile.mkdtemp(prefix="pcrepack_") + try: + r = subprocess.run(["bsdtar", "-xf", path, "-C", tmp], capture_output=True, text=True) + if r.returncode != 0: + report.append(("PC", "FAIL", origin, (r.stderr or "bsdtar failed")[:60], "")); return + tmp_zip = dest + ".part" + with zipfile.ZipFile(tmp_zip, "w", zipfile.ZIP_DEFLATED) as z: + for root, _, files in os.walk(tmp): + for fn in files: + fp = os.path.join(root, fn) + z.write(fp, os.path.relpath(fp, tmp)) + if PLACE: + os.makedirs(dest_dir, exist_ok=True) + os.replace(tmp_zip, dest) + else: + os.remove(tmp_zip) + report.append(("PC", "OK", origin, f"repacked {ext}->zip", f"{dest_dir.split('/')[-1]}/{out_name}")) + finally: + shutil.rmtree(tmp, ignore_errors=True) + + +def place_pc_installer(path, hackname, origin): + """Wrap a standalone .exe installer in a zip so RomM can serve it.""" + tag = detect_variant(path) or "[Installer]" + out_name = f"Pokemon - {hackname} (Hack) {tag}.zip" + dest_dir = pc_dest_dir(tag) + dest = os.path.join(dest_dir, out_name) + tmp_zip = dest + ".part" + with zipfile.ZipFile(tmp_zip, "w", zipfile.ZIP_DEFLATED) as z: + z.write(path, os.path.basename(path)) + if PLACE: + os.makedirs(dest_dir, exist_ok=True) + os.replace(tmp_zip, dest) + else: + os.remove(tmp_zip) + report.append(("PC", "OK", origin, "installer wrapped in zip", f"{dest_dir.split('/')[-1]}/{out_name}")) + + def process_archive(path, origin): # keep the source archive if PLACE: @@ -242,8 +385,12 @@ def process_archive(path, origin): subprocess.run(["docker", "run", "--rm", "-v", f"{os.path.dirname(path)}:/in:ro", "-v", f"{tmp}:/out", "node:lts", "bash", "-c", "apt-get update -qq>/dev/null 2>&1; apt-get install -y -qq unar>/dev/null 2>&1; " - f"unar -force-overwrite -o /out '/in/{os.path.basename(path)}' >/dev/null"], + f"unar -force-overwrite -o /out '/in/{os.path.basename(path)}' >/dev/null; " + "chown -R $(stat -c %u:%g /out) /out"], capture_output=True, text=True) + if is_pc_fan_game(tmp): + place_pc_archive(path, clean_name(path), origin) + return for root, _, files in os.walk(tmp): for fn in files: fp = os.path.join(root, fn) @@ -258,7 +405,16 @@ def main(): args = [a for a in sys.argv[1:] if not a.startswith("--")] PLACE = "--place" in sys.argv incoming = args[0] - for fn in sorted(os.listdir(incoming)): + + def _sort_key(fn): + low = fn.lower() + if "fire red (j)" in low: + return (0, fn) + if os.path.splitext(fn)[1].lower() in PATCH_EXT: + return (2, fn) + return (1, fn) + + for fn in sorted(os.listdir(incoming), key=_sort_key): fp = os.path.join(incoming, fn) if os.path.isfile(fp): process_file(fp) diff --git a/scripts/vault-sync-placed.py b/scripts/vault-sync-placed.py new file mode 100644 index 0000000..55def89 --- /dev/null +++ b/scripts/vault-sync-placed.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 +"""Sync vault hack notes with placed RomM library paths (2026-06-23 batch).""" +import re +from pathlib import Path + +VAULT = Path(r"C:\Users\MattC\Documents\Obsidian Vault\Pokémon ROM Hacks\Hacks") + +# RomM filename stem (without Pokemon - / (Hack) / variant) -> note stem +PLACED = { + # windows primary + variants + "Alchemist": ("PC", "roms/windows/Pokemon - Alchemist (Hack).zip", "Complete"), + "Abstract": ("PC", "roms/windows/Pokemon - Abstract (Hack).zip", "Complete"), + "Awakening ENG": ("PC", "roms/windows/Pokemon - Awakening ENG (Hack).zip", "Complete"), + "Bizarre ENGLISH": ("PC", "roms/windows/Pokemon - Bizarre ENGLISH (Hack).zip", "Complete"), + "Concealed 2.1": ("PC", "roms/windows/Pokemon - Concealed 2.1 (Hack).zip", "Complete"), + "Consonancia 1.2": ("PC", "roms/windows/Pokemon - Consonancia 1.2 (Hack).zip", "Complete"), + "Eon Guardians": ("PC", "roms/windows/Pokemon - Eon Guardians (Hack).zip", "Complete"), + "Fire Ash": ("PC", "roms/windows/Pokemon - Fire Ash (Hack).zip", "Complete"), + "Floral Tempus": ("GBA", "roms/windows/Pokemon - Floral Tempus (Hack).zip", "Complete"), + "HGSS Sevii": ("NDS", "roms/windows/Pokemon - HGSS Sevii (Hack).zip", "Complete"), + "Hero Legacy": ("PC", "roms/windows/Pokemon - Hero Legacy (Hack).zip", "Complete"), + "Jam Festival": ("PC", "roms/windows/Pokemon - Jam Festival (Hack).zip", "Complete"), + "Legends of the Arena": ("PC", "roms/windows/Pokemon - Legends of the Arena (Hack).zip", "Complete"), + "Mega Adventures": ("PC", "roms/windows/Pokemon - Mega Adventures (Hack).zip", "Complete"), + "Nightmare 1.3.0": ("PC", "roms/windows/Pokemon - Nightmare 1.3.0 (Hack).zip", "Complete"), + "Poketale": ("PC", "roms/windows/Pokemon - Poketale (Hack).zip", "Complete"), + "Prisme": ("PC", "roms/windows/Pokemon - Prisme (Hack) [Installer].zip", "Complete"), + "Shattered Light": ("PC", "roms/windows/Pokemon - Shattered Light (Hack).zip", "Ongoing"), + "Tectonic 3.3.1": ("PC", "roms/windows/Pokemon - Tectonic 3.4.1 (Hack).zip", "Ongoing"), + "Tectonic 3.4.1": ("PC", "roms/windows/Pokemon - Tectonic 3.4.1 (Hack).zip", "Ongoing"), + "Uranium": ("PC", "roms/windows/Pokemon - Uranium (Hack) [Installer].zip", "Complete"), + "InfiniteFusion": ("PC", "roms/windows/Pokemon - InfiniteFusion (Hack) [Full].zip", "Complete"), + "Infinity 3.3.1": ("PC", "roms/windows/Pokemon - Infinity 3.3.1 (Hack).zip", "Complete"), + "Rejuvenation": ("PC", "roms/windows/Pokemon - Rejuvenation (Hack).zip", "Ongoing"), + "Itinerant": ("GBA", "roms/windows/Pokemon - Itinerant (Hack).zip", "Ongoing"), + "Relict": ("PC", "roms/windows/Pokemon - Relict (Hack).zip", "Complete"), + "Reminiscencia": ("PC", "roms/windows/Pokemon - Reminiscencia (Hack).zip", "Complete"), + "Vanguard": ("PC", "roms/windows/Pokemon - Vanguard (Hack).zip", "Ongoing"), + "Xenoverse": ("PC", "roms/windows/Pokemon - Xenoverse (Hack).zip", "Complete"), + "Reborn": ("PC", "roms/windows/Pokemon - Reborn (Hack).zip", "Complete"), + "Coral": ("GBC", "roms/gbc/Hacks/Pokemon - Coral (Hack).gbc", "Beta"), + "Giratina Strikes Back Full": ("GBA", "roms/gba/Hacks/Pokemon - Giratina Strikes Back Full (Hack).gba", "Complete"), + "Sienna Complete": ("GBA", "roms/gba/Hacks/Pokemon - Sienna Complete (Hack).gba", "Complete"), + "Spades and Clubs": ("GBA", "roms/gba/Hacks/Pokemon - Spades and Clubs (Hack).gba", "Beta"), + "Emerald Seaglass": ("GBA", "roms/gba/Hacks/Pokemon - Emerald Seaglass (Hack).gba", "Complete"), +} + +NOTE_MAP = { + "Awakening ENG": "Awakening", + "Bizarre ENGLISH": "Bizarre", + "Concealed 2.1": "Concealed", + "Consonancia 1.2": "Consonancia", + "Nightmare 1.3.0": "Nightmare", + "Tectonic 3.4.1": "Tectonic", + "Tectonic 3.3.1": "Tectonic", + "Giratina Strikes Back Full": "Giratina Strikes Back", + "Sienna Complete": "Sienna", + "Infinity 3.3.1": "Infinity", + "InfiniteFusion": "Infinite Fusion", + "Reminiscencia": "Reminiscencia", +} + +VARIANTS_BLOCK = """## Alternate builds (RomM) + +| Variant | Path | +|---|---| +{rows} + +> Windows zip is the Playnite primary unless noted. Joiplay/Android/Linux/macOS builds are separate RomM download entries. +""" + + +def patch_fm(text, key, val): + if re.search(rf"^{key}:", text, re.M): + return re.sub(rf"^{key}:.*$", f'{key}: {val}', text, count=1, flags=re.M) + # insert after title + return re.sub(r"(^title:.*\n)", rf"\1{key}: {val}\n", text, count=1, flags=re.M) + + +def main(): + updated = [] + for rom_key, (plat, lp, status) in PLACED.items(): + stem = NOTE_MAP.get(rom_key, rom_key) + p = VAULT / f"{stem}.md" + if not p.exists(): + print(f"SKIP no note: {stem}") + continue + text = p.read_text(encoding="utf-8") + text = patch_fm(text, "platform", plat) + text = patch_fm(text, "status", status) + text = patch_fm(text, "library_path", f'"{lp}"') + if rom_key == "Infinity" or rom_key == "Infinity 3.3.1": + text = patch_fm(text, "version", '"3.3.1"') + if rom_key == "Nightmare 1.3.0": + text = patch_fm(text, "version", '"1.3.0"') + if rom_key == "Tectonic 3.4.1": + text = patch_fm(text, "version", '"3.4.1"') + # normalize In the library section + if "## In the library" in text: + text = re.sub( + r"(?ms)^## In the library\s*\n.*?(?=^## |\n\[\[Index|\Z)", + f"## In the library\n\n> Placed in RomM library (`{lp}`).\n\n", + text, + count=1, + ) + p.write_text(text, encoding="utf-8") + updated.append(stem) + print(f"Updated {len(updated)} notes: {', '.join(sorted(updated))}") + + +if __name__ == "__main__": + main() diff --git a/wiki/catalog.json b/wiki/catalog.json index a240ea4..e510be0 100644 --- a/wiki/catalog.json +++ b/wiki/catalog.json @@ -1,21 +1,21 @@ { "generated": "2026-06-23", - "count": 372, + "count": 395, "facets": { "platform": { - "GBA": 191, - "NDS": 47, - "Unknown": 45, - "PC": 41, - "GBC": 22, + "GBA": 196, + "PC": 64, + "NDS": 48, + "Unknown": 38, + "GBC": 23, "GB": 14, "3DS": 6, "Patch": 6 }, "base": { - "Unknown": 184, - "Emerald": 58, - "FireRed": 50, + "Unknown": 204, + "Emerald": 59, + "FireRed": 52, "Crystal": 19, "Ruby": 8, "HeartGold": 6, @@ -49,10 +49,10 @@ "the north atlantic island nation of Iceland": 1 }, "status": { - "Complete": 171, - "Unknown": 161, - "Ongoing": 29, - "Beta": 10, + "Complete": 195, + "Unknown": 153, + "Ongoing": 34, + "Beta": 12, "Complete (beta)": 1 }, "engine": { @@ -68,17 +68,17 @@ "pokeemerald (decomp, likely)": 1 }, "type": { - "Expansion": 143, - "New Experience": 130, - "Difficulty": 105, + "New Experience": 155, + "Expansion": 144, + "Difficulty": 107, "QoL": 54, "Vanilla+": 25, "Cosmetic": 11, "Demake": 8, - "Roguelite": 5 + "Roguelite": 6 }, "play_status": { - "Unplayed": 368, + "Unplayed": 391, "Completed": 3, "Dropped": 1 } @@ -185,34 +185,46 @@ { "stem": "Abstract", "title": "Pokémon Abstract", - "platform": null, + "platform": "PC", "base": null, "version": "1.7", "status": "Complete", - "generation": null, + "generation": "Joiplay/RPGXP", + "developer": "Nandthesword", "release_date": "2023", "banner": "https://romhacks-files.ginnoir.com/_meta/Pokemon_Abstract/title-1-14b9cf3147b2a7f1.gif", "source": "https://www.pokecommunity.com/threads/pokémon-abstract-version.527324/", - "library_path": "—", + "library_path": "roms/windows/Pokemon - Abstract (Hack).zip", "play_status": "Unplayed", "scrape_dir": "Pokemon_Abstract", - "type": [], + "type": [ + "New Experience" + ], "tags": [ "hack", + "platform/pc", "status/complete", + "type/newexperience", "source/discord" ], - "summary": "**Creator**: Nandthesword **Version**: 1.7 **Updated**: August 10, 2023 **Status**: Completed [Source Website](https://www.pokecommunity.com/threads/pokémon-abstract-version.527324/) ## __Description__ > Velos supports a wide variety of cultures, landscapes and unique views. Although, because of its diversity, this region is divided into four provinces, each with their own differences and conflicts. > > It's time for you to go out into the unknown! > > Traverse new areas, take on the Velos Gym Challenge, find new Pokémon, and meet people with new perspectives at your OWN leisure! ## __Features__ - 11 Settlements. - 28 Wild Areas. - 4 Provinces Tranquill, Strife, Carnage, & Vigor. - Gyms/Story Events that can be done in any order. - 18 New Pokémon. - 8 New Megas. - New tiles. - Fully Custom UI. - Level scaling. - Difficulty modes. - HM Items that open up new areas. - A full story. ## :Download: [Download Here](https://drive.usercontent.google.com/download?id=1lbpV4vCwn77LZxIxRTyXMxY_gqUBuffq&export=download&authuser=0)", + "summary": "Nonlinear Essentials fangame in the Velos region, divided into four provinces (Tranquill, Strife, Carnage, Vigor). Gyms and story events can be tackled in any order; 18 new Pokémon, eight new megas, and a fully custom UI with level scaling and difficulty modes.", "notability": "", "story": "", - "features": [], + "features": [ + "Velos region — 11 settlements, 28 wild areas, four provinces", + "Nonlinear gyms and story events", + "18 new Pokémon; 8 new Mega Evolutions", + "Fully custom UI; level scaling; difficulty modes", + "HM items gating new areas", + "Same developer as [[Concealed]]" + ], "links": [ { - "label": "Info / thread", + "label": "Source / info", "url": "https://www.pokecommunity.com/threads/pokémon-abstract-version.527324/" }, { - "label": "Link", + "label": "Download", "url": "https://drive.usercontent.google.com/download?id=1lbpV4vCwn77LZxIxRTyXMxY_gqUBuffq&export=download&authuser=0" } ] @@ -486,6 +498,46 @@ } ] }, + { + "stem": "Alchemist", + "title": "Pokémon Alchemist", + "platform": "PC", + "base": null, + "version": "5.3", + "status": "Complete", + "generation": "Joiplay/RPGXP", + "developer": "Jttyzzle", + "release_date": "2021", + "source": "https://www.pokecommunity.com/threads/pokémon-alchemist.378280/", + "library_path": "roms/windows/Pokemon - Alchemist (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience" + ], + "summary": "A long-running Essentials fangame set in the Kamla region: classic eight-gym structure blended with gens III–V sensibilities, no fakemon, and 649 Pokémon. An evil team plot to resurrect an ancient Pokémon drives the main story, but the real draw is an enormous postgame with twelve episodic arcs, visits to five classic regions, and over twenty gyms total.", + "notability": "", + "story": "", + "features": [ + "Original Kamla region plus Kanto, Johto, Hoenn, Sinnoh, and Unova areas in postgame", + "649 Pokémon; no fakemon", + "Eight main gyms + League, then 12 postgame episodes (time travel, enemy bases, viruses, and more)", + "20+ gyms across five regions; World Tournament and Championship", + "International Police storyline with secret bases and sidequests", + "v5.3 complete release" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/pokémon-alchemist.378280/" + } + ] + }, { "stem": "All In", "title": "Pokémon All In", @@ -1006,35 +1058,39 @@ { "stem": "Awakening", "title": "Pokémon Awakening", - "platform": null, + "platform": "PC", "base": null, "version": null, - "status": null, - "generation": null, + "status": "Complete", + "generation": "Joiplay/RPGXP", "banner": "https://romhacks-files.ginnoir.com/_meta/Pokemon_Awakening/Pokemon-Awakening-e163a4214e22864c.png", "source": "https://mega.nz/221fb646-0a04-4316-a163-f9b532c89197", - "library_path": "—", + "library_path": "roms/windows/Pokemon - Awakening ENG (Hack).zip", "play_status": "Unplayed", "scrape_dir": "Pokemon_Awakening", "type": [ - "Difficulty" + "Difficulty", + "New Experience" ], "tags": [ "hack", + "platform/pc", + "status/complete", "type/difficulty", + "type/newexperience", "source/discord" ], - "summary": "Catalogued from the Discord ROM-hack archive. See links below.", + "summary": "Fantasy-flavored Essentials fangame in Waerfall Village, where ancient Idols guard secrets of the past. You wield D. Moon, a mysterious grimoire, alongside guardian fairy Pixi — choosing between order and chaos shapes the combat-focused adventure.", "notability": "", - "story": "Waerfall Village is a peculiar place where certain Idols that hold very important secrets from the past are kept safe. You are a young Apprentice of the Sage Addae and the owner of D. Moon, a special grimoire that they say was found between you and your brother as children before raising you in the village. One day, D. Moon begins to react strongly near a waterfall north of the village, as if he felt a call coming from within... But that was only the beginning of an adventure.\n\nExperience the journey of the hero who defied his destiny and was blessed by the gods!\n\nFight side by side with your Pokémon and meet Pixi, a guardian fairy, who will accompany you on this adventure full of fantasy and diverse emotions. Discover the secrets that D. Moon keeps and go in search of your village's treasures before it's too late.\n\nWill order be your conviction, or will you succumb to chaos?", + "story": "Waerfall Village is a peculiar place where certain Idols that hold very important secrets from the past are kept safe. You are a young Apprentice of the Sage Addae and the owner of D. Moon, a special grimoire that they say was found between you and your brother as children before raising you in the village. One day, D. Moon begins to react strongly near a waterfall north of the village, as if he felt a call coming from within... But that was only the beginning of an adventure.\n\nExperience the journey of the hero who defied his destiny and was blessed by the gods! Fight side by side with your Pokémon and meet Pixi, a guardian fairy, who will accompany you on this adventure full of fantasy and diverse emotions. Discover the secrets that D. Moon keeps and go in search of your village's treasures before it's too late.\n\nWill order be your conviction, or will you succumb to chaos?", "features": [ - "Class/job system.", - "Wild overworld encounters.", - "Special events. (Crossovers)", - "An accessible yet challenging adventure, where every decision in combat counts.", - "A path of order and chaos.", - "Relationship system. (Persona like)", - "Various actions depending on the time of day." + "Class/job system", + "Wild overworld encounters", + "Special crossover events", + "Accessible yet challenging combat — every decision counts", + "Order vs chaos path system", + "Persona-like relationship system", + "Time-of-day dependent actions" ], "links": [ { @@ -1368,6 +1424,46 @@ } ] }, + { + "stem": "Bizarre", + "title": "Pokémon Bizarre", + "platform": "PC", + "base": null, + "version": null, + "status": "Complete", + "generation": "Joiplay/RPGXP", + "developer": "MrGrossi", + "release_date": "2022", + "source": "https://www.mediafire.com/file/lox59f4nubxflw6/Pokemon_Bizarre_ENGLISH.zip/file", + "library_path": "roms/windows/Pokemon - Bizarre ENGLISH (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience" + ], + "summary": "Comedy-punk Essentials fangame in the Quintueles region — classic eight-gym structure with absurd humor, regional forms, fakemon, and Gen 8 Pokémon. ~25–30 hours of main story plus side content; day/night cycle and fairy type included.", + "notability": "", + "story": "", + "features": [ + "Quintueles region — eight gyms, new story and characters", + "Pokémon gens 1–8; regional forms and fakemon", + "Punk/comedy tone — eccentric NPCs, wild side missions", + "Day/night system; physical/special split; Gen 7 moves/abilities", + "Gen 4–style graphics", + "40+ hours with side quests (per English release notes)" + ], + "links": [ + { + "label": "Download", + "url": "https://www.mediafire.com/file/lox59f4nubxflw6/Pokemon_Bizarre_ENGLISH.zip/file" + } + ] + }, { "stem": "Black 2 - Silly Edition", "title": "Pokémon Black 2 : Silly Edition", @@ -2605,6 +2701,45 @@ } ] }, + { + "stem": "Concealed", + "title": "Pokémon Concealed", + "platform": "PC", + "base": null, + "version": "2.1", + "status": "Complete", + "generation": "Joiplay/RPGXP", + "developer": "Nandthesword", + "release_date": "2024", + "source": "https://www.pokecommunity.com/threads/concealed.527325/", + "library_path": "roms/windows/Pokemon - Concealed 2.1 (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience" + ], + "summary": "Psychological horror Essentials fangame starring Onylle, a girl trapped in the idyllic-but-oppressive Presadi City. Beneath the cheerful surface lies trauma, control, and a society that hides from the outside world. About 10–12 hours; content warnings for abuse, depression, and mild horror.", + "notability": "", + "story": "", + "features": [ + "Essentials v20; ~10–12 hour story", + "Presadi City setting — utopian community with a dark underbelly", + "Psychological narrative about trauma and escaping toxic simplicity", + "Pokémon through Gen 8 sprites", + "Same developer as [[Abstract]]" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/concealed.527325/" + } + ] + }, { "stem": "Conquest - Ultimate", "title": "Pokémon Conquest: Ultimate", @@ -2646,6 +2781,46 @@ } ] }, + { + "stem": "Consonancia", + "title": "Pokémon Consonancia", + "platform": "PC", + "base": null, + "version": "1.2", + "status": "Complete", + "generation": "Multi-gen", + "developer": "Team Pokémon Consonancia", + "release_date": "2024", + "source": "https://www.pokecommunity.com/threads/pokémon-consonancia-full-game.537329/", + "library_path": "roms/windows/Pokemon - Consonancia 1.2 (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience" + ], + "summary": "Pokémon Masters–inspired Essentials fangame set in the Passio region. You compete in the WPM, a high-level trainer tournament, while recruiting hundreds of sync-pair-style characters through story and a gacha system. Spanish-origin; English build in library.", + "notability": "", + "story": "", + "features": [ + "Passio region tournament arc (WPM) — not a traditional gym crawl", + "600+ recruitable characters via story and gacha mode", + "Trainers and characters from Kanto through Paldea plus Masters cast", + "Triple battles; level caps between bosses", + "Looped Masters soundtrack; official character mugshots and voices", + "Gacha album to track your collection" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/pokémon-consonancia-full-game.537329/" + } + ] + }, { "stem": "Cope", "title": "Pokémon Cope", @@ -2681,14 +2856,14 @@ { "stem": "Coral", "title": "Pokémon Coral", - "platform": null, + "platform": "GBC", "base": null, "version": null, - "status": null, + "status": "Beta", "generation": null, "banner": "https://romhacks-files.ginnoir.com/_meta/Pokemon_Coral/IMG_9876-4bd4b29d7e537d57.webp", "source": "https://raw.githubusercontent.com/vbaemulator/GBC-Roms/main/Pokemon%20Coral%20Version%20v1.2.zip", - "library_path": "—", + "library_path": "roms/gbc/Hacks/Pokemon - Coral (Hack).gbc", "play_status": "Unplayed", "scrape_dir": "Pokemon_Coral", "type": [ @@ -2774,6 +2949,46 @@ } ] }, + { + "stem": "Crown", + "title": "Pokémon Crown", + "platform": "PC", + "base": null, + "version": null, + "status": "Ongoing", + "generation": "Joiplay/RPGXP", + "developer": "Blah", + "release_date": "2023", + "source": "https://www.pokecommunity.com/threads/pokémon-crown.463821/", + "library_path": "—", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/ongoing", + "type/newexperience" + ], + "summary": "Pokémon Crown is a PC Essentials fan-game that reimagines Pokémon as a medieval auto-chess RPG in the Guelder region. Battles are 6v6 placement-and-synergy combat instead of turn-based fights — closer to TFT than traditional Pokémon. Beta release; download via Discord when available.", + "notability": "", + "story": "", + "features": [ + "Auto-chess-inspired battle engine (no traditional turn-based combat)", + "Guelder region with pseudo-open world and quest system", + "Pokémon from all generations; new catching mechanics", + "Day/night system, custom UI, boss battles, and challenge modes", + "Online PvP (PC client)", + "Crown League tournament structure instead of eight gyms" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/pokémon-crown.463821/" + } + ] + }, { "stem": "Crystal 16-bit", "title": "Pokémon Crystal 16-bit", @@ -3755,7 +3970,7 @@ "platform": "PC", "base": null, "version": "1.4", - "status": null, + "status": "Complete", "generation": null, "release_date": "2022", "banner": "https://romhacks-files.ginnoir.com/_meta/Pokemon_Deserted/TCjUt.qR4e-small-Pokemon-Deserted-A-Short--102745be5cc33d62.jpg", @@ -3769,6 +3984,7 @@ "tags": [ "hack", "platform/pc", + "status/complete", "type/qol", "source/discord" ], @@ -4717,6 +4933,51 @@ } ] }, + { + "stem": "Eon Guardians", + "title": "Pokémon Eon Guardians", + "platform": "PC", + "base": null, + "version": "2.0.9", + "status": "Complete", + "generation": "Gen IV", + "developer": "NikDie", + "release_date": "2024", + "source": "https://www.pokecommunity.com/threads/pokémon-eon-guardians.527913/", + "library_path": "roms/windows/Pokemon - Eon Guardians (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience" + ], + "summary": "Gen 4–styled Essentials fangame in the Terre region with 50+ hours of content, eight badges, and a deep postgame. All Pokémon from gens I–IV, heavy QoL (following Pokémon, HM items, level caps, crafting), and optional randomizer and Nuzlocke modes.", + "notability": "", + "story": "", + "features": [ + "Terre region — 50+ hours, eight gyms, Titanium Plateau", + "Gen 4 graphics; Pokémon through Gen 4", + "Difficulty modes, level caps, following Pokémon, HM items", + "Item crafting system; 50+ side quests", + "Randomizer and Nuzlocke modes; New Game+", + "Rematchable Colosseum, Combat Pillar, challenging postgame", + "Custom Pokéballs and EBDX move animations" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/pokémon-eon-guardians.527913/" + }, + { + "label": "FAQ", + "url": "https://sites.google.com/view/pokemon-eon-guardians/general/faq" + } + ] + }, { "stem": "Ephemerald", "title": "Pokémon Ephemerald", @@ -5010,6 +5271,50 @@ } ] }, + { + "stem": "Fire Ash", + "title": "Pokémon Fire Ash", + "platform": "PC", + "base": null, + "version": "3.6", + "status": "Complete", + "generation": "Multi-gen", + "developer": "Reinhartmax & team", + "release_date": "2024", + "source": "https://www.pokecommunity.com/threads/pokémon-fire-ash.399096/", + "library_path": "roms/windows/Pokemon - Fire Ash (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/ongoing", + "type/newexperience" + ], + "summary": "Essentials fangame that follows Ash Ketchum's anime journey from Kanto through Galar in FireRed/LeafGreen presentation. Fight anime rivals, league circuits, and Masters Eight; seven outfits across the adventure. Actively updated — check Discord for latest patches beyond the RomM zip.", + "notability": "", + "story": "", + "features": [ + "Anime storyline across Kanto, Johto, Hoenn, Sinnoh, Unova, Kalos, Alola, and Galar", + "FRLG-style graphics and UI (Essentials v19+)", + "Anime rivals, multiple Pokémon Leagues, and Masters Eight arc", + "Seven unlockable outfits for Ash", + "Encounter docs and community walkthrough included with releases", + "English, Spanish, and Italian versions available" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/pokémon-fire-ash.399096/" + }, + { + "label": "Active thread", + "url": "https://www.pokecommunity.com/threads/pokémon-fire-ash-version-3-6-part-2-out.531791/" + } + ] + }, { "stem": "Fire Red 898", "title": "Pokémon Fire Red 898", @@ -5496,6 +5801,52 @@ } ] }, + { + "stem": "Floral Tempus", + "title": "Pokémon Floral Tempus", + "platform": "GBA", + "base": null, + "version": "1.9.4", + "status": "Complete", + "generation": "Gen III", + "developer": "Juno and Ice", + "release_date": "2022", + "source": "https://www.pokecommunity.com/threads/pokémon-floral-tempus-ex-1-9-4-released-12-gym-badges-elite-4-champion.409175/", + "library_path": "roms/windows/Pokemon - Floral Tempus (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience", + "Difficulty" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience", + "type/difficulty" + ], + "summary": "Essentials fangame in the Rialtra region with a mature story, 12 gyms, and heightened challenge. Team Blight's kidnappings kick off an orphanage-origins plot with level caps, scaling trainers, and multiple difficulty modes from easy through insane.", + "notability": "", + "story": "", + "features": [ + "Rialtra region — 12 gyms, Elite Four, and Champion (Floral Tempus EX)", + "Level caps tied to badge progress; trainer level scaling by difficulty", + "Following Pokémon, HM items, berry farming, custom megas", + "Trade evolutions via Trade Stone or held-item method", + "Map revamps, updated sprites, and rebalanced trainers in EX", + "Multiple difficulty modes (easy / normal / hard / insane)" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/pokémon-floral-tempus-ex-1-9-4-released-12-gym-badges-elite-4-champion.409175/" + }, + { + "label": "Wiki", + "url": "https://pokemon-floral-tempus.fandom.com/wiki/Pok%C3%A9mon_Floral_Tempus_Wiki" + } + ] + }, { "stem": "Following Renegade Platinum", "title": "Pokémon Following Renegade Platinum", @@ -5916,12 +6267,12 @@ "platform": "GBA", "base": "FireRed", "version": null, - "status": null, + "status": "Complete", "generation": "Gen III", "release_date": "2017", "banner": "https://romhacks-files.ginnoir.com/_meta/Pok_mon_Giratina_Strikes_Back/pokemon-giratina-strikes-back-efd99b614659b4a5.png", "source": "https://www.mediafire.com/file/3rojwlf24n32ak7/Giratina_Strikes_Back_Full.zip/file", - "library_path": "/storage1/Emulation/roms/gba/Giratina Strikes Back Full.gba", + "library_path": "roms/gba/Hacks/Pokemon - Giratina Strikes Back Full (Hack).gba", "play_status": "Unplayed", "scrape_dir": "Pok_mon_Giratina_Strikes_Back", "type": [ @@ -6386,6 +6737,55 @@ } ] }, + { + "stem": "HGSS Sevii", + "title": "Pokémon HGSS Sevii", + "platform": "NDS", + "base": null, + "version": "1.1.0", + "status": "Complete", + "generation": "Gen IV", + "developer": "PurpleZaffre", + "release_date": "2021", + "homepage": "https://www.purplezaffre.com/", + "source": "https://www.pokecommunity.com/threads/pokémon-hgss-sevii-islands-hoenn-postgame.434636/", + "library_path": "roms/windows/Pokemon - HGSS Sevii (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience" + ], + "summary": "Standalone Essentials sequel to HeartGold/SoulSilver — not a ROM hack. Starts right after defeating Red; Eusine sends you to the Sevii Islands to investigate Team Rocket and the remaining Legendary Beasts, then opens a full Hoenn epilogue. 40+ hours with HGSS presentation.", + "notability": "", + "story": "", + "features": [ + "Continues HGSS canon (post-Red); opening questionnaire sets starter, version, gender", + "Eight chapters on Sevii Islands vs Team Rocket", + "Full Hoenn epilogue — Aqua/Magma resurgence, quests, and League challenge", + "Mega Evolution (incl. custom/G-Max megas), regional forms, Paradox Pokémon", + "Online trading and battling; enhanced Pokégear with storage and quest log", + "40+ hours; speed-up button and customizable controls" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/pokémon-hgss-sevii-islands-hoenn-postgame.434636/" + }, + { + "label": "Website", + "url": "https://www.purplezaffre.com/" + }, + { + "label": "Wiki", + "url": "https://pokemon-hgss-sevii-islands.fandom.com/wiki/Pok%C3%A9mon_HGSS:_Sevii_Islands_Wiki" + } + ] + }, { "stem": "Heart and Soul", "title": "Pokémon Heart and Soul", @@ -6572,6 +6972,46 @@ } ] }, + { + "stem": "Hero Legacy", + "title": "Pokémon Hero Legacy", + "platform": "PC", + "base": null, + "version": "3.0.7", + "status": "Complete", + "generation": "Gen 1–8", + "developer": "Younam", + "release_date": "2025", + "source": "https://www.pokecommunity.com/threads/pokémon-hero-legacy-eng-de-now-with-new-game-mode.538518/", + "library_path": "roms/windows/Pokemon - Hero Legacy (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience" + ], + "summary": "Epilogue-style Essentials epic in the New Zealand–inspired Aoroa region. You play as an established Champion exploring legacy, family, and a new generation of challenges — 55+ hours main story, 120+ with side content, and every Pokémon from gens 1–8 catchable.", + "notability": "", + "story": "", + "features": [ + "Aoroa region — eight gyms with unique mechanics each", + "Post-Galar narrative; returning characters with new arcs", + "Quest system, item crafting, HM substitutes, level caps", + "EV/IV summary screen; PC access anywhere; Apricorn Balls", + "New Game+ mode (deposit eggs from prior save)", + "English and German full translations" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/pokémon-hero-legacy-eng-de-now-with-new-game-mode.538518/" + } + ] + }, { "stem": "Hisui Red", "title": "Pokémon Hisui Red", @@ -7116,7 +7556,7 @@ "banner": "https://romhacks-files.ginnoir.com/_meta/Pokemon_Infinite_Fusion/FB_IMG_1709754195267-745fda0d8b7fee05.jpg", "homepage": "https://infinitefusion.fandom.com/", "source": "https://www.pokeharbor.com/2023/03/pokemon-infinite-fusion/", - "library_path": "roms/pc/Pokemon - Infinite Fusion (sprite-seeded).zip", + "library_path": "roms/windows/Pokemon - InfiniteFusion (Hack) [Full].zip", "play_status": "Unplayed", "scrape_dir": "Pokemon_Infinite_Fusion", "type": [ @@ -7154,11 +7594,10 @@ "title": "Pokémon Infinity", "platform": "PC", "base": null, - "version": null, - "status": null, - "generation": "Joiplay/RPGXP", + "version": "3.3.1", + "status": "Complete", "source": "https://1fichier.com/?n6v1eej3pipn1ts9sx69&af=2885774", - "library_path": "/storage1/labdata/romhacks/library/Pokemon_Infinity/", + "library_path": "roms/windows/Pokemon - Infinity 3.3.1 (Hack).zip", "play_status": "Unplayed", "scrape_dir": "Pokemon_Infinity", "type": [], @@ -7362,6 +7801,86 @@ } ] }, + { + "stem": "Itinerant", + "title": "Pokémon Itinerant", + "platform": "GBA", + "base": null, + "version": "7.9.4", + "status": "Ongoing", + "generation": "Gen IX", + "developer": "RegalSword", + "release_date": "2024", + "source": "https://www.pokecommunity.com/threads/pokemon-itinerant.528218/", + "library_path": "roms/windows/Pokemon - Itinerant (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/ongoing", + "type/newexperience" + ], + "summary": "Essentials fangame with FRLG-style graphics and Gen 9 mechanics (Terastal, Gen 9 Pokémon). Stranded abroad on vacation, you and your rival get swept into Team Exodus's schemes. Main story complete through the Championship Tournament; v8 postgame planned.", + "notability": "", + "story": "", + "features": [ + "Gen 9 Pokémon, Terastal phenomenon, FRLG-style presentation", + "Eight gyms plus Championship Tournament (E4/Champion equivalent)", + "Exp. All, quicksave, speed-up, Battle Tower and Battle Factory", + "v7 postgame: Alcan's Epilogue (Bloodmoon Ursaluna reward)", + "Save after Hall of Fame to preserve compatibility with upcoming v8 postgame", + "Joiplay-compatible with specific plugin versions" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/pokemon-itinerant.528218/" + } + ] + }, + { + "stem": "Jam Festival", + "title": "Pokémon Jam Festival", + "platform": "PC", + "base": null, + "version": "1.0", + "status": "Complete", + "generation": "Gen III", + "developer": "bombastik", + "release_date": "2025", + "source": "https://www.pokecommunity.com/threads/pkmn-jam-festival.536702/", + "library_path": "roms/windows/Pokemon - Jam Festival (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience" + ], + "summary": "Chill open-world Essentials fangame on the Jamaica-inspired Jameyka island. Reconnect with your estranged grandpa and compete in the Jam Festival Trial — gathering ingredients from Trial Captains in any order. Slice-of-life tone, double battles only, no evil-team save-the-world plot.", + "notability": "", + "story": "", + "features": [ + "Open-world Jameyka — challenge Trial Captains in any order after intro", + "All double battles (set style, no healing items in fights)", + "~15 hours; 21 side quests; dialogue choices affect story", + "Level scaling by Trial Captains beaten; toggleable level caps and Exp. Share", + "Starter evolves into four forms; regional variants and fakemon", + "HM items, encounter list, IV/EV summary screen, advanced Pokédex" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/pkmn-jam-festival.536702/" + } + ] + }, { "stem": "Jet Black", "title": "Pokémon Jet Black", @@ -7973,6 +8492,46 @@ } ] }, + { + "stem": "Legends of the Arena", + "title": "Pokémon Legends of the Arena", + "platform": "PC", + "base": null, + "version": "1.4.1", + "status": "Complete", + "generation": "Joiplay/RPGXP", + "developer": "—", + "release_date": "2021", + "source": "https://www.pokecommunity.com/threads/pokémon-legends-of-the-arena.298738/", + "library_path": "roms/windows/Pokemon - Legends of the Arena (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience" + ], + "summary": "Unconventional Essentials fangame built around the International Pokémon Championships instead of gym badges. Five years after a civil war nearly tore Aria apart over the tournament, you and your brother enter the IPC — cults, celebrities, and Pokémon battles woven through a talking protagonist.", + "notability": "", + "story": "", + "features": [ + "Aria region — tournament structure over eight rounds to the final", + "Seven Eevee-based starters chosen via personality quiz", + "Rich RPG plot with multiple endings", + "Side quests: treasure hunting, time travel, and more", + "13+ hidden legendaries", + "No traditional eight-gym formula" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/pokémon-legends-of-the-arena.298738/" + } + ] + }, { "stem": "Let's Go Peerless Pikachu & Exquisite Eevee", "title": "Pokémon Let's Go: Peerless Pikachu & Exquisite Eevee", @@ -8314,6 +8873,50 @@ } ] }, + { + "stem": "Mega Adventures", + "title": "Pokémon Mega Adventures", + "platform": "PC", + "base": null, + "version": "1.3", + "status": "Complete", + "generation": "Gen VI", + "developer": "Leon Draceus", + "release_date": "2016", + "source": "https://www.pokecommunity.com/threads/pokemon-mega-adventure.362058/", + "library_path": "roms/windows/Pokemon - Mega Adventures (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience" + ], + "summary": "Early Essentials megas showcase in the Akito region. Research Professor Oak's Mega Evolution study while stopping Team Prime from weaponizing the strongest mega. 721 Pokémon, all Mega Stones, and a Latios/Latias storyline at Misty Island.", + "notability": "", + "story": "", + "features": [ + "Akito region — seven gyms, 18 towns and cities", + "721 Pokémon catchable; all Mega Evolutions and Mega Bracelet", + "Kanto and Kalos starter options", + "Mystery Gifts; Pixie/Leaf/Ice Stones for Eevee evolutions", + "Link Cable item for trade evolutions without trading", + "Nuzlocke, randomizer, and randomized Nuzlocke modes" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/pokemon-mega-adventure.362058/" + }, + { + "label": "Website", + "url": "https://megaadventure.weebly.com/" + } + ] + }, { "stem": "Mega Blue", "title": "Pokémon Mega Blue", @@ -9611,6 +10214,46 @@ } ] }, + { + "stem": "Nightmare", + "title": "Pokémon Nightmare", + "platform": "PC", + "base": null, + "version": "1.3.0", + "status": "Complete", + "generation": "Multi-gen", + "developer": "bombastik", + "release_date": "2024", + "source": "https://www.pokecommunity.com/threads/pokémon-nightmare.504856/", + "library_path": "roms/windows/Pokemon - Nightmare 1.3.0 (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience" + ], + "summary": "Essentials fangame in the cozy Pacatus region that turns sinister when Team Epialtes emerges. ~15 hours, hand-picked dex of ~300 Pokémon plus 23 regional variants, seven custom megas, and a mysterious-but-not-edgy tone. Challenging but not kaizo.", + "notability": "", + "story": "", + "features": [ + "Pacatus region — standard gym circuit with darker undertones", + "~300 curated Pokémon; 23 regional variant lines; 7 new megas", + "Toggleable level caps; improved battle AI; single and double battles", + "Speed-up (Q); stat check in battle (M/N); encounter list and advanced Pokédex", + "EXP All (unlocked later); HM move relearning in summary", + "Same developer as [[Jam Festival]]" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/pokémon-nightmare.504856/" + } + ] + }, { "stem": "Null", "title": "Pokémon Null", @@ -10656,6 +11299,46 @@ } ] }, + { + "stem": "Poketale", + "title": "Pokémon Poketale", + "platform": "PC", + "base": null, + "version": "1.16", + "status": "Complete", + "generation": "Multi-gen", + "developer": "Jofremou", + "release_date": "2024", + "source": "https://www.mediafire.com/file/n6yzxnclf2uys7c/Poketale.zip/file", + "library_path": "roms/windows/Pokemon - Poketale (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience" + ], + "summary": "Undertale × Pokémon crossover set 70 years after monsters were freed from the Underground. A mysterious light transformed weak monsters into Pokémon in the Ebottia region — uncover the transformation's secret while challenging the Champion. 1010 Pokémon with animated sprites.", + "notability": "", + "story": "", + "features": [ + "Ebottia region; Undertale lore respected", + "1010 Pokémon (through Gen 9, excl. SV DLC); animated battle sprites", + "Regional animated starters unique to this game", + "Higher difficulty from gym 5 onward (competitive items/strategies)", + "Achievement system and side quests", + "Extensive postgame: rematches, legendaries with battle themes, Infernal Tower" + ], + "links": [ + { + "label": "Download", + "url": "https://www.mediafire.com/file/n6yzxnclf2uys7c/Poketale.zip/file" + } + ] + }, { "stem": "Poketropolis", "title": "Pokémon Poketropolis", @@ -10840,6 +11523,45 @@ } ] }, + { + "stem": "Prisme", + "title": "Pokémon Prisme", + "platform": "PC", + "base": null, + "version": null, + "status": "Complete", + "generation": "Joiplay/RPGXP", + "developer": "Prisme Team", + "release_date": "—", + "homepage": "https://pokemonprisme.com", + "source": "https://pokemonprisme.com", + "library_path": "roms/windows/Pokemon - Prisme (Hack) [Installer].zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience" + ], + "summary": "Long-running French Essentials fangame (Prisme) with English support. Story-driven adventure distributed as a Windows installer — RomM serves the installer zip; run `PokemonPrismeInstaller.exe` after download to set up the game.", + "notability": "", + "story": "", + "features": [ + "Original Prisme region and narrative (French development, English available)", + "Full Essentials fangame scope — gyms, story, and postgame content", + "Windows installer distribution (not a raw Game.exe zip)", + "Official site for updates, patches, and community" + ], + "links": [ + { + "label": "Official site", + "url": "https://pokemonprisme.com" + } + ] + }, { "stem": "Project Nova", "title": "Pokémon Project Nova", @@ -11476,7 +12198,7 @@ "banner": "https://romhacks-files.ginnoir.com/_meta/Pokemon_Reborn/16-1-5dc2bc1637770907.png", "homepage": "https://www.rebornevo.com/", "source": "https://www.rebornevo.com/pr/index.html/", - "library_path": "/storage1/Emulation/roms/windows/Pokemon - Reborn (Hack).zip", + "library_path": "roms/windows/Pokemon - Reborn (Hack).zip", "play_status": "Unplayed", "scrape_dir": "Pokemon_Reborn", "type": [ @@ -11805,7 +12527,7 @@ "banner": "https://romhacks-files.ginnoir.com/_meta/Pokemon_Rejuvenation/Screenshot_20240628_152348_Discord-6a5d3f6cae7802de.jpg", "homepage": "https://rejuvenation.wiki.gg/", "source": "https://www.pokeharbor.com/2024/01/pokemon-rejuvenation/", - "library_path": "/storage1/Emulation/roms/windows/Pokemon - Rejuvenation (Hack).zip", + "library_path": "roms/windows/Pokemon - Rejuvenation (Hack).zip", "play_status": "Unplayed", "scrape_dir": "Pokemon_Rejuvenation", "type": [ @@ -11838,17 +12560,62 @@ } ] }, + { + "stem": "Relict", + "title": "Pokémon Relict", + "platform": "PC", + "base": null, + "version": "1.2", + "status": "Complete", + "generation": "Multi-gen", + "developer": "Phion Games", + "release_date": "2025", + "source": "https://phiongames.blogspot.com/2025/12/descarga-pokemon-relict.html", + "library_path": "roms/windows/Pokemon - Relict (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience", + "Roguelite" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience", + "type/roguelite" + ], + "summary": "Roguelike Essentials fangame with randomized runs, 1025 Pokémon through second Paldea DLC, and megas (no Legends Z-A megas). Normal, hard, and unfair difficulty modes; English and Spanish. Not yet in the RomM library.", + "notability": "", + "story": "", + "features": [ + "Roguelike / randomized structure — each run differs", + "Full dex through Paldea DLC 2 (1025 Pokémon); megas included", + "Three difficulty modes: normal, hard, unfair", + "English and Spanish in-game language toggle", + "PC (Windows) and Joiplay (Android) supported" + ], + "links": [ + { + "label": "Source / download", + "url": "https://phiongames.blogspot.com/2025/12/descarga-pokemon-relict.html" + }, + { + "label": "", + "url": "https://phiongames.blogspot.com/2025/12/pokemon-relict-faq-en.html" + } + ] + }, { "stem": "Reminiscencia", "title": "Pokémon Reminiscencia", - "platform": null, + "platform": "PC", "base": null, "version": "1.8", "status": "Complete", "generation": null, "banner": "https://romhacks-files.ginnoir.com/_meta/Pokemon_Reminiscencia/image-10-9793b8b0f07c45c1.png", "source": "https://mega.nz/file/5oNDGI5R#0b_7aQ3fMlUCo6Gwo8dVLXEXnW-seV-o_OanYqxVdRg", - "library_path": "—", + "library_path": "roms/windows/Pokemon - Reminiscencia (Hack).zip", "play_status": "Unplayed", "scrape_dir": "Pokemon_Reminiscencia", "type": [ @@ -13073,6 +13840,50 @@ } ] }, + { + "stem": "Shattered Light", + "title": "Pokémon Shattered Light", + "platform": "PC", + "base": null, + "version": "1.1.0", + "status": "Ongoing", + "generation": "Gen III", + "developer": "Voltseon, ENLS & Tristantine The Great", + "release_date": "2022", + "source": "https://eeveeexpo.com/shattered-light/", + "library_path": "roms/windows/Pokemon - Shattered Light (Hack).zip", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/complete", + "type/newexperience" + ], + "summary": "Polished Game Jam Essentials fangame in the Tepora region with Gen 3 aesthetics. Eight gyms, completable National Dex, Mega Evolution, Shadow Pokémon, and ~10 hours of story — remarkable scope for a jam project. Battle facilities postgame.", + "notability": "", + "story": "", + "features": [ + "Tepora region — 8 gyms, Elite Four, Champion (~10h story)", + "Full National Dex obtainable; Mega Evolutions and Shadow Pokémon", + "Gen 3–style presentation with modern QoL plugins", + "Battle facilities after becoming Champion", + "Dynamic weather-driven encounter variety on routes", + "Completed v1.1.0 (Eevee Expo lists as complete, not ongoing)" + ], + "links": [ + { + "label": "Source / info", + "url": "https://eeveeexpo.com/shattered-light/" + }, + { + "label": "PokeCommunity mirror", + "url": "https://www.pokecommunity.com/threads/pokémon-shattered-light.527324/" + } + ] + }, { "stem": "Shinju Adventures", "title": "Pokémon Shinju Adventures", @@ -13170,6 +13981,47 @@ } ] }, + { + "stem": "Sienna", + "title": "Pokémon Sienna", + "platform": "GBA", + "base": "FireRed", + "version": "Final", + "status": "Complete", + "generation": "Gen III", + "developer": "Manipulation", + "release_date": "2020", + "source": "https://www.pokecommunity.com/threads/hack-of-the-year-2010-pokémon-sienna-complete-version-released.202372/", + "library_path": "roms/gba/Hacks/Pokemon - Sienna Complete (Hack).gba", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/gba", + "base/firered", + "status/complete", + "type/newexperience" + ], + "summary": "Landmark story-driven FireRed hack in the Voultan region — winner of PokéCommunity Hack of the Year 2010. Branching decisions shape the narrative; travel between regions, hit Focus Punch trees for rare drops, and explore one of the earliest hacks to prioritize player choice over formula.", + "notability": "", + "story": "", + "features": [ + "Voultan region with decision-based storyline", + "Exclusive Pokémon and fakemon; Gen 4+ moves on Gen III engine", + "Focus Punch trees — rare Pokémon and items fall out", + "Travel between multiple regions", + "Custom tiles, music, and realistic city graphics", + "Complete final release (August 2020)" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/hack-of-the-year-2010-pokémon-sienna-complete-version-released.202372/" + } + ] + }, { "stem": "Silver Rival", "title": "Pokémon Silver Rival", @@ -13782,6 +14634,50 @@ } ] }, + { + "stem": "Spades and Clubs", + "title": "Pokémon Spades and Clubs", + "platform": "GBA", + "base": "Emerald", + "version": "0.2.1", + "status": "Beta", + "generation": "Gen III", + "developer": "Capuden", + "release_date": "2025", + "source": "https://senta-storage-system.neocities.org/patchrelease", + "library_path": "roms/gba/Hacks/Pokemon - Spades and Clubs (Hack).gba", + "play_status": "Unplayed", + "type": [ + "New Experience" + ], + "tags": [ + "hack", + "platform/gba", + "base/emerald", + "status/beta", + "type/newexperience" + ], + "summary": "Emerald ROM hack in the Senta region — an island whose Pokémon League disbanded and is now rebuilding. You and a friend from Lotus Town set out as the league reopens, with fakemon and a focus on growing as trainers. Demo covers two gyms.", + "notability": "", + "story": "", + "features": [ + "Senta region — original story and fakemon", + "Demo 0.2.1: progress through 2nd gym badge", + "Evolutions above level 20 locked in current demo", + "League revival premise; uncle Cypress provides starter Pokémon", + "Active development with balance and content updates planned" + ], + "links": [ + { + "label": "Patches / info", + "url": "https://senta-storage-system.neocities.org/patchrelease" + }, + { + "label": "Project site", + "url": "https://senta-storage-system.neocities.org/main" + } + ] + }, { "stem": "Spirit of the Storm", "title": "Pokémon Spirit of the Storm", @@ -14766,6 +15662,49 @@ } ] }, + { + "stem": "Tectonic", + "title": "Pokémon Tectonic", + "platform": "PC", + "base": null, + "version": "3.4.1", + "status": "Ongoing", + "generation": "Gen VIII", + "developer": "Tectonic Team", + "release_date": "2024", + "source": "https://www.tectonic-game.com", + "library_path": "roms/windows/Pokemon - Tectonic 3.4.1 (Hack).zip", + "play_status": "Unplayed", + "type": [ + "Difficulty", + "New Experience" + ], + "tags": [ + "hack", + "platform/pc", + "status/ongoing", + "type/difficulty", + "type/newexperience" + ], + "summary": "Flagship difficulty Essentials fangame set in the Balkans-inspired Makya region. 60+ hours of nonlinear exploration, full species rebalance, custom AI, and a teambuilding sandbox with MasterDex/MoveDex documentation. Gen 8 Pokémon plus Hisuian forms; 20+ Makya regionals and 30+ new evolutions.", + "notability": "", + "story": "", + "features": [ + "Makya region — 60+ hours, nonlinear progression", + "Team Chasm backstory across eight questlines", + "Full competitive rebalance; every species has a niche", + "MasterDex, MoveDex, and in-game Battle Guide", + "Move Mentoring, Style Points, experience overhaul (no grinding)", + "Custom trainer AI; open-source codebase for modders", + "Windows, Linux, and Android builds; Spanish available" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.tectonic-game.com" + } + ] + }, { "stem": "Terra", "title": "Pokémon Terra", @@ -15728,14 +16667,14 @@ { "stem": "Uranium", "title": "Pokémon Uranium", - "platform": null, + "platform": "PC", "base": null, "version": null, - "status": null, + "status": "Complete", "generation": null, "banner": "https://romhacks-files.ginnoir.com/_meta/Pokemon_Uranium/pokemon_uranium_fi-dea83ecc017e53e8.png", "source": "https://mega.nz/file/gh82ST6S#makZr_hsZAcMOIKSEPUwejVJ_N4OW7Mk9wEBlWIoIG0", - "library_path": "—", + "library_path": "roms/windows/Pokemon - Uranium (Hack) [Installer].zip", "play_status": "Unplayed", "scrape_dir": "Pokemon_Uranium", "type": [ @@ -15880,15 +16819,15 @@ { "stem": "Vanguard", "title": "Pokémon Vanguard", - "platform": null, + "platform": "PC", "base": null, "version": null, - "status": "Complete", + "status": "Ongoing", "generation": null, "release_date": "2024", "banner": "https://romhacks-files.ginnoir.com/_meta/Pokemon_Vanguard/Pokemon_Vanguard-cd7de7b420b78d04.png", "source": "https://www.mediafire.com/file/w9gy3qldi29imhk/Vanguard+3.0.12.7z/file", - "library_path": "—", + "library_path": "roms/windows/Pokemon - Vanguard (Hack).zip", "play_status": "Unplayed", "scrape_dir": "Pokemon_Vanguard", "type": [ @@ -15954,6 +16893,49 @@ } ] }, + { + "stem": "Vega Fairy EX", + "title": "Pokémon Vega Fairy EX", + "platform": "GBA", + "base": "FireRed", + "version": "1.4", + "status": "Complete", + "generation": "Gen III", + "developer": "the_teenag_villain", + "release_date": "2022", + "source": "https://www.pokecommunity.com/threads/pokemon-vega-fairy-edition-ex-minus-v1-4-balance-updates-and-skarmory-evo.475538/", + "library_path": "—", + "play_status": "Unplayed", + "type": [ + "New Experience", + "Expansion" + ], + "tags": [ + "hack", + "platform/gba", + "base/firered", + "status/complete", + "type/newexperience", + "type/expansion" + ], + "summary": "Complete Vega re-release with Fairy type integrated from Deneb/Procyon assets. Replaces gym leader Annette with Fairy-type Gwendolyn, adds snow tiles, overhauled sprites, and balance tuned so Fairy isn't overpowered. Requires clean Squirrels FireRed 1.0 to patch.", + "notability": "", + "story": "", + "features": [ + "Full Pokémon Vega campaign with Fairy type and moves", + "Pokémon and lines from Deneb and Procyon; new snow tiles and battle backgrounds", + "Gym 8 reworked — Fairy leader Gwendolyn replaces Annette", + "No National Dex required for trade evolutions", + "Sylveon added; type retunes (e.g. Cheshile Dark/Fairy, Sealkie Water/Fairy)", + "v1.4: Skarmory evolution line, final balance pass" + ], + "links": [ + { + "label": "Source / info", + "url": "https://www.pokecommunity.com/threads/pokemon-vega-fairy-edition-ex-minus-v1-4-balance-updates-and-skarmory-evo.475538/" + } + ] + }, { "stem": "Victory Fire", "title": "Pokémon Victory Fire", @@ -16797,14 +17779,14 @@ { "stem": "Xenoverse", "title": "Pokémon Xenoverse", - "platform": null, + "platform": "PC", "base": null, "version": null, - "status": null, + "status": "Complete", "generation": "Joiplay/RPGXP", "banner": "https://romhacks-files.ginnoir.com/_meta/Pok_mon_Xenoverse/jbowjpcc3j661-2-aa0a8d772f1f68ea.jpg", "source": "https://mega.nz/file/pCBWBaxK#5LZjsYXaMu3CQhX9zz0EkSeTqIeqmyVD39ME8TYZj6U", - "library_path": "/storage1/labdata/romhacks/library/Pok_mon_Xenoverse/", + "library_path": "roms/windows/Pokemon - Xenoverse (Hack).zip", "play_status": "Unplayed", "scrape_dir": "Pok_mon_Xenoverse", "type": [], @@ -17007,7 +17989,7 @@ "platform": "PC", "base": null, "version": "1.1.12", - "status": null, + "status": "Complete", "generation": null, "banner": "https://romhacks-files.ginnoir.com/_meta/Pokemon_bushido/NLihHbc-924807f554fe09e6.gif", "source": "https://www.pokecommunity.com/threads/pokemon-bushido.447182/", @@ -17020,6 +18002,7 @@ "tags": [ "hack", "platform/pc", + "status/complete", "type/expansion", "source/discord" ],