-
Notifications
You must be signed in to change notification settings - Fork 2
Tutorial 03 New Species
Goal. Add a brand-new species that battles, is catchable, appears in the Pokedex, shows a party icon, and plays a cry.
Prerequisites. Tutorials 01–02; Concepts: Data Model; Guide: Art Pipeline.
Files created.
mods/tutorial_03_species/
├── manifest.json
├── main.lua
└── assets/
├── front.png -- your art: 4-shade grayscale, white = transparent
├── back.png
├── icon.png
└── cry.wav
-
Register the full record. A
register(unlikepatch) must carry every required field;modkit validatechecks it against the schema before you ever boot:return function(mod) mod.content.pokemon:register("MODMON", { id = "MODMON", name = "MODMON", dex = 152, types = { "NORMAL" }, baseStats = { hp = 60, attack = 70, defense = 55, speed = 90, special = 65 }, catchRate = 120, baseExp = 100, growthRate = "MEDIUM_FAST", level1Moves = { "TACKLE", "GROWL" }, learnset = { { level = 12, move = "QUICK_ATTACK" }, { level = 20, move = "SLASH" }, }, evolutions = {}, spriteFront = mod.assets:path("assets/front.png"), spriteBack = mod.assets:path("assets/back.png"), frontSize = 5, dexEntry = { kind = "TUTORIAL", heightFt = 2, heightIn = 4, weight = 30.0, text = "Added by a mod.\nIt is very new." }, }) end
Outcome:
modkit validate tutorial_03_speciesconfirms the record — a missing field is a mod-attributed load error, not a runtime crash.growthRatemust name agrowth_ratesrecord (vanilla curves:MEDIUM_FAST,MEDIUM_SLOW,FAST,SLOW,SLIGHTLY_FAST,SLIGHTLY_SLOW). -
A dex number past 151 just works. The Pokedex scales from the merged data (
constants.dexSize/ the highestdex), not a hard-coded 151. Outcome: the dex lists 152 entries and shows yourdexEntrytext. For a sparse or padded dex, setdexSize/dexDigitsexplicitly (Concepts: Data Model). -
Give it a party icon. The
iconsregistry is keyed by species id:mod.content.icons:register("MODMON", { image = mod.assets:path("assets/icon.png"), })
Outcome: the party menu shows your icon instead of the fallback.
-
Give it a cry. A file-based cry def:
mod.content.cries:register("MODMON", { file = mod.assets:path("assets/cry.wav"), })
Outcome: the cry plays on send-out and from the dex screen. (You can also derive from a vanilla cry —
{ base = "PIKACHU", pitch = 200 }— or author a chip cry; see Audio Authoring.) -
Meet it in the wild. Patch an encounter table so you can catch one:
mod.content.encounters:patch("ROUTE_1", { grass = { slots = { __prepend = { { species = "MODMON", level = 5 } } } }, })
Outcome: Route 1 grass rolls MODMON in its top (most common) slot.
Catch a MODMON, save, and reload: the mon survives the save validation pass, because a registered species is a known id. Then disable the mod and reload the same save: the mon moves to the LOST box with a report — and comes home when you re-enable the mod (Concepts: Save Model).
-
Forgetting
frontSize. The battle layout reads it (1–7 tiles); validation requires it for exactly that reason. -
Occupying a taken
dexnumber. Two species on one dex slot fight over the list row; pick the next free number or renumber deliberately. - Skipping the cry. A species with no cry degrades to silence rather than crashing — but add one; the dex and send-out feel broken without it.
- Art format. Sprites are 4-shade grayscale with white as transparency for battle pics; see Art Pipeline before drawing.
Engine 1.0.0 · mod API 2 · repository · Discord
This project ships no ROM data. All game content is decoded on the player's machine from their own verified Pokemon Red ROM; mods ship recipes and original assets, never extracted content.
Start here
Concepts
Tutorials
- The ladder
- 01 Sprite and Text Tweak
- 02 Balance Patch
- 03 New Species
- 04 New Item and Ball
- 05 New Move
- 06 NPC and Dialogue
- 07 New Map
- 08 Quest
- 09 Custom Music
- 10 New Mechanic
- 11 Custom UI Screen
- 12 Mini Total Conversion
Reference
Guides
Playing