-
Notifications
You must be signed in to change notification settings - Fork 2
Tutorial 10 New Mechanic
Goal. Add a new status condition and a new damage type with chart rows, then scale difficulty through a battle hook — deep engine changes without forking a file.
Prerequisites. Tutorials 05 and 09; Concepts: Events and Hooks.
Files created.
mods/tutorial_10_mechanic/
├── manifest.json
└── main.lua
-
Register a status. Statuses are records the battle engine, catch math, and HUD all read from one registry — vanilla's SLP/PSN/BRN/FRZ/ PAR are engine registrations in it (
src/battle/Status.lua):return function(mod) mod.content.statuses:register("CURSE", { label = "CURSE", hudLabel = "CRS", -- end-of-turn tick, like PSN/BRN: damage the mon, return the text residual = function(battler, opponent, battle) local mon = battler.mon mon.hp = math.max(0, mon.hp - math.max(1, math.floor(mon.stats.hp / 16))) return { ("%s's\nhurt by the curse!"):format(battler.name) } end, onInflict = function(_, _, _, display) return { ("%s\nwas cursed!"):format(display) } end, catchBonus = 12, -- the status term of the catch roll cureOnSwitch = true, }) end
Record fields (
src/battle/Status.luadocuments the consumers):label(required),hudLabel(the HUD glyph text),canInflict(target)/onInflict(battle, target, opts, display),beforeMove(+beforeMovePriority),residual(battler, opponent, battle) -> messages,catchBonus/shakeBonus(catch math),statPenalty({ stat, div }, like PAR's speed or BRN's attack),cureOnSwitch. Outcome: the record validates. -
Inflict it from a move effect. Reuse tutorial 05's pattern:
mod.content.move_effects:register("CURSE_EFFECT", { kind = "secondary", run = function(ctx) ctx.inflict(ctx.target, "CURSE") end, }) mod.content.moves:register("MODCURSE", { id = "MODCURSE", name = "MODCURSE", type = "GHOST", category = "status", power = 0, accuracy = 100, pp = 10, effect = "CURSE_EFFECT", })
Outcome: MODCURSE inflicts CURSE; the HUD shows
CRS, residual damage ticks each turn,battle.status_inflictedfires, and the catch roll counts the bonus — every consumer reads the one record. -
Add a type and its chart rows. The
type_chartregistry holds both forms under one roof: bare type ids and"ATTACKER>DEFENDER"matchup rows.mod.content.type_chart:register("FAIRY", { category = "special" }) mod.content.type_chart:register("FAIRY>DRAGON", { multiplier = 20 }) mod.content.type_chart:register("FAIRY>FIRE", { multiplier = 5 }) mod.content.type_chart:register("DRAGON>FAIRY", { multiplier = 0 })
multiplieris base 10 (20 = super effective, 5 = not very, 0 = immune). The per-typecategorydrives the physical/special split for moves that do not state their own. Mind the one odd vanilla id: the psychic type isPSYCHIC_TYPE. Outcome: a FAIRY-typed move hits Dragonite super-effectively, with the standard effectiveness text. -
A difficulty scaler through the damage hook.
mod.hooks:wrap("battle.damage", function(next, ctx) local dmg, info = next(ctx) if not ctx.user.isPlayer then dmg = math.max(1, math.floor(dmg * 12 / 10)) end return dmg, info end)
Outcome: enemy damage lands 20% harder, applied after every vanilla modifier because the wrapper post-processes
next's result. The link is pcall-guarded: throw from it and the chain logs, skips you, and the battle continues.
CURSE ticks residual damage over several turns and clears on switch-out; a FAIRY move on a DRAGON target reports super-effective and doubles damage; enemy hits are scaled with the mod on and vanilla with it off.
-
Forgetting
hudLabel. The status works but the HUD has nothing to draw for it; always name the glyph text. -
Assuming a new type has a category. State
categoryon the type (or on each move); an unknown type must not fall through the vanilla physical/special type list. -
A hook that throws taking down the chain. It does not — the
failing link is skipped and logged. Try it:
error("boom")in the wrapper and watch the battle proceed with an attributed log line.
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