Skip to content

API - Combat & Weapons

Back to API Reference · Feature guide: Gameplay Automation

Every flow function here returns { completed: false } and does nothing when its Lancer flow class is missing or the input is invalid. Check completed before chaining on a result.


Attacks

attackWith async → Promise<{ completed: boolean; flow?: any; reloaded?: boolean }>
attackRollWith async → Promise<{ completed: boolean; flow?: any }>
hitWith async → Promise<{ completed: boolean; flow?: any }>
damageWith async → Promise<{ completed: boolean; flow?: any }>


await api.attackWith(weapon, targets?, { reloadIfEmpty?, fxSourceToken? })   // target + start the weapon attack flow
await api.attackRollWith(weapon, targets?, { fxSourceToken?, title? })       // repeat the weapon's attack roll only
await api.hitWith(weapon, targets, damageOptions?)                           // declare a hit: onHit trigger + the weapon's damage flow
await api.damageWith(weapon, targets?, damageOptions?)                       // the weapon's damage flow alone

Params: reloadIfEmpty boolean (default false) · fxSourceToken Token (default null) · title string card title override

attackWith sets the given tokens as targets then starts the weapon's attack flow. reloadIfEmpty: true reloads instead and returns { reloaded: true } when the weapon is unloaded. fxSourceToken plays the lancer-weapon-fx effect from that token instead of the attacker (the roll stays the attacker's) - reflected shots, turrets, drones.

attackRollWith repeats the weapon's attack roll as a basic attack with the weapon's stats (tier-resolved for NPC features) and carries its damage/tags to the damage roll, but skips the weapon-fire mechanics: no loading gate, no self-heat, no item updates. Rebound pattern.

