feedback1 WA: Lappland counts her own first refresh; Mutation Cell is not consumed

Player reports after 0.1.0, #1 and #4.

#1 拉普兰德 (garrison_123, SERVER_GAIN_BOND_LAYER_BY_REFRESH_CNT) checked the
player's refresh count of the round, so a copy bought after the round's first
manual refresh never stacked that round. Players report the official
behaviour: the first refresh after acquiring her also stacks. Each copy now
counts the manual refreshes it witnessed this round (board or hand) through a
per-piece round counter (PlayerState.pieceRoundCount, ctx.incPieceCounter); an
elite merged this round keeps the highest count of its copies [ASSUMED]. The
"本回合每刷新过1次" multiplier traits keep the player's count.

#4 突变细胞 destroyed itself after one transformation. Official text never
says 销毁 (every consumable's does), PRTS notes "原干员销毁,获得一名高一阶的随机
初始干员", and players re-inject the cell every round. The built-in now replaces
the carrier with a random normal operator one tier higher (max 6) and returns
the carrier's equipment, the cell included, to the hand
(transformChess returnItems); the content override is gone. The item card
shows the rule (items.json note, build-data ITEM_RULES); bots inject their
least valuable single normal operator below tier 6 (bot.js cellTarget).
This commit is contained in:
sganggs committed 2026-10-03 01:47:52 +08:00
1 parent 7f134737ce
commit f8e35d5055
17 files changed
+514 -54

No files matched your search

+13 -2
View File
@@ -20,6 +20,10 @@
// * [ASSUMED] 余 SERVER_MOST_BOND: ties between most-member bonds are shuffled; the chess is a copy-weighted pool roll
// of any tier (the text gives no tier cap); a bond without an available chess falls through to the next tied one.
// * [ASSUMED] 松果: the "免费特殊招募" is a free pick-one offer of `rewardOffer.count` (3) chess of the pool's tier.
// * 拉普兰德 SERVER_GAIN_BOND_LAYER_BY_REFRESH_CNT "若为本回合首次主动刷新": per copy — the first manual refresh this
// operator witnesses in the round (players' report after 0.1.0); an elite merged this round keeps its copies'
// count [ASSUMED]. "本回合每刷新过1次" (SERVER_ADD_REFRESH_CNT_MULTIPLIER_BOND_LAYER, 阿罗玛 / 安洁莉娜 / 售出时)
// fires on another event and reads the player's refreshes of the round (roundStats), like 本回合每获得过 / 每花费.
import { metaBonds, frontPiece, behindPiece, distinctTiers } from '../support/meta.js';
@@ -188,11 +192,18 @@ H.SERVER_ADD_REFRESH_CNT_MULTIPLIER_BOND_LAYER = {
},
};
// 拉普兰德 "<刷新时>若为本回合首次主动刷新…,此干员在整备区时也有效": the refresh count is the operator's own — the manual
// refreshes this copy witnessed this round (board or hand), so a 拉普兰德 bought after the round's first refresh still
// fires on the next one (players' report after 0.1.0: "获得该干员后该回合的首次刷新" also stacks — the official behaviour;
// read as each trait instance counting its own SERVER_REFRESH_SHOP triggers against bb.refresh_cnt). A re-triggered trait
// (ev.trigger) is no manual refresh: it neither fires nor counts. The copies of an elite merged this round pass on their
// count [ASSUMED] (PlayerState.pieceRoundCount); a new copy (bought — after a sale too —, granted) starts at 0.
H.SERVER_GAIN_BOND_LAYER_BY_REFRESH_CNT = {
onRefresh(ctx, ev) {
if (ev && ev.trigger) return;
const { bb, bbStr, garrison } = ctx.source;
if ((ctx.roundStats().refreshes | 0) !== num(bb.refresh_cnt, 1)) return;
const { bb, bbStr, garrison, piece } = ctx.source;
if (!piece || !Number.isInteger(piece.uid) || piece.uid <= 0) return;
if (ctx.incPieceCounter(piece.uid, 'refreshes') !== num(bb.refresh_cnt, 1)) return;
addAll(ctx, ids(bbStr.bond), num(bb.layer), requireActiveOf(garrison));
},
};
+5 -22
View File
@@ -3,17 +3,17 @@
// The engine built-ins (server/match/builtinMeta.js) already implement most consume-on-equip items and Arts from the
// concrete item's params; they are reviewed and kept (盟约之币, 骑士储蓄罐, 随身身份牌, 精打细算玩偶, 简易通讯机 (tier ≤
// shop level), 见钱眼开玩偶, 人事部文档 (cap 9), 博士投影 (golden now / normal at the next round start), 拟态物质, 信标,
// 商业包装方案 (count from the concrete record: 8 / golden 7)). The Arts' rangeGrid (画卷 = placed tile + the tile in
// front) and the per-round limit are engine rules.
// 商业包装方案 (count from the concrete record: 8 / golden 7), 突变细胞 (after the battle the carrier becomes a NORMAL
// random tier+1 operator, max 6; its equipment — the cell too, which is not consumed (player feedback after 0.1.0) —
// returns to the hand)). The Arts' rangeGrid (画卷 = placed tile + the tile in front) and the per-round limit are engine
// rules.
// Overridden / added here (a built-in, when present, is wrapped — never re-implemented):
// 画卷 the copy keeps the target's items; a copied normal item that pairs with an owned one merges and the
// golden stays in the hand (the built-in equipped the merged golden on the copy, and its live loop over
// the target's items skipped the item after a merge)
// 紧急调度券 a shop operator leaves its slot only when it was actually granted (built-in cleared the slot first)
// 寻呼模块 the special refresh shows `refresh_cnt` DIFFERENT operators (fewer when the pool has no more)
// 突变细胞 after the battle the carrier becomes a NORMAL random tier+1 operator; its other equipment goes back to
// the hand (built-in kept it on the new operator)
// 教鞭 trap_create_self_choice {choice_event: hunter_band_1}: the bounty is a 战术特训 card (choices.json
// 教鞭 trap_create_self_choice {choice_event: hunter_band_1}: the bounty is a 战术特训 card (choices.json
// cards.bounty payout `perfect`, e.g. 战术特训·飞行I "若各自行动阶段就达成完美作战,获得1资金") — PRTS
// 卫戍协议:盟约 下半/PRTS盟约记录 §法术 教鞭 "于3个战术特训的悬赏任务中选择一项", §机变阶段 "※以下悬赏任务仅由
// 法术教鞭生成", and 杜宾 加练! "<教鞭>:使用后为下场战斗添加额外敌人,若自身战斗完美作战可获得资金" (user
@@ -103,23 +103,6 @@ export function registerMeta(registry) {
},
}));
// 突变细胞 — char_chess_transformation_equip
wrap(registry, 'chess_item_5_08_e', () => ({
onBattleResult(ctx) {
const { piece, holder } = ctx.source;
if (!piece || !holder) return;
const tier = Math.min(6, ctx.gd.tierOf(holder.id) + 1);
const id = ctx.rollChess({ tier });
if (!id) return;
const others = (ctx.piece(holder.uid)?.items || holder.items || []).filter((it) => it && it.uid !== piece.uid);
ctx.destroyPiece(piece.uid);
for (const it of others) {
if (ctx.destroyPiece(it.uid)) ctx.grantItem(it.id, { source: 'mutation' });
}
ctx.transform(holder.uid, ctx.gd.baseIdOf(id));
},
}));
// 教鞭 / “神秘顾客” — trap_create_self_choice {choice_event}: 教鞭 a 战术特训 card, “神秘顾客” a band bounty (enemyeffect_b_*)
for (const [key, family] of [['chess_item_6_03_m', isTraining], ['chess_item_6_01_m', isBandBounty]]) {
wrap(registry, key, (base) => ({