0.2.4-dev: round-29 community fixes and the official shared card pool
- Shared card pool and item stock as in the official mode (the owner's request, from the 路标档案馆 video and public notes): solo low-tier exceptions, co-op operators x2, shared item stock with special-item exceptions, normal / advanced occupancy 1 / 2, re-check on buy, 机变 exhaustion, release on consume / destroy / elimination; 整备 never exceeds stock; invariant held <= cap. - 突袭: one taunt-first reselect right after a revive (the owner's rule); ordinary polls and redeploys keep the 0.2.3 rule; a revive on an enemy's tile stays. #475: online boss / hidden-boss Raid may land on the empty half (owner-limited scope). - 浊心斯卡蒂 S1 x 坚守 no longer bounce redirected damage, and the two shares conserve the hit (idea of PR #464 by @HappyTanuki). - Operator fixes adapted from PRs by @Xinglan233 (#459 哈洛德 S2 elemental trigger, #460 涤火杰西卡 shield on the four adjacent tiles, #461 家族徽章 first hit after stealth, #462 松果 S2 regrow per deploy); 克莱门莎 S2 splash 1.1 / 100% ATK and air auto-trigger (#467); 白面 copying 歌蕾蒂娅 / 余 skips the three-member condition (#473, the owner's video). - 香槟炸弹 is not chosen by friendly auras / heals (PR #468 / #476 by @Siornya); 琳琅诗怀雅 coin balance (PR #450 by @IceCodeNew); Touch prep display (PR #451 by @YinqiMargatroid); lobby header (PR #471 by @YuriRestia); Japanese UI terms (PR #448 by @scutkane). - AI-only boss countdown grace, render-failure cache / recovery without restarting a battle, device units kept on a same-field re-entry, DIY detail / skill previews, large-text result buttons. - golden: battle families equal 0.2.3 except diy-135 / diy-136 (克莱门莎); all 18 release matches move through the shared pool, every flip named in docs/history/0.2.4.md §29.12; two coverage scenarios added.
This commit is contained in:
1 parent
1db8e51023
commit
6bfc08270c
129 files changed
+3477
-1011
No files matched your search
+5
-3
@@ -159,7 +159,7 @@ The research JSONs in `docs/research/` (03, 05, 07) define **which** ids are nee
|
||||
| Token Spine | fexli: the default model, or else the first skin variant (`spine/{tokenId}/{variant}/Spine/`) | `spine/token/{tokenId}/{stem}.*` |
|
||||
| Enemy Spine (PC build, premultiplied alpha) | isHarryh/Ark-Models `models_enemies/{key}/`, file names from `models_data.json` | `spine/enemy/{enemyId}/{stem}.*` |
|
||||
| Enemy Spine that no dump carries (灼热源石虫 / 炽焰源石虫) | the local client only (`tools/local-extract/extract.py ENEMY_SPINES`, optional); never downloaded and never required: an overlay of the web alias (`enemies[id].spineLocal`) | `local/spine/enemy/{enemyId}/{stem}.*` (listed in `data/local-assets.json`) |
|
||||
| Token Spine that no dump carries (39 summons: most 自选 summons, 凯瑟琳's 爬行号·防护单元, 凛御银灰's 风雪之眼) | the local client only (`tools/local-extract/extract.py TOKEN_SPINES`, optional); never downloaded and never required: an overlay (`tokens[id].spineLocal`; without it the avatar diamond) | `local/spine/token/{tokenId}/{stem}.*` (listed in `data/local-assets.json`) |
|
||||
| Original token Spine overlays (40 summons: most 自选 summons, 凯瑟琳's 爬行号·防护单元, 凛御银灰's 风雪之眼, 香槟炸弹) | local-client extraction (`tools/local-extract/extract.py TOKEN_SPINES`, optional); the original overlay is preferred, with any listed web model retained as fallback | `local/spine/token/{tokenId}/{stem}.*` (listed in `data/local-assets.json`) |
|
||||
| BGM | AA2 `voice` branch `audio/sound_beta_2/music/**` (大厅/休整期 `act1autochess`, 开战 `act13side/m_bat_kazimierz2_{1,2}` — 骑士之日 / 无畏者; the 开战 track follows the round: `_2` 无畏者 rounds 1–7, `_1` 骑士之日 from round 8) | `audio/bgm/{file}.mp3` |
|
||||
| SFX (UI, battle, per unit) | AA2 `voice` `audio/sound_beta_2/**`, mapped from `audio_data.json` banks | `audio/sfx/{same sub-path}.mp3` |
|
||||
| 干员战斗语音 | AA2 `voice` `audio/sound_beta_2/voice_cn/{charId}/cn_nn.mp3` (Chinese, `audio.voice`) and `voice/{charId}/cn_nn.mp3` (Japanese, `audio.voiceJp`: the same file names) — the lines `charword_table.json` lists (`placeType` = when the game plays one, `voiceAsset` = the path); `--voice-lang=jp|en|kr` fills `audio.voice` from `voice/`, `voice_en/`, `voice_kr/` instead | `audio/voice/cn/{charId}/{cn_nn}.mp3`, `audio/voice/jp/{charId}/{cn_nn}.mp3` (`audio/voice/{lang}/…` for another `--voice-lang`) |
|
||||
@@ -418,7 +418,7 @@ Other renderer rules from research 07 §5.4–5.5:
|
||||
"missing skel"), nor of 凯瑟琳's 爬行号·防护单元 and 凛御银灰's 风雪之眼, so they were drawn as the avatar diamond. The
|
||||
local client has them in its battle token packs (`pkgrps/btl_pfb_tokens_*.ab`, the Windows build carries all of them;
|
||||
the iOS build lacks `btl_pfb_tokens_0` and has ASTC pages), the same overlay as the enemies above:
|
||||
- `tools/local-extract/extract.py TOKEN_SPINES` (39 ids; `--only spine/token`) reads each token's battle prefab
|
||||
- `tools/local-extract/extract.py TOKEN_SPINES` (40 ids; `--only spine/token`) reads each token's battle prefab
|
||||
(`dyn/battle/prefabs/[uc]tokens/<id>.prefab`), takes the skeleton of its Front renderer — a directional token has
|
||||
Front / Back (/ Down) renderers, each with its own skeleton of the same name; the web tokens use Front too — and
|
||||
writes it to `public/assets/local/spine/token/{tokenId}/` like an enemy model (skeleton, sized `pma: true` atlas,
|
||||
@@ -441,7 +441,7 @@ Other renderer rules from research 07 §5.4–5.5:
|
||||
|
||||
### Other fallbacks
|
||||
|
||||
- **Emotes and 玩法说明 pages** (`public/js/data.js artUrls / nextArtUrl`, `ui/guide.js guideStage`): the local-client picture (`data/local-assets.json`) first, then the mirror copy (`ui['emoticon/…']`, `ui['guide/…']`), each tried in turn when one fails to load; when none is left — none listed, or every copy failed (for example data/assets.json lists the downloaded pages but the files are not on disk yet: a `git pull` and restart without setup) — the neutral emote glyph, and for a page the official tips text (`config.tips`). The rest of the local-client art (the 3D board, the official HUD sprites, module type icons, the two enemy models and the 39 token models above) is not downloaded: the client looks it up in `data/local-assets.json` only (most of the HUD sprites are on the mirror too, DESIGN §22.5); docs/DEPLOY.md §6 lists what falls back without it.
|
||||
- **Emotes and 玩法说明 pages** (`public/js/data.js artUrls / nextArtUrl`, `ui/guide.js guideStage`): the local-client picture (`data/local-assets.json`) first, then the mirror copy (`ui['emoticon/…']`, `ui['guide/…']`), each tried in turn when one fails to load; when none is left — none listed, or every copy failed (for example data/assets.json lists the downloaded pages but the files are not on disk yet: a `git pull` and restart without setup) — the neutral emote glyph, and for a page the official tips text (`config.tips`). The rest of the local-client art (the 3D board, the official HUD sprites, module type icons, the two enemy models and the 40 token models above) is not downloaded: the client looks it up in `data/local-assets.json` only (most of the HUD sprites are on the mirror too, DESIGN §22.5); docs/DEPLOY.md §6 lists what falls back without it.
|
||||
- **Tokens:**
|
||||
- Without an avatar, use `chars[owner].avatar` with a 召唤物 badge, or `prof.battlecard.token` — except 圣聆初雪's 保护目标(冻结状态) (PRTS 无头像; the frozen gate), drawn as a procedural ice diamond (`render/units.js ICE_TOKENS`).
|
||||
- Without a Spine (and without its local-client model, "Token models from the local client"), draw the avatar sprite with a bob tween.
|
||||
@@ -511,3 +511,5 @@ banks prefer START over ON, then plain/numeric order; this is a deterministic ap
|
||||
operator's runtime ability graph. Mixed-letter banks are skipped. Preserve `mixOf` for each selected bank separately;
|
||||
`attacks`/`hits` and `attackMix`/`hitMix` use matching skill keys. Regenerate the current manifest instead of importing
|
||||
an older PR's full JSON, preserving JP voices and current operators. See DESIGN §28.17.
|
||||
|
||||
The 40th local token model is the original champagne bomb (`token_10031_swire2_gdtrap`, §29.5), extracted from the official `btl_pfb_tokens_0.ab` through `TOKEN_SPINES`. Its web fallback is retained. Failed board-pack/image requests can retry after connectivity/visibility recovers; a failed three.js module gets at most two fresh-URL retries per page because browser module failures are cached. Successful resources remain cached.
|
||||
+2
-1
@@ -109,7 +109,8 @@ Top level: `{ season, seasonName, modes, economy, lpCapPerRound, bossOvertimeAft
|
||||
| `itemSellable`, `itemDestroyRefund` | `false`, `0` | items can only be destroyed |
|
||||
| `benchSize`, `tempSize`, `deployCap`, `storeCntMax` | `10`, `5`, `8`, `6` | |
|
||||
| `equipPerChess`, `maxArtsPerRound` | `2`, `2` | |
|
||||
| `poolCopies[tier]` + `poolCopiesOverrides` | `{"1":12,"2":14,"3":18,"4":16,"5":8,"6":5}`, `{"chess_char_6_11_a":4}` (缪尔赛思) | shared pool copies per base chess |
|
||||
| `poolCopies[tier]` + `poolCopiesOverrides` | 12/14/18/16/8/5 plus measured low-tier identity exceptions (DESIGN §29.8) | single-player copies; `coopPoolMultiplier: 2` doubles shared operators, not private DIY stock |
|
||||
| `itemPoolCopies[tier]` + `itemPoolCopiesOverrides` | 4/6/7/8/7/3 plus eight measured exceptions (DESIGN §29.8) | shared shop-equipment ownership: normal 1, upgraded 2; non-shop effect-only equipment unlimited |
|
||||
| `goldenCopies`, `mergeCount`, `mergeCountOverrides`, `itemMergeCount` | `3`, `3`, `{"chess_char_2_11_a":2}` (风丸), `2` | |
|
||||
| `rewardOffer` | `{"count":3,"tierOffset":1,"maxTier":6,"price":0,…}` | merge reward: 3 **different** free chess of tier `min(shopLevel+1,6)` (a short tier tops up from the tier below; `PlayerState.pushRewardOffer`, user playtest #6 item 19) |
|
||||
| `handFillOrder` | `"rightToLeft"` | |
|
||||
|
||||
+2
-1
@@ -4,7 +4,7 @@ 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, 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.
|
||||
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-dev** adds the subsequent community fixes — §29, the current development 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.
|
||||
|
||||
---
|
||||
|
||||
@@ -35,3 +35,4 @@ normative lines it rewrote).
|
||||
| §26 | [history/0.2.1.md](history/0.2.1.md) | 0.2.1 — after the 0.2.0 release |
|
||||
| §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 — development after 0.2.3 |
|
||||
+26
-4
@@ -85,7 +85,7 @@ legal from R14 into R15. The client mirrors it
|
||||
| 机变 first / other pickers | `spFirst` 30 / `spTurn` 16 (co-op; solo / single human untimed) |
|
||||
| PREP | `modes[m].rounds[r].prepTime` (co-op; solo / single human untimed) |
|
||||
| COMBAT / 联防 | `modes[m].rounds[r].combatTimeLimit` (= the level's `maxPlayTime`) real seconds = 2× that in game seconds |
|
||||
| 最终攻势 / 隐秘核心 | no hard stop: countdown `rounds[r].levelMaxPlayTime` 120 real s; overtime drain from `bossOvertimeAfter` 150 real s, 1 team LP per real s (§3) |
|
||||
| 最终攻势 / 隐秘核心 | no hard stop: countdown `rounds[r].levelMaxPlayTime` 120 real s; overtime drain at 120 real s for all-human teams, configured 150 real s with a non-departed AI teammate; 1 team LP per real s (§3) |
|
||||
| ROUND_START / after combat / SETTLE | 2 / 1.5 / 3 (presentation delays, `Match.DELAYS`) |
|
||||
| bot action delay | 0.9 s (+0.35 s per seat) |
|
||||
|
||||
@@ -95,7 +95,7 @@ band draft / 机变 / PREP deadline, and BATTLE_CHECK / ROUND_START / SETTLE run
|
||||
(draft order and skip, 6 机变 cards, 联防) stay.
|
||||
`m.public.deadline` is the absolute end of the current timer (ms epoch, 0 = untimed; combat: estimated end at 2×;
|
||||
最终攻势 / 隐秘核心: the boss level's `levelMaxPlayTime` countdown, 120 real s — the battle goes on past it — with
|
||||
`m.public.overtimeAt` = when the overtime drain starts, 150 real s; both on the field clock).
|
||||
`m.public.overtimeAt` = when the overtime drain starts: 120 real s for all-human teams, 150 real s with an AI teammate at fight start; both on the field clock).
|
||||
|
||||
### 1.1 Band draft
|
||||
Co-op: random order (all seats, bots included), one pick per turn, ONE countdown: `BAND_TURN_SECONDS` 50 s per turn,
|
||||
@@ -682,8 +682,9 @@ Any `choice:` handler whose EffectRef reuses its own key must guard like this (o
|
||||
which replaces the fixed pool of 「保持固定血量」 (config `bossHpScale.perPlayer: false` with `solo: 0.25` restores it;
|
||||
its optional × alive / 4, `aliveScaling`, stays off); leaders are never scaled by `enemyScale`, their parts and escorts
|
||||
keep their own HP. The merged team LP loses leaks (`lpr`), the overtime drain
|
||||
(`bossTurnHpReduceTime` 150 counts REAL seconds, like the boss level's 120 s maxPlayTime that runs out first — the
|
||||
battle goes on — so 1 LP per real second from 150 real s = 300 game s on the 2× field clock; `gd.bossOvertimeDue`)
|
||||
(the boss level's 120 real-second countdown for all-human teams; `bossTurnHpReduceTime` 150 real seconds only with
|
||||
a non-departed AI teammate at fight start. The first deduction follows one complete real second after that threshold;
|
||||
`gd.bossOvertimeDue` receives the fight's frozen threshold — DESIGN §29.1)
|
||||
and leader "扣除目标生命" effects (the sim's `lpLoss` hook: boss_7 Doom, 斥退 …); after every change it is written back
|
||||
to the alive players as shares of the LP each brought in (`lpAtFinal`, largest remainder), so `lp` in m.public /
|
||||
m.private / m.result is what is left (Σ = team LP).
|
||||
@@ -915,3 +916,24 @@ requests cannot affect a new opening. See DESIGN §28.21 for cancellation and ti
|
||||
`botEmotes.js` is isolated from bot decisions and RNG. It sends the existing `m.emote` only in mixed matches, under
|
||||
normal cooldown/whitelist rules; `SP_BOT_EMOTES=0` disables it. The cooperation score in `bot.js` and these cosmetic
|
||||
choices are explicitly [ASSUMED]; DESIGN §28.15–16 records the source and validation.
|
||||
|
||||
### Community follow-up contracts (DESIGN §29)
|
||||
|
||||
- `triggerGarrisons` includes `source.copiedFrom` for copied effects. Only Ptilopsis copying Yu/Gladiia at SERVER_PREP_START skips the three-in-row prerequisite, as confirmed by the original-game recording; Saria and other copies keep existing conditions.
|
||||
- Jessica's placeable shield uses `shared/summonPlacement.js` for the four orthogonal neighbors, independent of her selected skill, facing or module. Client preview and server moves/swaps use the same grid.
|
||||
- Client result statistics resolve DIY and stand-in names from the authoritative BattleSpec. A client cannot replace those names.
|
||||
|
||||
### Shared inventory after 0.2.3 (DESIGN §29.8)
|
||||
|
||||
`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.
|
||||
整备 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.
|
||||
+11
-3
@@ -463,7 +463,7 @@ recorded for the player whose half contains the goal it reached, with `sourcePla
|
||||
0, so float dust of the pool sync can never keep a leader alive; user playtest #6). A boss/hidden battle **with a
|
||||
`sharedBoss`** ends only when the pool reaches 0 or on `forceEnd` (DESIGN §5.5) — an emptied field keeps running
|
||||
(the h07_04 pair leader has no wait step and can walk into the objective: the leak costs its `lpr`, then the field
|
||||
idles while another field may still empty the pool or the match's overtime drain — team LP, from 150 real s — ends it); without a pool
|
||||
idles while another field may still empty the pool or the match's overtime drain — team LP, from 120 real s for all-human teams / 150 with an AI teammate — ends it); without a pool
|
||||
(sandboxes, tools) it still ends `cleared` when empty. `timeout`: `time ≥ timeLimit` —
|
||||
every living non-boss enemy becomes a leak; spawns that never happened are dropped from `total` and listed in `unspawned`.
|
||||
- `leaked[].counted = false` for `notCountInTotal`/`unharmful`/boss parts (LP rules: normal rounds count only `counted`
|
||||
@@ -907,7 +907,7 @@ instance) and skip `'counter'` / `'reflect'` damage. When the guard trips, the l
|
||||
| `getPlayer(playerId)` | `{ playerId, seat, side, colOffset, mirror, dir (default unit direction: RIGHT, mirrored side LEFT), facing (its sign), bonds (live copy, layers updated by addLayers), bandId, playerEffects, lpForBoss, dp, units }` |
|
||||
| `mapTile(ps, row, col, abs?)` / `mapDir(ps, dir, abs?)` | board → field tile / direction of a player (the FA right-side mirror) |
|
||||
| `onOwnBoard(ps, r, c)` | whether a field tile lies on the player's own board — GEO.FIELD (rows 9–12, cols 2–10) mapped onto this field: the 联防 right-hand helper's +8 columns, the boss field's rows 2–5 (never its hand / 临时整备区 rows 0–1), the mirrored right half; 乌尔比安's S3 【移动】 takes only such tiles (DESIGN §25.17.2) |
|
||||
| `onFieldBoard(r, c)` | whether a field tile lies on the board of a player of this field — `onOwnBoard` of any of `players` (the players whose units the battle holds; an eliminated or absent teammate is not one): both halves of the two-helper 联防 field and of a Final Assault / Hidden Core pair field, the own half only for a lone 联防 helper and on a solo boss field, never a boss field's hand / 临时整备区 rows; the 突袭 landing takes only such tiles (DESIGN §25.18, §26.1) |
|
||||
| `onFieldBoard(r, c)` | whether a field tile lies on the board of a player of this field — `onOwnBoard` of any of `players` (the players whose units the battle holds; an eliminated or absent teammate is not one): both halves of the two-helper 联防 field and of a Final Assault / Hidden Core pair field, the own half only for a lone helper/player, never a boss field's hand / 临时整备区 rows. Raid additionally admits the empty deployment half only in `mode_multi_*` boss/hidden fights (rows 2–5, cols 2–18), without changing this general method or terrain/reservation checks (DESIGN §29.13, #475) |
|
||||
| `addDp(playerId, n)`, `retreat(unit, {reason, permanent, dying})`, `relocate(unit, r, c)` | `relocate` only changes the tile (state kept, no event) |
|
||||
| `moveRedeploy(unit, r, c, { clearSp })` | a 【移动】 (PRTS 术语释义: "不退场,以当前血量在目标位置部署", a special retreat + redeploy): `relocate`'s checks (false = refused, nothing changed), then a new deployment (`deploySeq` / `aggroSeq` / `deployedAt`) and `deploy {initial:false, move:true}` (deploy effects fire again); no `die` / `death`, timer or cost (不屈 / 阿戈尔's revive never see it); HP, buffs and a running skill are kept (owner's deviation, DESIGN §22.3); `clearSp` empties the SP before the deploy handlers run — 乌尔比安 S3's move (kits/ops/chess_char_5_05-ulpia.js) and 【返回】 (`clearSp`; also the 从不混淆的方向 fallback, content/tokens.js) |
|
||||
| `redeploy(unit, { free=true, tile, keepSp })` | immediate (re)deployment of a dead/retreated ally (full HP, `deploy {initial:false}`); `free: false` pays `base.cost` DP (refused without it); without `tile` it lands on the unit's rest tile (`restTile`: where a knocked-out operator lies, else home); `tile: [r, c]` lands on that tile once (home unchanged; refused when off-rect, occupied or a knocked-out operator's tile, no fallback); `keepSp` keeps SP/charges (保留技力), restored before `deploy` fires — but not for a skill that costs no SP, which the reset re-arms as at every deployment (伊内丝 S3 casts again on a 突袭 landing) — 突袭 raids, 阿戈尔 / 不屈 revives where the unit lies |
|
||||
@@ -1381,7 +1381,7 @@ Unknown subprofessions fall back to the profession default (test `professions.te
|
||||
|
||||
## 9. Wire format (snapshot.js, DESIGN §8.2)
|
||||
|
||||
- `snapshot()` → `{ fieldId, t, units: [[id, x, y, hp, maxHp, sp, spMax, flags, anim]], dp, killed, total, resolved, dps?, boss?, down?, elem?, ammo?, wolves?, neg?, stand?, standCut? }`.
|
||||
- `snapshot()` → `{ fieldId, t, units: [[id, x, y, hp, maxHp, sp, spMax, flags, anim]], dp, killed, total, resolved, dps?, boss?, down?, elem?, ammo?, coins?, wolves?, neg?, stand?, standCut? }`.
|
||||
`killed` counts every `counted` knock-out (§1.3) and `total` only the enemies this field scheduled (`inTotal`), so it may
|
||||
exceed it; `resolved = min(total, killedInTotal + leakedInTotal)` is the HUD capsule's numerator (DESIGN §14 顶栏胶囊).
|
||||
`sp/spMax` show remaining duration/ammo as a draining bar while a timed skill is active (ammo: `ammoLeft / ammoMax`, the
|
||||
@@ -1561,3 +1561,11 @@ yet — enemy content must pick one); 抵抗 covers the control statuses of `RES
|
||||
“余音” owns a same-call pulse queue (DESIGN §28.24): reflected hits enqueue their earned pulses instead of recursively
|
||||
entering another pulse. This retains the lethal-hit pulse and prevents valid high hit-count chains from tripping the
|
||||
general hook guard. The queue is emptied in `finally`; it introduces no timer or simulation RNG.
|
||||
|
||||
### Community follow-up contracts (DESIGN §29)
|
||||
|
||||
- Optional snapshot `coins: [[id, balance, cap]]` comes from `snapshot.js coinView`: a live allied Swire skill's nonnegative integer balance and blackboard cap, including zero. Invalid/missing entries are omitted; interpolation clears absent values.
|
||||
- Raid's one reselect after a revive orders by taunt, then remaining route distance, then id, and jumps while the operator is not blocking (contact on the current tile is refreshed first). Ordinary polls keep remaining-distance order and the empty-range prerequisite.
|
||||
- Healing skill activation includes elemental-only injury when the operator's heal profile can cure it. Pinecone S2 growth is deployment-local. Skadi S1 and Stead preserve redirect ancestry and take both shares from the pre-redirect hit, so the total damage is conserved.
|
||||
|
||||
`champagneHold` includes the internal `isolated` ally-selection flag (§29.11): device-type champagne bombs are excluded from ordinary allied auras/inspiration in both creation paths. Other unhealable summons retain their own selection behavior.
|
||||
@@ -63,7 +63,7 @@ Audio: autochess BGM per phase, UI SFX (buy/sell/refresh/level/merge/ready/timer
|
||||
- `guide/autochess_{home,shop,handbook}_N.png` — the 19 official tutorial pages; stored squashed to 1024² — **display at 16:9** (the mirror copies too, §22.5).
|
||||
- `projectiles/*` — battle projectile sprites.
|
||||
- `spine/enemy/<id>/` — enemy models no web dump carries (灼热 / 炽焰源石虫, `extract.py ENEMY_SPINES`): manifest `enemies[id].spineLocal` (metadata from the committed `tools/assets/local-enemy-spines.json`); drawn instead of the tinted web alias when every file is listed (§21.14).
|
||||
- `spine/token/<id>/` — token (summon) models no web dump carries (39: most 自选 summons, 凯瑟琳's 爬行号·防护单元, 凛御银灰's 风雪之眼; `extract.py TOKEN_SPINES`, the Front renderer's skeleton of each battle token prefab): manifest `tokens[id].spineLocal` (metadata from the committed `tools/assets/local-token-spines.json`); drawn instead of the avatar diamond when every file is listed (docs/ASSETS.md "Token models from the local client").
|
||||
- `spine/token/<id>/` — token (summon) models no web dump carries (40: most 自选 summons, 凯瑟琳's 爬行号·防护单元, 凛御银灰's 风雪之眼; `extract.py TOKEN_SPINES`, the Front renderer's skeleton of each battle token prefab): manifest `tokens[id].spineLocal` (metadata from the committed `tools/assets/local-token-spines.json`); drawn instead of the avatar diamond when every file is listed (docs/ASSETS.md "Token models from the local client").
|
||||
- `module/<TYPE>` — the official module (uniequip) TYPE icons (white glyphs; keys are the client's mixed-case file names, e.g. `PRI-X`, `mar-x`, `isw-a`), matched **case-insensitively** against a ModuleRecord's `typeName` by `assetUrls.moduleTypeIconUrl(local, typeName)` (Greek type letters map to the file's Latin letter: `ISW-α` → `isw-a`) — shown on the 干员调配 module cards / module info, the detail panel's 模组 row and the shop card's module tag; lettered tiles / type text without them.
|
||||
|
||||
---
|
||||
@@ -141,5 +141,12 @@ shows the current base pose. A subsequent attack/death supersedes that pending e
|
||||
or per-phase animation schedule is added by this change.
|
||||
|
||||
The simplified-view notice describes a renderer load failure, rather than declaring the device incapable of 3D.
|
||||
On same-battle metadata refresh, remembered once-spawned device records also seed the renderer's new entry (§29.14).
|
||||
This preserves device tile picking and live-HP cards; records explicitly supplied by the refresh take precedence,
|
||||
and a different field never inherits the previous field's devices.
|
||||
The same fallback covers import failure, timeout and WebGL initialization errors; a reload can retry.
|
||||
It does not diagnose a particular user's GPU or persist a disabled renderer preference (§28.25).
|
||||
|
||||
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.
|
||||
@@ -224,3 +224,12 @@ the hook-depth guard on scaled hit-count HP; the guard remains unchanged for oth
|
||||
as well as by its aura tick, including the first hit and immediately after the last companion leaves.
|
||||
|
||||
Sources and the feedback items requiring no simulation change are recorded in [§28.25](../history/0.2.3.md#2825-community-feedback-of-2026-10-10).
|
||||
|
||||
Community corrections in §29 are normative: Raid's one reselect after a revive uses taunt then route distance and jumps while unblocked, after refreshing contact on the current tile; ordinary polls stay on route distance and the empty-range rule. Healing cast conditions include curable elemental injury; Pinecone S2 growth restarts per deployment; crest consumption is checked on damage. Mixed Skadi/Stead redirects preserve ancestry and both take their share from the pre-redirect hit, so the victim keeps the remainder and the total is conserved. Clementia S2 secondary splash is 100% ATK within a 1.1 collision radius (four additional ground targets), while its main hit and 1.5-radius vortex keep their own coefficients. Final-mode leaders retain their erosion immunity, explicitly stated in the PRTS mode tips. 整备 does not upgrade a purchase when the golden's second copy would exceed shared item stock, and it does not spend its charge in that case.
|
||||
|
||||
Raid alone may land on an empty deployment half in multiplayer (`mode_multi_*`) Final Assault / Hidden Core battles
|
||||
(#475, maintainer-approved, §29.13): rows 2–5, cols 2–18, subject to the existing field rect, terrain, occupied/downed
|
||||
tile and attack-reach checks. Hand/temp rows, empty halves in single-player mode or lone-helper 联防 stay excluded.
|
||||
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.
|
||||
@@ -28,7 +28,7 @@ LOBBY(room) → INFO_CHECK (co-op 25 s; solo and any single-human match untimed
|
||||
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
|
||||
real s after 150 real s (§4, m.public.overtimeAt); no layer gains; team LP 0 ⇒ defeat at once (PRTS 直接失败),
|
||||
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)
|
||||
→ RESULT (per-player stats, titles, rounds passed, victory/defeat)
|
||||
@@ -60,7 +60,7 @@ Summons (§20.1): an operator on the board sends its manually deployable summons
|
||||
|
||||
Equipment (research 04 §2 + addendum, 09 §1.2): 2 slots per chess; a third item on a full carrier replaces the equipped item `replaceUid` names (the replace dialog's pick, official `UseEquipUp.unloadInstId`; absent ⇒ the oldest; a uid not equipped on the target ⇒ `BAD_TARGET`, nothing changes) and the replaced item is destroyed. A consume-on-equip item (盟约之币, 博士投影 …) on a full carrier replaces the same way before it resolves, so the carrier is left with a free slot (the normal 博士投影 takes it until the next round start); a target its effect refuses (博士投影 on an elite) keeps both items — PRTS 卫戍协议/帮助 "达到上限强行佩戴会改为替换装备" names no exception (GitHub #263; the client opens the replace dialog for it, `equipReplaces`). Equipped items are otherwise **locked**: `destroy` (销毁) accepts hand / temp items only (`BAD_TARGET 'equipped items are locked'`); equipment goes back to the hand only when its carrier merges, is sold, or is destroyed by 突变细胞's transformation (the cell itself returns too; PRTS 帮助 "在失去该干员(干员出售、销毁、合并等)…时自动卸除", §21.1) — a sale is refused with `HAND_FULL` when there is no room for it; returned equipment is stowed before the operator a transformation gains and before a merge elite's summon cards, and every path that hands the player an item — returned equipment included — ends with the auto-merge, so no player holds two identical mergeable normal items (§21.7).
|
||||
|
||||
Economy/shop/pool/merge/hand rules: exactly as research 00-INDEX §3–§4 (income `min(3+r,12)`; prices by tier; refresh 1; freeze toggles all; sell +1; items not sellable; upgrade prices per mode with −1/round; shared pool copies 12/14/18/16/8/5 (缪尔赛思 4) across all players; elite = 3 copies; odds = copy-weighted draw over unbanned visible chess with tier ≤ level; merge 3 (风丸 2) → elite onto the consumed deployed copy's tile, else to the hand (§20.11) + reward offer of 3 **different** free chess of tier `min(level+1, 6)` (copy-weighted; a tier short of different chess tops up from the tier below [ASSUMED], §20.6); full hand blocks every buy / reward pick, a merge-completing one too (PRTS 卫戍协议/帮助 §手牌区, GitHub #82); overflow to temp; a free hand slot pulls the temp pieces back in at once, right → left (`PlayerState._fillHandFromTemp`); temp blocks ready).
|
||||
Economy/shop/pool/merge/hand rules: exactly as research 00-INDEX §3–§4 (income `min(3+r,12)`; prices by tier; refresh 1; freeze toggles all; sell +1; items not sellable; upgrade prices per mode with −1/round; single-player pool copies 12/14/18/16/8/5 plus measured exceptions; co-op shared operators use twice those counts, while equipment has separate shared stock (DESIGN §29.8); elite = 3 copies; odds = copy-weighted draw over unbanned visible chess with tier ≤ level; merge 3 (风丸 2) → elite onto the consumed deployed copy's tile, else to the hand (§20.11) + reward offer of 3 **different** free chess of tier `min(level+1, 6)` (copy-weighted; a tier short of different chess tops up from the tier below [ASSUMED], §20.6); full hand blocks every buy / reward pick, a merge-completing one too (PRTS 卫戍协议/帮助 §手牌区, GitHub #82); overflow to temp; a free hand slot pulls the temp pieces back in at once, right → left (`PlayerState._fillHandFromTemp`); temp blocks ready).
|
||||
|
||||
**Temp overflow (临时整备区, row 8; user playtest #3 item 3).** Passive gains that find the hand full (merge elites, grants — the operator a 突变细胞 transformation gains included, §21.1 —, battle-result rewards, equipment returned by a merged / sold / transformed carrier) overflow into the 5 temp slots, and Ready is refused while any is occupied (official "直到溢出情况排除才可开始进行作战"). A temp piece is resolved — a chess sold back to the pool with its summons removed, items destroyed, a summon stack removed (it comes back at the next round start, PRTS "干员所属召唤物会于下一回合返还", §20.1) — only at the deadline of the **first prep in which its player could act on it** (`PlayerState.tempDue(piece)` vs `prepsEnded`; every write into a temp slot goes through `_putTemp`, which records it): a piece that arrived during a prep before Ready is due at that prep's end; one that arrived after Ready or during the `<休整期结束时>` effects, or outside PREP (COMBAT, 联防, SETTLE — battle-result grants, a SETTLE merge's elite, returned equipment —, the next ROUND_START, 机变) is kept, visible and usable (move to a free hand slot, place, equip, use, destroy, sell) through the **next** prep. Un-readying (`setReady(false)`) makes whatever arrived while ready due at the current prep. ROUND_START no longer wipes temp (it used to destroy what SETTLE had put there before the player ever saw it). A merge's elite whose merge consumed a deployed copy takes that copy's tile and facing (§20.11); otherwise it goes to the hand, overflowing into temp (also outside PREP). `server/match/audit.js` (`tools/matchrun.mjs --check`) tracks the arrivals itself and flags any temp piece that outlives its due prep. The UI frames the row on the board with the rule (§17.5).
|
||||
|
||||
@@ -139,3 +139,5 @@ remain fixed and random results can repeat. A separate seed-derived stream leave
|
||||
have a 300 ms anti-burst guard, revision and vote identities. All new setup data and player DIY stocks are prepared
|
||||
before mutation; data preparation failure leaves the old opening intact. This is a remake convenience, not an official
|
||||
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.
|
||||
@@ -30,7 +30,7 @@ S→C:
|
||||
- NOTE: game time in `b.snap`/`b.ev` is carried as **`gt`** (the frame's `t` is the message type).
|
||||
- Active finite zero-SP timed skills display `sp=timeLeft`, `spMax=duration` and `UF.SKILL`; after end they display
|
||||
`0/0`. Snapshot display capacity does not change runtime SP/cost.
|
||||
- `b.snap` — `{ fieldId, gt, units: [[id, x, y, hp, maxHp, sp, spMax, flags, anim]] , dp, killed, total, resolved, down?, elem?, ammo?, wolves?, neg?, stand?, standCut? }` 20 Hz (a countdown summon's `hp` is maxHp × the share of its life left, §25.16.5). Optional, only when non-empty (§18.3): `down: [[id, respawnAt (game s), respawnTime (s), state, row, col]]` — knocked-out operators waiting to redeploy, `state` 0 counting | 1 timer done, waiting for DP | 2 timer done, its tile taken — a safeguard, no ally deploys there (sim/constants.js `DOWN_STATE`); `row, col` = the tile it lies on and comes back on (§21.24); `elem: [[id, element, fill, cooldownEnd (game s), cooldown (s)]]` — the one gauge a unit shows: the fullest (ties by the official element id 神经 < 侵蚀 < 灼燃 < 凋亡), fill with 2 decimals rounded DOWN and kept at 0.01–0.99 outside a burst (§20.8); during a 爆发冷却 the bursting element with fill 1 and the cooldown numbers (else 0, 0); the three HP-bar readouts (0.2.2, GitHub PR #303 / #378 / #383, display only — no sim state reads them, the nine-field tuples and the SP fraction an ammo skill still puts in them are unchanged; `render/interp.js` keeps them per snapshot and `sample()` hands them out from the older snapshot like `flags`, so they step with the skill flag; a malformed entry or an id the snapshot does not list is dropped, a snapshot without the list clears the readout): `ammo: [[id, rounds left, rounds in the magazine]]` — an ally's running ammo skill, whole rounds, the magazine being the activation's real total (extra bullets and refills included; 隐现's S2 holds 14, skill_table `attack@trigger_time`) — the client draws yellow cells in place of the SP bar (the count, not a pixel copy of the official magazine widget — its art is in no game data we have), and UnitInfo `ammoSkill: true` (an ally whose skill is an ammo magazine, known from its first appearance) tells it to draw no standing skill aura; `wolves: [[id, 狼影 left, the talent's maximum]]` — 伺夜's 狼群 (`mem.shadows` / `mem.wolfCapacity`, both the placed and the automatic pack), one diamond per slot under the HP bar (plain diamonds: no official counter art is known, the portrait of PR #378 was not taken), nothing in the 战术点形态; `neg: [[id, fill]]` — the share (0.01–1) of its cap a negative-HP pool holds (斩业星熊's 我执, `unit.negFill`), drawn as the red bar over her drained HP bar. These show only for a living, deployed, visible unit and only when it has one
|
||||
- `b.snap` — `{ fieldId, gt, units: [[id, x, y, hp, maxHp, sp, spMax, flags, anim]] , dp, killed, total, resolved, down?, elem?, ammo?, coins?, wolves?, neg?, stand?, standCut? }` 20 Hz (a countdown summon's `hp` is maxHp × the share of its life left, §25.16.5). Optional, only when non-empty (§18.3): `down: [[id, respawnAt (game s), respawnTime (s), state, row, col]]` — knocked-out operators waiting to redeploy, `state` 0 counting | 1 timer done, waiting for DP | 2 timer done, its tile taken — a safeguard, no ally deploys there (sim/constants.js `DOWN_STATE`); `row, col` = the tile it lies on and comes back on (§21.24); `elem: [[id, element, fill, cooldownEnd (game s), cooldown (s)]]` — the one gauge a unit shows: the fullest (ties by the official element id 神经 < 侵蚀 < 灼燃 < 凋亡), fill with 2 decimals rounded DOWN and kept at 0.01–0.99 outside a burst (§20.8); during a 爆发冷却 the bursting element with fill 1 and the cooldown numbers (else 0, 0); the three HP-bar readouts (0.2.2, GitHub PR #303 / #378 / #383, display only — no sim state reads them, the nine-field tuples and the SP fraction an ammo skill still puts in them are unchanged; `render/interp.js` keeps them per snapshot and `sample()` hands them out from the older snapshot like `flags`, so they step with the skill flag; a malformed entry or an id the snapshot does not list is dropped, a snapshot without the list clears the readout): `ammo: [[id, rounds left, rounds in the magazine]]` — an ally's running ammo skill, whole rounds, the magazine being the activation's real total (extra bullets and refills included; 隐现's S2 holds 14, skill_table `attack@trigger_time`) — the client draws yellow cells in place of the SP bar (the count, not a pixel copy of the official magazine widget — its art is in no game data we have), and UnitInfo `ammoSkill: true` (an ally whose skill is an ammo magazine, known from its first appearance) tells it to draw no standing skill aura; `wolves: [[id, 狼影 left, the talent's maximum]]` — 伺夜's 狼群 (`mem.shadows` / `mem.wolfCapacity`, both the placed and the automatic pack), one diamond per slot under the HP bar (plain diamonds: no official counter art is known, the portrait of PR #378 was not taken), nothing in the 战术点形态; `neg: [[id, fill]]` — the share (0.01–1) of its cap a negative-HP pool holds (斩业星熊's 我执, `unit.negFill`), drawn as the red bar over her drained HP bar. These show only for a living, deployed, visible unit and only when it has one
|
||||
Optional, only when non-empty (PR #381; display metadata, SIM §9): `stand: [[id, until]]` — the game time an enemy's
|
||||
attack recovery ends (`atkStandUntil`; enemies alive, deployed, visible, neither feared nor stunned): when it falls
|
||||
between two snapshots the renderer holds the position until then and interpolates the rest (HP / SP unchanged), and
|
||||
@@ -134,3 +134,9 @@ voting, refuses stale ids and cancels on disconnect/leave; DESIGN §28.21 / META
|
||||
|
||||
Explicit local recovery (§28.20) reuses saved hello tokens after a fresh live-tab claim check. Display names and room
|
||||
codes are UI metadata only, never authentication. No new network message or nickname/IP matching is introduced.
|
||||
|
||||
Optional `coins: [[id, balance, cap]]` is an integer skill-currency readout (§29.6), separate from ammo. It includes zero, is stepped between snapshots and clears when omitted. Result-validation names for board operators are resolved from the server's DIY/stand-in selections, never a supplied display name.
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,276 @@
|
||||
# DESIGN §29 — 0.2.4 (development)
|
||||
|
||||
Part of [DESIGN.md](../DESIGN.md). This chapter records changes after the 0.2.3 release, not a released version.
|
||||
|
||||
## 29. Community follow-up
|
||||
|
||||
### 29.1 Boss overtime and Raid revival
|
||||
|
||||
- The maintainer requested the extra Final Assault / Hidden Core overtime grace only for teams with an AI teammate.
|
||||
At fight start, a non-departed AI seat preserves the configured 150 real seconds; otherwise the threshold is the
|
||||
visible level countdown (120 real seconds). The decision stays fixed during that fight. The first deduction is at
|
||||
the following whole real second, at one team LP per real second. `overtimeAt` uses that same threshold.
|
||||
- Ordinary Raid polls keep the 0.2.3 order: own field first, then remaining route distance and stable id, and they
|
||||
still jump only when the skill is ready or the member has been idle long enough and the range is empty.
|
||||
The maintainer confirmed one reselect immediately after a revive. That reselect alone orders by taunt, then
|
||||
remaining route distance, then id, and it jumps while the operator is not blocking, even if another enemy is
|
||||
already in range. Standing on an enemy's tile is blocking: the 0.25 s poll runs before that tick's block pass,
|
||||
so the reselect refreshes contact before it decides to stay. A retreat, a move, a redeploy that waited out its
|
||||
timer, the initial deployment and a Raid jump do not arm it. [ASSUMED] A revive is recognised as a knock-out
|
||||
redeploy that returns before `respawnAt`; the bond text does not name that timer split.
|
||||
- Regression: `boss-ai-grace.test.js` covers both final fights with/without AI; `community-round29.test.js` covers
|
||||
Texas S2 with local enemies, remote taunt/route priority, blocked revival and no repeated self-trigger.
|
||||
|
||||
### 29.2 Operator, item and sharing corrections
|
||||
|
||||
- #462, Pinecone S2: PRTS's growth is per deployment. A deployment-local use count resets on redeploy; the runtime's
|
||||
lifetime activation sequence is unchanged. Normal and elite variants are covered.
|
||||
- #459, Harold S2: a healer that can heal elemental injury considers elemental-only injury when deciding to cast.
|
||||
Full HP plus an elemental gauge can trigger; a wholly uninjured ally cannot.
|
||||
- #461, family crest: the first damage after stealth ends consumes the accumulated bonus immediately, including
|
||||
damage before the next growth poll. A synchronous equipment combo cannot consume it repeatedly; the current hit
|
||||
and combo retain the attack value that triggered them.
|
||||
- #464, Skadi S1 / Stead sharing: redirected damage carries both existing redirect ancestry markers, so neither
|
||||
mechanism revisits its own output and the transfer tree stays bounded. Both shares are taken from the pre-redirect
|
||||
hit and the victim keeps `1 − R − S` (1000 true with the official 0.4 and 0.5 leaves the victim 100, the three
|
||||
members 400 together and Skadi 500, including the one cross-application the ancestry tags already allow). A single
|
||||
effect is unchanged: Stead alone leaves 600 + 400, Skadi alone leaves 500 + 500. [ASSUMED] The two ratios add as
|
||||
shares of the original hit; no official source says they multiply. The same split does not depend on which
|
||||
damaged handler runs first. Hook registration order remains otherwise unchanged.
|
||||
- Sources: [PRTS 松果](https://prts.wiki/w/松果), [哈洛德](https://prts.wiki/w/哈洛德), mode item descriptions and the
|
||||
existing sharing contracts. `community-round29.test.js` includes before/after reproductions.
|
||||
|
||||
### 29.3 Ptilopsis copying Yu / Gladiia (#473)
|
||||
|
||||
The [original-game recording](https://www.bilibili.com/video/BV1XJSoBzEFB/) around 2:30–2:38 shows and explains that
|
||||
Ptilopsis's copies of Yu and Gladiia bypass the three-in-row prerequisite. The maintainer approved reproducing
|
||||
**only these two exceptions**. Preparation-start gifts from these copied traits skip the row condition; original
|
||||
owners, Saria, other traits and other events retain their conditions. The dispatcher records the copied origin in
|
||||
`source.copiedFrom`; eight original/copier-row combinations are tested in `garrisons_meta.test.js`.
|
||||
|
||||
### 29.4 Clementia S2 and final-boss erosion
|
||||
|
||||
[PRTS 克莱门莎](https://prts.wiki/w/克莱门莎), checked 2026-10-10, now specifies S2 ordinary-attack splash: radius
|
||||
1.1 with collision testing, at most four extra ground targets, each taking 100% ATK physical damage. This replaces
|
||||
the launch-day assumed 1.5 centre radius and copied main-hit multiplier. The primary target retains the skill's
|
||||
own attack multiplier; the vortex remains radius 1.5. Normal/elite numeric, radius and large-body regressions live in
|
||||
`op_clemnt.test.js`. The unresolved launch-day carriage/bomb timing assumptions remain documented in §28.1.
|
||||
|
||||
The [PRTS mode record's tips](https://prts.wiki/w/卫戍协议:盟约/PRTS盟约记录) explicitly state that Final Assault
|
||||
leaders do not receive erosion injury. The existing mode-specific immunity remains. All ten final-leader definitions
|
||||
were compared against all five injury types: erosion was blocked, the other four could burst. Main-game constants
|
||||
give leaders a 2,000 erosion threshold, so main-game boss identity alone is not general erosion immunity; that does
|
||||
not override the mode tip or prove every scripted boss phase susceptible. Pith's current three named injury types
|
||||
are unchanged. No unannounced future-season behavior is inferred.
|
||||
|
||||
### 29.5 Shield placement and original champagne art
|
||||
|
||||
- #460: Jessica's placeable shield uses the four orthogonally adjacent tiles stated by her talent. Preview, server
|
||||
validation, owner movement and swaps use a shared placement grid, independent of skill, facing or module.
|
||||
`jessica-placement.test.js` covers legal/illegal moves, swaps, bots and other summons.
|
||||
- #468: the original champagne-bomb model is extracted from the local official token bundle through the existing
|
||||
extraction/build pipeline. There are now 40 local token metadata records. Only this token's `spineLocal` and the
|
||||
generated asset hash change; the web fallback remains. No game art enters Git.
|
||||
|
||||
### 29.6 UI and recovery
|
||||
|
||||
- DIY selection reuses the roster's `LoadoutStats` component, showing the chosen ordinary/elite stats, attack range,
|
||||
trait, talents, potential and cultivation. Skill descriptions/SP labels follow the same preview level. The list
|
||||
uses aligned roster-style rows; list and details scroll independently, leaving Confirm reachable.
|
||||
- #450: Swire's skill coins show as current/cap, including zero. Optional `coins: [[id, balance, cap]]` comes from
|
||||
valid live-unit state, is stepped between snapshots and clears when absent. It changes no earning/spending rule.
|
||||
- #471: lobby tools are grouped at the left; the player chip opens statistics. Responsive title allocation prevents
|
||||
overlap with long names, translated text, resume and install controls; a narrow header puts its title on a new row.
|
||||
- #458: settlement summary scrolls independently from its return button. Enlarged text no longer pushes the button
|
||||
outside the viewport.
|
||||
- Transient failed images and board packs can retry on a later useful event. Three.js failed imports use two bounded
|
||||
fresh URLs because browsers cache module failures. A failed field engine may remount on online/visibility events,
|
||||
with cleanup and at most two consecutive retries; explicit fallback/2D choices remain respected. Real Chrome
|
||||
tests abort actual resource requests and verify recovery, single canvas ownership and unmount cleanup. This does
|
||||
not establish the cause of every reported device/GPU failure.
|
||||
- #469's repeated “甄选干员干员” was a result validator replacing a DIY operator's name with its empty slot's name.
|
||||
It now resolves DIY and stand-in names from the authoritative BattleSpec; client-supplied names remain ignored.
|
||||
- #448: Japanese UI terms are corrected, including 自然回復 and 完璧な作戦, consistent with official Japanese data.
|
||||
|
||||
### 29.7 Verified reports and pending proposals
|
||||
|
||||
Muelsyse's deployed Harmony correctly adds one member to existing core bonds, without counting a benched copy or
|
||||
stacking duplicate traits. Six Kazimierz stuns nearby hovering enemies and makes them land; the radius remains 0.8.
|
||||
Targeted real-socket tests cover eliminated host/guest departures in prep/combat/unite and survivor reconnection.
|
||||
These checks did not reproduce the reported generic Harmony/room failures; no speculative rule change was made.
|
||||
|
||||
The plugin groundwork remains the existing content-pack manifest/language implementation; a runtime plugin API is
|
||||
not added. Additional dub languages remain deferred until supported resources exist. Other rule/AI proposals
|
||||
require explicit decisions and evidence; open PRs are not blanket approval for their implementations.
|
||||
|
||||
Validation and intended golden moves are recorded in §29.12.
|
||||
|
||||
### 29.8 Shared inventory (#466, #430; approved after reviewing the source video)
|
||||
|
||||
The maintainer requested the measured rules in 路标档案馆's original
|
||||
[路标月报 #2](https://www.bilibili.com/video/BV1eLXXBqEgF/) (2026-03-29): single-player operators around
|
||||
0:30–1:00, equipment around 1:30, co-op operators around 2:00, ownership/special grants around 2:30–4:00.
|
||||
Official client tables supply identities, tiers and merge recipes;
|
||||
[PRTS mode help](https://prts.wiki/w/卫戍协议/帮助) supplies equipment return/merge and hand rules.
|
||||
|
||||
| Stock | Base counts by tier I–VI | Exceptions |
|
||||
|---|---|---|
|
||||
| Single-player operators | 12 / 14 / 18 / 16 / 8 / 5 | I: 普罗旺斯、德克萨斯、跃跃、古米、格雷伊 = 10; II: 风丸 = 8, 赫默、休谟斯、砾、蒂比、调香师 = 12 |
|
||||
| Co-op shared operators | twice the single-player counts | exceptions doubled too; independent of seat count |
|
||||
| Shared shop equipment | 4 / 6 / 7 / 8 / 7 / 3 | 简易通讯机 = 5; 蜂鸣器、防暴盾、浓缩嗅盐 = 6; 寻呼模块、伪装服、拉特兰桥夹 = 7; 商业包装方案 = 2 |
|
||||
|
||||
- This explicit decision supersedes the old blanket shared counts and Muelsyse override. Private DIY stock keeps its
|
||||
per-player 8/5 capacities; the video's multiplier describes the shared pool.
|
||||
- Normal/elite operators occupy 1/3 copies by every gain route. Kazemaru still merges two normals, but the elite
|
||||
occupies three. Promotion also occupies the full three. Grants beyond capacity keep a negative internal balance:
|
||||
selling one copy cannot expose stock while ownership remains above the cap. Public availability and sampling are
|
||||
clamped at zero; `raw balance + owned copies = capacity` remains invariant.
|
||||
- Mimic samples eligible identities rather than remaining copies and can exceed stock, including the third-copy
|
||||
branch. This supersedes #207's old empty-pool failure. Other pool-weighted grants keep their selection rules.
|
||||
- Equipment across every player's hand, temporary area and equipped slots is counted live: normal 1, upgraded 2.
|
||||
Shop/choice displays reserve nothing. Exhausted purchases fail before charging or marking the offer taken; draft
|
||||
duplicates become unavailable when an earlier choice empties stock, and automatic picks skip them. Equipment
|
||||
returned from a sold/merged operator still occupies stock in the hand. 整备 upgrades the bought item only when
|
||||
another copy is still free (the purchase already took one, and a golden takes two). Otherwise the item stays
|
||||
normal and the 整备 charge is not spent. An uncapped item may still be upgraded. Held copies of every capped
|
||||
shop item stay within that cap.
|
||||
- [ASSUMED] Consumption/destruction/removal by elimination ends ownership and therefore releases equipment stock;
|
||||
the video does not separately document every removal path. A third lifetime purchase is possible after a prior
|
||||
copy leaves ownership. Non-shop effect-only equipment has no shared shop cap, consistent with unlimited special
|
||||
gifts. This never becomes a two-appearance or two-purchase limit for commercial packaging.
|
||||
- Stock counts alone do not establish probabilities. Existing shop tier shares, uniform item selection and explicit
|
||||
effect-pool weights remain, filtered for availability. No new probability curve is inferred from the table.
|
||||
- `shared-stock.test.js` covers exceptions, shared ownership, stale offers, reacquisition after destruction, upgraded
|
||||
occupancy, consumption, duplicate draft exhaustion and Mimic overdraw/release.
|
||||
|
||||
### 29.9 Ember proposal (#465) — current behavior preserved
|
||||
|
||||
The history in §22.8 and the 0.1.2 changelog records the chosen compromise for queued 深池逐火 enemies. Comparing
|
||||
the current code with the proposed phase-order swap reproduces that risk: after a blocker takes the next warrior,
|
||||
the three husk types can be finished by ranged hits in the current reveal window; the proposal hides them throughout
|
||||
that window and they stand up again. Reveal or spare blocking capacity defeats them in either version. This is not
|
||||
absolute invulnerability, but it removes the previously chosen counterplay window. The proposal is not adopted;
|
||||
the existing phase-order assumption remains pending a better official comparison.
|
||||
|
||||
### 29.10 Approved scope additions
|
||||
|
||||
- #467: Clementia S2 includes selectable airborne targets in the expanded skill attack grid when deciding to cast,
|
||||
like Chen S3. Normal attacks stay ground-only. [ASSUMED] No mode recording establishes a separate trigger shape
|
||||
for this new operator. Tier/form, range, stealth/sleep, stun and operation-cooldown regressions cover it.
|
||||
- #451: the reserve medic appears in preparation, scouting and boss-half views as a read-only map character,
|
||||
including fallback rendering. Touch replaces it when battle starts. Initial aggro order remains unchanged.
|
||||
|
||||
### 29.11 Champagne selection follow-up (#476, replaces #468)
|
||||
|
||||
[PRTS 香槟炸弹](https://prts.wiki/w/香槟炸弹) identifies it as a device, normally excluded from ordinary allied selection. Both bomb creation paths now share the internal `isolated` selection barrier: Angelina auras and Skadi inspiration no longer select it, while ordinary unhealable summons remain selectable. HP protection, no-heal behavior and detonation retain the previous rules. The new source is PR #476 by Siornya; its original-art portion was first proposed in #468. Both creation paths, ordinary-summon controls and existing aged/contact detonations are tested.
|
||||
|
||||
### 29.12 Validation and golden changes
|
||||
|
||||
Full regeneration after the post-revive Raid reselect, the shared-damage split and the 整备 stock check. The corpus is
|
||||
287 scenarios. No release scenario was removed. Two scenarios were added.
|
||||
|
||||
265 of the 285 release scenarios keep the 0.2.3 digest (`1db8e510`): roster 49/49, bonds 46/46, fields 22/22,
|
||||
stand-ins 10/10, and 138 of 140 DIY battles. The taunt order applies only to the one reselect after a revive, and
|
||||
these battle digests stay on the release result.
|
||||
|
||||
`diy-135` and `diy-136` move because their fields include Clementia. `op-clemnt.js` is the only operator kit on
|
||||
either field that differs from 0.2.3; the Mon3tr kit, and the defender, guard and sniper kits on `diy-136`, are the
|
||||
release kits. The splash and airborne-cast changes are §29.4 and §29.10.
|
||||
|
||||
- `diy-135` (Clementia S1–S3 and Mon3tr): `cleared` at 198.03 s, 150 kills, 0 leaks, perfect, 1 death becomes
|
||||
`timeout` at 230 s (5,941 → 6,900 ticks), 149 kills, 1 leak, not perfect, 0 deaths. Damage dealt 1,661,420 →
|
||||
1,648,194. The first unit row that moves is Clementia S1 (`chess_char_5_diy1_a`), kills 1 → 0.
|
||||
- `diy-136` (Clementia S1–S3 with defenders, guards and snipers): still `cleared` at 212.4 s, still not perfect.
|
||||
Kills 13 → 12, leaks 110 → 111, damage dealt 651,626 → 540,205. Clementia S2 (`chess_char_6_diy2_a`) kills
|
||||
7 → 6 and damage 383,594 → 320,372.
|
||||
|
||||
All 18 release matches move. Every one changes its shop-draw count, and the first settle row that differs changes
|
||||
the board hash (operator, tile and equipment). That is the shared-stock lineup change in §29.8. `solo-HARD-9-boosted`
|
||||
is the only match whose first differing row also changes kills and leaks; its board and bonds change on that same row.
|
||||
|
||||
The ending class changes:
|
||||
|
||||
- `solo-FUNNY-2`: defeat at round 8, team LP 0, boss HP left 17,162 becomes victory at round 9, team LP 2, boss
|
||||
cleared. Shop draws 123 → 154. The round-1 board changes and gains `yanShip 0/1`.
|
||||
- `solo-HARD-1`: victory at round 14, team LP 12, boss cleared becomes defeat at round 13, team LP 0, boss HP left
|
||||
341,377. Shop draws 201 → 215. The round-3 board changes.
|
||||
- `solo-HARD-2`: defeat at round 13, team LP 0, boss HP left 66,239 becomes victory at round 14, team LP 28, boss
|
||||
cleared. Shop draws 279 → 283. The round-1 board changes.
|
||||
- `solo-ABYSS-1`: eliminated in round 13 after 12 rounds becomes defeat at round 13, still alive, team LP 0, boss HP
|
||||
left 2,832,671, hidden boss unreached. Shop draws 138 → 215. The round-3 board changes.
|
||||
- `solo-ABYSS-2`: eliminated in round 12 after 11 rounds becomes defeat at round 13, still alive, team LP 0, boss HP
|
||||
left 2,823,834, hidden boss unreached. Shop draws 179 → 280. The round-1 board changes.
|
||||
- `coop3-ABYSS-5`: eliminated at round 11 becomes defeat at round 13, team LP 0, boss HP left 2,616,799, hidden boss
|
||||
unreached. `ai_0` stays eliminated in round 10. `ai_1` is no longer eliminated in round 12 and passes 13 rounds.
|
||||
`ai_2` is eliminated in round 11 after 10 rounds, previously round 10 after 9. Shop draws 531 → 506. The round-2
|
||||
board changes.
|
||||
- `coop4-ABYSS-7`: eliminated at round 12 becomes defeat at round 13, team LP 0, boss HP left 3,486,896, hidden boss
|
||||
unreached. `ai_0` is no longer eliminated in round 13 and passes 13 rounds. `ai_1` passes 8 → 11 rounds and is
|
||||
eliminated in round 12 instead of 9. `ai_2` passes 11 → 12 rounds and is eliminated in round 13 instead of 12.
|
||||
`ai_3` stays eliminated in round 8 after 7 rounds. Shop draws 539 → 645. Round-4 boards, bonds, pending gold and
|
||||
layer counts change.
|
||||
|
||||
Same victory and reason, team LP changes:
|
||||
|
||||
- `solo-FUNNY-1`: victory at round 9, team LP 27 → 16. Shop draws 142 → 87. The round-1 board drops `sargonShip`.
|
||||
- `solo-NORMAL-2`: victory at round 14, team LP 25 → 15. Shop draws 227 → 226. The round-1 board changes.
|
||||
- `coop2-NORMAL-3`: victory at round 14, team LP 68 → 51 (`ai_0` 41 → 34, `ai_1` 27 → 17). Shop draws 449 → 487.
|
||||
The round-3 `ai_1` board changes.
|
||||
- `coop2-NORMAL-8-serverrun`: victory at round 14, team LP 58 → 26 (`ai_0` 30 → 10, `ai_1` 28 → 16). Shop draws
|
||||
485 → 482. The round-1 `ai_1` board changes and `preciShip` goes from tier 1 to tier 0.
|
||||
- `coop2-NORMAL-14-standins`: victory at round 14, team LP 30 → 31 (human 17 → 18). Shop draws 428 → 403. The
|
||||
round-4 boards change and the human's `raidShip 1/8` is gone. Stand-ins were fielded in 10 of 13 settle rows at
|
||||
0.2.3 and in 0 of 13 now.
|
||||
- `coop2-ABYSS-10-boosted`: victory at round 15 with the hidden boss cleared, team LP 630 → 704 (`ai_0` 315 → 354,
|
||||
`ai_1` 315 → 350). Shop draws 591 → 649. The round-1 boards change.
|
||||
|
||||
Same victory, reason, rounds and team LP:
|
||||
|
||||
- `solo-NORMAL-1`: defeat at round 13, team LP 0. Boss HP left 884 → 50,897. Shop draws 207 → 159. The round-3
|
||||
board changes.
|
||||
- `solo-HARD-9-boosted`: victory at round 15, team LP 399, hidden boss cleared. Shop draws 346 → 343. Round 8
|
||||
changes the board, the bonds, gold, kills 18 → 19 and leaks 1 → 0 together; that row's LP is 399 → 400 and the
|
||||
final team LP stays 399.
|
||||
- `coop2-HARD-4`: eliminated at round 12. Shop draws 419 → 417. The round-3 boards and bonds change (`ai_0` gains
|
||||
`arcaneShip` and `preciShip`; `ai_1` loses `sargonShip`).
|
||||
- `coop2-NORMAL-70-diy`: victory at round 14, team LP 55. Shop draws 503 → 586. The round-3 boards change and the
|
||||
human's bonds become `miraShip` and `yanShip`. DIY operators were fielded in 6 of 13 settle rows at 0.2.3 and in
|
||||
0 of 13 now. Virtual duration 121,400 → 118,400 ms.
|
||||
- `coop4-FUNNY-6`: victory at round 14, team LP 130. Shop draws 832 → 952. The round-1 `ai_2` board, layers and
|
||||
bonds change. Virtual duration 130,000 → 127,000 ms.
|
||||
|
||||
Added coverage, both victories at round 14:
|
||||
|
||||
- `coop2-NORMAL-1-coverage-standins`: team LP 37 (human 11, bot 26). Stand-ins are fielded in 6 of 13 settle rows.
|
||||
- `coop2-NORMAL-5-coverage-diy`: team LP 30 (human 23, bot 7). DIY operators are fielded in 5 of 13 settle rows.
|
||||
|
||||
Seeds 14 and 70 keep their outcome rows and, under these lineups, field no stand-in and no DIY operator. The two
|
||||
added seeds carry those paths.
|
||||
|
||||
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. A refresh of the same field whose metadata lists no device keeps crates and turrets already noted from their one spawn event; metadata that names devices replaces that list. A different field does not keep the previous battle's devices.
|
||||
|
||||
### 29.13 Multiplayer boss Raid landing (#475)
|
||||
|
||||
The maintainer approved a narrow revision to §26.1 on 2026-10-10 after the report of three remaining multiplayer
|
||||
seats leaving one boss field unpaired. Only Raid in `mode_multi_*` Final Assault / Hidden Core battles may use the
|
||||
empty half's normal deployment area (rows 2–5, cols 2–18). This is an explicit maintainer decision on the community
|
||||
report, not a claim of independently verified official footage. Hand row 0, temporary row 1, single-player mode's
|
||||
empty boss half and lone-helper 联防's empty half stay closed. Terrain, field bounds, living/downed reservations,
|
||||
target ordering and attack reach retain their checks. The exception is local to Raid; general board membership,
|
||||
Ulpian S3 movement, summons and preparation placement do not expand.
|
||||
|
||||
`feedback5-raid-own-board.test.js` reproduces the eight left/right, melee/ranged, boss/hidden blocked cases before
|
||||
the fix, and checks actual solo modes, hand/temp/side margins, terrain and living/downed reservations afterward.
|
||||
All 287 golden scenarios were regenerated and verified with no additional digest changes. A fresh 80-match sample
|
||||
also had zero errors and unchanged wins, completed rounds and final LP versus the preceding candidate. Two co-op
|
||||
HARD runs changed round-14 counters: seed 33's unpaired player killed 22 enemies instead of 26; seed 39's unpaired
|
||||
player killed 5 instead of 6 and leaked 1 instead of 0. Opening more landing tiles does not guarantee better outcomes.
|
||||
|
||||
### 29.14 Device cards after field refresh
|
||||
|
||||
Re-entering the same battle with metadata that omits once-spawned devices now restores the remembered device records
|
||||
to the renderer as well as to the detail-card lookup. Otherwise an HP snapshot recreated the crate as an unknown
|
||||
enemy: picking emitted a unit click with no definition, instead of the tile click needed by the device card. The
|
||||
engine-canvas regression retains the card/100 HP assertions and also covers another field refresh, live HP loss and
|
||||
closing the card when the crate is destroyed. Device metadata supplied by the new entry still wins; changing fields
|
||||
does not carry old devices across. Gameplay and allied targeting rules are unchanged.
|
||||
Reference in new issue
Block a user