The chain is attack > hit > damage: attackWith runs all three stages, hitWith the last two (fires onHit with the upcoming damage flow as its flowState, then rolls the weapon's damage), damageWith the last one. damageOptions override the damage flow data and take the same keys as executeDamageRoll's options (defaults: the weapon's tier-resolved damage and tags).

getTier → number
tierValue → any


api.getTier(tokenOrActor)                                     // → 1-3
api.tierValue(tokenOrActor, [t1, t2, t3])                     // → value for the actor's tier

Params: tokenOrActor Token|Actor · values [any, any, any] per-tier values

tierValue(reactorToken, [4, 6, 8]) replaces tier ladders and clamped index picks.

afterFlow → boolean


api.afterFlow(triggerData, callback)                          // run callback after the trigger's flow completes

Params: triggerData the trigger's data object · callback (flow, success) => any

afterFlow runs the callback once the trigger's flow completes or aborts, after its card printed - one-shot, matched to that exact flow. Use it for anything that must not interleave with the flow (follow-up attacks, moves).

executeBasicAttack async → {completed, flow}


await api.executeBasicAttack(actor, options, extraData)

Starts a BasicAttackFlow.

Param Type Default Description
actor Actor required The actor making the attack
extraData Object {} Injected into state.la_extraData
inside options
targets Token\|Token[] null Who is attacked. Avoids touching setTarget
tags Array undefined Weapon tags carried onto the attack card
damage Array undefined Damage list carried onto the card, so its damage button rolls pre-filled
fxSourceToken Token null Play the lancer-weapon-fx effect from this token instead of the attacker
fxItem Item null Item whose FX the flow should use
item Item null Roots the flow on this item, so it uses the item's stats and triggers see it as weapon. Forces non-tech classification

Those six are consumed here. Any other key is forwarded to the BasicAttackFlow constructor.

await api.executeBasicAttack(actor, {
    targets: targetToken,
    damage: [{ type: 'Energy', val: '1d6' }]
});
executeTechAttack async → {completed, flow}


await api.executeTechAttack(target, options, extraData)
Param Type Default Description
target Actor\|Item required The actor or item initiating the tech attack
extraData Object {} Injected state data
inside options
targets Token\|Token[] null Who is attacked
damage Array undefined Damage list carried onto the attack card

Any other key is forwarded to the flow constructor.

await api.executeTechAttack(actor, { targets: [target] });
executeSkirmish async → void


await api.executeSkirmish(actorOrToken, bypassMount, preTarget, weaponFilter, options)
Param Type Default Description
actorOrToken Actor\|Token\|TokenDocument required The actor or token performing the skirmish
bypassMount Object null Mount object to skip mount selection
preTarget Token null Pre-selected target token
weaponFilter (weapon: Item) => boolean null Filter for available weapons
options Object {} noFX: true skips the skirmish FX
await api.executeSkirmish(token, null, targetToken);
executeBarrage async → void


await api.executeBarrage(actorOrToken, bypassMount, preTarget)

Runs a Barrage: attacks with either two different mounts or one superheavy mount. Prompts for the mounts unless bypassMount supplies them.

Param Type Default Description
actorOrToken Actor\|Token\|TokenDocument required The acting entity
bypassMount Object\|Array null Mounts to use, skipping selection
preTarget Token null Pre-targeted before each attack flow
await api.executeBarrage(token, null, targetToken);
executeInvade async → Promise<void>


await api.executeInvade(actorOrToken, bypassChoice)

Prompts for one of the actor's invade options, then fires the tech attack flow.

Params: actorOrToken Actor|Token · bypassChoice Object optional preselected invade option, skips the picker

await api.executeInvade(token);
beginWeaponAttackFlow async → {completed, flow?}


await api.beginWeaponAttackFlow(weapon, options, extraData)
Param Type Default Description
weapon Item required The weapon item to attack with
extraData Object {} Injected state data
inside options
targets Token\|Token[] null Who is attacked

Any other key is forwarded to the flow constructor.

Pass targets rather than calling setTarget yourself.

await api.beginWeaponAttackFlow(weapon, { targets: [target] });
executeDamageRoll async → {completed, flow}


await api.executeDamageRoll(attacker, targets, damageValue, damageType, title, options, extraData)
Param Type Default Description
attacker Token\|Actor required The attacker
targets Array<Token> required Damage targets
damageValue number\|string null Base damage
damageType string null kinetic, energy, explosive, burn, heat, infection, variable. Case-insensitive, and anything unrecognized silently becomes Kinetic
title string "Damage Roll" Roll title
options Object {} Flow options (see below)
extraData Object {} Injected state data

options keys (all merged onto the DamageRollFlow's flow data, not its state. extraData is what goes to state.la_extraData):

Key Type Default Meaning
ap boolean false Armor Piercing.
paracausal boolean false Damage can't be reduced (bypasses armor and resistances).
overkill boolean false Overkill - the flow rerolls 1s on the damage dice (self-heat per reroll).
reliable boolean false Reliable.
half_damage boolean false Halve all damage dealt.
add_burn boolean true Whether Burn-type damage also accumulates on the target's burn track.
invade boolean false Flags the roll as an Invade tech-attack (passed to Lancer flow).
has_normal_hit boolean true At least one normal (non-crit) hit exists -> rolls normal damage.
has_crit_hit boolean false At least one crit exists -> rolls crit damage.
tags Array [] Weapon tags that shape the roll (Overkill/Reliable/AP...). Element: { lid, val?, name?, description? }.
bonus_damage Array [] Extra damage entries added to the roll. Element: { type, val } where type is a DamageType ("Kinetic"/"Energy"/"Explosive"/"Heat"/"Burn"/"Variable") and val a formula string.
hit_results Array [] Per-target hit outcomes that decide which targets take damage (chained damage rolls carry these instead of user targets). Element: { target: Token, total: string, hit: boolean, crit: boolean, usedLockOn?: boolean }.
targeting Object - See below.

options.targeting { range?: number, pattern?: "target"|"blast"|"cone"|"line"|"burst", size?: number } - opens the damage HUD with the targeting picker already engaged on that shape. Without it, the picker auto-engages only on weaponless rolls that start with no target.

await api.executeDamageRoll(reactorToken, [target], 2, 'Heat', 'Ring of Fire');

Checks & Saves

executeStatRoll async → {completed, total, roll, passed}


await api.executeStatRoll(actor, stat, title, target, extraData)
Param Type Default Description
actor Actor required The actor making the roll
stat string required "HULL", "AGI", "SYS", "ENG", "GRIT"
title string auto Roll title
target number\|"token"\|Token\|TokenDocument 10 Pass threshold or "token" for interactive choice
extraData Object {} { targetStat: "HULL" } reads that HASE stat off the target as the DC. sourceItemUuid / sourceAction attribute the roll, surfacing as item / actionName on onInitCheck and onCheck. sendToOwner routes the roll to the owning player, cardTitle / cardDescription set the card text. Every other key is merged into state.la_extraData

extraData.accuracy / extraData.difficulty / extraData.flatModifier pre-fill the HASE HUD, the way a weapon's tags pre-fill an attack. They are added to whatever the HUD already computed and stay editable by the roller. No bonus needed for a one-off +1 Difficulty.

passed is total >= target. A number target is that number. A token target is the aggressor and resolves at roll time to its SAVE, falling back to 10. extraData.targetStat reads a HASE stat off it instead. If the flow does not complete, only { completed: false } comes back.

await api.executeStatRoll(actor, 'SYS', 'Blind', witchToken, { difficulty: 1 });
executeSaveVsEffect async → Array<{ target, passed, result }>


await api.executeSaveVsEffect(targets, options)

Save-or-effect over a target list: each target rolls the save (owner-routed by default, in parallel), failures get effects and/or onFail, passes get onPass.

Param Type Default Description
targets Token\|Token[] required Rollers
inside options
stat string required "HULL" / "AGI" / "SYS" / "ENG" / "GRIT"
title string required Roll title
origin number\|Token 10 DC, or the token forcing the save (its SAVE is the DC)
effects string\|Object\|Array null Applied on fail (applyEffectsToTokens shape)
duration Object { label: 'indefinite' } Forwarded to the effect application
note string title Note on the applied effects. Falls back to title
extraFlags Object {} Identity flags stamped on the applied effects
cardTitle / cardDescription string \| ((target: Token) => string) null Owner card text. Description can be per target
sendToOwner boolean true Route each roll to its owner
onFail / onPass (target: Token, result: { passed: boolean, total: number }) => void \| Promise<void> null Per-target extras
accuracy / difficulty / flatModifier number \| ((target: Token) => number) 0 Pre-fill each roller's HASE HUD. Pass a function for a per-target value
halfDamageOnSave { value, type?, title? } null Afterwards roll this damage on ALL targets, halved for the ones that saved. Requires a Token origin

halfDamageOnSave uses origin as the attacker of the follow-up damage roll. A numeric origin (including the default 10) leaves no attacker, so the damage roll is skipped with a warning. Pass the source token when you use it.

await api.executeSaveVsEffect(targets, {
    stat: 'SYS', title: 'Blind', origin: witchToken, effects: ['blinded'],
    difficulty: (target) => api.inDangerZone(target) ? 1 : 0,
});
executeContestedCheck async → { completed, winner, loser, winnerToken, loserToken, tie, results }


const res = await api.executeContestedCheck(input1, stat1, input2, stat2, options)
Param Type Default Description
input1 Actor\|Token required First contender
stat1 string required "HULL" / "AGI" / "SYS" / "ENG" / "GRIT"
input2 Actor\|Token required Second contender
stat2 string required Second contender's stat
inside options
title string "Contested Check" Card header
sendToOwner boolean true Roll on each contender's owner client
accuracy1 / accuracy2 number 0 Accuracy dice pre-filled on that side's HASE HUD
difficulty1 / difficulty2 number 0 Difficulty dice pre-filled on that side's HASE HUD
flatModifier1 / flatModifier2 number 0 Flat modifier pre-filled on that side's HASE HUD
sourceItem Item\|string null Item the check belongs to, surfaced as item on onInitCheck / onCheck
sourceAction string null Action the check belongs to, surfaced as actionName
extraData object null Extra keys merged into both rolls' la_extraData

Rolls both stats, posts an outcome card, plays the win/loss FX. winner/loser (and their *Token) are null on a tie. results always holds both { actor, stat, total, roll }. When either roll does not complete, the result is { completed: false } with winner, loser and tie set but no winnerToken/loserToken keys at all. This is what openHaseContestCard returns.

const res = await api.executeContestedCheck(tokenA, 'HULL', tokenB, 'AGI', { title: 'Grapple', difficulty2: 1 });
if (!res.tie && res.winnerToken === tokenA)
    ui.notifications.info(`${tokenA.name} wins the grapple`);
executeForceCheck async → { completed, results }


const res = await api.executeForceCheck(skill, targets, options)
Param Type Default Description
skill string required "HULL" / "AGI" / "SYS" / "ENG"
targets Token[] user targets The tokens that roll
inside options
saveVs Token\|Actor null Makes it a save vs that actor's SAVE, pre-targeted in the roller's HUD
sendToOwner boolean true Roll on each target's owner client
title string "" Card header
accuracy / difficulty / flatModifier number\|(rollerToken) => number 0 Pre-filled on the roller's HASE HUD. Per-roller when given a function

Sends each target its HASE check (owner rolls, or the GM if unowned), then posts a PASS/FAIL summary. Returned by openForceCheckCard.

await api.executeForceCheck('ENG', [target], { saveVs: witchToken, title: 'Petrify' });

Activations & Actions

executeItemActivation async → {completed, flow?}


await api.executeItemActivation(item, options, extraData)

Runs an item's activation flow. The item's own automation fires. activateGeneralAction is the equivalent for registry actions that belong to no item.

The flow class is picked in this order: flowName if given, then CoreActiveFlow for a frame with path: "system.core_system", then TalentFlow or ActivationFlow for a talent, then BondPowerFlow for a bond, then ActivationFlow if there is a path or the item has any actions (system.actions.0 when no path is given), then SystemFlow for a mech system, weapon mod, or non-weapon NPC feature, then WeaponAttackFlow for a weapon. If none match it errors and returns { completed: false }. This is close to triggerData.startRelatedFlow but not the same: that one tries weapons before actions, prefers a Reaction action over actions.0, has no CoreActiveFlow branch, and falls back to a simple activation card instead of erroring.

Param Type Default Description
item Item required The item to activate
extraData Object {} Merged onto flow.state.la_extraData before the flow begins
inside options
path string null Sets action_path, to pick one action on a multi-action item. On a talent, ranks[N] for the rank card or ranks[N].actions[M] for its action. On a bond, powers[N]
flowName string null Forces a specific flow class instead of the dispatched one
const { completed } = await api.executeItemActivation(item, {}, { fromReaction: true });
executeSimpleActivation async → {completed, flow}


await api.executeSimpleActivation(actor, options, extraData)
Param Type Default Description
actor Actor\|Token required Acting actor, or a token to take the actor from
options { title?: string, action?: { name, activation }, detail?: string, tags?: Array } {} Card fields
extraData Object {} Injected state data. An item here roots the flow on that item instead of the actor
await api.executeSimpleActivation(actor, {
    title: 'Vent Coolant',
    action: { name: 'Vent', activation: 'Quick' },
    detail: 'Clear 2 heat.'
});
activateGeneralAction async → {completed, flow}


await api.activateGeneralAction(actorOrToken, name)

Params: actorOrToken Actor|Token · name string registry action name

Triggers a general action (Brace, Boost, ...) from its registry definition: activation type and card text come from the registry, and the action's automation fires. For an item's action use executeItemActivation.

await api.activateGeneralAction(reactorToken, 'Brace');
executeExtraActionCombat async → {completed, flow}


await api.executeExtraActionCombat(actorOrToken, action, sourceItem?, options?)

Fires an extra action's combat mode: action.laCombat === 'attack' rolls a to-hit (tech attack when activation is Invade/Quick Tech/Full Tech, else a basic attack with a full acc_diff from its weapon tags + accuracy/difficulty/attack_bonus/attack_type). 'damage' rolls action.damage with no to-hit. See the ExtraAction shape in HUD API.

Param Type Default Description
actorOrToken Actor\|Token required The attacker
action ExtraAction required The extra action (must have laCombat)
sourceItem Item\|null null Owning item, if any (tech attacks route through it)
inside options
targets Token[] user targets Who is attacked, instead of the user's current targets
fxSourceToken Token null Play the FX from this token. Basic-attack branch only
fxItem Item null Item whose FX to use. Basic-attack branch only
await api.executeExtraActionCombat(actor, {
    name: 'Turret Shot',
    activation: 'Quick',
    laCombat: 'attack',
    attack_bonus: 2,
    damage: [{ type: 'Kinetic', val: '1d3' }]
});
afterFx → void


api.afterFx(callback)

Runs callback at flow end, right after lancer-weapon-fx starts its sequence (or immediately at flow end if there is no FX). Use in trigger code whose printed cards should land after the FX.

The queue only drains on the flows lancer-weapon-fx binds: WeaponAttackFlow, BasicAttackFlow, TechAttackFlow, ActivationFlow, SystemFlow, CoreActiveFlow, OverchargeFlow, FullRepairFlow, StructureFlow, SecondaryStructureFlow, OverheatFlow, CascadeFlow. Stat rolls and damage rolls are deliberately excluded, since automations nest them inside an outer flow. A callback queued from one of those runs when the outer flow ends, not when the roll does.

api.afterFx(() => api.executeDamageRoll(reactorToken, targets, 4, 'Heat', 'Tear Down'));

Meltdown & Rest

executeReactorMeltdown async → Promise<void>
executeReactorExplosion async → Promise<void>


await api.executeReactorMeltdown(tokenOrActor, turns)
await api.executeReactorExplosion(token)

executeReactorMeltdown starts the meltdown countdown, and turns skips the turn-picker dialog. executeReactorExplosion runs the explosion itself: a Burst 2 catch-confirm picker around the token, then the damage.

Params: tokenOrActor Token|Actor · turns number countdown length · token Token the exploding mech

await api.executeReactorMeltdown(token, 2);
executeRest async → Promise<void>
executeDowntime async → Promise<void>
openAddReserveDialog async → Promise<void>


await api.executeRest(token)
await api.executeDowntime()
await api.openAddReserveDialog(tokenOrActor)

The out-of-combat flows, same as their TAH entries: the Rest card, the downtime activity builder, and the add-a-reserve dialog. Feature guide: Gameplay Automation.

Params: token Token the resting mech, or a pilot token with an active mech · tokenOrActor Token|Actor the pilot's mech

await api.executeRest(token);

Weapon & Item Details

Processed weapon/item info, with active actor bonuses applied (e.g. Accuracy, Threat).

getItemTags_WithBonus async → Array<Object>


await api.getItemTags_WithBonus(item, actor)

Effective tag list for one item.

Param Type Default Description
item Item required The item to inspect
actor Actor item.parent The actor whose bonuses should be applied
const tags = await api.getItemTags_WithBonus(weapon);
const isSmart = tags.some(t => t.lid === 'tg_smart');
getActorMaxThreat → number


api.getActorMaxThreat(actor)

Returns the highest Threat range across all weapons held by the actor, accounting for active bonuses. Floored at 1, so a ranged-only actor still reads 1. It is 0 only for a deployable, or an actor with no weapons at all.

Param Type Description
actor Actor The actor to inspect
if (api.getTokenDistance(reactorToken, moverToken) <= api.getActorMaxThreat(reactorToken.actor))
    return true;
getMaxWeaponRanges_WithBonus → Record<string, number>


api.getMaxWeaponRanges_WithBonus(input)

Max range value per range type, across every weapon in the input.

Param Type Description
input Actor\|Token\|Item\|Array The source(s) to scan for weapons
const ranges = api.getMaxWeaponRanges_WithBonus(actor);
const threat = ranges.Threat ?? 1;
getMaxWeaponReach_WithBonus async → number


await api.getMaxWeaponReach_WithBonus(input)

Returns the single highest reach value across all scanned weapons. Scans Range, Threat, Line, Burst, and Cone (ignores Blast). Also accounts for the tg_thrown tag.

Param Type Description
input Actor\|Token\|Item\|Array The source(s) to scan for weapons
const reach = await api.getMaxWeaponReach_WithBonus(reactorToken);
getMaxItemRanges_WithBonus async → Object


await api.getMaxItemRanges_WithBonus(item, actor)

Single item's max range per type, with bonuses, e.g. { Range: 10, Thrown: 5, Deploy: 8 }. Also folds in action ranges, tg_thrown (Thrown) and deployRange (Deploy).

Params: item Item · actor Actor (optional, defaults to item.parent).

const ranges = await api.getMaxItemRanges_WithBonus(item);
const throwRange = ranges.Thrown ?? 0;
getWeaponProfiles_WithBonus → Array<Object>


api.getWeaponProfiles_WithBonus(weapon, actor)[weapon.system.selected_profile_index ?? 0].range

All profiles with bonuses merged into range/damage (base_range/base_damage keep the originals).

Params: weapon Item · actor Actor (optional, defaults to weapon.parent).

const profile = api.getWeaponProfiles_WithBonus(weapon)[weapon.system.selected_profile_index ?? 0];
getSensorRange_WithBonus → number


api.getSensorRange_WithBonus(actor)

Actor's effective sensor range (system.sensor_range, else 10), plus any Sensor range-type bonuses.

Params: actor Actor|Token.

const inSensors = api.getTokenDistance(reactorToken, target) <= api.getSensorRange_WithBonus(reactorToken);
hasTag async → boolean


await api.hasTag(item, 'smart')

Params: item Item · tagLid string tag LID · actor Actor (optional, defaults to item.parent) whose bonuses apply

True if the item has the tag (bonus-aware). Accepts the LID with or without tg_, so 'smart' and 'tg_smart' both work.

if (!await api.hasTag(weapon, 'smart')) return false;

Simple lookups

Function Returns Description
getWeaponType(item) string Weapon subtype (e.g. "Superheavy Rifle", "Melee"). Synchronous, no bonuses.
getItemType(item) string Lancer item type (e.g. "Weapon", "System", "mech_weapon").
getActivationIcon(actionOrActivation) string\|null Icon path or CSS class, null when nothing matches. Accepts "reaction", "quick", "full", "protocol", "free", "invade" or an action object. An action with tech_attack: true (or a "tech" activation) gets the tech icons, and an action whose name contains "grenade" gets the grenade icon.