Skip to content

Cookbook Battle And Mechanics

bryanthaboi edited this page Jul 19, 2026 · 1 revision

Cookbook — battle and mechanics

Hook contracts: Reference: Hooks; worked path: Tutorial 10.

R19 — Add a custom AI brain

mod.content.trainers:patch("OPP_BROCK", {
  brain = function(battle)
    -- always pick the enemy's first usable move
    for _, mv in ipairs(battle.enemy.curMoves) do
      if mv.pp > 0 then return mv end
    end
  end,
})

Checkpoint: Brock picks moves your way; a nil return falls back to Struggle handling. A brain supersedes the class action and move scoring entirely (src/battle/BattleState.lua vanillaEnemyAction). Reusable brains live in the ai_classes registry (kind = "brain"), named from a trainer's aiClass; the battle.enemy_action hook intercepts every trainer at once.

R27 — React to a battle event

mod.events:on("battle.move_used", function(ev)
  mod.log:info("%s used %s", ev.user.name, ev.move.name)
end)

Checkpoint: a log line per move. The full battle event set — battle.started, battle.turn_started/turn_ended, battle.damage_dealt, battle.fainted, pokemon.caught, ... — is in Reference: Events.

R28 — Wrap the damage hook

mod.hooks:wrap("battle.damage", function(next, ctx)
  local dmg, info = next(ctx)
  if not ctx.user.isPlayer then dmg = math.floor(dmg * 12 / 10) end
  return dmg, info
end)

Checkpoint: enemy hits land 20% harder; with the mod disabled the chain is empty and numbers are vanilla. Return both values — the second is { crit, typeMult }.

R29 — Add a status condition

mod.content.statuses:register("CURSE", {
  label = "CURSE", hudLabel = "CRS",
  residual = function(battler)
    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,
  catchBonus = 12, cureOnSwitch = true,
})

Checkpoint: a move effect calling ctx.inflict(ctx.target, "CURSE") ticks residual damage each turn and shows CRS on the HUD. One record feeds the HUD, the catch math, and the turn loop (src/battle/Status.lua).

R30 — Add a type + chart row

mod.content.type_chart:register("FAIRY", { category = "special" })
mod.content.type_chart:register("FAIRY>DRAGON", { multiplier = 20 })

Checkpoint: FAIRY hits Dragons super-effectively. multiplier is base 10; bare ids are types (mind PSYCHIC_TYPE), "A>B" ids are matchup rows — one registry holds both.

Clone this wiki locally