The leak alarm: an enemy entering the blue gate plays the official stage sound (ON_ENEMY_REACHED_EXIT), one alarm per burst (#134)
Battle.leak emits its own 'leak' event, which no sound handled, so every leak was silent; the client now plays battle.ON_ENEMY_REACHED_EXIT (b_ui_alarmenter) with the bank's own one-at-a-time rule, leaks closer than the sound's length sharing one alarm. The manifest gains only audio.sfx.battle.leak. Contributed by @Convey123.
This commit is contained in:
1 parent
a9dfd17bee
commit
d582925816
6 files changed
+86
-2
No files matched your search
@@ -650,3 +650,62 @@ describe('impact sounds (user playtest #4 item 6)', () => {
|
||||
} finally { globalThis.performance = perf; restore(); }
|
||||
});
|
||||
});
|
||||
|
||||
// =====================================================================================================================
|
||||
// 漏怪 sound (user request "接下来加漏怪的音效", then "应该是原版明日方舟关卡中的怪进蓝门的音效"). The sim emits
|
||||
// `['leak', id]` when an enemy reaches its goal (Battle.leak) — NOT a `die` — so until now an escape was completely
|
||||
// silent, for the player's own field and for a 联防 the helpers could not hold alike.
|
||||
//
|
||||
// The cue is the ORIGINAL Arknights stage alarm an enemy entering the exit plays in any normal stage: the manifest's
|
||||
// `sfx.battle.leak`, bank `battle.ON_ENEMY_REACHED_EXIT`, file `Battle/b_ui/b_ui_alarmenter`. (The autochess banks
|
||||
// have nothing named for an escape — all 13,948 SFX banks searched — but the stage itself does.) The official bank is
|
||||
// a one-shot: `maxSoundAllowed: 1` with `popOldest: true` on the `Battle_UI_Important` mixer.
|
||||
|
||||
describe('漏怪 sound', () => {
|
||||
async function rig() {
|
||||
const fw = fakeWindow();
|
||||
const urls = [];
|
||||
const origFetch = globalThis.fetch;
|
||||
globalThis.fetch = async (u) => { urls.push(u); return { ok: true, arrayBuffer: async () => new ArrayBuffer(8) }; };
|
||||
const a = new AudioManager({ win: fw.win, getManifest: () => manifest });
|
||||
a.install();
|
||||
fw.fire('pointerdown');
|
||||
const settle = () => new Promise((r) => setTimeout(r, 10));
|
||||
return { a, fw, urls, settle, restore: () => { globalThis.fetch = origFetch; } };
|
||||
}
|
||||
|
||||
test('an escaped enemy plays the original stage exit alarm — and no death sound (a leak is not a `die`)', async () => {
|
||||
const { a, urls, settle, restore } = await rig();
|
||||
try {
|
||||
const url = manifest.audio.sfx.battle.leak;
|
||||
assert.ok(url, '前提:清单里有 sfx.battle.leak');
|
||||
assert.match(url, /b_ui_alarmenter\.mp3$/, '就是原版关卡里怪进蓝门那一声');
|
||||
a.handleBattleEvents([['leak', 7]]);
|
||||
await settle();
|
||||
assert.ok(asked(urls, url), `漏怪 plays ${url}`);
|
||||
assert.equal(askedCount(urls, manifest.audio.sfx.battle.enemyDie), 0, 'a leak is not a death — no death sound');
|
||||
} finally { restore(); }
|
||||
});
|
||||
|
||||
test('leaks of one disaster are ONE alarm (the cue is 1.44 s long), a later one rings again', async () => {
|
||||
const { a, fw, urls, settle, restore } = await rig();
|
||||
try {
|
||||
const url = manifest.audio.sfx.battle.leak;
|
||||
a.handleBattleEvents([['leak', 1]]);
|
||||
await settle();
|
||||
assert.equal(askedCount(urls, url), 1, 'the first escape rings');
|
||||
// the plays themselves, not the fetches: the buffer is cached after the first one
|
||||
const before = fw.made.started;
|
||||
// six more at once — a wiped board, or a 联防 the helpers could not hold
|
||||
a.handleBattleEvents([['leak', 2], ['leak', 3], ['leak', 4], ['leak', 5], ['leak', 6], ['leak', 7]]);
|
||||
await settle();
|
||||
assert.equal(fw.made.started - before, 0, 'one disaster never stacks alarms (the official bank allows 1)');
|
||||
// a genuine later leak is a new disaster and rings again, once the cue (1.44 s) has finished
|
||||
await new Promise((r) => setTimeout(r, 1600));
|
||||
a.handleBattleEvents([['leak', 8]]);
|
||||
await settle();
|
||||
assert.equal(fw.made.started - before, 1, 'a later leak rings again');
|
||||
assert.ok(a.limiter.active <= a.limiter.maxVoices);
|
||||
} finally { restore(); }
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user