Release Healer Man 0.1.45
This commit is contained in:
1 parent
756ee4f64a
commit
f82daf1c13
242 files changed
+1440
-101
No files matched your search
@@ -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();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user