feat: improve tactical audiovisual clarity
This commit is contained in:
@@ -6,6 +6,8 @@ export type AudioCategoryMultipliers = Record<AudioCategory, number>;
|
||||
|
||||
export type EffectPoolMap = Record<string, readonly string[]>;
|
||||
|
||||
export type StrategyImpactKind = 'fire' | 'roar' | 'arcane';
|
||||
|
||||
export type SoundscapeOptions = {
|
||||
musicKey?: string;
|
||||
ambienceKey?: string;
|
||||
@@ -74,6 +76,16 @@ type MusicDuckState = {
|
||||
};
|
||||
};
|
||||
|
||||
type PlayedEffectDebug = {
|
||||
key: string;
|
||||
trackKey: string;
|
||||
poolKey: string | null;
|
||||
at: number;
|
||||
baseVolume: number;
|
||||
volume: number;
|
||||
rate: number;
|
||||
};
|
||||
|
||||
export class SoundDirector {
|
||||
private context?: AudioContext;
|
||||
private master?: GainNode;
|
||||
@@ -116,15 +128,8 @@ export class SoundDirector {
|
||||
at: number;
|
||||
remainingMs: number;
|
||||
};
|
||||
private lastEffect?: {
|
||||
key: string;
|
||||
trackKey: string;
|
||||
poolKey: string | null;
|
||||
at: number;
|
||||
baseVolume: number;
|
||||
volume: number;
|
||||
rate: number;
|
||||
};
|
||||
private lastEffect?: PlayedEffectDebug;
|
||||
private readonly recentEffects: PlayedEffectDebug[] = [];
|
||||
private lastMovementStep?: { key: string; mounted: boolean; stepIndex: number; at: number; volume?: number; rate?: number };
|
||||
private readonly effectVolume = 0.42;
|
||||
|
||||
@@ -385,6 +390,35 @@ export class SoundDirector {
|
||||
}
|
||||
}
|
||||
|
||||
playStrategyImpact(kind: StrategyImpactKind, critical: boolean) {
|
||||
if (kind === 'fire') {
|
||||
this.playEffect('burn-tick', {
|
||||
volume: critical ? 0.34 : 0.28,
|
||||
rate: critical ? 0.86 : 0.94,
|
||||
stopAfterMs: 680
|
||||
});
|
||||
this.playTone(critical ? 150 : 185, 0.11, critical ? 0.026 : 0.018, 'sawtooth');
|
||||
} else if (kind === 'roar') {
|
||||
this.playEffect('combat-impact', {
|
||||
volume: critical ? 0.4 : 0.3,
|
||||
rate: critical ? 0.72 : 0.8,
|
||||
stopAfterMs: 980
|
||||
});
|
||||
this.playTone(critical ? 92 : 118, 0.16, critical ? 0.03 : 0.022, 'triangle');
|
||||
} else {
|
||||
this.playEffect('strategy-cast', {
|
||||
volume: critical ? 0.34 : 0.26,
|
||||
rate: critical ? 1.12 : 1.2,
|
||||
stopAfterMs: 720
|
||||
});
|
||||
this.playTone(critical ? 820 : 690, 0.12, critical ? 0.022 : 0.016, 'sine');
|
||||
}
|
||||
|
||||
if (critical) {
|
||||
this.playCriticalAccent();
|
||||
}
|
||||
}
|
||||
|
||||
playBattleOutcome(outcome: 'victory' | 'defeat') {
|
||||
this.duckMusic({
|
||||
multiplier: outcome === 'victory' ? 0.34 : 0.24,
|
||||
@@ -496,7 +530,7 @@ export class SoundDirector {
|
||||
effect.muted = this.muted;
|
||||
this.activeEffects.add(effect);
|
||||
this.effectBaseVolumes.set(effect, baseVolume);
|
||||
this.lastEffect = {
|
||||
const playedEffect = {
|
||||
key,
|
||||
trackKey: resolvedTrack.trackKey,
|
||||
poolKey: resolvedTrack.poolKey,
|
||||
@@ -505,6 +539,11 @@ export class SoundDirector {
|
||||
volume: effect.volume,
|
||||
rate: effect.playbackRate
|
||||
};
|
||||
this.lastEffect = playedEffect;
|
||||
this.recentEffects.push(playedEffect);
|
||||
if (this.recentEffects.length > 12) {
|
||||
this.recentEffects.shift();
|
||||
}
|
||||
effect.addEventListener(
|
||||
'ended',
|
||||
() => {
|
||||
@@ -597,6 +636,7 @@ export class SoundDirector {
|
||||
),
|
||||
activeEffectCount: this.activeEffects.size,
|
||||
lastEffect: this.lastEffect ?? null,
|
||||
recentEffects: this.recentEffects.map((effect) => ({ ...effect })),
|
||||
lastMovementStep: this.lastMovementStep ?? null
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user