Release Healer Man 0.1.9

This commit is contained in:
phenom committed 2026-08-30 14:16:56 -04:00
1 parent c245a199b6
commit d060296ade
74 files changed
+5901 -334

No files matched your search

+123
View File
@@ -0,0 +1,123 @@
import { describe, expect, it } from "vitest";
import type { CombatPresentationEvent } from "../game/combatPresentation";
import {
COMBAT_EFFECT_SYSTEM_LIMIT,
advanceCombatEffectFrame,
updateCombatEffectQueue,
type ActiveCombatEffect,
} from "./combatEffectRuntime";
function event(
id: number,
patch: Partial<CombatPresentationEvent> = {},
): CombatPresentationEvent {
return {
id,
sessionId: 1,
occurredAt: id,
phase: "impact",
actorGroup: "enemy",
sourceActorId: `enemy-${id}`,
targetActorId: "player",
abilityId: "fixture",
name: "Fixture",
source: "fallback",
school: "shadow",
delivery: "projectile",
origin: [0, 0, 0],
targetPosition: [1, 0, 0],
...patch,
};
}
function enqueue(
events: readonly CombatPresentationEvent[],
quality: "off" | "low" | "high",
): readonly ActiveCombatEffect[] {
return events.reduce<readonly ActiveCombatEffect[]>(
(current, next) => updateCombatEffectQueue(current, next, quality),
[],
);
}
describe("combat-effect runtime budget", () => {
it("expires effects by wall time while bounding motion after a hitch", () => {
let frame = advanceCombatEffectFrame(0, 1 / 60, 420);
frame = advanceCombatEffectFrame(frame.elapsedMs, 1 / 60, 420);
frame = advanceCombatEffectFrame(frame.elapsedMs, 0.5, 420);
expect(frame.elapsedMs).toBeCloseTo(533.333, 2);
expect(frame.motionDeltaSeconds).toBe(0.05);
expect(frame.progress).toBe(1);
expect(frame.done).toBe(true);
expect(advanceCombatEffectFrame(frame.elapsedMs, Number.NaN, 420).elapsedMs)
.toBe(frame.elapsedMs);
});
it("bounds large bursts while retaining player feedback and the newest event", () => {
const player = event(1, {
actorGroup: "player",
sourceActorId: "player",
school: "holy",
});
const enemies = Array.from({ length: 512 }, (_, index) => event(index + 2, {
phase: "tick",
}));
const high = enqueue([player, ...enemies], "high");
const low = enqueue([player, ...enemies], "low");
expect(high).toHaveLength(COMBAT_EFFECT_SYSTEM_LIMIT.high);
expect(low).toHaveLength(COMBAT_EFFECT_SYSTEM_LIMIT.low);
expect(enqueue([player], "off")).toEqual([]);
expect(updateCombatEffectQueue(enqueue([player], "high"), enemies[0], "off"))
.toEqual([]);
expect(high.some(({ event: active }) => active.id === player.id)).toBe(true);
expect(high.at(-1)?.event.id).toBe(enemies.at(-1)?.id);
expect(new Set(high.map(({ key }) => key)).size).toBe(high.length);
});
it("keeps combat-significant enemy casts ahead of low-value friendly ticks", () => {
const partyTicks = Array.from({ length: COMBAT_EFFECT_SYSTEM_LIMIT.low }, (_, index) => event(index + 1, {
actorGroup: "party",
sourceActorId: `party-${index}`,
phase: "tick",
}));
const enemyCast = event(100, {
actorGroup: "enemy",
sourceActorId: "boss",
phase: "cast-start",
});
const effects = enqueue([...partyTicks, enemyCast], "low");
expect(effects).toHaveLength(COMBAT_EFFECT_SYSTEM_LIMIT.low);
expect(effects.some(({ event: active }) => active.id === enemyCast.id)).toBe(true);
expect(effects.filter(({ event: active }) => active.phase === "tick"))
.toHaveLength(COMBAT_EFFECT_SYSTEM_LIMIT.low - 1);
});
it("coalesces a single area burst but preserves projectile phases", () => {
const areaRelease = event(1, {
occurredAt: 100,
phase: "release",
delivery: "area",
sourceActorId: "caster",
});
const areaImpacts = Array.from({ length: 5 }, (_, index) => event(index + 2, {
occurredAt: 100,
phase: "impact",
delivery: "area",
sourceActorId: "caster",
targetActorId: `target-${index}`,
}));
const area = enqueue([areaRelease, ...areaImpacts], "high");
expect(area).toHaveLength(1);
expect(area[0].event.phase).toBe("impact");
const projectile = enqueue([
event(10, { occurredAt: 200, phase: "release", sourceActorId: "caster" }),
event(11, { occurredAt: 200, phase: "impact", sourceActorId: "caster" }),
], "high");
expect(projectile).toHaveLength(2);
});
});