feat: improve tactical audiovisual clarity

This commit is contained in:
2026-07-22 20:08:23 +09:00
parent d3af88c2a9
commit 8bda36d46d
5 changed files with 663 additions and 58 deletions

View File

@@ -237,12 +237,27 @@ try {
message: result.message,
tileVisible: scene.isTileVisible(unit.x, unit.y),
feedback: battle.mapResultFeedback,
soundCaption: battle.soundCaption,
expectedDirection: scene.offscreenTileDirection(destination),
unit: battle.units.find((candidate) => candidate.id === unitId)
};
}, initial.ally.id);
assert.match(offscreenTick.message, /화상/);
assert.equal(offscreenTick.tileVisible, false);
assert.equal(offscreenTick.feedback.activeCount, 0, 'offscreen burn damage must not clamp a popup to the map edge');
assert.equal(offscreenTick.soundCaption.visible, true, 'offscreen burn damage should create one fixed sound caption');
assert.equal(offscreenTick.soundCaption.kind, 'status');
assert.match(offscreenTick.soundCaption.text, /화상 피해/);
assert.equal(offscreenTick.soundCaption.direction, offscreenTick.expectedDirection);
assert(
offscreenTick.soundCaption.bounds.x >= offscreenTick.feedback.mapBounds.x &&
offscreenTick.soundCaption.bounds.y >= offscreenTick.feedback.mapBounds.y &&
offscreenTick.soundCaption.bounds.x + offscreenTick.soundCaption.bounds.width <=
offscreenTick.feedback.mapBounds.x + offscreenTick.feedback.mapBounds.width &&
offscreenTick.soundCaption.bounds.y + offscreenTick.soundCaption.bounds.height <=
offscreenTick.feedback.mapBounds.y + offscreenTick.feedback.mapBounds.height,
'the fixed sound caption must remain inside the battle map'
);
assert.equal(offscreenTick.unit.hp, initial.ally.hp - 6);
assert.equal(offscreenTick.unit.statusBadges.length, 0, 'expired status badges must be removed after the offscreen tick');
@@ -251,7 +266,11 @@ try {
const debug = window.__HEROS_DEBUG__;
const scene = debug.scene('BattleScene');
const recoveryPlayedAt = debug.audio().semanticCues.playedAt.recovery ?? null;
const selected = scene.playTurnStartFeedbackCue('ally', true, true);
const selected = scene.playTurnStartFeedbackCue(
'ally',
{ burnTicked: true, offscreenBurnSources: [] },
{ applied: true, offscreenRecoverySources: [] }
);
return { selected, recoveryPlayedAt, audio: debug.audio() };
});
assert.equal(prioritizedBurn.selected, 'status');
@@ -268,7 +287,12 @@ try {
const debug = window.__HEROS_DEBUG__;
const scene = debug.scene('BattleScene');
const before = debug.audio().semanticCues.lastPlayed;
const selected = scene.playTurnStartFeedbackCue('ally', true, true, true);
const selected = scene.playTurnStartFeedbackCue(
'ally',
{ burnTicked: true, offscreenBurnSources: [] },
{ applied: true, offscreenRecoverySources: [] },
true
);
return { before, selected, after: debug.audio().semanticCues.lastPlayed, activeEffectCount: debug.audio().activeEffectCount };
});
assert.equal(operationPriority.selected, 'operation');
@@ -278,7 +302,11 @@ try {
const recoveryCue = await page.evaluate(() => {
const debug = window.__HEROS_DEBUG__;
const scene = debug.scene('BattleScene');
const selected = scene.playTurnStartFeedbackCue('ally', false, true);
const selected = scene.playTurnStartFeedbackCue(
'ally',
{ burnTicked: false, offscreenBurnSources: [] },
{ applied: true, offscreenRecoverySources: [] }
);
return { selected, audio: debug.audio() };
});
assert.equal(recoveryCue.selected, 'recovery');
@@ -286,10 +314,22 @@ try {
assert.equal(recoveryCue.audio.lastEffect.trackKey, 'recovery-cue');
assert.equal(recoveryCue.audio.activeEffectCount, 1, 'the standalone recovery cue must decode and play in the browser');
const delayedOutcomeCaption = await page.evaluate((unitId) => {
const debug = window.__HEROS_DEBUG__;
const scene = debug.scene('BattleScene');
const unit = scene.debugUnitById(unitId);
scene.completeBattle('defeat', 720);
scene.showOffscreenBurnCaption([{ x: unit.x, y: unit.y }]);
return debug.battle().soundCaption;
}, initial.ally.id);
assert.equal(delayedOutcomeCaption.visible, true, 'lethal offscreen burn must remain captioned before the result reveal');
assert.equal(delayedOutcomeCaption.kind, 'status');
assert.match(delayedOutcomeCaption.text, /화상 피해/);
assert.deepEqual(pageErrors, [], `Unexpected page errors: ${pageErrors.join('\n')}`);
assert.deepEqual(consoleErrors, [], `Unexpected browser console errors: ${consoleErrors.join('\n')}`);
console.log(
'Verified 1920x1080 DPR1 paired status badges, decoded and prioritized cues, offscreen popup suppression, expiry, and opening isolation.'
'Verified 1920x1080 DPR1 paired status badges, offscreen sound captions, decoded and prioritized cues, popup suppression, expiry, and opening isolation.'
);
} finally {
await browser?.close();