2285 lines
241 KiB
Markdown
2285 lines
241 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), W5Y (round 18:
|
||
three GitHub issues and three community PRs), W5AA and CB1–CB5 (the community reports of 2026-10-06), W5AC
|
||
(rebindable shortcuts) and W5AD (language packs). 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, 自制投石机's 索敌不受阻挡影响), §5.6 (the trigger rules), §8.1 / §8.3
|
||
(`welcome.diyKitted`, `standIns`, `diy`, `diyBanned`), §10 (the rebindable shortcuts), §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; the rebindable shortcuts → §25.15; the
|
||
second batch of community reports of 2026-10-06, one section per stream: CB2, healers, summons, timers (刺玫's S2 heals,
|
||
琳琅诗怀雅 healing herself and her 破财消灾 cost after a redeploy, 赫默's drone at full SP, the countdown summons' 无敌 /
|
||
禁疗 / timer bar, stacked alchemy zones; the chain heal, DoT damage, 伺夜's 狼影 and the 吟游者 trait answered) → §25.16;
|
||
CB3, operator kits and triggers (砾's double hit, 乌尔比安's S3 landing behind the 联防 red gate, the 「受到攻击时」
|
||
counters on every enemy damage instance, a 突袭 member's jump after an in-place 复活, 银灰's sound; 铃兰's trigger,
|
||
琳琅诗怀雅's champagne, the 突袭 玛恩纳, 归溟幽灵鲨 devoured and 荒芜拉普兰德 / 叙拉古 already answered; 乌尔比安's revive
|
||
tile on his deployment tile, the owner's deviation) → §25.17; CB4, enemies, bosses, waves, movement (the 突袭 landing on the 临时整备区 row and the
|
||
other half of the 联防 map, a silenced 萨卡兹枯朽战士's death pollution, 萨卡兹穿刺手's speed after a stun and its first
|
||
hit, 自制投石机 blocked on the 排气格栅; the briefing types' 7–9 waves, 新硎's 断刃, a freed prisoner in 联防 and 鸭爵's two
|
||
swaps in one wave already answered; the moving leaders' routes checked; 野鬃, 锏's pulls, 昆图斯's footprint and the leaders' attack rate not
|
||
reproduced) → §25.18; CB5, match flow and UI (a module's 特性追加 line after the class trait, the new shop slot filled at
|
||
the upgrade, an eliminated player following a player through every round, the boss field and its leader in a watcher's
|
||
boss prep, the pair together in the boss prep with the official green frames; PRs #189 / #191 reused, not merged; the
|
||
battle-history request postponed by the owner, the hotkey request built in §25.15) → §25.19; language packs, the first
|
||
type of content packs (a
|
||
language is a file in the language folder) → §25.20; the last stream of that batch, CB1, bonds, strategies and items (the
|
||
谢拉格 wind's endless freeze, 埃芒加德's and M3茧甲's 复活 as a knock-out and a free redeploy, 佩佩's paid refresh, the 炎佑 on
|
||
the medic's slot, 凯瑟琳's offer, the hidden layers on the result card; the official behaviours pinned) → §25.21; and, before the release, four GitHub reports of round 19 (a stunned or frozen enemy blocked by contact, #232; the
|
||
round-start banner of an eliminated player or a spectator seat, #236; 干员调配 without its game data, #173; the official
|
||
result box and battle-over sounds of the approved PR #112, #235) and four community reports of 2026-10-07 (the
|
||
5-阿戈尔 revive order, an enemy's attack clip after its strike and the 鸭爵 swap's re-stealth, 蕾缪安's S3, the 整备区
|
||
layers pinned) → §25.22; the Japanese, Korean and Traditional Chinese interfaces → §25.23.
|
||
|
||
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); 2026-10-07 — the in-match shortcuts rebindable in 设置 (§25.15); a language is a file in the
|
||
language folder, and the language pack is the first type of a general content-pack mechanism; Japanese, Korean and
|
||
Traditional Chinese ship with the official game texts and fallback UIs — the Traditional one's in Simplified Chinese
|
||
(§25.20); 乌尔比安 knocked
|
||
out during his S3 comes back on his deployment tile, a deliberate deviation from PRTS's "where it fell" (§25.17.3);
|
||
烛煌's 绝处重燃 before 坚固维式重锤's lock and the official tier cap of 寻呼模块 / 简易通讯机 kept as they are (§25.21.1,
|
||
§25.21.10); 0.2.0 held for round 19's four reports and four more community reports (§25.22); the 5-阿戈尔
|
||
battle-start revives by board position, replacing §24.3's knock-out order for that batch (§25.22.5); the 鸭爵 swap's
|
||
流泪小子 hides again 1 s after a block ends (§25.22.6); the three new interfaces completed — zh-TW converted, ja / ko
|
||
machine-translated with the official terms, marked as such (§25.23).
|
||
|
||
### 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`.
|
||
- **Withdrawn in 0.2.1**, see §26 — 联防 plays on the round's battlefield again (the owner's decision of 2026-10-07,
|
||
「官服保留地形」: the escaped levels' map is the placeholder road every wave template level carries).
|
||
|
||
#### 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`.
|
||
|
||
### 25.15 Rebindable shortcuts (W5AC; the community request 「快捷键可不可以自己设置」, the owner's decision of 2026-10-07) — `ui/gameLogic/shortcuts.js`, `ui/gameLogic/settings.js sanitizeSettings`, `ui/settings.js` (`HotkeySection`, `hotkeyLabelOf`), `screens/game.js`, `ui/facingWheel.js`
|
||
|
||
- **Asked**: players wanted to choose their own keys.
|
||
- **Before**: R 刷新, F 冻结, D 升级, Q 撤退 / X 出售 the selected operator (PR #114, 0.1.4), Space 准备就绪 (in a solo battle:
|
||
pause / resume) and Esc (close) were fixed in `shortcutFor`; the shop bar, the ready / pause button and the
|
||
underframe drew them as fixed text, the facing wheel swallowed Space and `KeyR` / `KeyF` / `KeyD`. No camera, speed or
|
||
panel keys exist; the other keys are the dialogs', the guide's, 干员调配's and the facing wheel's own (Esc, Enter, the
|
||
arrows, paging), listed with the shortcuts in docs/PLAYING.md §11. Nothing official to follow: the shortcuts are the
|
||
remake's.
|
||
- **Now**: the settings (localStorage `sp.pref.settings`) hold `keys`, action → `KeyboardEvent.code`; the defaults are the
|
||
keys of 0.1.4, so nothing changes for a player who never opens the section. `sanitizeSettings` keeps each saved key
|
||
that may be a shortcut and gives any other its default; not a map, or two actions on one key, gives the defaults. One
|
||
lookup, `actionForKey` — the action of the character typed (the keycap: AZERTY, Dvorak), else of the physical key (a
|
||
Russian layout, an IME), the 0.1.4 `code === 'KeyR' || key === 'r'` match generalised and identical for the defaults —
|
||
serves `shortcutFor(e, keys)` in game.js and the facing wheel's `facingSwallows`; the modifier, text-field, repeat and
|
||
overlay guards are unchanged. The key hints read `hotkeyLabelOf`. 设置 → 快捷键 (the one SettingsModal, in a match and
|
||
on the title screen): each action with its key; a click — or Enter on the focused key — waits, the next key binds;
|
||
Esc cancels and the dialog stays open, Tab leaves; a key held with Ctrl / Alt / ⌘ or one the interface keeps (Esc,
|
||
Tab, Enter, the arrows, F1–F12) is refused and the wait goes on; a key another action has is swapped (that action takes
|
||
the old key) and the line under the list names both; 恢复默认. Bindable: A–Z, 0–9, Space, the punctuation keys, Delete,
|
||
Insert, Home, End, PageUp, PageDown; Esc stays fixed. On a touch-only device the section says the keys need a
|
||
keyboard and folds the list; under 768 px it is one column.
|
||
- [ASSUMED]: a conflict swaps rather than refuses (the request names neither, a swap never leaves an action without a
|
||
key); Esc and the dialogs' own keys stay fixed; the bindable set; no modifier combinations (no shortcut used one).
|
||
- Golden: unchanged (client UI only). Tests: `test/ui/feedback5-hotkeys.test.js` (the map, sanitising, conflicts, the
|
||
lookup equal to 0.1.4 for the defaults on four layouts, capture, handlers and hints with a rebound key),
|
||
`test/ui/gameLogic.test.js` (sanitizeSettings), `test/ui/hotkeys.e2e.test.js` (SP_E2E=1: 撤退 rebound to W with the
|
||
keyboard only in the mock match — Q then does nothing, W retreats, the choice survives a reload; phone width). Docs:
|
||
docs/PLAYING.md §11, README 操作, DESIGN §10 (design/client.md).
|
||
|
||
### 25.16 Community reports of 2026-10-06, stream CB2: healers, summons, timers — `kits/ops/chess_char_1_06-vendla.js`, `chess_char_3_04-swire2.js`, `chess_char_2_02-silent.js`, `content/tokens.js COUNTDOWN_SUMMONS / startCountdown`, `sim/snapshot.js unitTuple`, `render/fx/zones.js zoneAlpha`
|
||
|
||
The owner's second collection of community reports (2026-10-06/07) was split over five streams; CB2 took the healers,
|
||
the summons and the timers (items 11, 12, 13, 14, 18, 26, 31, 32, 33, 34 of the list). Each was reproduced on the 0.2.0
|
||
tree with a script first (on the v0.1.4 sources too where the report could be older), then checked against the official
|
||
data — the local client's battle prefabs (charpack, token and skill prefabs, projectiles; abnormal flag ids per PRTS 异常
|
||
效果: 5 无敌, 7 禁疗), ArknightsGameData's buff templates, skill_table / character_table, PRTS (备注 included) — and the
|
||
earlier decisions. Six were real and are fixed, one commit each with its golden scenarios named; four are answered with
|
||
the evidence.
|
||
|
||
#### 25.16.1 「刺玫开技能(装备源石药剂)之后不能治疗」 (item 12): only the S2 counter's trait heal goes to her protégé — `kits/ops/chess_char_1_06-vendla.js`
|
||
|
||
- **Seen**: during 荆藤庇荫 every trait heal went to the protégé, usually at full HP — a 源石溶剂 carrier drained from 1017 to
|
||
297 HP over the skill with all eight heals spent on a 9000 / 9000 ally.
|
||
- **Official**: 「该角色受到攻击时刺玫对目标造成攻击力20%的法术伤害并仅对该角色触发刺玫特性」 (en "…and activates her Trait on the
|
||
ally"); the client buff `vendla_tr` heals through the selector S2TraitHealRange (the `vendla_s_2` holder) only for a
|
||
damage whose modifier carries the key `vendla_s_2` — the counter, `vendla_s_2[extra_damage]` — else through
|
||
TraitHealRange (`_excludeOwner` 0, 禁疗 excluded).
|
||
- **Now**: the counter's damage names the protégé (`traitAlly`); every other damage she deals heals the lowest-HP ally of
|
||
her range, herself included, skill running or not.
|
||
- Golden: roster-001 / 002, bond-deputShip-low / -high, bond-suntShip-high, bond-victoriaShip-low / -high, the bot matches
|
||
solo-FUNNY-2, coop2-NORMAL-3, coop3-ABYSS-5, coop4-FUNNY-6, coop4-ABYSS-7. Tests:
|
||
`test/content/feedback5-vendla-heal.test.js`.
|
||
|
||
#### 25.16.2 「琳琅诗怀雅不会治疗自己」 (item 18): S1 仗义疏财 heals her own tile too — `kits/ops/chess_char_3_04-swire2.js`
|
||
|
||
- **Official**: the client charpack (char_1033_swire2, mode S1, ability HealAlly) selects with range x-4 — the 3×3 with her
|
||
own tile —, ally side, `_excludeOwner` 0, max HP ratio 0.7, one target. **Cause**: the kit skipped her and kept
|
||
Chebyshev distance 1 only. **Now**: the lowest HP ratio below 70 % of the 3×3, herself included (her own 禁疗 still
|
||
stops it); the owner's cadence of 2026-10-04 is unchanged.
|
||
- Golden: roster-027. Tests: `test/content/feedback5-swire2-self-heal.test.js`.
|
||
|
||
#### 25.16.3 「进入联防阶段琳琅诗怀雅所需的复活费用应该重置,正常对局中死亡之后再部署复活费用也应该重置」 (item 33): 破财消灾 restarts at 5 DP with every deployment — `kits/ops/chess_char_3_04-swire2.js`
|
||
|
||
- **Official**: PRTS 破财消灾 备注 「再部署时重置本天赋费用消耗」; the client buff `swire2_t_2` doubles the `cost` of its own
|
||
blackboard, rebuilt when she is deployed. **Cause**: the kit kept its save count for the whole battle (5 → 10 → 20 across
|
||
a redeploy). **Now**: reset at each of her deployments (battle start, redeploy, 突袭 再部署); a 联防 field is a battle of
|
||
its own, so it always started at 5 (pinned).
|
||
- Golden: roster-008 (a cheaper save after a redeploy), roster-049 (snapshots only). Tests:
|
||
`test/content/feedback5-swire2-revive-cost.test.js`.
|
||
|
||
#### 25.16.4 「赫默的无人机在2技能好了之后应该秒放」 (item 34): S2 医疗无人机 casts at full SP — `kits/ops/chess_char_2_02-silent.js`
|
||
|
||
- **Seen**: S2 full at 26 s and no cast while nobody was hurt; the drone came only once an ally in her range was injured.
|
||
- **Official**: the client skill `skchr_silent_2` (AUTO) has no `_trigger`, `_allowNoTarget` 1, `_checkHasTargetBeforeDoCast`
|
||
0 and a RechargeToken action — no cast condition; `_stopSpWhenTokenIsFull` 1 = PRTS S2 备注 「库存达到上限后赫默获得阻回,
|
||
直到库存被消耗为止」.
|
||
- **Now**: trigger SP_FULL — the placed drone takes its tile the moment S2 is ready; 阻回 (`noSp`) while her stock is full.
|
||
- Golden: roster-003 / 005, bond-visiShip-low / -high. Tests: `test/content/feedback5-silent-drone.test.js`.
|
||
|
||
#### 25.16.5 「赫默的无人机、浊心斯卡蒂的海嗣等这种召唤物不会受到外来伤害(包括源石地板),也不会被干员治疗,血量随时间减少」 (item 26): the countdown summons — `content/tokens.js COUNTDOWN_SUMMONS / startCountdown`, `sim/snapshot.js unitTuple`, `sim/units.js` (`countdown`), the kits of 浊心斯卡蒂, 温蒂, 莱伊, 鸿雪, 酒神
|
||
|
||
- **Seen**: a 海嗣 on 活性源石 lost 70 of its 100 HP every second; a hurt drone drew every medic's heals and the 吟游者
|
||
regeneration; their bars were plain HP.
|
||
- **Official / sources**: PRTS 斯卡蒂的海嗣 备注 「持有禁疗、无敌」; the token prefabs give 海嗣 and 沙地兽 the abnormal flags 5 +
|
||
7, 工程蓄水炮 7; their lives are suicide buffs (`suicide_after_buff`, the drone's `skcom_withdraw`). The report describes
|
||
the official mode: no outside damage, no heal, a bar that runs down like a timer and the summon gone when it is empty.
|
||
- **Now**: the summons that "不会受到攻击" and leave after a fixed time — 医疗探机 (10 s), 诅咒娃娃 (15 s), 斯卡蒂的海嗣 (25 / 30
|
||
s) and the 自选 工程蓄水炮 (20 s), 沙地兽 (25 s), “打字机” (25 s), 本能的召唤 (10 s) — hold 无敌 + 禁疗 from each deployment
|
||
(`startCountdown`, called where each lifetime is scheduled) and the snapshot's hp is maxHp × the share of the life left
|
||
(`unit.countdown`). The sim HP stays full, so no selector sees a low-HP summon. Summons that block and are attacked
|
||
(沙之碑, 战术装备, “小自在”, 结构性原理, 狼群 …) keep real HP.
|
||
- [ASSUMED]: 无敌 + 禁疗 for the four whose base prefabs carry no flag (医疗探机, 诅咒娃娃, “打字机”, 本能的召唤), and the bar as
|
||
a display of the time left — from the report; no HP-drain node exists in the client data.
|
||
- Golden: snapshot hashes only (the bar): roster-003 / 016 / 018 / 035 / 045 / 046, bond-visiShip-low / -high,
|
||
boss-boss_1 / 3 / 5 / 7-pair, unite-1; gameplay too: roster-005 (medics no longer heal the drone), roster-037 and
|
||
hidden-boss_9-pair (a 海嗣 / drone under damage stays up). Tests: `test/sim/feedback5-countdown-summons.test.js`. Docs:
|
||
docs/SIM.md (token pieces), docs/PLAYING.md.
|
||
|
||
#### 25.16.6 「炼金师分支干员的炼金单元等范围持续性技能特效太亮(尤其是多层叠加以后)」 (item 14): stacked areas stay readable — `render/fx/zones.js zone / zoneAlpha`, `render/fx/simfx.js`, `kits/ops/chess_char_5_15-thorn2.js`
|
||
|
||
- **Cause**: 引星棘刺 S2's drifting unit was re-sent every second and drawn as a new additive zone for the rest of its life —
|
||
up to twelve layers on one spot; overlapping units (锡人's charges, several alchemists) added up the same way.
|
||
- **Now**: the fx carries `key` and the client moves / resizes that one zone; a persistent area (> 3 real s) is drawn at
|
||
0.16 / 0.5 (disc / edge) and ÷ √n among the n persistent areas overlapping it; short bursts and telegraphs unchanged.
|
||
- Golden: unchanged. Tests: `test/render/feedback5-zone-stack.test.js` (node; no browser suite draws zones).
|
||
|
||
#### 25.16.7 Answered with the evidence: items 11, 13, 31, 32 — no change
|
||
|
||
- **11 「链愈师…只能从周身8格里的干员开始,最远不会跳出攻击范围,…即使后续跳跃干员满血也会按照规则顺序跳跃」**: the x-4 jump
|
||
around the last one healed and full-HP allies jumped in order are 0.2.0's WE1 (§25.7.6; on v0.1.4 a full-HP ally was
|
||
never jumped). The main target is the lowest-HP ally of the whole attack range y-2 (PRTS 分支特性信息), and the client's
|
||
chain selector (`projectile_chr_papyrs`: `_rangeId` x-4 around the hit, `_maxTarget` 3) has no attack-range bound, so a
|
||
jump may leave the range — not implemented.
|
||
- **13 「有的持续造成伤害类的技能无伤害(如炼金师分支干员的炼金单元)」**: not reproduced — every DoT skill of the pool and of
|
||
the 自选 operators deals damage once its condition is met (a sweep with two layouts; on two real stages 锡人 S1 / S2 and
|
||
引星棘刺 S2 / S3 deal 13 000–134 000, the same on v0.1.4). The only zero is the hidden 锡人 record chess_char_1_16 (never
|
||
in the shop) whose kit lacks S1. The stacked, over-bright zones (item 14) are the likely cause of the impression.
|
||
- **31 「伺夜的召唤物随时间增长的狼影最高能叠三只(即在新的狼影恢复前能受到三次致命伤害才死亡)」**: what the sim does (kit pack
|
||
and placed piece, this tree and v0.1.4): 2 狼影 at deployment, 3 after 25 s, lethal hits 3 → 2 → 1 at full HP, the third
|
||
into the 战术点形态 — PRTS 狼群 备注. Pinned by `test/content/tokens_devices.test.js`, `kits_alt_t3.test.js`.
|
||
- **32 「吟游者的特性能恢复战术家的召唤物、不屈者分支干员的血量…(但赫默的无人机、浊心斯卡蒂的海嗣这种的血量不可以恢复)」**: the
|
||
trait is 生命回复速度, which 禁疗 and 无法被友方治疗 do not stop (§25.6.8): 狼群 440 → 532 and 斥罪 1480 → 1618 HP in 3 s
|
||
under 魔王 (pinned by `test/content/feedback5-regen.test.js`); 孤立 units stay out (PRTS 孤立). The countdown summons
|
||
cannot be refilled since §25.16.5.
|
||
|
||
### 25.17 Community reports of 2026-10-06, stream CB3: operator kits and triggers — `sim/ai.js resolveHit` (`hitDmgMul`), `kits/ops/chess_char_2_12-gravel.js`, `kits/ops/chess_char_5_05-ulpia.js`, `sim/battle/players.js onOwnBoard`, `kits/shared/tier1.js byEnemyAttack`, `content/items/battle.js revivedInPlace`, `tools/assets/audio.mjs pickUnitSfx`
|
||
|
||
The owner's second collection of community reports (2026-10-06/07) was split over five streams; CB3 took the items about
|
||
operator kits and skill triggers (items 2, 16.1, 16.4, 16.5, 17, 27, 28, 30, 44, 46, 54 of the list). Each was reproduced
|
||
on the 0.2.0 tree with a script first (where the report could be older, on the v0.1.1–v0.1.4 sources too), then checked
|
||
against the official data (character_table, skill_table, activity_table → act2autochess, audio_data, ArknightsGameData's
|
||
buff templates, the local client's charpacks and skill prefabs) and PRTS (备注 included). Five are real and fixed, one
|
||
commit each with its golden scenarios named; five were already answered or are not bugs (pinned by tests); one is a
|
||
question for the owner (settled on 2026-10-07: §25.17.3).
|
||
|
||
#### 25.17.1 「砾的平A是比较特殊的双判,是两次50%伤害倍率(不是攻击倍率)」 (item 16.5): two instances of 50 % 伤害倍率 per normal attack — `sim/ai.js resolveHit`, `sim/professions.js` (`hitDmgMul`), `kits/ops/chess_char_2_12-gravel.js`
|
||
|
||
- **Seen**: one damage instance per attack (measured: against DEF 300, ATK 352, one hit of 52), so a 频次 enemy lost 1.
|
||
- **Official**: PRTS 砾 特性备注 — in her attack animation every normal attack deals two instances, each 50 % of the final
|
||
damage (after DEF / damage reduction, before 重设伤害), and the second triggers no 受击回复.
|
||
- **Now**: the profile field `hitDmgMul` — the DamageInfo `mul` of each of the `hits` instances on the main target, applied
|
||
after DEF / RES and the damage multipliers, `noSp` on the later ones — and 砾's kit trait `{ hits: 2, hitDmgMul: 0.5 }`:
|
||
two hits of 26 in the example (the same total), 2 per attack against a 频次 enemy. Both her skills are passive, so every
|
||
attack she makes is a normal attack.
|
||
- [ASSUMED]: the two instances land at once, at her attack's damage frame (the animation's second hit is not timed).
|
||
- Golden: 7 scenarios with 砾 on the board — roster-004 / 005 / 024, bond-indomShip-low / -high, bond-kazimierzShip-low /
|
||
-high (two damage events per attack; in roster-024 and bond-kazimierzShip-high the last blow lands on another instance,
|
||
so kills move between her and her neighbours). Tests: `test/sim/feedback5-gravel-double-hit.test.js`. Docs: docs/SIM.md.
|
||
|
||
#### 25.17.2 「乌尔比安使用3技能会在联防阶段跳到红门后」 (item 27): the S3 【移动】 lands only on his own board — `kits/ops/chess_char_5_05-ulpia.js`, `sim/battle/players.js onOwnBoard`
|
||
|
||
- **Seen**: on the one-helper 联防 map (act1autochess_escaped_single: the lone helper on the left half, the enemies out of
|
||
the middle gate at col 10) an anchor that met no enemy flew on 6 tiles into the right half, where no enemy walks, and he
|
||
stood there behind the red gate for the whole skill (reproduced: (10,7) → (10,13); on a solo boss field (2,5) → (2,11)).
|
||
- **Official**: PRTS 乌尔比安 S3 备注 ③ — the anchor tile if it can be deployed on, else the tile one beyond, else his own
|
||
tile. "可部署" is a tile his player deploys on.
|
||
- **Cause**: "deployable" was any standable tile of the battle rect; UNITE_RECT spans both halves of the 联防 map and
|
||
BOSS_RECT the hand / 临时整备区 rows and the partner's half.
|
||
- **Now**: the landing must also lie on his board — `Battle.onOwnBoard(ps, r, c)`, the board region GEO.FIELD mapped onto
|
||
the field as `mapTile` maps the pieces (the helper stream CB4 adds for the 突袭 landing; the hunk is identical).
|
||
The anchor still flies its 6 tiles and blasts there; he stays when neither tile is his.
|
||
- [ASSUMED]: that the official "可部署" excludes the other half of a shared field (the level files mark both halves
|
||
buildable; no player deploys on the other's).
|
||
- Golden: 1 scenario — fields hidden-boss_9-solo (his first cast landed on the right half). Tests:
|
||
`test/sim/feedback5-ulpia-own-board.test.js`; `test/sim/facing-invariance.test.js` counts every tile of its open field
|
||
as the player's own (a board-position rule, like the deployment order it already avoids).
|
||
|
||
#### 25.17.3 「乌尔比安3技能期间死亡会留在3技能位移后的位置复活,应回到初始部署位复活」 (item 28): back to his deployment tile — the owner's decision of 2026-10-07, a deliberate deviation from the sources — `kits/ops/chess_char_5_05-ulpia.js`, `sim/battle/tiles.js _layBody`, `sim/units.js downAtHome`
|
||
|
||
- **Checked**: knocked out during S3 he lies on the landing tile and comes back there — the rule of every operator moved
|
||
off its board tile since 0.1.1 (§21.24, `Battle._layBody`): PRTS 卫戍协议/帮助 「原地留下一个“倒地干员”…自动部署至该位置」,
|
||
whose one exception (「若干员被击倒的位置为其他干员或召唤物的初始位置,则…尝试返回其自身的初始位置」) does not apply to his
|
||
landing tile. PRTS 乌尔比安 S3 备注 ④ (the 【返回】 at the skill's end) says nothing of a knock-out, and the client's S3
|
||
templates (`ulpia_s3_*`: the 【移动】 respawn clips and flags) carry no other rule. With §25.17.2 he can no longer fall
|
||
behind the red gate.
|
||
- **Decision**: asked whether to keep "where he fell" (the sources) or send him back to his deployment tile (the report),
|
||
the owner chose the deployment tile (the owner's decision of 2026-10-07) — **a deliberate deviation** from PRTS's rule,
|
||
for his S3 only: every other operator moved off its tile (a 突袭 jump, the 【移动】 of other kits) still lies and comes
|
||
back where it fell.
|
||
- **Now**: his kit sets `Unit.downAtHome` once the S3 【移动】 has put him on the anchor tile; the 【返回】 (the skill over
|
||
with him standing) and every deployment clear it. Knocked out while it holds, `Battle._layBody` lays him on his home
|
||
tile — his deployment tile, where the 从不混淆的方向 stood (gone with the skill) — and he redeploys there (timed, 不屈, or at
|
||
once by CB1's 复活, §25.21.3); b.snap `down` names that tile, so the client draws him there.
|
||
- [ASSUMED]: his deployment tile taken (a unit or another body on it) → where he fell, the one attempt of the PRTS
|
||
exception above; a 突袭 member's jump tile before the S3 is not his deployment tile (his board home is).
|
||
- Golden: unchanged — the corpus moves him 23 times (roster-015, four solo boss fields) and knocks him out 6 times,
|
||
never while moved (instrumented). Tests: `test/sim/feedback5-ulpia-revive-home.test.js` (3: knocked out during S3 he
|
||
lies and redeploys at home, revived at home by M3茧甲 — both fail before —, and the control: after the 【返回】 and for a
|
||
突袭 member the PRTS rule holds). Docs: docs/SIM.md §1, DESIGN §5 (design/engine.md), docs/PLAYING.md.
|
||
|
||
#### 25.17.4 「退行的潮涌者的攻击无法触发菲莱2技能的受击反击(排查其他类似技能的干员)」 (item 30): the 「受到攻击时」 counters answer every damage instance from an enemy — `kits/shared/tier1.js byEnemyAttack`, `kits/ops/chess_char_3_06-philae.js` and the kits below
|
||
|
||
- **Seen**: the report's 退行的潮涌者 is the 巢涌者 (深溟 / 富营养的巢涌者 in this mode): no normal attack, its talent hurts
|
||
every operator in range once a second — and 菲莱 S2 never answered it (measured: 0 blasts).
|
||
- **Official** (ArknightsGameData buff_template_data): the pulse is an AdvancedApplyDamage with the enemy as its source
|
||
(`enemy_dsubrl_aoe[aura]`); the counters fire on ON_TAKE_DAMAGE — `philae_s_2` with no filter at all, and on a source of
|
||
the other side `inverse_damage` (星熊 S2, from its skill prefab), `inverse_damage[magic]` + `nian_s_2` (年 S2),
|
||
`bubble_s_2` / `bubble_t_1` (泡泡 S2, 尖刺盾), `vendla_s_2` (刺玫 S2), `yu_s_1[inverse_damage]` (余 S1), `hsgma2_s_1` /
|
||
`hsgma2_e_003_tr_take` (斩业星熊 S1, AST-X), `mlynar_t_2[inverse]` (玛恩纳 无动于衷). 棘刺 S2 (a 普通伤害 filter) and 信仰搅拌机
|
||
S3 (any damage) were already right.
|
||
- **Cause**: those kits required `dmg.isAttack`.
|
||
- **Now**: `byEnemyAttack` = any damage instance from an enemy but a 流失 (PRTS 作战机制: 流失 triggers no 受击 events), an
|
||
element 损伤, 无来源 damage or another counter / reflection (tags `counter` / `reflect`, no ping-pong); 菲莱 S2 takes any
|
||
instance but a 流失 or a counter. `test/content/op_nian.test.js` pinned "a non-attack hit returns nothing" for 年 S2 —
|
||
updated on purpose.
|
||
- [ASSUMED]: a hit fully absorbed by a shield still counts (ON_TAKE_DAMAGE fires on the damage instance); a dodged one does not.
|
||
- Found on the way, not changed: the pulse is `_ignoreForSp` officially (no 受击回复 SP, so it should not set off 雷蛇's
|
||
talent either) and still gives SP here; `content/generic.js`'s parsed counter still takes attacks only (no unit uses it).
|
||
- Golden: 19 scenarios where an enemy's non-attack damage reached one of these operators — roster-002 / 005 / 008 / 010 /
|
||
012 / 016 / 033 / 044; bond-lateranoShip-low; fields boss-boss_2-solo, boss-boss_4-pair / -solo, hidden-boss_8-pair /
|
||
-solo; matches solo-FUNNY-1 / -2, coop4-ABYSS-7, coop2-ABYSS-10-boosted; diy-051. Tests:
|
||
`test/sim/feedback5-counters-any-damage.test.js`. Docs: docs/SIM.md (re-entrancy rule).
|
||
|
||
#### 25.17.5 「突袭盟约的干员如果带被动技能,复活之后不会立马突袭出去,还要等突袭CD」 (item 44): a 复活 starts a deploy-timed skill again — `content/items/battle.js revivedInPlace` (since the CB1 merge `reviveNow`)
|
||
|
||
- **Seen**: 缄默德克萨斯 (S3) revived by M3茧甲 or 埃芒加德 with nothing in range jumped 10.00 s later; after 不屈's real
|
||
redeploy 0.23 s later. After a timed redeploy every passive member already jumped at once (measured for 宴, 缄默德克萨斯,
|
||
斯卡蒂, 耀骑士临光, 伊内丝).
|
||
- **Official**: PRTS 盟约记录 备注 — 「复活」 is 退场 + a 0-time / 0-cost redeploy, a new deployment, after which a deploy-timed
|
||
skill runs again; a 突袭 member counts that running window as 技能就绪 (`raidPoll`, GitHub #49 / #109).
|
||
- **Cause**: the remake revives in place (a `fatal` hook, §21.21): her window, over by then, stayed over and only the idle
|
||
trigger was left.
|
||
- **Now**: `revivedInPlace` also restarts an `activateOnDeploy` skill on the next tick — anew when its window had ended,
|
||
back to its full duration when it still ran — so the member jumps at once; 砾 gets a fresh barrier, 缄默德克萨斯 a new
|
||
sword rain. The SP reset and the other 部署时 effects of PRTS's form stay unmodelled (§21.21).
|
||
- **At the merge with CB1** (§25.21.3): CB1 models PRTS's form itself — the 复活 is a knock-out and an immediate free
|
||
redeploy (`reviveNow`), whose skill reset starts a deploy-timed skill anew — so `revivedInPlace` and its restart were
|
||
dropped; this item's tests (the jump at once, the window back to full, 砾's fresh barrier) pass on that model.
|
||
- [ASSUMED]: none (§21.21's in-place form is gone with CB1).
|
||
- Golden: 1 scenario — roster-012 (the elite 缄默德克萨斯 revived in place three times). Tests:
|
||
`test/sim/feedback5-raid-revive.test.js`. Docs: docs/SIM.md, DESIGN §5.4 (design/engine.md, the `fatal` hook).
|
||
|
||
#### 25.17.6 「干员银灰的普通攻击的音效错误的使用了3技能期间的攻击音效」 (item 54): an operator whose default mode is the unsuffixed ability never takes a skill mode's sound — `tools/assets/audio.mjs pickUnitSfx`, data/assets.json
|
||
|
||
- **Seen**: 银灰's normal attack swung with p_atk_silver_n and hit with p_imp_sword_n.
|
||
- **Official** (audio_data, the local client's charpack): his normal attack is the Default mode's Combat — impact
|
||
`ON_ABILITY_HIT.char_172_svrash.combat` p_imp_spear_n, no swing bank; `.attack.2` (silver swing, sword impact) is his S3
|
||
mode, `.attack.1` his S2 mode.
|
||
- **Cause**: the picker's skill-mode test is by file name (`_d` / `_h` / `_s`), and those files end in `_n`.
|
||
- **Now**: an operator with a plain attack / combat bank (its default mode is the unsuffixed ability) never takes a
|
||
numbered variant; those that number their default mode (`attack.0` …) keep the order. Of the 209 operators it changes
|
||
4: 银灰, 雷蛇 (S2's lightning impact), 初雪 (her S1-2 mode's impact), 圣约送葬人 (S3_End's impact). data/assets.json was
|
||
regenerated offline (`fetch-assets --offline --add-only --allow-shrink`; JSON compare: those 4 entries, the hash and
|
||
stats). 银灰's official impact file was not on disk yet, so his entry stayed empty in the stream; at the merge one online
|
||
`node tools/fetch-assets.mjs --add-only` downloaded p_imp_spear_n.mp3 (8.8 KB, the only new file) and the manifest lists
|
||
his impact again (JSON compare with the stream's manifest: `char_172_svrash.hit`, the hash and stats).
|
||
- Golden: unchanged. Tests: `test/feedback5-operator-sfx.test.js`. Docs: docs/ASSETS.md.
|
||
|
||
#### 25.17.7 Already answered or not a bug: 铃兰's trigger, 琳琅诗怀雅's champagne, the 突袭 玛恩纳, 归溟幽灵鲨 devoured, 荒芜拉普兰德 and 叙拉古 (items 2, 17, 16.1, 16.4, 46) — no change
|
||
|
||
- **Item 2** 「敌人在干员…铃兰技能范围内没有开技能,在攻击范围才开」: her default S3 狐火渺然 (「攻击范围扩大」, no class or charId
|
||
row) was DEFAULT up to v0.1.4 — an enemy in her own 2-tile range; 0.2.0's ACTIVE_RANGE (§25.5, `resolveTrigger`) casts
|
||
it with an enemy in its running range y-8 (3 tiles ahead), as for 忍冬 (§25.14.2). data/chess.json already says so.
|
||
- **Item 17** 「琳琅诗怀雅的2技能的香槟只会在攻击范围内生成」: fixed by 0.2.0 WC (GitHub #116 item 2, §25.6): S2 “见面礼” throws
|
||
on the placeable, walkable ground tiles of range x-6 — her tile and two tiles up / down / left / right (PRTS 备注
|
||
「香槟炸弹放置范围:x-6」), onto an enemy's tile when one stands there. Pinned by `test/content/kits_t3.test.js`.
|
||
- **Item 16.1** 「突袭转职玛恩纳触发突袭的频率低很多…攻击范围里有怪的时候即使长时间没攻击也不会突袭」: the bond text itself —
|
||
「干员10秒内未进行攻击或技能就绪时,若范围内没有敌人」. A 解放者 never attacks with his skill off, so his 10 s are always met,
|
||
and an enemy in his range (one he does not block keeps walking through it) is what holds the jump, as for every member.
|
||
Should the owner have footage of the official game jumping with an enemy in range, that would be a new rule.
|
||
- **Item 16.4** 「归鲨被吃的时候不是变替身而是进了再部署」: not reproduced — an 阿戈尔 devour mark switches her to her 替身 on
|
||
normal, 联防 and boss fields; a sweep of 400 random chains (241 marked, 201 lethal) on this tree and on v0.1.2–v0.1.4:
|
||
never a knock-out. A player who does not own her fields her 补位 stand-in Sharp (近卫-无畏者, no 替身).
|
||
- **Item 46** 「荒芜拉普兰德开技能之后好像没有普攻了…叙拉古恐惧概率不高」: during her default S3 every drone is out chasing the
|
||
enemies nearest to it (PRTS 技能流程), so she makes no attack of her own — the drones hit — and her attacks come back
|
||
when it ends (measured). 叙拉古 6's true damage + fear is PRTS's rule: 0.139 % per 普通伤害 attempt, +0.139 % per miss,
|
||
a counter shared by the player's members (3 % on average; measured 3.0 %).
|
||
- Golden: unchanged. Pinned: `test/sim/feedback5-cb3-pins.test.js` (items 2, 16.1, 16.4, 46).
|
||
|
||
### 25.18 Community reports of 2026-10-06, stream CB4: enemies, bosses, waves, movement — `sim/battle/players.js onOwnBoard`, `content/bonds/addon/battle.js raidTile`, `content/enemies/archetypes.js kitPolluted`, `content/enemies/special.js kitRush`, `targeting.js canTargetAlly`
|
||
|
||
The owner's second collection of community reports (2026-10-06/07) was split over five streams; CB4 took the items about
|
||
enemies, bosses, waves and movement (items 6, 10, 16.3, 24, 29, 35, 36, 38, 39, 40, 47, 52, 53, 57 of the list). Each was
|
||
reproduced on the 0.2.0 tree with a script first, then checked against the official data (enemy_database,
|
||
enemy_handbook_table, activity_table → act2autochess, the level files) and PRTS (备注 included) and the earlier decisions.
|
||
The real ones are fixed, one commit each with its golden scenarios named; the rest are answered with the evidence.
|
||
Normative text touched: §5.5 (design/engine.md: 自制投石机's exception to "a stealthed ally is attacked only by the enemy
|
||
it blocks"); docs/SIM.md (`onOwnBoard`, the 索敌不受阻挡影响 target rule, the silenced 枯朽战士); docs/PLAYING.md (the
|
||
briefing types' share of the waves).
|
||
|
||
#### 25.18.1 「…新约能天使在开了突袭之后蹦到了下方…临时放置溢出的干员和道具的那一栏高台」, 「单人联防时突袭也可以跑到对面的场地上」 (items 40, 16.3): 突袭 lands only on its player's own board — `sim/battle/players.js onOwnBoard`, `content/bonds/addon/battle.js raidTile`
|
||
|
||
- **Changed in 0.2.1** (§26.1, the owner's decision of 2026-10-07): where both halves of the field are taken — the
|
||
two-helper 联防 field and a Final Assault / Hidden Core pair field — a member may land on its teammate's half too
|
||
(`Battle.onFieldBoard`); the hand / 临时整备区 rows, a lone helper's empty half and a solo boss field's other half stay
|
||
closed. This replaces the own-half rule of **Now** below on those two fields.
|
||
- **Seen**: in a solo leader round a ranged 突袭 member (新约能天使 with the 转职球 and the 突袭手雷) jumped onto the
|
||
boss field's 临时整备区 row; in a 联防 with one helper a member jumped onto the right half of the map.
|
||
- **Cause**: `raidTile` took any tile of the battle rect its position may stand on (grid.canStand). BOSS_RECT holds rows
|
||
0–5, so the boss field's hand row 0 and 临时整备区 row 1 (tile_achand: high ground, buildable ALL) were landing tiles
|
||
for a ranged member (reproduced: an enemy on the left telin (1,3) of 战场#01 drew the member onto the hand tile (0,3));
|
||
UNITE_RECT spans both halves of the 联防 map (cols 0–20) while a lone helper's board is the left half (escaped_single's
|
||
deploy tiles: cols 3–9), and on a pair field a member jumped onto its partner's half.
|
||
- **Official**: the bond text 「保留技力立即再部署至一名地面敌人周围」 — a 再部署 goes where its player deploys; the stage data
|
||
lists each player's deploy tiles per half (data/stages.json `deployTiles`: normal, bossLeft, bossRight).
|
||
- **Now**: `Battle.onOwnBoard(ps, r, c)` — the board region (rows 9–12, cols 2–10) mapped onto the field as `mapTile`
|
||
maps the player's pieces (the right-hand helper's +8 columns, the boss rows 2–5, the mirrored right half) — and
|
||
`raidTile` takes only those tiles; a target only reachable from elsewhere is skipped (the next candidate is tried, else
|
||
the member stays and the next poll looks again, as before).
|
||
- [ASSUMED]: none beyond §22.2's landing rule (the official landing tile among the legal ones is not known).
|
||
- Golden: 8 scenarios, each a member that used to land on the other half (checked with the parent instrumented):
|
||
boss-boss_2 / 3 / 4 / 5 / 6-pair, hidden-boss_8 / 10-pair (members landing on the partner's half, 1–7 per battle) and
|
||
the bot match coop2-ABYSS-10-boosted (ai_0's members on the right half of its leader fields). Tests:
|
||
`test/sim/feedback5-raid-own-board.test.js` (4 cases; each fails on the parent). Docs: docs/SIM.md (`onOwnBoard`).
|
||
|
||
#### 25.18.2 「沉默效果没有沉默枯朽战士敌人,枯朽战士敌人被沉默之后死亡依然留下了毒」 (item 10): silenced at its death, 萨卡兹枯朽战士 releases no 污染秽蚀 — `content/enemies/archetypes.js kitPolluted`
|
||
|
||
- **Seen**: a silenced 萨卡兹枯朽战士 (组长) still left its poison zone when it died (reproduced: 150 HP in 3 s to its
|
||
blocker, silenced or not).
|
||
- **Official**: PRTS 萨卡兹枯朽战士 天赋 「{{特殊机制|死亡爆炸}}(释放半径2.0,持续8s的【污染秽蚀】)」; PRTS 特殊机制 死亡爆炸
|
||
「如无特殊说明,此能力默认可沉默…若不处于沉默状态,将会…释放」. The client agrees: the battle prefab's PollutedDie
|
||
ability is a buff of template `projectile_on_killed`, whose ON_OWNER_KILLED checks `CheckAbnormalFlag SILENCED`
|
||
(unset) before `EmitProjectile` — the same template as 高能源石虫's blast. Its handbook line alone is NORMAL (高能源石虫's is
|
||
SILENCE), so the rule "`sil` = the handbook's SILENCE lines" (content/enemies.js) missed it. An audit of all 243 enemy
|
||
prefabs of the local client (every ability's buff templates; those whose ON_OWNER_KILLED checks SILENCED: 11 enemies)
|
||
found one more NORMAL line of that kind — 刺胄之弹's blast, a part of 假想敌:胄 (not changed, for later: its blast is
|
||
triggered by its arrival); the other nine are SILENCE lines our kits already silence. 萨卡兹枯朽战车's 秽蚀轰击, also
|
||
NORMAL, stays unsilenceable (its skill node has `_ignoreSilence` 1).
|
||
- **Now**: kitPolluted's death ability is `sil`; the silence test of every authored enemy names the two keys as the
|
||
template exceptions.
|
||
- [ASSUMED]: none.
|
||
- Golden: 5 bot matches, each with silenced 枯朽战士 deaths (14–83 per match, counted instrumented): solo-NORMAL-1,
|
||
coop2-NORMAL-3, coop4-ABYSS-7, coop2-NORMAL-8-serverrun, coop2-NORMAL-14-standins. Tests:
|
||
`test/content/enemies_bosses.test.js` (the silence rule, the two keys silenced and after a silence ran out; 3 fail on
|
||
the parent).
|
||
|
||
#### 25.18.3 「每局游戏开始展示的敌人类型(折射、飞行等等),实际出现波次在7到9波,而且每个最多三波,其余波次用特异类型填充」 (item 6): already the official schedule — no change
|
||
|
||
- **Checked**: `setupMatchWaves` (research 08 §2.1, decoded from the client's `RandomEnemyGenerater`): each of the three
|
||
briefing types owns 3 of the 15 round slots, SPECIAL (特异) the other 6, shuffled, one type per round. R14 (the leader)
|
||
and R15 (the hidden core) take slots too, so the 13 normal rounds of 险境 / 绝境 / 终极 hold 7–9 type waves — 400 seeds
|
||
per mode: 7 in 141 matches, 8 in 192, 9 in 67; per type 1–3 — and every other wave is SPECIAL (solo 标准: 8 normal
|
||
rounds, 3–7). Exactly what the player describes.
|
||
- **Official**: act2autochess `specialEnemyRandomTypeDict` (count 3 per random type, SPECIAL −1), constData
|
||
`maxLevelCnt` 15, `specialEnemyNum` 3, `enemyTypeIdentifierToFillRandom` 1 (SPECIAL).
|
||
- **Now**: docs/PLAYING.md states it at 确认本局信息 (the report: 「更新日志和机制描述也没写」).
|
||
- Golden: unchanged. Pinned: `test/sim/feedback5-cb4-pins.test.js` (the 7–9 and the 1–3), `test/match/waves.test.js` (3 of
|
||
the 15 slots each).
|
||
|
||
#### 25.18.4 「敌人新硎提升攻击力的断刃好像无限消耗,实际应当攻击一次消耗一个,具体有几个复核」 (item 53): already fixed in 0.2.0 (§25.6.2, GitHub #107) — no change
|
||
|
||
- **Checked**: on v0.1.4 新硎's ATK went 2430 → 3510 → 4590 → 5670 and stayed (a layer per attack, none removed) — the
|
||
report. On this tree: 4 attacks at 2430 (+80 %), the 4th spends the last 断刃 and ends the bonus, the next swing comes at
|
||
once at 1350; killed, max(1, 4 − spent) 铁矛头 (沉沙: +70 %, 铜矛头).
|
||
- **Official**: PRTS 天赋 (4 【断刃】, one spent per successful attack); the client's template `enemy_dead_spawn[sfji]`
|
||
(battle prefab enemy_1207_sfji_2): ON_OUTPUT_ATK_OR_HEAL — while `cnt` ≥ 1, `cnt` += `cnt_add` (−1) and one blade marker
|
||
goes; ON_ABILITY_FINISH — `cnt` ≤ 0 ends the ATK buff and switches to mode 1 (无断刃模式); ON_OWNER_KILLED (not 坠落) —
|
||
summons `cnt` (at least 1).
|
||
- [ASSUMED]: the client spends a blade per damage output; here every attack spends one, so an attack an operator dodges
|
||
spends one too.
|
||
- Golden: unchanged. Pinned: `test/content/enemies_bosses.test.js` (the #107 test).
|
||
|
||
#### 25.18.5 「囚犯敌人的解放状态联防时不应继承」 (item 57): already answered (§25.14.1) — no change
|
||
|
||
- **Checked**: a leak re-enters 联防 as a new spawn — `planUnite` passes on its key, spawn mods, LP and bounty only, and
|
||
`buildUniteWave` spawns it — so `prisoner()` starts it confined (the 禁锢 buff, no form) and only its own attacks there
|
||
free it; the client drops every view when a battle starts. The freed look was 普通 / 老练囚犯's red clip set, drawn from
|
||
the gate until §25.14.1.
|
||
- Golden: unchanged. Pinned: `test/sim/feedback5-cb4-pins.test.js` (freed in its own combat, leaked, confined in 联防,
|
||
freed at its 4th attack there).
|
||
|
||
#### 25.18.6 「萨卡兹穿刺手被眩晕或者减速恢复之后移速不会重置(降低),伤害也异常」 (item 36): a stun or 束缚 ends its acceleration; its first hit adds speed × 600 — `content/enemies/special.js kitRush`
|
||
|
||
- **Seen**: after a stun it walked on at the speed it had built up (it even kept accelerating while stunned: 1 → 1.5 in a
|
||
2 s stun); its first hit after a block was one multiplied attack (×(1 + 6 × layers / 25), 2286 at 17 layers), also
|
||
after a stun that came in between.
|
||
- **Official**: PRTS 天赋 「每0.1秒检测一次:①若受晕眩/束缚影响,停止加速 ②若未被阻挡,开始加速…每0.5秒尝试获得1层移动速度+50%
|
||
的增益,最多尝试25次(增益于停止加速时解除…),同时普通攻击附加的Buff会额外造成一次当前移动速度×600的…物理伤害并停止加速」. The
|
||
battle prefab agrees: listeners every 0.1 s end `dlancer_t[trigger]` on STUNNED (a) or UNMOVABLE (b) and start it when
|
||
not blocked (c); the trigger stacks a MULTIPLIER move-speed layer every 0.5 s, blocked or not; the FirstAttack buff
|
||
`dlancer_t_atk` deals `DamageViaAttr` MOVE_SPEED × atk_scale (physical, melee, ignoreForSp) while the trigger exists,
|
||
then ends it. A slow (减速) is no reset — the report's slow is the official behaviour; it only lowers the speed while it
|
||
lasts, and so the extra damage.
|
||
- **Now**: kitRush follows the templates: a 0.1 s listener (晕眩 / 束缚 statuses end the acceleration and drop its layers;
|
||
not blocked starts it, from the spawn), a layer every 0.5 s up to 25 tries, the extra damage = its current move speed
|
||
× 600 as a second, non-attack physical instance with no 受击回复, ending the acceleration (so a block's first hit only).
|
||
Reproduced after the fix: 2 s stun → base speed, a fresh build-up; blocked at 2.375 → 450 + 1500 (2.5 × 600, one more
|
||
layer before the hit).
|
||
- [ASSUMED]: 冻结, 沉睡 and 浮空 do not stop it (they set FROZEN / SLEEPING / LEVITATE, not the two flags the listeners
|
||
read); the client's 0.1 s listener order is folded into one check.
|
||
- Golden: 6 scenarios, each with 萨卡兹穿刺手 in it: roster-016, standin-04, standin-08, diy-028, diy-124 and the bot match
|
||
coop2-HARD-4 (160 spawned). Tests: `test/content/enemies_bosses.test.js` (3: the layers and the cap, the resets, the
|
||
first hit; all fail on the parent).
|
||
|
||
#### 25.18.7 「玩家的官方原版反馈:「投石车」敌人如果被蒸汽地板上的干员阻挡会不进行攻击」 (item 24): 自制投石机's 索敌不受阻挡影响 — `targeting.js canTargetAlly / sortAllyTargets`, `ai.js attackTargets`, `content/enemies/special.js` (enemy_10162_mnctpt)
|
||
|
||
- **The enemy and the terrain**: 「投石车」 = 自制投石机 (enemy_10162_mnctpt, ranged 4.0, the 悬赏·特异III bounty); the 「蒸汽
|
||
地板」 = 战场#07 (下半)'s 排气格栅 (tile_smog: an operator on it is 隐匿 to enemy ranged attacks).
|
||
- **Seen here**: blocked by an operator on the smog, it attacked that operator — every enemy does (the engine's rule: a
|
||
blocked enemy attacks its blocker whatever its selectability, PRTS 索敌的概念 「…强行无视对方可选性发动攻击」).
|
||
- **Official**: PRTS 自制投石机 天赋 「…索敌不受阻挡影响,且不会因丢失目标而结束攻击」 — the blocker exception does not apply to
|
||
it, so a 隐匿 blocker is no target and, with nobody else in its range, it does not attack: the players' report.
|
||
- **Now**: the catapult's profile is `blockFree` (spawns.js gives every enemy the field): `attackTargets` takes the
|
||
allies in reach as if it were unblocked, `canTargetAlly` refuses a 隐匿 / 迷彩 blocker to it, `sortAllyTargets` puts no
|
||
blocker first (仇恨值: taunt, then the latest deployed). Every other enemy keeps attacking a 隐匿 blocker.
|
||
- [ASSUMED]: none for the rule. Not changed, for later: its stones' splash radius (PRTS 「目标半径1.5范围」, the data's
|
||
`projectile_range` 0.5 × 3; the kit uses 0.5), the 0.3 s between its three stones, and 「不会因丢失目标而结束攻击」.
|
||
- Golden: 1 battle — standin-06 (the bounty catapult, blocked by 忍冬, now shot the 斯卡蒂 / 瑕光 pieces by 仇恨值, its
|
||
blocker no longer first). Tests: `test/sim/feedback5-catapult-smog.test.js` (3: no attack on a hidden blocker alone, another operator
|
||
instead, every other ranged enemy still attacks its hidden blocker; the first two fail on the parent). Docs:
|
||
docs/SIM.md.
|
||
|
||
#### 25.18.8 「鸭爵策略的悬赏现在有时候会一波出现多只,比如多只鸭子」 (item 35): the official 0–2 swaps per wave — no change
|
||
|
||
- **Checked**: 鸭爵's “神秘顾客” (`round_start_all_player_change_enemy_2`: min 0, max 2, from round 5, the late part of the
|
||
wave — minweight 0.6 / maxweight 0.99) swaps 0–2 ground enemies of each player's wave, each into one of 鸭爵, 高普尼克,
|
||
流泪小子, 圆仔 at random (bands/meta.js duckReplace, once per player per battle — no second handler). 1000 real waves
|
||
(`m._normalOpts`, solo and co-op, rounds 5–12): 0 swaps 388, 1 swap 312, 2 swaps 300, never more; the two of a 2-swap
|
||
wave were the same kind in 81 of 300 (two of one kind in ≈ 1 wave in 12, two ducks in ≈ 1 in 50). A pair leader field holds
|
||
each player's 0–2 on its own half, and 联防 re-enters every leaker's leaked swaps (both as before).
|
||
- **Official**: PRTS 卫戍协议:盟约 下半/PRTS盟约记录 鸭爵 备注 「每回合将有0~2名敌人被替换为上述敌人之一」 — two ducks in one
|
||
wave is the official rule.
|
||
- Golden: unchanged. Pinned: `test/sim/feedback5-cb4-pins.test.js` (≤ 2 per wave, 0 / 1 / 2 and two of a kind all occur,
|
||
1 fund each).
|
||
|
||
#### 25.18.9 「会移动的关底boss在各个地图的移动路线复核下是否正确」 (item 29): checked on every boss field — no change
|
||
|
||
- **Checked**: the leaders that walk are 铳 (boss_2 / 9) and 卢西恩 (boss_5); the 巨型单位 (胄, 管, 昆图斯, 阿利斯泰尔, 萨米的意志)
|
||
are 自缚 (content/bosses.js SELF_BOUND). Their routes are the level files' (level_act1autochess_h07_02 route 6 and act2
|
||
h07_05: PATROL_MOVE (3,9) → (2,3) → (5,9), 卢西恩's list four such rounds with a MOVE (5,9) between them), walked with the
|
||
official SPFA flow field and looped by `patrolLoop` (back to the first leg instead of the goal). On all 8 boss fields
|
||
of the season, solo and pair, 240 s each: every sample on a walkable tile, the targets in the official order, the pair's
|
||
mirrored copy on (3,11) → (2,17) → (5,11) (its branch route), 卢西恩 restarting after its 19th checkpoint and never reaching
|
||
the goal (its lpr 30).
|
||
- Found, not changed: without the match's `waveId` (tests, tools) `templateOf` infers the template from the route list
|
||
only and can take another leader's; 卢西恩 then misses its patrol loop and walks to the goal. The match, the server's
|
||
headless fields and the browser battles always pass it (BattleSpec `waveId`).
|
||
- Golden: unchanged. Pinned: `test/sim/feedback5-cb4-pins.test.js`.
|
||
|
||
#### 25.18.10 「干员野鬃放在红门前两格的时候有概率会把怪顶出地图显示漏怪」 (item 38): not reproduced — no change
|
||
|
||
- **Checked**: 野鬃 (elite, S2 夹枪冲锋 kept running) two tiles before either red gate, facing it, on 战场#01–#08 against real
|
||
waves (912 battles, normal fields; 480 more with the solo leader fields), also on v0.1.4: her pushes (up to 30 a battle)
|
||
never left a ground enemy on a tile it cannot walk, and every leak happened at its route's end. `Battle.displace`
|
||
moves a ground enemy only over walkable tiles of the battle rect, so it stops on the gate tile at the field's edge;
|
||
planLeg then walks it back. What the rule does allow: an enemy she keeps pushing back onto the gate until the time
|
||
limit is counted as leaked (时间到仍存活的敌人算漏怪), as in the official game. A recording or the map and round would
|
||
settle what the player saw.
|
||
- Golden: unchanged. Pinned: `test/sim/feedback5-cb4-pins.test.js` (two real waves, three tiles before the gates).
|
||
|
||
#### 25.18.11 「怪物的重量以及干员的推拉力度还是有点不对,比如锏能拉动10重的关底boss」 (item 39): not reproduced — no change
|
||
|
||
- **Checked**: a leader (tag boss) is never displaced (`Battle._displaceable`); 锏's S3 pulls with 力度 1 (中力) and, at
|
||
its end, 2 (较大力): 受力等级 = 力度 − 重量 ≤ −3 moves nothing (PRTS 推与拉), so no weight ≥ 5 enemy moves either. 40 S3
|
||
casts next to each of the 10 leaders (weights 6–10): never moved; 自在 as a bounty (weight 10) not even by 特大力. The
|
||
one thing that looks like it: 卢西恩's 不祥幻影 has his model and weight 2, so 锏 does pull it (all the way, 受力等级 0).
|
||
- Golden: unchanged. Pinned: `test/sim/feedback5-cb4-pins.test.js`.
|
||
|
||
#### 25.18.12 「昆图斯占地少最左边和最右边两排,似乎变成3x3了」 (item 47): not reproduced — no change
|
||
|
||
- **Checked**: 昆图斯's hit area is PRTS' 「受击判定区域为长4.95宽2.95的长方形,向上偏移1.0」 (tools/build-data.mjs HIT_AREAS):
|
||
standing on (3,10) it occupies cols 8–12 × rows 3–5 (body.js bodyKeys); an operator whose range reaches only its
|
||
leftmost column (艾丝黛尔 on (3,7)) attacks it; the Final Assault prep lights the same 15 tiles in red on both boards
|
||
(headless screenshots of the render demo's Final Assault prep; render/pick.js hitTiles = bodyKeys, pinned by
|
||
`test/render/feedback3-leader-prep.test.js`). Its model is drawn at the official prefab scale.
|
||
- Golden: unchanged. Pinned: `test/sim/feedback5-cb4-pins.test.js`.
|
||
|
||
#### 25.18.13 「最终boss跟原版相比攻击欲望感觉低了,不怎么打人,复核」 (item 52): every leader attacks at its data interval — no change
|
||
|
||
- **Checked**: solo leader fields with eight walls on the board, 150 s: 胄 38 normal attacks (interval 4 s), 昆图斯 43 (3.5 s,
|
||
two targets each), 阿利斯泰尔 19 (8.2 s), 萨米的意志 25 (6 s) — each at its official interval from its first target on —,
|
||
their skills at their cooldowns; v0.1.4 gives the same counts (only the first strike now comes at the damage frame,
|
||
§25.7.2). 铳 opens at the PRTS minimum attack speed 20 (22.5 s) and gains +80 per attack on the same target (5 times),
|
||
so a fight that keeps switching its target sees few of its attacks; 管's normal attacks strike its 余音, not operators;
|
||
卢西恩 attacks only its blocker and blinks past it. A leader and a situation from the reporter would show what differs.
|
||
- Golden: unchanged. Pinned: `test/sim/feedback5-cb4-pins.test.js` (the four interval leaders at ≥ max − 1 attacks).
|
||
|
||
### 25.19 Community reports of 2026-10-06, stream CB5: match flow and UI — `ui/loadoutModel.js traitLines`, `player/economy.js _openLevelSlots`, `match/watch.js _followScout`, `match/views.js prepFieldMeta / bossMateView`, `render/app.js syncMates`, `ui/gameLogic/camera.js teamFrameIds`
|
||
|
||
CB5 took the items about the match flow and the screens (16.2, 19, 51, 55, 56 of the list; 22 and 48 are feature
|
||
requests — 22 postponed by the owner, 48 built in §25.15 —, both at the end). Each was reproduced first (a script, or the real server in
|
||
headless Chrome for the screens), checked against the official data, PRTS and the official tutorial pages, then fixed in
|
||
one commit with its tests; two open community PRs were reused without merging them (§25.19.6).
|
||
|
||
#### 25.19.1 「干员调配界面很多干员的某个模组只有额外特性没有基础特性,不清楚是文本错误还是实际效果也有错」 (item 16.2): text only — the module's added line now follows the class trait — `ui/loadoutModel.js traitLines / fullTraitText`, `ui/detailPanel.js traitText`, `screens/loadout.js ModuleInfo`, `screens/diy.js ModuleRow`
|
||
|
||
- **Seen**: 114 of the 164 modules the 干员调配 screen offers (128 of all 184 elite module records) showed under 特性 only
|
||
the module's extra line — 隐现's MAR-X read 「攻击空中单位时攻击力提升至110%」 without 「优先攻击空中单位」; 局内数值, the
|
||
in-match detail card and the 自选 module row did the same.
|
||
- **Official**: a module's trait candidate either rewrites the class trait (`overrideDescripton`) or adds a line after it
|
||
(`additionalDescription`); PRTS flags the latter 「特性追加」 on every such module (e.g. 伊芙利特 BLA-X / BLA-Δ, 玛恩纳
|
||
LIB-X, 莫斯提马 SPC-X / SPC-Y).
|
||
- **Cause**: the data keeps both lines (`traitOverride.desc` = the class trait or its rewrite, `moduleDesc` = the added
|
||
line); the screens showed `moduleDesc` instead of `desc` (since 0.1.2: the review of GitHub #64 in §22 picked the
|
||
module line over a cloned record's class trait). The battle was right: for every added-line module the unit keeps the class
|
||
trait — the same trait text, targeting, attack shape and trait blackboard as 不装备 (圣约送葬人 REA-Y also rewrites it).
|
||
- **Now**: `traitLines` / `fullTraitText`: the class trait (or the rewrite), then the added line; the module card shows
|
||
them as 特性 and 特性追加 (en "Added Trait").
|
||
- Golden: unchanged (no sim change). Tests: `test/ui/feedback5-module-trait.test.js` (6; the text cases fail on the
|
||
parent, the data and sim pins pass there), `test/ui/loadout-stats.test.js` updated; SP_E2E `loadout.e2e` 9 / 9.
|
||
Docs: docs/DATA.md (`trait`, `traitOverride`).
|
||
|
||
#### 25.19.2 「升级商店获得新的商店位时用新卡补上,而不是空着」 (item 19): the upgrade opens the new slot with a new card — `player/economy.js _openLevelSlots`, `audit.js`
|
||
|
||
- **Seen**: a level-up from 1 to 2 (险境: 3 → 4 operator slots) or 3 to 4 (4 → 5; 标准 5 → 6) showed no new card until the
|
||
next refresh or round start (the shop kept its rolled layout; META listed it as an assumption).
|
||
- **Official**: the tutorial's 休整期 page (local guide art `autochess_home_4`): 「升级:消耗资金升级调度中心。升级后将出现更多
|
||
的商品栏位、可调度干员以及新装备」; PRTS 帮助 「消耗资金可以为调度中心升级,从而增加刷新栏位」.
|
||
- **Now**: `levelUp` → `_openLevelSlots`: the new level's extra slots are appended to the operator slots at once (the
|
||
item slot stays after them), each drawn at the new level; the cards shown stay in place, a bought card stays sold.
|
||
`audit.js` checks the count and the kept cards (`matchrun --check`: no violation).
|
||
- [ASSUMED]: the new card follows the freeze toggle, as a manual refresh's cards do.
|
||
- Golden: matches — all 18 scenarios (every bot levels its shop and now sees, and draws the shop RNG for, the new card at
|
||
once); the battle families unchanged. Tests: `test/match/feedback5-shop-levelslots.test.js` (3, all fail on the
|
||
parent). Docs: docs/META.md §3 / §7, docs/PLAYING.md.
|
||
|
||
#### 25.19.3 「死亡观战时每一回合结束都会被转回自己家」 (item 56): an eliminated player follows a player through every phase reset — `match/watch.js watchPref / _watchTargetOf / _followScout`, `battle/observe.js followedScout`
|
||
|
||
- **Seen** (real server, headless Chrome): every round start cleared an eliminated player's watch — in 回合开始 / 机变 /
|
||
休整期 it saw its own empty board, each battle started on the first field; a spectator seat asked for the first player
|
||
itself.
|
||
- **Official**: research 09 §3.1 — after elimination the client keeps observing (self_dead_dialog KEEP_WATCH, the
|
||
server's DeadAutoObDn { obIndex, state, preparation }, FindFirstAvailObTarget).
|
||
- **Now**: `Match.watchPref` = the player of the viewer's last manual `g.watch` (a prep scout, a single-player field, or
|
||
— new, optional — `g.watch { playerId }` naming the row tapped on a shared 联防 / boss pair field); `_watchTargetOf` = that
|
||
player while still in, else the first player still in (seat order, AI seats included). The round start pushes its prep
|
||
board (`_followScout`, kept through 机变 and 休整期), both combat modes and the boss fields start on its field, a resync or
|
||
a spectator joining in prep gets the board, a followed player who quits hands over at once. The screen adopts the pushed
|
||
board like a 前往查看 tap (`followedScout`; PR #189's stale-field fix) and keeps it through the prep phases; 返回自己 asks
|
||
the server for nothing (the viewer has no board).
|
||
- Golden: unchanged. Tests: `test/match/feedback5-watch-follow.test.js` (9; 8 fail on the parent's server),
|
||
`test/match/spectator.test.js` updated. Docs: design/network.md, docs/PLAYING.md.
|
||
|
||
#### 25.19.4 「死亡后观战视角看不到场上的关底boss」 (item 55): a watcher of a boss round's prep sees the boss field and its leader — `match/views.js prepFieldMeta`, `screens/game.js`
|
||
|
||
- **Seen** (headless Chrome, the guest eliminated at the boss round): in the Final Assault fight the watched boss field
|
||
showed the leader (enemy_9013_acstmk at 10,3); in the boss round's prep the guest saw its own empty normal board (camera
|
||
'prep', no leader) and a scout of a teammate was the normal board too — while the players prepare on their half of the
|
||
boss field with the leader standing there (§23.18, community report #12).
|
||
- **Now**: in a boss round's prep the scout is built on the boss field — `kind: 'boss'`, `BOSS_RECT`, the scouted player's
|
||
pieces through `bossFieldPlacement` (rows − 7, the right half mirrored with RIGHT ↔ LEFT), `side`, the leader's spawn in
|
||
`nextEnemies` — and framed by the boss-field prep camera of that side, which shows the leader. With §25.19.3 the
|
||
eliminated player gets it at the round start; the same run after the fix: field 'boss', camera bossPrep, leader shown.
|
||
- Golden: unchanged. Tests: `test/match/feedback5-boss-prep-scout.test.js` (2, fail on the parent); SP_E2E
|
||
`test/ui/feedback5-boss-pair.e2e.test.js` (item 55 case). Docs: design/network.md, design/client.md §15.
|
||
|
||
#### 25.19.5 「还原原版最终boss战准备阶段:像战斗中那样把会成一组的两个玩家放在一起…同组两个玩家屏幕左边的头像也像原版那样用绿框框起来」 (item 51): the pair together in the boss prep, the official green frames — `match/views.js bossMateView`, `match/messaging.js markPrivate`, `render/app.js syncMates`, `ui/teamPanel.js`, `ui/gameLogic/camera.js teamFrameIds`
|
||
|
||
- **Seen**: the own half was already the official one — the right-hand player on the right half with the
|
||
right_boss_*_camera_param camera, its layout mirrored col c → 20 − c with RIGHT ↔ LEFT, so its operators face the leader
|
||
as before (research 09 §1.2, §15) — but the partner's half stood empty and nothing framed the pair.
|
||
- **Official**: every client knows every board (ChangePositionDn { boardStatus }, research 09); the team list frames the
|
||
co-op group (the owner's recall; the client's ui/battle `bg_team_border`, a white 100×100 frame with its glow, and the
|
||
autochess green of `icon_self`, #4ed8af).
|
||
- **Now**: in a boss round's prep `m.private.bossMate { playerId, side, units }` carries the partner's board on its half,
|
||
placed as the battle will (bossFieldPlacement); a partner's change marks the player's m.private too (`markPrivate`), so
|
||
it follows live; the own prep view draws those units read-only ('m:<uid>' views, never picked or dragged) and lights the
|
||
whole boss field; a scout of either player shows both halves (`mate`). The team panel frames the pair's two avatars
|
||
(`teamFrameIds`: the players still in by seat, two by two, as `prepCamera`; the boss field in the fight) from the round
|
||
start through the fight, with the official sprite tinted green (a plain ring without the local art); a lone player, an
|
||
eliminated player and a spectator seat get none; 联防 is not framed (not asked).
|
||
- [ASSUMED]: the partner's bench is not shown (its board only); the frame's exact official geometry (one frame per avatar).
|
||
- Golden: unchanged. Tests: `test/match/feedback5-boss-pair-prep.test.js` (4, fail on the parent), SP_E2E
|
||
`test/ui/feedback5-boss-pair.e2e.test.js` (both halves, the mirrored right half, the frames in prep and fight).
|
||
Docs: design/client.md §10 / §15, design/network.md, docs/PLAYING.md.
|
||
|
||
#### 25.19.6 Overlap with the open community PRs #189 and #191 (not merged; their authors' fixes were pending)
|
||
|
||
- PR #189 (watch preference, @2321Robin) — §25.19.3 builds the same chain (a manual watch is the preference; round start,
|
||
both combat modes, the boss fields and the resync follow it; the stale-field fix of the adopted scout), on the 0.2.0
|
||
method containers. Differences: the fallback is the first player still in with AI seats included (a lone human with AI
|
||
teammates had nobody to follow — the report's case), and a shared field records the `playerId` the row tap sends (the
|
||
review's point 2) instead of nothing.
|
||
- PR #191 (same-field frames, issue #190) — §25.19.5 frames the pair as the owner asked: green, the official sprite, both
|
||
avatars (self included), the boss rounds only; the pairing is read from m.public as the prep camera already does, so no
|
||
`bossPairing` field; #191's 联防 frames and the phase banner naming the partner are not built. If the owner still wants
|
||
them, they can go on top of this.
|
||
|
||
#### 25.19.7 The two feature requests: battle history postponed by the owner, custom hotkeys built (§25.15)
|
||
|
||
- **22 战绩 / 分队胜率** — postponed by the owner; what it would take: the result is already complete (`m.result`:
|
||
per-player stats, lineup, band, bonds, titles, rounds passed, victory — `server/match/results.js`). With no accounts the
|
||
simplest is per browser: append a compact record at `m.result` to localStorage (capped, e.g. the last 200; only matches
|
||
of ≥ 2 rounds, as asked), a 战绩 screen in the lobby (list, win rate per strategy / core bond / mode and difficulty,
|
||
导出 / 导入 like the loadout), tests and i18n — no server change. Server-side history needs persistence and an identity
|
||
the remake does not have. Decisions left for then: browser-only or not; what 「分队」 groups by (strategy, core bond,
|
||
lineup); the sample cap.
|
||
- **48 自定义快捷键** — built in 0.2.0: §25.15 (W5AC; the community request 「快捷键可不可以自己设置」, the owner's decision of
|
||
2026-10-07). 设置 → 快捷键 rebinds 刷新, 冻结, 升级, 撤退, 出售 and 准备就绪 / 暂停 (Esc stays fixed); the key map lives in
|
||
the settings (`sanitizeSettings`) and `shortcutFor`, the facing wheel and every key hint read it. One difference from
|
||
the estimate that stood here: a key another action has is swapped, not refused. The official PC client's keys are
|
||
fixed as far as the data shows (`pc_key_holder` hints), so the shortcuts are the remake's own.
|
||
|
||
### 25.20 Language packs: a language is a file in the language folder, the first type of content packs (W5AD; the owner's decisions of 2026-10-07) — `shared/packs.js`, `shared/i18nPacks.js`, `shared/i18n.js`, `shared/i18nData.js`, `server/packs.js`, `server/http/static.js`, `public/js/ui/lang.js`, `public/js/data.js`, `tools/i18n.mjs`, `tools/packs.mjs`, `tools/build-i18n.mjs`, `tools/package.mjs`, docs/I18N.md §5, docs/PACKS.md
|
||
|
||
- **Seen**: after §25.2 English was wired in by name — the language list `['zh', 'en']`, the switch's labels, English
|
||
checks in the title screen, `fmtNum`, the tab title, a CSS rule, the overlay URL pattern — so another language meant
|
||
editing code, and players asked to translate into their own languages.
|
||
- **Decision**: the owner's decision of 2026-10-07 — putting an adapted language file into the language folder is all
|
||
it takes for the game to offer that language, so the community can add languages themselves; the same day, design the
|
||
language pack as the first type of a general content-pack mechanism (later: resource packs for art / audio, then
|
||
server-side data packs) with one manifest, one registry and one index.
|
||
- **Now** (docs/I18N.md §5 for translators, docs/PACKS.md for the mechanism):
|
||
- **A pack** is a manifest plus its files, in one of two layouts the same registry reads: the single file
|
||
`public/i18n/<code>.json` (manifest: its `_meta` block; optional game texts `data/i18n/<code>.json`) — the
|
||
translator's way and how English ships — or a folder `packs/<id>/pack.json` naming its files (every future type).
|
||
The manifest: type (`lang`; `assets` and `data` planned: parsed, listed as not supported, never served), version,
|
||
the app versions it targets (a range; outside it a language pack still loads and is flagged), its name in its own
|
||
language and in English, authors / credits / licence, and the type's fields (`lang`, `base`, `fallback`, `complete`,
|
||
`numberUnits`). English carries one like any pack (`complete: true`).
|
||
- **Discovery**: `server/packs.js` scans the language folders and `packs/` at start and again when their files
|
||
change (looked at on each index or pack-file request, at most once a second), validates the manifests, and answers
|
||
`GET /packs/index.json` (live, never cached; packs of supported types with the URLs of their files) and
|
||
`GET /packs/<id>/<file>` (only a file a manifest names, with its role's extension, inside the pack folder). A static
|
||
host uses `node tools/packs.mjs index` (packs/index.json); the release zips ship packs/ and that file. A broken
|
||
manifest, a planned type, a second pack for an id or a language: skipped with the reason in the server log and
|
||
`node tools/packs.mjs list`.
|
||
- **The client** lists every `lang` entry under its own name (title screen and 设置: buttons up to four languages, a
|
||
list beyond); `?lang=<code>` and the stored choice resolve to a listed pack (`en-US` → `en`; a pack that is gone →
|
||
Chinese); without an index the stored pack still loads by its code. Nothing in the client names English: the title
|
||
screen lays out by the script of the pack's title (`scriptOf`: an alphabetic title takes English's layout), the tab
|
||
title and `<html lang>` follow the pack, `fmtNum` takes `numberUnits` (Chinese 万 / 亿; without them K / M / B).
|
||
- **Fallback chain** per string: the pack → its base (`pt-BR` → `pt`; `zh-TW` none) → the packs `_meta.fallback`
|
||
names (English) → the Chinese msgid; game texts per text (each from the first overlay of the chain that has it:
|
||
`applyFileOverlay(json, overlay, onto)`, `data.setLocale(lang, chain)`).
|
||
- **Placeholders**: a translation that drops a plain placeholder of its msgid, uses one the caller does not pass, or
|
||
has a broken plural form is skipped like a missing one (the next language of the chain shows; a development page
|
||
warns once on the console; `tools/i18n.mjs check` checks the call sites). **Plurals**: `{n|one|other}` picks by
|
||
`Intl.PluralRules` (English exactly as before), and named categories serve other languages
|
||
(`{n|one:…|few:…|many:…|other:…}`).
|
||
- **Tools**: `node tools/i18n.mjs template <code>` (a skeleton: `_meta` and every msgid; on an existing pack only
|
||
the msgids it lacks), `check <code> | --all` (coverage; errors; a complete pack must have every msgid);
|
||
`node tools/build-i18n.mjs --lang ja | ko | zh-TW` builds a pack's game texts from the official JP / KR / TW client
|
||
(ArknightsAssets/ArknightsGamedata `jp/`, `kr/`, `tw/`, each with both 盟约 seasons, checked 2026-10-07: ja 96.5 %,
|
||
ko 97.4 %, zh-TW 91.1 % of 22 114 texts); a language without a client uses `--dict` (a community dictionary) or no
|
||
game texts at all (they follow the chain). The stream shipped no language but English (a game-text file without
|
||
its UI pack is not listed).
|
||
- **Shipped: 日本語, 한국어, 繁體中文** (the owner's decision of 2026-10-07, at the merge): `data/i18n/ja.json`,
|
||
`ko.json`, `zh-TW.json` built with `build-i18n --lang` (ja 96.5 %, ko 97.4 %, zh-TW 91.1 %) and minimal UI packs
|
||
`public/i18n/ja.json`, `ko.json`, `zh-TW.json` — a `_meta` manifest (its own and English name, credits: the official
|
||
client data via ArknightsAssets) and no UI strings yet: `ja` / `ko` fall back to English, `zh-TW` to the Simplified
|
||
Chinese UI (no fallback — the owner's choice; [ASSUMED] numbers in 萬 / 億). With five languages the menu is
|
||
a list (buttons up to four). UI translations are welcome from the community (docs/I18N.md §5 "Shipped packs").
|
||
- **The output in Chinese and English did not change**: `test/i18n-packs.test.js` renders every msgid of
|
||
`public/i18n/en.json` in both languages with sample params and compares it with the renderer of 0.2.0 before packs;
|
||
`node tools/build-i18n.mjs --check` still finds `data/i18n/en.json` up to date. One English entry was added, the tab
|
||
title (`卫戍协议:盟约 · STRONGHOLD PROTOCOL`, the same text as before).
|
||
- [ASSUMED]: the menu turns into a list above four languages; two plain plural forms follow the language's rules (only
|
||
-1 renders differently from before in English, "-1 second"); a regional code falls back to its language's pack before
|
||
the declared fallbacks; with two packs for one language the language folder's file wins; a pack outside its app range
|
||
still loads; a development page is a dev build or one served from localhost.
|
||
- Golden: unchanged. Tests: `test/i18n-packs.test.js` (12: discovery of both layouts and of broken / planned /
|
||
duplicate packs, a pack dropped in or removed while the server runs, the file allowlist, manifests and app ranges,
|
||
the chain, placeholders, plurals in English and Russian, the per-text game-text fallback, the client loader and menu,
|
||
the template / check / index tools, build-i18n's `--lang` and `--dict`, zh / en unchanged), `test/package.test.js` (both layouts ship, a local pack does
|
||
not, the generated index), `test/ui/i18n.e2e.test.js` (`SP_E2E=1`: a pack file and a pack folder dropped in while the
|
||
server runs show in the menu and switch, English filling the gaps; a removed pack sends the stored choice back to
|
||
Chinese); `test/i18n.test.js`, `test/i18n-data.test.js`, `test/i18n-server.test.js` unchanged and green.
|
||
|
||
### 25.21 Community reports of 2026-10-06, stream CB1: bonds, strategies, items — `sim/battle/status.js applyStatus` (cold), `content/items/battle.js reviveNow`, `content/bands/battle.js` (埃芒加德), `content/bands/meta.js` (佩佩), `content/tokens.js airTile`, `screens/result.js resultBonds`, `tools/build-data.mjs` (pool_equip_kathe)
|
||
|
||
Fifteen of the owner's community reports of 2026-10-06 (items 5, 7, 8, 9 / 37, 15, 20, 21, 23, 25, 41, 42, 43, 45, 49,
|
||
50 of the list). Each was reproduced on this tree with a script, checked against the official data (bonds.json,
|
||
items.json, the client's buff templates), PRTS (卫戍协议:盟约 下半/PRTS盟约记录 and its 备注, 术语释义, 特殊机制) and the
|
||
earlier decisions. Seven were real and are fixed in six commits (7 and 8 share one; golden named in each); five are the
|
||
official behaviour (four pinned by tests); three could not be reproduced and need the reporters' cases; two questions
|
||
went to the owner (the order of §25.21.1, a fallback in §25.21.10) — the owner's decision of 2026-10-07 kept both as they
|
||
are.
|
||
|
||
#### 25.21.1 「维多利亚的锁血锤和烛煌的锁血只生效了一个」: both work, one after the other — no change
|
||
|
||
- **Measured**: 烛煌 (elite) carrying 坚固维式重锤, a lethal hit every 2 s: 倒地 at the first (绝处重燃, a kit `fatal` saver
|
||
−50), the hammer's lock at the hit that breaks the 6000 barrier while she is 倒地 (`PRIO_REVIVE` −100), death 8 s later;
|
||
without the hammer she falls at the second. The 蒸汽之心 path (another operator's hammer) behaves the same.
|
||
- **Why it looks like one**: PRTS 备注 「不处于【重燃】状态下,受到足以致命的伤害时,可触发此天赋效果,次数不限」 — the talent takes
|
||
every lethal hit outside 【重燃】, so the lock only ever shows when she is killed while 倒地. The order — kits' savers before
|
||
the consumable 不死 — is the documented [ASSUMED] (§21.21, §22.7's 余烬): the official talent fires on
|
||
ON_BEFORE_TRY_SET_HP_ZERO (buff template blaze2_t_2) and the autochess hammer's template is not in the client's buff
|
||
data, so no source gives an order. Asked whether the lock should take her first lethal hit instead, **the owner kept the
|
||
order** (the owner's decision of 2026-10-07): 绝处重燃 first, then the lock.
|
||
- Golden: unchanged. Pinned: `test/content/feedback5-blaze-hammer.test.js`.
|
||
|
||
#### 25.21.2 「谢拉格盟约冰冻时间没有随层数正确成长」 and 「…被在无法被任何干员攻击到的地方永控」: a pair of colds becomes the freeze — `sim/battle/status.js applyStatus`
|
||
|
||
- **Seen**: the 6-member wind (every 25 s, 寒冷 20 + 0.1 × layers s) froze an enemy for the rest of the battle from 51 layers
|
||
on, wherever it stood (at the gate too), and never below: measured, 60 layers → frozen from 50 s to the end; 40 → never.
|
||
- **Official**: PRTS 术语释义 寒冷 「友方寒冷始终需要两两一对产生友方冻结,持续时间取双方之中最高」; 异常效果 COLD
|
||
「在特定条件下转变为冻结」 — the pair turns into one freeze (a lone 友方 cold on a frozen enemy needs a partner, unlike the
|
||
敌方 rule 「…施加的敌方寒冷会变为敌方冻结」).
|
||
- **Cause**: the second cold froze for max(remaining, incoming) (§23.27) and the older cold stayed on, extended to the same
|
||
length, so the next cold before it ran out — the next gust — froze again.
|
||
- **Now**: on an enemy the pair becomes the freeze and no cold is left; on an operator (敌方寒冷) the old rule stays. The wind
|
||
alone freezes 20 + 0.1 × L s of every 50 s from 51 layers (60 → 26 s, 200 → 40 s, all of it from 300).
|
||
- [ASSUMED]: a paired cold emits no `statusApplied` 'cold' (the freeze does).
|
||
- Golden: every scenario where a second cold met a cold enemy (the commit lists 35). Tests:
|
||
`test/sim/feedback5-kjerag-cold.test.js`; `feedback3-cold-freeze` and 灵知 S2 (`kits_t4`) updated. Docs: docs/SIM.md
|
||
(`cold`), DESIGN §5 (design/engine.md).
|
||
|
||
#### 25.21.3 「卡西米尔和艾芒加德策略似乎有BUG:像砾和瑕光这种死亡和部署的叠层效果…无法触发」: a 复活 is a knock-out and a free redeploy — `content/items/battle.js reviveNow`, `content/bands/battle.js`, `content/bonds/core.js installEgir`
|
||
|
||
- **Seen**: with 埃芒加德's 命结之秘, 砾 (<部署时> 卡西米尔 +1, <被击倒时> 不屈 +2) gained nothing from his first three
|
||
knock-outs and stacked only on the 4th, real death; 瑕光's <部署时> +4 never fired on a revive.
|
||
- **Official**: PRTS 埃芒加德 (and M3茧甲, 阿戈尔) 备注 「“复活”的实现方式为:受益者因移动之外的原因退场时下次部署的再部署时间和
|
||
费用归零」 — the operator is knocked out and redeployed at once.
|
||
- **Cause**: both 复活 were `fatal` savers that kept the unit standing (a known simplification, §21.20's "not done"): no
|
||
`death`, no `deploy`.
|
||
- **Now**: `reviveNow`, a `death` hook (M3茧甲 `PRIO_RESPAWN` 13, 埃芒加德 `PRIO_BAND_REVIVE` 12, ahead of 阿戈尔 5 at 11 and
|
||
不屈 at 10): the knock-out stands (被击倒时 effects, 克莱门莎, 卡莱莎, 不屈's +5 SP …) and the operator redeploys where it
|
||
lies, free (full HP, SP reset, 部署时 effects, the 卡西米尔 deployment ATK, a new 坚固 lock — `revivedInPlace` is gone).
|
||
The ctx carries `revivedBy`, so 阿戈尔 5 does not count that knock-out as the member's first (the owner's decision of
|
||
2026-10-05, unchanged).
|
||
- [ASSUMED]: a revive whose tile is taken spends nothing (as 阿戈尔 5); with both, M3茧甲 answers first (as before).
|
||
- Golden: the battles with M3茧甲 or 埃芒加德 whose operators fell (11, the commit lists them). Tests:
|
||
`test/content/feedback5-revive-redeploy.test.js`; bands / bonds_core / feedback1f-hammer / op_lessng / op_zuole /
|
||
docs-consistency updated. Docs: docs/SIM.md (`fatal`, `death`), DESIGN §5 (design/engine.md), docs/PLAYING.md, research 04.
|
||
|
||
#### 25.21.4 「局内划掉被ban的盟约的实际效果有问题:只在标准模拟中生效」: the drawn bonds are the same in every difficulty — no change
|
||
|
||
- **Measured**: the drawn set D — 0 core + 1 add-on in 标准, 3 + 4 in 险境 / 绝境 / 终极 — removes only the operators whose
|
||
every bond is in it (23–25 banned, none in the pool); each drawn bond keeps 2–10 members through their other bond, 标准's
|
||
one included. Only 标准 also has the mode's static list (the official modeDataDict inactiveBondIdList, 10 bonds that never
|
||
activate, §21.7).
|
||
- **Official**: 帮助 「…以及不完整的盟约与不会进入调配池的干员」, the briefing badge 「部分盟约所含干员阵容不完整」, the
|
||
strategies' 「在<X>部分干员缺席时体验可能不完整」 (research 01 A2). The briefing legend already says it.
|
||
|
||
#### 25.21.5 「佩佩策略的特殊刷新也是要花钱的,不是免费」: the special refresh is paid — `content/bands/meta.js`
|
||
|
||
- **Seen**: reaching shop level 2 / 4 / 6 granted a free refresh; the special one cost 0.
|
||
- **Official**: 博学多通 「获得1次特殊刷新」 names no 免费 (德克萨斯's trait 「获得1次免费刷新」 does); the blackboard's `price`
|
||
0 had been read as its price.
|
||
- **Now**: the level-up marks the next manual refresh special — the usual refresh price, the chess slots filled with
|
||
<萨尔贡> first. [ASSUMED] `cnt` / `price` 0 change nothing. Golden: unchanged. Test: `test/content/bands.test.js`.
|
||
|
||
#### 25.21.6 「独行这种盟约是不能叠层的」: they stack, the game never shows them — `screens/result.js resultBonds`
|
||
|
||
- **Official**: PRTS 盟约记录's header 「下述盟约中部分盟约不会显示叠加层数,但是叠加层数的特质/策略/装备等效果仍然对其生效」 — the
|
||
four bonds.json `noStack` bonds (调和, 协防干员, 独行, 绝技) take layers like every other (GitHub #139's answer, 0.1.4
|
||
PR #66); their effects do not read them. The report asks for what the game does not do.
|
||
- **Now**: the one place still printing the hidden count — the result card (「独行 24」, ranked by it) — shows no number and
|
||
does not rank by it, as the bond strip since PR #66. Golden: unchanged. Test: `test/ui/feedback5-result-bonds.test.js`.
|
||
Docs: docs/PLAYING.md (层数), research 02 §2.2.
|
||
|
||
#### 25.21.7 「Touch策略给的医疗干员会跟炎盟约的炎祐冲突,无法同时出场」: the 炎佑 keeps off the map-character slot — `content/tokens.js airTile`
|
||
|
||
- **Seen** (every season map): on 战场#08 涨潮控制 (always) and 战场#07 排气格栅 (the second 炎佑 of 9 炎) the 外勤医疗 medic /
|
||
Touch never stood.
|
||
- **Cause**: both spawn at battle start; the 炎佑's tile (void tiles nearest the half's centre) took (10, 2), the medic's
|
||
stage slot (stages.json `mapChars`), first. The 联防 maps have no predefined medic in the official levels: none there.
|
||
- **Now**: `airTile` holds the map characters' positions. Golden: unchanged. Test: `test/content/feedback5-yanyou-touch.test.js`.
|
||
|
||
#### 25.21.8 Not reproduced — 「炎祐能错误的被空中单位阻挡」 (item 25), 「选pith策略的时候阿戈尔在联防时会出现加成被清空」 (item 41), 「源石溶剂在干员血量满的时候没生效」 (item 42) — no change
|
||
|
||
- 25: the 炎佑 never blocks (block 0) and is never blocked (only enemies are block candidates), as PRTS 特殊机制 我方单位
|
||
「敌人类我方单位不会被角色类单位阻挡」; it hovers on the top-aggro enemy, and an unblocked ranged enemy — a flyer included —
|
||
stands for each attack (GitHub #58), so a flyer shooting it looks held.
|
||
- 41: Pith's 盟约·辅助干员 (调和) with four 阿戈尔 (5 with 调和's +1): the same 阿戈尔 HP bonus in the normal battle and in 联防,
|
||
one or two helpers, either half; the 联防 input is the normal one plus the round's layers, HP ratio, SP and 倒地.
|
||
- 42: from full HP the drain ticks 60 / s and ATK +40 % holds. Noted for the owner: the official `periodic_damage` template
|
||
has `_ignoreForSp: true` (no 受击 SP), while §21.12 lets it charge 受击回复 SP.
|
||
- The reporters' cases (operators, items, screenshots) are needed.
|
||
|
||
#### 25.21.9 「凯瑟琳装备池没有超出商店等级的装备」: the 凯瑟琳 offer is every shop item — `tools/build-data.mjs`
|
||
|
||
- **Seen**: the 1 → 2 upgrade offered tiers I–II only (40 seeds: 55 × I, 65 × II).
|
||
- **Official**: the pool is server-side; the players' first-hand account 「原版凯瑟琳1升2都能有6本装备」.
|
||
- **Now**: `pool_equip_kathe` is every shop-eligible item, uniform [ASSUMED] (40 seeds: I 9 … VI 24); data/choices.json
|
||
rebuilt offline (only that pool's `maxTier` gone). Golden: coop4-ABYSS-7. Test: `test/match/feedback5-cathy-pool.test.js`.
|
||
|
||
#### 25.21.10 The official behaviour, pinned — 「寻呼模块和电话对干员缪尔赛思用不会给缪尔赛思」 (item 45), 「炎祐能吃到掉血道具的效果」 (item 49), 「两个空弦转职阿戈尔…最后面的空弦不能吃前面的空弦」 (item 50) — no change
|
||
|
||
- 45: 「电话」 is 简易通讯机 (its phone icon; 备注 「获得的干员等阶不高于当前调度中心等级」), like 寻呼模块 「(不高于当前调度中心
|
||
等级)」. 缪尔赛思's only bond is 调和, whose only operator in the pool is her, tier VI: below shop level 6 nothing qualifies
|
||
and the item is used up (as 拟态物质 at the copy cap, §25.13.1); at 6 she comes. Offered a fallback to any tier when
|
||
nothing qualifies (what the reporter expects), **the owner kept the official cap** (the owner's decision of 2026-10-07).
|
||
- 49: PRTS 源石溶剂 备注 「携带后,全场范围内的所有敌人类我方单位也会获得此装备的“每秒受到60真实伤害”效果」 — the 炎佑 is one
|
||
(600 HP in 10 s, no ATK bonus).
|
||
- 50: two operators made 阿戈尔 by 变形同构体 + 阿戈尔重刃 (two 空弦, 空弦 + 哈洛德) devour like any others, through the real
|
||
intents too (+3 layers, ATK, block). Two NORMAL copies of one item merge (the official rule), so two 空弦 need a normal
|
||
and an 进阶 set; and the pair counts once toward the 3 members.
|
||
- Pinned: `test/content/feedback5-cb1-pins.test.js`.
|
||
|
||
### 25.22 GitHub round 19 and the community reports of 2026-10-07, fixed before the release (the owner's decisions of 2026-10-07) — `sim/ai.js updateEnemy` / `enemyAttack`, `ui/gameLogic/phases.js`, `screens/game.js`, `screens/loadout.js`, `match/settle.js`, `match/views.js`, `ui/components.js ResultDialog`, `content/bonds/core.js egirReviveScan`, `content/enemies/helpers.js`, `kits/ops/chess_char_6_01-lemuen.js`
|
||
|
||
The owner held 0.2.0 for the new GitHub reports of 2026-10-06 (#214–#251, triaged in round 19) and then for four more
|
||
community reports relayed on 2026-10-07. Each was reproduced first. Real and fixed: a stunned or frozen enemy blocked by
|
||
contact (#232, §25.22.1), the round-start banner of an eliminated player or a spectator seat (#236, §25.22.2), 干员调配
|
||
without its game data (#173, §25.22.3), the official result box and battle-over sounds of the approved PR #112 (#235,
|
||
§25.22.4), the 5-阿戈尔 batch revive by board position (§25.22.5), an enemy finishing its attack clip after a strike
|
||
(§25.22.6, with the owner's 1 s re-stealth for the 鸭爵 swap's 流泪小子, a deliberate deviation), and 蕾缪安's S3 that
|
||
waits for targets (§25.22.8); from the owner's own playtest, 宴's model no longer kneels while her deployment skill
|
||
runs (§25.22.9). Official as it was (checked, no change): 阿戈尔's devour block count for 水月 and converted members
|
||
(§25.22.10), 拉普兰德's and 赫默's layers from the 整备区 (§25.22.7). The rest of
|
||
round 19 was answered (not a bug, already fixed in 0.2.0, or left for 0.2.1).
|
||
|
||
#### 25.22.1 GitHub #232 「再部署之后的干员无法阻挡破隐被冰冻的隐身怪」 (@ccyl; the repro and the cause by @kukiC): a stunned or frozen enemy is blocked by contact — `sim/ai.js updateEnemy`
|
||
|
||
- **Seen**: a 隐匿 enemy kept frozen beside an operator who falls hides again 3 s after the block ends; the operator
|
||
redeploys on its tile — the enemy inside its block radius, a slot free — and neither blocks nor reveals it until the
|
||
freeze ends. Measured on 0b306ba with kukiC's steps (a block-2 operator, the enemy 0.2 tile from its centre): a tick after
|
||
the redeploy, not blocked and still 隐匿; the freeze removed, blocked and revealed on the next tick. 晕眩 the same, and
|
||
without 隐匿 the same (nothing to reveal). 0.1.4 had it: v0.1.4 gives the same output (the same early return).
|
||
- **Official**: PRTS 异常效果 — STUNNED and FROZEN switch the state machine (no attack, no skill; an enemy cannot move);
|
||
neither holds 不可阻挡 (BLOCK_FREE 「无法阻挡/被阻挡,自动解除阻挡」), which SLEEPING and LEVITATE do. 术语释义 冻结
|
||
「无法移动、攻击及使用技能」 names no block, unlike 沉睡 「无法阻挡/被阻挡」. 作战机制 §碰撞体积与位置识别: an operator deployed
|
||
onto an enemy blocks it, one standing still included — a block needs contact, not movement. [ASSUMED] no page names the
|
||
frozen / stunned case in words; it follows from those definitions.
|
||
- **Cause**: updateEnemy returned on `stunned && !e.hidden` before the contact check (`Battle._checkBlock`), and 冻结 /
|
||
沉睡 / 浮空 set `stun` too (units.js): a held enemy was never checked, so an operator redeployed or deployed beside it, a
|
||
slot freeing up or a push / pull into contact with a stun all waited for the status to end (`e.hidden` there is off the
|
||
field, not 隐匿).
|
||
- **Now**: the held branch runs the same check before it returns (no move, no attack, as before): a stunned or frozen enemy
|
||
in an operator's block radius with a free slot is blocked where it stands, and the block lifts its 隐匿; the 3 s window
|
||
after a block's end is unchanged. `_checkBlock` still refuses 沉睡 / 浮空 / 恐惧 / 不可阻挡, and an enemy held short of
|
||
contact is blocked only once it walks in after the status, at the same point as without it — the rule of a moving or
|
||
standing enemy (a 束缚 one, which is not stunned, was already blocked there).
|
||
- Open, not changed (not #232): the held branch still does not re-check a block the enemy already holds, so a held enemy
|
||
that gains 不可阻挡 through a plain buff keeps its blocker until the stun ends — a `reborn()` 重生 (主角阵营角色 …: the buff
|
||
carries `stun` + `unblockable`) stays blocked through it, as in 0.1.4, though PRTS 特殊机制 重生 gives 无敌 + 无法阻挡 and
|
||
`reborn()`'s comment says its blocker lets go. Re-checking it would move two more golden scenarios (roster-012,
|
||
standin-04).
|
||
- Golden: 52 scenarios — roster-003, -014 … -019, -031, -036, -038, -040, -041, -045 … -047; bond-indomShip-high,
|
||
-kazimierzShip-high, -raidShip-low, -siracusaShip-low, -suntShip-low; boss-boss_3-solo, boss-boss_4-pair,
|
||
boss-boss_7-solo, hidden-boss_8-pair, hidden-boss_9-pair, hidden-boss_10-pair, unite-2; solo-FUNNY-1, solo-NORMAL-2,
|
||
solo-HARD-2, solo-ABYSS-1, coop2-NORMAL-3, coop2-HARD-4, coop3-ABYSS-5, coop2-NORMAL-8-serverrun, coop2-NORMAL-70-diy;
|
||
diy-003, -004, -026, -034, -035, -056, -057, -065, -066, -070, -071, -094, -095, -101, -102, -103. Traced one by one with
|
||
an instrumented copy: in each the first divergence is a stunned or frozen enemy blocked during its status by an operator
|
||
or summon it touched with a free slot, before or inside the first differing snapshot window of the battle scenarios;
|
||
every scenario that moved has one.
|
||
- Tests: `test/sim/feedback5-frozen-reblock.test.js` (9: the four #232 cases and the 晕眩 / 冻结 capacity cases fail on
|
||
0b306ba; the contact-only, 束缚 and refusal guards pass on both). Docs: docs/SIM.md (§1.2 Blocking, `stun`, `freeze`),
|
||
DESIGN §5 (design/engine.md), docs/PLAYING.md.
|
||
|
||
#### 25.22.2 GitHub #236 「被淘汰后每回合开始横幅仍显示「资金已到账」(观战席同理)」 (@2321Robin, with PR #237): the round-start banner reads 观战中 to an eliminated player and a spectator seat — `ui/gameLogic/phases.js phaseBanner`, `screens/game.js`
|
||
|
||
- **Seen** (a real Match with fake battles: three humans and a spectator seat, p_0 out of LP at round 1's settlement):
|
||
at the round-2 start p_0 (funds 0, pending 0) and the spectator seat (no seat, no funds) got 「第 2 回合 · 资金已到账」,
|
||
the same as p_1 (funds 5). The sub had been fixed text since 0.1.0.
|
||
- **Official**: no rule for the banner's text. The money: round income goes only to the players still in.
|
||
`startRound` runs `ps.startRound` (income + pending coins) for `alivePlayers()` only, and `eliminate()` zeroes
|
||
`funds` / `pendingFunds` (server/match/match/phases.js, player/round.js). An eliminated player keeps watching
|
||
(research 09: KEEP_WATCH).
|
||
- **Now**: `phaseBanner(phase, pub, { alive, spectator })`. The match screen passes its `alive` and `spectator`.
|
||
`alive` is false for an eliminated player and for a spectator seat. A spectator seat has no row in m.public, so `pub`
|
||
alone cannot tell. For those viewers ROUND_START's sub is 「观战中」 (en "Spectating", the combat HUD's spectator
|
||
caption). A player still in keeps 「资金已到账」. The title and the other phases do not change. PR #237 was read for the
|
||
idea only: its fourth `alive` argument sits on top of the #189 / #191 stack and Match.js changes, so it was not merged.
|
||
- Golden: unchanged (client text only). Tests: `test/ui/gameLogic.test.js` +1 (a player still in, an eliminated
|
||
player, a spectator seat, the screen's call). It fails on the parent: 「资金已到账」 where 「观战中」 is expected.
|
||
|
||
#### 25.22.3 GitHub #173 「bug:网页版游戏文件未加载」 (@sarilendorf): a 干员调配 tab without its game data says so, and every import is refused — `screens/loadout.js missingGameData / importRefusal / DataMissing`
|
||
|
||
- **Seen**: on the reporter's own server (Node 24) the operators, bonds, maps and enemies did not load. Servers other
|
||
people host worked, and a loadout exported there failed to import locally. The screenshots, as described in the
|
||
thread: 干员调配 empty, the import toast 「导入失败:这份数据在当前版本没有可用的调配,未做任何改动」, the `npm start` log
|
||
with every check passed, an ad blocker showing one block. Reproduced with every /data/*.json request answering 404. All five files of the screen end
|
||
`missing`, the screen counts them as loaded, the roster is empty (「没有符合条件的干员」) and the loadout import gives the
|
||
reporter's toast. Two imports did worse: 干员持有 said 「已导入:全部持有」 and stored [] over the saved list, and
|
||
自选编队 said 「已导入:全部名额为空」 and stored {} over the saved picks. With the files served, the same three imports
|
||
work. 0.1.3 and 0.1.4 behave the same.
|
||
- **Cause**: `useData` (public/js/data.js:489–501) counts a file that never arrived (status `missing`) as settled, so
|
||
the UI can carry on without optional files. In screens/loadout.js `ready` (:399) was then true. The tab drew its empty
|
||
roster, and the import guard `if (!ready)` (:479) let the import run. It exists to stop an import before chess.json
|
||
loads, because such an import would sanitise every entry away. The loadout import kept the loadout but blamed the data
|
||
(:501). `applyOwnershipImport` / `applyDiyImport` (ui/loadoutSync.js:93, :113) stored the empty result. The server sync
|
||
was already safe: the loadout sync sends nothing without chess.json, and the other two send the stored lists.
|
||
- **Official**: no rule involved; the page reads its game data from the server it was opened from (/data/*.json).
|
||
- **Now**: `missingGameData(tab)` names the files a tab cannot work without: chess.json, plus backups.json for 自选编队.
|
||
When one is `missing`, the tab shows `DataMissing` in place of the roster: 「游戏数据没有载入」, the file paths (e.g.
|
||
/data/chess.json), that the saved settings are unaffected, and what to try (reload; then the ad blocker and the
|
||
network). `importRefusal(kind, ready)` is the one guard of every import. It refuses while the files load (as before) and
|
||
when the data is missing (「导入失败:游戏数据没有载入,未做任何改动。请刷新页面;仍不行时,请检查广告拦截插件和网络」),
|
||
before anything is parsed or applied. Three new UI strings, with English.
|
||
- [ASSUMED]: the cause on the reporter's machine is still unknown: the ad blocker, a proxy or security software, or a
|
||
different address. The new message and the console line `[data] /data/<file> unavailable (<reason>)` are what to ask for.
|
||
- Golden: unchanged (client only). Tests: `test/ui/feedback5-loadout-data-missing.test.js` (4, all fail on the parent:
|
||
the tab's files, the refusals, the screen's guard order, the message in Chinese and English); loadout, loadout-stats,
|
||
module-trait, moduleIcons, diy-ui and standin-ui tests pass unchanged.
|
||
|
||
#### 25.22.4 「提问:联防结算播报没了」 (GitHub #235; PR #112 by @Convey123, approved, never merged): the official 「作战结束」 box and the three BATTLEOVER sounds at settlement — `match/settle.js`, `match/views.js`, `ui/gameLogic/phases.js`, `ui/components.js ResultDialog`, `screens/game.js`
|
||
|
||
- **Seen**: 0.1.4 and 0.2.0 have no result box and never play the battle-over sounds. A co-op 联防 round run to SETTLE
|
||
through the match harness: the SETTLE m.public carries nothing about the 联防; `public/js` names none of the three
|
||
sounds, though `data/assets.json` `audio.sfx.ui` lists all three and they are on disk (so the full zip, which packs
|
||
every file the manifest lists, already carries them). PR #112 targeted 0.1.4's layout; the owner approved it on
|
||
2026-10-05 once the remake's own 「联防成功 / 联防失败:还有 N 只突破防线」 line went (the author removed it, then made
|
||
「全员无伤!」 true-only).
|
||
- **Official**: research 09 §3.1 "Round result dialog": 「作战结束」 + 「全员无伤!」, or 「生命值减少」 and the LP lost; the
|
||
client's audio data names `ON_ACT1AUTOCHESS_BATTLEOVER_REDUCE / _NOREDUCE / _NORMAL`, not when each plays. No EN client
|
||
text for the three lines in `data/i18n/en.json`: plain translations (Battle over — the existing msgid —, All unharmed!,
|
||
LP reduced by {n}).
|
||
- **Now** (ported by hand onto the 0.2.0 modules, every line reviewed): `settle()` keeps `uniteResultView` — `through`
|
||
(the leakers' enemies that still got through), helpers, leakers and `losses` (every alive player's own charge, the very
|
||
`loss` deducted) — which the SETTLE m.public carries as `uniteResult` (cleared at the round start; design/network.md
|
||
§8.2). At SETTLE (the moment is [ASSUMED] — the sources do not time the dialog, and a leaker's number exists only
|
||
after the 联防) the screen pops `ResultDialog` for 2.8 s (inside SETTLE's 3 s; click-through, under the phase banner):
|
||
「作战结束」 and the viewer's own line — after a 联防 from `losses`: charged → 「生命值减少 −N」 (red); nothing got through
|
||
→ 「全员无伤!」 (mint, true for everyone); the 联防 leaked but the viewer paid nothing (a helper, a spared leaker) → the
|
||
title alone (orange); without a 联防, the own battle's `min(cap, leaks)` as kept while it ran (`roundLossRef`, the
|
||
live LP's own inputs). Sound: Reduce when charged, NoReduce when a 联防 ran and the viewer paid 0, Normal otherwise
|
||
[ASSUMED mapping, PR #112's; the owner called the three right]. No ticker line for the outcome.
|
||
- **Who sees it**: solo — every normal round (no 联防 there) [ASSUMED: the same dialog]; bots — nothing to show, listed
|
||
in `losses`; a spectator seat or a player eliminated earlier — no box and no sound in any round, where PR #112's last
|
||
commit gave them the title alone after a 联防 although its own rule gave them nothing in an ordinary round (and no sound
|
||
either) [ASSUMED]; 最终攻势 / 隐秘核心 — no SETTLE phase (`_finishFinal` → the result screen or the Hidden Core round)
|
||
and the merged team LP has no per-player loss, so no box [ASSUMED]; a reconnect landing on SETTLE — the 联防 box (the
|
||
server's figure) without sound, nothing in an ordinary round.
|
||
- Left out of the PR: ResultDialog's unused `icon` prop and gold / ice tones. Golden: unchanged (283 scenarios). Tests:
|
||
`test/ui/gameLogic.test.js` (5 new: sounds, loss, words in zh and en, 联防 cases, no-联防 box; the file does not load on
|
||
the parent), `test/match/playtest6-matchflow.test.js` #235 (2; the 联防 one fails on the parent: losses = the LP
|
||
settled, no result ticker, gone in the next phase), SP_E2E `test/ui/resultbox.e2e.test.js` (3, mock variants
|
||
`unite[,through][,helper|,dead]`). Docs: PLAYING.md §1 / §5, design/network.md, design/client.md, design/match.md.
|
||
|
||
#### 25.22.5 「阿戈尔盟约的二阶复活逻辑应该有些bug」 (a community report the owner relayed on 2026-10-07, two screenshots not yet seen): the 5-阿戈尔 revives of the battle-start devour's knock-outs go by board position once the devour is over — `content/bonds/core.js installEgir` (`egirReviveScan`, `egirStart`)
|
||
|
||
- **Seen**: the player's model of the official game: 「原作里是第一步给所有鱼加盟约的血量,第二步是开始一个个大鱼吃小鱼,
|
||
第三步是检测左下到右上哪些鱼睡着了给他复活」 — a fish that survives the devour on the bond's HP takes no revive; in the
|
||
remake 「蓝蒂的位置肯定是比水月要更优先复活的」 and 「中间位的小鱼(蓝蒂、小鲨)已经超5000血量了还是被吞死了」; in an
|
||
official game they recorded an elite 深巡 (under 3000 HP in prep) stood its devour, 「所以肯定是部署后先经过盟约加血才
|
||
活了下来」. Reproduced on 0255afd (real chess, scratchpad w5-r19d-notes/repro.mjs): (a) one row 浊心斯卡蒂 → 乌尔比安 →
|
||
斯卡蒂 → 幽灵鲨 → 水月 → 深巡, all elite, 60 layers: 斯卡蒂 at 7513 HP and 幽灵鲨 at 4965 each take two marks (浊心斯卡蒂's
|
||
and 乌尔比安's, 2 × 4751 and 2 × 4635); 斯卡蒂 is saved only by her module DRE-Y. (b) 乌尔比安 → elite 深巡 (2904 HP, DEF
|
||
655), one mark of 4345: knocked out at 0 and 14 layers (3920 / 4327 HP), standing at 15 (4356 → 11 HP). (c) Two rows,
|
||
乌尔比安 → 水月 → 海霓 on the top row and 浊心斯卡蒂 → 幽灵鲨 → 深巡 on the bottom one: four knocked out at t = 0 in the
|
||
order 水月, 海霓, 幽灵鲨, 深巡 — the first three revived, 深巡 down.
|
||
- **Official**: PRTS 卫戍协议:盟约 下半/PRTS盟约记录, 阿戈尔 (fetched 2026-10-07, unchanged since the 2026-10-03 copy): the
|
||
3-tier gives the members 生命值 +(35+1×层数)% (bonds.json `base_max_hp` 0.35, `max_hp_per_stack` 0.01; 直接乘算, the
|
||
page's 「盟约效果…提供的属性加成均为直接乘算」) and the devour; the 5-tier the revives (`max_free_respawn_cnt` 3). The devour
|
||
is 「5000点物理流失」 (the in-game text says 物理伤害; PRTS corrects it), one per mark (「每个标记令目标受到一次5000点物理流失」),
|
||
and the marks chain (「以及被自身吞噬的【阿戈尔】干员身前一格干员」), so a member is marked by every 阿戈尔 behind it in its
|
||
chain. PRTS 作战机制 §伤判效果与生命流失: a 物理流失 「会受到目标当前防御力…影响而相应衰减」 and skips every other step
|
||
(no 脆弱 / 庇护, no dodge, block, shield or barrier). No source gives the moment of the HP bonus or the order of the
|
||
revives; PRTS 卫戍协议/帮助: 「满足再部署条件时…自动部署」.
|
||
- **Steps 1 and 2 hold (not changed)**: the bond's HP is a match-long buff put on the members when the battle is built, so
|
||
each is deployed with it at full HP and the devour finds it — (b) is the player's official 深巡 exactly: it stands from 15
|
||
layers on. The prep card's 「开战时」 生命上限 comes from a started preview battle (match/intents.js `_unitStatsOf`), so it
|
||
includes the bond's HP as the battle does. The devours resolve one by one in marking order, one 5000 物理流失 less DEF
|
||
per mark, as PRTS says; a fish over 5000 HP stands one mark and falls to a second — that is (a)'s 「中间位的小鱼」: in a
|
||
chain each 阿戈尔 behind it marks it. So the HP was real; what killed 蓝蒂 and 小鲨 was the second mark.
|
||
- **Cause (step 3)**: §24.3's rule gave the 3 slots to the first 3 members knocked out, at the knock-out, so inside the
|
||
devour the knock-out order decided — the food the first marks reach (often the far end of a chain, or the row whose big
|
||
fish marks first) took the slots while a member further left fell to a later mark and stayed down.
|
||
- **Now**: the members the battle-start devour knocks out wait until every player's devour pass on the field is over (the
|
||
window `egirStart`: the passes counted at install, a depth while one resolves, the 5-tier players' batches run after the
|
||
last pass); then those still down are revived by board position (`egirReviveScan`) while slots last; the rest stay down,
|
||
their first knock-out spent. Unchanged from §24.3: a member takes one slot at most, on its first knock-out; a member never
|
||
knocked out takes none (survivors = uneaten + up to 3 eaten); a knock-out later in the fight takes a slot left at once,
|
||
in time order; a save by its own kit / item / band is no knock-out; a member entering 联防 down is not knocked out; each
|
||
battle counts its own; a mirrored boss player scans its own board. (c) now: 幽灵鲨, 水月 and 深巡 revive (left column
|
||
first, bottom first), 海霓 stays down. A member a teammate's devour knocks out on a shared field waits for its owner's
|
||
scan too (before: back at once, so it was standing — and marking — in its owner's pass).
|
||
- **Changed from §24.3**: only which battle-start knock-outs take the slots and when they come back (after the last devour
|
||
pass instead of inside it). With three or fewer knocked out at t = 0 the same members revive; the order of their
|
||
redeploys (the later deployed is attacked first) is now the scan order.
|
||
- [ASSUMED]: (1) 「左下到右上」 on the player's own board as seen in prep — row 0 at the bottom of the screen
|
||
(render/projection.js), col 0 at the left, a mirrored player from its own left as `egirOrder` — read as the columns from
|
||
the left, bottom first inside a column, like the act-2 positional orders (the deployment, the devour order). The other
|
||
reading, the rows from the bottom with left first inside a row (act 1's deployment order), is the one-line comparator in
|
||
the comment above `egirReviveScan`; `test/content/bonds_core.test.js` '阿戈尔 5 (community report, 2026-10-07) step 3'
|
||
pins the choice — under the other reading its F1 stays down instead of F4. The screenshots should settle it. (2) Inside
|
||
the window a devour knock-out is otherwise any knock-out: 被击倒 triggers fire and 不屈 rolls (before, the 阿戈尔 revive
|
||
answered first and 不屈 never rolled); a member 不屈 redeploys is awake at the scan and takes no slot (「哪些鱼睡着了」).
|
||
(3) Each player's devour stays its own pass (§24.4 [ASSUMED] (2)).
|
||
- Golden: unchanged — traced with an instrumented copy: the corpus's only 5-阿戈尔 battle (bond-egirShip-high, 999 layers)
|
||
has no devour knock-out, and no 5-阿戈尔 member is knocked out later in any scenario.
|
||
- Tests: `test/content/bonds_core.test.js` +3 — step 1 / 2 (the elite 深巡 at 14 / 15 layers, the HP before the devour; an
|
||
elite 幽灵鲨 at 5013.54 HP stands one mark and falls to a second in a chain; passes on the parent too: those steps held),
|
||
step 3 (four food knocked out in the order F1, F2, F4, F3: all marks first, then F3, F2, F1 revive and F4 stays down —
|
||
normal, 联防 with a marker entering down, the mirrored boss player; the parent revives F1, F2, F4 inside the pass), later
|
||
knock-outs / uneaten members / 不屈 (fail on the parent); three titles of the older 阿戈尔 tests reworded.
|
||
`test/content/feedback4-egir-unite.test.js` +1 (a teammate's mark knocks out p2's 幽灵鲨: revived after p2's own pass,
|
||
fails on the parent). Docs: research 02 §3.6 and its JSON spec (data/bonds.json `egirShip.spec` regenerated with
|
||
`build-data --offline`; only `tiers[0]` / `tiers[2]` / `algorithm[3]` / `assumed[0]` changed — the stale assumption
|
||
「5000 physical 流失 ignores DEF and shields」, wrong since 0.1.1, gave way to the scan reading), DESIGN §5's `death` row
|
||
(design/engine.md), docs/SIM.md (`death` hook), the core.js comments; §24.3's title points here.
|
||
|
||
#### 25.22.6 「ai的鸭爵分队真的好阴…哭狗瞬间隐匿没有后摇马上就到下一格干员的脸上秒抬手秒晕」 (community report of 2026-10-07) and GitHub #214 「鸭爵技能生成的泪眼汪汪没有反隐直接一路顺畅走进蓝门」 (@FrogThai; PR #243 by @TsangAsuna declined): an enemy finishes its attack clip after its block ends — `sim/ai.js enemyAttack`, `sim/battle/displacement.js displace`
|
||
|
||
- **Seen**: 泪眼汪汪 / 哭狗 / 隐匿狗 is 流泪小子 (`enemy_2034_sythef_2`, 「唯唯诺诺的佩洛」 — no enemy is named 泪眼汪汪), the
|
||
only 隐匿 and stunning enemy of the four the 鸭爵 strategy swaps in. Measured on 0255afd with a lane of four blockers that
|
||
never attack (route 0, cols 8 → 5): blocked at 3.233 s, swing 3.267, strike 4.033 (the wall stunned 3.5 s, the block
|
||
released, 隐匿 at once) and walking on the very next tick; the next wall reached at 6.533 (one tile at 0.4 tiles/s) and
|
||
struck 0.767 s after the contact, its cooldown ready; a wall whose stun ended took it over again while it was still
|
||
inside that wall's block radius. 8 stuns, 19.8 s 隐匿 / 9.0 s revealed, leaked at 28.9 s.
|
||
- **Official**: every number the report questions is the official one. enemy_database `enemy_2034_sythef_2` level 0:
|
||
moveSpeed 0.8 (× the level's moveMultiplier 0.5: 0.4 tiles/s), baseAttackTime 2.0, MELEE, `Combat.attack@stun` 3.5 —
|
||
PRTS 卫戍协议:盟约 下半/PRTS盟约记录 鸭爵 备注: a 「特殊版本,相较于原版更弱」 (4500 HP, 3.5 s stun) that keeps its 隐匿 (the
|
||
handbook line is unchanged). PRTS 流泪小子 (same prefab): 「隐匿(解除阻挡0秒后恢复),近战攻击使目标晕眩」 — it attacks only
|
||
its blocker. Its Spine Attack clip: 1.567 s, OnAttack at 0.767 s (data/assets.json). gamedata_const `ba.stun`
|
||
「无法移动、阻挡、攻击及使用技能」, PRTS 异常效果 STUNNED 「无法攻击、释放技能、阻挡敌人类单位」: a stunned operator lets it go —
|
||
the hypothesis that it should keep blocking is wrong. The attack cooldown is the unit's and runs on the walk, so a new
|
||
blocker sees the swing at once and the strike 0.767 s later (official too). PRTS 状态机: an enemy's ATTACK state
|
||
「每帧检查异常状态…攻击结束后回退到MOVE状态」 and COMBAT 「逻辑同ATTACK」 — only a character's COMBAT 「检测到不存在阻挡对象时强行
|
||
切回IDLE状态」: an enemy finishes its attack when its blocker goes. The band: 「你和队友遭遇的部分敌人可能会替换为…」 — a bot
|
||
teammate's 鸭爵 swaps into a human's battles, the Final Assault and the Hidden Core too, on the replaced enemy's route
|
||
(`content/bands/meta.js duckReplace`; #214's 「上路」 is that route).
|
||
- **Cause**: enemyAttack set the post-strike stand only for an unblocked ranged enemy (`!e.blockedBy && radius > 0`), so
|
||
a melee enemy released by its own strike — or by its blocker's knock-out — walked on the same tick: the 「没有后摇」.
|
||
- **Now**: every enemy stands for the rest of its attack clip after a strike (`attackStand(e).rest`; ATTACK_PAUSE with no
|
||
clip known); a blocked enemy never walks, so the stand shows only when its block ends meanwhile — its blocker stunned
|
||
or knocked out by that strike, or gone (retreat, substitution). A stun / freeze / sleep / 浮空, leaving the field and,
|
||
new, a displacement (失衡: the UNBALANCE state replaces ATTACK) end it. 流泪小子 now stands 0.8 s after each strike —
|
||
隐匿, since its restore is 0 s — and a stunned blocker often takes it over again before it leaves its radius. The same
|
||
lane: 13 stuns, 29.1 s 隐匿 / 12.8 s revealed, leaked at 42.0 s; four blockers that hit back (550 ATK) now knock it out
|
||
(it leaked with 2 % HP before); the real R6 wave on 战场#01 with one swapped 流泪小子 and 8 elite operators (8 seeds):
|
||
leaked 8 / 8 before and after, 47 → 58 % HP left.
|
||
- [ASSUMED]: the stand lasts the clip's rest, as the #58 stand (no source gives a length); a melee swing whose target
|
||
goes before the strike is still cut (unchanged, §22.14).
|
||
- PR #243 (declined): it removed the copy's 隐匿 — the data and PRTS keep it — and, on a stale base, reverted the
|
||
high-ground rule (only elite 歌蕾蒂娅 with HOK-Y) and rewrote unrelated skills (宴 S2, 野鬃 S1, 锡人 / 吟游者 heals).
|
||
- Golden: 216 scenarios — roster 41 of 49 (all but -003, -005, -009, -018, -019, -025, -035, -049), bonds 21
|
||
(deputShip-low, emptyShip-low / -high, indomShip-low / -high, investShip-low, kazimierzShip-low / -high,
|
||
kjeragShip-high, lateranoShip-high, miraShip-high, raidShip-low, sargonShip-high, siracusaShip-low, soloShip-low /
|
||
-high, suntShip-low / -high, swiftShip-high, visiShip-low, yanShip-low), fields 13 (all but boss-boss_1-solo,
|
||
boss-boss_2-pair / -solo, boss-boss_6-solo, boss-boss_7-pair / -solo, hidden-boss_8-solo, hidden-boss_10-solo,
|
||
unite-1), matches 17 (all but solo-HARD-9-boosted), standins 10 of 10, diy 114 of 138 (all but -011, -012, -018,
|
||
-020, -025, -027, -029, -031, -033, -047, -053, -077, -080 … -082, -086 … -088, -091 … -093, -098, -108, -123). Traced
|
||
in lockstep against a copy of the parent: in each of the 199 battle scenarios the first differing tick is an enemy
|
||
standing out its clip after a strike where the parent walked on; every moved match has such stands from an earlier or
|
||
the same round. The displacement rule alone moves one roster scenario.
|
||
- Tests: `test/sim/feedback5-attack-clip-rest.test.js` (5; the four behaviour tests fail on 0255afd, the data pin passes
|
||
on both). Docs: docs/SIM.md (enemy attacks), DESIGN §5 (design/engine.md), docs/DATA.md (`attackAnim`).
|
||
- **Deliberate deviation — the owner's decision of 2026-10-07** (「鸭爵策略产生的泪眼汪汪我想了一下,要不等待个1秒这样再重新隐匿,
|
||
或者提供点别的降低难度的方案」): the 鸭爵 swap's copies (spawn tag `'duck'`, `content/bands/meta.js duckReplace` — in
|
||
practice 流泪小子, the only one of the four with 隐匿) get their 隐匿 back no sooner than 1 s after a block ends
|
||
(`content/enemies/helpers.js DUCK_STEALTH_RESTORE`, `archetypes.js stealth`; officially 0 s). The same enemy anywhere
|
||
else — the bounty card's 流泪小子 (`enemy_2034_sythef`), any other spawn — keeps 0 s; a copy leaked into 联防 keeps its
|
||
tag and the 1 s. After each strike it is now revealed through its 0.8 s stand and 0.2 s of walking.
|
||
- Measured, 8 seeds each (W: 3 elite melee operators in a lane + an elite sniper against the R6 wave's ground enemies with
|
||
one swapped 流泪小子; B: 8 elite operators on 战场#01 against the whole R6 wave with one swap) — leaked, HP left, revealed
|
||
s per battle: before 0.2.0's fixes W 5/8, 42 %, 2.3 / B 8/8, 47 %, 3.2; after the clip fix W 5/8, 31 %, 2.6 / B 8/8,
|
||
58 %, 2.5; with the 1 s W 4/8, 31 %, 4.0 / B 8/8, 56 %, 5.5. Other options, measured on the fixed engine and not built:
|
||
2 s — W 4/8, 31 %, 5.4 / B 8/8, 46 %, 8.5; 3 s (the general 隐匿 rule of PRTS 作战机制) — W 4/8, 31 %, 6.4 / B 8/8,
|
||
39 %, 11.5; a 1.5 s stun on the copy (below its 2 s interval: its blocker recovers while it still stands in its block
|
||
radius and takes it over again) — W 4/8, 2 %, 4.0 / B 4/8, 6 %, 5.5; a 1 s stun — knocked out in all 16; the 1 s delay
|
||
with a 2 s stun — W 4/8, 21 %, 5.1 / B 5/8, 26 %, 8.1. Worse, not offered: half speed while 隐匿 (B 8/8, 76 % — it
|
||
stays hidden longer), a stunned operator that keeps blocking it (pins that operator for the whole battle).
|
||
- Golden (this rule alone): matches solo-HARD-2 — its bot holds 鸭爵; the swapped 流泪小子 of round 13 is free and revealed
|
||
for 49 ticks in its 1 s windows (the round-12 one is never released by a block), so the match parts at round 13 and
|
||
ends in a victory instead of a defeat; the other 282 scenarios are unchanged. Tests:
|
||
`test/content/feedback5-duck-restealth.test.js` (3; the swap's 1 s and the band path fail before it, the 0 s guard
|
||
for the same enemy elsewhere passes on both).
|
||
|
||
#### 25.22.7 「小拉和赫默有概率在备战区叠不上叙拉古和远见」 (community report, relayed by the owner on 2026-10-07): not a bug — 拉普兰德 stacks from the 整备区 when 【叙拉古】 is active, 赫默's trait works only deployed (official data) — no code change; `docs/PLAYING.md` §6
|
||
|
||
- **Seen**: 「有的时候在备战区的干员不能100%叠层…小拉和赫默有概率在备战区叠不上叙拉古和远见」. 备战区 is the players' word
|
||
for the 整备区 (community guides: 「远见奇迹干员不需要了就放备战区」). Reproduced through the match paths: a matrix of 26
|
||
cases (the 整备区, the board, the 临时整备区; bought before / after the refresh, two copies, an elite merged this round, a
|
||
full hand, a 机变 round, a pending reward, the shop frozen, a free refresh, a reconnect, a bot), and 115 whole matches
|
||
(60 solo, 40 co-op, 15 co-op with client-run combat; a random human and the bots) checked against an oracle written
|
||
from the official text: 11 951 refreshes and 3 640 round starts, no difference. Every case without layers is one of
|
||
four rules, nothing random: (1) 【叙拉古】 is inactive — it counts different 叙拉古 deployed, and 拉普兰德 on the bench is
|
||
not one of the three (普罗旺斯 + 德克萨斯 deployed, her in the 整备区: 2/3); (2) her trait fires on the first manual
|
||
refresh she sees each round, so a refresh made while 叙拉古 is inactive spends it — deploying the third 叙拉古 and
|
||
refreshing again adds nothing until the next round (in the random matches 440 of the 675 first refreshes a bench
|
||
拉普兰德 saw were of this kind, the other 235 stacked); (3) in the 临时整备区 she neither fires nor counts, and fires on
|
||
her first refresh once a free slot pulls her into the 整备区; (4) 赫默 in the 整备区 never fires, 远见 active or not
|
||
(204 such round starts).
|
||
- **Official**: garrison_123 「<刷新时>若为本回合首次主动刷新,使已激活的【叙拉古】层数+4,此干员在整备区时也有效」 (elite +8, no
|
||
condition key); 叙拉古 activeCondition BOARD (「在场」). garrison_80 「<进入休整期时>使自身已激活的盟约层数+2」 (elite +4) has
|
||
no such clause, and its blackboard carries conditionkey `character_target_inboard`: deployed only. In the act2autochess
|
||
garrison table every 进入休整期时 / 休整期结束时 / 刷新时 trait that works in the 整备区 says so and has no condition key —
|
||
拉普兰德 123, 调香师 81, 波登可 102, 琳琅诗怀雅 98 (「若已激活【炎】/【投资人】此特质在整备区也有效」); every other one is
|
||
`character_target_inboard`, or a row / tile-in-front condition only a deployed operator meets. 远见's
|
||
「整备区的【远见】干员也可用于激活盟约」 counts bench members for the bond; it moves no trait to the bench. The in-game tips
|
||
name the overflow 「临时整备区」 apart from the 整备区 (「处于临时整备区的调度资源,在进入下一回合后会自动销毁」).
|
||
- **Now**: unchanged. Prep traits run for deployed operators and, unless `character_target_inboard`, for the 10 整备区
|
||
slots (`effectsMeta.js _garrisons`), never for the 临时整备区 (§21.1, like the 远见 / 奇迹 / 投资人 count). PLAYING.md §6
|
||
now says where a 特质 works, that 「使已激活的…」 needs the bond active, and what 拉普兰德's refresh needs.
|
||
- [ASSUMED] (unchanged since §21.1): a refresh made while 叙拉古 is inactive spends her trait for the round (the literal
|
||
「若为本回合首次主动刷新」, counted per copy); the 临时整备区 is not the 整备区; a free refresh is a manual refresh. Open for
|
||
the owner: fire on her first refresh with 叙拉古 active instead — no source either way.
|
||
- Golden: unchanged (no code change). Tests: `test/match/feedback5-bench-traits.test.js` (6 pins: the official data rule;
|
||
+4 / +8 in the 整备区 with the hand full, the shop frozen, a free refresh, a reward pending, a reconnect, in a 机变 round,
|
||
for a bot; the inactive bond and the spent refresh; the 临时整备区; a copy bought after the first refresh and 普罗旺斯's
|
||
free refresh; 赫默 deployed vs in the 整备区).
|
||
|
||
#### 25.22.8 Community report 「蕾缪安3技能范围里没人好像会自动结束」 (relayed by the owner): 蕾缪安's S3 waits with its bullets while nothing is in her range — `kits/ops/chess_char_6_01-lemuen.js`, `render/fx/locks.js`
|
||
|
||
- **Seen** (a script on the parent 0255afd: S3 cast with 5 bullets, the locked enemy killed by someone else after 2
|
||
locks, another enemy alive outside her range): the skill ended at the next lock tick
|
||
(1.00 s, `skillEnd` reason `ammo`), 3 bullets thrown away, 2 shells; an enemy that came into her range 3 s later found
|
||
it over. A locked walker leaving her range ended it the same way (4 locks, 1 bullet thrown away). In golden the elite
|
||
蕾缪安 of roster-018 ended three of her five casts early (2 / 6, 5 / 9 and 6 / 9 bullets left).
|
||
- **Official**: the skill text 「每0.5秒消耗1发子弹依次锁定敌人……攻击装有5发弹药,打完后结束(可随时停止技能)」: an ammo
|
||
skill ends when its bullets are spent or when the player stops it. PRTS 卫戍协议/帮助 §作战阶段 技能操作: 「可执行的技能
|
||
操作包括开启/关闭技能,通常不会自动关闭技能」 — the only automatic close is 玛露希尔's 召唤使魔; 蕾缪安's S3 is on the
|
||
basic strategy. The client (charpack char_4193_lemuen, battle/buff_template_data.json): the S3 mode's lock is an attack
|
||
that needs a target (`_minTargetNum` 1, `_allowNoTarget` 0, cooldown `aim_interval`); the skill buff `lemuen_s_3`
|
||
switches to the S3_End mode (the bombardment) on `ON_BUFF_FINISH` only, and nothing ends it for want of a target. PRTS
|
||
S3 note: a mark follows its target and stays where the target left.
|
||
- **Cause**: the kit's lock tick ended the skill when `pickLock` found nobody and anyone had been locked —
|
||
`if (!e) { if (m.lemLocks.length) skill.end('ammo'); return; }` (chess_char_6_01-lemuen.js:169 on the parent), there
|
||
since the initial import with no decision behind it.
|
||
- **Now**: with nothing to lock the skill waits, bullets and locks kept — the marks follow their enemies (out of her range
|
||
too) or stay where they left — with its lock ready: the next enemy that comes into her range (or is 通缉) is locked on
|
||
the next tick, then every `aim_interval` s. The skill ends when the bullets are spent and the shells fall on every mark
|
||
in lock order, as before. While it waits she gains no SP (a running ammo skill holds it, as before); knocked out or
|
||
withdrawn, no bombardment (unchanged); a battle that ends meanwhile ends without shells (nothing left to hit). The S3
|
||
`lock` fx carry `hold`: render/fx/locks.js keeps such a reticle while the shooter's view has the skill bit (UF.SKILL)
|
||
and counts its LOCK_T (5 game s) from the skill's end — without it the reticles faded 5 s into a wait. S2's aim lock
|
||
(no `hold`) keeps its timeout.
|
||
- Unchanged and noted: the client lock's 0.1 s pre-delay is not modelled (the lock lands on its tick, as before).
|
||
- Seen on the way, not changed (S2, not this report): 归乡邀约 spends a bullet on every normal attack (5 of its 6 gone in
|
||
8 s of attacks on an enemy that is not 通缉), while PRTS's S2 note says only the aimed snipe at a 通缉 target spends one
|
||
(「若目标为被通缉状态,则攻击改为消耗1发弹药的瞄准狙击,否则不消耗弹药」) — left to the owner: fixed, S2 would hold its
|
||
buff until 通缉 enemies come, a large change.
|
||
- Golden: 3 scenarios — traced on both trees with an instrumented copy (SkillRuntime start / end logged, the round's
|
||
fields and the carried SP); in each the first divergence is an S3 the parent ended with bullets left and nothing in her
|
||
range:
|
||
- roster-018: the elite 蕾缪安's first S3 (7.63 s) ended at 9.63 s with 2 of 6 bullets left; now the 6th goes at
|
||
12.00 s (first differing snapshot window 0–10 s).
|
||
- boss-boss_3-pair: her second S3 (27.8 s) ended at 30.3 s with 4 of 9 left; now all 9 by 34.43 s (window 30–40 s); the
|
||
boss now falls at 199.53 s (before: `forced` at the 200 s cap with 145080 HP left).
|
||
- coop2-NORMAL-14-standins: ai_0's 蕾缪安 (her own kit) — in round 11's battle her S3 ended at 17.2 s (6 of 8 left) and
|
||
77.97 s (7 of 9); now all bullets are spent and the third cast does not come, so she enters the round's 联防 with
|
||
25.96 SP instead of 10.27, casts S3 there and kills one more of h_0's leaked enemies: h_0 loses 1 LP less (rounds
|
||
11–12 LP 18 → 19, 8 → 9; lpLost 30 → 29; ai_0 kills +1, dmgDealt +288).
|
||
- bonds, standins and diy unchanged.
|
||
- Tests: `test/sim/feedback5-lemuen-s3-wait.test.js` (3: the killed target and the walker who leaves fail on the parent —
|
||
the skill ended —; the battle that ends while she waits passes on both), `test/render/fxproj.test.js` +1 (a held lock
|
||
stays while the shooter's skill bit is on, then LOCK_T after; an unheld one times out — fails on the parent's
|
||
renderer); `test/content/kits_t6.test.js`, `kits_alt_t6.test.js`, `test/sim/feedback3-ammo-bar.test.js` pass unchanged.
|
||
|
||
#### 25.22.9 宴 knelt through the opening seconds of every battle (the owner's playtest of 2026-10-07: 「干员宴的模型开局时是跪地的状态,不是正常的站立」) — `tools/assets/spine.mjs PREFAB_SPINE_ROLES`, `data/assets.json`
|
||
|
||
- **Seen**: 宴 on the board knelt as the battle opened and stood up a few seconds later. **Cause**: her skeleton has one
|
||
unnumbered skill set (Skill_Start / Skill_Loop / Skill_End) — she sits down and rests, S1 分神's pose (停止攻击,防御力
|
||
提升,每秒恢复生命); tools/assets/anim-roles.mjs resolves clips by name, so both skill indices got it, and S2 — the 卫戍
|
||
default 落地斩·破门, on for its duration from every deployment — played the rest pose. **Now**: PREFAB_SPINE_ROLES also
|
||
fixes operator models (by character id, front and back): 宴's index 1 plays her ordinary clips (`via: 'attack'`, which
|
||
render/spine.js treats as no skill clip), index 0 keeps the rest; `fetch-assets --offline` rebuilt data/assets.json
|
||
(only her entries changed). [ASSUMED]: by the clips' pose and S1's text (the prefab's skill table was not read).
|
||
- Open: 29 more operators in the mode share one unnumbered skill set across their skills (e.g. 德克萨斯, 雷蛇, 拉普兰德,
|
||
银灰, 煌); for most it is an attack-like skill pose, so a skill that officially has none shows it while it runs — to be
|
||
checked against the prefabs' skill tables for 0.2.1.
|
||
- Tests: `test/feedback5-utage-anims.test.js` (the resolver alone kneels in S2; the fix; the shipped manifest, both models).
|
||
Checked in a real match (the fast server's starter kit on round 2): both copies stand at 0.7 s with 落地斩·破门 on.
|
||
|
||
#### 25.22.10 「阿戈尔盟约的干员水月在互吃叠buff时阻挡数没有叠」 (a community report the owner relayed on 2026-10-07, with 「其他干员若转职阿戈尔有没有类似问题(尤其是伏击客分支这种默认不阻挡的)」): not reproduced — no change
|
||
|
||
- **Official**: PRTS 卫戍协议:盟约 下半/PRTS盟约记录, 阿戈尔 ※: the marker 「获得所有标记单位的基础攻击力(最终加算)和阻挡数」 and
|
||
never marks 「“自身”/“自身已付与过标记的单位”/“已将标记付与自身的单位”」.
|
||
- **Checked** (real chess): 水月 (伏击客, base block 0) eating a 幽灵鲨 has block 2 and holds two enemies at once; elite 水月
|
||
eating a 深巡 3 and three; through a chain 水月 → 幽灵鲨 → 斯卡蒂 3 (the prep card's 「开战时」 阻挡数 reads 3 too — the
|
||
match's start-of-battle preview runs the devour); a member revived by the 5-tier keeps its gains. Face to face, the member
|
||
further left / up marks first and the other marks nothing back — no block for it (PRTS's rule above; likely what the
|
||
player saw). 变形同构体 + 阿戈尔重刃 make any class a member with the same gains; 水月 is the pool's only 伏击客, and the
|
||
official no-block states — 解放者 with the skill off, 旗手 during the skill, a 傀儡师's 替身 — still block nothing.
|
||
- Tests: `test/content/feedback5-egir-block.test.js` (2; both pass on the parent).
|
||
|
||
### 25.23 The Japanese, Korean and Traditional Chinese interfaces (UI-JA, UI-KO, UI-TW; the owner's decision of 2026-10-07) — `public/i18n/ja.json`, `ko.json`, `zh-TW.json`, `shared/packs.js`, `shared/i18nPacks.js`, `shared/i18n.js`, `public/js/ui/lang.js machineTranslationNote`, `public/js/ui/settings.js`, `tools/build-i18n.mjs` (`untranslated: 'native'`, `nativeCharset`), `data/i18n/*.json`, `public/css/theme.css` (`--cjk-faces`, `:lang()`), `public/js/screens/lobby.js`, docs/I18N.md, docs/PACKS.md
|
||
|
||
- **Seen**: the owner tested 0.2.0 — 「新版本日语韩语繁体中文实测切换没有生效,只有中文英文生效」. The switch worked (the game texts
|
||
changed: 能天使 → エクシア / 엑시아, 陈 → 陳), but §25.20 had shipped the three packs with a `_meta` and no interface
|
||
strings, so ja / ko showed the English interface and zh-TW the Simplified Chinese one — every title, button and menu.
|
||
**Decision** (the owner's, 2026-10-07): complete all three interfaces for 0.2.0 — zh-TW converted from the Simplified
|
||
Chinese (Taiwan usage), ja / ko translated with the official JP / KR game terms, marked as machine translation,
|
||
corrections from the community welcome.
|
||
- **Now**: every msgid of `en.json` in all three packs (`node tools/i18n.mjs check ja ko zh-TW --strict`: 1028 used, 1028
|
||
translated, 0 errors), each `complete: true`.
|
||
- zh-TW: OpenCC (cn → twp, Taiwan phrases; a tool run outside the repository, no dependency), then the TW client's own
|
||
word where it differs (97 terms from the TW tables walked beside the zh ones — 调度中心 stays 調度中心, not twp's
|
||
排程中心; 刷新 → 更新; 重装 → 重裝), then a manual pass over the whole pack (只 / 隻, 重新整理 only for a page reload,
|
||
廣告攔截擴充功能 where twp's 外掛 reads as "cheat"). Its fallback stays the Simplified Chinese (the owner's
|
||
「繁中缺的字回落到简中」).
|
||
- ja: a 93-term glossary from the JP client data (単独演算 / 連合演算, 管理センター, 整備エリア, 防衛支援, 最終防衛段階,
|
||
標準 / 逆境 / 死地 / 究極; the mode's JP title 堅守協定:盟約), then a translation of every msgid in short UI Japanese;
|
||
eight strings shortened after a screenshot pass (the title-screen name field, the hotkey row, the room's ready lines,
|
||
the emote button …).
|
||
- ko: a 102-term glossary from the KR client data (위수 협의: 맹약, 독립 / 동맹 시뮬레이션, 보급센터, 정비 구역, 연합 방어,
|
||
표준 / 험지 / 극한 / 초월), 합니다체 like the KR client's tips; one hotkey label shortened.
|
||
- The mark: `_meta.machineTranslated: true`, a new optional manifest field (docs/PACKS.md; shared/packs.js validates it
|
||
as a boolean and copies it into the pack index entry like `complete`); 设置 shows 「当前语言的界面文字为机器翻译,可能不够
|
||
准确,欢迎在 GitHub 上指正。」 under the language switch when the current pack has it (ui/lang.js
|
||
`machineTranslationNote`).
|
||
- The game texts the JP client writes exactly like the Chinese (炎, 不屈, 助力, 速射手 …) were dropped by build-i18n as
|
||
untranslated ('same'), so the Japanese interface showed the bonds 炎 / 不屈 / 助力 by their English names. ja's test is
|
||
now 'native': a text identical to the Chinese is the client's own when every Han character of it appears in the
|
||
client's translated texts (`nativeCharset`); one with a character the client never writes (甄选干员) is still
|
||
untranslated. data/i18n/ja.json 96.5 % → 97.5 % (bonds 100 %); ko.json and zh-TW.json rebuilt for the UI packs'
|
||
emote names (ko 97.5 %, zh-TW 91.2 %).
|
||
- The CJK font stack follows `<html lang>` (`--cjk-faces`; `:root:lang(ja / ko / zh-TW)`): Japanese kanji, Traditional
|
||
Chinese and Hangul take their own faces instead of the Simplified Chinese glyph forms. The lobby's difficulty lines
|
||
drop the JP bullet ・ like the Chinese ·.
|
||
- Known limits (for later): the remake's composed stage names (战场#01 …) have no Japanese / Korean / Traditional
|
||
wording in data/i18n, so ja / ko show the English name and zh-TW the Simplified one where the stage name comes from the
|
||
data; 冻结 is one msgid for the shop button and the frozen status (Korean 동결 for both; the official status word is
|
||
빙결 — a context key would split them).
|
||
- Tests: `test/i18n-packs.test.js` (the field, its warning, the shipped manifests, the note shown / hidden),
|
||
`test/i18n-data.test.js` (the 'native' test, the shipped ja names 炎 / 不屈 / 助力), `test/ui/i18n.e2e.test.js` (SP_E2E;
|
||
reads its expected strings from the pack files and checks the note), `test/i18n.test.js` (placeholders of every pack).
|
||
Screenshots of every screen in each language (title, settings, lobby, room, 干员调配, briefing, band draft, prep,
|
||
combat, results) were checked by each stream.
|