chore: sync ammo readout with upstream dev (#552)
This commit is contained in:
222 files changed
+10419
-2026
No files matched your search
@@ -0,0 +1,713 @@
|
||||
# DESIGN §30 — 0.2.5
|
||||
|
||||
Part of [DESIGN.md](../DESIGN.md). This chapter records 0.2.5, released on 2026-10-12.
|
||||
|
||||
## 30. Community follow-up
|
||||
|
||||
### 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.
|
||||
|
||||
### 30.17 Loadout sync preparation
|
||||
|
||||
PR #540 by @Xinglan233. Restoring defaults while a loadout sync was still waiting on backups.json could put the
|
||||
previous skill back on the server. `prepare()` assigned its request number only after the await, so the older
|
||||
payload was treated as the newer one. A stale missing-data result or a failed download could also replace a sync
|
||||
the reset had already finished.
|
||||
|
||||
`installPrefSync` now keeps a preparation revision. An edit of a watched field, including restoring defaults, and
|
||||
`welcome` increment it before the new flush is scheduled. A preparation that started at an older revision does not
|
||||
send and does not change sync status when it finishes, whether it built a payload, found the data missing, or
|
||||
failed. Debounce, the close flush, request ordering and the RATE / lock retry stay as they are. The same engine
|
||||
covers 干员持有 and 自选编队. Golden unchanged. Tests: `test/ui/loadout-sync-stale.test.js`.
|
||||
|
||||
### 30.18 Loadout import with ops while backups are missing
|
||||
|
||||
PR #538 by @Xinglan233. Importing a loadout file that includes `ops` checked only that chess.json was loaded.
|
||||
`cultivationCharIds` then dropped 自选 operators, which only backups.json names, and the import still saved. That
|
||||
cleared a 练度 the file was not meant to erase. `ops: {}` is the same replacement.
|
||||
|
||||
After a successful parse, `loadoutOpsImportRefusal` refuses the whole import with the 自选编队 data check
|
||||
(`importRefusal('diy')`) before any write. A file with no `ops` still imports skills and modules once chess.json is
|
||||
ready and leaves the current 练度 in place. Golden unchanged. Tests: `test/ui/loadout-ops-import.test.js` (node, no
|
||||
browser).
|
||||
|
||||
### 30.19 Player package scripts and doc links
|
||||
|
||||
GitHub #531 and #530. The player zip copied the repository `package.json`. `npm test` is `node --test`, and `test/`
|
||||
is not in the zip, so it reported 0 tests and exited 0. Nine other scripts name files or tools the zip does not
|
||||
contain (`golden`, `golden:update`, `build-data`, `check:imports`, `ci`, `package`, `package:lite`, `lint`,
|
||||
`typecheck`). README, CHANGELOG, NOTICE, THIRD-PARTY-NOTICES, PLAYING and DEPLOY also keep relative links to
|
||||
developer docs, pictures and `../../releases/latest`. Twenty-three of those, in README, PLAYING and DEPLOY, point
|
||||
at developer files.
|
||||
|
||||
The stage rewrites `package.json` only. A script stays when every `node <file>` it names is in the zip and it names
|
||||
at least one (`start`, `dev`, `setup`, `doctor`, `launch`, `postinstall`, `vendor`, `assets`). The others are
|
||||
removed, so `npm test` is a missing script and exits non-zero. The repository `package.json` is unchanged. The same
|
||||
stage rewrites those six Markdown files: a relative link whose target ships stays relative; a picture becomes
|
||||
`https://github.com/sganggs/Stronghold-Protocol/raw/v<tag>/<path>`; another file becomes `.../blob/v<tag>/<path>`;
|
||||
`../../releases/latest` becomes `.../releases/latest`. The tag is `v` plus the package version with a trailing
|
||||
`-dev` removed. [ASSUMED] an unreleased `0.2.5-dev` build points those links at `v0.2.5`, the tag that version will
|
||||
use. Source copies in the git checkout stay relative. Golden unchanged. Tests: `test/package-player.test.js`,
|
||||
`test/package.test.js`, `test/docs-paths.test.js`.
|
||||
|
||||
### 30.20 Official damage numbers and the title-page repository link
|
||||
|
||||
Issues #412 and #543. #412's font swap, element-colour pass and bold crit type are not part of this change.
|
||||
The new setting 「官方伤害数字」 (`officialDamageNumbers`) defaults off. While it is off, every rounded hit and
|
||||
heal still pops the existing typed number (merge, colours, 90-number ceiling, sparks and slashes unchanged).
|
||||
Turning 「显示伤害数字」 off still hides every digit, including official ones. The value is sanitised with the
|
||||
other settings (a missing or non-boolean saved value stays off) and copied into the live field view.
|
||||
|
||||
The official rule is PRTS [作战机制](https://prts.wiki/w/作战机制) 「伤害红字(暴击)」 (fetched 2026-10-12): show a
|
||||
red integer of the final damage when 最终伤害 ≥ 期望伤害 × 1.5, or when a skill forces red. Expected damage follows
|
||||
the normal formula except that DEF/RES penetration, post-mitigation bonuses (temporary attack-scale increases,
|
||||
damage-scale increases such as 脆弱, amount rewrites, barrier absorption), final-damage resets and special HP
|
||||
mechanisms are not counted. Invulnerable targets multiply expected damage by 0, and 0 ≥ 0 × 1.5 still shows red 0.
|
||||
A dodge of a hit that would have been red shows yellow MISS (`#ff9000`) instead. After 卫戍协议:盟约 the official
|
||||
client no longer caps red numbers at 10; this client does not restore that cap. The existing 90-number ceiling
|
||||
stays as a renderer limit [ASSUMED: 「无限制」 means the old cap of 10 is not brought back].
|
||||
|
||||
In this sim the comparison runs inside `dealDamage` and does not change HP, shields, hooks or RNG:
|
||||
|
||||
- Expected damage is mitigation of `dmg.amount` with penetration forced to 0, times `dmg.mul` only.
|
||||
- The compared total is the pre-shield amount after source and target multipliers. The integer on the existing
|
||||
`dmg` tuple — what both modes display — is what remains after shields and an `hpDamage` rewrite.
|
||||
- A qualifying tuple that already fires (`amount >= 0.5`, not silent) gains a fifth element `'r'`. Other tuples
|
||||
stay four elements. Element gauge fills are not marked. Heals are not marked, so official mode hides them.
|
||||
- A dodge that already fires sets `num: 'm'` on its fx payload only when the same test says the landed hit would
|
||||
be red. That test does not roll RNG again and does not refresh a dirty attacker's stats (a dirty `source.s`
|
||||
read rescales HP).
|
||||
|
||||
[ASSUMED] gaps, left unmarked rather than guessed:
|
||||
|
||||
- `dmg.amount` already includes the attack's stated ATK × 攻击倍率 (`atkScaleMul` is baked in by callers). It is
|
||||
not divided back out. `dmg.mul` stays on both sides of the comparison.
|
||||
- Cached-ATK expected damage (raw ATK, ignoring the attack scale and the target's DEF/RES), forced red, blue
|
||||
numbers and yellow BLOCK are not represented on DamageInfo. The three wiki examples are not hard-coded.
|
||||
- An invulnerable or sleeping hit, and a qualifying total below 0.5, still emit no `dmg` event, so official mode
|
||||
cannot show that red 0. Emitting one would increment `events.dmg` and could play an impact. The renderer can
|
||||
draw a red 0 when a tuple `['dmg', id, 0, type, 'r']` is supplied. Liftoff and a cancelled or hit-capped attack
|
||||
are not red 0.
|
||||
- PRTS does not say that ordinary hits are silent. That is the requested setting: official mode shows only the
|
||||
marked red integer and the yellow MISS. The sentence in the issue comment is not a PRTS sentence.
|
||||
- The random position is about ±0.35 tiles across and 0.15–0.55 tiles above the head. The simplified board keeps
|
||||
its fixed slot and only changes the colour / the MISS label.
|
||||
- Sparks and the melee slash stay in both modes.
|
||||
|
||||
#543: the title footer carries a text link labelled 「项目仓库」 to
|
||||
`https://github.com/sganggs/Stronghold-Protocol`, `target="_blank"` and `rel="noopener noreferrer"`. It does not
|
||||
replace 设置 → 问题反馈.
|
||||
|
||||
Tests: `test/sim/official-damage-numbers.test.js`, `test/ui/official-damage-numbers.test.js`,
|
||||
`test/render/official-numbers.test.js`. Golden digests do not move: no new event kind is emitted, and the extra
|
||||
tuple field is not part of the digest. Player notes: PLAYING; client notes: design/client.md.
|
||||
|
||||
### 30.21 Official battlefield scenes (#532)
|
||||
|
||||
Report: the web board draws the metal theme for every battlefield. The reporter asked for the sand theme.
|
||||
PR #533 by @andrew05060414.
|
||||
|
||||
Findings (2026-10-11; the official hot-update lists and asset indexes, read from the CDN, and the scene bundles of
|
||||
version `26-04-13-12-31-42_e9b560`):
|
||||
|
||||
- The official board is not assembled at run time. Every battlefield is a prebuilt scene bundle, shipped only while
|
||||
the season runs. DESIGN §15 said otherwise from an off-season list and is corrected there.
|
||||
- Which art a battlefield uses is the dependency list of its scene bundle: the sand theme for act1 m01–m07 and act2
|
||||
m02 / m04, `map_lakegarden` + `map_syracuse_metro` for act2 m01, `map_kxmr` + `map_lm_center` for act2 m03. The
|
||||
same in the 上半 version of 2025-11 and the 下半 versions of 2026-03 / 04. No battlefield uses the metal theme.
|
||||
- The sand theme bundle holds no mesh because the models are baked into each scene ("Combined Mesh (root: scene)").
|
||||
- A scene's three sub-graphics `HIDDEN@1…3` are the left normal field, the right normal field and the boss field.
|
||||
- `python3 tools/local-extract/fetch_scenes.py --list` against that Android hot-update list names 33 bundles and
|
||||
22,801,308 bytes. That is the compressed CDN download, not the extracted size in the full zip.
|
||||
|
||||
Change: `tools/local-extract/scenes.py` exports a battlefield's scene (meshes in board space, materials, key light,
|
||||
lightmap pages with the baked shadow mask in alpha, albedo textures) to `public/assets/local/scene/<stageId>/`;
|
||||
`extract.py --only scene` runs it, reading the scene bundles from the client, `--scenes <dir>` or
|
||||
`.cache/official-scenes/*`; `tools/local-extract/fetch_scenes.py` downloads the in-season bundles from the official
|
||||
CDN (md5-checked against that version's hot-update list). The 3D board draws a stage's scene when the local-art
|
||||
manifest lists it (`board3d/load.js loadScenePack`, `scene.js setScenePack`); the procedural metal board stays the
|
||||
fallback and still draws the devices, gates, field edges and terrain overlays. Chunks of the parts on screen that
|
||||
share a material and a lightmap page are one mesh (`mergeSceneChunks`), so a battlefield such as act2 m02 (36 chunks,
|
||||
5 lightmap pages) stays inside the board's draw-call budget. A switched-off HIDDEN part is left out of that mesh.
|
||||
|
||||
Owner decision (2026-10-12): the eleven scenes belong to the 0.2.5 asset pack. The maintainer's full release zip
|
||||
includes the extracted files. A lite package or a source install may download and extract them on that machine
|
||||
(`node tools/setup.mjs --scenes`; `--no-scenes` skips). Missing Python 3.8+ or UnityPy / lz4 / Pillow is a warning,
|
||||
and the metal board remains. The repository never stores the bundles or the extracted files (`.gitignore` already
|
||||
ignores `public/assets/`, `data/local-assets.json` and `.cache/`, and names `.cache/official-scenes/`). Packaging
|
||||
does not fail when the scenes are absent; the summary line `battlefield scenes` says whether this machine has them.
|
||||
`scenes.py` and `fetch_scenes.py` ship in a player zip only after they are committed, because the packager reads
|
||||
`git ls-files`.
|
||||
|
||||
No gameplay change: the scene is art under the same grid, camera and unit layer. Golden results are not moved by
|
||||
this change.
|
||||
|
||||
**[ASSUMED]** the light gains `SCENE_LIGHT` (`range` 8.0, `ambient` 0.2, `direct` 0.8, `indirect` 0.4) and the RGBM
|
||||
reading of the lightmap pages (Unity linear decode, range 5), both in DESIGN §15. Not done: the scene's normal /
|
||||
metallic / emission maps, map effects, sky box and post-processing; the tile graphics a level switches at run time
|
||||
(mire, tide) still use the remake's overlays. The extracted byte size inside a full zip was not measured here.
|
||||
|
||||
Tests: `test/render/board3d-scene.test.js` (the scene table against data/stages.json, board-space conversion, chunk
|
||||
layout shared by scenes.py and load.js, sub-graphic groups, RGBM decode, the loader with a fake store, BoardScene
|
||||
with a stub renderer: scene on / areas / fallback). `test/scene-assets.test.js` (setup's scene step, the full plan
|
||||
ships extracted scene files, the lite plan ships none, git ignores the bundles).
|
||||
|
||||
### 30.22 Prepared 外勤医疗 target order and preparation inspection
|
||||
|
||||
PR #523 by @YinqiMargatroid, continuing #451. PR #451 made 预备干员-医疗 visible in preparation and left its initial
|
||||
aggro order unchanged. The owner decided on 2026-10-12 to take both halves of this report as the author describes them.
|
||||
The retained team grant in §30.14 is unchanged: a confirmed Touch selection still supplies the medic after the holder
|
||||
is eliminated or leaves.
|
||||
|
||||
In the recording [卫戍协议](https://b23.tv/RQLI8WS), the right-side 联防 board at 19:13 has Touch and 哈洛德 inside the
|
||||
same flying 守墓石像's attack range when it locks its target, and the attack selects 哈洛德. The 17:01 preparation
|
||||
frame shows 哈洛德 with no equipment, and his position makes him the right player's first ordinary deployment under
|
||||
the current column scan. The 19:36 clip supplies another targeting comparison. [PRTS 卫戍协议/帮助](https://prts.wiki/w/卫戍协议/帮助)
|
||||
gives the column order and places operators before summons; [PRTS 作战机制](https://prts.wiki/w/作战机制) gives 索敌 as
|
||||
blocker, then special priority, then 仇恨, then earliest appearance. These observations support an effective priority
|
||||
earlier than ordinary operators for the prepared 外勤医疗 slot. They do not expose the official unit identity or the
|
||||
exact deployment counter.
|
||||
|
||||
The battle sim still creates the selected map-character variant at `battleStart`, after the board deployment.
|
||||
[ASSUMED] The prepared slot keeps an earlier effective targeting order whether it stays 预备干员-医疗 or is replaced
|
||||
by Touch. Only `aggroSeq` receives a negative pre-initial value (`i - chars.length` across every prepared character
|
||||
on the field); `deploySeq` remains the actual spawn's identity for deployment hooks and scheduled effects. `0` is not
|
||||
used, because `aggroCmp` treats a falsy `aggroSeq` as `deploySeq`. [ASSUMED] When several players have prepared slots,
|
||||
their relative order follows the existing player iteration, the same way other initial placements do. A map character
|
||||
spawned ad hoc after battle start, without `preBattleAggroSeq`, keeps ordinary summon order. Redeploy and device
|
||||
spawn still assign `aggroSeq` from the new `deploySeq`. The flying 守墓石像 tests check both variants at target-lock
|
||||
time, a right-side 联防 Touch ahead of the left medic and behind no ordinary operator, and the higher-taunt exception.
|
||||
|
||||
The further recording [准备阶段](https://b23.tv/4JXAp12) at 0:17 shows 预备干员-医疗 selected, with its detail card and
|
||||
attack range visible before combat. This shows an inspection affordance. It does not establish that the official game
|
||||
already simulates the medic as a combat entity during preparation. The client lets the existing read-only preparation
|
||||
view open its operator-style card and board-space range by tap, including on the mirrored boss half and in the flat
|
||||
fallback renderer. The original board-space record is kept for the card; only the rendered view is transformed. The
|
||||
preview stays immovable and is not sold or retreated. The battle creation point is unchanged. The same click path
|
||||
accepts another map-character variant if one is included in `prepMapChars`.
|
||||
|
||||
Normative lines: SIM.md §1 and §2 (`aggroSeq`, `spawnToken` `preBattleAggroSeq`), design/engine.md §5.5, design/client.md
|
||||
Interactions, design/network.md preparation state. Tests: `test/content/bands.test.js`, `test/content/tokens_devices.test.js`,
|
||||
`test/ui/inspect-range.test.js`, `test/ui/playtest6_summons.test.js`, `test/render/browser.test.js` (needs `RENDER_E2E=1`).
|
||||
|
||||
`npm run golden:update` recomputed all 287 scenarios against the preceding 0.2.5 candidate. No scenario was added or
|
||||
removed. Only `coop2-NORMAL-14-standins` moved. Its human seat holds `band_amedic`, so the team grant places the
|
||||
prepared map character on both fields; the earlier `aggroSeq` changes who those enemies strike, and the later bond
|
||||
and combat totals follow. The match stays a round-14 victory with team LP 31. The partner (`band_chiave`) first
|
||||
differs at round 11: activated layers 149 → 161, with 拉特兰 5 → 11 and 精准 24 → 30 in that settle row. Round 12
|
||||
continues the same layer gap (191 → 206). The human settle row first differs at round 13: kills 21 → 22, leaks
|
||||
36 → 35. Final human totals: kills 272 → 273, leaks 44 → 43, damage dealt 2,564,165 → 2,565,610, boss damage
|
||||
193,091 → 189,876. Partner boss damage 586,909 → 590,124, damage dealt 3,838,927 → 3,843,408, activated layers
|
||||
267 → 282; final bonds move 奥术 27 → 30, 拉特兰 17 → 23 and 精准 53 → 59. This scenario was not among the 45 that
|
||||
already differed from 0.2.4 (§30.9, §30.16), so the release-relative total is now 46. The other 286 digests match
|
||||
the preceding candidate.
|
||||
|
||||
### 30.23 Silenced 枯朽 death fog, and 自选 in the promotion reward
|
||||
|
||||
Two owner decisions of 2026-10-12. Neither is a new pool or a change to any other silence rule.
|
||||
|
||||
**#470.** `enemy_1267_nhpbr` (萨卡兹枯朽战士) and `enemy_1267_nhpbr_2` (萨卡兹枯朽战士组长) share one death ability,
|
||||
PollutedDie 【污染秽蚀】 (`kitPolluted`). A death while `flags.silence` is set creates no zone. The owner's official-play
|
||||
recall is that killing one which already shows the silence icon leaves no fog. That recall contradicts the PRTS /
|
||||
in-game text 「不可沉默」. Both handbook lines are `format: "NORMAL"` ("被击倒时释放污染秽蚀,使周围我方持续损失生命"),
|
||||
not `SILENCE`. 0.2.0 already withheld the fog (§25.18.2), from the general 死亡爆炸 line "如无特殊说明,此能力默认可沉默"
|
||||
and a client-template reading of `projectile_on_killed`. That section stays as the 0.2.0 reading. The reason recorded
|
||||
now is the owner's recall, against 「不可沉默」. The local gamedata cache does not contain the string 「不可沉默」; the
|
||||
contradiction is the issue title and the owner's statement.
|
||||
|
||||
The same ability is only those two keys. Checked and left unchanged: 萨卡兹枯朽战车 / 尖端 (`enemy_1272_nhtank`, `_2`)
|
||||
秽蚀轰击 is an attack skill with `_ignoreSilence` and `silenceImmune`; 枯朽之种 (`enemy_1269_nhfly`) self-destructs and
|
||||
is silence-immune; 枯朽萃聚使徒 (`enemy_1321_wdarft`) summons seeds and is silence-immune; 萨卡兹枯朽前锋 / 辟路前锋
|
||||
(`enemy_1422_lrsldr`, `_2`) deal arts while in a 源石污染区; 假想敌:蚀裂 (`enemy_9006_actoxi`) has a different death
|
||||
cloud that was already silenceable; 高能源石虫's 死亡爆炸 is a different ability. A silence that has expired does not
|
||||
stop the fog. A leak (`reason !== 'killed'`) still creates none. A killing blow that would apply silence only if the
|
||||
target is still alive is not this case: the report is the icon already showing.
|
||||
|
||||
**#515.** The promotion reward (three different operators, one tier above the 调度中心, at most 6, price 0) includes
|
||||
自选 operators of the newly reached tier, the way the ordinary shop includes them once the 调度中心 is at that tier.
|
||||
`pushRewardOffer` with no explicit `ids` now passes `diyStockEntries()` into `pool.roll`. The tier filter is unchanged,
|
||||
including the downward walk when a tier has no further distinct chess (playtest #6 item 19). Shop level 4 rolls reward
|
||||
tier 5, so a stocked tier-5 自选 piece can appear and a tier-6 piece cannot. Shop level 5 rolls reward tier 6, so a
|
||||
stocked tier-6 piece can appear; a tier-5 piece appears only if that roll walks down. Shop level 6 still can roll tier
|
||||
6. Shop level 3 rolls tier 4 and has no tier-4 自选 piece. The ordinary shop (`economy.js`, `diyRollEntries`) still
|
||||
waits for `shopLevel` 5 / 6. Effect offers that pass explicit `ids` do not roll. A 自选 piece is not guaranteed. A slot
|
||||
whose every bond is banned still has no stock. `left <= 0` stays out. Copy counts 8 / 5 stay [ASSUMED] and unchanged.
|
||||
|
||||
Seen: 卫戍协议/帮助 干员的获得与精锐化 describes a temporary refresh of three operators one tier above the 调度中心 and
|
||||
does not say that 自选 are excluded. The next section's note "仅在调度中心等级 ≥ 干员所在等阶时,该干员才有可能出现在栏位中"
|
||||
is the persistent shop: binding it to the refresh would leave a level-4 调度中心 with no tier-5 operator.
|
||||
`shopLevelDisplayDataDict` lists the tier-5 DIY slots at level 5 and the tier-6 slots at level 6; those rows are visible
|
||||
shop chess, and no second pool excludes them. No parsed page names 自选 inside the refresh. The inclusion is the
|
||||
owner's decision of 2026-10-12, not a new [ASSUMED]. 0.2.0 §25 had [ASSUMED] that the reward used the slot's shop
|
||||
level; that sentence stays there, and this section reverses it.
|
||||
|
||||
Normative lines: `server/match/player/acquire.js` `pushRewardOffer`, `server/match/player/diy.js`, META.md §3,
|
||||
DATA.md `rewardOffer` and §18, design/match.md economy, PLAYING.md 自选编队, SIM.md enemy damage zones,
|
||||
`server/sim/content/enemies/archetypes.js` `kitPolluted`. Tests: `test/match/diy-shop.test.js` (the reward tallies;
|
||||
the level-4 ordinary shop still rolls no tier-5 自选 piece), `test/content/enemies_bosses.test.js` (both keys, silenced
|
||||
and after the silence runs out).
|
||||
|
||||
`npm run golden:update` recomputed all 287 scenarios. No scenario was added or removed, and no digest moved.
|
||||
#470 does not change the sim: the fog was already withheld. #515 can change a promotion reward only when the seat
|
||||
has stocked 自选 of the reward tier and the 调度中心 is still below that slot's shop level. The two DIY matches start
|
||||
at shop level 5. `coop2-NORMAL-5-coverage-diy` rolls its only reward after the shop is already 6, where both iterators
|
||||
include the tier-6 stock, so the offer is the same. `coop2-NORMAL-70-diy` rolls four tier-6 rewards while the shop is
|
||||
still 5. On this seed the card the seat takes is the same operator as before. Rounds 8–10 differ only in an untaken
|
||||
card (round 8 swaps the other two; rounds 9 and 10 replace the third). The other level-5 offer is unchanged. Both
|
||||
level-6 offers match the previous roll, including the one that shows the tier-6 自选 piece, which the shop gate already
|
||||
allowed. The digest records
|
||||
shop draws, fielded pieces, board hashes and the rng state, not an untaken reward card, so the stored scenario does
|
||||
not move. The release-relative total against 0.2.4 stays 46.
|
||||
|
||||
### 30.24 Funnel normal attacks keep a body hit
|
||||
|
||||
PR #537 by @Xinglan233. [PRTS 分支特性信息 驭械术师](https://prts.wiki/w/分支特性信息/data) says a drone that has not
|
||||
been released by a skill deals additional damage on top of the operator's attack: 20 % ATK at first, +15 on the same
|
||||
target, cap 110 %. A skill-released drone deals skill damage.
|
||||
|
||||
The profession used to return that ramp as the whole normal-attack multiplier, so the body hit was missing.
|
||||
`resolveHit` now keeps a 100 % ATK body instance and separate drone instances. `funnelMul` holds only the drone ramp;
|
||||
an attack's `dmgMul` (至简's talent) is applied once to both. Extra attached drones raise `hits`, not the body count.
|
||||
至简's charged S2 sets `funnelBodyHits`, so two body hits and two additions share one ramp step. Both share one
|
||||
`attackId` and one attack hook; only the body is `isAttack`. Additions carry `addition` and `funnel` and are not also
|
||||
emitted as a normal attack.
|
||||
|
||||
[ASSUMED] Body instances precede additions at the existing projectile impact, and a multi-hit volley takes one ramp
|
||||
step. Ordinary attacks and any skill that only buffs or retargets the normal attack keep the body. `info.isSkill` is
|
||||
not the switch: every attack or targeting override sets it. `funnelBodyHits === 0` means the attack is drone-only
|
||||
(the ramp stays inside those hits and no body is added). 荒芜拉普兰德 S2 sets that. 至简 S2 sets `funnelBodyHits`
|
||||
to two, so two body hits and two additions still share one ramp step.
|
||||
|
||||
耶拉 S2, base and hidden, follows the 洛洛 S2 split. `skchr_kjera_2` (docs/research/03-operators.md) says 自身与浮游单元
|
||||
攻击, and the lock lasts until the enemy dies or the skill ends. While it runs, `funnelMul` is detached, so her own
|
||||
shot is one 100 % `isAttack` hit inside her range and the unreleased addition is off. `1 + attack@cnt` drones tick
|
||||
on their own (`kjera:drone`, arts, `isSkill`, not `isAttack`) and may stay outside her range. Cold is rolled once
|
||||
on the body and once on each drone hit. Ending the skill restores the multiplier.
|
||||
|
||||
[ASSUMED] Those released drones use the trait ramp (20 % → +15 % on the same target → the cap). Her blackboard has
|
||||
no drone scale; the branch page gives that ramp to drones that were not released. The base form continues its
|
||||
per-target ramp, and two drones on one enemy in the same tick take one step. That map is written back when the skill
|
||||
ends. The hidden form restarts each drone at the initial scale, and those scales are not written back onto the single
|
||||
trait ramp. There is no flight delay. A lock that can no longer be targeted is dropped and the drone retargets. Stun
|
||||
and disarm do not pause the released drones. An in-flight shot from before the skill can still step the live ramp;
|
||||
the skill keeps its own copy, and a shot that lands after the skill ends can step the restored ramp.
|
||||
|
||||
[ASSUMED] 荒芜拉普兰德 S1 says 释放浮游单元 and does not say she stops attacking. The toggle is read as a retarget of
|
||||
the unreleased attack: one body hit plus the two additions, at the raised ATK. A 洛洛-style release is not used.
|
||||
澄闪's skills and 荒芜拉普兰德 S3 stay on their own `dealDamage` paths. 澄闪 S3 and the skill-drone simulator on
|
||||
淬羽 are unchanged.
|
||||
|
||||
Kits that stored the ramp on `dmgMul` (至简, both 耶拉 forms, 澄闪 S2) now store it on `funnelMul`.
|
||||
|
||||
Tests: `test/sim/funnel-body.test.js`, and the funnel cases in `kits_t3`, `kits_t4`, `kits_t6`, `kits_alt_t6`,
|
||||
`kits_alt_t2` and `op_gdglow`. The golden moves from this correction, measured against the candidate after §30.29,
|
||||
are §30.30.
|
||||
|
||||
### 30.25 Redeploy resets the drone ramp
|
||||
|
||||
PR #536 by @Xinglan233. The same branch page says that changing target, or redeploying the operator, restores the
|
||||
drone damage to its initial value at once.
|
||||
|
||||
`installFunnel` resets `funnelTarget`, `funnelScale` and the per-target `funnelMap` (耶拉 / 至简) on a normal
|
||||
deployment, including automatic revival against the same living target. A free move (`moveRedeploy`, the same carry
|
||||
as a 秘术师's stored energy and 乌尔比安 S3) keeps the ramp. An in-flight drone still applies the ramp it computes on
|
||||
impact, so a shot launched before the reset can step the new ramp. That limit is documented and not changed.
|
||||
|
||||
Tests: `test/sim/funnel-redeploy.test.js`, `test/match/funnel-redeploy.test.js`.
|
||||
|
||||
### 30.26 洛洛 S2 keeps its lock outside her range
|
||||
|
||||
PR #535 by @Xinglan233. The official skill table `skchr_rockr_2`, as recorded in `docs/research/03-operators.md`,
|
||||
says the released drone stays locked until the enemy is killed or the skill ends, then returns. Leaving her attack
|
||||
range is not a return condition. The branch page says a skill-released drone deals skill damage, and that additional
|
||||
damage belongs to drones that were not released.
|
||||
|
||||
S2 now runs one independent skill tick (`rockr:drone`, one drone at both ranks). While the skill is up the trait
|
||||
multiplier is detached, so new body shots are ordinary attacks and the unreleased addition is off. The drone's hits
|
||||
are arts skill damage (`isSkill`, not `isAttack`). It inherits the trait ramp on its own copy, so an older projectile
|
||||
cannot change that ramp. A living selectable lock stays valid outside the body's range. Ending the skill writes the
|
||||
ramp back and restores the multiplier and the overload cap. S1 and other operators' funnel attacks keep their
|
||||
existing paths. 立于磐石 is unchanged.
|
||||
|
||||
[ASSUMED] There is no flight delay. A lock that becomes untargetable is dropped and the drone retargets. Body control
|
||||
(stun and the like) does not pause the released drone.
|
||||
|
||||
Tests: `test/content/rockrock-s2-lock.test.js`, and the 洛洛 case in `kits_t1t2`.
|
||||
|
||||
### 30.27 Hit tiles use half-even rounding
|
||||
|
||||
PR #520 by @Cloudnyco. PRTS 作战机制 (oldid 433935, 「碰撞体积与位置识别」) says the struck unit's coordinates are
|
||||
rounded half to even (四舍六入五成双) onto the tile they occupy. `Math.round` sends an exact .5 toward +∞, so an enemy
|
||||
held on an outer half-tile was indexed off the board and dropped from the hit index.
|
||||
|
||||
`roundHalfEven` is used for hit tiles only: `body.js` `posKey`, the point cases of `bodyOnTile` and `bodyTileReach`,
|
||||
the point-enemy index in `battle/queries.js`, and `targeting.js` `tileKeyOf`. Movement, knockback, `ai.js`, a unit's
|
||||
standing tile for range keys, and `onFrontLine` still use `Math.round`. #519's signed-zero case in `powi` was already
|
||||
on this candidate and is left as it is.
|
||||
|
||||
[ASSUMED] `FIELD_EDGE_INSET` = 1/1048576 pulls a clamped enemy just inside the outer half-tile, so half-even rounding
|
||||
keeps it on the edge tile. An inset of 1/1024 was rejected because it moved unbalance steps. The inset has no
|
||||
official source.
|
||||
|
||||
Tests: `test/sim/hit-tile-round.test.js`, `test/sim/detmath.test.js`, the edge landing in
|
||||
`feedback5-raid-own-board`, the 连星 probe in `op_wang`, and the 麦哲伦 probe in `feedback5-wv-summon-triggers`.
|
||||
|
||||
### 30.28 Bots soft-reserve a living teammate's opening bonds
|
||||
|
||||
PR #518 by @IceCodeNew, for issue #514. This is not an official rule. It extends the accepted #407 card penalty.
|
||||
|
||||
Opening-band choice and focus planning used to ignore a living teammate's selected strategy until someone from it was
|
||||
deployed, so a bot could take that faction's high cards. A living teammate's strategy now soft-reserves its bonds for
|
||||
both choices, before any member is deployed. The reservation ends when that teammate is eliminated (`alivePlayers`).
|
||||
It does not hard-exclude a strategy, reserve stock, or stop an immediate merge. A reserved band's draw weight is a
|
||||
quarter of its unreserved weight (`SOFT_BAND_RESERVE` = 0.25) and stays above zero, so the strategy can still be
|
||||
drawn. Focus planning applies the existing −6 teammate penalty to those bonds as well. Mode-inactive bonds stay
|
||||
weight 0 (DESIGN §21.26). A solo match has no teammate to reserve against. The shared-pool −18 card penalty is
|
||||
unchanged, and a stronger merge can still win it.
|
||||
|
||||
[ASSUMED] The quarter weight is a project choice. The PR text called the reservation soft; its diff hard-zeroed the
|
||||
weight. This candidate follows the text. The reservation is equal for human and AI teammates.
|
||||
|
||||
Tests: the two `#514` cases in `test/match/bot-smarter.test.js`. One proves the focus leaves the reserved bond while
|
||||
the teammate lives and returns after elimination. The other proves a reserved strategy is still drawn, and drawn more
|
||||
often once that teammate is eliminated. The existing card test still shows a merge outscoring the −18 penalty.
|
||||
|
||||
### 30.29 Golden changes after the funnel, hit-tile and bot-reservation ports
|
||||
|
||||
All 287 scenarios were recomputed once after §30.24–§30.28 and compared with this candidate before those ports
|
||||
(`HEAD` `7fd0478d`, `git show HEAD:test/golden/*.json`). No scenario was added or removed. 43 digests differ from
|
||||
that candidate. They are additional to §30.9 and §30.16.
|
||||
|
||||
Against released 0.2.4 the total is now 64. Of the previous 45, 21 are byte-for-byte the digests already on this
|
||||
candidate and are not repeated below: `roster-011`, `roster-012`, `roster-013`, `roster-032`, `roster-033`,
|
||||
`roster-034`, `roster-039`, `roster-040`, `roster-043`, `bond-maniShip-high`, `bond-yanShip-low`,
|
||||
`boss-boss_2-pair`, `boss-boss_5-solo`, `hidden-boss_8-pair`, `hidden-boss_9-solo`, `solo-NORMAL-2`,
|
||||
`coop2-NORMAL-3`, `solo-HARD-9-boosted`, `coop2-ABYSS-10-boosted`, `standin-06`, `standin-07`. The other 24 of
|
||||
those 45 moved again, and 19 scenarios that still matched 0.2.4 on this candidate now differ.
|
||||
|
||||
Opening strategy ids do not change in any of the 20 match digests. A solo match has no teammate, so §30.28 cannot
|
||||
move one. Co-op seeds keep the same `bandId` and the same bot-draw counts except `coop4-ABYSS-7`. The recorded
|
||||
match moves are battle totals from §30.24–§30.27, and the later gold and LP those totals change. No isolated
|
||||
counterfactual was re-run; the groups below follow who is actually on the board.
|
||||
|
||||
| Cause | Changed scenarios |
|
||||
|---|---|
|
||||
| Funnel body hit plus redeploy reset, and 洛洛 S2's independent lock (§30.24–§30.26). These boards include 洛洛 | `roster-004`, `roster-005`, `roster-023`, `roster-024`, `bond-victoriaShip-low`, `bond-victoriaShip-high` |
|
||||
| Funnel body hit plus redeploy reset (§30.24–§30.25). 至简 and/or 耶拉, not 洛洛 | `roster-007`, `roster-009`, `roster-026`, `roster-028`, `bond-deputShip-low`, `bond-emptyShip-low`, `bond-kjeragShip-high`, `bond-maniShip-low`, `bond-miraShip-low`, `bond-sargonShip-high`, `bond-soloShip-low`, `bond-visiShip-low` |
|
||||
| Same body hit and redeploy reset on 荒芜拉普兰德 | `roster-017`, `roster-019`, `roster-036`, `roster-046`, `roster-047`, `boss-boss_3-pair`, `boss-boss_5-pair`, `boss-boss_7-pair`, `hidden-boss_9-pair` |
|
||||
| 澄闪 DIY: the normal attack is a body hit plus one drone addition (§30.24) | `diy-098`, `diy-099` |
|
||||
| Hit-tile half-even rounding and the edge inset (§30.27). No funnel operator is deployed; the damage total stays 1388100 and the hook counts and the snapshot sample at index 27 move | `standin-04` |
|
||||
| Full matches. Opening bands are unchanged. Final lineups include a funnel operator, except `coop2-HARD-4` (both seats eliminated, lineup empty) and `coop3-ABYSS-5` (the surviving lineup has none), whose first divergence is round 7 and round 5; those two are the hit-tile change, or a funnel operator who is not left in the stored lineup | `solo-FUNNY-1`, `solo-FUNNY-2`, `solo-NORMAL-1`, `solo-HARD-1`, `solo-ABYSS-1`, `coop2-HARD-4`, `coop2-NORMAL-1-coverage-standins`, `coop2-NORMAL-5-coverage-diy`, `coop2-NORMAL-8-serverrun`, `coop2-NORMAL-70-diy`, `coop3-ABYSS-5`, `coop4-FUNNY-6`, `coop4-ABYSS-7` |
|
||||
|
||||
Result flips inside that match list: `solo-NORMAL-1` defeat → victory (team LP 0 → 2); `solo-FUNNY-1` team LP 15 → 23
|
||||
and `solo-FUNNY-2` team LP 8 → 23, both still victories, with every settled round row unchanged; `coop2-NORMAL-8-serverrun`
|
||||
team LP 26 → 27; `coop4-ABYSS-7` eliminated at round 12 → defeat at round 13, and its shop and bot draw counts change.
|
||||
The other matches keep the same end reason. `standin-04` is the only battle in this set with no funnel operator on
|
||||
the board.
|
||||
|
||||
### 30.30 Golden changes after the skill-only funnel body correction
|
||||
|
||||
All 287 scenarios were recomputed after the §30.24 correction (a skill that only buffs or retargets keeps the body;
|
||||
耶拉 S2 uses the 洛洛 split) and compared with this candidate after §30.29 (`HEAD` `e0f37718`,
|
||||
`git show HEAD:test/golden/*.json`). No scenario was added or removed. `fields`, `standins` and `diy` are unchanged
|
||||
(澄闪 stays on `dealDamage`). 19 digests differ. They are additional to §30.9, §30.16 and §30.29. Seventeen of them
|
||||
already moved in §30.29 and move again. `roster-038` and `coop2-NORMAL-14-standins` did not move in §30.29.
|
||||
|
||||
Opening strategy ids do not change in any of the 20 match digests. No isolated counterfactual was re-run. The roster
|
||||
and bond rows name the skill index the corpus assigns: 耶拉 index 1 is 心随意动, 荒芜拉普兰德 index 0 is 慵怠者悲鸣.
|
||||
至简 is on two of those roster boards at index 1; her S2 already kept two body hits, and her totals move because the
|
||||
fight around 耶拉 changed.
|
||||
|
||||
| Cause | Changed scenarios |
|
||||
|---|---|
|
||||
| 耶拉 S2, base form, skill index 1. `roster-007` also fields 至简 S2 | `roster-007`, `roster-009` |
|
||||
| 耶拉 S2, skill index 1. No 荒芜拉普兰德 on the board | `bond-emptyShip-low`, `bond-kjeragShip-high`, `bond-miraShip-low`, `bond-soloShip-low` |
|
||||
| 荒芜拉普兰德 S1, skill index 0. The toggle keeps one body hit and both unreleased additions | `roster-036`, `roster-038` |
|
||||
|
||||
Battle-total flips in that table: `roster-007` killed 132 → 137, leaks 41 → 37, coins 4 → 6, deaths 11 → 10, damage
|
||||
234357 → 243212 (耶拉's own damage 9204 → 17443; 至简 8936 → 9558). `roster-009` keeps the same kills and leaks;
|
||||
耶拉's damage 2 → 3 and 至简's kills 28 → 29, damage 7594 → 7168. `roster-036` killed 75 → 76, leaks 55 → 54,
|
||||
damage 1160465 → 1189341 (荒芜拉普兰德 60604 → 99946, kills 2 → 3). `roster-038` damage 3467641 → 3468742
|
||||
(荒芜拉普兰德 kills 4 → 14, damage 106163 → 187571). The four bonds keep the same kills and leaks. `bond-emptyShip-low`
|
||||
healing 381 → 362; 耶拉's damage 6585 → 11450 (kills 1 → 3), `bond-kjeragShip-high` 6927 → 16312,
|
||||
`bond-miraShip-low` 10165 → 18617 (kills 2 → 4), `bond-soloShip-low` 1963 → 2764.
|
||||
|
||||
Match end and the final lineup. A bot's chosen skill is not stored. Where the final lineup still contains 耶拉, her
|
||||
default skill is S2, which is the skill this correction changes.
|
||||
|
||||
| Final lineup | Changed scenarios and the recorded end |
|
||||
|---|---|
|
||||
| 耶拉, lineup unchanged | `solo-FUNNY-1` (`3_20_b`): victory, team LP 23 → 27; only round 8's bond layers move (steadShip 34 → 35). `solo-FUNNY-2` (`3_20_a`): victory, team LP 23 → 29; all eight stored round rows are identical, so the LP change is the boss round. `solo-NORMAL-1` (`3_20_b`): victory, team LP 2 → 11; first divergence round 10 (kjeragShip 13 → 14). `solo-HARD-1` (`3_20_a` and 至简 `3_13_a`): still a defeat, team LP 0, boss pool 215042 → 212054; first divergence round 8, the board hash. `coop2-NORMAL-8-serverrun` (ai_1 `3_20_a`): victory, team LP 27 → 37 (ai_0 LP 10 → 19, ai_1 LP 17 → 18); first divergence round 8, ai_1 killed 22 → 23, leaks 1 → 0. `coop2-NORMAL-5-coverage-diy` (ai_0 `3_20_a`): victory, team LP 33 → 34 (h_0 LP 27 → 28); first divergence round 13, ai_0's board hash, killed 26 → 21, leaks 17 → 22 |
|
||||
| 耶拉 was on the pre-change lineup; that seat is then eliminated and the stored lineup is empty | `solo-ABYSS-1`: defeat at round 13 → eliminated at round 12, team LP 0 → null. The pre-change lineup had 耶拉 `3_20_a` and 至简 `3_13_a`. First divergence round 8: LP 27 → 18, killed 19 → 10, leaks 0 → 9. `coop4-ABYSS-7`: still a defeat at round 13, team LP 0, boss pool 4821366 → 3417504. ai_1 is eliminated at round 13; the pre-change lineup had 至简 `3_13_a` and 耶拉 `3_20_a`. First divergence round 8: ai_1 LP 19 → 20, killed 2 → 3, leaks 7 → 6. ai_0's lineup also changes and has no funnel chess id before or after |
|
||||
| 耶拉 plus other funnel operators, lineup unchanged, same victory and the same team LP 130 | `coop4-FUNNY-6`: ai_0 耶拉 `3_20_a`, ai_1 荒芜拉普兰德 `6_18_a`, ai_3 洛洛 `2_10_a`. First divergence round 11, ai_0's kjeragShip layers 26 → 23 |
|
||||
| No 耶拉 on the final lineup. The diverging round's pieces and skill choice are not stored | `coop2-NORMAL-1-coverage-standins`: still a defeat, team LP 0, boss pool 25040 unchanged. ai_0's final lineup includes 荒芜拉普兰德 `6_18_a`. First divergence round 7, the other seat's miraShip layer 5 → 6. `coop2-NORMAL-14-standins`: victory, team LP 31 → 40 (ai_0 LP 13 → 22). Neither final lineup contains a funnel chess id. First divergence round 10 bond layers (raidShip 26 → 28, steadShip 16 → 18); that round's board hash is unchanged |
|
||||
|
||||
### 30.31 Ammunition readout
|
||||
|
||||
Active ammunition skills show remaining rounds and magazine capacity below the segmented bar (§10), including
|
||||
Laterano's extra rounds and refills. The renderer reads the existing exact snapshot counts rather than estimating
|
||||
them from SP. Missing ammunition snapshots, preparation and death hide the number. Dense magazines retain their
|
||||
numeric readout when the renderer omits cell separators. Combat rules and golden results are unchanged.
|
||||
Reference in new issue
Block a user