Skip to content

Tutorial 02 Balance Patch

bryanthaboi edited this page Jul 19, 2026 · 1 revision

Tutorial 02 — Balance patch

Goal. Rebalance a move, a species' stats, and a boss party in one mod, gated behind a mod option the manager renders automatically.

Prerequisites. Tutorial 01; Concepts: Registries (the three merge semantics).

Files created.

mods/tutorial_02_balance/
├── manifest.json
└── main.lua

Steps

  1. Scaffold as in tutorial 01, then patch a move in main.lua:

    return function(mod)
      mod.content.moves:patch("TACKLE", { power = 50, accuracy = 100 })
    end

    patch deep-merges a partial record — every field you do not name keeps its vanilla value. Outcome: Tackle hits noticeably harder in the first rival fight.

  2. Patch a stat sub-table.

    mod.content.pokemon:patch("PIDGEY", { baseStats = { speed = 71 } })

    The baseStats sub-table merges — hp, attack, defense, and special stay vanilla. This is why patch exists: the old copy-every-field idiom silently dropped whatever you forgot. Outcome: wild Pidgey outspeed your starter.

  3. Rewrite a boss party.

    mod.content.trainers:patch("OPP_BROCK", {
      parties = { { { species = "ONIX", level = 14 },
                    { species = "GEODUDE", level = 12 } } },
    })

    parties is a list of parties, each a list of { species, level } slots. Arrays replace wholesale in a record registry — element-wise merging of a party is ambiguous — so state the whole party. Outcome: Brock leads Onix.

  4. Gate it behind an option.

    return function(mod)
      mod.options:define({
        { key = "hard_mode", type = "toggle", label = "HARD MODE", default = true },
      })
      if mod.options:get("hard_mode") then
        mod.content.moves:patch("TACKLE", { power = 50, accuracy = 100 })
        mod.content.pokemon:patch("PIDGEY", { baseStats = { speed = 71 } })
        mod.content.trainers:patch("OPP_BROCK", {
          parties = { { { species = "ONIX", level = 14 },
                        { species = "GEODUDE", level = 12 } } },
        })
      end
    end

    Outcome: the mod's entry in the manager grows a HARD MODE toggle. Content is merged at boot, so toggling it takes effect on the next launch.

Checkpoint

With the option on, Tackle deals more damage than vanilla; with it off (or the mod disabled), damage is vanilla to the point. modkit validate tutorial_02_balance stays green.

Common pitfalls

  • Expecting an array field to deep-merge. Lists replace; to extend instead, wrap: { learnset = { __append = { { level = 20, move = "FLY" } } } } (Concepts: Registries).
  • Typos in stat names. baseStats = { spd = 71 } is rejected under api = 2 — nested records are strict, and near-miss keys get a did you mean suggestion.
  • Two mods patching the same record. Patches stack in load order (priority ascending, ties by id). If your rebalance must land after another mod's, raise your manifest priority or declare a dependency.

Next: Tutorial 03 — New Species.

Clone this wiki locally