Playtest #6 fixes: summons placed by hand, boss pool stall, bounties, 联防 leak counter, distinct offers, 机变 card text, phone buy tap, skill triggers, blocking, push force, 孤立, enemies, element bar

- #1 #2 skill / device summons (赫默's drone, 巫恋's doll, 凯瑟琳's devices) are hand cards placed by the player;
  placed summons deploy once at battle start, then a skill summon re-appears at its tile on each cast (the user's call)
- #3 叙拉古 隐匿 ends on time (32 + 0.4 × layers s); 忍冬 S3 迷彩 lasts until her next cast (official), kept apart from 隐匿
- #4 multi-round bounty cards last two battles (the user's call; MULTI_ROUND_BOUNTY_BATTLES), blue / red card text
- #5 the shared boss pool's float dust (≈3.6e-12 HP) stalled Final Assault leaders at 0 %; < 1 HP now clears the pool,
  and the team LP reaching 0 first is a defeat (PRTS)
- #6 #10 机变 cards show their official effect text; an invisible 详情 button no longer swallows the confirming tap on phones
- #7 live ×N counter of a leaker's enemies still on the 联防 field (LP loss stays capped at 10)
- #8 #15 #16 skill triggers per 技能策略: skill-range triggers, injured-ally heals (古米, 塞雷娅), tank take-damage
  triggers with a 3 s cooldown; 新约能天使 S2 shields the highest-aggro operator in range
- #9 official per-enemy model scales (威龙)
- #11 element bar under the unit's HP bar (white = 元素值 left, element-coloured refill after a burst), floor rounding
- #12 枯朽战车 kit per PRTS; every ranged enemy reaches its target's 0.25 collider
- #13 恐惧 wander (萨科塔之翼 at half HP, operator fears make enemies flee) with re-planning after pushes
- #14 push / pull distance by 力度 − 重量 (PRTS table); #17 every blocker attacks what it blocks; ASPD floor 20
- #18 炎佑 is 孤立: no heals or ally buffs
- #19 every free pick-one chess offer (promotion reward, 信标, 寻呼模块) shows different operators
- DESIGN §20 and the normative lines, SIM / META / DATA / PLAYING updated; 2747 unit tests and all 27 browser suites
  green; dev recordings regenerated
This commit is contained in:
sganggs committed 2026-10-01 19:08:23 +08:00
1 parent e6628f0cfe
commit 6464e4b46a
138 files changed
+7946 -1379

No files matched your search

+26 -14
View File
@@ -184,7 +184,9 @@ test('见行者 (3_07) 惊爆射击 pushes along her direction (DOWN: the enemy
checkInvariants(h.b);
});
test('薄绿 (3_08) 聚能涡旋 pulls toward the tile in front along her direction', () => {
test('薄绿 (3_08) 聚能涡旋 pushes the target towards her centre whatever her direction (PRTS 备注: a reversed radial push)', () => {
// PRTS 薄绿 S2 备注 "此技能的“拖拽”机制实际为反方向(指向薄绿方向)的推开" / 推与拉 (radial force): towards her centre,
// the official push distance (小力 vs weight 0: 1.7 tiles), stopping at the 急停 radius in front of her [ASSUMED]
const id = 'chess_char_3_08_a';
const run = (dir) => {
const h = makeBattle({ defs: { enemies: { enemy_d: dummy('enemy_d', { mass: 0 }) } }, timeLimit: 60, units: [{ chessId: id, row: 9, col: 4, dir }], enemies: [{ key: 'enemy_d', pos: [11, 4] }] });
@@ -195,10 +197,11 @@ test('薄绿 (3_08) 聚能涡旋 pulls toward the tile in front along her direct
h.run(3);
return h.enemy('enemy_d');
};
const up = run('UP');
assert.ok(up.y < 11 - 0.2 && Math.abs(up.x - 4) < 0.05, `UP: pulled straight down toward (10,4) (${up.x}, ${up.y})`);
const right = run('RIGHT');
assert.ok(right.x > 4.2, `RIGHT: pulled toward (9,5) (${right.x}, ${right.y})`);
for (const dir of ['UP', 'RIGHT']) {
const e = run(dir);
assert.ok(e.y < 11 - 0.2 && Math.abs(e.x - 4) < 0.05, `${dir}: pushed straight down towards her (${e.x}, ${e.y})`);
assert.ok(Math.hypot(e.x - 4, e.y - 9) >= 0.6708 - 1e-6, `${dir}: stops in front of her, not on her tile (${e.y})`);
}
});
test('乌尔比安 (5_05) S3 throws the anchor straight ahead along his direction (and triggers on the rotated grid)', () => {
@@ -223,18 +226,27 @@ test('乌尔比安 (5_05) S3 throws the anchor straight ahead along his directio
assert.ok(!r.h.hooksOf('skillStart').some((c) => c.unit === r.u), 'facing RIGHT: nothing ahead, no cast');
});
test('凯瑟琳 (4_11) places a device behind her operator along ITS direction, facing the operator', () => {
test('凯瑟琳 (4_11): a placed device shields the operator on the tile IT faces (range 1-1 rotated by its direction)', REAL, () => {
const id = 'chess_char_4_11_a', ally = 'chess_char_1_02_a';
const place = (dir) => {
const h = makeBattle({ units: [{ chessId: id, row: 12, col: 2 }, { chessId: ally, row: 10, col: 5, dir }], timeLimit: 30, hooks: [] });
// the device at (10,5); operators on its four neighbours; its direction picks the one it serves (user playtest #6)
const serve = (dir) => {
const h = makeBattle({
units: [
{ chessId: id, row: 12, col: 2, uid: 1 },
{ chessId: ally, row: 10, col: 6, uid: 2 }, { chessId: ally, row: 11, col: 5, uid: 3 },
{ chessId: ally, row: 9, col: 5, uid: 4 }, { chessId: ally, row: 10, col: 4, uid: 5 },
{ kind: 'token', tokenId: 'token_10041_cathy_catsld', ownerUid: 1, row: 10, col: 5, uid: 6, dir },
],
timeLimit: 30, hooks: [],
});
h.run(0.2);
const d = h.b.allyUnits.find((x) => x.defId === 'token_10041_cathy_catsld' && x.alive && x.mem.tr === 10 && x.mem.tc === 5);
assert.ok(d, `a device serves the ${dir} operator`);
return [d.tileR, d.tileC, d.dir];
const shielded = h.b.allyUnits.filter((x) => x.kind === 'op' && x.findBuff('cathy:shield')).map((x) => `${x.tileR},${x.tileC}`);
return shielded;
};
assert.deepEqual(place('UP'), [9, 5, 'UP'], 'below an UP operator, pointing up at it');
assert.deepEqual(place('RIGHT'), [10, 4, 'RIGHT']);
assert.deepEqual(place('LEFT'), [10, 6, 'LEFT']);
assert.deepEqual(serve('RIGHT'), ['10,6']);
assert.deepEqual(serve('UP'), ['11,5'], 'row 0 is the bottom: UP faces the row above');
assert.deepEqual(serve('DOWN'), ['9,5']);
assert.deepEqual(serve('LEFT'), ['10,4']);
});
test('余 (6_03) S3 fire wall runs through his tile perpendicular to his direction (UP / DOWN: his row; RIGHT / LEFT: his column)', REAL, () => {