feedback1f WV: a knocked-out operator keeps its tile; 突袭 never lands on it
Player report F5 after 0.1.0: "突袭盟约的干员会移动到濒死干员的尸体上". Real. A knocked-out operator left the occupancy map at once and only its home tile stayed reserved. A 突袭 member that fell after its jump lay on the landing tile, which nothing reserved, so the next member's jump (same target, same scoring) landed on it; and a member's timed redeploy came back on its home where a teammate that had jumped there lay. Real matches (six real 突袭 members, 战场#07 / #08, R6 / R9 / R12, 96 battles): 6 placements on a body (3 jumps, 3 home redeploys) before, 0 of 526 jumps after. Official (PRTS 卫戍协议/帮助, 作战阶段 / 单位部署): - "干员退场后…原地留下一个“倒地干员”…满足再部署条件时,移除场上的该倒地干员 并自动部署至该位置" - "倒地干员所在地块视为可部署,但所有我方单位在此处的部署行为将被阻止" - "若干员被击倒的位置为其他干员或召唤物的初始位置,则在被击倒后,尝试返回其 自身的初始位置" Now (sim/Battle.js): - A knocked-out operator lies on `unit.body`: the tile it fell on, or its own home when it fell on another board piece's home and its home is free (one attempt at the knock-out, assumed). x / y / tileR / tileC keep where it fell, so the kill / death handlers still act there. - Every redeploy comes back there (restTile): the timed one, 不屈's and 阿戈尔's. A retreated operator still comes back on its home. - downOn(r, c): _deploy (redeploys, the 突袭 landing, summons), spawnDevice and relocate refuse the tile for every ally of the field; isReservedTile reports it, so every automatic picker skips it (突袭 raidTile, tactical points, summon / device pickers, 维娜's lions). The kit helpers that kept their own home-tile loop (tier1 summonTileFree, tier3 / tier4 freeTile) go through isReservedTile. - b.snap `down` entries gain the body tile: [id, respawnAt, respawnTime, state, row, col]. DOWN_STATE.WAIT_TILE becomes a safeguard only. Tests: test/sim/feedback1f-downed-tile.test.js (real Match / PlayerState / BattleSpec runs with real 突袭 chess, the 突袭 jump, the engine refusals, the return home); downelem and bonds_addon follow the official rule.
This commit is contained in:
1 parent
60ed4fdab9
commit
5a3d562b75
12 files changed
+374
-71
No files matched your search
+14
-12
@@ -1,6 +1,6 @@
|
||||
// test/sim/downelem.test.js — user playtest #4 items 8 and 9, sim side (server/sim/Battle.js snapshot / fieldMeta,
|
||||
// damage.js elementView): b.snap `down` lists the knocked-out operators waiting to redeploy on their own tile (the
|
||||
// client keeps them on the field knocked down with a redeploy countdown) and `elem` the element gauge each unit shows
|
||||
// damage.js elementView): b.snap `down` lists the knocked-out operators waiting to redeploy on the tile they lie on (the
|
||||
// client keeps them there knocked down with a redeploy countdown) and `elem` the element gauge each unit shows
|
||||
// (PRTS 元素: the fullest gauge, its 爆发冷却) — entries, states, and what is left out. User playtest #5 item 2: an
|
||||
// operator entering a battle knocked out (联防 carryState `down`, constants.js FORCED_EXIT) is down the same way.
|
||||
|
||||
@@ -16,7 +16,7 @@ const op = (id, stats = {}) => chessRec({ id, profession: 'WARRIOR', stats: { at
|
||||
const TOKEN = { name: '测试召唤物', stats: { maxHp: 100, atk: 0, def: 0, res: 0, blockCnt: 0, cost: 0, respawnTime: 0 } };
|
||||
const downOf = (h, id) => (h.snapshot().down || []).find((d) => d[0] === id) || null;
|
||||
|
||||
test('a knocked-out operator is `down` until it redeploys: its timer, then waiting for its tile / the DP; then back', () => {
|
||||
test('a knocked-out operator is `down` until it redeploys: its timer, then waiting for the DP (no ally takes its tile); then back', () => {
|
||||
const h = makeBattle({
|
||||
defs: { chess: { t_a: op('t_a'), t_b: op('t_b') } }, units: [{ chessId: 't_a', row: 9, col: 5 }, { chessId: 't_b', row: 10, col: 5 }],
|
||||
content: 'none', autoFinish: false, timeLimit: 120, flags: { dpInit: 0, dpPerSec: 1, dpMax: 99 },
|
||||
@@ -31,18 +31,20 @@ test('a knocked-out operator is `down` until it redeploys: its timer, then waiti
|
||||
approx(d[1], Math.round((t0 + 6) * 100) / 100, 0.011);
|
||||
approx(d[2], 6, 0.011);
|
||||
assert.equal(d[3], DOWN_STATE.COUNTING);
|
||||
assert.deepEqual(d.slice(4), [9, 5], 'the tile it lies on (player report F5 after 0.1.0)');
|
||||
assert.ok(h.b.fieldMeta().units.some((u) => u.id === a.id), 'a client joining now gets its UnitInfo');
|
||||
h.run(6.5);
|
||||
assert.equal(downOf(h, a.id)[3], DOWN_STATE.WAIT_DP, 'timer done, 6.5 DP < cost 12');
|
||||
const tok = h.b.spawnToken('p1', 'token_test', 9, 5, { def: TOKEN });
|
||||
assert.ok(tok && tok.alive, 'a summon stands on its tile');
|
||||
assert.equal(downOf(h, a.id)[3], DOWN_STATE.WAIT_TILE);
|
||||
h.run(7);
|
||||
assert.ok(!a.alive, 'no redeploy while its tile is taken');
|
||||
assert.equal(downOf(h, a.id)[3], DOWN_STATE.WAIT_TILE);
|
||||
h.b.retreat(tok, { reason: 'expired', permanent: true });
|
||||
h.step();
|
||||
assert.ok(a.alive && a.deployed, 'redeployed once the tile is free (DP 13.5 ≥ 12)');
|
||||
// "倒地干员所在地块视为可部署,但所有我方单位在此处的部署行为将被阻止" (PRTS 卫戍协议/帮助): WAIT_TILE (its tile taken)
|
||||
// is a safeguard only — no summon (or any ally) is deployed on the tile it lies on
|
||||
assert.equal(h.b.spawnToken('p1', 'token_test', 9, 5, { def: TOKEN }), null, 'no summon on its tile');
|
||||
assert.equal(h.b.isReservedTile(9, 5), true);
|
||||
h.run(5);
|
||||
assert.ok(!a.alive, 'no redeploy while the DP is short (11.5 < 12)');
|
||||
assert.equal(downOf(h, a.id)[3], DOWN_STATE.WAIT_DP);
|
||||
h.run(1);
|
||||
assert.ok(a.alive && a.deployed, 'redeployed on its tile once the DP is there (12.5 ≥ 12)');
|
||||
assert.deepEqual([a.tileR, a.tileC], [9, 5]);
|
||||
assert.equal(downOf(h, a.id), null);
|
||||
assert.equal(h.snapshot().down, undefined);
|
||||
assert.ok(h.eventsOf('deploy').some((e) => e[1] === a.id));
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
// Player report F5 after the 0.1.0 release: "突袭盟约的干员会移动到濒死干员的尸体上" — a 突袭 member jumping
|
||||
// ("保留技力立即再部署至一名地面敌人周围") landed on the tile of a knocked-out (濒死) operator lying there, and an
|
||||
// operator's timed redeploy came back on its home tile although another operator lay knocked out on it.
|
||||
// Official (PRTS 卫戍协议/帮助 §作战阶段 单位部署):
|
||||
// "干员退场后,将返回隐藏的待部署区,并原地留下一个“倒地干员”以供查看信息,满足再部署条件时,移除场上的该倒地干员并
|
||||
// 自动部署至该位置。"
|
||||
// "倒地干员所在地块视为可部署,但所有我方单位在此处的部署行为将被阻止。"
|
||||
// "若干员被击倒的位置为其他干员或召唤物的初始位置,则在被击倒后,尝试返回其自身的初始位置。"
|
||||
// So a knocked-out operator lies where it fell (on its own home tile when it fell on another board piece's home and its
|
||||
// own is free), comes back on that tile, and no ally deployment (a 突袭 landing, a redeploy, a summon, a device, a
|
||||
// move) takes it meanwhile.
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { makeBattle, chessRec, enemyRec, checkInvariants } from '../helpers/battleHarness.js';
|
||||
import { makeMatch } from '../match/harness.js';
|
||||
import { buildBattleSpec, createBattleFromSpec } from '../../server/sim/spec.js';
|
||||
import { inRange } from '../../server/sim/content/support/index.js';
|
||||
|
||||
const RAID = { raidShip: { count: 2, active: true, tier: 1, layers: 0 } };
|
||||
const raider = (id) => chessRec({ id, bonds: ['raidShip'], profession: 'WARRIOR', skill: null });
|
||||
const plain = (id) => chessRec({ id, bonds: [], profession: 'WARRIOR', skill: null });
|
||||
const tileOf = (u) => [u.tileR, u.tileC];
|
||||
const kill = (b, u) => b.dealDamage(null, u, { amount: 1e9, type: 'true' });
|
||||
/** The b.snap `down` entry of `u` ([id, respawnAt, respawnTime, state, row, col]) or null. */
|
||||
const downEntry = (b, u) => (b.snapshot().down || []).find((d) => d[0] === u.id) ?? null;
|
||||
/** Where the client draws the knocked-out `u`: the tile its `down` entry names (a 4-element entry: where it fell). */
|
||||
const bodyOf = (b, u) => { const d = downEntry(b, u); return d && d.length >= 6 ? d.slice(4) : tileOf(u); };
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// the player scenario on the real product path
|
||||
|
||||
/**
|
||||
* The normal field of a solo player at PREP of `round` (seed `seed`, stage `stageId`) with exactly `pieces`
|
||||
* ([chessId, row, col]) on the board: the real Match, PlayerState, chess data and round wave, built like
|
||||
* Match._ccField (the BattleSpec the browser and the server both build their Battle from).
|
||||
*/
|
||||
function realField({ pieces, round, seed, stageId }) {
|
||||
const h = makeMatch({ mode: 'solo', difficulty: 'NORMAL', seed }).start();
|
||||
const ps = h.ps('p_0');
|
||||
assert.ok(h.drive(() => { if (ps.lp > 0 && ps.lp < 300) ps.lp = 300; return h.m.phase === 'PREP' && h.m.round === round; }), `PREP R${round}`);
|
||||
h.setStage(stageId);
|
||||
for (const p of [...ps.board.values(), ...ps.hand.filter(Boolean)]) if (p.kind === 'chess') ps.returnCopies(p);
|
||||
ps.board.clear();
|
||||
ps.hand.fill(null);
|
||||
for (const [id, r, c] of pieces) ps.board.set(`${r},${c}`, ps.newPiece('chess', id));
|
||||
ps.recompute();
|
||||
const spec = buildBattleSpec({ ...h.m._normalOpts(ps), battleId: 'feedback1f', fieldId: 'n:p_0', kind: 'normal', content: h.m.battleContent });
|
||||
return createBattleFromSpec(spec, h.m.ds, { quiet: true, recordEvents: false });
|
||||
}
|
||||
|
||||
// Six 突袭 members (宴 休谟斯 斯卡蒂 瑕光 伊内丝 缄默德克萨斯 史尔特尔 仇白 耀骑士临光 — real chess) on 战场#07 / 战场#08 (下半)
|
||||
// against the real round waves: on 0.1.0 each run put a member on a knocked-out operator — a 突袭 landing on the body
|
||||
// of a member that fell after its own jump, or a member's timed redeploy on its home tile where a teammate lay that
|
||||
// had jumped there and fallen.
|
||||
const RUNS = [
|
||||
{ stageId: 'act2autochess_m03', round: 12, seed: 4, pieces: [['chess_char_4_04_a', 12, 2], ['chess_char_4_16_a', 10, 2], ['chess_char_5_07_a', 12, 5], ['chess_char_6_15_a', 10, 5], ['chess_char_6_17_a', 9, 4], ['chess_char_1_18_a', 11, 6]] },
|
||||
{ stageId: 'act2autochess_m04', round: 6, seed: 3, pieces: [['chess_char_3_12_a', 12, 3], ['chess_char_4_04_a', 11, 3], ['chess_char_4_16_a', 10, 3], ['chess_char_5_07_a', 9, 3], ['chess_char_6_15_a', 12, 4], ['chess_char_6_17_a', 11, 4]] },
|
||||
{ stageId: 'act2autochess_m04', round: 12, seed: 1, pieces: [['chess_char_2_09_a', 12, 3], ['chess_char_3_05_a', 11, 3], ['chess_char_3_12_a', 10, 3], ['chess_char_4_04_a', 9, 3], ['chess_char_4_16_a', 12, 4], ['chess_char_5_07_a', 11, 4]] },
|
||||
{ stageId: 'act2autochess_m04', round: 12, seed: 1, pieces: [['chess_char_2_09_a', 12, 2], ['chess_char_3_05_a', 10, 2], ['chess_char_3_12_a', 12, 5], ['chess_char_4_04_a', 10, 5], ['chess_char_4_16_a', 9, 4], ['chess_char_5_07_a', 11, 6]] },
|
||||
{ stageId: 'act2autochess_m04', round: 12, seed: 4, pieces: [['chess_char_4_04_a', 12, 3], ['chess_char_4_16_a', 11, 3], ['chess_char_5_07_a', 10, 3], ['chess_char_6_15_a', 9, 3], ['chess_char_6_17_a', 12, 4], ['chess_char_1_18_a', 11, 4]] },
|
||||
];
|
||||
|
||||
test('F5 real match: no 突袭 landing, redeploy or summon ever takes the tile of a knocked-out operator; it comes back where it lies', () => {
|
||||
let jumps = 0, downs = 0, comebacks = 0;
|
||||
const bad = [];
|
||||
for (const run of RUNS) {
|
||||
const b = realField(run);
|
||||
const tag = `${run.stageId} R${run.round} seed ${run.seed}`;
|
||||
const lay = new Map(); // knocked-out operator → the tile it lies on
|
||||
b.on('death', (c) => {
|
||||
const u = c.unit;
|
||||
if (c.reason !== 'killed' || u.kind !== 'op' || !b.isDown(u)) return;
|
||||
downs++;
|
||||
const body = bodyOf(b, u);
|
||||
lay.set(u, body);
|
||||
// it lies where it fell — on its own home when it fell on another board piece's home and its own is free
|
||||
const other = b.allyUnits.find((a) => a !== u && a.uid != null && !a.removed && a.homeR === u.tileR && a.homeC === u.tileC);
|
||||
const homeFree = !b.allyUnits.some((a) => a !== u && ((a.alive && a.tileR === u.homeR && a.tileC === u.homeC) || (!a.alive && !a.removed && b.restTile(a).join() === `${u.homeR},${u.homeC}`)));
|
||||
if (other && (u.tileR !== u.homeR || u.tileC !== u.homeC) && homeFree && body.join() !== `${u.homeR},${u.homeC}`) bad.push(`${tag} t=${b.time.toFixed(1)}: ${u.name} lies on ${other.name}'s home ${body} (its own ${u.homeR},${u.homeC} is free)`);
|
||||
else if (!other && body.join() !== tileOf(u).join()) bad.push(`${tag} t=${b.time.toFixed(1)}: ${u.name} fell on ${tileOf(u)} but lies on ${body}`);
|
||||
});
|
||||
b.on('deploy', (c) => {
|
||||
const u = c.unit;
|
||||
if (c.initial || u.side !== 'ally') return;
|
||||
if (u.kind === 'op' && (u.tileR !== u.homeR || u.tileC !== u.homeC) && !lay.has(u)) jumps++;
|
||||
for (const [d, t] of lay) {
|
||||
if (d === u || d.alive) continue;
|
||||
if (t[0] === u.tileR && t[1] === u.tileC) bad.push(`${tag} t=${b.time.toFixed(1)}: ${u.name} deployed on ${t} where ${d.name} lies knocked out`);
|
||||
}
|
||||
if (lay.has(u)) {
|
||||
const t = lay.get(u);
|
||||
lay.delete(u);
|
||||
comebacks++;
|
||||
if (t[0] !== u.tileR || t[1] !== u.tileC) bad.push(`${tag} t=${b.time.toFixed(1)}: ${u.name} lay on ${t} but redeployed on ${tileOf(u)}`);
|
||||
}
|
||||
});
|
||||
while (!b.finished && b.time < 400) b.step();
|
||||
}
|
||||
assert.deepEqual(bad, []);
|
||||
// the scenario: members jumped, fell and came back
|
||||
assert.ok(jumps >= 20 && downs >= 10 && comebacks >= 5, `jumps ${jumps}, knocked out ${downs}, redeploys ${comebacks}`);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// the rule, step by step (synthetic chess, flat stage)
|
||||
|
||||
test('F5 突袭: a member never lands on a knocked-out member\'s body; the fallen member comes back on the tile it lies on', () => {
|
||||
const defs = {
|
||||
chess: { r_a: raider('r_a'), r_b: raider('r_b') },
|
||||
enemies: { enemy_f5_dummy: enemyRec({ key: 'enemy_f5_dummy', hp: 1e7, speed: 0 }), enemy_f5_bait: enemyRec({ key: 'enemy_f5_bait', hp: 2500, speed: 0 }) },
|
||||
};
|
||||
// A idles from the start; B kills the bait in front of it first (~5 s), so it becomes idle later than A
|
||||
const h = makeBattle({
|
||||
defs, bonds: RAID, units: [{ chessId: 'r_a', row: 12, col: 3 }, { chessId: 'r_b', row: 10, col: 3 }],
|
||||
enemies: [{ key: 'enemy_f5_dummy', pos: [9, 8] }, { key: 'enemy_f5_bait', pos: [10, 4] }],
|
||||
});
|
||||
const A = h.unit('r_a'), B = h.unit('r_b');
|
||||
assert.ok(h.runUntil(() => A.tileR !== 12 || A.tileC !== 3, 12), 'A jumped');
|
||||
const L = tileOf(A);
|
||||
assert.deepEqual([B.tileR, B.tileC], [10, 3], 'B still busy / idle at home');
|
||||
kill(h.b, A);
|
||||
assert.ok(h.b.isDown(A), 'A knocked out');
|
||||
assert.deepEqual(downEntry(h.b, A).slice(4), L, 'A lies where it fell: b.snap down carries that tile');
|
||||
assert.equal(h.b.isReservedTile(L[0], L[1]), true, 'its tile is reserved for it');
|
||||
assert.equal(h.b.isReservedTile(12, 3), false, 'its home is not (only the body\'s tile blocks)');
|
||||
assert.ok(h.runUntil(() => B.tileR !== 10 || B.tileC !== 3, 20), 'B jumped');
|
||||
assert.notDeepEqual(tileOf(B), L, 'B did not land on A\'s body');
|
||||
assert.ok(inRange(B, h.enemy('enemy_f5_dummy')), 'B still lands next to the enemy, with it in range');
|
||||
// "满足再部署条件时,移除场上的该倒地干员并自动部署至该位置"
|
||||
assert.ok(h.runUntil(() => A.alive, 30), 'A redeployed after its timer');
|
||||
assert.deepEqual(tileOf(A), L, 'on the tile it lay on');
|
||||
assert.deepEqual([A.homeR, A.homeC], [12, 3], 'its home (the board tile) is unchanged');
|
||||
checkInvariants(h.b);
|
||||
});
|
||||
|
||||
test('F5 engine: every ally placement refuses the tile a knocked-out operator lies on — redeploy, summon, device, move', () => {
|
||||
const defs = { chess: { d_a: plain('d_a'), d_b: plain('d_b'), d_c: plain('d_c') } };
|
||||
const h = makeBattle({ defs, units: [{ chessId: 'd_a', row: 12, col: 3 }, { chessId: 'd_b', row: 10, col: 3 }, { chessId: 'd_c', row: 11, col: 5 }] });
|
||||
h.step();
|
||||
const b = h.b, A = h.unit('d_a'), B = h.unit('d_b'), C = h.unit('d_c');
|
||||
// A moved away like a 突袭 jump, then knocked out there
|
||||
b.retreat(A, { reason: 'raid' });
|
||||
assert.ok(b.redeploy(A, { free: true, tile: [9, 8] }));
|
||||
kill(b, A);
|
||||
assert.ok(b.isDown(A));
|
||||
assert.deepEqual(tileOf(A), [9, 8]);
|
||||
assert.equal(b.isReservedTile(9, 8), true);
|
||||
b.retreat(B, { reason: 'raid' });
|
||||
assert.equal(b.redeploy(B, { free: true, tile: [9, 8] }), false, 'a redeploy onto the body is refused');
|
||||
assert.ok(b.redeploy(B, { free: true }), 'B back home');
|
||||
assert.deepEqual(tileOf(B), [10, 3]);
|
||||
assert.equal(b.spawnToken('p1', 'token_10028_vigil_wolf', 9, 8), null, 'a summon onto the body is refused');
|
||||
assert.equal(b.spawnDevice('f5_device', 9, 8, { hp: 100 }), null, 'a device onto the body is refused');
|
||||
assert.equal(b.relocate(C, 9, 8), false, 'moving an operator onto the body is refused');
|
||||
assert.deepEqual(tileOf(C), [11, 5]);
|
||||
// a tactician at (9,6) whose range holds (9,8) — the nearer tile — and (9,9)
|
||||
assert.equal(b.findTacticalPoint({ baseRangeKeys: [9 * 21 + 8, 9 * 21 + 9], tileR: 9, tileC: 6, dir: 'RIGHT' })?.join(), '9,9', 'no tactical point on the body');
|
||||
// its own redeploy comes back there ("自动部署至该位置")
|
||||
assert.ok(b.redeploy(A, { free: true }));
|
||||
assert.deepEqual(tileOf(A), [9, 8]);
|
||||
assert.equal(b.isReservedTile(9, 8), true, 'standing there now');
|
||||
checkInvariants(b);
|
||||
});
|
||||
|
||||
test('F5 "若干员被击倒的位置为其他干员或召唤物的初始位置…尝试返回其自身的初始位置": a body on another piece\'s home goes back to its own', () => {
|
||||
const defs = { chess: { h_a: plain('h_a'), h_b: plain('h_b') } };
|
||||
const setup = () => {
|
||||
const h = makeBattle({ defs, units: [{ chessId: 'h_a', row: 12, col: 3 }, { chessId: 'h_b', row: 10, col: 3 }] });
|
||||
h.step();
|
||||
const b = h.b, A = h.unit('h_a'), B = h.unit('h_b');
|
||||
b.retreat(A, { reason: 'raid' });
|
||||
assert.ok(b.redeploy(A, { free: true, tile: [11, 6] }), 'A away from its home');
|
||||
b.retreat(B, { reason: 'raid' });
|
||||
assert.ok(b.redeploy(B, { free: true, tile: [12, 3] }), 'B on A\'s home (free: A is away)');
|
||||
return { h, b, A, B };
|
||||
};
|
||||
{
|
||||
const { h, b, A, B } = setup();
|
||||
let fellAt = null;
|
||||
b.on('death', (c) => { if (c.unit === B) fellAt = [B.tileR, B.tileC]; });
|
||||
kill(b, B);
|
||||
assert.ok(b.isDown(B));
|
||||
assert.deepEqual(fellAt, [12, 3], 'the death handlers (被击倒时 effects) still see where it fell');
|
||||
assert.deepEqual(downEntry(b, B).slice(4), [10, 3], 'B lies on its own home, not on A\'s (b.snap down)');
|
||||
assert.deepEqual(b.restTile(B), [10, 3]);
|
||||
assert.equal(b.isReservedTile(12, 3), false, 'A\'s home stays free');
|
||||
assert.equal(b.isReservedTile(10, 3), true);
|
||||
// A knocked out too: it lies where it is and comes back there
|
||||
kill(b, A);
|
||||
assert.deepEqual(downEntry(b, A).slice(4), [11, 6], 'A fell on no other piece\'s home: it stays');
|
||||
assert.ok(h.runUntil(() => A.alive && B.alive, 40), 'both redeploy');
|
||||
assert.deepEqual(tileOf(B), [10, 3]);
|
||||
assert.deepEqual(tileOf(A), [11, 6]);
|
||||
checkInvariants(b);
|
||||
}
|
||||
{
|
||||
// its own home taken (A moved onto it): the body stays where it fell [ASSUMED: one attempt, at the knock-out]
|
||||
const { b, A, B } = setup();
|
||||
b.retreat(A, { reason: 'raid' });
|
||||
assert.ok(b.redeploy(A, { free: true, tile: [10, 3] }), 'A on B\'s home');
|
||||
kill(b, B);
|
||||
assert.deepEqual(downEntry(b, B).slice(4), [12, 3], 'B stays on the tile it fell on');
|
||||
assert.equal(b.isReservedTile(12, 3), true);
|
||||
checkInvariants(b);
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user