Courage.Hooks#
require("Courage.Hooks") has helpers for common Twilight Princess hook patterns.
Actor and function names are on the Actors and Functions tabs of the TP Ultimate Spreadsheet. Match symbols on Game Hooks before you hook.
Hooks.readStageName(stageArg)#
Reads a stage name (up to 16 characters) from a hook argument that may be a Luau string or a NativePtr / light userdata.
Augment.Hook.readCString is the same helper on the Hook module.
Hooks.trackStageName(mod, opts?)#
Registers daAlink_c::checkStageName and returns { get, set, reset }.
Hooks.overrideItemGrant(mod, remapFn, opts?)#
Hooks the standard fopAcM_createItem* helpers. remapFn(itemId, ctx) returns a replacement item id or nil to leave vanilla.
Hooks.overrideItemGrant(self, function(itemId, ctx)
if itemId == 0x42 then return 0x99 end
return nil
end, {
symbols = {
"fopAcM_createItem",
"fopAcM_createItemForPresentDemo",
"fopAcM_createItemForDirectGet",
"fopAcM_createItemForSimpleDemo",
"fopAcM_createItemForTrBoxDemo",
"fopAcM_createItemFromTable",
}
})
import * as Hooks from "Courage.Hooks"
Hooks.overrideItemGrant(this, (itemId, ctx) => {
if (itemId === 0x42) return 0x99
return undefined
}, {
symbols: [
"fopAcM_createItem",
"fopAcM_createItemForPresentDemo",
"fopAcM_createItemForDirectGet",
"fopAcM_createItemForSimpleDemo",
"fopAcM_createItemForTrBoxDemo",
"fopAcM_createItemFromTable",
]
})
Hooks.remapSetNextStage(mod, opts)#
Hooks dComIfGp_setNextStage. Requires opts.lookup(stageName, point, room, layer) returning { stageName, point, room, layer } or nil.
mod is unused. It is there to match the other Courage.Hooks helpers.
| Option | Description |
|---|---|
skipStages | Map of stage names to skip (default: title screen F_SP108) |
clearOoccooMode | When true, maps Ooccoo lastMode 0xC to 0 |
onRemap | Optional (ctx, dest) callback before args are written |
import * as Hooks from "Courage.Hooks"
Hooks.remapSetNextStage(this, {
lookup: (stage, point, room, layer) => {
const dest = mySeed.lookup(stage, point, room, layer)
if (!dest) return undefined
return {
stageName: dest.stage,
point: dest.spawn,
room: dest.room,
layer: dest.layer,
}
},
clearOoccooMode: true,
})
Process ID and View helpers#
Hooks.procId(name)#
Converts a process name string ("E_RD" or "PROC_E_RD") into its numeric process ID. Returns nil if unknown.
Hooks.procName(id)#
Converts a numeric process ID back into its process name string ("PROC_E_RD").
Hooks.wrap(structName, ptr)#
Wraps an arbitrary native pointer ptr with an Augment struct view proxy for structName.
Hooks.actorView(ptr)#
Convenience alias for Hooks.wrap("fopAc_ac_c", ptr).
Hooks.actorProc(ptr)#
Reads the process profile ID (profname) directly from an actor pointer ptr.
Event and Actor Lifecycle Hooks#
Hooks.onActorCreate(mod, fn, opts?)#
Registers a callback fn(ptr, proc) that fires when an actor finishes creation (fpcBs_SubCreate). ptr is the raw native actor pointer (lightuserdata), and proc is the numeric process ID. opts.procs can filter by process names or IDs.
Hooks.onActorDelete(mod, fn, opts?)#
Registers a callback fn(ptr, proc, captured) that fires after an actor is deleted. captured holds data returned by opts.capture = function(view, proc) if defined before the memory is freed.
Hooks.onEnemyDamaged(mod, fn, opts?)#
Hooks cc_at_check and calls fn(hit) whenever an enemy takes damage. hit contains:
enemy: Struct view proxy of the enemy actorenemyPtr: Raw native pointer of the enemy actorproc: Enemy process IDattacker: Struct view proxy of the attacking actor (if any)attackerPtr: Raw native pointer of the attacking actorattackerProc: Attacker process IDdamage: Amount of damage dealtkilled: Boolean indicating whether this hit was lethal
Hooks.onEnemyKilled(mod, fn, opts?)#
Calls fn(hit) exactly once when an enemy is killed. Uses the same hit structure as onEnemyDamaged and deduplicates multiple death hits.
Hooks.onPlayerDamaged(mod, fn)#
Hooks daAlink_c_setDamagePoint before Link takes damage. fn(amount, ctx) can return a new damage number or false to cancel damage entirely.
Storage and Save File Tracking#
Hooks.saveSlotStorage()#
Returns a Petrichor.Storage wrapper that automatically prefixes storage keys with slot<N>:, keeping mod data isolated between save slots.
Hooks.trackSaveFile(mod, opts?)#
Polls the active save slot and calls opts.onChange(slot, prevSlot) whenever the loaded save slot changes.