Skip to content

Latest commit

 

History

History
131 lines (111 loc) · 8.48 KB

modding.md

File metadata and controls

131 lines (111 loc) · 8.48 KB

Modding

The game's content is data: the levels, their rooms and themes, the level-select pages, the actor categories (the vehicle and boss stages), the bosses' rewards, the music, the cutscenes, the credits, the text in its six languages and the graphics. A plain make builds whatever data the tree has, and make compare checks that the original data still gives the original ROM byte for byte. A mod is other data: it needs no code change and no baserom.gba.

The sample mod

mods/sample/ is a small mod that uses most of what is moddable, and the worked example for this page. It adds a fifth world (a fifth level-select page) after Neo Cortex's:

what where it comes from the doc
a new song, sample_tune, played by a new level theme and by the new cutscene an XM the mod writes (16-row patterns; a new instrument with its own synthesized sample, and a pool instrument) audio.md, "Adding a song"
a new theme, THEME_SAMPLE jungle's picture and colour cycle, the new song levels.md, "Adding a theme"
a new room, sample_grove/main (room 41) jungle jam's room under its own symbols, one 8x8 block repainted (a new tile) levels.md, "Adding a room"
a recoloured actor category, CATEGORY_SAMPLE_ICE snow crash's polar stage with its own OBJ palette and BG palette cycle levels.md, "Category graphics"
three numbered levels, "sample grove", "sample slope", "sample sewer" the new room, the new category's stage, just in slime's room levels.md, "Adding a world"
a boss level, "sample showdown" Dingodile's room, "boss_kind": "DINGODILE" (the boss HUD) and an "on_clear" that plays the new cutscene and marks it cleared levels.md, "Boss levels"
a partial level-select page and its number icons 21-23 world 4 of "worlds", opened when world 3's levels are cleared; new frames of sprite bank 51 levels.md, "Partial pages", graphics.md, "New frames"
the 64 Kbit save 29 levels, past the 4 Kbit save's 28 levels.md, "The save"
a new cutscene, CUTSCENE_SAMPLE_CLEARED a picture the mod draws, a page of text data.md, "A new cutscene"
the levels' names and the cutscene's text in the six languages entries of games/xs/text/crashxs.pot and the five .po files text.md, "A new level's name"

Every asset is generated by the mod or derived from the tree's own data (the palettes are the ROM's recoloured), so it carries no copied art and no copyrighted music.

Trying it

make mod MOD=mods/sample

applies the mod to a copy of the tree in build/mods/sample (tools/apply_mod.py, whose code is crashdata.mods) and builds it there with a plain make. The modded ROM is build/mods/sample/crashbandicootxs.gba (16 MB: the new data goes past the original's 8 MB). Your own tree is not changed. In the modded tree,

make text-check
python3 tools/gfx_manifest.py check
python3 mods/sample/boottest.py

check the translations and the graphics manifest, and play the ROM in headless mGBA (mgba, its SDL frontend, on PATH: 0.10.5, which CI builds from source; see tools/boottest.py, buildtools.boottest): the new room and its song, the category's palettes on the screen, the fifth page and its boss entry, the boss HUD, the cutscene after the boss and the 8 KiB save. CI (.github/workflows/mods.yml) does all of this on every PR, so a change that breaks modding fails there even when make compare passes.

In the game, the fifth page opens once the levels of the four ROM worlds are cleared; the boot test pokes that progress into the save instead of playing it.

Writing a mod

A mod is a folder with a mod.py and, optionally, a files/ folder:

  • files/ is copied over the tree, at the same paths: new files, or replacements of the tree's. XS's data is under games/xs/ (files/games/xs/graphics/..., files/games/xs/data/levels/...) and the code under engine/ (files/engine/src/...), as in the tree (#1167, file_layout.md);
  • the paths mod.py gives the helpers (tree.path(...), tree.json(...)) are the tree's too: games/xs/sound/gax_manifest.json, engine/src/game/...;
  • mod.py defines apply(tree), which edits the copy's data with the helpers of crashdata.mods.Tree (tools/apply_mod.py's): tree.levels() and tree.json(path) edit a JSON file, tree.add_graphics(...) adds games/xs/graphics/manifest.json entries, tree.copy_room(...) copies a room under new symbols, tree.add_level_name(...) and tree.add_cutscene_text(...) add text in the six languages, tree.run(...) runs a tool. mod.py runs with the copy's tools/ on sys.path, so it can import a tool by its old name (import jasc_pal, which is crashdata.common.jasc_pal, as the sample does) or the packages themselves (from crashdata.common import jasc_pal; file_layout.md, "The Python packages").

tools/apply_mod.py MOD DEST applies it to a new copy at DEST, and make mod MOD=<folder> does that and builds it. make data-check MOD=<folder> applies it and checks the copy's data without building: every file against its JSON Schema, then the checks the build makes (editors.md, "Checking the data"). To work on the data directly instead, edit the tree itself, following the docs above, and run make; make compare then fails, as it should. The editor (make editor, editors.md) edits a mod's tree (build/mods/<name>) the same way: new, resized and deleted rooms, drawn tiles, new collision values, a room's kind and blend; applying the mod again makes the tree anew, so what is kept goes into mod.py.

What a mod can change

area moddable the doc
levels rooms (pictures, collision, entities), the level table, themes and their colour cycles, level-select pages and what opens them, names levels.md
vehicle and boss stages actor categories: spawn lists, numbers, cell animation, sky, OBJ palette, palette cycle, sprite sheet, animation table levels.md, "Actor categories"
bosses which boss a level has ("boss_kind") and what clearing a level does ("on_clear") levels.md, "Boss levels"
the save grows with the levels (64 Kbit past 28), versioned by a hash of the level data levels.md, "The save"
text every string, in six languages; the credits text.md
cutscenes slides, pictures, timing, music, text data.md, "Cutscenes"
music new songs from XM files, on the ROM's instruments or new ones (an XM's own samples, or WAVs); new sound effects with their own samples; which song plays where; the music editor plays them and edits the tables, the songs' cells and the samples audio.md, editors.md, "The music editor"
graphics the graphics of the manifest, new ones, sprite banks and frames, palettes graphics.md

What a mod can't do yet

These are code, or not built yet:

  • Editors. The level, cutscene and music editors (make editor, editors.md) edit a mod's tree (build/mods/<name>, as make mod makes it) as they edit the game's: the sample mod's sample_tune plays in the music editor, its own instrument too. What they don't do yet is in each editor's "Not yet"; for the music, an XM is still written in a tracker (the editor edits its cells, and plays them as GAX2 will), and a ROM instrument's envelope or loop is the manifest's (the "Data files" tab).
  • New behaviour. A new actor kind, boss kind, power, category type or entity type is code: the data reaches what the existing kinds draw and where they spawn, not what they do (levels.md, "Category sprite sheets" and "Boss levels").
  • New sprite frames outside bank 51's animation 0. Other banks need their C to take new frames (graphics.md, "New frames").
  • More than 60 levels, the 64 Kbit save's largest record.
  • N-Tranced. The modding pipeline is Crash Bandicoot XS's; N-Tranced's data isn't decompiled yet (n_tranced.md).