feedback5 WV: 望's placed 棋子 occupy her stock like ones she deployed and a 棋子 that goes off goes back into it, so S1 / S2 and 阻回 keep cycling through the battle (the owner's decision of 2026-10-06, a deviation from the mode's 不消耗持有数量); golden unchanged (no corpus battle places her 棋子)
This commit is contained in:
1 parent
e2bb090f44
commit
ed5c1f2ab8
3 files changed
+72
-9
No files matched your search
+2
-1
@@ -121,7 +121,8 @@ its loadout's `skillIndex` / `moduleId` and no equipment (the copies' items went
|
||||
Token pieces: `{ kind:'token', tokenId, ownerUid, row, col, dir? }` — the manually deployable summons the player placed
|
||||
(data `placeable`, PRTS 卫戍协议/帮助 §战斗部署; user playtest #6). A piece marks the tile its summon deploys on: a talent
|
||||
summon the owner holds from the start (狼群, 海嗣, 流形, 凯瑟琳's 爬行号·防护单元 — facing the operator it shields) deploys
|
||||
with the board; a skill's summon (赫默 S2 医疗探机, 巫恋 S2 诅咒娃娃, "获得一个…") deploys once at the battle start, free
|
||||
with the board (望's 棋子 too, each one occupying her stock while it stands and going back into it as it leaves — the
|
||||
owner's decision of 2026-10-06, kits/ops/op-wang.js); a skill's summon (赫默 S2 医疗探机, 巫恋 S2 诅咒娃娃, "获得一个…") deploys once at the battle start, free
|
||||
and regardless of the holding (PRTS §作战阶段 "所有手动部署的召唤物,无视所属干员的持有状态…作战开始时立即部署一次"), then
|
||||
waits on its tile and takes the field there each time the skill gives one (stock ≤ 1, after the token's redeploy time
|
||||
once it left, free; never while its owner is off the field [ASSUMED] — a stocked one deploys as soon as the owner is
|
||||
|
||||
@@ -22,12 +22,19 @@
|
||||
// may). Module TRP-X "部署费用更低(-1)…可同时部署的陷阱数量提升(+1)": the 棋子 variant's cost 2 (the DP of its returns) and
|
||||
// deploy limit 7 (the hand count — the match's); its attributes in the stats.
|
||||
// - T1 铸子 (cnt / attack@max_spawn_cnt; "最多拥有7枚"): the 棋子 are hand pieces the player places; they deploy with the board
|
||||
// for free and without using her stock (stock = cnt at the start, at most STOCK_CAP; the skills add to it). 棋子 / 跟子
|
||||
// for free. Her stock (持有库存: the 棋子 in her hand — cnt at the start, at most STOCK_CAP; the skills add to it) counts
|
||||
// them — the owner's decision of 2026-10-06, a deliberate deviation from PRTS 卫戍协议/帮助 (placed summons "无视所属干员的
|
||||
// 持有状态,不消耗持有数量", which left her stock at cnt: one S1 / S2 cast reached the cap and 阻回 held her SP for the rest
|
||||
// of the battle): every deployment of a 棋子 (the battle start's and each return) takes one from it, like one she deployed
|
||||
// herself (never below 0 [ASSUMED: a 7th placed piece of TRP-X's deploy limit takes none]), and a 棋子 that leaves the
|
||||
// field (set off, or gone with her) goes back into it at once by the official summon rule — its card back in her hand
|
||||
// while its redeploy time runs (as shared/summoner.js's recall) —, at most the cap [ASSUMED: one over the cap is lost].
|
||||
// So "立即获得两枚棋子" and the 阻回 at the cap keep cycling through the battle. 棋子 / 跟子
|
||||
// that touch on a side (上下 / 左右) activate each other and stay active once activated [ASSUMED from the S2 备注]; an
|
||||
// enemy (air units too) on an active one's tile sets it off: its effect, then it is used up (a 棋子 leaves the field; a
|
||||
// 跟子 is gone) [ASSUMED: a trap is spent by its trigger]. A spent 棋子 comes back on its tile ("原地再部署") after its
|
||||
// redeploy time (2 s), paying its cost, while 望 is on the field — its own card returns to the stock as it leaves, so the
|
||||
// stock does not change [ASSUMED]. That return is the mode's deployment of her card: it counts as a 手动部署 for 铸子 —
|
||||
// redeploy time (2 s), paying its cost and one of her stock, while 望 is on the field. That return is the mode's
|
||||
// deployment of her card: it counts as a 手动部署 for 铸子 —
|
||||
// one 跟子 on a tile next to it (the PRTS order above), at most attack@max_spawn_cnt on the field [ASSUMED: the battle-start
|
||||
// deployment does not count]. When 望 leaves the field her 棋子 and 跟子 vanish (PRTS 分支特性信息); the 棋子 come back
|
||||
// with her.
|
||||
@@ -195,7 +202,7 @@ export default {
|
||||
const at = battle.time + Math.max(0, num(stone.base.respawnTime));
|
||||
battle.every(RETRY, (b, sched) => {
|
||||
if (stone.alive || stone.removed || b.finished) { sched.cancel(); return; }
|
||||
if (b.time + 1e-9 < at || !up(unit)) return;
|
||||
if (b.time + 1e-9 < at || !up(unit) || unit.mem.wang.stock < 1) return; // (one of her stock: the deployment takes it)
|
||||
const r = stone.homeR, c = stone.homeC;
|
||||
const s3on = unit.skill?.id === S3 && unit.skill.active && inHerRange(unit, r, c);
|
||||
if (groundFoeOn(b, r, c) && !s3on) return; // "陷阱无法放置于敌人已在的格子中"
|
||||
@@ -219,12 +226,16 @@ export default {
|
||||
battle.addBuff(unit, { key: 'trait:wangStone', flags: { untargetable: true }, persist: true, allowDead: true });
|
||||
battle.on('deploy', (ctx) => {
|
||||
if (ctx.unit !== unit) return;
|
||||
unit.mem.wangNode = { seq: ++owner.mem.wang.seq, act: false, h: false, v: false, stacks: 0 };
|
||||
const w = owner.mem.wang;
|
||||
unit.mem.wangNode = { seq: ++w.seq, act: false, h: false, v: false, stacks: 0 };
|
||||
w.stock = Math.max(0, w.stock - 1); // it occupies her stock (the owner's decision of 2026-10-06)
|
||||
}, { owner: unit });
|
||||
battle.on('death', (ctx) => {
|
||||
if (ctx.unit !== unit || battle.finished) return;
|
||||
unit.removed = false; // the piece is kept (Battle.redeploy accepts it; its hooks stay)
|
||||
unit.mem.wangNode = null;
|
||||
const w = owner.mem.wang;
|
||||
w.stock = Math.min(stockCap, w.stock + 1); // its card goes back into her stock (the official summon rule)
|
||||
scheduleReturn(battle, owner, unit);
|
||||
}, { owner: unit, priority: -10 });
|
||||
},
|
||||
|
||||
@@ -216,7 +216,8 @@ test('S1 取势 (AUTO, SP_FULL): the triggering enemy is 停顿 6.5 s and takes
|
||||
const sk = skillOf(tier, elite, S1);
|
||||
assert.deepEqual([sk.spCost, sk.bb.cnt, sk.bb['attack@atk_scale'], sk.bb['attack@sluggish']], elite ? [20, 2, 1.2, 6.5] : [21, 2, 1.05, 6.5], `T${tier}`);
|
||||
const { h, u, st } = field({ tier, elite, skill: 0, stones: [[10, 6], [10, 7]] });
|
||||
assert.deepEqual([u.skill.kind, u.skill.rule, u.mem.wang.stock], ['instant', 'SP_FULL', 6]);
|
||||
// her stock: 6 less the 2 placed 棋子 (the owner's decision of 2026-10-06 — see the stock test below)
|
||||
assert.deepEqual([u.skill.kind, u.skill.rule, u.mem.wang.stock], ['instant', 'SP_FULL', 4]);
|
||||
const e = h.spawn('enemy_dummy', { pos: [10, 7] });
|
||||
h.step();
|
||||
const slug = h.hooksOf('statusApplied').find((c) => c.target === e && c.status === 'sluggish');
|
||||
@@ -238,7 +239,7 @@ test('S1 取势 (AUTO, SP_FULL): the triggering enemy is 停顿 6.5 s and takes
|
||||
h.step();
|
||||
h.step();
|
||||
assert.equal(e2.buffs.filter((b) => b.key === 'wang:qushi').length, 2, `T${tier}: independent`);
|
||||
// the active part: +2 stock (6 → 7: the cap), then 阻回
|
||||
// the active part: +2 stock (6 → 7: the cap — both pieces are off the field, their cards back in her hand), then 阻回
|
||||
u.skill.gainSp(999);
|
||||
assert.ok(h.runUntil(() => u.skill.activations === 1, 1), `T${tier}: cast at full SP`);
|
||||
assert.equal(u.mem.wang.stock, 7, `T${tier}: 最多拥有7枚`);
|
||||
@@ -248,6 +249,56 @@ test('S1 取势 (AUTO, SP_FULL): the triggering enemy is 停顿 6.5 s and takes
|
||||
}
|
||||
});
|
||||
|
||||
test('her stock (the owner\'s decision of 2026-10-06): the placed 棋子 occupy it like ones she deployed; a 棋子 that goes off goes back into it at once and its return takes one again; at the cap one that goes off is lost to the cap, so 阻回 lifts with its return and S1 / S2 keep casting', () => {
|
||||
for (const skill of [0, 1]) {
|
||||
const S = `S${skill + 1}`;
|
||||
const { h, u, st } = field({ tier: 6, elite: true, skill, stones: [[10, 6], [10, 7]] });
|
||||
const w = u.mem.wang;
|
||||
assert.equal(w.stock, 6 - 2, `${S}: 6 less the 2 placed`);
|
||||
const a = at(st, 10, 6), b = at(st, 10, 7);
|
||||
let e = h.spawn('enemy_dummy', { pos: [10, 7] });
|
||||
h.step();
|
||||
assert.ok(!b.alive, `${S}: set off`);
|
||||
assert.equal(w.stock, 5, `${S}: its card is back in her stock at once`);
|
||||
h.b.kill(e, null);
|
||||
assert.ok(h.runUntil(() => b.alive, 5), `${S}: back on its tile`);
|
||||
assert.equal(w.stock, 4, `${S}: its return takes one`);
|
||||
// two casts: 4 → 6 → 7 (8, over the cap); 阻回 at the cap only
|
||||
u.skill.gainSp(999);
|
||||
h.step();
|
||||
assert.deepEqual([u.skill.activations, w.stock], [1, 6], `${S}: 立即获得两枚棋子`);
|
||||
h.step();
|
||||
assert.ok(!u.s.flags.noSp, `${S}: below the cap, no 阻回`);
|
||||
u.skill.gainSp(999);
|
||||
h.step();
|
||||
assert.deepEqual([u.skill.activations, w.stock], [2, 7], `${S}: 最多拥有7枚`);
|
||||
h.step();
|
||||
assert.ok(u.s.flags.noSp, `${S}: 阻回 at the cap`);
|
||||
const sp0 = u.skill.sp;
|
||||
h.run(2);
|
||||
assert.equal(u.skill.sp, sp0, `${S}: no SP under 阻回`);
|
||||
// at the cap: the piece that goes off is lost to the cap, its return takes one ⇒ 阻回 lifts, SP comes back
|
||||
e = h.spawn('enemy_dummy', { pos: [10, 6] });
|
||||
h.step();
|
||||
assert.ok(!a.alive, `${S}: set off at the cap`);
|
||||
assert.equal(w.stock, 7, `${S}: still the cap`);
|
||||
h.b.kill(e, null);
|
||||
assert.ok(h.runUntil(() => a.alive, 5), `${S}: back`);
|
||||
assert.equal(w.stock, 6, `${S}: its return took one`);
|
||||
h.step();
|
||||
assert.ok(!u.s.flags.noSp, `${S}: 阻回 lifted`);
|
||||
const sp1 = u.skill.sp;
|
||||
h.run(2);
|
||||
assert.ok(u.skill.sp > sp1, `${S}: her SP recovers again`);
|
||||
done(h);
|
||||
}
|
||||
// TRP-X: 7 placed 棋子 (its deploy limit) on a stock of 6 ⇒ 0, never below
|
||||
const { h, u, st } = field({ tier: 6, elite: true, mod: X, skill: 0, stones: [[10, 3], [10, 4], [10, 5], [10, 6], [10, 7], [10, 8], [10, 9]] });
|
||||
assert.ok(st.length === 7 && st.every((s) => s.alive), 'TRP-X: all 7 deploy');
|
||||
assert.equal(u.mem.wang.stock, 0, 'TRP-X: 7 placed on a stock of 6');
|
||||
done(h);
|
||||
});
|
||||
|
||||
test('S2 连星 (AUTO, SP_FULL): a triggered piece hits every enemy on its connected lines (its tile ± 3; air too) for 420 % / 480 % ATK arts and slows them 35 % / 40 % for 6 s — each slow on its own timer, added up, speed ≥ 0.1', () => {
|
||||
for (const [tier, elite] of [[5, false], [6, true]]) {
|
||||
const sk = skillOf(tier, elite, S2);
|
||||
@@ -308,7 +359,7 @@ test('S3 天下劫 (MANUAL, ACTIVE_RANGE 4-12, 20 bullets): passive — the piec
|
||||
assert.equal(u.skill.attackOverride()?.noAttack, true, `T${tier}: 停止攻击`);
|
||||
assert.equal(u.mem.wang.stock, 7, `T${tier}: +8, capped`);
|
||||
const fl = placed(h).map(([r, c]) => `${r},${c}`);
|
||||
assert.equal(fl.length, 7, `T${tier}: 6 + 8 − 7 over the cap`);
|
||||
assert.equal(fl.length, 5, `T${tier}: (6 − 2 placed) + 8 − 7 over the cap`);
|
||||
assert.deepEqual(fl.slice(0, 2).sort(), ['10,7', '9,5'], `T${tier}: the enemies' tiles first (${fl})`);
|
||||
assert.ok(h.hooksOf('damaged').some((c) => c.target === a && c.source === u && c.dmg.tags.includes('wang:stone')), `T${tier}: they set off`);
|
||||
// inside her range a 棋子 comes back onto an enemy ("可部署至敌人所在位置") — and sets off again
|
||||
|
||||
Reference in new issue
Block a user