1065 lines
111 KiB
Markdown
1065 lines
111 KiB
Markdown
# DESIGN §25 — 0.2.0
|
||
|
||
Part of [DESIGN.md](../DESIGN.md) (the index; section numbers are global).
|
||
|
||
## 25. 0.2.0 — the maintainability refactor, two languages, 补位, 自选编队, fidelity fixes, the 0.1.4 ports, release packaging
|
||
|
||
0.2.0 was built on `feedback5`, branched from feedback4 at 583899d (0.1.3, the golden-result harness and part of 0.1.4);
|
||
later merges of feedback4 brought the rest of 0.1.4 in. The workstreams, each on its own `fb5-*` branch, each merged
|
||
after review with its golden scenarios named: R1–R6 (refactor, tooling), W5A (golden results), W5B / W5D / W5G /
|
||
K1–K3 / W5N (补位), W5H / W5K / O1–O24 (自选编队 and its operator kits), W5I / W5S (languages, phases 1 and 2), W5C /
|
||
W5E / W5F / W5J / W5L (fidelity, wave 1), WE1 / WE2 (the follow-ups the kit waves reported), W5M, W5R and the feedback4
|
||
merges (the 0.1.4 ports), W5V (the owner's items of 2026-10-06), W5U (packaging), W5T (the docs) and W5Y (round 18:
|
||
three GitHub issues and three community PRs). Each rule was
|
||
checked against the official data and PRTS; anything no source backs is marked [ASSUMED].
|
||
The normative sections were rewritten with the streams: §0 (the DIY slots), §2 (the layout), §5.5 (the enemy damage
|
||
frame, the block-count target rule), §5.6 (the trigger rules), §8.1 / §8.3 (`welcome.diyKitted`, `standIns`, `diy`,
|
||
`diyBanned`), §16 (干员持有, 自选编队). Where each is handled: refactor and tooling → §25.1; Chinese and English →
|
||
§25.2; 补位 → §25.3; 自选编队 and the 71 operator kits → §25.4; trigger rules (the larger-range rule, AUTO skills) →
|
||
§25.5; fidelity fixes of wave 1 (GitHub #41, #49, #82, #96 / #137, #107, #116; 伺夜's 狼群; Touch) → §25.6; WE1, sim
|
||
rules (GitHub #181, #187 / #170, follow-ups) → §25.7; WE2, data / match / UI (follow-ups, GitHub #148) → §25.8; the
|
||
0.1.4 ports → §25.9 (the last two, W4D's sleep rule and W4C's board tap → §25.9.1 / §25.9.2); the settled decisions,
|
||
what stays [ASSUMED] and the questions left to the owner → §25.10. The closing additions: the owner's decisions of
|
||
2026-10-06 (望's stock, skill triggers through summon areas, the 突袭 landing, GitHub #148) and the items the sources
|
||
settled (泥岩's 闭锁; 忍冬, 深靛, 阿) → §25.11; release packaging and the asset manifest (the 自选 voices, the summons
|
||
with no Spine model) → §25.12; round 18 — 拟态物质 at the copy cap (GitHub #207), 华法琳's 7 / 14 (GitHub #175, PR #192),
|
||
a merged elite 拉普兰德 as a new one (GitHub #169), the leader pool per player alive (PR #209), the flying lift and two
|
||
model quirks (PR #211) → §25.13; the community reports of 2026-10-06 (the 孤岛风云 prisoners drawn freed, 忍冬's trigger, a
|
||
bounty burned to death by the 活性源石, 枯朽之种 paying a bounty) → §25.14.
|
||
|
||
Decisions of the owner: 2026-10-04 — the server stays on plain `node:http` + `ws`, no web framework (§25.1);
|
||
2026-10-05 — the 补位 plan (§25.3); the 自选编队 rules, the collab operators out of the pool, ISW-A refused (§25.4);
|
||
Chinese by default with an English switch, official English game texts, PR #70's translations reused with credit
|
||
(§25.2); the larger-range trigger rule on the basic strategy, the SEARCH row and 深巡 S2, every 自选 重装 cast with an
|
||
enemy in range, 纯烬艾雅法拉 S1 at full SP, 伺夜 S1 only with his pack on the field (§25.5); 2026-10-06 — a chess the player
|
||
does not own shows as its stand-in everywhere (the owner's recall of the official mode, §25.3); the enemy damage frame
|
||
kept (§25.7.2); 望's placed 棋子 count in her stock, skills that act through summons cast on an enemy in a summon's area,
|
||
a melee 突袭 member lands where it can block (§25.11); 华法琳's granted trait at the data's 7 / 14, replacing the 12 / 24
|
||
lock (§25.13.2); a newly merged elite 拉普兰德 counts as a new 拉普兰德 (§25.13.3); the leader pool = bloodPoint × the players
|
||
alive at the fight's start, adopting PR #209 and replacing 「保持固定血量」 (§25.13.4); flying units at 1.3 tiles and the two
|
||
model quirks of PR #211 (§25.13.5); the bounty pays whenever its enemy dies (relayed with the community
|
||
reports, §25.14.3).
|
||
|
||
### 25.1 Refactor and tooling: the big files split, golden results, lint, types, import boundaries (refactor plan; owner's decision of 2026-10-04: no web framework) — `server/http/`, `server/match/match/`, `server/match/player/`, `server/sim/battle/`, `content/enemies/`, `kits/ops/`, `public/js/ui/gameLogic/`, `render/fx/`, `render/app/`, `screens/game/`, `tools/golden.mjs`, `tools/check-imports.mjs`, `eslint.config.js`, `jsconfig.json`
|
||
|
||
- **Why**: the files every fix touched had grown to thousands of lines (`Match.js` 3237, `enemies.js` 3162,
|
||
`Battle.js` 2465, `fx.js` 2259, `render/app.js` 2046, `gameLogic.js` 1913, `PlayerState.js` 1673, the six kit tiers
|
||
864–3362 each), and the new operator kits needed one file per operator. **Official**: none — nothing a player sees
|
||
changes (refactor plan rule 1).
|
||
- **Safety net first** (W5A, merged on feedback4 before the refactor; `test/golden/README.md`): `tools/golden.mjs` runs a
|
||
seeded corpus through the production BattleSpec path and `Match` with a `VirtualScheduler` and reduces every scenario
|
||
to a digest — families `roster` (every chess record × skill × module, every stage and enemy kind), `bonds` (every
|
||
bond at 1 and 999 layers), `fields` (every leader, 联防 with 1 and 2 helpers), `matches` (bot matches to the end), and
|
||
since 0.2.0 `standins` (§25.3) and `diy` (§25.4). `npm test` checks the fast subset, `GOLDEN_FULL=1` / `npm run
|
||
golden` everything; a refactor never changes the files, a gameplay change regenerates them in the same commit and
|
||
names every scenario that moved (the rule every 0.2.0 stream followed).
|
||
- **Now** (R1–R5, each a pure move listed in `.git-blame-ignore-revs`, then a docs commit; golden unchanged after each):
|
||
1. R1: `server/index.js` (786 lines → 110) keeps `startServer()` and the same 15 exports; the code is in
|
||
`server/http/` (config, websocket, static, media, files, buildTag, routes, common, boot). Still plain `node:http` +
|
||
`ws` (the owner's decision of 2026-10-04: no Hono); response header order, the /healthz keys, the banner and the
|
||
`/data.js` stand-in text are byte for byte the same (a scripted fingerprint of 51 requests matched).
|
||
2. R2: `Match.js` (3237 → 383) and `PlayerState.js` (1673 → 239) keep the class, the constructor and the interface
|
||
header; their 167 / 87 members moved verbatim into 16 / 9 per-concern method containers (`server/match/match/`,
|
||
`server/match/player/` — W5K added `diy.js` later; shared constants in `common.js`), installed on the prototype in
|
||
a fixed order — a name defined twice throws.
|
||
3. R3: `Battle.js` (2465 → 189) the same way into `server/sim/battle/` (131 methods, 14 containers + `util.js`);
|
||
`content/enemies.js` (3162 → 321) into `content/enemies/` (helpers, archetypes, one file per special type,
|
||
leaders) with the `KITS` order kept.
|
||
4. R4: the 129 kits of `kits/tier1..6.js` became `kits/ops/<chessId>-<codename>.js` (the code name = the charId
|
||
without `char_<n>_`; the chess id is the unique key — 锡人, 耶拉, 华法琳 are two chess each), helpers shared by a
|
||
tier in `kits/shared/tierN.js`, the registry `kits/index.js` (a guarded dynamic import per file: a broken file only
|
||
drops its own kit to the generic one); `kits/README.md` is the kit guide with the fidelity checklist. The
|
||
`tier*.js` re-export shims were removed in WE2 (§25.8.8).
|
||
5. R5: the client — `ui/gameLogic.js` (1913 → 47) and `render/fx.js` (2259 → 45) became barrels over
|
||
`ui/gameLogic/` (18 modules) and `render/fx/` (15); the field view's helpers moved to `render/app/` and the match
|
||
screen's standalone parts to `screens/game/` (same exports).
|
||
- **Tooling** (R6): `npm run lint` — a correctness-only ESLint (`eslint.config.js`; no formatter, warnings allowed);
|
||
`npm run typecheck` — `tsc --checkJs` over a first slice (`jsconfig.json`: `shared/` but `protocol.js` /
|
||
`bandBonds.js`, `sim/rng.js`, `dir.js`, `constants.js`, the typedefs of `types/core.js`; `types/README.md` says how to
|
||
widen it); `npm run check:imports` — `tools/check-imports.mjs`: `server/sim/` (served to browsers) imports neither the
|
||
match, the lobby, the entry, the net layer, `public/` nor a Node builtin, `server/match/` neither `public/` nor the
|
||
net layer; the one listed exception is `sim/nodeData.js`, the Node-only loader (`test/check-imports.test.js` pins the
|
||
list); `tools/package.mjs` (+ `--lite`) builds the release zips from a runtime allowlist (W5U, §25.12).
|
||
CI gained a tooling job (lint, imports, typecheck; once, not per matrix entry).
|
||
- **Measured**: a match now loads about 340 small script modules; over HTTP/1.1 at 100 ms latency a cold load took
|
||
13.4 s instead of 9.8 s, so docs/DEPLOY.md recommends HTTP/2 at the reverse proxy (the browser sim warms up during the
|
||
band draft, so play is not delayed).
|
||
- Tests: `test/content/kits_layout.test.js` (every `ops/` file listed once, named after its chess id and charId, one
|
||
registry key, no Node-only import, no clock or `Math.random`), `test/check-imports.test.js`, `test/version.test.js`
|
||
(reads the banner / `/healthz` from their new files), `test/docs-consistency.test.js` (reads the classes as their
|
||
façade plus method modules); `GOLDEN_FULL=1 node --test test/golden.test.js` after every refactor commit.
|
||
- Docs: docs/ARCHITECTURE.md (the map of the code after the split) and CONTRIBUTING.md (setup, tests, the fidelity
|
||
rules, conventions) are new in 0.2.0; §2 lists every file.
|
||
|
||
### 25.2 Chinese by default, an English switch (W5I, phase 1; W5S, phase 2; PR #70 by @YuriRestia; the owner's decision of 2026-10-05) — `shared/i18n.js`, `shared/i18nData.js`, `tools/build-i18n.mjs`, `tools/i18n.mjs`, `public/i18n/en.json`, `data/i18n/en.json`, `public/js/ui/lang.js` (`sentText`), docs/I18N.md
|
||
|
||
- **Seen**: English-speaking players asked for an English interface. PR #70 (@YuriRestia) translated by replacing the
|
||
strings in place across every file, logic included; the owner did not merge it (reply on PR #70, 2026-10-05) and
|
||
asked for real i18n instead.
|
||
- **Official**: the English game texts exist in the official EN client data (the EN tables carry act2autochess with the
|
||
zh_CN ids); the YoStar repository the plan first named is archived and has no 盟约 season.
|
||
- **Decision**: the owner's decision of 2026-10-05 — Chinese stays the default (an English browser still opens in
|
||
Chinese), English is a switch; game texts from the official EN data; PR #70's translations reused with credit; no
|
||
i18n framework.
|
||
- **Now** (docs/I18N.md is the reference): UI strings go through `t('中文')` — gettext style, the Chinese text is the
|
||
message id, so an untranslated string shows Chinese, never a key (`{name}` parameters, one plural form, `tc()` for
|
||
context, `N_()` marks module-level tables); their English is `public/i18n/en.json`, seeded from PR #70's
|
||
translations. Game texts (operators, skills, talents, modules, traits, enemies, bonds, items, effects, strategies,
|
||
特质, 机变 cards, modes, stages, tokens) come from an overlay, `data/i18n/en.json`, which `tools/build-i18n.mjs` builds
|
||
by walking the zh_CN and EN tables side by side (exact, template and composite matches; fallbacks: the remake's own
|
||
strings, PR #70's, the UI table) and `public/js/data.js` applies: 97.6 % of 22 183 texts with the 自选 data (the
|
||
CN-only operators and modules are what is missing). Server toasts and ticker lines travel as `msgid` + `params`
|
||
(`wireMessage`; `text` keeps older clients working) and each client renders its own language. The switch: the title
|
||
screen (top right) and 设置, `?lang=en` once, kept in `sp.pref.lang`, re-rendered in place. Phase 1 converted the
|
||
title screen, lobby, room, settings, the app shell and every server message; `tools/i18n.mjs` (extract / check /
|
||
codemod / seed) finds what is left.
|
||
- **Phase 2** (W5S, 2026-10-06; docs/I18N.md §4): of the 1 128 Chinese literals `extract` still listed, 1 056 go through
|
||
`t()`, `N_()` or the new `tParts()` (a sentence with markup or a component inside: the translation split at its
|
||
placeholders, vnode params kept) — the screens (band draft, briefing, the game screen and its overlays, 干员调配 /
|
||
干员持有, the result), the HUD, shop bar, detail card, bond strip and popup, 机变 overlay, enemy drawer, team panel,
|
||
guide, emotes, components and the client models, the phase banners, refusal reasons and formats of `ui/gameLogic`
|
||
(`fmtNum` writes K / M / B in English, 万 / 亿 in Chinese), the canvas, 2D-fallback and facing-wheel labels and the
|
||
msgid tables of `shared/constants.js`; the other 72 are marked as no player text and skipped by the audit (error
|
||
details and logger lines, the invariant reports, the bilingual HTTP error pages, the AI seats' names, the dev STUB
|
||
match, data keys). `extract` now reports 0 and `check` 1 002 msgids, every one translated (`public/i18n/en.json`
|
||
1 015 entries; the 64 fragments the sweep replaced dropped). Game texts the server copies into the match views in
|
||
Chinese — a 机变 card, an effect entry, the draft's name, a reward offer's label, the result title — show the localized
|
||
record when the sent text is that record's own (`data.lookupRaw`, `ui/lang.js sentText`; names through `tName`); a
|
||
text the server reworded (the multi-round 悬赏's two-battle text, `choices.js bountyText`) stays as sent. A language
|
||
switch in the middle of a screen re-reads the game texts (`useGameData()`, the 干员调配 / 干员持有 rosters, the strategy
|
||
list and the open detail card list `data.locale()` among their memo dependencies). What stays Chinese in English:
|
||
player names (the AI seats' too), that reworded 悬赏 text, the game texts the official EN client lacks (some 自选
|
||
operators, newer modules) and the 玩法说明 pictures (their titles translated). The 虫动 emote set follows the official
|
||
EN name (Slug Style). The Chinese output did not change: a render of every converted file in Chinese equals the code
|
||
before the sweep, and the few rewrites it cannot follow were checked by hand.
|
||
- [ASSUMED]: the English of the remake's own strings (排气格栅 "Exhaust Grille" as PR #70 has it, the 联防 map names, the
|
||
server's own templates, the 126 msgids phase 2 added).
|
||
- Golden: unchanged. Tests: `test/i18n.test.js` (since phase 2 it scans the whole client, shared and the server
|
||
messages: no Chinese literal left unwrapped, every msgid translated — `extract` 0 and `check --strict` as a test;
|
||
floors 1 000 catalog entries, 1 350 msgid uses), `test/i18n-data.test.js` (coverage floors), `test/i18n-server.test.js`
|
||
(also the sent data texts), `test/ui/i18n.e2e.test.js` (`SP_E2E=1`).
|
||
|
||
### 25.3 补位: an operator the player does not own fights as its official stand-in (W5B, W5D, W5G, K1–K3, W5N; the approved plan, the owner's decision of 2026-10-05; the owner's recall of 2026-10-06) — `tools/build-data.mjs buildBackups`, `data/backups.json`, `shared/standIn.js`, `sim/simdata.js getStandIn`, `content/index.js kitOf`, `kits/ops/standin-*.js`, `shared/protocol.js room.ownership`, `screens/ownership.js`, `ui/gameLogic/standIn.js`
|
||
|
||
- **Seen**: the official mode fills an operator the player does not own with a stand-in; the remake always fielded
|
||
the real operator, and the data build dropped the official backup fields.
|
||
- **Official**: act2autochess — 133 chess: 74 PRESET (特许, always available), 55 NORMAL (each naming a backup: charId,
|
||
template, skill, module, potential), 4 DIY; PRTS 卫戍协议 — a missing operator is filled by a prototype of its class
|
||
with a fixed skill, and the bonds and 特质 stay the chess's. The 17 stand-ins: the eight 4★ 预备干员 and nine elite
|
||
prototypes (郁金香, Sharp, Mechanist, Stormeye, Pith, Touch, Raidian, Misery, 领主·Sharp).
|
||
- **Decision**: the approved 补位 plan (2026-10-05): only the 55 NORMAL chess can be marked not owned, everything is
|
||
owned by default, no borrowing from friends, bots own everything; the 重装 stand-ins (预备干员-重装, Mechanist) cast with
|
||
an enemy in range, like §21.29. The owner's first-hand recall of 2026-10-06: the shop, the hand, the board and the
|
||
result screen show the STAND-IN — this replaced the first build's cards that kept the chess with a 「替补:X」 badge.
|
||
- **Now**: data (W5B): every chess.json record keeps `backup`; data/backups.json `units` holds the 17 stand-ins in every
|
||
form (DATA.md §18). Battle (W5D): `getChess(id, { standIn: true })` = the chess's ids, bonds and tier with the
|
||
stand-in's body (`def.standInFor`); its kit is the stand-in's own (`kits/ops/standin-<codename>.js`,
|
||
`STANDIN_KIT_FILES`), never the replaced operator's; without one, the generic kit plus `genericTalents` — the eight
|
||
预备干员 get their talents, 一击即退 for 10 s from every deployment and 冲锋号令 +12 DP; the browser battle loads
|
||
data/backups.json too. Match (W5G): C→S `room.ownership { notOwned }` (the 55 droppable chess only; fixed for the
|
||
match); `battleInput` marks `standIn: true` in every field — the rules read the chess (price, bonds, 特质, merges,
|
||
pools), the body is the stand-in's (placement by its own position, range, no summons). Client: the 干员持有 tab of
|
||
干员调配 (export / import, `sp.pref.ownership`); since W5N the stand-in is drawn everywhere — shop and reward cards,
|
||
hand, 临时整备区, board, detail card, bond popups, result lineup, bench scouting, tickers — with a small ice 「替补」 mark
|
||
and the chess's tier, price and bonds. It speaks with its own voice (the §21.30 port; a 预备干员 stays silent).
|
||
- Kits (K1–K3; every skill on every form, the numbers from the composed record, the data's trigger):
|
||
|
||
| stand-in | kit (`kits/ops/`) | stands in for | notable [ASSUMED] |
|
||
|---|---|---|---|
|
||
| Sharp | `standin-acguad.js` | 忍冬, 银灰, 百炼嘉维尔, 隐德来希, 归溟幽灵鲨, 佩佩 | — |
|
||
| 领主·Sharp | `standin-sharp2.js` | 水月, 玛恩纳, 维娜·维多利亚, 妮芙 | 陷阵勇气 counts targetable enemies; LOR-X's 流失 follows a shielded hit |
|
||
| Misery | `standin-acspec.js` | 缄默德克萨斯, 山, 新约能天使, 锏 | 四维分离 counts her own tile and air units; S3's drag area is its x-4; S1 / S2 deploy-timed duration skills (WE1) |
|
||
| Stormeye | `standin-acnipe.js` | 空弦, 莫斯提马, 百炼嘉维尔, 妮芙, 蕾缪安, 异客 | 风雨欲来's delay = no attack for 2 s, counted from deployment |
|
||
| Pith | `standin-accast.js` | 烛煌, 焰影苇草, 迷迭香, 荒芜拉普兰德 | two Piths' 授我所授 / S2 never add up |
|
||
| Raidian | `standin-acsupo.js` | 灵知, 夕, 安洁莉娜, 浊心斯卡蒂, 仇白 | 诱引 rolls at an attack's first damage instance; new `applyStatus` option `stackAs` |
|
||
| 郁金香 | `standin-acpion.js` | 瑕光, 焰尾, 凛御银灰, 圣聆初雪, 缪尔赛思, 耀骑士临光 | the 集成战略 备注 applies; S3's 8 slashes at the clip's OnAttack events |
|
||
| Mechanist | `standin-acfend.js` | 星熊, 号角, 余 | S3 pulses from 1 s after the cast |
|
||
| Touch | `standin-acmedc.js` | 塞雷娅, 塑心, 纯烬艾雅法拉 | shares the 外勤医疗 strategy's Touch code (§25.6.6); S2's 所有医疗干员 = her own player's |
|
||
|
||
- [ASSUMED]: a stand-in is placed by its own position (melee tiles for a melee stand-in); without accounts any of the 55
|
||
may be dropped, also one the player owns; AI 托管 values a dropped chess by the chess record; the detail card names
|
||
「X的替补」 in place of the English name; the 「替补」 mark's look.
|
||
- Golden: new family `standins` (10 battles: every NORMAL record, normal and elite, fielded as its stand-in) and the
|
||
match `coop2-NORMAL-14-standins` (a human seat on AI 托管 owning none of 7 NORMAL chess); nothing else moved.
|
||
- Tests: `test/backups.test.js`, `test/content/standin.test.js` (the plumbing and the eight 预备干员),
|
||
`test/content/standin_*.test.js` (the nine kits), `test/match/standin-ownership.test.js`,
|
||
`test/lobby-ownership.test.js`, `test/ui/standin-ui.test.js`, `test/golden-standins.test.js`,
|
||
`test/ui/standin.e2e.test.js` (`SP_E2E=1`).
|
||
|
||
### 25.4 自选编队: the four DIY slots field the player's own 6★, and 71 operator kits (W5H, W5K, O1–O24; the owner's decisions of 2026-10-05) — `data/backups.json diy`, `shared/diy.js`, `sim/simdata.js getDiy`, `server/match/player/diy.js`, `shared/protocol.js room.diy`, `screens/diy.js`, `kits/index.js OPERATOR_KIT_FILES`, `kits/ops/op-*.js`, `kits/shared/summoner.js`
|
||
|
||
- **Seen**: the four DIY chess were removed from the shared pool (§0). A first attempt (PR #71) had put them in the
|
||
shared pool, one chess id meaning a different operator per player — the shape to avoid.
|
||
- **Official**: act2autochess `diyChessDict` / `shopLevelDisplayDataDict` — two slots at tier 5 (from 调度中心 level 5),
|
||
two at tier 6 (level 6), price 4, sold for 1; PRTS 盟约 下半 — the player's own 6★ or a 6★ prototype, no 特质, the
|
||
core bonds its factions meet (else 协防); forms: normal = E2 Lv1 with skills at rank 4, elite = E2 Lv60 rank 7 with its
|
||
module at stage 1 (tier 5) or 3 (tier 6).
|
||
- **Decision**: the owner's decisions of 2026-10-05 — two plus two slots per player; an owned 6★ with a kit, any of its
|
||
three skills, any elite module; a prototype keeps the skill and module of its 补位 rows; a per-player shop; levels
|
||
follow the chess forms; the six collab 6★ are out (copyright), and so is 焰狐龙梓兰 (MH05, a Monster Hunter 联动寻访
|
||
operator the team list does not name: `DIY_EXCLUDED_NUMBER_PREFIXES`) — 71 owned picks; the 集成战略-only ISW-A
|
||
modules are refused (WE2 adds SO-A / SO-B / RA-A, §25.8).
|
||
- **Now**: data (W5H): data/backups.json `units` adds the 71 owned picks in the three slot forms, `tokens` their 38
|
||
summons, `diy` the slots, the prototypes (15 at tier 5, 9 at tier 6), their locked loadouts, `ownedPool` and the
|
||
derived bonds (DATA.md §18); `shared/diy.js` (`diyPool`, `validateDiyPicks`, `diyRecordOf`); the sim fields a pick
|
||
(`getDiy`; kit `KITS[charId]`). In play (W5K): C→S `room.diy { picks }` (`checkDiyPicks`; `welcome.diyKitted` lists
|
||
the operators with a kit); the player's data view makes a slotted DIY slot its operator everywhere — bonds, placement,
|
||
summons, AI 托管 — with no 特质; a per-player stock never enters the shared pool and the player's own shop draws it from
|
||
the slot's 调度中心 level; a piece whose every bond is off this match leaves the shop (`m.private.diyBanned`, shown since
|
||
WE2); a placed operator's summons go to the hand (official counts since WE2, §25.8). Client: the 自选编队 tab of
|
||
干员调配 (two tier-5 and two tier-6 slots, the picker with skill and module, export / import, `sp.pref.diy`) and a mint
|
||
「自选」 badge on cards and pieces.
|
||
- **The kits**: 推进之王 first (W5H, the worked example of kits/README.md "How to add an operator (自选)"), then O1–O24 in
|
||
three waves — every skill at ranks 4 and 7, every talent, every module at stages 1 and 3, the range while a skill
|
||
runs, triggers, targeting, damage typing, summons and statuses, per the kit checklist; potential 0 for every pick
|
||
[ASSUMED: no account]. Engine additions, each additive (only the `diy` golden family moved): `palsyTrigger` (O3,
|
||
`ai.js`: a 麻痹 stack interrupting an enemy attack), the `hpDamage` hook after the shields (O5, `damage.js`), target
|
||
priority `heaviest` and the boomerang hooks `boomerangCaught` / `boomerangOnward` (O7), shields limited to damage
|
||
types (`shieldType`, O8 / O16) and a profile's `skipEnemy` (O8), enemy shots carrying `isProjectile` and priority
|
||
`elite` (O11), a healer profile's `healThrough` (O16), the 缚地 status `groundbind` (O20), the `enemyAttackStart` hook,
|
||
the `noNewBlock` flag and `holdsUndying` reading an `undying` buff (O22), ally attack targets
|
||
(`Battle.setAllyTarget`, O23), the air-block mod `blockRadiusScale` (O24); `kits/shared/summoner.js` (O21) holds the
|
||
召唤师 deck of 麦哲伦 / 令 / 电弧. Match: a placeable summon's hand count reads the active module's variant (O19: 望's
|
||
TRP-X 7). Client: visuals for the 13 fx kinds the new kits emit (`render/fx/kinds.js`); the picks' art comes with the
|
||
asset plan (`tools/fetch-assets.mjs --add-only`; their battle voices and the summons with no Spine model: §25.12).
|
||
|
||
| 干员 (summons) | kit (`kits/ops/`) | stream | notable [ASSUMED] (and later changes) |
|
||
|---|---|---|---|
|
||
| 推进之王 | `op-siege.js` | W5H | S2 跃空锤 reaches ground enemies only (no source says air); SOL-Y's extra SP goes to a random deployed other 【先锋】 |
|
||
| 陈 | `op-chen.js` | O4 | S3's ten slashes = the first ten of the clip's eleven OnAttack events; S3 refused with no ground enemy in its 技能范围 |
|
||
| 艾丽妮 | `op-irene.js` | O4 | S3's first bombardment 0.3 s after the opening strike, an empty one skipped; ISW-A refused in 自选 (W5K) |
|
||
| 赫拉格 | `op-helage.js` | O4 | 运筹帷幄 is the 生命回复速度 attribute (no PRTS 备注); the 武者 heal per damage instance (WE1) |
|
||
| 闪灵 | `op-shining.js` | O8 | S2's DEF bonus ends with her last barrier on that unit; PHY-X heals ×1.15 at or below 50 % (WE1) |
|
||
| 夜莺 (幻影) | `op-cgbird.js` | O8 | a held 幻影 returns after 20 s for 5 DP whether or not 夜莺 stands; 3 hand pieces (WE2) |
|
||
| 嵯峨 | `op-saga.js` | O8 | 清明 is a 生命回复速度 (hpRegenRatio) buff; SOL-Y stage 3 takes the blackboard's 6.5 % (the text says 6 %) |
|
||
| 艾雅法拉 | `op-amgoat.js` | O2 | S3's lava has no splash; 乱火 maxima 15 / 15; S3 now casts by the larger-range rule (「攻击范围增大」) |
|
||
| 刻俄柏 | `op-cerber.js` | O2 | 剥壳's ramp restarts per deployment |
|
||
| 霍尔海雅 | `op-heyak.js` | O2 | S3's whirlwinds hit air units, nearest first; one not yet released drops when she leaves; ISW-A refused |
|
||
| 早露 | `op-poca.js` | O7 | S3's strikes are her attacks, the first one tick after the cast; SIE-Y's distance bonus is linear |
|
||
| 提丰 | `op-typhon.js` | O7 | S3's arrows are skill damage, not attacks (no SIE-X / SIE-Y bonus) |
|
||
| 娜仁图亚 | `op-narant.js` | O7 | S1 (切换) stays on until she leaves; S3's boomerangs fly together and its blast is no attack |
|
||
| 逻各斯 | `op-logos.js` | O3 | 语汇演化 rolls once per attacked target and may draw the attacked enemy |
|
||
| 真言 | `op-mantra.js` | O3 | S2's first shot keeps the engine's bolt speed 11 (备注 10); only operators starting a skill grant 麻痹 |
|
||
| 维伊 | `op-veen.js` | O3 | 战争技艺 restarts its 5 s with every stack; her energy store is now the engine's 秘术师 rule (WE1) |
|
||
| 左乐 | `op-zuole.js` | O5 | S3's 7 slashes resolve at the cast and reach air units |
|
||
| 重岳 | `op-chyue.js` | O5 | S2's second segment always fires; 止戈 rolls only on hits that leave the target alive |
|
||
| 煌 | `op-huang.js` | O5 | S3's cuts deal 100 % ATK once a second (no blackboard key); the card keeps her 1-1 (the game shows 3-6) |
|
||
| 黑 | `op-shwaz.js` | O6 | 正前方 = her straight line ahead, her own tile included; S3 DEFAULT (「攻击范围改为」 is a range change) |
|
||
| 鸿雪 (打字机) | `op-bgsnow.js` | O6 | the 打字机 returns only while 鸿雪 stands and keeps its 25 s when she falls |
|
||
| 伊芙利特 | `op-ifrit.js` | O1 | BLA-Δ's extra 元素伤害 also follows 灼地 ticks (`_targetFamilyMask` 31); 灼地's 2 % 流失 as stated |
|
||
| 谬因 (中继器) | `op-aphris.js` | O1 | a huge enemy counts on every tile it covers; the 中继器's 无敌 / 孤立 / 禁疗 are kit flags; S2 area trigger (WE2) |
|
||
| 林 | `op-lin.js` | O1 | the 琉璃璧 sits in the buff order (an earlier shield absorbs first); its burst comes before a knock-out |
|
||
| 年 | `op-nian.js` | O14 | PRO-Y counts a teammate's 重装 on a shared field; 铁御 skips summons |
|
||
| 斩业星熊 | `op-hsgma2.js` | O14 | AST-X's extra damage with or without a running skill; 我执 on the engine's 1-HP floor; normal attack physical (WE2) |
|
||
| 珊比 | `op-thumpy.js` | O14 | the conveyor moves 0.533 tile/s (20 frames read per game second); S2 / S3 cast by the area rule |
|
||
| 森蚺 | `op-zumama.js` | O15 | a blockee turning 无敌 + 无法选中 loses the S2 stun after one pulse; RA-A refused in 自选 (WE2) |
|
||
| 斥罪 | `op-judge.js` | O15 | her barrier is spent oldest first (the client's priority −1000 would put it last); the thorns cannot be dodged |
|
||
| 黍 | `op-shu.js` | O15 | the 【播种标记】 and the teleport end with S3; S3's TRY_SEARCH_ALLY_SKILL is now resolved in the data (WE2) |
|
||
| 帕拉斯 | `op-pallas.js` | O9 | 休谟斯's own 精力充沛 is not merged with hers; S2 casts by the larger-range rule (「向前延伸」) |
|
||
| 止颂 | `op-lessng.js` | O9 | S3 casts nothing under 晕眩 / 冻结 / 沉睡; S2's strike spacing is not modelled |
|
||
| 贝洛内 (牵绊) | `op-demetr.js` | O9 | several 贝洛内 on one enemy share one 【手段】; every move is instant |
|
||
| W (此面向敌) | `op-cqbw.js` | O12 | no cap on mines; 此面向敌 cannot be targeted; her knock-out withdraws the mines |
|
||
| 菲亚梅塔 | `op-phenxi.js` | O12 | S1 follows the current client (no air targets, no range growth, trigger DEFAULT — PRTS 备注 of 2026-08-01) |
|
||
| 维什戴尔 (魂灵之影) | `op-wisdel.js` | O12 | aftershocks 0.3 s apart; S3's last shell loses the +ATK (the engine's ammo rule) |
|
||
| 棘刺 | `op-thorns.js` | O10 | the spikes carry the LOR-X addition; his poison keeps ticking after he left |
|
||
| 赤刃明霄陈 | `op-chen3.js` | O10 | the first slash at the cast; a hiding target counts as gone; the 【移动】 lands at once |
|
||
| 司霆惊蛰 | `op-leizi2.js` | O10 | currents outlive the skill, bounce off the field edge, use screen directions; S1 by the larger-range rule |
|
||
| 薇薇安娜 | `op-vvana.js` | O11 | enemy content projectiles carry no `isProjectile` (melee for 散华); S3 area trigger (WE2) |
|
||
| 怒潮凛冬 | `op-headb2.js` | O11 | the hammers are skill damage, lost while she is stunned; 高台 = the HIGH tiles of the field |
|
||
| 赫德雷 | `op-hodrer.js` | O11 | S3's 流失 may knock him out; attack riders land even on a dodged hit |
|
||
| 假日威龙陈 | `op-chen2.js` | O13 | the slime shot's selector range is her attack range at the attack; it outlives her |
|
||
| 莱伊 (沙地兽) | `op-ray.js` | O13 | the 沙地兽 scouts 25 s, attacks nothing, returns after its redeploy time for 3 DP while she stands |
|
||
| 阿斯卡纶 | `op-ascln.js` | O13 | 高台 = the level's HIGHLAND tiles (the forbidden rim too); separate 命中率 cuts roll apart |
|
||
| 涤火杰西卡 (机动盾牌) | `op-jesca2.js` | O16 | a 机动盾牌 not next to her gets no turn, mark or aura |
|
||
| 机械师 (结构性原理) | `op-mcnist.js` | O16 | the S3 charge lands free of DP; `_ignoreTriggerOnce` read as nothing |
|
||
| 凯尔希 (Mon3tr) | `op-kalts.js` | O16 | S2 / S3 are heal skills on DEFAULT (no injured ally, no cast); PHY-X Lv3's half-HP blast once per deployment |
|
||
| 琴柳 | `op-sleach.js` | O17 | 精神感召 saves DP only on a redeploy (the battle-start deployment is free here) |
|
||
| 可露希尔 (指挥中心) | `op-closur.js` | O17 | 部署费用下限 has no counterpart (costs never drop below 0); her own tile counts beside the 指挥中心 |
|
||
| 澄闪 | `op-gdglow.js` | O17 | her own attack stops in every skill (all drones out); S2 fires at full SP |
|
||
| 阿 | `op-haak.js` | O18 | S2 / S3 keep the data's DEFAULT: with no ally in range the cast does nothing (settled by the data and the skill prefabs, §25.11.5) |
|
||
| 傀影 (镜中虚影) | `op-phatom.js` | O18 | S3's push and status land on a dodged hit too; the twin is readied at his redeploy (WE1) |
|
||
| 弑君者 | `op-crosly.js` | O18 | S2's blast lands at once; any action-stopping state or 缴械 cancels it |
|
||
| 老鲤 | `op-lmlee.js` | O19 | 周围八格 = the 3 × 3 with his tile, flyers counted |
|
||
| 温蒂 (工程蓄水炮) | `op-weedy.js` | O19 | S2 reaches air units; the cannon's forced skill fires once per deployment (data DEFAULT, re-checked in WE2) |
|
||
| 望 (棋子, 跟子) | `op-wang.js` | O19 | 跟子 are kit records, no unit; placed 棋子 take and return her stock, so S1 / S2 keep cycling (the owner's decision of 2026-10-06, §25.11.1); 棋子 on any tile (WE2) |
|
||
| 多萝西 (共振装置) | `op-doroth.js` | O20 | a used-up piece returns 5 s after the LAST trap deployment; the hand holds at most 9 |
|
||
| 予愿安洁莉娜 (“一会儿见!”) | `op-aglna2.js` | O20 | flight 2 tiles/s, landing clips not modelled; the marker is no hand card (WE2); new status 缚地 |
|
||
| 黑键 (旧日残影) | `op-ebnhlz.js` | O20 | his energies land with the main bolt; S2 at full SP with a free tile (WE2) |
|
||
| 麦哲伦 (龙腾) | `op-mgllan.js` | O21 | 龙腾.F makes no attack (ATK 0); 3 summon pieces, 4 with SUM-Y (WE2); S1 casts on an enemy in a drone's range (§25.11.2) |
|
||
| 令 (清平 / 逍遥 / 弦惊) | `op-ling.js` | O21 | her summons strike during S2 even when stunned; 3 pieces (WE2); S3 casts on a ground enemy in a summon's x-5 (§25.11.2) |
|
||
| 电弧 (戴乌 / 赛柯 / 桑特拉) | `op-radian.js` | O21 | 桑特拉's link is its own attack with its own ATK; SO-A / SO-B refused in 自选 (WE2); S2 / S3 cast on an enemy in a summon's range (§25.11.2) |
|
||
| 淬羽赫默 (夜灯) | `op-slent2.js` | O22 | 丰润羽翼 as 生命回复速度 rests on the client template (kept, §25.11.5; owner question) |
|
||
| 遥 | `op-haruka.js` | O22 | her bubbles outlast her; the T2 heal uses the ATK of the grant (kept, §25.11.5; owner question) |
|
||
| 酒神 (本能的召唤, 迷狂牢笼) | `op-phatm2.js` | O22 | 本能的召唤 lures at most 4 in all; its redeploys cost no DP; the 迷狂牢笼 blocks no sleeper (§25.9.1) |
|
||
| 白铁 (支援装置, 铁钳号) | `op-ironmn.js` | O23 | the 铁钳号 is charged only by attacks that select it; 2 devices in hand (WE2) |
|
||
| 娜斯提 (支援装置) | `op-nasti.js` | O23 | the built 高台's operator bonus (m4–m6_bonus) never applies |
|
||
| 死芒 (悲叹的仆役) | `op-necras.js` | O23 | the servant consumed is the earliest made; S3's strikes are skill damage; S2's sleepers leave her servants' block (§25.9.1) |
|
||
| 凯尔希·思衡托 (战术锚点) | `op-kalts2.js` | O24 | S2's shot flies at the engine's orb speed 10 (official 12); 战术锚点 placement (WE2) |
|
||
| Mon3tr (重构体) | `op-monstr.js` | O24 | the 路标形态 marker is not placed; 重构体 placement (WE2); the chain heal jumps in the 3×3 (WE1) |
|
||
|
||
- [ASSUMED] (besides the table): the per-player stock, 8 at tier 5 and 5 at tier 6 (no table gives it); bots field no
|
||
自选 piece; 信标 sends no 自选 piece to a teammate; a prototype in a tier-5 and a tier-6 slot counts as two bond members;
|
||
the reward offers' temporary refresh draws the player's 自选 pieces from the slot's level on.
|
||
- Golden: new family `diy` (138 battles: every kitted owned operator in each form × module × skill at tiers 5 and 6,
|
||
then the prototypes) and the match `coop2-NORMAL-70-diy` (a human seat on AI 托管 slotting 推进之王 and prototypes);
|
||
each kit wave added its own scenarios, no other family moved.
|
||
- Tests: `test/backups.test.js`, `test/diy.test.js`, `test/content/diy.test.js`, `test/content/kits_layout.test.js`,
|
||
`test/content/op_*.test.js` (71: one per kit, every form × module × skill), `test/match/diy-shop.test.js`,
|
||
`test/match/diy-bonds.test.js`, `test/lobby-diy.test.js`, `test/ui/diy-ui.test.js`, `test/golden-diy.test.js`,
|
||
`test/assets-diy.test.js`, `test/ui/diy.e2e.test.js` (`SP_E2E=1`).
|
||
|
||
### 25.5 Trigger rules: a larger running range casts as soon as an enemy is inside it; AUTO skills that need no target fire at full SP (W5C, W5F, the kit waves; the owner's decisions of 2026-10-05) — `tools/build-data.mjs resolveTrigger / ACTIVE_RANGE_OVER / ATTACK_RANGE_CHANGE / UNIT_TRIGGER_CORRECTIONS / TRIGGER_ALLY_RULES`, `sim/skills.js setTrigger`, §5.6
|
||
|
||
- **Seen** (community report): a skill that enlarges the attack range waited for an enemy inside the normal range,
|
||
as the official basic strategy does (§20.2); the 0.2.0 audit after GitHub #124 found 35 AUTO skills among the 112
|
||
visible chess that never fired alone with full SP and no enemy.
|
||
- **Official**: PRTS 卫戍协议/帮助 技能策略 — DEFAULT casts on an enemy in the initial range; SEARCH on an enemy in the
|
||
initial range; AUTO skills take no strategy row, so DEFAULT waits for the unit's own attack.
|
||
- **Decision and now** (the normative text is §5.6):
|
||
1. **ACTIVE_RANGE** — the owner's deliberate deviation of 2026-10-05, like §21.29: a MANUAL skill whose running
|
||
range strictly contains the operator's own checks the DEFAULT condition on that running range every tick, no
|
||
attack needed (`rawRule` keeps the official row). First on the basic strategy (W5C: 33 skills / 66 records, e.g.
|
||
野鬃 S2, 银灰 S3, 莫斯提马 S3), then the SEARCH row and 深巡 S2 (W5F: 薄绿 S1, 蜜蜡 S1, 卡涅利安 S3, 玛恩纳 S2, 安洁莉娜 S3,
|
||
深巡 S2 — 39 skills / 78 records). The wording of a range change was widened as the kit reports found misses:
|
||
「攻击范围增大」 (艾雅法拉 S3), 「攻击范围改为」 (黑 S3: DEFAULT, not a 技能范围), 「攻击范围向前延伸」 / 「攻击范围朝…扩大」 (帕拉斯 S2,
|
||
司霆惊蛰 S1); `UNIT_TRIGGER_CORRECTIONS` follows a live-client change the text misses (菲亚梅塔 S1 is DEFAULT since the
|
||
2026-08-01 client, PRTS 备注: no range growth, no air targets). A range the data cannot express is set by the kit:
|
||
珊比 S2 / S3 (her tile plus the glue / conveyor area), 谬因 S2 (the beam path, `addTriggerRange`), 薇薇安娜 S3 (3-2
|
||
from her second cast, the new `skill.setTrigger`).
|
||
2. **重装 of data/backups.json** — the owner's decisions of 2026-10-05: the 重装 stand-ins and every 自选 重装 (森蚺,
|
||
涤火杰西卡, 斩业星熊, 年, 黍, 斥罪, 机械师, 珊比; 48 skill forms) cast with an enemy in range — DEFAULT, or ACTIVE_RANGE
|
||
when the running range is larger — instead of the class row's TAKE_DAMAGE.
|
||
3. **AUTO skills that need no target** fire at full SP (`SP_FULL`; kits/README.md checklist item 5): 浊心斯卡蒂 S2 and
|
||
伺夜 S2 (W5C, after GitHub #124's 引星棘刺 S1), 纯烬艾雅法拉 S1 (the owner's decision of 2026-10-05, W5F), and in the 自选
|
||
kits every AUTO skill that acts on the operator itself, its allies or its summons (e.g. 谬因 S1, 维伊 S1, 莱伊 S2,
|
||
澄闪 S2, 多萝西's three). Skills that need a target keep waiting (a "next attack / next heal" skill, attack buffs).
|
||
伺夜 S1 / S2 cast only while his pack is on the field (PRTS 备注; the owner's decision of 2026-10-05 for S1, W5F; the
|
||
战术点形态, §25.6.5 and §25.7.9), 黑键 S2 only with a free deployable tile in range (§25.8.4).
|
||
4. Data aliases: 黍 S3's TRY_SEARCH_ALLY_SKILL resolves to SKILL_RANGE with `allies` on its x-2 (`TRIGGER_ALLY_RULES`,
|
||
§25.8.4).
|
||
5. **Through summons** — the owner's decision of 2026-10-06, the larger-range rule read through the summons' areas:
|
||
麦哲伦 S1, 令 S3 and 电弧 S2 / S3 also cast on an enemy in a standing summon's area the skill acts through
|
||
(`kits/shared/summoner.js summonTriggerArea`, §25.11.2).
|
||
- Kept on their rows: 烛煌 S2 / S3 (their ranges do not contain her 3-1), TAKE_DAMAGE 重装 skills of the chess pool but
|
||
the §21.29 six, CUSTOM_RANGE skills, AUTO skills that need a target, SEARCH skills whose range does not grow.
|
||
- Golden: each step names its scenarios in its commit (the SEARCH / 深巡 step: roster-001 / 002 / 016 / 026 / 027 / 041
|
||
/ 042 / 044, bond-egirShip-low, bond-suntShip-high, boss-boss_2-pair, boss-boss_6-pair and the bot matches fielding
|
||
them; 纯烬艾雅法拉 S1: roster-038; 伺夜 S1: roster-028; the range-wording fixes: only `diy`).
|
||
- Tests: `test/sim/feedback5-active-range.test.js`, `test/sim/feedback1-tank-triggers.test.js`,
|
||
`test/sim/feedback1e-skillrange.test.js`, `test/data.test.js` (the counts), `test/content/kits_alt_t3.test.js`
|
||
(伺夜), `test/content/kits_alt_t6.test.js` (浊心斯卡蒂, 纯烬艾雅法拉), `test/content/feedback5-we2-area-triggers.test.js`.
|
||
|
||
### 25.6 Fidelity fixes, wave 1 (W5C, W5E, W5J, W5L)
|
||
|
||
#### 25.6.1 琳琅诗怀雅 S2 “见面礼” throws onto an enemy's tile on x-6, with no enemy needed (GitHub #116 item 2) — `kits/ops/chess_char_3_04-swire2.js` (installS2)
|
||
|
||
- **Seen**: the bomb landed only in front of her or nowhere. **Official**: PRTS S2 备注 — bomb range x-6; an enemy in range
|
||
gets it on its tile, else a random deployable tile (the client needs a free x-6 tile and her coin buff). **Now**: with a
|
||
coin and a free x-6 tile her attack turn throws: onto the first ground enemy's tile in her target order, else a random
|
||
free tile (in the field, empty, walkable melee ground, not a knocked-out operator's tile); damage, 停顿 and the 3 s
|
||
second hit unchanged. Item 1 of #116 (the solo 标准 shop prices) is not a bug. [ASSUMED]: the throw is instant and costs
|
||
one tick of her attack. Tests: `test/content/kits_t3.test.js` (3 cases), `summon_loadout_conflicts.test.js`.
|
||
|
||
#### 25.6.2 新硎 / 沉沙: one ATK layer while a 断刃 is held, gone with the last one (GitHub #107) — `content/enemies/times.js` (kitBlades)
|
||
|
||
- **Seen**: 新硎's ATK kept climbing (1350 → 3510 after two hits). **Official**: PRTS talent — ATK +80 % (沉沙's
|
||
blackboard 0.7) while holding 4 【断刃】, one spent per attack; the attack spending the last drops the bonus and clears
|
||
its cooldown; unspent blades become 矛头 on death (at least 1). **Now**: one layer from the spawn, removed by the
|
||
attack that spends the 4th blade, which is followed at once by the next (unbuffed) attack; death spawns max(1,
|
||
unspent) 矛头 at once (the 0.7 s delay is not modelled). Tests: `test/content/enemies_bosses.test.js`.
|
||
|
||
#### 25.6.3 A full 整备区 buys nothing; a freed slot pulls the 临时整备区 in (GitHub #82, second part, reported by Hucxious) — `PlayerState.buy / pickReward / _fillHandFromTemp`, `match/invariants.js`, `match/bot.js`
|
||
|
||
- **Seen**: a full hand still bought a third copy (it merged), and a freed slot did not pull the overflowed operator
|
||
back. **Official**: PRTS 卫戍协议/帮助 §手牌区 — with the 10 regular slots full, 招募 / 购入 are refused, merge or not;
|
||
temp pieces move in when a slot frees; board ↔ hand swaps stay allowed. **Now**: `buy` / `pickReward` refuse with
|
||
`HAND_FULL` (client: 整备区已满); every `recompute()` moves temp pieces into free slots (invariant: temp is non-empty
|
||
only while the hand is full); bots never buy into a full hand and shed their weakest single for a third copy.
|
||
[ASSUMED]: temp empties right → left into the hand's next free slot right → left. Golden: coop2-NORMAL-3,
|
||
solo-HARD-9-boosted, coop2-ABYSS-10-boosted. Tests: `test/match/feedback5-hand.test.js`.
|
||
|
||
#### 25.6.4 联防 plays on its own official map (GitHub #41 item 3, reported by Hucxious and shanzhaikabi) — `tools/build-data.mjs buildStages`, data/stages.json `kind: 'unite'`, `unite.js uniteStageId`, `match/unitePhase.js _uniteOpts`
|
||
|
||
- **Seen**: the 联防 field showed the round's battlefield (water pools, crates) opened to both halves. **Official**:
|
||
act2autochess `level_act1autochess_escaped_single` / `_multi` — one 19 × 21 road grid, no devices, runes or terrain;
|
||
the right half is the own board + 8 columns. **Now**: two `kind: 'unite'` stage records (1 / 2 helpers, `active:
|
||
false`) carry the 联防 battle in both combat modes; the client draws that map and restores the board after. No water,
|
||
crates, devices or terrain in 联防; the BGM (PR #110) is unchanged. [ASSUMED]: the records' names 联防阵地(1名玩家) /
|
||
(2名玩家). Golden: unite-1, unite-2 and the co-op matches. Tests: `test/match/feedback5-unite-map.test.js`.
|
||
|
||
#### 25.6.5 伺夜's 狼群 has the official 战术点形态; S1 acts by the pack's state (PRTS 备注; the owner's decision of 2026-10-05) — `content/tokens.js wolfPack / installWolfTacticalPoint / wolfReturnNow`, `kits/ops/chess_char_3_19-vigil.js`
|
||
|
||
- **Seen**: a pack losing its last 狼影 died and came back after 10 s with 2 狼影; S1 fired and paid its DP with no pack
|
||
on the field. **Official**: PRTS 伺夜 talent and 狼群 备注 — the last 狼影 lost or a 撤退 turns the pack into its
|
||
战术点形态 (无敌, no attack) for the 25 s talent interval, then back with 1 狼影; S1 casts only with the pack on the field:
|
||
① the form returns at once, ② +1 狼影, ③ at the cap HP to max. **Now**: `installWolfTacticalPoint` keeps a 'killed' /
|
||
'retreat' pack as a knocked-out piece (tile reserved) while 伺夜 stands, back after 25 s at full HP with 1 狼影; S1 is
|
||
the kit's own cast in either form (+cost DP, ① ② ③). S2 in the form: §25.7.9. [ASSUMED]: the return is a redeploy (仇恨
|
||
order, deploy hooks); a form at the combat's end enters 联防 fresh. Golden: roster-007 / 009 / 026 / 028 / 040,
|
||
bond-siracusaShip-high and the bot matches fielding 伺夜. Tests: `test/content/kits_alt_t3.test.js`, `kits_t3`,
|
||
`tokens_devices`.
|
||
|
||
#### 25.6.6 Touch: S3's extra heal, 「低于」 half HP, 攫升 on every heal, 超脱 on a dying exit (review of the stand-in kits) — `content/tokens.js touchGospel / mapCharTalents`, `kits/ops/standin-acmedc.js`
|
||
|
||
- **Seen**: S3's extra heal copied the boosted main heal; the boost applied at exactly 50 %; 攫升 missed self / zero
|
||
heals; 超脱 missed 余烬 exits. **Official**: PRTS Touch (卫戍协议) — the extra heal is 30 % of the main heal on x-5,
|
||
lowest ratio first, boosted itself on units 「低于」 half HP; 攫升 3 SP for any heal; 超脱 5 SP on dying exits too.
|
||
**Now**: the extra heal = `battle.heal(Touch, recipient, base × 0.3)` once per heal action with its own boost; the boost
|
||
strictly below `hp_ratio`; 攫升 on every heal she outputs; 超脱 on a knock-out or `Battle.retreat(…, { dying: true })`
|
||
(the 外勤医疗 strategy's Touch shares the code). [ASSUMED]: equal ratios go to the main target; 骑士戒律 + 竞技旗's exit
|
||
counts as dying. Golden: roster-041, standin-03 / 04 / 08 / 09 / 10, coop2-NORMAL-14-standins. Tests:
|
||
`test/content/standin_acmedc.test.js`, `tokens_devices.test.js`.
|
||
|
||
#### 25.6.7 突袭: a passive skill that is on counts as 技能就绪 (GitHub #49) — `content/bonds/addon/battle.js raidPoll`
|
||
|
||
- **Seen**: 突袭 members with passive skills (缄默德克萨斯, 宴, 斯卡蒂 S2 …) waited for the 10 s idle trigger. **Official**:
|
||
PRTS 【突袭】 — idle 10 s or 技能就绪, no enemy in range → redeploy beside a ground enemy; nothing on passives. **Now**:
|
||
`raidPoll` counts a passive that is on, and since the PR #109 port a deploy-timed duration skill while its window runs
|
||
(§25.9); §22.2's landing rule kept. [ASSUMED]: 「技能就绪」 = the skill is running. Golden: roster-039 / 046,
|
||
bond-raidShip-low / high, boss-boss_2 / 4 / 6-pair, standin-01 / 06, coop2-HARD-4, coop2-NORMAL-14-standins. Tests:
|
||
`test/content/bonds_addon.test.js`.
|
||
|
||
#### 25.6.8 生命回复速度 is not 治疗 (GitHub #96 / #137; the separation proposed in PR #135 by @SpiritedAwayCN) — `sim/damage.js` (heal `regen`), `professions.js bardRegen`, kits of 魔王 ×2, 浊心斯卡蒂 (+ 海嗣), 调香师, 瑕光, 铃兰, 锡人
|
||
|
||
- **Seen**: per-second HP effects were heals, refused on 无法被友方治疗 / 禁疗 units (#96: 隐德来希 got nothing from 浊心斯卡蒂;
|
||
#137: 折桠 and 圣约送葬人 from 调香师). **Official**: PRTS 吟游者 raises 生命回复速度; the 备注 of 调香师, 瑕光 S2, 铃兰 S3, 锡人 S2 —
|
||
unaffected by 治疗加成 and 禁疗. **Now**: hpRegen buffs the provider refreshes, applied as the target's own regen tick (no
|
||
healing multiplier, no heal hook): the 吟游者 trait (`bardRegen`), 调香师, 瑕光 S2, 铃兰 S3, 锡人; direct heals unchanged
|
||
(引星棘刺 S1 / S2, 塞雷娅 S3, 流明's and 纯烬's HoTs stay heals). kits/README.md checklist item 11. [ASSUMED]: the buffs
|
||
refresh from the start; two providers add up. Golden: 50 scenarios that field a converted operator (listed in the
|
||
merge). Tests: `test/content/feedback5-regen.test.js`, the kits' tests, `test/sim/professions.test.js`.
|
||
|
||
### 25.7 WE1 — engine-fidelity follow-ups (sim rules)
|
||
|
||
#### 25.7.1 秘术师 store energy at the attack check, not one interval later (GitHub #181, reported by Paper-Yuan) — `professions.js installMystic` (`storeEnergy` / `releaseEnergy` / `hitsFn`), `ai.js updateAlly / performAttack`
|
||
|
||
- **Seen**: 深靛 stood 4.2 s after binding the only enemy; with no enemy the first energy came after 6 s. **Official**:
|
||
PRTS 分支特性信息 §秘术师 — storing shares the attack interval: at the check, a target → attack; none and energy not full
|
||
→ store (an attack action); idle only when full. **Now**: `updateAlly` stores at the check when nothing is valid and
|
||
restarts the interval; `releaseEnergy` spends the energies with the next attack, one arts hit each; 维伊 and 黑键 use
|
||
the shared check. [ASSUMED]: a redeployment holds no energy. Golden: roster-003 / 021 / 022, bond-preciShip-high,
|
||
diy-032, diy-114 and 13 matches fielding 深靛. Tests: `test/sim/feedback5-mystic-store.test.js`.
|
||
|
||
#### 25.7.2 Enemy attacks strike at their damage frame; a short stun before it cuts the swing (GitHub #187 point 1, #170) — `ai.js updateEnemy / enemyAttack / attackWindup / attackTargets`, `battle/spawns.js` (`enemy.swing`)
|
||
|
||
- **Seen**: short stuns never stopped an enemy attack (忍冬 S3's stun showed, the hit still landed): a stun only paused
|
||
the cooldown. **Official**: PRTS 异常效果 — STUNNED cannot attack, DISARMED interrupts; the damage lands at the clip's
|
||
strike frame (data/enemies.json `attackAnim.hit`). **Now**: an enemy with an attack clip strikes at its damage frame;
|
||
stun / freeze / sleep / 浮空 / 缴械 / 恐惧 or losing every target before it cut the swing (restart from the wind-up), a
|
||
stun in the cooldown only pauses it, shots in flight land; 36 of 249 kinds without a clip keep the old rule (§5.5;
|
||
withdraws §22.14's [ASSUMED]). [ASSUMED]: targets re-taken at the frame; an interrupted swing keeps its cooldown.
|
||
Golden: 275 of 283 scenarios moved (solo-HARD-2 now wins, coop2-NORMAL-8-serverrun loses in round 13). The owner kept
|
||
the rule on 2026-10-06 (follow-up 29, §25.10). Tests: `test/sim/feedback5-enemy-swing.test.js`,
|
||
`feedback2-enemy-attack-stand.test.js`.
|
||
|
||
#### 25.7.3 武者: the trait heal on every damage instance, through the own 禁疗 (follow-up 1) — `professions.js installMushaHeal / installReaperHeal`, `kits/ops/op-helage.js`, `op-zuole.js`
|
||
|
||
- **Seen**: a 武者 healed once per enemy struck (a double strike healed once). **Official**: PRTS §武者 — 常态持有禁疗,
|
||
ignored by the unit's own trait / talent / skill heals; the trait heal follows every damage output. **Now**: one heal
|
||
per damage instance dealt to an enemy (skill, item and bond damage too; not dodged hits, 流失, element 损伤, talent or
|
||
DoT damage), passing `ignoreHealFree`; 收割者 keeps its own rule. Golden: diy-007 / 008 / 009 (赫拉格), diy-033 / 034 /
|
||
035 (左乐); 宴 unchanged. Tests: `test/sim/feedback5-musha-heal.test.js`.
|
||
|
||
#### 25.7.4 庇护 is one effect per unit, the strongest counts (follow-up 18) — `kits/shared/tier1.js PROTECT / holdProtect`, kits 宴, 余, 缪尔赛思, 赫拉格, 左乐, 赫德雷
|
||
|
||
- **Seen**: the older kits used private 庇护 multipliers, so two sources multiplied (25 % + 18 % → 38.5 %). **Official**:
|
||
ba.protect — same-name 庇护 take the highest (遥's bubbles use another key). **Now**: `holdProtect` applies the shared
|
||
`PROTECT` effect (`applyStrongest`), refreshed by each kit; the 自选 kits already did. Golden: unchanged. Tests:
|
||
`test/content/feedback5-protect.test.js`.
|
||
|
||
#### 25.7.5 "治疗生命值低于50%…" compares as each module's client buff does (follow-up 19) — `kits/shared/tier4.js installLowHpHealBonus`, `kits/shared/tier5.js lowHpHealUp`
|
||
|
||
- **Official**: the client module buffs — LT for 瑕光 / 古米 / 塞雷娅 / 录武官 / Touch, LE for 华法琳 / 闪灵 / 黍 / 凯尔希.
|
||
**Now**: 华法琳's and 闪灵's PHY-X heal ×1.15 at or below 50 % (不高于), the LT ones strictly below; 黍 and 凯尔希 were
|
||
already ≤. Golden: unchanged. Tests: `test/content/feedback5-lowhp-heal.test.js`.
|
||
|
||
#### 25.7.6 链愈师: the heal jumps within the 3×3 around the last one healed (follow-up 27) — `ai.js chainHealNext / doHeal`, `kits/ops/op-monstr.js`
|
||
|
||
- **Seen**: 莎草's chain jumped within 2.5 tiles, Mon3tr's kit within the 3×3. **Official**: PRTS §链愈师 — jump range x-4
|
||
(3×3), no repeat, ×75 % per jump, lowest HP ratio first then the latest deployed, full-HP allies selectable, bound by
|
||
禁疗. **Now**: `chainHealNext` serves the profession and Mon3tr. [ASSUMED]: a 禁疗 unit is never a jump target. Golden:
|
||
roster-004 / 005 / 023 / 024, bond-sargonShip-low, diy-133 / 134. Tests: `test/sim/feedback5-chain-heal.test.js`.
|
||
|
||
#### 25.7.7 One reading of charge_token[born]: the owner's redeployment readies a waiting summon (follow-up 20) — `kits/ops/op-phatom.js`, `op-kalts.js`
|
||
|
||
- **Official**: the client buff template — `charge_token[born]` on the owner's birth (NORMAL timing); the other summoner
|
||
kits read it so. **Now**: 傀影's (re)deployment readies a waiting 镜中虚影 at once, as 凯尔希's does Mon3tr. [ASSUMED]:
|
||
NORMAL = usable now. Golden: unchanged. Tests: `test/content/feedback5-summon-recharge.test.js`.
|
||
|
||
#### 25.7.8 Misery's S1 / S2 are deploy-timed duration skills (follow-up 12) — `kits/ops/standin-acspec.js`
|
||
|
||
- **Now**: 物理的服从 / 战争的恭顺 (PASSIVE / ON_DEPLOY, 10 s) are `kind: 'duration'` with `activateOnDeploy` — a start and an
|
||
end at every deployment, the PR #109 contract; numbers unchanged. Golden: standin-01, standin-06. Tests:
|
||
`test/content/standin_acspec.test.js`.
|
||
|
||
#### 25.7.9 伺夜 S2 casts while the pack is in its 战术点形态 (follow-up 2) — `kits/ops/chess_char_3_19-vigil.js` (installGift)
|
||
|
||
- **Now**: S2 casts when ready while the pack is on the field in either form and holds no unused gift; in the form it
|
||
pays its DP at once and the gift waits for the returning pack. [ASSUMED]: S2's 备注 uses S1's words, so the form counts
|
||
as on the field. Golden: unchanged. Tests: `test/content/kits_alt_t3.test.js`.
|
||
|
||
#### 25.7.10 「同时攻击阻挡的所有敌人」 takes up to the block count of targets (the queued centurion question; Mon3tr S3) — `ai.js acquireTargets / targetCount` (`hitAllBlocked`)
|
||
|
||
- **Official**: PRTS §强攻手 / 重剑手 / 推击手 — max targets = the block count (≥ 1), blocked enemies first; the client
|
||
flag `_limitedMaxTargetNumToBlockedCnt`. **Now**: an attack with `hitAllBlocked` takes max(1, ⌊block count⌋) +
|
||
`maxTargets` mods targets from its range, blocked first (§5.5); Mon3tr S3 drops its `maxTargets: 1`. [ASSUMED]: the
|
||
mods add to the block count. Golden: 52 scenarios with such an attacker. Tests:
|
||
`test/sim/feedback5-block-targets.test.js`.
|
||
|
||
### 25.8 WE2 — fidelity follow-ups (data, match, UI)
|
||
|
||
#### 25.8.1 Summon hand counts from the tokens' own talents (follow-up 21) — `tools/build-data.mjs tokenTalentDeckBonus`, `match/player/diy.js placeableTokens`
|
||
|
||
- **Seen**: placing 麦哲伦 or 令 gave one summon piece, 白铁 one device, 夜莺 one 幻影. **Official**: PRTS 卫戍协议/帮助
|
||
§战斗部署 — the hand gets as many summons as the deploy limit, not the initial stock; the owners' talents give 3 at once /
|
||
5 held (麦哲伦, 令, 电弧), 2 / 3 (白铁, 娜斯提), 幻影 3. **Now**: the token talents' `max_deploy_count` /
|
||
`max_deck_stack_cnt` join the variant stats; hand counts 麦哲伦 / 令 3 (4 with SUM-Y), 电弧 3, 白铁 2, 夜莺 3, 娜斯提 2, 望 6
|
||
(TRP-X 7), 多萝西 9 (the hand's cap), others 1. Golden: unchanged. Tests:
|
||
`test/content/feedback5-we2-summon-hand.test.js`.
|
||
|
||
#### 25.8.2 望's 棋子 on any tile; no hand card for 予愿安洁莉娜's “一会儿见!” (follow-ups 22, 24) — `tools/build-data.mjs TOKEN_POSITION_CORRECTIONS / summonRecord`
|
||
|
||
- **Official**: PRTS 棋子 部署位置 全部位 (its 备注: the in-game summon info is wrong); PRTS “一会儿见!” is not selectable and
|
||
her `displayTokenDict` is empty. **Now**: the 棋子's `position` is ALL (a 高台 too); a summon is `placeable` only when an
|
||
owner displays it, so the marker stays out of the hand (the kit places it). Golden: unchanged. Tests:
|
||
`test/match/feedback5-we2-placement.test.js`, `test/content/op_aglna2.test.js`.
|
||
|
||
#### 25.8.3 Where 重构体 and 战术锚点 may stand (follow-up 26) — `tools/build-data.mjs summonRecord`, `match/board.js positionClass / canPlace`, `match/player/placement.js _legal / summonExcluded / _liftOutOfRange`
|
||
|
||
- **Official**: Mon3tr's 自我修复 — 重构体 on the ground inside her attack range; PRTS 战术锚点 — only ranged tiles outside
|
||
凯尔希·思衡托's attack range. **Now**: `ownerRange` from the owner's talent, new `ownerRangeOutside` / `rangedTilesOnly`;
|
||
an owner turned or promoted so that her range covers the 战术锚点 sends it back with a toast; client and bot follow.
|
||
[ASSUMED]: "ranged operators may stand on melee tiles" does not widen the 战术锚点. Tests:
|
||
`test/match/feedback5-we2-placement.test.js`.
|
||
|
||
#### 25.8.4 Triggers re-checked: 黑键 S2 at full SP with one free tile; 黍 S3's ally rule in the data (follow-ups 23, 17) — `kits/ops/op-ebnhlz.js`, `tools/build-data.mjs TRIGGER_ALLY_RULES`, `sim/simdata.js normalizeSkill`
|
||
|
||
- **Official**: 黑键 S2 (AUTO) 备注 — no deployable tile in range → no cast, so the condition is a free tile, not an enemy;
|
||
act2autochess `TRY_SEARCH_ALLY_SKILL` (黍 S3) = an injured ally on the skill range. **Now**: 黑键 S2 is the kit's cast at
|
||
full SP with a free attack-range tile; 黍 S3 resolves to SKILL_RANGE + `allies` in the data (the kit override is gone);
|
||
温蒂's cannon (DEFAULT) and 凯尔希·思衡托 S2 (ACTIVE_RANGE on an injured ally) stay. Golden: diy-114 / 115 / 116. Tests:
|
||
`test/content/op_ebnhlz.test.js`, `op_shu.test.js`.
|
||
|
||
#### 25.8.5 Kit-side larger-range triggers: 谬因 S2 and 薇薇安娜 S3 (follow-up 16) — `kits/ops/op-aphris.js`, `op-vvana.js`, `sim/skills.js setTrigger`
|
||
|
||
- **Now**: the scan of the 41 kitted 自选 MANUAL skills found two whose running range the data cannot hold (§25.5): 谬因
|
||
S2's beam path is a content trigger range; 薇薇安娜 S3 switches to ACTIVE_RANGE 3-2 after its first cast of a
|
||
deployment (new additive `skill.setTrigger`). [ASSUMED]: the owner's rule read through these kit ranges. Golden:
|
||
diy-045, diy-078. Tests: `test/content/feedback5-we2-area-triggers.test.js`. The skills that act through their
|
||
summons' areas (麦哲伦 S1, 令 S3, 电弧 S2 / S3) waited for the owner: §25.11.2.
|
||
|
||
#### 25.8.6 自选 rosters refuse SO-A / SO-B / RA-A like ISW-A (follow-ups 25, 10) — `shared/diy.js DIY_EXCLUDED_MODULE_TYPE`
|
||
|
||
- **Official**: their texts name other modes (集成战略 / 生息演算); battle_equip_table gates them (`validInGameTag`).
|
||
**Now**: `/^(?:ISW|SO|RA)-/` modules are refused by `validateDiyPicks`, dropped by `checkDiyPicks` and hidden by the
|
||
picker. [ASSUMED]: the reason of the owner's ISW-A decision applies. Tests: `test/diy.test.js`, `test/ui/diy-ui.test.js`.
|
||
|
||
#### 25.8.7 自选 in the match: random grants draw 自选 pieces, the banned line, AI 托管 (follow-ups 9, 11, 13) — `match/player/diy.js diyStockEntries`, `effectsMeta.js rollChess / rollPool`, `ui/gameLogic/diy.js diyBannedPieces`, `ui/matchInfo.js`, `match/bot.js buyScore / levelUp`
|
||
|
||
- **Official**: PRTS / the season notes — 自选 pieces widen the 调度中心's random range. **Now**: bands, items, 特质, 机变 cards
|
||
and reward pools that grant a random operator also draw the player's own 自选 stock (never another player's); a
|
||
slotted piece left out of the shop (every bond banned) is named under 本局禁用干员 in the briefing, the draft's match info
|
||
and the in-game tab; AI 托管 scores the player's own 自选 piece higher and levels 调度中心 one round earlier for its tier.
|
||
[ASSUMED]: the 托管 preference (bonus 12, one round). Golden: coop2-NORMAL-70-diy. Tests:
|
||
`test/match/feedback5-we2-diy-grants.test.js`, `test/ui/feedback5-we2-diybanned.test.js`,
|
||
`test/match/feedback5-we2-bot-diy.test.js`.
|
||
|
||
#### 25.8.8 Smaller items: 塑心's cap, 斩业星熊's normal attack, GitHub #148, the shims (follow-ups 30, 15, 3, 5) — `content/garrisons/battle.js fireGain`, `tools/build-data.mjs classifyAttack`, `content/bonds/addon/battle.js raidTile`
|
||
|
||
- 塑心 (garrison_90): the per-battle cap (10 / elite 20) is the trait instance's whichever bond is highest — a new highest
|
||
bond no longer opens a fresh cap (found in the PR #178 review; `test/content/feedback5-we2-garrison90.test.js`).
|
||
- 驭法铁卫 (斩业星熊): the data's normal attack is physical — arts only while a skill runs (display and AI only).
|
||
- GitHub #148 reproduced: a melee 突袭 member never lands on a 高台; on 战场#08 it lands on a 围墙 tile (deployable, drawn
|
||
raised), so no rule changed here (`test/content/feedback5-we2-raid-148.test.js`); the owner then chose a landing
|
||
tile where it can block (2026-10-06, §25.11.3).
|
||
- The `kits/tier1..6.js` re-export shims and `shared/standIn.js diyRecord` are removed.
|
||
|
||
### 25.9 Ports from 0.1.4 (W5M, W5R and the feedback4 merges)
|
||
|
||
0.1.4 (§24, CHANGELOG 0.1.4) shipped from feedback4 while the refactor ran; every fix was ported by hand into the split
|
||
layout, with the golden moves each named: PRs #150, #66, #146, #74, #72, #103, #149, #109, #160 and W4A (高台 by the
|
||
trait, the 阿戈尔 revive slots, the 联防 devour) in W5M; PR #129 (teammate scouting); the restarted-cast events and 伊内丝's
|
||
影哨 before 不屈; PR #73 (operator battle voices, §21.30) and the settlement line's speaker; PRs #186, #134, #185, #24, #183
|
||
(their 42 new strings through `t()`); W4B (阿戈尔's devoured ATK as a 最终加算, a fallen marker's marks, 缇缇 S2's pulses,
|
||
§24.7 / §24.8); W4D (a sleeping enemy cannot be blocked, §24.9; W5R, §25.9.1) and W4C (a tap on the board stays on
|
||
its tile, §18.1; §25.9.2). Where a 0.1.4 change met 0.2.0 work:
|
||
|
||
- **突袭 × PR #109**: deploy-timed skills became duration skills, which the #49 rule (a passive that is on) missed;
|
||
`raidPoll` counts a skill that needs no SP while its window runs (`test/content/bonds_addon.test.js`).
|
||
- **一击即退 × PR #109**: the generic deploy-timed passives (the 预备干员-特种 stand-in) are `kind: 'duration'` too
|
||
(`content/generic.js`; numbers unchanged).
|
||
- **The invite line (PR #103) × i18n**: the copied line goes through `t()`, Chinese byte-identical to the PR's.
|
||
- **高台 by the trait × 补位**: a stand-in is placed by its own trait (`placeClass`, `piecePosition`); of the 自选 picks only
|
||
温蒂 carries the line.
|
||
- **Voices × 补位 / 自选**: the stand-in or the 自选 operator on screen speaks for itself; the settlement line, which never
|
||
played (it looked up chess ids as character ids), now names the record the own piece shows (`screens/game.js ownShown`).
|
||
|
||
#### 25.9.1 沉睡 frees the block slot on the split layout; 酒神's 迷狂牢笼 skips a sleeper too (W4D, GitHub #140; ported by W5R) — `sim/battle/blocking.js _checkBlock`, `sim/battle/status.js applyStatus`, `sim/ai.js updateEnemy`, `sim/buffs.js` (`sleep`), `kits/ops/chess_char_3_12-blemsh.js` (瑕光 S2), `kits/ops/op-phatm2.js cageBlock`
|
||
|
||
- **Port**: §24.9 (the rule, PRTS 异常效果 SLEEPING = 无法行动+无敌+不可阻挡, the owner's decision of 2026-10-06), its §24
|
||
intro entry, the §5.5 Blocking sentence and §22.8's "(since §24.9)" came over from feedback4 unchanged; §24.9's heading
|
||
now names the 0.2.0 files above (0.1.4 had them in `sim/Battle.js` and `kits/tier3.js`). On the split layout
|
||
`_checkBlock` (battle/blocking.js) refuses `flags.sleep` and `applyStatus` (battle/status.js) releases an enemy that
|
||
falls asleep. WE1's swing cut (§25.7.2) runs before `enemyAttack`, but a plain-buff `flags.sleep` still makes the
|
||
enemy `stun` (`units.js`), so its release stays in `updateEnemy`'s cannot-act branch, after the cut: the swing is
|
||
cut, the enemy is let go, and it stands until it wakes.
|
||
- **New on feedback5**: 酒神's 迷狂牢笼 (O22, `cageBlock`) blocked every unblocked enemy on its tile but the old three
|
||
不可阻挡 flags; it now skips a sleeper too (PRTS BLOCK_FREE 「无法阻挡/被阻挡」: no blocker of any kind). Before, the 牢笼
|
||
held the sleeper, refreshed its own HP and block count for it and lost it on the enemy's next update. 予愿安洁莉娜's S3
|
||
helper needed no change (`canTargetEnemy` never returns a sleeper). Followed without code: `blockedTargets`, the 要塞
|
||
branch of `acquireTargets` (`u.blocking`), “庞贝”'s clock (`blockedBy`), the snapshot's `UF.BLOCKED` and the client's
|
||
block marker; 死芒 S2 折朽 (自选) sleeps the enemies it links — one her 悲叹的仆役 held is let go, and SOC-X's
|
||
×atk_scale on "an enemy one of her summons blocks" no longer applies to it.
|
||
- **Golden** (feedback5's own list; a probe over all 283 scenarios counted the sleeps of blocked enemies, in brackets,
|
||
and every scenario that moved has some; the outcomes differ from §24.9's because feedback5's baselines differ, WE1's
|
||
damage frame first): roster-003 (小满 S2 [5]: the same fight, `blocked` 27 → 29 and the snapshot hashes); roster-005
|
||
(elite 小满 S2 [3]: the 140 s timeout with 83 kills and 1 leak, where it cleared at 135.43 s with 84); roster-013 (缇缇
|
||
S3 [11]: the same kills, `blocked` 22 → 33); roster-032 (缇缇 S1 [10]: 71 kills instead of 68, 8 leaks instead of 11,
|
||
4 knock-outs instead of 8, 萨尔贡 layers 41 → 35); roster-038 (elite 缇缇 S2 [1]: ends at 197.40 s instead of
|
||
197.27 s); roster-039 (瑕光 S2 normal + elite [31 + 12]: the same kills and counted leaks, the 窃贼 gets away, `blocked`
|
||
53 → 87); roster-042 (缇缇 S2 [3]: ends at 168.77 s instead of 166.93 s); bond-maniShip-high (小满 [1]: `blocked`
|
||
29 → 30, the snapshot hashes); solo-FUNNY-1 (ai_0's 缇缇 [3]: only ai_0's damage dealt); coop4-FUNNY-6 (ai_0's 缇缇
|
||
[15 + 56]: from round 9 ai_0's 精准 / 萨尔贡 layers and boss damage move, ai_1 loses no LP from round 11, team LP
|
||
124 → 130); coop4-ABYSS-7 (ai_2's 小满 [18]: ai_2 one kill fewer, ai_0 one more LP lost in round 9);
|
||
coop2-NORMAL-8-serverrun (ai_1's 缇缇 [83]: only ai_1's damage dealt — WE1 had already turned this match into a loss);
|
||
coop2-NORMAL-70-diy (the 自选 seat h_0's 缇缇 [171], ai_0's 缇缇 [74] and 小满 [19 + 21]: h_0's layers move from round
|
||
4, then its AI 托管 buys differently, boards from round 7; ai_0 246 kills instead of 233, the same end); diy-131 (死芒
|
||
S2 at tiers 5 and 6 [1 + 1]: the snapshot hashes only); diy-132 (elite 死芒 S2 [2]: ends at 199.50 s instead of
|
||
198.13 s, the same kills). coop2-HARD-4 sleeps a blocked enemy [1] and did not move: the sleeper wakes with no room
|
||
and is blocked further on, and a match digest has no snapshot hashes (its kills, leaks, damage and funds are the
|
||
same). `fields` and `standins` did not move; no scenario spawns a 牢笼 over a sleeper.
|
||
- Tests: `test/sim/feedback4-sleep-unblock.test.js` (5 cases, from feedback4) passes unchanged on the split layout;
|
||
every case fails with the three sim hunks reverted, case 3 (the plain-buff sleep) with only the `ai.js` release
|
||
reverted.
|
||
|
||
#### 25.9.2 A tap on the board stays on its tile; long browser waits poll in slices (W4C, the 0.1.4 release candidate; PR #149) — `render/app.js onTapTarget`, `test/e2e/client.mjs waitForFunctionLong`
|
||
|
||
- **Seen** (the 0.1.4 release candidate, `test/render/models.browser.test.js` #4.1 touch): at 844×390 a tap on the row-12
|
||
unit opened the bond popup instead of selecting it. **Cause**: the browser's touch adjustment moves a tap onto a
|
||
nearby element that responds to clicks (pointer listeners do not count) when the finger's contact area reaches one,
|
||
and PR #149's 收起 toggle (§10) had pushed the bond discs one button (≈ 55 px) to the right, over row 12. **Now**
|
||
(§18.1 Touch): the field canvas is a click target of its own (a no-op `click` listener, `app.js onTapTarget`), so a
|
||
tap on the board stays on its tile; the browser test passes with #149's client diff reverted and fails with it.
|
||
Ported as is (`render/app.js` keeps `createFieldView`, §25.1).
|
||
- **Test harness**: the real-server browser suites' long waits poll in slices under the browser's 90 s CDP protocol
|
||
timeout (`waitForFunctionLong`, `PROTOCOL_TIMEOUT_MS`). Puppeteer runs a whole `waitForFunction` poll inside one
|
||
`Runtime.callFunctionOn`, so watch-bonds' 240 s wait died with a bare "Waiting failed" whenever the own battle
|
||
outlasted 90 s (playtest2.real's 120 s wait had the same gap) — a harness timing flake, no product change.
|
||
- Golden: unchanged (client and tests only). Tests: `test/ui/playtest2.test.js`, `test/e2e/client-wait.test.js`;
|
||
browser: `test/render/models.browser.test.js` (`RENDER_E2E=1`), `test/ui/watch-bonds.e2e.test.js` and
|
||
`test/ui/playtest2.real.e2e.test.js` (`SP_E2E=1`).
|
||
|
||
### 25.10 Settled decisions, what stays [ASSUMED], and the questions left to the owner
|
||
|
||
| Decision | Settled |
|
||
|---|---|
|
||
| No web framework: plain `node:http` + `ws` (§25.1) | the owner, 2026-10-04 |
|
||
| The 补位 plan: the 55 NORMAL chess droppable, all owned by default, no borrowing, bots own everything (§25.3) | the owner, 2026-10-05 |
|
||
| A not-owned chess shows as its stand-in everywhere (§25.3) | the owner's recall, 2026-10-06 |
|
||
| 自选编队: 2 + 2 slots, owned 6★ with a kit, any skill / module, prototypes locked, per-player shop, levels by the chess forms (§25.4) | the owner, 2026-10-05 |
|
||
| The collab 6★ out of the 自选 pool, 焰狐龙梓兰 included; ISW-A refused (§25.4) | the owner, 2026-10-05 |
|
||
| Chinese default, English switch, official EN game texts, PR #70 credited (§25.2) | the owner, 2026-10-05 |
|
||
| The larger-range rule (ACTIVE_RANGE) on DEFAULT, on SEARCH and for 深巡 S2 (§25.5) | the owner, 2026-10-05 (deliberate deviation) |
|
||
| The 重装 stand-ins and every 自选 重装 cast with an enemy in range (§25.5) | the owner, 2026-10-05 (deliberate deviation) |
|
||
| 纯烬艾雅法拉 S1 at full SP; 伺夜 S1 only with his pack on the field (§25.5, §25.6.5) | the owner, 2026-10-05 |
|
||
| Enemy attacks strike at their damage frame; a short stun before it cuts the swing (follow-up 29, §25.7.2) | the owner, 2026-10-06 (kept) |
|
||
| 望's placed 棋子 take and return her stock, so S1 / S2 keep cycling (§25.11.1) | the owner, 2026-10-06 (deliberate deviation from 「不消耗持有数量」) |
|
||
| Skills that act through summons cast on an enemy in a summon's area: 麦哲伦 S1, 令 S3, 电弧 S2 / S3 (§25.11.2) | the owner, 2026-10-06 (the larger-range rule) |
|
||
| A melee 突袭 member lands on a tile where it can block before one where it cannot (GitHub #148, §25.11.3) | the owner, 2026-10-06 |
|
||
| 华法琳's granted trait stops at the data's 7 / 14 (PRTS 3/27: lowered from 12 / 24; GitHub #175, PR #192, §25.13.2) | the owner, 2026-10-06 (replaces the 12 / 24 lock) |
|
||
| A newly merged elite 拉普兰德 is a new 拉普兰德: +8 on its first manual refresh of the round (GitHub #169, §25.13.3) | the owner, 2026-10-06 (was [ASSUMED]: the copies' count carried) |
|
||
| The leader pool = bloodPoint × the players alive when the fight starts, solo × 1 (PR #209, §25.13.4) | the owner, 2026-10-06 (replaces 「保持固定血量」; config restores it) |
|
||
| Flying units hover 1.3 tiles; 帝国炮火先兆者 ×2 drawn 1.263× taller, 木制瑞印 mirrored (PR #211, §25.13.5) | the owner, 2026-10-06 |
|
||
| A bounty pays whenever its enemy dies — terrain and other 无来源 deaths included, in 联防 too (§25.14.3) | the owner, 2026-10-06 (relayed with the community reports) |
|
||
|
||
Settled by the sources in W5V, no longer questions: 泥岩 S3's dormancy is 闭锁 — she lets go and blocks nobody (PRTS,
|
||
§25.11.4); 阿 S2 / S3 keep the data's DEFAULT, 忍冬 S2's and 深靛 S1's notes are what the kits do (§25.11.5).
|
||
|
||
Still [ASSUMED] (each also in its code comment): potential 0 for every 自选 pick; the per-player 自选 stock 8 / 5;
|
||
bots field no 自选 piece; SO-A / SO-B / RA-A refused for ISW-A's reason; the AI 托管 preference for 自选 pieces; a
|
||
stand-in placed by its own position; the 联防 map names; 伺夜 S2 in the 战术点形态; the enemy swing's re-taken targets and
|
||
kept cooldown; a woken sleeper re-blocked in the enemy update order where it stands (§24.9); 望's card back in her hand
|
||
the moment a 棋子 leaves, a 棋子 over the cap lost, TRP-X's 7th placed 棋子 taking none, her stock kept through her
|
||
redeployment; 电弧 S2's area = 赛柯's 3-2 range, standing summons only; the official 突袭 landing taken as random among the
|
||
legal tiles, ranged members on the old order, the target's own tile counted as a blocking tile; 泥岩's 反制 during 闭锁
|
||
not modelled; the English of the remake's own strings; the lite zip without `public/fonts`, the zips' unchanged
|
||
package.json (maintainer scripts fail there); the 联防 payee of a bounty death no operator caused — the helper of the half
|
||
it fell on (§25.14.3); the stand-in and operator kit items of the tables above.
|
||
|
||
Left to the owner (none changed in 0.2.0): 淬羽赫默's 丰润羽翼 as 生命回复速度 (the client template, no PRTS note) and 遥's
|
||
break heal on the ATK cached at the grant (both kept, §25.11.5); whether a passive counts as 技能就绪 for the whole
|
||
deployment or its window only (§25.6.7); Stormeye S2 / Pith S1 (AUTO attack buffs) on DEFAULT or at full SP; 赫默 S2 and
|
||
巫恋 S2 (wasted with nobody to heal / no enemy); the AUTO cast of an attacker of 白铁's 铁钳号. Answered on 2026-10-06 and
|
||
moved to the table: 望's stock and 阻回, the 突袭 landing (GitHub #148), the trigger areas through summons; settled by the
|
||
sources: the ally condition for 阿 S2 / S3, 泥岩 S3's 闭锁.
|
||
|
||
Open polish (no rule): 34 or more of the 38 summons of the 自选 kits have no Spine skeleton in the online sources, so the
|
||
field draws them as the avatar placeholder (§25.12); `scripts/make-windows-bundle.mjs` still copies every tracked file
|
||
but test/ (it could reuse the package selection); the THIRD-PARTY-NOTICES "In the release bundle" column does not tell
|
||
the lite zip (no fonts) apart; the enemy prefabs whose default clips differ from the manifest's roles (猎狗pro, 大鲍勃,
|
||
碎骨, “斩胄之剑” / “破胄之锤”, §25.14.1).
|
||
|
||
### 25.11 The owner's decisions of 2026-10-06 and the items the sources settled (W5V) — `kits/ops/op-wang.js`, `kits/shared/summoner.js summonTriggerArea`, `content/bonds/addon/battle.js raidTile`, `kits/ops/chess_char_4_18-mudrok.js`
|
||
|
||
The questions WE2 and the kit waves had left open went to the owner as one batch on 2026-10-06; W5V implemented the
|
||
answers and checked the remaining items against PRTS and the client (W5V's commits name every golden scenario moved).
|
||
|
||
#### 25.11.1 望's placed 棋子 take and return her stock (the owner's decision of 2026-10-06) — `kits/ops/op-wang.js`
|
||
|
||
- **Seen** (O19, follow-up 22): in this mode her 棋子 are hand pieces deployed with the board, 「无视所属干员的持有状态,
|
||
不消耗持有数量」, so her stock stayed at 6; one S1 / S2 cast (「立即获得两枚棋子」) reached the cap 7, and 阻回 held her SP
|
||
for the rest of the battle — the skill cast once.
|
||
- **Official**: PRTS 卫戍协议/帮助 §作战阶段 (placed summons ignore the holding; one that leaves is redeployed in place once
|
||
the conditions are met); PRTS 望 铸子 (6 usable, 7 at most) and the S1 / S2 备注 (阻回 at the stock cap); the client's
|
||
charge_token templates (the stock = cnt at her deployment, the skills' +cnt, S3's overflow built as 跟子); a summon that
|
||
leaves returns to its owner's card while its redeploy time runs.
|
||
- **Decision**: the owner's decision of 2026-10-06, a deliberate deviation from 「不消耗持有数量」 — the placed 棋子 count in
|
||
her stock, and a 棋子 that goes off or returns replenishes it by the official rules, so her skills keep working.
|
||
- **Now**: every deployment of one of her 棋子 (the battle start's and each in-place return) takes one from her stock
|
||
(never below 0); a 棋子 that leaves the field (set off, or gone with her) puts one back at once, at most the cap; the
|
||
in-place return also waits for one in stock. At the cap a 棋子 that goes off is lost to the cap and its return takes
|
||
one, so the stock drops to 6, 阻回 lifts, her SP recovers and the next cast fills it again — S1 / S2 keep cycling.
|
||
S3's "+8, the overflow as 跟子" starts from the lower stock (2 placed: 4 + 8 → 7 with 5 跟子, was 7).
|
||
- [ASSUMED]: the card is back in her hand the moment the piece leaves (its redeploy time is the return's own wait); a
|
||
piece over the cap is lost; 7 placed 棋子 (TRP-X's deploy limit) on a stock of 6 — the 7th takes none; the stock carries
|
||
through her mid-battle redeployment.
|
||
- Golden: unchanged (no corpus battle places her 棋子). Tests: `test/content/op_wang.test.js` (9: the stock after the
|
||
placed pieces, a piece set off and its return, casts up to the cap, 阻回 only at the cap, a piece set off at the cap,
|
||
TRP-X's 7). Docs: docs/SIM.md (token pieces).
|
||
|
||
#### 25.11.2 Skills that act through summons cast on an enemy in a summon's area: 麦哲伦 S1, 令 S3, 电弧 S2 / S3 (the owner's decision of 2026-10-06) — `kits/shared/summoner.js summonTriggerArea`, `sim/skills.js` (`addTriggerRange` `{ keys, profile }`), `kits/ops/op-mgllan.js`, `op-ling.js`, `op-radian.js`
|
||
|
||
- **Seen** (WE2's scan, §25.8.5): their effects reach through the summons' areas, but the data's DEFAULT waits for an
|
||
enemy in the operator's own 3-1 (no data range can carry the larger area).
|
||
- **Official**: no trigger row (DEFAULT). The areas (PRTS, the client): 麦哲伦 S1 — 停顿 / 束缚 on her range and each drone's
|
||
range, air units too; 令 S3 — the x-5 around each summon, ground only (备注 「不可对空」); 电弧 S2 — 赛柯's bullets, ground
|
||
only; S3 — 停顿 + 法术脆弱 before her summons' damage, air units too (备注 「召唤物可对空」).
|
||
- **Decision**: the owner's decision of 2026-10-06, the larger-range rule (§25.5) read through the summons: cast when an
|
||
enemy is in the operator's range or in a deployed summon's area that the skill acts through.
|
||
- **Now**: `summonTriggerArea(battle, owner, skillId, area)` registers a content trigger range (checked every tick, on
|
||
top of the data's DEFAULT) built from the owner's standing summons, each giving `{ keys, profile }` — tile keys with the
|
||
enemy profile the effect selects by (`canHitFly` false: ground enemies only), a new additive entry form of
|
||
`addTriggerRange`. 麦哲伦 S1: each drone's range, air units too; 令 S3: each summon's x-5, ground only; 电弧 S2: each
|
||
summon's range (赛柯's 3-2), ground only; S3: each summon's range (桑特拉's 3-1), air units too. The other skills of the
|
||
three get no area.
|
||
- [ASSUMED]: 电弧 S2's area is 赛柯's 3-2 range, not its S2 bullets' longer flight (0.8 s ≈ 4 tiles at rank 7); only
|
||
summons standing on the field count.
|
||
- Golden: unchanged (no corpus battle places a 自选 summon). Tests: `test/content/feedback5-wv-summon-triggers.test.js`
|
||
(an enemy in a summon's area outside her range casts the skill; a flyer there does not for 令 S3 / 电弧 S2 and does for
|
||
麦哲伦 S1 / 电弧 S3; nobody in an area, or the drone off the field: no cast; all three fail with the helper switched
|
||
off). Docs: docs/SIM.md (content trigger ranges), the `skills.js` header.
|
||
|
||
#### 25.11.3 A melee 突袭 member lands where it can block (GitHub #148; the owner's decision of 2026-10-06) — `content/bonds/addon/battle.js raidTile`
|
||
|
||
- **Seen** (GitHub #148, reproduced in WE2, §25.8.8): a melee member never lands on a 高台, but it lands on a 围墙 tile
|
||
(drawn raised; it blocks nothing there) when that is the nearest tile covering its enemy, even with a road tile
|
||
covering it too.
|
||
- **Official**: 「再部署至一名地面敌人周围」 — no tile preference stated.
|
||
- **Decision**: the owner's decision of 2026-10-06 — prefer a landing tile where it can block an enemy over a tile where
|
||
it cannot; keep the rest of the landing rule.
|
||
- **Now**: for a melee member (position not RANGED) with a block count, `raidTile` ranks first the tiles where its block
|
||
applies — ground units pass the tile (not a 围墙 / 围栏: `Battle._blockerFor`) and an enemy ground path runs through it
|
||
(`Battle.groundPathTiles`) or its enemy stands on it — then the old order (nearest, then the facing frame). The rest of
|
||
§22.2's rule is unchanged: the 8 most advanced targets in turn, a tile from which its range covers the target,
|
||
`grid.canStand` (never a 高台, never the 深水区), free tiles, no useless jump. A 围墙 landing remains where nothing
|
||
else covers the enemy. §24.2's note on #148 points here.
|
||
- [ASSUMED]: the official landing picks among the legal tiles at random (the preference is the owner's); ranged members
|
||
keep the old order; "its enemy stands on it" counts as a tile where it blocks (a target off the computed paths).
|
||
- Golden: fields `boss-boss_2-pair`, `boss-boss_3-pair`, `boss-boss_4-pair`, `boss-boss_6-pair`, `boss-boss_7-pair`,
|
||
`hidden-boss_10-pair` — their 突袭 members (伊内丝, 缄默德克萨斯, 仇白) now land on a road tile of the enemy path instead
|
||
of a 围墙 tile (6 of the 8 changed landings) or an off-path road tile (2); roster / bonds / matches / standins / diy
|
||
unchanged. Tests: `test/content/feedback5-we2-raid-148.test.js` (updated on purpose: every stage × every low enemy
|
||
tile — never a 高台; whenever a tile where it blocks covers its enemy it lands on one; the old code fails at act1 m02).
|
||
|
||
#### 25.11.4 泥岩 S3's 10 s dormancy is 闭锁: she lets go and blocks nobody (PRTS) — `kits/ops/chess_char_4_18-mudrok.js`
|
||
|
||
- **Seen**: the kit kept her blocking through the dormancy of S3 秽壤的血脉 ("keeps blocking").
|
||
- **Official**: PRTS 泥岩 S3 备注 — the first 10 s are 闭锁, not 无法行动, with 眩晕 / 冻结 / 沉默 反制; PRTS 异常效果 — 闭锁
|
||
(SHELTERING) = 强制缴械 + 无敌 + 不可阻挡, and 不可阻挡 (BLOCK_FREE) 「无法阻挡/被阻挡,自动解除阻挡」: on an operator, it
|
||
blocks nobody and lets go of what it held (the enemy side of the same state: §24.9).
|
||
- **Now**: the dormancy adds the flag `noBlock` (with invulnerable and disarm): the enemies she held walk on (`ai.js` lets
|
||
go of a `noBlock` blocker) and she blocks none until she wakes. [ASSUMED]: the 备注's 反制 are not modelled.
|
||
- Golden: `roster-040` (it fields 泥岩 S3: the enemies she held walk on during the 闭锁). Tests:
|
||
`test/content/kits_alt_t4.test.js` (updated on purpose: the 闭锁 releases the three walkers and blocks none — enemies
|
||
placed on her tile neither —, awake she blocks again once their stun ends).
|
||
|
||
#### 25.11.5 Settled by the sources with no rule change: 忍冬 S2, 深靛 S1, 阿 S2 / S3; the shared 庇护 — kit comments, `test/content/feedback5-wv-sources.test.js`, `test/content/feedback5-protect.test.js`
|
||
|
||
- 忍冬: PRTS's 「无法选中被自身阻挡而没有位于技能范围内的敌人」 is the 备注 of S2 坠刃拷问 (技能范围 3-12), not of S3 (its only
|
||
备注 is the ASPD update; the client's S3 selector is the standard 「同时攻击阻挡的所有敌人」 one); the S2 kit already selects
|
||
on the 3-12 keys only — pinned.
|
||
- 深靛 S1: the S1 「每次攻击的攻击倍率」 applies to her stored energies (PRTS S1 备注; the client's ChargeAttackS1 reads the
|
||
same `atk_scale`), as the kit does (`ai.js resolveHit`) — pinned.
|
||
- 阿 S2 / S3: the data's DEFAULT — no trigger row names him; the skill prefabs cast with no target and keep the SP spent
|
||
(`_allowNoTarget` 1, `_checkHasTargetBeforeDoCast` 0, `_recoverSpIfNoTarget` 0); PRTS has no ally condition. With no
|
||
ally in his range the cast spends its SP and does nothing; the kit comment records the sources.
|
||
- 庇护: 淬羽赫默, 黍, 斥罪, 森蚺 and 娜斯提 grant it through the shared `holdProtect` (`kits/shared/tier1.js`, §25.7.4), 遥's
|
||
bubbles (their own key) through the shared `protectMods`; a guard test keeps kit-local copies out — a pure refactor.
|
||
- Kept as they are: 淬羽赫默's T2 丰润羽翼 as 生命回复速度 (the client's buff template atk_to_hp_recovery: 禁疗 does not
|
||
stop it, no 治疗加成) and 遥's T2 break heal on the ATK cached when the bubble is given (§25.10 keeps both open).
|
||
- Golden: unchanged.
|
||
|
||
### 25.12 Release packaging and the asset manifest (W5U; the 自选 voices) — `tools/package.mjs` (`npm run package` / `package:lite`), docs/DEPLOY.md §7, `tools/assets/plan.mjs`, `tools/assets/manifest.mjs`, `tools/fetch-assets.mjs`, data/assets.json
|
||
|
||
- **Seen**: 0.1.x releases came from a maintainer script outside the repository that zipped every tracked file (tests,
|
||
design docs, research notes, dev pages, the Windows-bundle maker) plus all of `public/assets` as it lay on the
|
||
maintainer's disk; there was no smaller download. 焰狐龙梓兰 left the 自选 pool (§25.4) but her art stayed in
|
||
data/assets.json, because fetch-assets refuses to shrink the manifest. The first real build found both
|
||
`module/dec-X.png` and `module/dec-x.png` listed — one file on Windows / macOS, so a zip built there carries one.
|
||
- **Official**: no game rule (release tooling). The collab exclusion is the owner's decision of 2026-10-05 (copyright);
|
||
the uniequip table spells one DEC X module `dec-X` (uniequip_003_aglina) and the others `dec-x`, and `WAH-Y` is the
|
||
other mixed-case type id.
|
||
- **Now**: `tools/package.mjs` builds `Stronghold-Protocol-v<version>.zip` (full) and `…-lite.zip`, each holding one
|
||
`Stronghold-Protocol/` folder, from an allowlist over `git ls-files`: `server/`, `shared/`, `data/`, `public/` (not
|
||
`public/dev/`), the start scripts and the tools a player runs (setup, vendor, fetch-assets + `tools/assets/`, doctor,
|
||
and what setup starts: `tools/local-extract/`, crop-board-atlas), the four research tables the server and fetch-assets
|
||
read (`03-operators`, `05-enemies`, `05-maps`, `07-assets`), package.json / lock, LICENSE / NOTICE /
|
||
THIRD-PARTY-NOTICES, README, CHANGELOG, docs/PLAYING.md and docs/DEPLOY.md; `npm ci --omit=dev` in the stage adds
|
||
node_modules and public/vendor. The full zip adds the files data/assets.json and data/local-assets.json list,
|
||
`public/fonts` and `public/assets/local/` — nothing else on disk, so her 15 files and other orphans never ship. Every
|
||
check also runs in `--dry-run`: the refusal list (0.1.x's plus test, .github, AGENTS.md, public/dev, `.env` / `.venv`
|
||
anywhere); imports and the player npm scripts resolve to shipped files; all listed art is present; no two paths differ
|
||
only in case; no shipped file holds a home-directory path or the machine's account name (text and binary, the name read
|
||
from the OS at run time); no shipped tracked file has uncommitted changes; a real build also checks the stage against
|
||
the plan. Measured on the 0.2.0 tree (before the voices below): full 421 421 613 bytes, 14 910 files, 589 MB unpacked;
|
||
lite 22 088 912 bytes, 6 430 files, 85 MB; the 0.1.x layout of the same tree zipped to 429 644 767 bytes (569 files
|
||
more, 25 MB more unpacked). Both stages boot; `setup --check` passes on the full stage and the lite stage plans the art
|
||
offline.
|
||
- **The manifest**: data/assets.json regenerated offline (`--offline --add-only --allow-shrink`) drops her 8 subtrees
|
||
(163 entries); module icons get one lower-case file per type (`module/<type in lower case>.png`: `modules.dec-X` and
|
||
`modules.WAH-Y` changed); `resolveTemplate` drops an array whose lines are all missing (it kept `{select: [], place: []}`
|
||
for the 71 自选 voice entries this machine had never downloaded); fetch-assets compares orphans (the `--prune` targets)
|
||
case-insensitively. Then (6499f4b) `fetch-assets --add-only` run online added the battle voices of the 71 自选 operators —
|
||
994 lines, 25.5 MB, `voiceChars` 120 → 191 (the manifest: 7 972 files, 485 MB) — and nothing else changed; the full zip
|
||
grows by about as much.
|
||
- **Open (polish)**: 34 or more of the 38 summons of the 自选 kits (Mon3tr, 麦哲伦's drones, 令's summons, 电弧's towers,
|
||
白铁's piles, 娜斯提's devices, 望's 棋子 …) have no Spine skeleton in the online sources (fetch-assets: "missing skel"),
|
||
and the manifest lists none of the 38 with a model, so the field draws them as the avatar placeholder; extracting them
|
||
from a local client (`tools/local-extract`) or keeping the placeholder is left for later.
|
||
- [ASSUMED]: the lite zip leaves out `public/fonts` too (fetch-assets downloads the fonts with the art); package.json
|
||
ships unchanged, so the maintainer scripts (`npm test`, `golden`, `package`) fail inside a zip; docs/img (the README
|
||
screenshots), docs/WINDOWS.md, docs/ASSETS.md and the Dockerfile stay out (Docker builds from a git clone).
|
||
- Golden: unchanged. Tests: `test/package.test.js` (9, no network: the selection on samples and on the real tracked tree,
|
||
the refusal list, a dry run and a `--no-install` build of a temporary checkout, the scans), `test/assets-diy.test.js`
|
||
(no `diy.excluded` operator keeps art; one lower-case module icon per type; no two manifest URLs differ only in case;
|
||
orphans compared case-insensitively), `test/assets.test.js` (the empty-array rule). Docs: docs/DEPLOY.md §7, the
|
||
README download section (full and lite), docs/ASSETS.md.
|
||
|
||
### 25.13 Round 18: GitHub #207, #175, #169 and the community PRs #192, #209, #211 (W5Y; the owner's decisions of 2026-10-06) — `server/match/builtinMeta.js`, `server/sim/content/garrisons/battle.js`, `server/match/player/acquire.js`, `server/match/gamedata.js bossPoolShareOf`, `render/units.js FLY_HOVER`
|
||
|
||
The round-18 triage of the open issues and pull requests left three bugs and three community changes for 0.2.0; the
|
||
owner decided the open questions on 2026-10-06. Each item is one commit (W5Y) naming the golden scenarios it moved; a
|
||
ported PR credits its author there and here.
|
||
|
||
#### 25.13.1 拟态物质 with 2 copies owned and the pool out gives nothing (GitHub #207) — `server/match/builtinMeta.js` (`use_equip_reward_char_chess`), `server/match/bot.js itemTarget`
|
||
|
||
- **Seen** (GitHub #207, reproduced in the triage): an elite 溯光星源 plus 2 normal copies hold all 5 of the Ⅵ阶 pool's
|
||
copies (3 + 2); 拟态物质 on one of the normal copies gave a random same-bond operator (白面鸮 on that seed; 至简 is in
|
||
the same roll). Also in 0.1.4.
|
||
- **Official**: the item text 「若已拥有至少2名该初始干员,则再获得1名该初始干员;否则随机获得1名同盟约初始干员」 — the 否则 is
|
||
the case of fewer than 2 owned; research 06 §7: some effects fail when the copy cap is hit.
|
||
- **Cause**: with 2 owned the handler returned only when `grantChess(base)` gave a piece; the null of an empty pool fell
|
||
through to the same-bond roll.
|
||
- **Now**: with 2 normal copies owned the item asks for the 3rd and stops there — none left in the pool, nothing is
|
||
given (the item is still consumed); the same-bond operator is only for fewer than 2 owned. With copies left the 3rd
|
||
copy still merges into the elite. The bots' carrier choice skips 2 copies whose pool is out.
|
||
- Golden: unchanged (no corpus match equips it on a pair whose pool is out). Tests: `test/content/items.test.js` (the
|
||
report — an elite and 2 normal 溯光星源, normal and golden item: nothing granted, no other operator, consumed; 2 copies
|
||
with the pool drained: nothing; 2 copies with copies left: the elite), `test/match/bot-smarter.test.js` (no bot carrier
|
||
on a pair whose pool is out). Docs: docs/META.md (built-ins, the bots' items), research 04 / 06.
|
||
|
||
#### 25.13.2 华法琳's granted trait stops at the data's 7 / 14 layers (GitHub #175; PR #192 by @kukiC; the owner's decision of 2026-10-06) — `server/sim/content/garrisons/battle.js`, `server/match/fields.js layerAllowanceOf`
|
||
|
||
- **Seen** (GitHub #175): the card says 至多7层, but the operator in front of 华法琳 gained up to 12 layers per bond in a
|
||
battle (the elite: 24). The cause was the remake's own override `GRANTED_CAP_OVERRIDE` (12 / 24 for garrison_95_a /
|
||
_b, in the battle and in the server's client-result layer bound), taken from research 02 Addendum 1. Also in 0.1.4.
|
||
- **Official**: PRTS 卫戍协议:盟约 下半, 3月27日更新#2调整 (revision 439189): 「[Ⅳ阶]华法琳:赋予的特质的叠层上限从 初始12/精锐24
|
||
降低至 初始7/精锐14」 — a nerf; the current 参战干员 record (下半/PRTS盟约记录) says 至多7层 / 14层, and the client
|
||
blackboard (`max_add_count_per_battle` 7 / 14) carries it with the other 3/27 numbers. The official notice 8584 says
|
||
only 「调整每场战斗至多获得的层数」. Addendum 1 had read the PRTS line backwards (7 / 14 raised to 12 / 24).
|
||
- **Decision**: the owner's decision of 2026-10-06 — follow the current page and the data: 7 / 14 (it replaces the
|
||
earlier 12 / 24 lock).
|
||
- **Now** (ported from PR #192 by @kukiC): the override is gone; a granted trait keeps its data cap like a native one —
|
||
the 7th cast in front of 华法琳 reaches 7 (elite: 14) and later casts add nothing; the client-result bound counts the
|
||
handed-out trait at the same cap. Research 00 / 01 / 02 corrected (02-bonds.json's note, copied into
|
||
data/bonds.json `miraShip.spec.layerGain`, regenerated offline — the only data change).
|
||
- Golden: unchanged (no corpus battle casts 8 times in front of 华法琳). Tests (from PR #192):
|
||
`test/content/garrisons_battle.test.js` (updated on purpose: the cap is the data's 7 / 14 — the 7th cast reaches it,
|
||
the 8th adds nothing), `test/match/feedback1-gaps.test.js` (the client-result bound with 华法琳 + 古米: 60 + 4·3 +
|
||
2 × cap passes, one more is refused), `test/ui/playtest3.test.js` (both cards show 至多7层 / 至多14层).
|
||
|
||
#### 25.13.3 A newly merged elite 拉普兰德 is a new 拉普兰德: its first manual refresh this round adds +8 (GitHub #169; the owner's decision of 2026-10-06) — `server/match/player/acquire.js _mergeChess`, `sim/content/garrisons/meta.js SERVER_GAIN_BOND_LAYER_BY_REFRESH_CNT`
|
||
|
||
- **Seen** (GitHub #169, new comments): two white 拉普兰德 that had already fired this round merged into the elite, and
|
||
the elite's next refresh added nothing. The triage confirmed the rest of the report is what the code does: each white
|
||
copy fires +4 on the first manual refresh it witnesses, also in the 整备区 (§21.1).
|
||
- **Official**: garrison_123 「<刷新时>若为本回合首次主动刷新,使已激活的【叙拉古】层数+4,此干员在整备区时也有效」 (the elite +8;
|
||
bb `refresh_cnt` 1); PRTS 下半 3月27日更新#2 changed only the amounts (+3 / +6 → +4 / +8). No source says whether a merge
|
||
resets the count; the code carried the copies' highest count onto the elite ([ASSUMED], conservative, since 0.1.1).
|
||
- **Decision**: the owner's decision of 2026-10-06 — a newly merged elite counts as a new 拉普兰德.
|
||
- **Now**: `_mergeChess` carries no per-piece round counter over (拉普兰德's refresh count is the only one): the elite starts
|
||
at 0 like any new piece, so its next manual refresh this round adds +8 and a later one nothing; an in-place promotion
|
||
(升华, 博士投影) keeps the piece and its count. A copy re-bought after a sale is still a new copy ([ASSUMED], unchanged).
|
||
- Golden: unchanged (no corpus match merges 拉普兰德 after a refresh in the same round). Tests:
|
||
`test/match/feedback1-meta.test.js` (updated on purpose: the elite made from copies that already fired adds +8 on its
|
||
next refresh, once; new: two white copies refreshed this round, merge, refresh → +8). Docs: docs/META.md (the counter
|
||
API, the edge cases), docs/PLAYING.md, the code comments.
|
||
|
||
#### 25.13.4 The leader pool is bloodPoint per player alive when the fight starts (PR #209 by @qingjingshenghuo; the owner's decision of 2026-10-06); 胄's drone share passes 限伤 — `server/match/gamedata.js bossPoolShareOf`, `server/match/finalAssault.js bossPoolHp`, `tools/build-data.mjs` (config `bossHpScale`), `sim/battle/combat.js loseHp`, `sim/content/bosses.js` (死亡集群)
|
||
|
||
- **Seen** (PR #209): the author's play of the official mode — the leader pool grows with the number of players; the
|
||
remake kept one fixed pool (co-op bloodPoint whatever the count, solo × 0.25 [ASSUMED]) since the owner's 「保持固定血量」
|
||
(§20.9 / §20.10).
|
||
- **Official**: activity_table bossInfoDict `bloodPoint` per difficulty, no per-player factor in the data; notice 5114's
|
||
「两侧的敌方领袖共享生命值(敌方领袖的总生命值不变)」 is about the mirrored copies of a pair field; the PR's rule is the
|
||
author's observation (实玩反馈), not an official text. 假想敌:胄 (PRTS): a drone that dies 「令假想敌:胄受到最大生命值2%的真实
|
||
伤害」; 限伤 (research 11 §2.1) cancels any damage modifier of ceil ≥ 300000 on a leader.
|
||
- **Decision**: the owner's decision of 2026-10-06 — adopt #209: the pool is the solo table value × the players alive
|
||
when the fight starts; it replaces 「保持固定血量」.
|
||
- **Now** (ported by hand onto 0.2.0's files; the PR's one-line `data/config.json` and its `docs/BOSS_HP_ZH.md` table
|
||
were not taken — the data is regenerated, PLAYING §7 gives the examples):
|
||
1. `bossPoolShareOf` (gamedata.js, used by `GameData.bossPoolShare` and by `finalAssault.bossPoolHp` for a plain
|
||
game-data object): solo × `solo` (1); co-op with `perPlayer` true × `coop` (1) × the players alive at the Final
|
||
Assault's / Hidden Core's start (`alivePlayers()`: bots and AI 托管 seats count, eliminated and departed seats do
|
||
not; at most `aliveFull` 4; a count left out = a full team). The global `config.bossHpScale` carries the rule
|
||
(`perPlayer: true, solo: 1`); the modes' entries keep only `bloodPointKey` (one place restores the fixed pool:
|
||
`perPlayer: false, solo: 0.25`, its optional × alive / 4 `aliveScaling` too). data/config.json regenerated offline:
|
||
only `bossHpScale` (global and per mode) changed. Leaders still ignore `enemyScale`; parts and escorts keep their HP.
|
||
2. #209 documented, without fixing, that 胄's drone link (2 % of the pool, `DRONE_LINK_BASE 'pool'`) meets 限伤: the
|
||
hidden 胄 终极 pool is 21 600 000 / 28 800 000 at 3 / 4 players, a drone 432 000 / 576 000, which the limit would
|
||
cancel — drones would stop counting exactly in the largest fights. The share is no hit: `Battle.loseHp` takes
|
||
`noHitLimit` and the drone link passes it; a part's 传递 and every hit stay under the limit.
|
||
- [ASSUMED]: the drone share past the limit (the official client checks every damage modifier on a leader and PRTS
|
||
calls the 2 % 真实伤害, but which max HP it reads is not documented — the remake reads the pool and keeps the share).
|
||
The count is taken at each boss round's start, as #209 states (a seat that leaves before the Hidden Core no longer
|
||
counts there).
|
||
- Golden: fields — the 20 boss / hidden scenarios (`boss-boss_1..7-pair` / `-solo`, `hidden-boss_8..10-pair` /
|
||
`-solo`): a pair field's pool × 2 (two players), a solo template's × 4 (solo × 1 instead of × 0.25); seven of them
|
||
(`boss-boss_1-pair`, `boss-boss_1-solo`, `boss-boss_3-pair`, `boss-boss_3-solo`, `boss-boss_5-solo`,
|
||
`boss-boss_7-pair`, `hidden-boss_9-solo`) now end at the 200 s cap instead of clearing; the two 联防 scenarios are
|
||
unchanged. matches — 11 of 18: `solo-FUNNY-2`, `solo-NORMAL-1`, `solo-HARD-1`, `solo-HARD-2` now lose the Final
|
||
Assault (team LP 0 with 93 088 – 176 395 of the pool left; solo leaders have 4× the HP); `solo-FUNNY-1`,
|
||
`solo-NORMAL-2`, `solo-HARD-9-boosted` (its Hidden Core too) win with more leader damage (team LP −6 / 0 / −1);
|
||
`coop2-NORMAL-3`, `coop4-FUNNY-6`, `coop2-ABYSS-10-boosted`, `coop2-NORMAL-70-diy` win with more leader damage
|
||
(the pool × the players alive). Unchanged: the matches that end before R14 and `coop2-NORMAL-8-serverrun` /
|
||
`coop2-NORMAL-14-standins` (one player left at R14: × 1, as before); roster / bonds / standins / diy unchanged.
|
||
- Tests: `test/match/boss-hp-scaling.test.js` (from PR #209, adapted: every leader and difficulty × 1–4 players and solo;
|
||
R14 / R15 leave out two departed players; AI 托管 and bots count, an eliminated player does not; config restores the
|
||
fixed pool — the PR's test said the opposite —, the plain-object fallback agrees; only the leader's HP scales),
|
||
`test/content/enemies_bosses.test.js` (hidden 胄 终极 at 3 / 4 players: the drone's 432 000 / 576 000 land, a hit of
|
||
the same size is cancelled), updated on purpose: `test/match/finalAssault.test.js` (the per-player pool, the fixed
|
||
pool restored through config, a mode entry overriding the global one), `test/match/balance.test.js`,
|
||
`test/match/bosshp.test.js`, `test/match/connection.test.js`, `test/docs-consistency.test.js` (the §20.9 record
|
||
points here; the data carries `perPlayer: true`), `test/sim/playtest6_limits.test.js` (the drone share lands past the
|
||
line), `test/match/playtest6-bosspool.test.js` (its 5 % knob halved to keep the two-player pool's size: that test is
|
||
about the pool's arithmetic). Docs: PLAYING §7, DATA (`bossHpScale`), META, BALANCE, SIM, the
|
||
design (engine.md 限伤, network.md boss rounds), the §20.9 / §20.10 records, research 00 / 01 / 08.
|
||
|
||
#### 25.13.5 Flying units hover 1.3 tiles; the 帝国炮火先兆者 pair is drawn 1.263× taller and 木制瑞印 mirrored (PR #211 by @xcdoge; the owner's decision of 2026-10-06) — `render/units.js FLY_HOVER / enemyModelScaleY` (the mirror flip), `tools/build-data.mjs MODEL_STRETCH_Y / MIRRORED_PREFABS`, `tools/local-extract/enemy_model_offsets.py`, docs/research/12-flying-visuals-official.md
|
||
|
||
- **Seen** (player report of 2026-10-05, PR #211): 无人机等飞行单位位置明显偏低 — every flyer drew ~1 tile too low; the two
|
||
妖怪 drones had their art under the tile (the flat lift was 0.32 tiles).
|
||
- **Official** (read from the client by the PR's author, research 12): the fly offset is one model-independent constant,
|
||
`Vector3(0, 0.35, 0)` set by `CharacterAnimator`'s constructor and added while flying; 0.35 is in the client's
|
||
character space, whose unit is the standard battle-prefab scale 0.27 — 0.35 / 0.27 ≈ 1.3 tiles, and an official
|
||
screenshot measures 1.2–1.4. The battle prefabs carry no per-model vertical correction for flyers. The same prefab
|
||
sweep found two model quirks: the 帝国炮火先兆者 pair's `Graphic` scale (0.19, 0.24, 0.24) (sy / sx 1.263) and
|
||
木制瑞印's negative X scale (a mirrored model).
|
||
- **Decision**: the owner's decision of 2026-10-06 — take all of it (the lift and both quirks).
|
||
- **Now** (ported by hand; 0.2.0 regenerated its own data/enemies.json offline — the JSON compare shows only
|
||
`enemy_1112_emppnt.modelScaleY`, `enemy_1112_emppnt_2.modelScaleY` 1.263 and `enemy_1196_msfyin.mirrorX`; the PR's
|
||
one-line enemies.json was not taken): `FLY_HOVER` 0.32 → 1.3, flat; `enemyModelScaleY` multiplies the skeleton's Y
|
||
scale and the head (bar) height, also in the impostor path; a mirrored model flips on top of the direction flip. The
|
||
body, its HP bar, damage numbers, projectile hits and skill rings ride the lift; the shadow stays on the ground tile;
|
||
range highlights are tiles; one camera drives the Pixi units over both the 2D and the three.js board, so both boards
|
||
show it. Research 12 ported without the PR's claim that the owner had said 「都要」 on 2026-10-05, and corrected where
|
||
the quirk enemies appear: 帝国炮火先兆者 is a FLY special enemy of the mode, 帝国炮火中枢先兆者 comes with the bounty
|
||
战术特训·飞行III, 木制瑞印 is in no wave of the mode. No screenshot or extracted art is committed; the extractor stays
|
||
optional.
|
||
- [ASSUMED]: the character-space → tile factor (1 / 0.27; the screenshot agrees within ±0.2 tiles).
|
||
- Golden: unchanged (drawing only; the sim reads neither field). Tests (from PR #211): `test/render/unitview.test.js`
|
||
(FLY_HOVER ≈ 0.35 / 0.27; the same lift for every flyer, the 妖怪 drones under the tile at the old 0.32; a flying view
|
||
lifts by FLY_HOVER — added here: its body and HP bar ride the lift, its shadow stays on the ground),
|
||
`test/render/playtest6-enemies.test.js` (exactly the two 先兆者 stretch and 木制瑞印 mirrors; the 1.263 aspect and the bar
|
||
height; the mirrored model's opposite x sign). Docs: DATA §9 (`modelScaleY`, `mirrorX`), ASSETS (model size, flying
|
||
units), research 00 / 12.
|
||
|
||
### 25.14 Community reports of 2026-10-06 (W5AA) — `content/enemies/archetypes.js prisoner`, `render/units.js FORMS`, `tools/assets/spine.mjs PREFAB_SPINE_ROLES`, `sim/battle/economy.js _bountyPayee`
|
||
|
||
The owner collected four community reports on 2026-10-06. Each was reproduced on the 0.2.0 tree with a script (and,
|
||
where the report could be older, on the v0.1.2 / v0.1.4 sources), checked against the official data — the battle
|
||
prefabs of the local client, ArknightsGameData's buff templates, PRTS — and the earlier decisions. Two were real and are
|
||
fixed (W5AA's commits name every golden scenario moved); two were already fixed and are pinned.
|
||
|
||
#### 25.14.1 「囚徒类敌人出门就是已解放的模型」: the 孤岛风云 prisoners leave the gate confined and change model as they are freed — `content/enemies/archetypes.js prisoner`, `render/units.js FORMS`, `render/fx/kinds.js SILENT_PHASES`, `tools/assets/spine.mjs PREFAB_SPINE_ROLES`
|
||
|
||
- **Seen**: 普通囚犯 / 老练囚犯 walked out of the gate drawn freed (a red collar light); no prisoner changed its model when
|
||
freed (强壮囚犯, 拳师囚犯, 重犯 and 传奇重犯 stayed grey all battle), on the 2D and the 3D board alike.
|
||
- **Official**: each prisoner skeleton holds three clip sets whose collar light is grey, blinking orange and red. The
|
||
battle prefabs (local client `battle/enm_pfb_6.ab`, read with UnityPy: the Graphic component's anim key → clip table,
|
||
the modes' replace pairs, the clip the Spine starts on) draw mode Default — 【禁锢】 — on the grey set and start on it,
|
||
mode R on the orange set and mode L — 【解放】 — on the red one. The buff templates (ArknightsGameData
|
||
`battle/buff_template_data.json`): `enemy_confinement` starts `confinement.times` charges; `enemy_confinement[atk_cnt]`
|
||
spends one ON_BEFORE_ATTACK unless the prisoner has 麻痹 (PRTS 拳师囚犯 「在持有麻痹的情况下,攻击不计数」) and switches to
|
||
mode R when one is left; `enemy_liberty_listener[warning]` switches to mode L before the next attack — PRTS
|
||
「进行第4次攻击前,切换至解放状态」.
|
||
- **Cause**: the client's name-based role resolver gave 普通 / 老练囚犯 their unnumbered clips, which are the red (freed)
|
||
set — their grey set is `*3`; FORMS had no prisoner entry and the sim sent no form. The sim also counted on the
|
||
'attack' hook, after the damage, so the 4th attack still hit confined.
|
||
- **Now**: `prisoner()` counts in the `before` hook (an attack 麻痹 interrupts never reaches it), sets the form
|
||
'warning' before attack times − 1 (fx 'phase', drawn silently — the blinking light is the model's) and 'liberty'
|
||
before attack times (fx 'liberate', the white blast as before), so that attack already hits with the liberty bonus;
|
||
重犯's free-all and 杰斯顿's knock-out switch every freed prisoner too, and UnitInfo `form` gives a view built later the
|
||
right set. FORMS maps 'warning' / 'liberty' for the six skeletons (普通 / 老练囚犯 `*2` / unnumbered, 强壮囚犯 `*2` /
|
||
`*3`, 拳师囚犯 / 重犯 / 传奇重犯 `*_orange` / `*_red`). `PREFAB_SPINE_ROLES` gives 普通 / 老练囚犯 their grey `*3` set
|
||
as the manifest's roles: data/assets.json regenerated (`fetch-assets --offline --add-only`, JSON compare: those two
|
||
`anims` and the hash), data/enemies.json too (`build-data --offline`: their `attackAnim.clip` Attack → Attack3, the
|
||
same length and strike frame). The 3D board draws the same Pixi views, so both boards follow.
|
||
- [ASSUMED]: none (the modes and their timing come from the prefabs and the buff templates).
|
||
- Found by the same audit (all 242 enemy prefabs against the manifest's roles), not changed, for later: 猎狗pro moves on
|
||
`Run_Loop` (manifest `Move_Loop`), 大鲍勃 attacks on `Attack2`, 碎骨 moves on `Move_02`, “斩胄之剑” / “破胄之锤” idle on
|
||
`Idle_A` (a 0 s pose the resolver skips on purpose); 杰斯顿, 扎罗 and 再生 differ only in the death clip their FORMS
|
||
already set.
|
||
- Golden: 28 scenarios — the warning's 'phase' fx only: roster-001 / 003 / 007 / 024 / 033, bond-miraShip-low; the freed 4th
|
||
attack: roster-004 / 021 / 022 / 026, bond-kazimierzShip-low / raidShip-low / soloShip-low / victoriaShip-low /
|
||
visiShip-low, standin-01, diy-017 / 024 / 061 / 065 / 066 / 094 / 097 / 104 / 105 / 127, and the bot matches
|
||
solo-ABYSS-2, solo-HARD-9-boosted. Tests: `test/content/feedback5-prisoners.test.js`,
|
||
`test/render/feedback5-prisoners.test.js`, `test/render/feedback5-prisoners.browser.test.js` (RENDER_E2E=1, both boards).
|
||
Docs: docs/ASSETS.md, docs/SIM.md, DESIGN §9 (design/client.md).
|
||
|
||
#### 25.14.2 「敌人在忍冬技能范围内没有开技能,在攻击范围才开」: already answered by the larger-range rule (§25.5) — no change
|
||
|
||
- **Checked**: data/chess.json — S1 小施惩戒 DEFAULT (AUTO, no larger range), S2 坠刃拷问 SKILL_RANGE on its 技能范围 3-12
|
||
(§25.11.5), S3 隐狐之艺 (her default) ACTIVE_RANGE on its running range 2-2 (`rawRule` DEFAULT); she is in neither
|
||
part of data/backups.json. On v0.1.4 S3 was on DEFAULT and cast only with an enemy in her 1-tile range — the report;
|
||
on this tree it casts with an enemy two tiles ahead (not three), S2 on any tile of the 3-12.
|
||
- Golden: unchanged. Pinned: `test/sim/feedback5-community-pins.test.js`.
|
||
|
||
#### 25.14.3 「被源石地板烫死的悬赏没给赏金」: a bounty enemy that dies with no operator behind it pays in 联防 too — `sim/battle/economy.js _bountyPayee`, `sim/battle/deploy.js _remove`
|
||
|
||
- **Seen**: a bounty enemy burned to death by the 活性源石 paid no bounty.
|
||
- **Checked**: on its own field it always paid its owner — all 96 walking kill-bounty enemies on 战场#04 with no
|
||
operator, on this tree and on v0.1.4: none unpaid. The loss is in 联防: a leaked bounty enemy re-enters carrying
|
||
`bounty.ownerPlayerId` = the leaker (unite.js planUnite), and a death without an operator killer fell back to that
|
||
owner, who has no per-player entry in the 联防 battle, so `addCoins` dropped the coins. Until 0.1.3 the 联防 field was
|
||
the round's map (GitHub #41), so 战场#04's 活性源石 burned leaked bounty enemies for nothing; the 联防 maps have no
|
||
terrain now, but a 无来源 tick, the enemy's own HP loss or another enemy's hit still paid nobody.
|
||
- **Official**: PRTS 卫戍协议:盟约 决策 「该敌人于对应玩家所属区域倒下时,使相应玩家获得额外资金」 — no exception for 环境伤害;
|
||
the owner's decision (relayed 2026-10-06): the bounty pays whenever the body dies.
|
||
- **Now**: `_bountyPayee` — an operator or summon of a player in the battle that dealt the blow pays its player (as
|
||
before, a 联防 helper included); any other death pays the card's owner when that player fights there (own field, Final
|
||
Assault / Hidden Core: unchanged), else the player whose half of the field the enemy fell on (`_ownerForTile`).
|
||
- [ASSUMED]: the 联防 payee of a death nobody caused (no source names one; PRTS's 「于…区域倒下」 reads as the area's
|
||
player).
|
||
- Golden: unchanged. Tests: `test/sim/feedback5-bounty-payee.test.js` (the 联防 cases fail on the parent; the own-field
|
||
活性源石 death, a helper's operator on the other half and a pair boss field pinned). Docs: docs/SIM.md §1.2,
|
||
docs/META.md, docs/PLAYING.md.
|
||
|
||
#### 25.14.4 「悬赏敌人枯朽萃聚使徒召唤的枯朽之种被击杀也会获得赏金」: already fixed in 0.1.3 (§23.25) — no change
|
||
|
||
- **Checked**: the 使徒's BornBugs spawn its seeds through `spawnChildren`, which drops the card's `bountyId` /
|
||
`bountyCoins` (§23.25); a seed never had a `bounty` on the own field, so killing one never paid. On the v0.1.2 sources a
|
||
bounty 使徒 whose seeds leaked sent every seed into 联防 carrying the card — 15 of 16 re-entries paid it again — which
|
||
is the report; on this tree only the 使徒's own leak carries it.
|
||
- Golden: unchanged. Pinned: `test/sim/feedback5-community-pins.test.js`.
|