65 lines
4.3 KiB
JavaScript
65 lines
4.3 KiB
JavaScript
// test/sim/feedback5-ulpia-own-board.test.js — community report of 2026-10-06 (item 27) 「乌尔比安使用3技能会在联防阶段跳到红门
|
|
// 后」. 乌尔比安 S3 必须开辟的通路 throws the anchor up to 6 tiles ahead (the nearest enemy of the line, else the farthest tile) and
|
|
// moves there when the tile "可以部署" (PRTS 备注 ③: the landing tile > the tile one beyond > his own tile). In a one-helper 联防
|
|
// (the helper's pieces on the left half, the enemies out of the middle gate at col 10; the fixture here is the escaped level's
|
|
// plain road, act1autochess_escaped_single — the 联防 field itself is the round's battlefield since 0.2.1) the right half is no
|
|
// tile his player deploys on, yet an anchor that met no enemy flew there and he moved behind the red gate for the whole
|
|
// skill. Now the landing must lie on his own board (Battle.onOwnBoard, the board region mapped onto the field).
|
|
// Run: node --test test/sim/feedback5-ulpia-own-board.test.js
|
|
|
|
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { makeBattle, enemyRec, checkInvariants } from '../helpers/battleHarness.js';
|
|
|
|
const ULPIA = 'chess_char_5_05_a';
|
|
const dummy = enemyRec({ key: 'enemy_anchor_dummy', hp: 1e9, speed: 0, mass: 0, atk: 0 });
|
|
|
|
/** 乌尔比安 cast S3 on `tile` of `kind`'s field; `enemy` = a parked enemy's tile or null. Returns where he stands after the cast. */
|
|
function cast({ kind = 'unite', stageId = 'act1autochess_escaped_single', tile = [10, 7], enemy = null, colOffset = 0 } = {}) {
|
|
const h = makeBattle({
|
|
kind, stageId, seed: 5, autoFinish: false, timeLimit: 120, defs: { enemies: { enemy_anchor_dummy: dummy } },
|
|
players: [{ playerId: 'p1', seat: 0, side: 'L', colOffset, units: [{ uid: 1, kind: 'chess', chessId: ULPIA, row: tile[0], col: tile[1] }], bonds: {} }],
|
|
});
|
|
h.step();
|
|
const u = h.unit(ULPIA);
|
|
const home = [u.tileR, u.tileC];
|
|
if (enemy) { h.spawn('enemy_anchor_dummy', { pos: enemy }); h.step(); } // (one tick: the enemy joins the tile index)
|
|
u.skill.gainSp(999, 'test');
|
|
// (its CUSTOM_RANGE trigger waits for an enemy on the line: with none the cast is made by hand, as a player's would be)
|
|
if (!u.skill.active) assert.ok(u.skill.activate('test'), 'S3 cast');
|
|
h.run(0.2);
|
|
const at = [u.tileR, u.tileC];
|
|
checkInvariants(h.b);
|
|
return { h, u, home, at };
|
|
}
|
|
|
|
test('one-helper 联防: an anchor that meets no enemy flies on past the middle gate — he stays on his own half (until 0.2.0 he moved behind the red gate)', () => {
|
|
const { h, u, home, at } = cast({ tile: [10, 7] });
|
|
assert.deepEqual(home, [10, 7]);
|
|
assert.ok(h.b.rect.c1 >= 13, 'the 联防 field spans both halves');
|
|
assert.deepEqual(at, home, `stays on (10,7) — not ${at}`);
|
|
assert.ok(h.b.onOwnBoard(u.player, 10, 7) && !h.b.onOwnBoard(u.player, 10, 13), 'cols 11+ are not his board');
|
|
assert.equal(h.b.allyUnits.filter((a) => a.kind === 'token' && a.alive).length, 0, 'no 从不混淆的方向: nothing to return from');
|
|
});
|
|
|
|
test('one-helper 联防: an enemy on his half still draws the anchor and he moves next to it (own board)', () => {
|
|
const { at } = cast({ tile: [10, 4], enemy: [10, 8] });
|
|
assert.deepEqual(at, [10, 8], 'he moves onto the anchor tile on his half');
|
|
});
|
|
|
|
test('two-helper 联防: the left helper never lands on the right helper\'s half; the right helper moves on its own half', () => {
|
|
const left = cast({ stageId: 'act1autochess_escaped_multi', tile: [10, 7] });
|
|
assert.deepEqual(left.at, left.home, `left helper stays (${left.at})`);
|
|
// the right-hand helper (colOffset 8): board col 3 → field col 11, enemy 3 tiles ahead on its own half
|
|
const right = cast({ stageId: 'act1autochess_escaped_multi', tile: [10, 3], colOffset: 8, enemy: [10, 14] });
|
|
assert.deepEqual(right.home, [10, 11]);
|
|
assert.deepEqual(right.at, [10, 14], 'moves on its own half');
|
|
assert.ok(right.h.b.onOwnBoard(right.u.player, 10, 14) && !right.h.b.onOwnBoard(right.u.player, 10, 7));
|
|
});
|
|
|
|
test('a normal battle is unchanged: the anchor stops at the field edge and he moves onto the farthest tile of his board', () => {
|
|
const { at, h, u } = cast({ kind: 'normal', stageId: 'flat', tile: [10, 3] });
|
|
assert.deepEqual(at, [10, 9], `6 tiles ahead, the last road tile before the gate column (${at})`);
|
|
assert.ok(h.b.onOwnBoard(u.player, 10, 9));
|
|
});
|