feat: replacement effects in Module 4 (Armor absorption, Bolf Ramshield redirect)
Applying a Damage to one target now runs DAMAGE_STEPS = [redirect, armor]
first. A damageRedirect aura (Bolf Ramshield, fetched from the wiki) sends
damage meant for its owner's hero to the oldest such minion; Armor absorbs
damage to a hero before Health, logged as the new ArmorLost{player, amount}
just before a full-amount Damaged. Four new Module 4 tests; propagated to the
references of Modules 4-10 in both tracks; card schema, catalog, card JSON,
harness.md, Lessons 2, 4 and 5 updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
97c64ebee8
commit
372c99c306
113 files changed
+1925
-231
No files matched your search
@@ -1,4 +1,5 @@
|
||||
// Auras, and the one routine that applies trigger multipliers.
|
||||
// Auras, the one routine that applies trigger multipliers, and the lookup for
|
||||
// damage redirects.
|
||||
//
|
||||
// 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
|
||||
@@ -12,17 +13,26 @@
|
||||
// Summoning a minion also runs an Aura Update.
|
||||
|
||||
import type { TriggerOn } from "./card";
|
||||
import type { PlayerId, World } from "./world";
|
||||
import type { EntityId, 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 })),
|
||||
world.card(world.cardName(id)).auras.map((aura) => ({ owner: world.ownerOf(id), source: id, aura })),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The minion that takes damage meant for `player`'s hero, if a redirect is in force:
|
||||
* the oldest (order of play) of `player`'s minions with a `damageRedirect` aura in the
|
||||
* snapshot. The snapshot lists minions oldest first, so that is the first one found.
|
||||
*/
|
||||
export function redirectFor(world: World, player: PlayerId): EntityId | undefined {
|
||||
return world.activeAuras().find((a) => a.aura.type === "damageRedirect" && a.owner === player)?.source;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -32,9 +42,10 @@ export function auraUpdateOther(world: World): void {
|
||||
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;
|
||||
for (const { owner: auraOwner, aura } of world.activeAuras()) {
|
||||
if (aura.type !== "triggerMultiplier") continue;
|
||||
const { trigger, times, stacking } = aura;
|
||||
if (auraOwner !== owner || trigger !== on) continue;
|
||||
if (stacking === "max") max = Math.max(max, times);
|
||||
else extra += times - 1;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user