// Auras, and the one routine that applies trigger multipliers. // // An aura is data on a card: a continuous effect its minion has while in play. // The engine never asks "is that card on the board?" in the middle of resolving // something. It takes a snapshot of the auras in force at defined points (an Aura // Update) and every rule reads the snapshot. // // Hearthstone runs two kinds of Aura Update when the outermost Phase ends: one for // Health/Attack auras before the Death Creation Step, and one for every other aura // after it. Trigger multipliers are "Other" auras, so a minion that dies in a Death // Creation Step no longer multiplies the Deathrattles of that step's Death Phase. // Summoning a minion also runs an Aura Update. import type { TriggerOn } from "./card"; import type { PlayerId, World } from "./world"; /** Aura Update (Other): replace the snapshot with the auras of every minion now in play. */ export function auraUpdateOther(world: World): void { world.setActiveAuras( world.minionsInPlay().flatMap((id) => world.card(world.cardName(id)).auras.map((aura) => ({ owner: world.ownerOf(id), aura })), ), ); } /** * How many times a trigger listening for `on`, on a minion `owner` controls, activates * when it resolves. Reads the snapshot from the last Aura Update. With no multiplier in * force the answer is 1. Multipliers with `stacking: "max"` contribute their largest * `times`; each `"additive"` one adds `times - 1` extra activations. */ export function activations(world: World, owner: PlayerId, on: TriggerOn): number { let max = 1; let extra = 0; for (const active of world.activeAuras()) { const { trigger, times, stacking } = active.aura; if (active.owner !== owner || trigger !== on) continue; if (stacking === "max") max = Math.max(max, times); else extra += times - 1; } return max + extra; }