144 lines
7.6 KiB
JavaScript
144 lines
7.6 KiB
JavaScript
// 观战队友的整备区(游玩记录 #2 item 1「观战队友时看不到队友的未上场的干员」,建议见 GitHub #44
|
|
// 「看不见队友的待战栏位」):prep 侦察的 m.field(`Match.prepFieldMeta`)把被侦察玩家的手牌当作
|
|
// 单位放进手牌行(row 7,col = 手牌槽位,道具是 kind 'item')——客户端按自己整备区的同一渲染路径
|
|
// 画出这一行(app.js battleView / ItemView)。手牌变化(部署 / 购入 / 装备)跟棋盘变化一样触发
|
|
// 推送(`_prepScoutSig`);观战席副本与玩家完全一致(test/match/spectator.test.js)。客户端:
|
|
// test/ui/prep-bench.test.js。
|
|
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { GEO, PHASE } from '../../shared/constants.js';
|
|
import { DATA, makeMatch, give, giveItem, legalTileFor, chessOfTier } from './harness.js';
|
|
|
|
const MELEE = (c) => c.position === 'MELEE' && c.profession === 'TANK';
|
|
|
|
test('#44 prep scout: held pieces are units on the hand row; deploying moves them onto the field', () => {
|
|
const S = 's_spec';
|
|
const h = makeMatch({ mode: 'coop', humans: 2, seed: 44, fake: true, spectators: [S] }).start();
|
|
h.toPrep(1);
|
|
const m = h.m;
|
|
assert.equal(m.phase, PHASE.PREP);
|
|
const b = h.ps('p_1');
|
|
assert.deepEqual(m.handle('p_1', { t: 'g.ready', ready: false }), { ok: true });
|
|
for (const p of [...b.board.values(), ...b.hand.filter(Boolean), ...b.temp.filter(Boolean)]) {
|
|
if (p.kind === 'chess') b.returnCopies(p);
|
|
}
|
|
b.board.clear();
|
|
b.hand.fill(null);
|
|
b.temp.fill(null);
|
|
b.recompute();
|
|
const id = chessOfTier(1, MELEE).find((x) => m.pool.has(x));
|
|
const piece = give(m, b, id); // into the hand
|
|
assert.deepEqual(m.handle('p_0', { t: 'g.watch', fieldId: 'n:p_1' }), { ok: true });
|
|
assert.deepEqual(m.handle(S, { t: 'g.watch', fieldId: 'n:p_1' }), { ok: true });
|
|
|
|
for (const pid of ['p_0', S]) {
|
|
const first = h.lastTo(pid, 'm.field');
|
|
assert.equal(first.prep, true);
|
|
const u = first.units.find((x) => x.uid === piece.uid);
|
|
assert.ok(u, `${pid}: the held operator is a unit of the scout`);
|
|
assert.deepEqual([u.x, u.y], [0, GEO.HAND_ROW], `${pid}: standing on the first hand slot`);
|
|
assert.equal(u.kind, 'op');
|
|
assert.equal(u.items, undefined, 'no items equipped yet');
|
|
}
|
|
assert.deepEqual(h.lastTo('p_0', 'm.field').effects, h.ps('p_1').effectsView(), 'the scouted effects column rides the meta');
|
|
|
|
// deploying it is a hand AND a board change: one new push with the piece on the field and off the hand row
|
|
const [r, c] = legalTileFor(m, b, id);
|
|
assert.deepEqual(m.handle('p_1', { t: 'g.move', uid: piece.uid, to: { area: 'board', row: r, col: c }, dir: 'LEFT' }), { ok: true });
|
|
const last = h.lastTo('p_0', 'm.field');
|
|
const u = last.units.find((x) => x.uid === piece.uid);
|
|
assert.deepEqual([u.x, u.y], [c, r], 'deployed onto the watched board');
|
|
assert.equal(last.units.some((x) => x.uid === piece.uid && x.y === GEO.HAND_ROW), false, 'and gone from the hand row');
|
|
m.dispose();
|
|
});
|
|
|
|
test('#44 prep scout: a held item is a kind-item unit on the hand row; equipped items ride their operator', () => {
|
|
const h = makeMatch({ mode: 'coop', humans: 2, seed: 46, fake: true }).start();
|
|
h.toPrep(1);
|
|
const m = h.m;
|
|
const b = h.ps('p_1');
|
|
assert.deepEqual(m.handle('p_1', { t: 'g.ready', ready: false }), { ok: true });
|
|
for (const p of [...b.board.values(), ...b.hand.filter(Boolean), ...b.temp.filter(Boolean)]) {
|
|
if (p.kind === 'chess') b.returnCopies(p);
|
|
}
|
|
b.board.clear();
|
|
b.hand.fill(null);
|
|
b.temp.fill(null);
|
|
b.recompute();
|
|
const id = chessOfTier(1, MELEE).find((x) => m.pool.has(x));
|
|
const op = give(m, b, id);
|
|
const item = giveItem(m, b, 'chess_item_1_01_e_a'); // 维式重锤, into the hand
|
|
assert.deepEqual(m.handle('p_0', { t: 'g.watch', fieldId: 'n:p_1' }), { ok: true });
|
|
const first = h.lastTo('p_0', 'm.field');
|
|
const iu = first.units.find((x) => x.uid === item.uid);
|
|
assert.ok(iu, 'the held item is a unit of the scout');
|
|
assert.equal(iu.kind, 'item');
|
|
assert.equal(iu.y, GEO.HAND_ROW);
|
|
// equip the item onto the operator (still in the hand): the operator's unit carries the item id
|
|
assert.deepEqual(m.handle('p_1', { t: 'g.equip', itemUid: item.uid, targetUid: op.uid }), { ok: true });
|
|
const after = h.lastTo('p_0', 'm.field');
|
|
assert.equal(after.units.some((x) => x.uid === item.uid), false, 'the equipped item left the hand row');
|
|
const ou = after.units.find((x) => x.uid === op.uid);
|
|
assert.deepEqual(ou.items, ['chess_item_1_01_e_a'], 'the operator scouts with its equipment');
|
|
m.dispose();
|
|
});
|
|
|
|
test("PR #129 review: moving a hand piece to another slot is a scout change (x follows the slot), and the temp row rides along", () => {
|
|
const h = makeMatch({ mode: 'coop', humans: 2, seed: 47, fake: true }).start();
|
|
h.toPrep(1);
|
|
const m = h.m;
|
|
const b = h.ps('p_1');
|
|
assert.deepEqual(m.handle('p_1', { t: 'g.ready', ready: false }), { ok: true });
|
|
for (const p of [...b.board.values(), ...b.hand.filter(Boolean), ...b.temp.filter(Boolean)]) {
|
|
if (p.kind === 'chess') b.returnCopies(p);
|
|
}
|
|
b.board.clear();
|
|
b.hand.fill(null);
|
|
b.temp.fill(null);
|
|
b.recompute();
|
|
const id = chessOfTier(1, MELEE).find((x) => m.pool.has(x));
|
|
const a = give(m, b, id, 'hand', 0);
|
|
// a full hand (distinct plain equipment: nothing merges), so the temp piece stays in temp — a free hand slot would pull
|
|
// it in (PRTS 卫戍协议/帮助 §手牌区 "常规手牌区出现空位时自动移入")
|
|
const plain = Object.values(DATA.items).filter((i) => i.itemType === 'EQUIP' && !i.isGolden && i.kind === 'passive').map((i) => i.itemId ?? i.id);
|
|
for (let i = 1; i < b.hand.length; i++) b.hand[i] = b.newPiece('item', plain[i]);
|
|
const c = give(m, b, id, 'temp', 0); // 临时整备区: PRTS 帮助把它算进手牌区,一起侦察
|
|
assert.ok(b.temp.includes(c));
|
|
assert.deepEqual(m.handle('p_0', { t: 'g.watch', fieldId: 'n:p_1' }), { ok: true });
|
|
|
|
const first = h.lastTo('p_0', 'm.field');
|
|
const tu = first.units.find((x) => x.uid === c.uid);
|
|
assert.deepEqual([tu.x, tu.y], [GEO.TEMP_C0, GEO.TEMP_ROW], 'the temp piece scouts on the temp row (first slot, col 4)');
|
|
assert.equal(first.units.find((x) => x.uid === a.uid).x, 0);
|
|
|
|
// a hand piece moved to another slot keeps uid and id — the slot must be in the signature for the push to fire
|
|
assert.deepEqual(m.handle('p_1', { t: 'g.move', uid: a.uid, to: { area: 'hand', idx: 3 } }), { ok: true });
|
|
const last = h.lastTo('p_0', 'm.field');
|
|
assert.ok(last, 'a new scout push arrived');
|
|
assert.equal(last.units.find((x) => x.uid === a.uid).x, 3, 'the piece stands on its new hand slot');
|
|
m.dispose();
|
|
});
|
|
|
|
test('#44 prep scout: an empty hand adds no units and never an m.private to a spectator seat', () => {
|
|
const S = 's_spec';
|
|
const h = makeMatch({ mode: 'coop', humans: 2, seed: 45, fake: true, spectators: [S] }).start();
|
|
h.toPrep(1);
|
|
const m = h.m;
|
|
const b = h.ps('p_1');
|
|
assert.deepEqual(m.handle('p_1', { t: 'g.ready', ready: false }), { ok: true });
|
|
for (const p of [...b.board.values(), ...b.hand.filter(Boolean), ...b.temp.filter(Boolean)]) {
|
|
if (p.kind === 'chess') b.returnCopies(p);
|
|
}
|
|
b.board.clear();
|
|
b.hand.fill(null);
|
|
b.temp.fill(null);
|
|
b.recompute();
|
|
assert.deepEqual(m.handle('p_0', { t: 'g.watch', fieldId: 'n:p_1' }), { ok: true });
|
|
assert.deepEqual(m.handle(S, { t: 'g.watch', fieldId: 'n:p_1' }), { ok: true });
|
|
const first = h.lastTo('p_0', 'm.field');
|
|
assert.equal(first.units.length, 0, 'nothing held, nothing deployed: no units');
|
|
assert.equal(first.bench, undefined, 'no separate bench field (the hand rides units)');
|
|
assert.equal(h.allTo(S, 'm.private').length, 0, 'still no private state to a scout');
|
|
m.dispose();
|
|
});
|