Skip to content

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
api.registerUserHelper('ringOfFire.has', hasRingOfFire);
api.registerUserHelper('rotary.launcherLid', 'npc-rebake_npcf_rotary_grenade_launcher_bastion');

api.helpers.ringOfFire.has(parent, api);
api.helpers.rotary.launcherLid;

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.

api.registerDefaultItemReactions({
    "mw_my_weapon": {
        category: "System",
        itemType: "mech_weapon",
        reactions: [{
            name: "My Reaction",
            triggers: ["onActivation"],
            activationType: "code",
            activationCode: async (triggerType, data, reactor, item, activationName, api) => { }
        }]
    }
});

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:

api.recordMovementExtra(reactorToken, api.tokenSpeed(reactorToken), { leg: 'boost' });

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>


await api.createAura(owner, auraConfig)

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>


await api.ensureAura(owner, auraConfig)

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
await api.ensureAura(token, { name: 'Suppression', radius: 3 });
deleteAuras async → Promise<void>


await api.deleteAuras(owner, filter, options)

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.

await api.deleteAuras(token, 'Suppression');
toggleAura async → boolean | null


await api.toggleAura(actorOrToken, auraName, on?)

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:

await api.toggleAura(token, "Bulwark");
await api.toggleAura(token, "Bulwark", true);
await api.toggleAura(token, "Bulwark", false);

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
await api.createAura(token, api.scaleAuraStroke({ name: 'Suppression', radius: 3, lineWidth: 3 }));

Sequencer Presets

Requires Sequencer. Used through Sequencer's .preset(), not through api.

la_scaleToBurst → EffectSection


.preset("la_scaleToBurst", burst, source)

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
new Sequence()
    .effect()
        .file("jb2a.lava_spout.001.001.complete.orangeyellow")
        .atLocation(token)
        .preset("la_scaleToBurst", 1)
    .play();