Sable Cove (Mini Conversion)
The smallest thing that is recognizably a different game: its own title screen, its own starting town, its own three-species dex, its own single badge — running on the same engine, with the same import.
Persona: the Total-Conversion Team. This is the capstone skeleton. It is deliberately incomplete as a game and deliberately complete as a demonstration of which seams a conversion owns.
Legal callout (read this first)
A total conversion on this engine is a recipe, not a redistribution.
- The Red import still runs. It supplies the fallback infrastructure this
conversion sits on: the
OVERWORLDtileset, the font, the move table, the type chart. That data lives on the player's machine, decoded from the player's own ROM. - The conversion overrides on top. Everything under
assets/here is original work, plotted pixel by pixel bytools/make_assets.py— run it yourself and diff the output. - It never ships extracted content, and it never launders extracted
content into "new" species by transforming Red sprites. If your
conversion wants to derive art from the player's cache, that is what
assets_transformsis for — seemods/examples/example_shiny_palette/for the worked pattern.
Try it
python3 tools/modkit.py validate mods/examples/example_mini_conversion --base imported
python3 tools/modkit.py lint mods/examples/example_mini_conversion
luajit mods/examples/example_mini_conversion/tests/example_mini_conversion_test.lua
# regenerate the original art from its shape tables
python3 mods/examples/example_mini_conversion/tools/make_assets.py
Enable it (example_mini_conversion = true under mods in options.lua,
or the F10 manager) and start the game. You land on the SABLE COVE title
screen; NEW GAME spawns you in Sable Cove with 1500 money as SABLE.
What it demonstrates
| Seam | Where |
|---|---|
profile = "total_conversion" |
manifest.json — implies affects_link |
content.field:patch("boot", …) |
main.lua — spawn, names, money, boot screens |
content.constants:patch / :override |
main.lua — dex size, level cap, badge list |
content.pokemon:register |
main.lua — three species with full records |
content.cries:register (ChipAsm) |
main.lua — one authored effect per species |
content.icons:register |
main.lua — party icons keyed by species id |
content.maps:register |
main.lua — one map on the imported tileset |
content.encounters:register |
main.lua — its wild table |
content.items:register |
main.lua — the badge, which is an item |
content.screens:register |
main.lua — the title screen the boot config names |
events:on("game.ready") |
main.lua — checking the boot merge actually took |
patch vs override on a deep registry
constants and field are deep registries. Two rules differ from the
record registries, and both bite a conversion:
registerandpatchare the same verb. A partial payload is the normal case; only the keys you name move.- Lists append. That is deliberate — two mods each adding a badge both land. But a conversion wants to replace the badge list, and appending would leave Kanto's eight in front of its one:
mod.content.constants:patch("badges", { … }) -- 8 + 1 = 9 badges
mod.content.constants:override("badges", { … }) -- 1 badge
override is the verb that drops a list. The test asserts both behaviors.
field.boot is the opposite case: patch is right there, because the keys
this conversion does not name (startFacing, the splash and newGame
screen ids) should keep the engine's values.
Priority
"priority": 900. A conversion wants to merge after content mods so its
field.boot and constants win. If another mod still beats it, the
game.ready listener says so by name instead of leaving the player on a
map they did not expect.
What a real conversion adds next
This skeleton stops at the boundary of the mechanism demonstration. A shipping conversion continues with:
map_scriptsfor the story (seemods/examples/example_lost_parcel/)maps:remove/pokemon:removetombstones to hide Kanto contentcontent.textandtext_pointersfor its own dialoguecontent.musicfor its soundtrack (seemods/examples/example_jukebox/)link_fieldsand an honestaffects_linkso its players do not corrupt each other's saves in a trade
Credits
- All original sprite art: this project (
tools/make_assets.py). - pret/pokered: the
OVERWORLDtileset, font and move table this builds on.