0.2.5-dev: community round 30 and follow-ups
- Stock: fixed trait gifts (缪尔赛思 / 变形者集群 变形同构体, 耶拉 不融冰, 蜜蜡 / 卡涅利安 迅捷作战粮, 诗怀雅 盟约之币) still occupy stock but are granted past the cap; an operator card already shown in the shop or a reward can be taken after the pool runs out and overdraws (GitHub #498, the owner's decision); item buys and item rewards keep the stock check. 洛洛 / 焰尾 sub-pools use the measured weights (PR #497 by @2321Robin; the occupancy idea of PR #496 by @2321Robin re-implemented differently). - Boss pairs are drawn at random once per match and fixed to battle start; the Hidden Core reuses them; a leaver does not split a full pair (the owner's decision). - 阿戈尔 in 联防 no longer re-applies the opening devour HP loss or a false revive; Touch's team medic stays for the match after its holder leaves (owner-approved, official lifetime unverified). - Auto-skill ranges: 司霆惊蛰 S2, 斩业星熊 S3 against air, 予愿安洁莉娜 S3; 自在's post-rebirth invulnerability is also untargetable (#510); Horn / Clementia / catapult / 忍冬 first hit (PR #502 by @Xinglan233); 不融冰 / tear gas trigger on real damage. - Bond layer-up sound in round start / draft / prep / battle (#482): one channel, a new cue replaces the old, no extra cooldown; a prep update that adds layers and activates a bond plays one cue. - Client: multi-swing fix (#506), refresh single-flight (PR #507 by @robll-v1), LP tower keeps the settled value with a −N tick (PR #504 by @robll-v1), export with only 潜能 / 练度 changes (PR #503 by @Xinglan233), spectator rosters list DIY members (PR #505 by @Xinglan233), banned members beside bond tooltips (PR #494 by @YuriRestia), recovery action above the away overlay (PR #511 by @RainoutOvO), the /dev/sim-check.html consistency page (PR #492 by @Cloudnyco), Korean (PR #490 by @D-Roote) and English Victoria wording (PR #499 by @YuriRestia). - golden: 45 of 287 scenarios move against 0.2.4 (roster 17, bonds 3, fields 6, matches 17, standins 2), each attributed in docs/history/0.2.5.md §30.9 / §30.16.
This commit is contained in:
1 parent
bc50cac01f
commit
221e6b8dd2
134 files changed
+4590
-1201
No files matched your search
@@ -3,6 +3,11 @@
|
||||
Owner: `tools/fetch-assets.mjs` and `tools/assets/*`. Research background: `docs/research/07-assets.md`.
|
||||
|
||||
All official game art, Spine models and audio are **downloaded at install time**. They are never committed; `public/assets/` is git-ignored.
|
||||
|
||||
The UI sound `audio.sfx.ui.bondUp` is the official `ON_ACT1AUTOCHESS_ADD_BOND` bank's
|
||||
`act1autochess_b_ui_buffup`. Live prep/battle layer gains use it as well as bond activation. Its bank settings are
|
||||
`maxSoundAllowed: 1` and `popOldest: true`: one dedicated SFX channel, replacing the previous sound without an extra
|
||||
cooldown. It respects the SFX/mute settings; a stale asynchronous decode cannot restart a replaced cue (#482).
|
||||
All downloaded game assets the client needs are listed in **`data/assets.json`**. Game-art requests must use that manifest.
|
||||
The original project icons below are shipped static files, not downloaded game assets.
|
||||
|
||||
|
||||
@@ -737,3 +737,12 @@ the DIY stock (per player in the match, `PlayerState.diyStock`: `config.economy.
|
||||
field), 助战 borrows (`borrowCount` 20), and a player's potential / 练度 per operator (the 干员调配 settings sent with
|
||||
`room.loadout`; the forms are built at full potential and carry the lower ranks, §2.3; 练度 = effects.json
|
||||
`aceffect_char_1…4`).
|
||||
|
||||
### Acquisition subsets corrected in 0.2.5-dev (§30.2)
|
||||
|
||||
`tools/build-data.mjs` owns the measured Rockrock/Flametail subset weights from
|
||||
[路标月报#2](https://www.bilibili.com/video/BV1eLXXBqEgF/). Rockrock: ordinary hammer 10; tremble, undying, haste,
|
||||
burn hammers 2 each; limited accelerator 1; shield drone and laser emitter 4 each. Flametail: Wild Mane 10,
|
||||
Ashlock 10, Fartooth 3. Rebuild `choices.json` offline; these weights do not exempt draws from shared availability.
|
||||
The runtime derives unlimited fixed-gift families from `SERVER_GAIN_EQUIP`; this is a grant-source exemption,
|
||||
not a zero-occupancy flag or a manually maintained second list in generated data.
|
||||
+5
-1
@@ -4,7 +4,10 @@ This is the **single source of truth** for every implementer. Research lives in
|
||||
|
||||
Language: player-facing text is **Simplified Chinese** by default, with an English switch since 0.2.0 (§25.2, docs/I18N.md: UI strings through `t('中文')`, game texts from the official Chinese data or the official EN client's). Code, comments and identifiers are English.
|
||||
|
||||
Versions: the first public release was **0.1.0** (2026-10-02, the state of §0–§20.15); the releases after it add the player feedback and GitHub reports — 0.1.1 §21, 0.1.2 §22, 0.1.3 §23, 0.1.4 §24 — and **0.2.0** (2026-10-07; `CHANGELOG.md`) the maintainability refactor, two languages, 补位, 自选编队 and their fidelity work — §25 — **0.2.1** (2026-10-07) the 联防 battlefield restored, full potential and the GitHub fixes after it — §26 — and **0.2.2** (2026-10-09) per-operator 潜能 / 练度, Japanese voices, the statistics page, 失衡, whole-frame attack timing and the GitHub fixes after 0.2.1 — §27. **0.2.3** (2026-10-10; `package.json`, `shared/constants.js APP_VERSION`) 克莱门莎 and new modules, community fixes, text size, per-operator voices, installation, the opening reroll and local match recovery — §28. **0.2.4** (2026-10-11) the official shared card pool and item stock, Raid revival and #475, and the community fixes after 0.2.3 — §29, the state described by this document. The labels v1 / v2 / v2.1–v2.5.2 in §0, §14–§20 and in the BALANCE / SIM comparisons name the design generations and the private playtest builds that came before it; they are kept as history.
|
||||
Current development state: **0.2.5-dev**, §30, the state described by this document. Its fixed gifts, already displayed operator offers, combat corrections
|
||||
and client/tool changes supersede the corresponding 0.2.4 rules below. It is not yet released.
|
||||
|
||||
Versions: the first public release was **0.1.0** (2026-10-02, the state of §0–§20.15); the releases after it add the player feedback and GitHub reports — 0.1.1 §21, 0.1.2 §22, 0.1.3 §23, 0.1.4 §24 — and **0.2.0** (2026-10-07; `CHANGELOG.md`) the maintainability refactor, two languages, 补位, 自选编队 and their fidelity work — §25 — **0.2.1** (2026-10-07) the 联防 battlefield restored, full potential and the GitHub fixes after it — §26 — and **0.2.2** (2026-10-09) per-operator 潜能 / 练度, Japanese voices, the statistics page, 失衡, whole-frame attack timing and the GitHub fixes after 0.2.1 — §27. **0.2.3** (2026-10-10; `package.json`, `shared/constants.js APP_VERSION`) 克莱门莎 and new modules, community fixes, text size, per-operator voices, installation, the opening reroll and local match recovery — §28. **0.2.4** (2026-10-11) the official shared card pool and item stock, Raid revival and #475, and the community fixes after 0.2.3 — §29. The labels v1 / v2 / v2.1–v2.5.2 in §0, §14–§20 and in the BALANCE / SIM comparisons name the design generations and the private playtest builds that came before it; they are kept as history.
|
||||
|
||||
---
|
||||
|
||||
@@ -36,3 +39,4 @@ normative lines it rewrote).
|
||||
| §27 | [history/0.2.2.md](history/0.2.2.md) | 0.2.2 — after the 0.2.1 release (2026-10-09) |
|
||||
| §28 | [history/0.2.3.md](history/0.2.3.md) | 0.2.3 — after the 0.2.2 release (2026-10-10) |
|
||||
| §29 | [history/0.2.4.md](history/0.2.4.md) | 0.2.4 — after the 0.2.3 release (2026-10-11) |
|
||||
| §30 | [history/0.2.5.md](history/0.2.5.md) | 0.2.5-dev — after the 0.2.4 release |
|
||||
@@ -156,6 +156,11 @@ rebuilt.
|
||||
the source on the record's own ids, then the 下半 season (`act2autochess`). Rich-text tags and placeholders are the
|
||||
same as in Chinese, so `ui/richText.js` renders the English unchanged (a few official EN texts leave a tag unclosed;
|
||||
the parser runs it to the end of the text, as the game does).
|
||||
- **Corrections**: `tools/i18n/corrections-<lang>.json` (the pack's code: `en`, `ja`, `ko`, `zh-TW`; optional) is
|
||||
tried before the official data of that language, for an official translation that contradicts the Chinese text and
|
||||
the engine (exact match on the raw Chinese text; the plain twin is stripped from it; every entry carries a `_why:`
|
||||
note; `_`-keys are never written to the overlay). Only `corrections-en.json` exists. Counted as `correction` in the
|
||||
coverage report.
|
||||
- **Fallbacks**, in order: `tools/i18n/fallback-remake.json` (the remake's own strings: stage-name parts, item notes,
|
||||
the escaped levels' map names, the season name), `tools/i18n/fallback-pr70.json` (PR #70's translations of texts the EN client
|
||||
lacks: modules of CN-only operators, the 甄选 slots, 结算称号 criteria, emote labels), then `public/i18n/en.json`;
|
||||
|
||||
+24
-8
@@ -64,7 +64,7 @@ LOBBY → INFO_CHECK (co-op 25 s; solo and single-human matches untimed; all hum
|
||||
```
|
||||
|
||||
**Deploy field (user playtest #5 item 7).** From the ROUND_START of a boss round (最终攻势 / 隐秘核心) a player deploys on
|
||||
its half of the boss field (`Match.deployFieldOf` → `'bossL'`, or `'bossR'` for the second player of a seat pair — the
|
||||
its half of the boss field (`Match.deployFieldOf` → `'bossL'`, or `'bossR'` for the second player of a drawn pair — the
|
||||
same pairing as the fields, `bossWaves` / `Match.bossGroupOf`, planned in `startRound` BEFORE the players' round start
|
||||
so R14 → R15 never re-checks a boss-half board against the normal field, and re-paired — with an immediate re-check —
|
||||
when a teammate quits before the fight): `board.js buildDeployMap`
|
||||
@@ -411,14 +411,14 @@ keeps it; `PlayerState.pieceRoundCount`; prefix keys with your module too) —
|
||||
first manual refresh that copy witnesses (player feedback after 0.1.0: "获得该干员后该回合的首次刷新" also stacks; a copy
|
||||
bought after selling one this round is a new copy and fires on its own first refresh [ASSUMED]).
|
||||
|
||||
Writes (all validated, never throw on bad input, never make funds / pools negative):
|
||||
Writes (validated, never throw on bad input; funds and available stock stay non-negative; authorized operator overdraw records an internal deficit):
|
||||
|
||||
| helper | effect |
|
||||
|---|---|
|
||||
| `addFunds(n, reason?)` / `addPendingFunds(n)` / `spendFunds(n)` | funds now / at the next round start / pay (false when short) |
|
||||
| `addLayers(bondId, n, { requireActive })` | layer gain (`requireActive` = "使已激活的…"); returns layers added — at most the room left under `BOND_LAYER_CAP` (999, shared/constants.js `layerGainRoom`; the battle gains merged at SETTLE too); fires onLayers unless it added 0 |
|
||||
| `addLayers(bondId, n, { requireActive })` | layer gain (`requireActive` = "使已激活的…"); returns layers added — at most the room left under `BOND_LAYER_CAP` (999, shared/constants.js `layerGainRoom`; the battle gains merged at SETTLE too); fires onLayers unless it added 0. During ROUND_START / SP_DRAFT / PREP, a positive gain also sends the owner an ephemeral `m.layer {playerId, bondId, add}` audio notification; no replay on resync or SETTLE backfill |
|
||||
| `grantChess(id, { toTemp, golden, requirePool=true, fromPool=true })` | acquire a chess (takes pool copies; with `requirePool` a pool chess with no copy left fails → `null`); merges; fires onGain. `toTemp` puts it into temp, but a free hand slot pulls it in at the next recompute (temp holds overflow only, `PlayerState._fillHandFromTemp`) |
|
||||
| `grantItem(id, { toTemp })` | acquire an item (merges with an identical normal item); `toTemp` as for grantChess |
|
||||
| `grantItem(id, { toTemp, requirePool=true })` | acquire an item (merges with an identical normal item); `toTemp` as for grantChess. `requirePool:false` bypasses stock only for fixed `SERVER_GAIN_EQUIP` gift families; every copy still counts in occupancy (§30.1). |
|
||||
| `rollChess({ maxTier, tier, bond, filter })` / `rollItem({ pool, tier, maxTier })` | copy-weighted chess id from the shared pool / item id (choices.json pools) |
|
||||
| `grantFreeRefresh(n)` | free refreshes (stack) |
|
||||
| `modifyPrice(delta)` / `setPrice(v)` | onPrice only: edit `ev.price` |
|
||||
@@ -436,6 +436,7 @@ Writes (all validated, never throw on bad input, never make funds / pools negati
|
||||
| `offerBountyChoice(cards, sourceItemId)` | 教鞭 only: open a PERSONAL choice of up to three of `cards` (cards.bounty entries) for this player — shuffled once with the meta rng, kept in `m.private.personalChoice` until the owner confirms one (`g.choice { idx, choiceId }`) or the prep's deadline / an AI seat picks (§2.5); returns the intent result (`{ ok }`, or `{ error, detail }` for a phase that is not PREP, a Ready player, a choice already open or no card — before any rng draw or id, so the Art stays in the hand) |
|
||||
| `toast(text, kind)` / `ticker(text)` / `giftTicker(fromName, chessId)` | messages |
|
||||
| `teammates()` / `player(playerId)` | ctx objects of other alive players (team effects) |
|
||||
| `teamMedicGranted()` | Whether this match has a confirmed Touch selection, including an eliminated/departed holder; only the retained 外勤医疗 grant uses this exception ([ASSUMED], §30.14) |
|
||||
|
||||
### 2.5 Items: consume-on-equip and Arts
|
||||
Items whose data `kind` starts with `consume_on_equip` resolve through their `item:` handler's `onEquip` and are
|
||||
@@ -674,6 +675,9 @@ Any `choice:` handler whose EffectRef reuses its own key must guard like this (o
|
||||
(own phase perfect) go to pending funds; bounty rounds decrement; LP ≤ 0 ⇒ eliminated (all copies back to the pool).
|
||||
* **Final Assault / Hidden Core**: finalAssault.js header. Boards are passed in board coordinates; the sim maps board
|
||||
rows 9–12 onto boss rows 2–5 (`BOSS_ROW_OFFSET` −7, matching every stage's boss rows) and mirrors the right side.
|
||||
Pairing uses a separate seeded shuffle once per match, before Final Assault prep; `bossPairs` retains partners and
|
||||
sides into Hidden Core. A departure preserves intact pairs and joins the remaining single players. The published
|
||||
`m.public.bossPairs` follows the preparation plan; camera, placement and green team frames use it, never new draws.
|
||||
Pool (`finalAssault.js bossPoolHp` → `GameData.bossPoolShare` → `gamedata.js bossPoolShareOf`, DESIGN §20.10,
|
||||
§25.13.4): one pool shared by every boss field (official tip "最终攻势中,所有人将一起对敌方领袖造成伤害"; notice 5114's
|
||||
"敌方领袖的总生命值不变" is about the mirrored copies of a pair field sharing it) = `bloodPoint[difficulty]` × the players
|
||||
@@ -731,6 +735,12 @@ smallest stat (坚若磐石 "目标生命值损失最少" = least `lpLost`). doc
|
||||
---
|
||||
|
||||
## 4. 联防 (Unite)
|
||||
|
||||
HP/SP restoration is completed after deployment and all `battleStart` effects. Living carry ratios remain exact,
|
||||
including below 1% or fractional HP under a smaller new maximum. As approved for the reported Egir bug, opening
|
||||
devour rebuilds attributes/mark chains without repeating HP loss or death/revive effects on a carried survivor.
|
||||
Forced-down carry still participates in attribute chains and stays down without using a revive slot. Fresh units
|
||||
without carry and other battle kinds retain normal devour damage; later redeploys do not reuse the old carry.
|
||||
Planned after the normal combats, at the end of the COMBAT_END pause from the players still in (`Match._afterCombat`, so a
|
||||
player who quit during the last field or the pause is neither a helper nor a leaker whose enemies re-enter; unite.js):
|
||||
helpers = `unite.js helperOrder` (research 08 §5, PRTS 卫戍协议/帮助 §联防阶段): ≤ `unite.maxHelpers` (2) perfect players
|
||||
@@ -927,13 +937,19 @@ choices are explicitly [ASSUMED]; DESIGN §28.15–16 records the source and val
|
||||
|
||||
`SharedItemPool` derives equipment availability from current ownership across all players: ordinary 1, upgraded 2.
|
||||
Equips, merges and returns cannot lose reservations. Consumptions/destruction release ownership [ASSUMED removal
|
||||
interpretation]. Shop/reward displays reserve nothing; rejected exhausted purchases retain funds and offers.
|
||||
interpretation]. Shop/reward displays reserve nothing; rejected exhausted **item** purchases retain funds and offers.
|
||||
整备 upgrades the purchased item only when `left` still has the golden's second copy; otherwise the item stays
|
||||
normal and the charge remains.
|
||||
`m.public.sp.cards[].soldOut` disables duplicates when a preceding choice used the final copy; timer/bot choices
|
||||
use the same availability. Non-shop effect-only equipment is unlimited.
|
||||
|
||||
Operator capacities use measured single-player exceptions and twice those counts in co-op; DIY remains private.
|
||||
`take(..., { overdraw: true })` records full occupation of a granted/promoted elite or a Mimic copy beyond capacity;
|
||||
normal takes remain bounded. Negative internal balance is a deficit, never negative available stock. Existing
|
||||
item selection probabilities and explicit grant weights remain unchanged.
|
||||
`take(..., { overdraw: true })` records full occupation, including authorized acquisitions beyond capacity.
|
||||
Already displayed operator shop offers remain purchasable after exhaustion (路标月报#2 2:50–2:57, #498);
|
||||
operator reward offers follow the same rule by the owner's 2026-10-11 decision. Future rolls still use available stock.
|
||||
Negative internal balance is a deficit, never negative available stock; selling first repays the deficit.
|
||||
|
||||
Fixed equipment gifts from `SERVER_GAIN_EQUIP` (卡涅利安、蜜蜡、缪尔赛思、耶拉、诗怀雅) may exceed the pool,
|
||||
including the same families awarded by 变形者. They still occupy ordinary/advanced 1/2 copies and can leave availability
|
||||
at zero after a removal. Ordinary shop, reward and random grants retain their limits. `requirePool:false` is not a
|
||||
universal equipment bypass. Rockrock/Flametail's measured weighted subsets remain subject to shared availability (§30.2).
|
||||
+5
-3
@@ -24,7 +24,7 @@
|
||||
| 休整期 | 购买、摆阵、配装备、冻结 / 刷新、升级调度中心;同盟有倒计时(65–215 秒,随回合增加);独立模拟、以及只有你一名玩家(只带 AI 队友)的同盟模拟不限时。所有人「准备就绪」即提前开战,全员就绪前可取消;点「准备就绪」时商店自动收起、棋盘放大到全场,取消准备时商店再展开(资金旁的「收起」和商店标签「展开商店」随时可以手动切换)。 |
|
||||
- **特殊地形点一下就有说明**:战场上的**活性源石**、**沼泽**、**排气格栅**、**深水区**,以及**红门 / 蓝门 / 传送点**,点一下就会弹出它自己的说明卡——名称、机制,以及**这一关自己的数值**(比如战场#04 的活性源石:每秒 70 点真实伤害、攻击力 +20%、攻击速度 +20、持续 300 秒)。休整期和作战期都能点。普通地板 / 道路 / 高台点了不会弹东西,所以点一下仍然只是「取消选中、关掉卡片」。
|
||||
- **场地装置点一下也有说明**:**阻隔工事**(挡路:地面敌人绕着走,无路可走才撞碎它;作战中说明卡上有它的实时血量,被摧毁后点不出来)、**“双眼皮”炮台**(自动法术攻击、命中附加脆弱,按当前层数最高的盟约强化;还没被机械援助或机变卡启用的炮台不显示、点不出来)、**射击台**(远程位可部署的高台位)和**源石流发生装置**(吹风方向,以及对干员攻击力、敌人移动速度的加减)点一下同样弹出说明卡,数值都取自所在关卡的装置数据,装置名称按当前语言显示官方译名;被机变卡移除的箱子同样不显示。休整期和作战期都能点(GitHub #228,PR #229,感谢 @rickylxw)。
|
||||
| 作战 | 每人在自己的战场各自作战(战斗在你的浏览器里模拟,2 倍速)。干员按**逐列从左到右、每列从上到下**的顺序(官方「从上到下>从左到右」:最左一列最先)自动部署并消耗部署费用(初始 10,+1/秒)。时限 45–115 秒(实际秒数,即屏幕上的倒计时),时间到仍存活的敌人算漏怪。顶栏中间的胶囊是官方的「已解决 / 本回合敌人数」:打死一个、漏掉一个都算已解决(开局 0/3,漏一个 1/3,打死一个 2/3,打死会分裂的那只 3/3);分裂出来的小怪、召唤物和领袖召唤的敌人不进分子也不进分母,但它们漏掉时仍然各自扣目标生命值、也会破坏完美作战(4 只磨砻全被打死、分裂出的 8 只全漏进蓝门:胶囊 4/4,扣 8 点),所以会召唤的领袖关胶囊也能填满。有敌人进入蓝门时,顶栏的目标生命值会**立即**显示扣除后的数值(红字 + 「−N」,每回合至多 10 点),结算时确定;联防阶段标注「联防中」,队友拦下的部分最后不扣。左侧队伍栏同样显示队友的待扣生命值。被击倒的干员**留在倒下的格子上**(倒地姿势、略微变灰),之后也在这一格再部署(与官方一样;倒在其他干员或召唤物初始位置上的,会回到自己的初始位置躺下,召唤物已经消失也一样;唯一的例外是乌尔比安:三技能把他移到船锚处期间被击倒时,他回到自己的部署位躺下、再部署——这是项目维护者 2026-10-07 应社区反馈有意做出的改动,与官方「原地倒下」不同);因自身效果强制退场的干员(史尔特尔「余烬」结束、耀骑士临光 2 技能结束等)同样倒在原地、在原地再部署;倒地干员所在的格子**不会被占用**,突袭盟约的再部署、援军、召唤物都会避开它。头上的圆圈是再部署倒计时:绿色圆环 + 秒数;变成黄色「DP」表示部署费用不够。血条下方的一行是**元素损伤**(与原版一致:元素图标 + 白条):干员为带图标的彩色圆盘,敌人为小号纯色圆盘,右侧白条是剩余元素值,像血条一样从右往左减少,白条耗尽的那一下就是爆条(被大额元素损伤一次打掉一截时白条也会一次少一截,例如掠海漂移体每击约为 25%–50%);爆条后进入爆发冷却(灼燃 / 神经 / 侵蚀 10 秒,敌方侵蚀 8 秒,凋亡 15 秒),这时白条变成**元素颜色**(神经青绿、侵蚀蓝、灼燃橙红、凋亡灰紫)并在冷却期间慢慢回满、图标闪烁——彩色条表示已经爆条、正在承受爆发效果,不是还剩的元素值;期间所有元素都不会累积也无法被治疗,结束后清零。元素爆发造成的是**无来源伤害**,不吃干员的增伤、穿透和装备加成(例如深巡打海嗣时灼燃爆发固定 7000),击杀仍记在爆条的干员名下;元素脆弱只提高元素伤害,不加快元素条;脆弱不影响元素伤害。已被击杀的敌人不会再被附加元素损伤。 |
|
||||
| 作战 | 每人在自己的战场各自作战(战斗在你的浏览器里模拟,2 倍速)。干员按**逐列从左到右、每列从上到下**的顺序(官方「从上到下>从左到右」:最左一列最先)自动部署并消耗部署费用(初始 10,+1/秒)。时限 45–115 秒(实际秒数,即屏幕上的倒计时),时间到仍存活的敌人算漏怪。顶栏中间的胶囊是官方的「已解决 / 本回合敌人数」:打死一个、漏掉一个都算已解决(开局 0/3,漏一个 1/3,打死一个 2/3,打死会分裂的那只 3/3);分裂出来的小怪、召唤物和领袖召唤的敌人不进分子也不进分母,但它们漏掉时仍然各自扣目标生命值、也会破坏完美作战(4 只磨砻全被打死、分裂出的 8 只全漏进蓝门:胶囊 4/4,扣 8 点),所以会召唤的领袖关胶囊也能填满。有敌人进入蓝门时,顶栏的目标生命值**先不变**(红字 + 「−N」标记待扣的点数,每回合至多 10 点),结算时才显示扣除后的数值(与官方一致,GitHub #479;0.2.4 及之前是立即显示扣除后的数值);联防阶段标注「联防中」,队友拦下的部分最后不扣。左侧队伍栏同样显示队友的待扣生命值。被击倒的干员**留在倒下的格子上**(倒地姿势、略微变灰),之后也在这一格再部署(与官方一样;倒在其他干员或召唤物初始位置上的,会回到自己的初始位置躺下,召唤物已经消失也一样;唯一的例外是乌尔比安:三技能把他移到船锚处期间被击倒时,他回到自己的部署位躺下、再部署——这是项目维护者 2026-10-07 应社区反馈有意做出的改动,与官方「原地倒下」不同);因自身效果强制退场的干员(史尔特尔「余烬」结束、耀骑士临光 2 技能结束等)同样倒在原地、在原地再部署;倒地干员所在的格子**不会被占用**,突袭盟约的再部署、援军、召唤物都会避开它。头上的圆圈是再部署倒计时:绿色圆环 + 秒数;变成黄色「DP」表示部署费用不够。血条下方的一行是**元素损伤**(与原版一致:元素图标 + 白条):干员为带图标的彩色圆盘,敌人为小号纯色圆盘,右侧白条是剩余元素值,像血条一样从右往左减少,白条耗尽的那一下就是爆条(被大额元素损伤一次打掉一截时白条也会一次少一截,例如掠海漂移体每击约为 25%–50%);爆条后进入爆发冷却(灼燃 / 神经 / 侵蚀 10 秒,敌方侵蚀 8 秒,凋亡 15 秒),这时白条变成**元素颜色**(神经青绿、侵蚀蓝、灼燃橙红、凋亡灰紫)并在冷却期间慢慢回满、图标闪烁——彩色条表示已经爆条、正在承受爆发效果,不是还剩的元素值;期间所有元素都不会累积也无法被治疗,结束后清零。元素爆发造成的是**无来源伤害**,不吃干员的增伤、穿透和装备加成(例如深巡打海嗣时灼燃爆发固定 7000),击杀仍记在爆条的干员名下;元素脆弱只提高元素伤害,不加快元素条;脆弱不影响元素伤害。已被击杀的敌人不会再被附加元素损伤。 |
|
||||
| 联防 | 见第 5 节。 |
|
||||
| 结算 | 扣 LP、发放悬赏资金、结算层数;LP ≤ 0 的玩家淘汰(其干员回到公共卡池)。结算开始时屏幕正中跳出官方的「**作战结束**」框(约 3 秒后自己消失,不挡操作),下面一行只写**你自己**这一回合被扣的目标生命值:没扣是「**全员无伤!**」,扣了是「**生命值减少 −N**」;同时播官方的战斗结束音效(扣了、联防里没扣、普通回合没扣各一种)。联防回合见第 5 节。最终攻势和隐秘核心没有这一框(之后直接是结算称号或隐秘核心);已淘汰的玩家和观战者不弹框。 |
|
||||
|
||||
@@ -59,7 +59,9 @@
|
||||
## 3. 招募、整备区与晋升
|
||||
|
||||
- **购买点两次**:第一次点商店卡片只选中(卡片抬起并打开详情,底部出现「确认购买 · 再次点击」),再点这张卡片的**任意位置**(包括金色的确认条)才购买;点别处或按 Esc 取消。升级调度中心、晋升奖励同样两次;策略或装备带来的免费挑选(如凯瑟琳【定向投放】升级后刷新的 3 件装备、娜仁图亚【见者有份】的 2 件装备、寻呼模块的 3 名干员)也一样出现在商店卡片的位置,左侧标题写着它的来源,装备显示为装备卡(图标、名称、说明、FREE),选 1 个免费获得;同时有多个免费挑选时依次出现,标题下和「稍后」后的提示按钮会写还有几项(如「+1」)。不能购买时(例如已准备就绪)点卡片只打开详情。
|
||||
- **公共卡池**(同盟):每名干员的副本数有限,I–VI 阶分别 12 / 14 / 18 / 16 / 8 / 5 份,所有玩家共用;持有的干员(棋盘 + 整备区)占用副本,商店里展示的不占用。一名干员被大家拿光后就刷不出来了;淘汰玩家的干员会还回卡池。
|
||||
- **刷新等待**:按下「刷新」后按钮会变暗,本次请求结束(成功或失败)后恢复可点;等待期间再点按钮或按 R 都不会重复发送,避免高延迟时连点多次扣费(GitHub #501)。
|
||||
- **公共卡池**:独立模拟 I–VI 阶的基础副本数分别为 12 / 14 / 18 / 16 / 8 / 5,少数干员有例外;同盟的公共干员库存是独立的两倍,自选干员仍用各自的私人库存。持有的普通/精锐干员占 1 / 3 份,商店展示不占份数。拿光后不能再刷到,但已经展示的干员商店牌和奖励牌仍可领取;超额部分也占库,卖出先抵消超额,淘汰时归还所持份数。
|
||||
- **装备库存**:普通/进阶装备通常占共享库存 1 / 2 份,道具商店和奖励领取时仍检查余量。缪尔赛思、耶拉等固定特质赠品仍占份数,但不会因库存已满停止赠送;拥有量降回上限以下后商店才有余量。商业包装方案的 2 份是同时库存,不是整局限买两次。
|
||||
- **位置上限**:棋盘最多部署 **8** 名;整备区 **10** 格。整备区满时**不能购买或领取**任何干员、装备(包括能凑齐 3 名合成精锐的那一张,和官方一样),先出售、部署或配发腾出格子;新获得的单位(合成的精锐、奖励、退回的装备等)进入**临时整备区**(整备区前面的 5 格),整备区一空出格子,临时整备区的单位就**自动补进去**(从右往左)。临时整备区有单位时**不能准备就绪**,棋盘上会用红色虚线框标出这一排并说明规则:把它们放进整备区或战场、配发或使用,或者出售 / 销毁。休整期中进入临时整备区的单位,若到**本休整期结束**时仍留在那里就会被自动处理(干员返还卡池、装备销毁);作战、结算期间或准备就绪之后才进入的(例如战斗奖励、结算时合成的精锐),会保留到**下一个休整期**结束,你一定有机会处理它们。
|
||||
- **晋升精锐**:3 名同名干员(无论是否部署)自动合成**精锐**(等级、技能、模组大幅提升;风丸只需 2 名),精锐不会再合成。如果被合成的干员里有**已经部署在战场上**的,精锐会直接出现在**那名干员的位置**(保持原来的朝向,不多占部署位;有两三名都在场上时,取最先部署的那名——最左一列优先,同一列从上到下);否则精锐进入整备区(满了进入临时整备区)。原先配发的装备都退回整备区,需要重新配发;被合成干员的召唤物随之移除,场上的精锐会把自己的召唤物送进整备区。点选一张能合成的商店卡片时,精锐将出现的那一格会亮起金色边框,同时打开的详情卡里也会写明去向(「可晋升:精锐干员将出现在作战区原位置 / 将进入整备区」;详情卡会自动停靠在不遮挡这一格的一侧)。在回合开始或结算时因策略、奖励等完成的合成,精锐出现时同样会播放金色的晋升特效。
|
||||
- **晋级奖励**:每次晋升后获得一次特殊招募:从 3 名 **高一阶**(最高 VI)、**互不相同**的随机干员中**免费**挑 1 名(该阶剩余干员不足 3 名时由低一阶补足)。它不能刷新、不能冻结、本回合结束失效。
|
||||
@@ -124,7 +126,7 @@
|
||||
|
||||
## 7. 最终攻势与隐秘核心
|
||||
|
||||
- **最终攻势**(第 14 回合;独立标准为第 9 回合):按座位两两配对,每对共享一个战场,一人守左半边、一人守右半边(右侧玩家的棋盘左右镜像)。所有人**共同削减同一条领袖血条**(血量 = 该难度的官方领袖生命值 × 开战时存活的玩家人数:领袖生命值取自当前版本的游戏数据,例如终极「假想敌:胄」3 600 000,4 人存活时为 14 400 000、2 人为 7 200 000;AI 队友和掉线托管的玩家都算,已被淘汰或中途退出的不算;独立模拟按 1 人计。这是作者 2026-10-06 采纳社区 PR #209 的决定,取代之前「保持固定血量」的做法),看不到另一组的战场。全队 LP 合并成一个池,不再有每回合 10 点上限。顶部的 120 秒倒计时结束后战斗**继续**(不会超时判负);从开战第 150 秒起(实际秒数)全队每秒扣 1 点 LP。领袖血量归零即胜利(血条显示 0 时领袖已倒下,战斗立即结束),LP 归零即失败——以先归零的一方为准,LP 耗尽后打出的伤害不再计入。此阶段盟约不叠层。
|
||||
- **最终攻势**(第 14 回合;独立标准为第 9 回合):每局开始时随机两两配对(准备期到开战固定,隐秘核心沿用同一分组),每对共享一个战场,一人守左半边、一人守右半边(右侧玩家的棋盘左右镜像)。所有人**共同削减同一条领袖血条**(血量 = 该难度的官方领袖生命值 × 开战时存活的玩家人数:领袖生命值取自当前版本的游戏数据,例如终极「假想敌:胄」3 600 000,4 人存活时为 14 400 000、2 人为 7 200 000;AI 队友和掉线托管的玩家都算,已被淘汰或中途退出的不算;独立模拟按 1 人计。这是作者 2026-10-06 采纳社区 PR #209 的决定,取代之前「保持固定血量」的做法),看不到另一组的战场。全队 LP 合并成一个池,不再有每回合 10 点上限。顶部的 120 秒倒计时结束后战斗**继续**(不会超时判负);超过开战 120 秒后(实际秒数)全队每秒扣 1 点 LP;仅开战时有 AI 队友的队伍延后至超过 150 秒。领袖血量归零即胜利(血条显示 0 时领袖已倒下,战斗立即结束),LP 归零即失败——以先归零的一方为准,LP 耗尽后打出的伤害不再计入。此阶段盟约不叠层。
|
||||
- **限伤**(最终攻势与隐秘核心,与官方相同):对领袖的**单次伤害达到 300000 或以上时整次作废**——这一下造成 0 点伤害,不计入领袖血条,也不显示伤害数字;不是截到 300000,而是一点都不算(299999 照常生效)。只针对领袖本体(含两人战场里的另一个领袖),领袖的部件、护卫、无人机和其他小怪不受影响,普通回合和联防也不受影响;部件把伤害等量转给领袖时,这一下也按一次伤害检查;无人机死亡令领袖失去的 2% 血条不算一次伤害,不受限伤影响(隐秘核心终极「假想敌:胄」3 或 4 人存活时每架为 43.2 万 / 57.6 万,按限伤会整次作废,本作仍然计入,属推断)。层数极高时领袖仍可能几秒内倒下(例如每名玩家的两个盟约都在 999 层,或所有激活的盟约都在 999 层),这来自官方按层数计算、没有上限的伤害倍率(谢拉格、奥术、精准等),官方社区也有「boss一秒死」的说法。
|
||||
- 最终攻势 / 隐秘核心的休整期和战斗中一样,**同组两人在同一个关底战场上**:你在自己的半场摆位(右侧玩家看到自己在右边,摆位左右镜像,干员相对领袖的朝向不变),队友当前的阵容显示在另一半场(只能看,随他调整实时更新);左侧成员栏里同组两人的头像带**绿框**,从回合开始一直到战斗结束。观战者查看其中一人时也会看到两人的阵容和站在关底的领袖。
|
||||
- 最终攻势 / 隐秘核心的休整期按你在**关底战场上的半场**判定可部署地块(右侧玩家左右镜像),拖动时高亮的就是可放置的格子:例如「源石流发生装置」关底图中被 1×3 橙色管子围起的地块可以部署。在最终攻势放在这些格子上的干员进入隐秘核心时会留在原位。
|
||||
|
||||
+40
-2
@@ -164,14 +164,18 @@ the old tile-key order), so a rotated layout plays the same (test/sim/facing-inv
|
||||
directions on an open field). 余 S3's fire wall runs through his tile perpendicular to his direction (his column facing
|
||||
RIGHT / LEFT, his row facing UP / DOWN; fx `firewall.axis` = `'col'|'row'`).
|
||||
`carryState: { hpPct, sp }` restores unite helpers' operators (HP ratio, and the SP = the official 技力, stored charges
|
||||
included: `unitsEnd` reports `skill.spTotal`, reset rebuilds the charges from it, and `skill.setSpTotal` sets it again after
|
||||
the `deploy` hook — PRTS "部署完成后…技力修改至与上一阶段结束时相同", so 独行 / 黄沙罗盘's deploy-time SP does not add to it;
|
||||
included: `unitsEnd` reports `skill.spTotal`; after all initial deployments and `battleStart` hooks, HP is restored
|
||||
against the new maximum and `skill.setSpTotal` restores the charges — PRTS "部署完成后…技力修改至与上一阶段结束时相同",
|
||||
so 独行 / 黄沙罗盘's opening SP does not add to it. Positive ratios are not raised to 1% or 1 HP;
|
||||
later redeploys keep those gifts); `carryState: { sp }` a board summon
|
||||
piece's SP only (PRTS "召唤物仅修改技力"). Nothing else is carried: a skill running at the end of the own combat enters
|
||||
switched off with the SP it had left — spent at its activation, 0 for a one-charge skill (`unitsEnd.skillActive` is
|
||||
reported, never carried; community report #34 — it used to restart for free).
|
||||
Timed deployment skills (`activateOnDeploy`) trigger once from the new deployment, consuming their deployment charge;
|
||||
they do not resume the previous skill state.
|
||||
The approved Egir carry policy rebuilds opening devour attributes while skipping its repeated HP loss on a living
|
||||
carry target; this prevents artificial knock-outs and revival-slot consumption before restoration. A fresh target
|
||||
without a previous state still takes that opening damage. Later combat, HP loss and redeploys follow the normal rules.
|
||||
`carryState: { down: true }` = an operator knocked out at the end of the helper's own combat (PRTS 卫戍协议/帮助 "上一阶段为
|
||||
退场状态的干员强制退场", user playtest #5 item 2): `start()` deploys it with everyone (initial `deploy` fires), then — before
|
||||
`battleStart` — withdraws it with reason `FORCED_EXIT` (constants.js `'forcedExit'`) and HP 0 (the end-of-phase HP ratio, as after
|
||||
@@ -1065,6 +1069,11 @@ has the generic spec. Summons: `battle.tokenDef(tokenId, unit)` / `battle.spawnT
|
||||
(token skill of that slot: `variants[owner].bySkill[i]`, module attributes: `.byModule[id]`). Coverage of the selectable
|
||||
skills: `node tools/kit-coverage.mjs --missing [--tier N] [--strict]`.
|
||||
|
||||
忍冬's 追凶 records the per-enemy start time and applies its arts addition in the same `damaged` callback,
|
||||
including the first instance (PRTS talent remarks; DESIGN §30.3). It does not refresh the ten-second window on
|
||||
repeated hits. Its `vulpisHunt` / `addition` tags and re-entrancy guard prevent the rider from feeding itself.
|
||||
`test/content/vulpis-first-hit.test.js` checks actual HP loss and damage events with naturally ready skills.
|
||||
|
||||
Timed deployment kits: 宴 S2 uses `bb.duration` and skill ATK mods, loses current HP once on landing, and converts normal
|
||||
physical attacks to arts only while S2 is active; S1 has no such conversion. 斯卡蒂 S2 uses its own record's
|
||||
`s.bb.duration` / `s.bb.atk`; DRE-Y revival in place does not restart it. 野鬃 S1 uses its record's `duration` /
|
||||
@@ -1486,6 +1495,11 @@ objects), and call `checkInvariants` at the end. Run: `node --test test/sim/*.te
|
||||
|
||||
## 11. Tools
|
||||
|
||||
Equipment/fortress corrections (§30.3): Kjerag Ice and Tear Gas use actual enemy damage events, including DoT,
|
||||
not attack declarations or element-gauge/HP-loss events. Fortress fallback targeting and skill automation include
|
||||
the operator's own tile after blocked/ranged candidates; only explicitly enabled skills retain melee splash.
|
||||
`performAttack` captures each shot's `fortressMelee` flag for impact resolution, independent of later target changes.
|
||||
|
||||
`node tools/simrun.mjs --mode mode_multi_normal --round 5 --stage act2autochess_m01 --lineup "角峰@9,7 隐现@10,4 艾丝黛尔*@12,5" --ascii 10`
|
||||
prints a per-unit damage/DPS/kills/heal table (+ ASCII frames: letters = operators, digits = ground enemies per tile,
|
||||
`^` = flyers, `■` = crates). `--wave <template>`, `--seed`, `--content generic`, `--hpMul/--atkMul/--speedMul`,
|
||||
@@ -1496,6 +1510,30 @@ skill × module, every bond at its threshold and at 999 layers, every leader fie
|
||||
reduced to digests in `test/golden/*.json`; `test/golden.test.js` fails, naming the scenario and the field, when a
|
||||
digest moves. A refactor must leave them unchanged; `npm run golden:update` records an intended gameplay change.
|
||||
|
||||
Cross-engine check (`tools/sim-check.mjs`, `public/dev/sim-check.html`): a browser simulates its battles and the server
|
||||
re-simulates them (SP_VERIFY, takeovers), so every engine must give the bits Node gives. `node tools/sim-check.mjs`
|
||||
builds the golden battle corpus (roster, bonds, fields, standins, diy — 267 BattleSpecs) and traces it in Node into
|
||||
`public/dev/simcheck/data/` (git-ignored, about a minute): after every tick the state (battle time, RNG state and per
|
||||
unit alive / removed / deployed, x, y, hp, atkCd, SP, the five element gauges, damage dealt / taken, healing, blocking
|
||||
count) hashed to the exact IEEE-754 bits, one hash per 30 ticks; every 30 ticks `b.snapshot()` (what viewers are sent);
|
||||
every 150 ticks a bounded traversal of unit-reachable state (depth 8; definitions, profile/kit, battle pointers, functions,
|
||||
accessors and `seq` left out); and `resultDigest(b.result())`. `/dev/sim-check.html` — on any device that reaches the server, a phone
|
||||
included — runs the corpus (or its fast subset, or a family) with the client's own loader (`loadBrowserSim`) and
|
||||
compares block by block: a battle that parts is reported with the first interval where a difference was detected, the level (the outcome, the
|
||||
snapshot, the state, or the hidden state only), and a download of that block's state vectors;
|
||||
`node tools/sim-check.mjs --diff <file>` replays the same ticks in Node and names differing recorded vector entries
|
||||
(with both values' bits). It cannot locate view-only/deep-only differences absent from those vectors.
|
||||
Special float values, including negative zero, survive JSON export. `--engines chromium,firefox,webkit [--subset fast|all|<family>]` runs the page headless after
|
||||
the trace (Firefox and WebKit through the `playwright` package when it is installed, `npx playwright install firefox
|
||||
webkit`; Chrome through puppeteer-core otherwise) and exits 1 on a difference. The tracing, comparison and page
|
||||
(`public/dev/simcheck/core.js`, `ui.js`, `node.mjs`) have no dependency on this repository; `stronghold.js` is the part
|
||||
that knows the sim. `--engines chrome` uses the local executable selected by `CHROME_PATH` (including Edge).
|
||||
The reference, corpus and dump share a content identity over scenarios, served sim/shared code and data. Dirty changes
|
||||
invalidate the reference. The page rechecks inputs before runs/dumps; `--diff` rejects stale or mismatched inputs.
|
||||
An empty/unknown selection, max-tick truncation or runtime exception is an error, never a zero-battle success.
|
||||
All-green means the recorded fields, sampled snapshots and result hashes agree: it does not prove equality of every
|
||||
internal field, event, projectile queue or rendered frame. Verification results belong to the tested revision.
|
||||
|
||||
## 12. Data notes (simdata.js)
|
||||
|
||||
Defs are normalised from data/*.json (DATA.md) with research JSON as a fallback. Chess: `stats {maxHp, atk, def, res, aspd,
|
||||
|
||||
@@ -4,6 +4,12 @@ Part of [DESIGN.md](../DESIGN.md) (the index; section numbers are global).
|
||||
|
||||
## 9. Client rendering contract (public/js/render)
|
||||
|
||||
Bond-layer audio (#482): live own preparation gains arrive as `m.layer`; the displayed battle's `layer` tuples
|
||||
play the same `bondUp` cue. A gain of several layers plays once, including gains to inactive bonds. The official
|
||||
`ON_ACT1AUTOCHESS_ADD_BOND` bank allows one sound and replaces the oldest; there is no added cooldown. Existing
|
||||
bond activation cues use this same channel. State snapshots, settlement backfill and buffered field-entry events
|
||||
do not generate layer cues. Field entry, leaving the game and muting cancel playing or still-decoding layer audio.
|
||||
|
||||
`import { createFieldView } from './render/app.js'`
|
||||
|
||||
```js
|
||||
@@ -150,3 +156,17 @@ It does not diagnose a particular user's GPU or persist a disabled renderer pref
|
||||
Community UI and recovery (§29.6): DIY reuses roster stats and skill previews; Swire's coins show current/cap. The lobby player chip opens statistics and the responsive header keeps optional controls from overlapping its title. Settlement's summary scrolls separately from Return. Failed board art can retry, and failed three.js imports use two bounded fresh URLs. Failed engine initialization can remount on online/visibility, at most twice consecutively, cleaning up each previous view; explicit fallback/2D stays selected.
|
||||
|
||||
Replacing a field renderer also resets the game screen's entered-view identity. Frames are buffered while the replacement loads; after subscribing, the local runner re-shows full current metadata/snapshot, or the server resends the watched field. Real local and server-streamed battles preserve the same simulation object and clock through recovery, including enemies spawned before the new renderer existed.
|
||||
|
||||
§30.4: the HP tower retains current HP until settlement and shows pending loss separately. Shop refresh is single
|
||||
flight per client until its promise settles (success or error); the button and R key share that state. DIY-only
|
||||
potential/cultivation changes are exportable; spectator member resolution includes the owner's DIY selection.
|
||||
Bond tooltips show banned visible members in one clamped scrollable compound box, stacked on narrow screens.
|
||||
An open list updates on member changes; long-press lists persist for reading and close on outside tap/Escape.
|
||||
The developer simulation checker and its bounded verification claims are specified in SIM §11 and history §30.5.
|
||||
|
||||
Operator attack clips play once per actual attack (§30.7), retaining their interval-based speed. A prepared wind-up
|
||||
is consumed without replay; a later queued attack may start during the previous recovery. Without another attack
|
||||
the actor returns to base/skill idle. Late operator events still start at the strike frame; no sim timing changes.
|
||||
|
||||
Connection recovery sits above the AI-away overlay and below global modals (§30.8), so a replaced session can
|
||||
be reclaimed by pointer while away. This does not change the stacking behavior of modals nested inside a screen.
|
||||
@@ -4,6 +4,15 @@ Part of [DESIGN.md](../DESIGN.md) (the index; section numbers are global).
|
||||
|
||||
## 5. Simulation (server/sim) — engine contract
|
||||
|
||||
联防 restoration (§30.13): the initial setup establishes buffs and devour attributes before restoring living
|
||||
operators' exact HP ratio and total SP; summons restore SP only. Opening Egir devour does not damage a carried
|
||||
survivor a second time. Forced-down carry stays out without spending an Egir revival; subsequent real knock-outs
|
||||
and redeploys are unchanged. No 1% / 1-HP floor is added to a positive carried ratio.
|
||||
|
||||
Expanded automatic skill areas (§30.11) include 司霆惊蛰 S2's current low-terrain flood when it strictly contains the
|
||||
initial area, 斩业星熊 S3's selectable air targets, and 予愿安洁莉娜 S3's initial 3-9 ∪ x-4.
|
||||
Permanent range extension, control/operation cooldown and targetability still apply; normal attacks are unchanged.
|
||||
|
||||
### 5.1 Battle API (implemented by the sim-core owner; consumed by match & content)
|
||||
|
||||
```js
|
||||
@@ -172,6 +181,8 @@ Profession traits (default behaviours implemented once in the engine, keyed by `
|
||||
Each domain file `server/sim/content/{tokens,bonds,garrisons,items,bands,enemies,bosses,devices,choices}.js` exports `install(battle)` (battle side; called once per Battle by `content/index.js → installContent`) and `registerMeta(registry)` (prep side; called once at server boot by `match/effectsMeta.js`, API documented in `docs/META.md`). Kits live one per file in `content/kits/ops/` (`export default { [baseChessId]: (bb, chess, def) => Kit }`), listed in `content/kits/index.js` (guide: `content/kits/README.md`). Content must be **data-driven from blackboards** (numbers never hard-coded when a blackboard key exists). Every effect gets at least one unit test in `test/content/*.test.js` using the `test/helpers/battleHarness.js` harness (provided by sim-core).
|
||||
|
||||
- kits: all 112 visible chess + hidden ones used by effects (盟约·辅助干员), default skill + talents + trait specifics; tokens. The 72 non-collaboration 6★ DIY operators include 克莱门莎 (§28.1); her launch-day provisional mechanics are local to her kit. 黍 GUA-Y and 乌尔比安 CRU-Y follow the generated module blackboards and existing module-level rules (§28.2).
|
||||
忍冬's 追凶 adds arts damage on the first qualifying instance too; the per-enemy window starts on that instance,
|
||||
and repeated hits do not extend it. The addition keeps its own tag and re-entrancy guard (§30.3).
|
||||
克莱门莎 S2 removes dead, hidden, self-bound / teleport-immune and unreachable passengers before checking new
|
||||
boarding in the same tick. Each released passenger returns its current weight to the cabin's remaining budget
|
||||
and frees its slot (§28.27); neither corpses nor failed carries reserve capacity.
|
||||
@@ -233,3 +244,14 @@ tile and attack-reach checks. Hand/temp rows, empty halves in single-player mode
|
||||
The general `onOwnBoard`/`onFieldBoard` contracts, other movement, summons and preparation placement remain unchanged.
|
||||
|
||||
香槟炸弹 also rejects ordinary allied auras and inspiration as a device, through its shared internal selection barrier (§29.11). This does not isolate other unhealable summons or alter its detonation.
|
||||
|
||||
§30.3 corrections: fortress targeting is blocked → ordinary range → own tile (selectable ground targets only).
|
||||
Automatic skill checks include that extra tile. Melee attacks are single-target unless the skill explicitly gives
|
||||
melee splash (Horn S2). Each shot retains its launch-time melee mode while flying. The bounty catapult's normal
|
||||
triple attack splashes at radius 1.5; 0.5 belongs to its 入戏 override. Clementia S3 accepts enemy erosion bursts only.
|
||||
Kjerag Ice and Tear Gas proc on actual carrier damage to enemies, including DoT/skill/splash; elemental gauge fill,
|
||||
HP loss, bare attack events and zero damage do not qualify. These changes do not alter other items' attack hooks.
|
||||
|
||||
Xi alone opts into hostile selection immunity during its ten-second post-rebirth invincibility (§30.8).
|
||||
The generic `invulnerable` flag remains damage protection only; other rebirth kits retain their existing choices.
|
||||
Presence-only and SP-only skill triggers are not suppressed merely because their enemies are unselectable.
|
||||
+10
-1
@@ -27,7 +27,7 @@ LOBBY(room) → INFO_CHECK (co-op 25 s; solo and any single-human match untimed
|
||||
PRTS "上一阶段为退场状态的干员强制退场", its full redeploy timer — confirmed by the user (§19.3))
|
||||
SETTLE (LP −min(leaks,10) per player (unite survivors to their source); eliminations; layer gains applied; coins; broadcast;
|
||||
after a 联防 the outcome and every player's charge ride the SETTLE m.public as `uniteResult`, GitHub #235)
|
||||
R14 FINAL_ASSAULT (merged team LP; pairs by seat; shared boss pool; 120 real s countdown, no hard stop; overtime −1 team LP per
|
||||
R14 FINAL_ASSAULT (merged team LP; random pairs fixed for this match; shared boss pool; 120 real s countdown, no hard stop; overtime −1 team LP per
|
||||
real s after 120 real s, or 150 with an AI teammate at fight start (§29.1, m.public.overtimeAt); no layer gains; team LP 0 ⇒ defeat at once (PRTS 直接失败),
|
||||
pool 0 ⇒ victory — the first end the server registers decides, §20.5)
|
||||
R15 HIDDEN_CORE (if difficulty ≥ NORMAL and Σ activated layers > 350 solo / 1200 co-op and team LP > 1)
|
||||
@@ -113,6 +113,9 @@ Official rule (bwiki 盟约, 更新公告 5114): before a match the player canno
|
||||
**UI:** a 干员调配 screen reachable from the lobby, room and briefing (INFO_CHECK): the roster is one list, a row per operator with aligned columns under a head row — portrait / name / bonds (opens the detail), the skills and the elite's modules to tap (不装备 first; the quick choices of PR #301 by @farridge, laid out as one list instead of its three columns of cards, the owner's call of 2026-10-08), the 潜能 / 练度 selects (`screens/loadout.js RosterRow`, `screens/cultivation.js`); the detail beside it (below 1000 px wide it slides over the list, a quick choice keeps the list) opens with the 潜能与练度 section (潜能 1–6, the four official 练度 tiers with their effect texts); the detail then shows the operator's 特质 — the in-match `GarrisonBlock` / RichText of the form its 普通 / 精锐 skill toggle shows, triggers such as 「<进入休整期时>」 kept (0.2.2, PR #301 by @farridge); filter by tier/bond/class, per chess choose skill (icon, name, SP info, desc at Lv4 and Lv7) and elite module (official type icon from the local-client art when extracted (§13), else a lettered tile; name/type, stat bonus, trait/talent changes), 恢复默认, persisted; a 局内数值 section between the skills and the modules (普通 / 精锐 toggle, 精锐 first) draws the detail card's own stats block, 特性 and 天赋 for the chosen skill / module (§22.16); the chosen skill/module shown on shop cards and in the detail panel (a teammate's unit — 前往查看 in prep, 联防 / 最终攻势 fields, an observed battle — shows **its owner's** skill/module from its UnitInfo `skillIndex` / `moduleId`, `gameLogic.js unitLoadout`) — which also shows the stats, 特性, talents and attack range the unit fights with (`shared/loadoutRecord.js` `loadoutRecord` / `attackRangeGrid`, the same composition the sim's `getChess(id, loadout)` uses; the deploy wheel's range preview too) — the range it is deployed with: a selected passive range skill (引星棘刺 S3 3-9) and the 特性's permanent 攻击距离 (信仰搅拌机 SPT-Y +1) included, over all 1284 loadouts equal to the battle's range at deployment; in battle and prep the card draws the live `range` (§21.16). In battle the renderer plays the equipped skill's own Spine clip and ON_SKILL_START sound (`UnitInfo.skillIndex`; `data/assets.json` lists icons, clips and sounds for every skill index).
|
||||
|
||||
**导出 / 导入 a loadout:** 导出 hands the current loadout out as a versioned envelope `{ kind: 'stronghold.loadout', v, exportedAt, count, entries, ops }` (`ops`: the 潜能 / 练度 settings, 0.2.2 — an import without them leaves the current settings alone) — copied through `ui/clipboard.js copyText` or downloaded as a file. 导入 accepts that envelope, the stored `{ v, entries }` form and a bare `{ [chessId]: { skill, module } }` map (serialised text too), and refuses another tool's `kind`, junk, an empty result and a **newer** `v` (`parseImport` — a newer payload is never mis-read). Both go through `loadoutSync.applyLoadoutEntries` → `sanitizeEntries`, so a preset from another build never sends the server an entry it would refuse, an import that keeps nothing changes nothing, and the result is reported as N imported / M not (`ui/loadoutModel.js`, `screens/loadout.js`).
|
||||
Export remains available for non-default `ops` alone, including operators outside the normal roster. The roster's
|
||||
adjusted count and reset scope stay limited to its own operators; the DIY export still carries picks only.
|
||||
|
||||
**干员持有 (0.2.0 补位):** the overlay's second tab marks operators as not owned (the 55 NORMAL chess; per-browser `sp.pref.ownership` = `{ v, notOwned }`, synced as `room.ownership { notOwned }` by the same sync engine as the loadout, `ui/loadoutSync.js installPrefSync`; 导出 / 导入 as `{ kind: 'stronghold.ownership', v, exportedAt, count, notOwned }`). A not-owned chess fights as its official stand-in with the backup skill / module — the loadout never applies to it ("对于补位干员其技能不可更改") — and is shown as the stand-in wherever the player's copy appears (shop / reward cards, hand and 临时整备区, board, detail card, result lineup, a teammate's scouting and bond popups: portrait, name, model, with a small 「替补」 mark; the owner's recall of the official mode, 2026-10-06), while its bonds, 特质, tier, price and merge stay the chess's; the 0.2.0 补位 design subsections have the rules and sources.
|
||||
**自选编队 (0.2.0):** the overlay's third tab fills the four DIY slots (5阶 ×2, 6阶 ×2) with an owned 6★ outside the chess pool (any of its three skills, any module of its elite form but a 集成战略 one) or a prototype (its locked skill / module); only operators with a kit are offered (`welcome.diyKitted`). Per-browser `sp.pref.diy` = `{ v, picks }`, synced as `room.diy { picks }` by the same sync engine; 导出 / 导入 as `{ kind: 'stronghold.diy', v, exportedAt, count, picks }` (`ui/diyModel.js`, `screens/diy.js`). In the match a slotted piece is the operator for its player (name, art, class, bonds from its factions, no 特质, the pick's skill and module; the slot's tier, price and merge), sold only in that player's shop from the slot's 调度中心 level with its own stock; the shop / reward / detail cards and the own pieces carry a 「自选」 badge (`ui/gameLogic/diy.js`); the 0.2.0 自选编队 design subsection has the rules and sources.
|
||||
|
||||
@@ -141,3 +144,9 @@ before mutation; data preparation failure leaves the old opening intact. This is
|
||||
mode rule. Unrelated result-screen changes from PR #408 are not included.
|
||||
|
||||
The shared DIY detail preview (stats, range, trait, talents, potential, cultivation and matching normal/elite skill descriptions) follows roster loadout resolution. Jessica shield placement is limited to her four orthogonal neighbors. The two Ptilopsis prep-gift copy exceptions are defined in §29.3 and META; no generic change to all copied conditions is implied.
|
||||
|
||||
Shared-stock corrections (§30.1–2): fixed `SERVER_GAIN_EQUIP` gifts still occupy ordinary/advanced 1/2 copies but
|
||||
may exceed capacity; `requirePool:false` bypasses equipment limits only for these fixed families. Already displayed
|
||||
operator shop and reward offers remain valid after exhaustion and record the deficit. Future rolls exclude empty
|
||||
stock; selling repays the deficit first. Item shop/reward claims and 整备 remain stock-limited. Rockrock and Flametail
|
||||
use the measured weighted subsets described in DATA and §30.2.
|
||||
@@ -40,6 +40,9 @@ S→C:
|
||||
interpolate linearly; nothing is inferred from the attack animation.
|
||||
- `b.ev` — `{ fieldId, ev: [ ... ] }` event tuples: `['spawn', UnitInfo]`, `['atk', srcId, tgtId, projKind]`, `['dmg', tgtId, amount, type]`, `['heal', tgtId, amount]`, `['skill', id, on:0|1]`, `['die', id, reason]` (reason `'killed'`, `'retreat'`, `'expired'` …; only `'killed'` plays an operator's knock-down sound), `['status', id, key, on]`, `['fx', kind, x, y, extra]` (`'hitCap' {id, n}` = a cancelled 限伤 hit, drawn as nothing, §20.12; `extra.form` = the unit's model form from then on (an enemy's mode, a 傀儡师's 替身 §22.11) — `shared/protocol.js fxForm`, state like a spawn: never dropped by the client, §21.4), `['layer', playerId, bondId, n]`, `['bounty', playerId, coins]`, `['deploy', id]`
|
||||
- `m.toast {kind, text}` · `m.ticker {text, id, type, priority, playerId}` (the strip plays the highest priority first, §21.10) · `m.emote {playerId, id}` · `m.result {...}`
|
||||
- `m.layer {playerId, bondId, add}` — a positive prep layer gain, sent only to that player in ROUND_START / SP_DRAFT /
|
||||
PREP for audio feedback. No replay on reconnect/resync and no settlement backfill; battle audio uses `layer` tuples
|
||||
from the displayed field. Older clients can ignore this notification without changing gameplay.
|
||||
- `m.unitStats {seq, round, units: [unitStatsEntry]}` — the answer to `g.unitStats` (`seq` echoed): every own board operator / summon by uid with `{id, uid, defId, hp, alive, maxHp, atk, def, res, interval, blockCnt, moveSpeed, range?, base: {…same}}` and `dir?` (shared/protocol.js `unitStatsEntry`; `range` = an ally's live range grid, facing RIGHT, never a target-selection grid, §21.16; `dir` = the unit's facing now, UP|RIGHT|DOWN|LEFT — the snapshot tuples carry none and UnitInfo `dir` is the facing at send time — which the detail card's range overlay rotates by, GitHub PR #281) as its next battle starts (§18.5)
|
||||
|
||||
`UnitInfo = { id, kind, side, ownerId, defId, name, tier, golden, spine, avatar, x, y, facing, dir, maxHp, skillIndex?, moduleId?, items?, form? }` (`dir` = the ally's deploy direction; the renderer picks the model (Back for UP, mirrored for LEFT) and the ground wedge from it; `skillIndex` = the ally's equipped skill (§16): the renderer plays that skill's Spine clip (`anims.skills[i]`) and the audio its own ON_SKILL_START sound; `moduleId` = an elite ally's equipped module (uniEquipId | 'none'); `items` = an ally operator's equipped item ids (absent without any; never on enemies or summons): the bond popup lists a 变形同构体 wearer from them and the detail card shows its 同构 chip and 装备 (§21.11); all three also on the prep-scouting `m.field` units (`Match.prepFieldMeta`, the held pieces included), so a teammate's unit shows its owner's loadout in the detail card and its equipped items as item pips on the unit (prep surfaces; user playtest #2 item 3); `form` = the unit's current model form (an enemy's mode §21.4, a 傀儡师's 替身 §22.11; a view built mid-battle starts in it)).
|
||||
@@ -140,3 +143,15 @@ Optional `coins: [[id, balance, cap]]` is an integer skill-currency readout (§2
|
||||
Preparation state carries read-only `prepMapChars` for 外勤医疗. Boss-mate and scouting metadata include them in
|
||||
displayed field coordinates. Draft cards expose optional `soldOut` when equipment stock is unavailable; the client
|
||||
disables picking and the server checks again before consumption.
|
||||
|
||||
`m.public.bossPairs: [[playerId, playerId?], …] | null` publishes the preparation pairing, first member left and
|
||||
second right. It is drawn once per match and retained for Hidden Core; intact pairs survive departures, singles
|
||||
pair up. Clients use it for preparation camera/placement/team frames; only older servers lacking the field use
|
||||
the legacy seat-order fallback. Viewing or reconnecting never draws a new pair.
|
||||
|
||||
[ASSUMED] Touch's confirmed initial team grant persists for this match after its holder is eliminated or leaves.
|
||||
The maintainer explicitly approved retaining this policy on 2026-10-12; its official-game lifetime remains unverified.
|
||||
The preparation medic and future battle's medic/Touch use the same entitlement; the receiving player must still be
|
||||
alive. A mere draft focus grants nothing; another match starts without it. Only `band_amedic` is retained in
|
||||
`contentInfo.matchBands`; `teammates` and other team strategies still filter eliminated players. The official text
|
||||
and initial/unlimited-round data do not explicitly settle the holder-elimination case (§30.14).
|
||||
@@ -0,0 +1,273 @@
|
||||
# DESIGN §30 — 0.2.5-dev
|
||||
|
||||
Part of [DESIGN.md](../DESIGN.md). Community reports after 0.2.4.
|
||||
|
||||
## 30. Community follow-up
|
||||
|
||||
Unreleased. Sources and decisions below describe the candidate behavior, not a published release.
|
||||
|
||||
### 30.1 Fixed gifts and already displayed operator offers
|
||||
|
||||
Reports #488/#491/#495, PR #496 by @2321Robin, and the owner's Muelsyse/Yela report: the shared equipment
|
||||
cap added in 0.2.4 incorrectly prevented fixed acquisition gifts. [路标档案馆:路标月报#2](https://www.bilibili.com/video/BV1eLXXBqEgF/)
|
||||
states both that equipment from any source occupies stock and that these operators' fixed gifts are unlimited.
|
||||
The owner confirmed on 2026-10-11: gifts still occupy stock, but exhaustion must never prevent the gift.
|
||||
|
||||
`GameData.isUnlimitedGiftItem` derives the families from `SERVER_GAIN_EQUIP`. The actual gift passes
|
||||
`requirePool:false` through `effectsMeta` to `acquireItem`; only those families bypass availability. Ordinary and
|
||||
advanced copies still count as 1/2. This covers Carnelian, Beeswax, Muelsyse, Kjera and Swire, and the same fixed
|
||||
family awarded by the Damazti strategy. It does not make every strategy's equipment unlimited. Shop and item
|
||||
reward purchases, random grants and 整备 upgrades keep their availability checks. When ownership exceeds the cap,
|
||||
removing one copy need not immediately reopen stock. The proposed PR's zero-occupancy model was not adopted.
|
||||
|
||||
#498: the same video's approximately 2:50–2:57 example describes nine owned 溯光星源 plus one
|
||||
already displayed card in each of four shops, allowing thirteen owned copies. Shop operator purchases therefore
|
||||
do not recheck availability; `acquireChess` records the full deficit and later rolls still exclude exhausted stock.
|
||||
The owner explicitly extended this behavior to already displayed **operator reward** offers; that extension is a
|
||||
maintainer decision, not footage directly establishing every reward type. Item purchases/rewards remain bounded.
|
||||
Funds, full-hand checks, per-offer sold flags, merge accounting and selling returns retain their ordinary rules.
|
||||
|
||||
Tests: `test/match/community-round30.test.js`, `shared-stock.test.js`, `garrisons_meta.test.js`.
|
||||
Normative rules: META shared inventory and helper contract; design/match economy.
|
||||
|
||||
### 30.2 Measured acquisition subsets
|
||||
|
||||
PR #497 by @2321Robin, same original research video's rule table: Rockrock's subset weights are ordinary hammer
|
||||
10; tremble/undying/haste/burn hammer 2 each; limited accelerator 1; shield drone 4; laser emitter 4. Flametail's
|
||||
subset is Wild Mane 10, Ashlock 10, Fartooth 3. These are weighted subsets, still constrained by shared stock.
|
||||
The generator owns these tables; `data/choices.json` is regenerated offline. Tests cover the table and exhausted
|
||||
eligibility rather than asserting that subset draws ignore ownership.
|
||||
|
||||
### 30.3 Damage and target-selection corrections
|
||||
|
||||
- Clementia S3's erosion-burst listener now requires an enemy target. The generic targetability helper does not
|
||||
check allegiance, so a friendly erosion burst previously scheduled a shot. Enemy bursts retain the same behavior;
|
||||
the mode's existing boss erosion immunity is unchanged.
|
||||
- Horn follows [PRTS 号角](https://prts.wiki/w/号角): blocked targets first, ordinary ranged targets next, then a
|
||||
selectable ground target on her own tile. Her skills' automatic target check includes that tile. Other adjacent
|
||||
blind tiles do not become valid targets. Ordinary/S1/S3 melee attacks are single-target; S2 explicitly retains
|
||||
melee splash. Each shot captures its melee mode, so switching targets cannot remove splash from a shell in flight.
|
||||
- The bounty [自制投石机](https://prts.wiki/w/自制投石机) has normal splash radius 1.5 and three hits. The old
|
||||
radius 0.5 came from its 入戏 override, not its ordinary attack. Tests cover adjacent/diagonal allies and an outside
|
||||
target. No claim is made here about unrelated attack cadence.
|
||||
- PR #502 by @Xinglan233: Vulpisfoglia's first qualifying damage instance marks the enemy and also deals 追凶's arts
|
||||
addition. Repeated damage does not extend the original window. Source: [PRTS 忍冬](https://prts.wiki/w/忍冬).
|
||||
- #489: [PRTS 盟约记录](https://prts.wiki/w/卫戍协议:盟约_下半/PRTS盟约记录) corrects both Kjerag Ice and Tear Gas
|
||||
from “攻击时” to “造成伤害时”. Only these handlers move to actual carrier damage, including DoT, skill and splash
|
||||
instances; bare attack events, elemental gauge fill, HP loss, zero damage and friendly targets do not trigger them.
|
||||
Existing probabilities/durations remain data-driven. Regression uses real Ascalon poison while she is disarmed.
|
||||
|
||||
Tests: `community-round30.test.js`, `item-damage-procs.test.js`, `vulpis-first-hit.test.js` under test/content,
|
||||
plus existing item/operator/fortress suites. Normative rules: SIM and design/engine.
|
||||
|
||||
### 30.4 Client information and input
|
||||
|
||||
- PR #503 by @Xinglan233: a loadout containing only operator potential/cultivation changes is exportable.
|
||||
- PR #505 by @Xinglan233: spectator `ownerOps` includes resolved DIY selection, so bond members have correct identity.
|
||||
- #479 / PR #504 by @robll-v1, owner approved: before settlement, the HP tower shows the current HP and a separate
|
||||
pending-loss marker; settlement updates the number. This supersedes the earlier live pre-deduction display choice.
|
||||
- #501 / PR #507 by @robll-v1, owner approved: a refresh request in flight disables another button/R request until
|
||||
it settles, including errors. This is a client interaction guard, not server-wide request idempotency.
|
||||
- #484 / PR #494 by @YuriRestia, owner approved: bond tooltips list this match's banned visible members. Main text
|
||||
and list share one viewport-clamped, scrollable container; narrow screens stack the sections. Dynamic member
|
||||
changes update an open tooltip even if the displayed count stays equal. Long-press lists persist for reading and
|
||||
close on outside tap or Escape; ordinary tooltips keep their short behavior.
|
||||
- PR #490 by @D-Roote: Korean UI corrections; the obsolete 3D failure key from the proposal is excluded in favor of
|
||||
the current recovery message. PR #499 by @YuriRestia: English Victoria text explicitly applies its bonus per item,
|
||||
through a narrow correction layer in the translation generator, retaining all placeholders.
|
||||
|
||||
Tests: refresh unit/E2E, loadout export E2E, match-info, watch-bonds, round30-tools E2E and i18n checks.
|
||||
Normative rules: PLAYING, I18N and design/client.
|
||||
|
||||
### 30.5 Developer simulation checker
|
||||
|
||||
PR #492 by @Cloudnyco, owner approved: `/dev/sim-check.html` replays generated BattleSpecs with the real browser
|
||||
loader against Node traces. The corpus is the golden battle families, excluding full matches. The CLI generates
|
||||
local ignored reference data and can run browser engines or compare an exported state block.
|
||||
|
||||
Review repairs: reject unknown/empty selections and unfinished runs; recover controls after start/step/result/dump
|
||||
errors; preserve negative zero and other special floats across JSON; verify shared content identity for specs,
|
||||
reference, runtime and data; reject stale inputs; escape reference text; allow long mobile result lists to scroll.
|
||||
Reports state the first **detected interval**, not an exact first divergent frame. State dumps can diagnose only
|
||||
their recorded fields; snapshot/deep-only differences may not expose a differing field. The bounded unit-state
|
||||
traversal and sampled snapshots do not prove equality of all memory, events or rendered frames. See SIM §11.
|
||||
|
||||
### 30.6 Rechecked reports without a gameplay change
|
||||
|
||||
Real browser loading verifies seven different Yan operators plus ordinary/elite Muelsyse carrying the converter
|
||||
and Yan item: count 9, tier 3 and two actual 炎佑. All 36 normal/advanced conversion-item pairings retain battle
|
||||
membership. The preparation/combat conversion feedback was not reproduced in these cases; this does not exclude
|
||||
an unreported configuration. Normal/hidden Helm missile tests confirm the existing shell and its 3×3 stun.
|
||||
|
||||
Lost Colossus and Zaaro exist in the source catalog, but the fixed bounty draw groups remain based on the earlier
|
||||
22-match evidence. The owner chose to retain those groups until direct grouping evidence is found; catalog
|
||||
presence alone is insufficient to assign a group or probability. No AI formation change from #452, WebRTC #487
|
||||
or built-in HTTPS #478 is included.
|
||||
|
||||
### 30.7 One visual clip per operator attack
|
||||
|
||||
#506: a single attack formerly kept an operator's animation looping for 1.4 attack intervals, allowing a second
|
||||
visual swing without another simulated attack. The owner approved playing one clip per real attack, retaining
|
||||
operator rhythm scaling, enemy speed rules, skill selection and damage timing. A queued wind-up can restart during
|
||||
the preceding attack's recovery; its actual attack consumes that preparation rather than replaying the clip.
|
||||
After recovery the actor returns to its base/skill-idle clip. With no look-ahead, operators still start at the strike
|
||||
frame: completing a late wind-up would delay the visual hit, so that separate policy is deliberately unchanged.
|
||||
Tests cover single/continuous fast attacks, real Provence metadata, skill idle and attack interpolation.
|
||||
|
||||
### 30.8 Xi invincibility and session recovery
|
||||
|
||||
#510: [PRTS “自在”](https://prts.wiki/w/“自在”) specifies ten seconds of invincibility after its five-second rebirth;
|
||||
the linked status also excludes hostile selection. Xi opts into `reborn.invincibleUntargetable` for that same
|
||||
window. The general `invulnerable` flag and other enemies' rebirth policies are unchanged. Attacks and
|
||||
target-requiring automatic skills wait; presence-only `SKILL_RANGE` and SP-only skills retain their existing
|
||||
trigger rules. In-flight damage and elemental fill still deal zero during invincibility. Tests cover all four
|
||||
trigger types, projectile arrival and resumed attacks after expiry.
|
||||
|
||||
PR #511 by @RainoutOvO: the connection recovery banner now sits above the AI-away overlay, so “continue here”
|
||||
remains clickable after another page replaces the session. It remains below global modals. Tests use actual
|
||||
pointer hit-testing and clicks, including a global confirmation dialog over the recovery button.
|
||||
|
||||
### 30.9 Golden changes
|
||||
|
||||
Before the follow-up changes below (§30.11 onward), all 287 scenarios were regenerated, with no additions or deletions;
|
||||
45 differed from 0.2.4. This table records that initial candidate. Follow-up changes are recorded separately below.
|
||||
Each cause below was checked by an isolated counterfactual rerun: reverting the named change or combination
|
||||
restores the old digest exactly. Shared RNG and later economy/target choices can amplify a local correction.
|
||||
The two co-op paths involving Rockrock can mask a damage-item effect when each is reverted alone; their combined
|
||||
rollback, not mere operator presence, establishes the attribution.
|
||||
|
||||
| Cause / combination | Changed scenarios |
|
||||
|---|---|
|
||||
| catapult normal splash radius | `roster-013`, `standin-06` |
|
||||
| catapult normal splash radius; Kjerag Ice / Tear Gas damage triggers and resulting RNG order | `roster-040` |
|
||||
| Kjerag Ice / Tear Gas damage triggers and resulting RNG order | `bond-maniShip-high`, `boss-boss_2-pair`, `boss-boss_3-pair`, `boss-boss_5-pair`, `coop2-ABYSS-10-boosted`, `coop2-NORMAL-70-diy`, `hidden-boss_8-pair`, `hidden-boss_9-solo`, `roster-005`, `roster-012`, `roster-019`, `roster-033`, `roster-047`, `solo-ABYSS-1`, `solo-FUNNY-1`, `solo-FUNNY-2`, `solo-HARD-1`, `solo-NORMAL-1`, `solo-NORMAL-2`, `standin-07` |
|
||||
| Kjerag Ice / Tear Gas damage triggers and resulting RNG order; Fortress own-tile targeting / melee splash | `coop2-HARD-4` |
|
||||
| Kjerag Ice / Tear Gas damage triggers and resulting RNG order; Fortress own-tile targeting / melee splash; Rockrock acquisition-subset weights; Vulpisfoglia first-hit addition | `coop3-ABYSS-5`, `coop4-ABYSS-7` |
|
||||
| Kjerag Ice / Tear Gas damage triggers and resulting RNG order; Rockrock acquisition-subset weights | `coop2-NORMAL-8-serverrun`, `coop4-FUNNY-6` |
|
||||
| Kjerag Ice / Tear Gas damage triggers and resulting RNG order; Rockrock acquisition-subset weights; Vulpisfoglia first-hit addition | `coop2-NORMAL-1-coverage-standins`, `coop2-NORMAL-3` |
|
||||
| Kjerag Ice / Tear Gas damage triggers and resulting RNG order; Vulpisfoglia first-hit addition | `coop2-NORMAL-5-coverage-diy`, `roster-026` |
|
||||
| Fortress own-tile targeting / melee splash (including Horn and Ashlock) | `boss-boss_5-solo`, `roster-004`, `roster-023`, `roster-032`, `roster-034`, `roster-043`, `solo-HARD-9-boosted` |
|
||||
| Vulpisfoglia first-hit addition | `bond-soloShip-low`, `bond-yanShip-low`, `roster-007`, `roster-009`, `roster-039` |
|
||||
| Xi post-rebirth hostile selection immunity | `roster-011` |
|
||||
|
||||
The fixed-gift, displayed-offer overdraw, Flametail-subset and Clementia changes do not move these corpus
|
||||
digests individually; their dedicated regressions cover the reported cases. UI, translation and developer-tool
|
||||
changes do not alter simulation rules. The 140 DIY-only corpus cases retain their previous digests.
|
||||
|
||||
### 30.10 Bond-layer audio
|
||||
|
||||
#482: the client only sounded an increase in active bond count, missing actual layer gains in prep and battle.
|
||||
The official audio table maps `ON_ACT1AUTOCHESS_ADD_BOND` to `act1autochess_b_ui_buffup`, with
|
||||
`maxSoundAllowed=1` and `popOldest=true`. The supplied [match recording](https://www.bilibili.com/video/BV1VxwNzZEqK/)
|
||||
also contains the cue around Matterhorn acquisition and battle layer gains. The maintainer approved that bank's
|
||||
single-channel replacement policy with no extra cooldown; the recording alone does not settle every timing edge.
|
||||
|
||||
Own live prep gains now send an ephemeral `m.layer`; the displayed battle's existing `layer` tuples use the same
|
||||
audio channel. One multi-layer gain is one cue, inactive bonds included; capped/zero gains are silent. New cues stop
|
||||
the previous source and invalidate its pending decode. Field entry, exit and mute cancel pending/playing cues.
|
||||
Snapshots, resync and settlement bookkeeping do not synthesize gains. Existing activation audio shares the channel.
|
||||
The change does not affect layer amounts, simulation events or RNG. Tests cover server unicast/phase/cap behavior,
|
||||
asynchronous replacement and cancellation, muted/missing audio and late field entry.
|
||||
|
||||
### 30.11 Automatic skill-area follow-up
|
||||
|
||||
Reports described Kroos the Keen Glint and Degenbrecher waiting for enemies to reach a smaller range. With full SP,
|
||||
normal/elite forms and all four facings, Kroos S1/S2 cast at the outer normal range and Degenbrecher S2/S3 cast in
|
||||
their own skill range outside normal attack range. The supplied still image does not establish SP, cooldown or
|
||||
the running client version, so those reports are not marked fixed. The documented operation cooldown and Kroos's
|
||||
normal-attack timing still apply.
|
||||
|
||||
The broader real-record audit covered 1,850 manual-skill configurations and 2,232 directional trigger cases.
|
||||
It found three independent omissions under the previously approved expanded auto-cast policy:
|
||||
|
||||
- 司霆惊蛰 S2 has a terrain-derived range with no static rangeId. Its extra trigger now uses the same low-tile
|
||||
flood and permanent range extension as the running skill, only when it strictly contains the initial range.
|
||||
High ground, field bounds, normal attacks and its SEARCH rule remain unchanged.
|
||||
- 斩业星熊 S3 can attack flyers while active, but its trigger inherited the inactive ground-only profile. Its
|
||||
actual expanded area now accepts selectable flyers, like the existing 陈 S3 exception.
|
||||
- 予愿安洁莉娜 S3's opening area is 3-9 plus the surrounding x-4. Its ACTIVE_RANGE trigger now includes that same
|
||||
union, without extending it to a future flight destination or changing its anchored post-move attack area.
|
||||
|
||||
These changes preserve SP, control and operation cooldown gates and do not admit stealth/sleep/untargetable enemies
|
||||
to an ACTIVE_RANGE condition. Tests cover all DIY forms, facings, ground/air targets, permanent extension and gates.
|
||||
|
||||
### 30.12 Random boss partners, retained for Hidden Core
|
||||
|
||||
The maintainer requested random pairing each match and explicitly chose to retain partners for the hidden boss.
|
||||
A separate seeded shuffle assigns pairs and left/right sides before Final Assault preparation. The same plan
|
||||
drives prep previews, legal deployment maps and the actual battle. Hidden Core retains it; a departure keeps intact
|
||||
pairs and pairs up the remaining single players. A new Match starts a fresh draw; a repeated seed remains reproducible.
|
||||
|
||||
`m.public.bossPairs` supplies the actual plan to the client camera, placement and green partner frames; seat-order
|
||||
inference survives only as compatibility with older servers missing this field. The audit checks coverage, saved
|
||||
pair stability and actual fields instead of recomputing seat pairs. Lowest-seat connected-human authority and
|
||||
other-pair watch restrictions are unchanged. Regression includes 2/3/4 players, departures, hidden continuation,
|
||||
mirror coordinates, reconnects and real-browser prep-to-battle views.
|
||||
|
||||
### 30.13 联防 HP/SP restoration and Egir opening devour
|
||||
|
||||
The report was reproduced through normal BattleResult → `uniteBattleOpts` → a new battle: an Egir survivor's
|
||||
carried HP was charged for opening devour again. Some survivors died and revived at full HP, consuming a revival
|
||||
slot and resetting SP; others lost HP twice. Two 1% clamps also raised legal low HP, and a 1-HP floor changed the
|
||||
ratio when the new maximum was smaller.
|
||||
|
||||
The maintainer approved reconstructing Egir marks/base-ATK/block attributes without repeating opening devour HP
|
||||
loss on a carried survivor. Deployment and battle-start effects establish the new stats, then the living operator's
|
||||
exact positive HP ratio and total SP are restored. Forced-down carry still contributes to the attribute chain and
|
||||
stays down without spending a revival slot. Summons carry SP only; previous active skills are not resumed. Normal,
|
||||
boss and fresh no-carry units keep their usual devour damage, and later knock-outs/redeploys work normally.
|
||||
|
||||
[PRTS 帮助](https://prts.wiki/w/卫戍协议/帮助) specifies restoring HP ratio and SP after deployment. The detailed
|
||||
suppression of repeated opening death/revive effects is the approved implementation of that contract, not a claim
|
||||
that the wiki documents each internal callback. Tests include real carry construction, prior full-health food that
|
||||
would otherwise die anew, remaining revival slots, values below 1%/1 HP, and ordinary/boss behavior.
|
||||
|
||||
### 30.14 Touch's team medic after its holder is eliminated
|
||||
|
||||
On 2026-10-12 the maintainer explicitly approved retaining the implementation, including both elimination and
|
||||
voluntary departure after a confirmed selection. This resolves the local policy choice, not the official-evidence gap.
|
||||
|
||||
The observed loss happens in newly constructed fields and the next preparation, not by removing an already spawned
|
||||
medic from a teammate's ongoing battle. Both prep and battle eligibility formerly searched only living holders.
|
||||
|
||||
[ASSUMED] A confirmed Touch selection grants the team medic for this match even after that player is eliminated
|
||||
or leaves. Official data marks the effect initial and unlimited in rounds and describes a medic on every player's
|
||||
field, but does not explicitly document the holder's elimination. This local candidate adopts the persistent grant
|
||||
under the maintainer's request to make evidence-based local choices pending review. A draft focus is insufficient;
|
||||
a confirmed choice followed by departure counts. New matches have no inherited grant. Recipients must be alive.
|
||||
|
||||
Only Touch is retained in `contentInfo.matchBands`; ordinary teammate contexts and other eliminated strategies
|
||||
stay excluded. Prep still displays the reserve medic, with the battle replacing it by Touch at the existing elite
|
||||
threshold. Tests cover LP elimination, departure, both medic variants, draft confirmation, fresh matches and the
|
||||
normal/unite/boss/hidden BattleSpec paths.
|
||||
|
||||
### 30.15 Other reports rechecked without changing their rules
|
||||
|
||||
- 联防 order: [PRTS 帮助](https://prts.wiki/w/卫戍协议/帮助) includes downed operators in deployed headcount. The
|
||||
implementation reads deployed count, not deployment capacity. Nine deployed with casualties may rank ahead of
|
||||
eight survivors; the active-bond and layer tie-breaks retain their existing documented uncertainty.
|
||||
- 乌尔比安 S3: [PRTS 乌尔比安](https://prts.wiki/w/乌尔比安) gives the next tile beyond an occupied anchor landing
|
||||
as a fallback before his own tile. The pictured report alone does not contradict this; his existing own-board,
|
||||
occupied/downed reservation and return rules remain unchanged.
|
||||
- 叙拉古: fixed-layer cases last exactly `32 + 0.4L` game seconds, which is half as many real seconds at 2×. The
|
||||
formula tooltip reads current layers while an already deployed buff retains its initial duration/ASPD; a new
|
||||
deployment reads the new layers. No direct source settled whether official in-battle gains should extend the old
|
||||
buff, so that separate uncertainty is retained; durations are not doubled globally.
|
||||
- 塑心: hidden-layer bonds can still receive layers under the documented PRTS rule (§25.21.6). The old exclusion
|
||||
was specific to 余's strategy (§27.21), not a global ban. Selecting the highest hidden layer count is retained.
|
||||
- Push/pull: 176 force/mass cases and real Degenbrecher boss cases did not reproduce a weight bypass. Mode leaders
|
||||
retain their existing displacement guard; an ordinary `rank=BOSS` enemy is not automatically the same as a
|
||||
protected mode leader. Weight, static-body and immunity checks remain. 余 S2 can teleport 铳 in one step under its
|
||||
separate teleport rules; this is a possible source of the reported movement, not an identification of the screenshot.
|
||||
Boss trigger-edge tests distinguish a large rendered model from its actual hit area; the still image alone does
|
||||
not establish a missed auto-cast.
|
||||
|
||||
### 30.16 Follow-up golden changes
|
||||
|
||||
All 287 scenarios were recomputed after §30.11–30.14. Only five match digests change from the preceding candidate:
|
||||
`coop2-NORMAL-3`, `coop4-FUNNY-6`, `coop2-ABYSS-10-boosted`, `coop2-NORMAL-70-diy`, and
|
||||
`coop2-NORMAL-5-coverage-diy`. In each, restoring only the old ordered boss pairing in an isolated process reproduces
|
||||
the preceding digest exactly; the changed partner/side also changes preparation choices and later combat totals.
|
||||
All five already differed from 0.2.4, so the final release-relative total remains 45 scenarios (§30.9 plus these
|
||||
additional pairing effects). There are no new corpus cases or removals. The other follow-up fixes do not move this
|
||||
corpus; their dedicated regressions cover the reported and newly found cases.
|
||||
Reference in new issue
Block a user