API - Registration, How-Tos & Auras¶
Back to API Reference · Feature guide: Automation Engine
Registration & Logic¶
User Helpers¶
registerUserHelper
getUserHelper → Function | null
api.registerUserHelper(name, value) // register a shared function or constant
api.getUserHelper(name) // retrieve it by name
api.helpers // the same entries as a tree, a dotted name nests
Shares logic and constants between activation scripts. Re-register on every load: the startup file runs at ready.
| Param | Type | Description |
|---|---|---|
| name | string |
Unique name. a.b lands at api.helpers.a.b |
| value | any |
Function or constant |
Registration Functions¶
registerDefaultItemReactions → void
registerDefaultGeneralReactions → void
api.registerDefaultItemReactions(reactions) // object mapping item LIDs to activation groups
api.registerDefaultGeneralReactions(reactions) // object mapping names to groups or single entries
Item reactions only fire for tokens carrying that LID. General reactions fire for every token.
Item entries must be groups, { reactions: [ ... ] }. The engine reads entry.reactions without a guard,
so a bare activation object throws. General entries may be flat.
How-To: Register Activations¶
Hooks.on('lancer-automations.ready', (api) => {
api.registerDefaultGeneralReactions({
"Custom Reaction": {
triggers: ["onDamage"],
evaluate: (triggerType, data, reactor, item, name, api) => data.target?.id === reactor.id,
activationCode: async (triggerType, data, reactor, item, name, api) => {
// ... logic
}
}
});
});
How-To: Fire a Custom Trigger¶
api.registerDefaultGeneralReactions({
"Supply Drop Pickup": {
triggers: ["onSupplyDrop"],
triggerSelf: true,
triggerOther: false,
activationType: "code",
activationCode: async (triggerType, data, reactor, item, name, api) => {
ui.notifications.info(`${reactor.name} recovered ${data.crate?.name ?? "the crate"}`);
}
}
});
api.dispatchCustomTrigger("onSupplyDrop", { triggeringToken: token, crate: crateToken });
data becomes triggerData. Reference: Custom Triggers.
How-To: Advanced Consumption¶
Shared Shield Charges:
await api.applyEffectsToTokens({
tokens: [target],
effectNames: ["resistance_kinetic", "resistance_energy"]
}, {
stack: 3,
consumption: {
trigger: "onDamage",
originId: target.id,
grouped: true
}
});
How-To: Bonus on One Action's Check¶
The bonus only ever applies to one check, so a cancelled roll leaves nothing behind. A stat roll is built on an actor and carries no item of its own, so stamp the action that caused it, then gate the bonus on that stamp.
Stamp the roll:
await api.openHaseContestCard({
tokenA: reactorToken,
skillA: "SYS",
tokenB: targetToken,
skillB: "AGI",
title: "SEARCH - SYSTEMS vs AGILITY",
sourceAction: "Search"
});
Gate the bonus on it:
onInit: async function (token, item, api) {
await api.ensureLinkedBonus({
items: [item],
bonusData: {
id: `perceptive-${item.id}`,
name: "Perceptive",
type: "accuracy",
val: 1,
rollTypes: ["stat_roll"],
condition: (state) => state?.la_extraData?.sourceAction === "Search"
},
addOptions: { duration: 'constant' }
});
}
executeContestedCheck and openHaseContestCard take sourceItem / sourceAction in their options.
executeStatRoll takes sourceItemUuid / sourceAction inside its extraData argument instead. Either way
both surface on onInitCheck / onCheck as item / actionName.
How-To: Per-Target Accuracy¶
applyToCondition gates each target and re-runs when the HUD's targets change or move.
onInit: async function (token, item, api) {
await api.ensureLinkedBonus({
items: [item],
bonusData: {
id: `handshake-etiquette-${item.id}`,
name: "Handshake Etiquette",
type: "accuracy",
val: 1,
rollTypes: ["attack"],
applyToCondition: (target, state, reactorToken) => {
const api = game.modules.get('lancer-automations')?.api;
return api.isHostile(reactorToken, target)
&& api.getTokenDistance(reactorToken, target) <= 3;
}
},
addOptions: { duration: 'constant' }
});
}
How-To: Extra Movement¶
Two shapes, and picking the wrong one leaks. A standing bonus lengthens every move of that kind for as long as it exists:
await api.addConstantBonus(actor, {
id: `nerveweave-${item.id}`,
name: "Nerveweave",
type: "movement_extra",
subtype: "boost",
val: 2
});
A one-shot binds to a single move, so boosting twice does not repeat it:
leg is 'standard', 'boost' or 'current', and defaults to 'current', the granted leg the spent distance
sits in. 'boost' lands on the Boost already taken this turn, or waits for the next one if none has been. Both
feed the ruler bands and the movement cap, so the yellow band and the cap move together.
Grid-Aware Auras Wrapper¶
Requires the Grid-Aware Auras module (or my fork).
createAura async → Promise<any>
Wrapper accepts a JS function in place of a macro ID. LaSossis GAA fork: stored as an inline-code macro. Stock GAA: libWrapper intercept, libWrapper required.
| Param | Type | Description |
|---|---|---|
| owner | Token\|TokenDocument\|Item |
The document that owns the aura. An Item owner ties the aura to the item's lifetime |
| auraConfig | Object |
Full Grid-Aware Auras configuration object |
| macros[].function | (token, parent, aura, options) => any |
Saved as source text |
| macros[].scope | Record<string, any> |
Outside names the function uses. Functions by source, values as JSON |
Rules for function:
- api inside it is this module's api.
- Nothing else from the defining file exists. Register it with registerUserHelper and read api.helpers.*, pass it in scope, or write it inside.
- api.helpers: live lookup, a fix reaches placed auras. scope: a copy frozen into that aura.
- A placed aura keeps its code until recreated.
Whenever an owning actor and token can be resolved, the wrapper deep-merges a default config underneath yours, so
a five-line call still comes out looking like the module's own auras. The defaults: one unified aura named
lancer-automations-aura, an animated dashed stroke (lineType: 2, width 2, 5/5 dashes), a fillType: 2 fill at
fillOpacity: 0.15 with the templatemacro hatching texture when that module is installed, owner visibility on,
and non-owner visibility on only when the owner's disposition is FRIENDLY. fillColor comes from token-factions,
or failing that the actor's folder color, and only while the owner still has a reaction available. Otherwise it
stays white. Any key you pass wins over its default.
macros Function Example:
macros: [{
mode: "ENTER_LEAVE",
function: (token, parent, aura, options) => {
if (options.hasEntered) console.log(`${token.name} entered the aura!`);
}
}]
Available Trigger Modes
| Category | Modes |
|---|---|
| Macro | ENTER_LEAVE, ENTER, LEAVE, PREVIEW_ENTER_LEAVE, PREVIEW_ENTER, PREVIEW_LEAVE, OWNER_TURN_START_END, OWNER_TURN_START, OWNER_TURN_END, TARGET_TURN_START_END, TARGET_TURN_START, TARGET_TURN_END, ROUND_START_END, ROUND_START, ROUND_END, TARGET_START_MOVE, TARGET_END_MOVE |
| Effect | APPLY_WHILE_INSIDE, APPLY_ON_ENTER, APPLY_ON_LEAVE, APPLY_ON_OWNER_TURN_START, APPLY_ON_OWNER_TURN_END, APPLY_ON_TARGET_TURN_START, APPLY_ON_TARGET_TURN_END, APPLY_ON_ROUND_START, APPLY_ON_ROUND_END, REMOVE_WHILE_INSIDE, REMOVE_ON_ENTER, REMOVE_ON_LEAVE, REMOVE_ON_OWNER_TURN_START, REMOVE_ON_OWNER_TURN_END, REMOVE_ON_TARGET_TURN_START, REMOVE_ON_TARGET_TURN_END, REMOVE_ON_ROUND_START, REMOVE_ON_ROUND_END |
await api.createAura(reactorToken, {
name: 'Suppression',
radius: 3,
lineWidth: 3,
lineColor: '#ffd600',
lineOpacity: 0.9
});
await api.createAura(droneToken, {
name: 'Restock Drone Zone',
radius: 1,
macros: [{
mode: 'ENTER',
scope: { healAmount, isRebake },
function: async (token, parent, aura, options) => {
if (!api.isFriendly(token, parent))
return;
await api.updateTokenSystem(token, { 'system.hp.value': token.actor.system.hp.value + healAmount });
}
}]
});
ensureAura async → Promise<any | null>
createAura that no-ops when the owner already has an aura with that name, returning null instead of a second copy. The onInit way to add an aura: safe to run on every init without a hand-written guard.
| Param | Type | Description |
|---|---|---|
| owner | Token\|TokenDocument\|Item |
The document that owns the aura |
| auraConfig | Object |
Same shape as createAura. name is required |
deleteAuras async → Promise<void>
Deletes the owner's auras and their function callbacks.
| Param | Type | Default | Description |
|---|---|---|---|
| owner | Token\|TokenDocument\|Item |
required | The document that owns the auras |
| filter | string\|Object |
required | String ID, name, or Object filter |
| options | Object |
see below | Internal Grid-Aware Auras delete options |
A non-Item owner defaults to { includeItems: true }, so the sweep also removes auras owned by that actor's items. An Item owner defaults to {}. Anything you pass overrides the default.
toggleAura async → boolean | null
Flips or sets the enabled flag in the actor's grid-aware-auras.auras flag. Does not create or delete the aura.
| Param | Type | Default | Description |
|---|---|---|---|
| actorOrToken | Actor\|Token\|TokenDocument |
required | Owner of the aura |
| auraName | string |
required | Name of the aura to toggle |
| on | boolean |
undefined |
true forces enable, false forces disable. Omit to flip the current state. |
Returns the new enabled state (true/false), or null if no aura with that name exists on the actor.
Only the actor flag is read, so an aura created with an Item owner is invisible here and always returns null. Delete and recreate those instead.
Examples:
gridScale → number
scaleAuraStroke → object
api.gridScale() // scene grid size relative to a 100 px baseline
api.scaleAuraStroke(aura) // scales the config's stroke fields in place, returns it
Aura widths are in pixels, so a config authored on a 100 px grid draws too thin on a larger one. scaleAuraStroke multiplies lineWidth, lineDashSize, lineGapSize and fillTextureScale by gridScale(), with a floor of 1.
| Param | Type | Description |
|---|---|---|
| aura | Object |
Aura config. Mutated, and returned for chaining |
Sequencer Presets¶
Requires Sequencer. Used through Sequencer's .preset(), not through api.
la_scaleToBurst → EffectSection
Sizes an effect to a Burst around its source, in grid units: size * 2 * (burst + 1). size is the actor's Lancer size (system.stats.size on deployables). .atLocation() must come first.
| Param | Type | Default | Description |
|---|---|---|---|
| burst | number |
1 |
Burst value. 0 is the token itself |
| source | Token\|TokenDocument\|Actor |
null |
Only for atLocation(..., { cacheLocation: true }), where the section's source is unreadable |