feedback1 cell: a 突变细胞 transformation gains the new operator into the 整备区 and frees the carrier's tile (pointed out in PR #2)

Official gameplay footage (bilibili BV1vzyVBuEN9 at about 8:24, BV1Qkw1zMEoR at about 7:25) shows the
next prep with the carrier's tile empty, one more deployment left, and the returned equipment plus the
new tier+1 operator on the bench, deployed by hand afterwards. That is the PRTS 备注 read as written
("生效时,原干员销毁,获得一名高一阶的随机初始干员"): a destroy followed by a gain. The closed PR #2 made
the same claim from a playtest.

- PlayerState.transformChess: the carrier is destroyed wherever it stands (board tile freed, summons
  removed, copies back to the pool); its equipment, the cell included, returns to the hand first
  (overflow temp, auto-merge); then the new operator is gained through acquireChess like any gained
  operator (hand, overflow temp, the no-room rule of every gain; no summon card until it is deployed).
  The returnItems option is gone (the cell's built-in was its only caller).
- A merge the gain completes merges like any gained copy: the elite takes a consumed deployed copy's
  tile, else the hand. _mergeChess loses fromKey / fromDir, so the destroyed carrier's tile never
  counts (PR #2 had kept that path; not adopted); audit.js drops its exception for it.
- builtinMeta, ctx.transform, items/meta.js and bot.js comments follow. Bots and AI 托管 deploy the
  gained operator in their normal lineup step (no bot change needed; a real co-op round pins it).
- ITEM_RULES note and implFormula for the item card; data/items.json rebuilt with build-data --offline.
- Tests: facing, merge, playtest6-elite-to-board and items no longer pin the kept tile; feedback1-meta
  covers a deployed and a bench carrier, hand full -> temp, hand and temp full, a merge with and
  without a deployed copy (never the carrier's tile), 商业包装方案's count on the returned item, and bots /
  AI 托管 redeploying; feedback1-cell checks the new note.
This commit is contained in:
sganggs committed 2026-10-03 15:18:42 +08:00
1 parent 842e1e13c4
commit 91c9b21d7f
14 files changed
+400 -178

No files matched your search

+19 -1
View File
@@ -4,7 +4,7 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { makeBattle, chessRec, enemyRec, checkInvariants } from '../helpers/battleHarness.js';
import { makeMatch, give, giveItem, DATA } from '../match/harness.js';
import { makeMatch, give, giveItem, DATA, legalTileFor } from '../match/harness.js';
import { createRegistry } from '../../server/match/effectsMeta.js';
import { lendItemEffects, itemGrants, PRIO_REVIVE } from '../../server/sim/content/items/battle.js';
import { unitBonds } from '../../server/sim/content/support/index.js';
@@ -993,6 +993,24 @@ test('突变细胞: after a battle the carrier becomes a random NORMAL tier+1 op
cover(A('5_08'), B('5_08'));
});
test('突变细胞: a DEPLOYED carrier leaves the field — the new operator is gained into the 整备区, the deploy slot comes back (PR #2)', () => {
// official footage (bilibili BV1vzyVBuEN9, BV1Qkw1zMEoR): the tile is empty at the next prep and the new operator waits
// on the bench; the case added by the closed PR #2, on the destroy-then-gain rule (DESIGN §21.1)
const { m, ps, equip } = setup({ seed: 3 });
const cid = plain((c) => c.tier === 2)[0];
const holder = give(m, ps, cid, 'board', legalTileFor(m, ps, cid));
assert.deepEqual(equip(giveItem(m, ps, A('5_08')), holder), OK);
assert.equal(ps.deployCount, 1, 'the carrier is deployed');
m.dispatch(ps, 'onBattleResult', { result: {}, lpLoss: 0, perfect: true });
assert.equal(ps.board.size, 0, 'the carrier left the field');
assert.equal(ps.deployCount, 0, 'the deploy slot came back');
const chess = ps.hand.filter((p) => p && p.kind === 'chess');
assert.equal(chess.length, 1, 'the new operator waits in the 整备区');
assert.equal(DATA.chess[chess[0].id].tier, 3, 'the random tier+1 operator');
assert.equal(DATA.chess[chess[0].id].isGolden, false);
assert.ok(handIds(ps, 'item').includes(A('5_08')), 'the cell back in the hand');
});
test('人事部文档: deploy cap becomes 9 (a second copy adds nothing)', () => {
const { m, ps, equip } = setup();
const t = give(m, ps, plain((c) => c.tier === 1)[0], 'hand');