Skip to content

Reference Hooks

bryanthaboi edited this page Jul 19, 2026 · 1 revision

Hook reference

Every hook the engine calls, with the arguments a wrapper receives after next, what it must return, and the call site. Read from the Runtime.call sites in src/. Wrap with mod.hooks:wrap(name, function(next, ...) ... end, priority); see Concepts: Events and Hooks for chain order and error isolation.

A wrapper's contract: call next(...) at most once, return the same shape the vanilla function returns. next() with no arguments forwards the current arguments unchanged.

Battle

Hook Wrapper receives (after next) Returns Call site
battle.accuracy ctx = { battle, ruleset, move, user, target, rng } true on hit src/battle/BattleState.lua (accuracyRoll)
battle.damage ctx = { battle, ruleset, user, target, move, opts, rng } damage, { crit, typeMult } src/battle/BattleState.lua (computeDamage)
battle.crit ctx = { ruleset, attacker, moveId, rng, highCrit } true on crit src/battle/Damage.lua
battle.turn_order playerBattler, playerMove, enemyBattler, enemyMove, ctx = { rng, invertTie? } true when the player moves first src/battle/BattleState.lua; also src/link/LinkBattle.lua (must stay deterministic across peers)
battle.enemy_action battle the enemy action src/battle/BattleState.lua (enemyAction — the whole AI choke point)
battle.run ctx = { battle, pSpd, eSpd, attempts, rng } true on escape src/battle/BattleState.lua (runRoll)
catch.rate ball, mon, def, opts = { rng, rateOverride, battle } caught, shakes src/battle/BattleState.lua (catchAttempt)
trainer.party trainerClass, partyIndex, party the party list ({ { species, level }, ... }) src/battle/BattleState.lua (trainer battle setup)
exp.gain ctx = { defeatedDef, level, isTrainer, participants, traded, mon } the exp number src/battle/Experience.lua

Example — a global difficulty scaler:

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

Progression and encounters

Hook Wrapper receives Returns Call site
evolution.check game, mon, evo, trigger true when the evolution fires src/pokemon/Evolution.lua (pendingFor)
encounter.roll encDef, ctx = { mapId, terrain, rng } an encounter ({ species, level }) or nil src/world/OverworldController.lua (rollEncounter)
encounter.species enc, ctx the (possibly rewritten) encounter src/world/OverworldController.lua (after a non-nil roll, before repel filtering)
encounter.fishing rod, mapId, candidates an encounter or nil src/world/OverworldController.lua (goFishing)

World

Hook Wrapper receives Returns Call site
movement.collision allowed, ctx = { map, mover, dir, fromX, fromY, toX, toY, reason } boolean; may rewrite ctx.reason src/world/Collision.lua (canMove)
warp.destination destMap, x, y, ctx = { warp, lastMap, data } destMap, x, y src/world/Warp.lua (destination)
map.palette name, map a palette name src/world/OverworldController.lua

Presentation and audio

Hook Wrapper receives Returns Call site
music.select song, ctx = { reason, mapId, mapSong, onBike, surfing, kind, battleKind, trainerId } a song id src/core/Music.lua (selectSong — every song choice passes through)
transition.style ctx = { trainer, stronger, dungeon, game } a transitions registry id src/render/BattleTransition.lua (an unknown style falls back to vanilla)
render.zones game, zones the zones list src/core/Game.lua (palette-zone pass before the blit)

Scripts, saves, UI, link

Hook Wrapper receives Returns Call site
script.command ctx, name, args the command's jump result (nil, a label, "end") src/script/ScriptRunner.lua (every script row)
save.new_game save the save table src/core/SaveData.lua (New Game skeleton)
ui.start_menu.items game, items the items list src/ui/StartMenu.lua
ui.party.submenu game, items, mon, ctx = { battle, overworld } the items list src/ui/PartyMenu.lua
ui.options.rows game, rows the rows list src/ui/OptionsMenu.lua
ui.pc.items game, items the items list src/world/OverworldController.lua (the PC menu)
link.fingerprint data, mods the digest string src/link/Fingerprint.lua (compute)

The four ui.* list hooks type-check the result: return anything but a table and the vanilla list is kept with a logged error. Insert with the mod.ui helpers rather than raw table.insert when position matters:

mod.hooks:wrap("ui.start_menu.items", function(next, game, items)
  mod.ui.insertBefore(items, "QUIT", {
    label = "QUESTS",
    onSelect = function() mod.ui.push(game, "QuestLog") end,
  })
  return next(game, items)
end)

Entries are { label, onSelect }; anchors are stable labels ("POKéDEX", "OPTION", "QUIT", ...), and a missing anchor appends.

Clone this wiki locally