No active sessions yet.

No games yet.

No conversations yet.

No characters yet.

Hooks

The moments a rule can attach to, and what each one carries.

A hook is a rule that runs when the engine does something anywhere in the world. An item rule, by contrast, runs when a player uses one specific object.

A hook has a trigger, an optional condition, and a body.

Triggers

Trigger Fires when $.event carries
onSpawnCreature a creature enters the world
onSpawnItem an item enters the world; the item is the subject
onDamage hit points actually drop, from any source amount killed
onHeal hit points actually rise amount
onDeath someone dies (players too), after loot and XP
onCombatStart a fight begins; subject is the location
onCombatRoundEnd a combat round closes; subject is the location
onEffectApplied an effect lands on someone
onAttack every swing, misses included weapon weaponKey ranged ammo attacking
onLocationEnter the party arrives; subject is the new location
onMapEdge the party reaches a dead end, every exit already visited exits
onItemUse an item rule runs
onRoll a skill check resolves; observe-only passed total dc margin crit botch stat note abilityName reason
onTurnStart once per actor per turn
onTurnEnd once per actor per turn inCombat
onTimePasses in-game time moves: a turn, travel, sleep minutes resting
onTravel the party covers ground distance
onBeforeAction a player tries something, before it happens attack ranged combatAction swings stat note actionOrdinal

A hook can also answer another plugin's event, written pluginId:eventKey, like rest:sleep. See Cooperation.

Picking one

  • Trying vs hurting. onAttack fires on every swing. onDamage fires only when hit points move. Stamina per swing goes on the first; bleeding goes on the second.
  • Per turn vs per minute. For anything that ticks per character per turn, use onTurnEnd. onTimePasses minutes can be the narrator's guess; see Minutes are not time.
  • The creature vs its gear. A hook writes to its subject. onSpawnCreature writes to the bandit; onSpawnItem writes to the bandit's sword. A rolled modifier or a curse on an object goes on the second.
  • Round vs turn. A turn is one actor; a round is everybody. Things that last "a round", like a brace or a mark, expire on onCombatRoundEnd.
  • Swinging vs swung at. A plugin's onAttack hook runs once per swing, about the target. A character's, creature's or effect's own hook runs for whichever side it's on, and $.event.attacking says which: true when they swung, false when they were swung at.
  • weapon vs weaponKey. weapon is the item's name. weaponKey is that exact object. Wear and tear goes on the key, or it lands on the spare in the pack instead of the blade in hand.
  • ammo is the ammunition the swing spent, such as Arrow, and empty when it spent none. $.spawnItem({ itemExpr: $.event.ammo, at: "self" }) drops the loosed arrow where the target stands.

onBeforeAction says no

It's the trigger for refusing. A refuse in it stops the action and says why.

if ($.event.attack && $.field('stamina') < 5) {
  $.refuse('their arms are too heavy to lift the blade again')
}

$.event.actionOrdinal is which action this is in the turn (0 for the first), so $.event.actionOrdinal > 0 limits a turn to one action.

onRoll only watches

An onRoll hook can write fields and nothing else. If a hook could change the roll, the roll card couldn't explain its own number.

It's how you make something improve with use:

if ($.event.passed && $.event.margin > 5 && $.event.note === 'read') {
  $.adjustField({ field: 'insight', by: 1 })
}

margin is total minus DC, negative on a failure. crit and botch read the natural die, which is a different question from passed.

Example: a fever, in three hooks

onTimePasses: it climbs.

if ($.field('fever') > 0) {
  $.adjustField({ field: 'fever', by: $.timed
    ? ($.event.minutes / 60) * $.dial('feverPerHour')
    : $.dial('feverPerTurn') })
}

onTurnEnd: a high fever hurts.

if ($.field('fever') >= 10) {
  $.damage({ amount: 1 })
}

onBeforeAction: too sick to fight.

if ($.event.attack && $.field('fever') >= 15) {
  $.refuse('the fever has taken their balance; the blade will not answer')
}

Next

Conditions: gating when a hook may run.