forked from phenom/healer-man
Update Healer Man server
This commit is contained in:
1 parent
71246e5b75
commit
a868401ebc
40 files changed
+1522
-161
No files matched your search
@@ -208,6 +208,62 @@ describe("combat audio output policy", () => {
|
||||
audio.resetCombatAudio();
|
||||
});
|
||||
|
||||
it("positions release audio at the caster and impact audio at the target", async () => {
|
||||
vi.resetModules();
|
||||
const audio = await import("./combatAudio");
|
||||
const panners: Array<{
|
||||
positionX: { value: number };
|
||||
positionY: { value: number };
|
||||
positionZ: { value: number };
|
||||
}> = [];
|
||||
const audioContext = {
|
||||
currentTime: 0, state: "running", destination: {},
|
||||
createGain: () => ({ connect: vi.fn(), disconnect: vi.fn(), gain: {
|
||||
setTargetAtTime: vi.fn(), value: 1,
|
||||
} }),
|
||||
createPanner: () => {
|
||||
const panner = {
|
||||
connect: vi.fn(), disconnect: vi.fn(),
|
||||
positionX: { value: 0 }, positionY: { value: 0 }, positionZ: { value: 0 },
|
||||
panningModel: "HRTF", distanceModel: "inverse",
|
||||
refDistance: 0, maxDistance: 0, rolloffFactor: 0,
|
||||
};
|
||||
panners.push(panner);
|
||||
return panner;
|
||||
},
|
||||
createBufferSource: () => ({
|
||||
connect: vi.fn(), disconnect: vi.fn(), start: vi.fn(), stop: vi.fn(),
|
||||
buffer: null, loop: false, onended: null,
|
||||
}),
|
||||
decodeAudioData: vi.fn(async () => ({ duration: 0.2 })),
|
||||
resume: vi.fn(async () => undefined),
|
||||
};
|
||||
vi.stubGlobal("window", { AudioContext: function () { return audioContext; } });
|
||||
combatMedia.ready = true;
|
||||
combatMedia.entry.mockReturnValue({
|
||||
key: "runewaker:490256", source: "runewaker", spellId: 490256,
|
||||
sounds: [
|
||||
{ url: "/assets/game/combat-effects/audio/rising-release.mp3", phase: "release" },
|
||||
{ url: "/assets/game/combat-effects/audio/rising-impact.mp3", phase: "impact" },
|
||||
],
|
||||
});
|
||||
combatMedia.fetch.mockImplementation(async () => new Response(new Uint8Array([1, 2, 3])));
|
||||
audio.configureCombatAudio(DEFAULT_COMBAT_PRESENTATION_SETTINGS, 0.6);
|
||||
const release = {
|
||||
...fixtureEvent, source: "runewaker" as const, sourceSpellId: 490256,
|
||||
phase: "release" as const, origin: [1, 2, 3] as const,
|
||||
targetPosition: [9, 8, 7] as const,
|
||||
};
|
||||
audio.playCombatAudio(release);
|
||||
audio.playCombatAudio({ ...release, id: 2, phase: "impact" });
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
expect(panners.map((panner) => [
|
||||
panner.positionX.value, panner.positionY.value, panner.positionZ.value,
|
||||
])).toEqual([[1, 2, 3], [9, 8, 7]]);
|
||||
audio.resetCombatAudio();
|
||||
});
|
||||
|
||||
it("loops only a flagged cast sound and stops the matching actor and ability", async () => {
|
||||
vi.resetModules();
|
||||
const audio = await import("./combatAudio");
|
||||
|
||||
@@ -128,15 +128,18 @@ function positionPanner(
|
||||
event: CombatPresentationEvent,
|
||||
): PannerNode | StereoPannerNode {
|
||||
if (typeof audioContext.createPanner === "function") {
|
||||
const position = event.phase === "impact"
|
||||
? event.targetPosition ?? event.origin
|
||||
: event.origin;
|
||||
const panner = audioContext.createPanner();
|
||||
panner.panningModel = "HRTF";
|
||||
panner.distanceModel = "inverse";
|
||||
panner.refDistance = event.actorGroup === "player" ? 8 : 5;
|
||||
panner.maxDistance = 55;
|
||||
panner.rolloffFactor = event.actorGroup === "player" ? 0.15 : 0.8;
|
||||
panner.positionX.value = event.origin[0];
|
||||
panner.positionY.value = event.origin[1];
|
||||
panner.positionZ.value = event.origin[2];
|
||||
panner.positionX.value = position[0];
|
||||
panner.positionY.value = position[1];
|
||||
panner.positionZ.value = position[2];
|
||||
return panner;
|
||||
}
|
||||
return audioContext.createStereoPanner();
|
||||
|
||||
@@ -178,6 +178,8 @@ export interface CombatEffectPhaseAsset {
|
||||
/** Browser-ready graph generated from the original client asset. */
|
||||
readonly effectGraphUrl?: string;
|
||||
readonly effectKind?: "wow-m2-particles" | "wow-m2-static-mesh" | "wow-m2-model" | "runewaker-particles";
|
||||
/** A source graph with verified sprite layers but omitted unsupported visual controllers. */
|
||||
readonly visualCompleteness?: "partial";
|
||||
readonly originalSourceSha256?: string;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user