feat: strengthen semantic battle feedback
This commit is contained in:
@@ -103,6 +103,9 @@ try {
|
||||
'objective-success': '/audio/objective-success.ogg',
|
||||
'objective-failure': '/audio/objective-failure.ogg',
|
||||
'story-page-turn': '/audio/story-page-turn.ogg',
|
||||
'recovery-cue': '/audio/recovery-cue.ogg',
|
||||
'burn-tick': '/audio/burn-tick.ogg',
|
||||
'reward-reveal': '/audio/reward-reveal.ogg',
|
||||
'ui-select': '/audio/ui-select.ogg'
|
||||
});
|
||||
director.registerEffectPools({
|
||||
@@ -388,7 +391,7 @@ try {
|
||||
debug = director.getDebugState();
|
||||
assert.deepEqual(
|
||||
debug.semanticCues.cooldownMs,
|
||||
{ turn: 900, operation: 650, objective: 1200, narrative: 220 },
|
||||
{ turn: 900, operation: 650, objective: 1200, narrative: 220, recovery: 1900, status: 280, reward: 1100 },
|
||||
'semantic cue cooldowns should be visible in debug state'
|
||||
);
|
||||
assert.deepEqual(
|
||||
@@ -447,6 +450,41 @@ try {
|
||||
clock.advance(1100);
|
||||
assert.equal(director.getDebugState().activeEffectCount, 0, 'story advance cues should retire after playback');
|
||||
|
||||
const feedbackCueStart = audioHarness.instances.length;
|
||||
const musicDuckRevisionBeforeFeedback = director.getDebugState().musicDuck.revision;
|
||||
assert.equal(director.playRecoveryCue(), true, 'the first recovery cue should play');
|
||||
assertClose(audioHarness.byOriginalSrc('/audio/recovery-cue.ogg').volume, 0.26, 'recovery cue volume');
|
||||
assert.equal(director.playRecoveryCue(), false, 'rapid recovery cues should be coalesced');
|
||||
assert.equal(director.playBurnTickCue(), true, 'the first batched burn cue should play');
|
||||
assertClose(audioHarness.byOriginalSrc('/audio/burn-tick.ogg').volume, 0.24, 'burn cue volume');
|
||||
assert.equal(director.playBurnTickCue(), false, 'rapid burn cues should be coalesced');
|
||||
assert.equal(director.playRewardRevealCue(), true, 'the first reward reveal cue should play');
|
||||
assertClose(audioHarness.byOriginalSrc('/audio/reward-reveal.ogg').volume, 0.26, 'reward reveal cue volume');
|
||||
assert.equal(director.playRewardRevealCue(), false, 'rapid reward reveal cues should be coalesced');
|
||||
debug = director.getDebugState();
|
||||
assert.equal(
|
||||
debug.musicDuck.revision,
|
||||
musicDuckRevisionBeforeFeedback + 1,
|
||||
'only the reward reveal cue should apply a short music duck'
|
||||
);
|
||||
assert.deepEqual(
|
||||
debug.semanticCues.lastSuppressed,
|
||||
{ group: 'reward', key: 'reward-reveal', at: clock.now, remainingMs: 1100 },
|
||||
'debug state should expose a coalesced reward reveal cue'
|
||||
);
|
||||
assert.equal(audioHarness.instances.length, feedbackCueStart + 3, 'coalesced feedback cues must not construct Audio');
|
||||
clock.advance(280);
|
||||
assert.equal(director.playRecoveryCue(), false, 'recovery cues should remain coalesced for the clip playback window');
|
||||
assert.equal(director.playBurnTickCue(), true, 'burn cues should replay after their cooldown');
|
||||
assert.equal(director.playRewardRevealCue(), false, 'reward cues should retain their longer arrival cooldown');
|
||||
clock.advance(820);
|
||||
assert.equal(director.playRewardRevealCue(), true, 'reward cues should replay after the arrival cooldown');
|
||||
assert.equal(director.playRecoveryCue(), false, 'recovery cues should still be coalesced before the clip finishes');
|
||||
clock.advance(800);
|
||||
assert.equal(director.playRecoveryCue(), true, 'recovery cues should replay after the full clip playback window');
|
||||
clock.advance(2000);
|
||||
assert.equal(director.getDebugState().activeEffectCount, 0, 'semantic feedback cues should retire after playback');
|
||||
|
||||
const semanticEffectStart = audioHarness.instances.length;
|
||||
director.playMeleeSwing(true, false);
|
||||
assert.equal(director.getDebugState().lastEffect?.key, 'melee-swing', 'melee API should use the swing pool');
|
||||
@@ -485,7 +523,7 @@ try {
|
||||
console.log(
|
||||
`Verified dual SoundDirector channels across ${debug.music.elementRevision} music and ` +
|
||||
`${debug.ambience.elementRevision} ambience element revisions, no-repeat effect pools, ` +
|
||||
'coalesced tactical and narrative cues, semantic combat effects, category multipliers, and deterministic music ducking.'
|
||||
'coalesced tactical, narrative, and feedback cues, semantic combat effects, category multipliers, and deterministic music ducking.'
|
||||
);
|
||||
} finally {
|
||||
restoreGlobals();
|
||||
|
||||
Reference in New Issue
Block a user