feedback4: the settlement line (结算) is spoken again — a battle result's unitsEnd names chess ids (chess_char_*), so the game screen maps them to the operator through the chess record's charId (resultSpeaker charOf); as merged in #73 the speaker took char_* ids only and no battle ever said its line (found while porting #73 to 0.2.0); test runs a real battle result through it; golden unchanged (client only)

This commit is contained in:
sganggs committed 2026-10-06 04:37:26 +08:00
1 parent beb0296a52
commit 9d56342494
4 files changed
+27 -6

No files matched your search

+14
View File
@@ -9,6 +9,7 @@ import { fileURLToPath } from 'node:url';
import { bgmKeyFor, resolveBgm, SfxLimiter, AudioManager, normalAttackSfx, installAudio, audio, combatTrackFor, COMBAT_TRACK_SWITCH_ROUND, VoiceGate, resultSpeaker, resultVoiceSlot, VOICE_PRIORITY, VOICE_COOLDOWN_MS } from '../../public/js/audio.js';
import { mediaUrl } from '../../public/js/media.js';
import { PHASE } from '../../shared/constants.js';
import { makeBattle, chessRec } from '../helpers/battleHarness.js';
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
const manifest = JSON.parse(readFileSync(path.join(ROOT, 'data', 'assets.json'), 'utf8'));
@@ -211,6 +212,19 @@ describe('operator battle voice', () => {
assert.equal(resultSpeaker({ unitsEnd: [{ defId: 'enemy_1007_slime', alive: true }] }, () => 0), null, 'an enemy');
});
test('resultSpeaker on a real battle result: unitsEnd names the chess, the chess record gives the speaking operator', () => {
// the sim reports each unit by its chess id (sim/Battle.js unitsEnd defId = the chess record's id), so the line needs
// the chess → charId step the game screen passes (data.lookup('chess', id).charId); without it no battle ever spoke
const chessTable = JSON.parse(readFileSync(path.join(ROOT, 'data', 'chess.json'), 'utf8'));
const id = 'chess_char_1_01_a';
assert.equal(chessTable[id]?.charId, 'char_498_inside');
const h = makeBattle({ defs: { chess: { [id]: chessRec({ id }) } }, units: [{ chessId: id, row: 10, col: 4 }], content: 'none' });
const mine = Object.values(h.runToEnd(30).perPlayer)[0];
assert.equal(mine.unitsEnd[0].defId, id, 'the result carries the chess id, not the charId');
assert.equal(resultSpeaker(mine, () => 0), null, 'no chess → charId step: silent (the 0.1.4 bug)');
assert.equal(resultSpeaker(mine, () => 0, (defId) => chessTable[defId]?.charId ?? null), 'char_498_inside');
});
test('VoiceGate: one line at a time, a global gap, per-unit cooldowns, higher priority takes over', () => {
assert.ok(VOICE_PRIORITY.start > VOICE_PRIORITY.skill1 && VOICE_PRIORITY.skill1 > VOICE_PRIORITY.place, 'the official order');
assert.ok(VOICE_PRIORITY.resultThree > VOICE_PRIORITY.skill1 && VOICE_PRIORITY.resultThree < VOICE_PRIORITY.faceEnemy);