feedback7 R22-VOICES: review fixes — a 选中 tap no longer restarts the battle-voice gap, and the second shop / reward card of one operator says its 选中 line too; the package switch's comment quotes the measured JP size; golden: unchanged
1. VoiceGate.start no longer moves lastAt for VOICE_TAP_SLOTS: a tap still skips the 1.2 s gap but starts none, so a 部署 / 技能 / 接敌 the battle asks for once after a short 选中 line has ended plays where the last battle line's gap ends (a 部署 at 0, a tap at 500: a 作战中 at 1300 was dropped, now plays; inside the 部署 gap it still waits). 2. Shop / reward cards hand only the chess id to the detail, so two cards of one operator (the pool deals duplicates) had one 选中 key and the second tap said nothing nor replaced the first line: game.js numbers every card it opens (`tap`, cardTap), resolveDetail keeps it, and detailPanel's new selectVoiceKey() includes it (a re-render of the same tap keeps its key; pieces / units unchanged). Checked in the mock match: the second card of 歌蕾蒂娅 now calls voice() (it made no call on the parent). 3. tools/package.mjs FULL_ZIP_JP_VOICE comment: 89,388,041 bytes = 85.2 MiB on disk, about 76 MB zipped (as ASSETS / DEPLOY), not "~93 MB, barely compresses". Tests: test/ui/audio.test.js (the tap-gap case; one earlier assertion that encoded the old gap after a tap replaced), test/feedback7-voices.test.js (new: the card tap in resolveDetail / selectVoiceKey / game.js) — both fail on the parent. §21.30's 0.2.2 note updated.
This commit is contained in:
1 parent
ddf8c39ed0
commit
bcee737f40
7 files changed
+79
-11
No files matched your search
@@ -137,3 +137,40 @@ test('package: the full zip ships the JP dub by default; FULL_ZIP_JP_VOICE off h
|
||||
const src = fs.readFileSync(path.join(ROOT, 'tools/package.mjs'), 'utf8');
|
||||
assert.match(src, /removable: \(rel\) => !removalProblem\(rel\) && !heldBack\.has\(rel\)/);
|
||||
});
|
||||
|
||||
test('选中干员 on every card tap (review of fb7-voices): two shop / reward cards of one operator are two taps, a re-render is none', async () => {
|
||||
// shop / reward cards hand only the chess id to the detail target (no piece, no unit): game.js numbers every card it opens
|
||||
// (`tap`), resolveDetail keeps it, and the panel's 选中 key (selectVoiceKey) includes it — the second 斯卡蒂 card spoke
|
||||
// nothing before, nor replaced the first card's line (the pool deals duplicates)
|
||||
const origFetch = globalThis.fetch;
|
||||
globalThis.fetch = async (url) => {
|
||||
const name = String(url).split('/').pop();
|
||||
let body;
|
||||
try { body = readJson(`data/${name}`); } catch { return { ok: false, status: 404, json: async () => ({}) }; }
|
||||
return { ok: true, status: 200, json: async () => body };
|
||||
};
|
||||
try {
|
||||
const { resolveDetail, selectVoiceKey } = await import('../public/js/ui/detailPanel.js');
|
||||
const { data } = await import('../public/js/data.js');
|
||||
await data.loadAll('chess', 'backups');
|
||||
const id = Object.values(readJson('data/chess.json')).find((c) => c.charId === 'char_263_skadi' && !c.isGolden).chessId;
|
||||
const card = (tap) => resolveDetail({ kind: 'chess', id, hint: null, tap }, new Map(), { priv: null });
|
||||
const a = card(1), b = card(2);
|
||||
assert.equal(a.chess.charId, 'char_263_skadi');
|
||||
assert.deepEqual([a.tap, b.tap], [1, 2], 'the tap rides along');
|
||||
assert.notEqual(selectVoiceKey(a), selectVoiceKey(b), 'the second card of the same operator is a new opening');
|
||||
assert.equal(selectVoiceKey(card(1)), selectVoiceKey(a), 'the same tap resolved again (a re-render) says nothing more');
|
||||
assert.equal(resolveDetail({ kind: 'chess', id }, new Map(), { priv: null }).tap, undefined, 'no tap, no field');
|
||||
// pieces and battle units keep their own identity; a non-operator card has no key
|
||||
assert.equal(selectVoiceKey({ type: 'chess', chess: { chessId: 'x' }, piece: { uid: 4 } }), 'x:4:');
|
||||
assert.equal(selectVoiceKey({ type: 'chess', chess: { chessId: 'x' }, unitId: 9 }), 'x:9:');
|
||||
assert.equal(selectVoiceKey({ type: 'item' }), null);
|
||||
assert.equal(selectVoiceKey(null), null);
|
||||
// the panel keys its 选中 effect on it, and the game screen numbers every operator card it opens
|
||||
assert.match(fs.readFileSync(path.join(ROOT, 'public/js/ui/detailPanel.js'), 'utf8'), /const selectKey = voice && detail\?\.type === 'chess' \? selectVoiceKey\(detail\) : null;/);
|
||||
const game = fs.readFileSync(path.join(ROOT, 'public/js/screens/game.js'), 'utf8');
|
||||
assert.match(game, /onDetail=\$\{\(id, kind, hint\) => setDetail\(\{ kind: kind === 'item' \? 'item' : 'chess', id, hint: hint \|\| null, tap: \+\+cardTap\.current \}\)\}/);
|
||||
} finally {
|
||||
globalThis.fetch = origFetch;
|
||||
}
|
||||
});
|
||||
+12
-1
@@ -264,7 +264,6 @@ describe('operator battle voice', () => {
|
||||
assert.equal(g.request('select', null, 0), 'play');
|
||||
g.start('select', null, 0); g.release(); // tap A, its line ended
|
||||
assert.equal(g.request('select', null, 300), 'play', 'an idle channel: the global gap never drops a tap');
|
||||
assert.equal(g.request('place', 'u1', 300), 'drop', 'the battle lines keep the gap');
|
||||
g.start('select', 'u1', 300); g.release();
|
||||
assert.equal(g.request('select', 'u1', 400), 'play', 'no cooldown either, keyed or not');
|
||||
g.start('select', null, 400);
|
||||
@@ -277,6 +276,18 @@ describe('operator battle voice', () => {
|
||||
g.start('skill1', 'u3', 0);
|
||||
assert.equal(g.request('select', null, 100), 'drop', '… nor a 作战中 line');
|
||||
g.reset();
|
||||
// a tap starts no gap of its own (review of fb7-voices): a 部署 at 0 holds the battle lines until 1200; a tap at 500
|
||||
// answers, its short line ends at 944, and a 作战中 the battle asks for once at 1300 still plays (it was dropped: the
|
||||
// tap had moved the gap's start to 500)
|
||||
g.start('place', 'u4', 0); g.release();
|
||||
assert.equal(g.request('select', null, 500), 'play');
|
||||
g.start('select', null, 500); g.release();
|
||||
assert.equal(g.request('skill1', 'u5', 1100), 'drop', 'inside the 部署 gap a battle line still waits');
|
||||
assert.equal(g.request('skill1', 'u5', 1300), 'play', 'the gap ends where the 部署 put it: the tap did not restart it');
|
||||
g.reset();
|
||||
g.start('select', null, 0); g.release();
|
||||
assert.equal(g.request('place', 'u6', 100), 'play', 'a battle line right after a tap: no gap behind a 选中 line');
|
||||
g.reset();
|
||||
// the manager: two taps 0.3 s apart in the prep (no battle, the real gate) both speak, the second replacing the first
|
||||
const fw = fakeWindow();
|
||||
const origFetch = globalThis.fetch;
|
||||
|
||||
Reference in new issue
Block a user