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:
sganggs committed 2026-10-12 14:07:08 +08:00
1 parent bc50cac01f
commit 221e6b8dd2
134 files changed
+4590 -1201

No files matched your search

+24 -8
View File
@@ -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).