Files
systemic-game-design-course/course/05-assemble/reference/ts/src/engine/aura.ts
T
Lucas WintherandClaude Opus 5.5 e04dc1a11f feat: module 05 assemble
Cards become JSON data in course/cards (one file per card, validated
against card.schema.json and the catalog); the M5 references load them
via registerCards and interpret effects, replacing content closures.
Adds assemble(base, donor, half), the assemble/buffHand effects with an
injected chooser, Fleshshape as the data-only Expansion Drop, and stages
course/cards in verify-references and start-module.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 03:17:21 +01:00

43 lines
1.8 KiB
TypeScript

// 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;
}