Release Healer Man 0.1.12

This commit is contained in:
phenom committed 2026-09-01 14:35:56 -04:00
1 parent 13970d03c8
commit 65e24f644e
201 files changed
+5061 -123

No files matched your search

+35
View File
@@ -1,6 +1,7 @@
import type { AbilityDefinition, AbilityEffect } from "./abilityCatalog";
export type CombatActorGroup = "player" | "party" | "enemy";
export type CombatVfxMode = "generated" | "original";
export type CombatVfxQuality = "off" | "low" | "high";
export type CombatPresentationPhase =
| "cast-start"
@@ -23,6 +24,7 @@ export type CombatPresentationSource = "wow335" | "ascension" | "runewaker" | "f
export type CombatPresentationPosition = readonly [number, number, number];
export interface CombatPresentationSettings {
readonly vfxMode: CombatVfxMode;
readonly vfxQuality: CombatVfxQuality;
readonly vfxEnabled: Readonly<Record<CombatActorGroup, boolean>>;
readonly audioEnabled: Readonly<Record<CombatActorGroup, boolean>>;
@@ -32,6 +34,7 @@ export interface CombatPresentationSettings {
const ACTOR_GROUPS: readonly CombatActorGroup[] = ["player", "party", "enemy"];
export const DEFAULT_COMBAT_PRESENTATION_SETTINGS: CombatPresentationSettings = Object.freeze({
vfxMode: "generated",
vfxQuality: "high",
vfxEnabled: Object.freeze({ player: true, party: true, enemy: true }),
audioEnabled: Object.freeze({ player: true, party: true, enemy: true }),
@@ -77,10 +80,14 @@ export function normalizeCombatPresentationSettings(
const record = value && typeof value === "object" && !Array.isArray(value)
? value as Partial<Record<keyof CombatPresentationSettings, unknown>>
: {};
const vfxMode = record.vfxMode === "generated" || record.vfxMode === "original"
? record.vfxMode
: fallback.vfxMode;
const vfxQuality = record.vfxQuality === "off" || record.vfxQuality === "low" || record.vfxQuality === "high"
? record.vfxQuality
: fallback.vfxQuality;
return Object.freeze({
vfxMode,
vfxQuality,
vfxEnabled: booleanGroups(record.vfxEnabled, fallback.vfxEnabled),
audioEnabled: booleanGroups(record.audioEnabled, fallback.audioEnabled),
@@ -155,6 +162,10 @@ export interface CombatEffectPhaseAsset {
readonly model?: string;
readonly attachment?: string;
readonly scale?: number;
/** Browser-ready graph generated from the original client asset. */
readonly effectGraphUrl?: string;
readonly effectKind?: "wow-m2-particles" | "wow-m2-static-mesh" | "runewaker-particles";
readonly originalSourceSha256?: string;
}
export interface CombatEffectSoundAsset {
@@ -215,6 +226,30 @@ export function combatEffectManifestEntry(
return manifestBySpellId.get(spellId) ?? null;
}
export function originalCombatPhaseAssets(
entry: CombatEffectManifestEntry | null | undefined,
phase: CombatPresentationPhase,
): readonly CombatEffectPhaseAsset[] {
return (entry?.phases?.[phase] ?? []).filter((asset) => (
typeof asset.effectGraphUrl === "string"
&& asset.effectGraphUrl.startsWith("/assets/game/combat-effects/original/")
&& (
asset.effectKind === "wow-m2-particles"
|| asset.effectKind === "wow-m2-static-mesh"
|| asset.effectKind === "runewaker-particles"
)
));
}
export function combatOriginalPhaseAssets(
event: Pick<CombatPresentationEvent, "phase" | "source" | "sourceSpellId">,
): readonly CombatEffectPhaseAsset[] {
return originalCombatPhaseAssets(
combatEffectManifestEntry(event.sourceSpellId, event.source),
event.phase,
);
}
function abilityHasEffect(ability: AbilityDefinition, kind: AbilityEffect["kind"]): boolean {
return ability.effects.some((effect) => effect.kind === kind);
}