fix: 准备阶段显示外勤医疗预备干员 (#315)

This commit is contained in:
YinqiMargatroid committed 2026-10-09 22:53:41 +08:00
1 parent 3b57f72704
commit 9db9f3ceea
9 files changed
+132 -15

No files matched your search

+47
View File
@@ -0,0 +1,47 @@
// 外勤医疗: the official preparation field already shows 预备干员-医疗; Touch replaces it at battle start.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { makeMatch } from './harness.js';
const MEDIC = 'char_605_cmedic';
const STAGE = 'act2autochess_m01';
test('外勤医疗 shows the reserve medic on every prep board and in prep scouting, without adding a movable piece', () => {
const h = makeMatch({ mode: 'coop', humans: 2, seed: 6301, fake: true }).start().toPrep();
h.setStage(STAGE);
const [holder, teammate] = [h.ps('p_0'), h.ps('p_1')];
assert.deepEqual(holder.privateView().prepMapChars, [], 'no medic without the strategy');
holder.bandId = 'band_amedic';
for (const ps of [holder, teammate]) {
const priv = ps.privateView();
assert.equal(priv.prepMapChars.length, 1);
const medic = priv.prepMapChars[0];
assert.deepEqual([medic.defId, medic.kind, medic.x, medic.y, medic.dir, medic.ownerId],
[MEDIC, 'token', 2, 10, 'RIGHT', ps.playerId]);
assert.ok(medic.uid < 0 && !priv.board.some((p) => p.uid === medic.uid), 'display only: no board piece to move or sell');
assert.equal(h.m.prepFieldMeta(ps).units.find((u) => u.uid === medic.uid)?.defId, MEDIC);
}
holder.bandId = null;
assert.deepEqual(teammate.privateView().prepMapChars, [], 'the preview goes away when nobody holds the strategy');
h.m.dispose();
});
test('外勤医疗 boss preparation shows both reserve medics on their matching halves, mirrored for the right player', () => {
const h = makeMatch({ mode: 'coop', humans: 2, seed: 6302, fake: true }).start().toPrep();
h.setStage(STAGE);
const m = h.m;
m.bossWaves = [{ players: ['p_0', 'p_1'], wave: { spawns: [] } }];
h.ps('p_0').bandId = 'band_amedic';
const [left, right] = [h.ps('p_0'), h.ps('p_1')];
const own = left.privateView().prepMapChars[0];
const mate = left.privateView().bossMate.units.find((u) => u.defId === MEDIC);
assert.deepEqual([own.y, own.x, own.dir], [10, 2, 'RIGHT'], 'own prep uses board coordinates');
assert.deepEqual([mate.y, mate.x, mate.dir, mate.ownerId], [3, 18, 'LEFT', 'p_1']);
const scout = m.prepFieldMeta(right);
assert.equal(scout.kind, 'boss');
const medics = scout.units.filter((u) => u.defId === MEDIC).sort((a, b) => a.x - b.x);
assert.deepEqual(medics.map((u) => [u.y, u.x, u.dir, u.ownerId]),
[[3, 2, 'RIGHT', 'p_0'], [3, 18, 'LEFT', 'p_1']]);
assert.notEqual(medics[0].uid, medics[1].uid, 'both model IDs remain distinct on the shared field');
m.dispose();
});
+40
View File
@@ -73,6 +73,46 @@ describe('render engine in headless Chrome', { skip }, () => {
});
}
test('外勤医疗 reserve medic is visible but not draggable in normal and right boss preparation', async () => {
const { page, problems } = await open('scene=prep&panel=0', 1600, 900);
const first = await page.evaluate(() => {
const v = window.__demo.view;
const st = JSON.parse(JSON.stringify(window.__demo.scene.state));
st.prepMapChars = [{ id: -1, uid: -1, kind: 'token', side: 'ally', ownerId: 'p_0',
defId: 'char_605_cmedic', name: '预备干员-医疗', spine: 'char_605_cmedic', avatar: 'char_605_cmedic',
area: 'board', x: 2, y: 10, dir: 'RIGHT', facing: 1, maxHp: 1202 }];
v.setPrep(st, { editable: true });
const medic = v.debug.views.get('m:-1');
const p = v.tileScreen(10, 2), rect = v.debug.app.view.getBoundingClientRect();
const out = { exists: !!medic, id: medic?.info.defId, x: medic?.x, y: medic?.y,
draggable: !!v.debug.pick.pieceAt(p.x - rect.left, p.y - rect.top) };
return out;
});
await wait(500);
await page.screenshot({ path: path.join(OUT, 'touch-prep-normal.png') });
const boss = await page.evaluate(() => {
const v = window.__demo.view;
v.setCamera('bossPrep', { side: 'R', instant: true });
const mirrored = v.debug.views.get('m:-1');
return [mirrored?.x, mirrored?.y, mirrored?.dir];
});
await wait(500);
await page.screenshot({ path: path.join(OUT, 'touch-prep-boss-right.png') });
const removed = await page.evaluate(() => {
const v = window.__demo.view;
const st = JSON.parse(JSON.stringify(window.__demo.scene.state));
st.prepMapChars = [];
v.setPrep(st, { editable: true });
return !v.debug.views.has('m:-1');
});
await page.close();
assert.deepEqual(problems, []);
assert.deepEqual(first, { exists: true, id: 'char_605_cmedic', x: 2, y: 10,
draggable: false });
assert.deepEqual(boss, [18, 3, 'LEFT']);
assert.equal(removed, true);
});
test('fx gallery: every sim fx kind, projectile and status renders without errors; board art in use', async () => {
const { page, problems } = await open('scene=fx&panel=0', 1280, 720);
// cycle through the whole FX_KINDS table (one kind every 0.5 game s = 0.25 real s), watching the FX system: shots