Release Healer Man 0.1.45

This commit is contained in:
phenom committed 2026-09-15 14:43:15 -04:00
1 parent 756ee4f64a
commit f82daf1c13
242 files changed
+1440 -101

No files matched your search

+96
View File
@@ -161,4 +161,100 @@ describe("enemy casting and interrupts", () => {
engaged: false,
});
});
it("resolves composite drains as damage, healing, control, and one impact cue", () => {
const deathCoil: EnemyAttackDefinition = {
...spell("death-coil", "shadow", 0),
effect: {
kind: "composite",
effects: [
{ kind: "leech", damageMultiplier: 1, healMultiplier: 1 },
{ kind: "control", mechanic: "fear", durationMs: 4_000 },
],
},
};
registerCaster([deathCoil]);
useCombatStore.getState().damageMob("caster", 400, 999);
const bossHealth = useCombatStore.getState().mobs.caster.health;
const playerHealth = useCombatStore.getState().health;
const events: CombatPresentationEvent[] = [];
const unsubscribe = subscribeCombatPresentation((message) => {
if (message.kind === "event" && message.event.sourceActorId === "caster") {
events.push(message.event);
}
});
expect(useCombatStore.getState().advanceMobCombat(1_000)).toBeGreaterThan(0);
expect(useCombatStore.getState().health).toBeLessThan(playerHealth);
expect(useCombatStore.getState().mobs.caster.health).toBeGreaterThan(bossHealth);
expect(useCombatStore.getState()).toMatchObject({
controlMechanic: "fear",
controlledUntil: 5_000,
});
expect(events.map((event) => event.phase)).toEqual(["release", "impact"]);
unsubscribe();
});
it("anchors defensive aura indicators on the caster and applies their gameplay payload", () => {
const barrier: EnemyAttackDefinition = {
...spell("shock-barrier", "arcane", 0),
delivery: "area",
target: "self",
range: 0,
effect: {
kind: "aura",
aura: "shock-barrier",
durationMs: 10_000,
absorbMultiplier: 2.5,
reflectSpellChance: 0.5,
},
};
registerCaster([barrier]);
const events: CombatPresentationEvent[] = [];
const unsubscribe = subscribeCombatPresentation((message) => {
if (message.kind === "event" && message.event.sourceActorId === "caster") {
events.push(message.event);
}
});
useCombatStore.getState().advanceMobCombat(1_000);
expect(useCombatStore.getState().mobs.caster.auras).toContainEqual(expect.objectContaining({
id: "shock-barrier",
endsAt: 11_000,
}));
expect(useCombatStore.getState().auras).toContainEqual(expect.objectContaining({
targetId: "caster",
definition: expect.objectContaining({
reflectSpellChance: 0.5,
absorbs: [expect.objectContaining({ id: "shock-barrier:absorb" })],
}),
}));
expect(events.map((event) => [event.phase, event.targetActorId])).toEqual([
["release", "caster"],
["aura-start", "caster"],
]);
unsubscribe();
});
it("resolves teleport-to-caster effects as forced movement with an impact cue", () => {
const summonPlayer: EnemyAttackDefinition = {
...spell("summon-player", "arcane", 0),
effect: { kind: "pull", destination: "source" },
};
registerCaster([summonPlayer]);
const events: CombatPresentationEvent[] = [];
const unsubscribe = subscribeCombatPresentation((message) => {
if (message.kind === "event" && message.event.sourceActorId === "caster") {
events.push(message.event);
}
});
useCombatStore.getState().advanceMobCombat(1_000);
expect(useCombatStore.getState().playerPosition).toEqual([2, 0, 0]);
expect(events.map((event) => event.phase)).toEqual(["release", "impact"]);
unsubscribe();
});
});