feat: deepen audiovisual story immersion

This commit is contained in:
2026-07-23 10:57:07 +09:00
parent a9e401aedf
commit 8cf0886d7d
38 changed files with 2037 additions and 144 deletions

View File

@@ -63,6 +63,13 @@ assert.match(campSupply, /soundDirector\.playRecoveryCue\(\)/);
const victoryReward = privateMethodBody(campSource, 'showVictoryRewardAcknowledgement');
assert.equal(countMatches(victoryReward, /soundDirector\.playRewardRevealCue\(\)/g), 1, 'victory reward should reveal once');
const progressChapterDetail = privateMethodBody(campSource, 'renderProgressChapterDetail');
assert.match(progressChapterDetail, /const battleTitleWidth = 116/);
assert.match(progressChapterDetail, /const objectiveX = battleTitleX \+ battleTitleWidth \+ 10/);
assert.match(progressChapterDetail, /compactText\(battle\.title, 10\)[\s\S]*fixedWidth: battleTitleWidth/);
assert.match(progressChapterDetail, /compactText\(battle\.victoryConditionLabel, 15\)[\s\S]*fixedWidth: objectiveWidth/);
assert.match(progressChapterDetail, /setData\('timelineField', 'battle-title'\)[\s\S]*setData\('timelineField', 'victory-condition'\)/);
const deploymentConfirmation = privateMethodBody(battleSource, 'confirmPreBattleDeployment');
assert.match(deploymentConfirmation, /showOpeningBattleEvent\(\)/);
assert.doesNotMatch(deploymentConfirmation, /soundDirector\.playSelect\(\)/, 'opening alert must not overlap a selection cue');
@@ -72,6 +79,18 @@ assert.match(resolveDamageTarget, /triggerBattleEvent\('first-engagement'[\s\S]*
const triggerBattleEvent = privateMethodBody(battleSource, 'triggerBattleEvent');
assert.match(triggerBattleEvent, /options\.playCue !== false/);
const movementSound = privateMethodBody(battleSource, 'playMovementSound');
assert.match(movementSound, /const minInterval = isMounted \? 125 : 180/);
assert.match(movementSound, /Math\.floor\(duration \/ minInterval\) \+ 1/);
assert.match(movementSound, /pulseCount > 1 \? duration \/ \(pulseCount - 1\) : 0/);
assert.match(movementSound, /playMovementStep\(isMounted, index, \{\s*terrain,/s);
assert.doesNotMatch(movementSound, /stopAfterMs/, 'movement one-shots should clean up on ended instead of truncating each step');
assert.equal(
countMatches(battleSource, /playMovementSound\(unit, movementDuration, movementDistance, battleMap\.terrain\[y\]\?\.\[x\]\)/g),
2,
'both synchronous and asynchronous movement paths must pass destination terrain to movement audio'
);
const mapCombat = privateMethodBody(battleSource, 'playCombatMapPresentation');
assert.match(mapCombat, /contactDelayMs = Math\.max\(70, Math\.round\(duration \* 0\.42\)\)/);
assert.match(mapCombat, /await this\.waitSceneDuration\(contactDelayMs\);\s*this\.playCombatContactSound\(result\)/s);