129 Commits
Author SHA1 Message Date
sganggs 221e6b8dd2 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.
2026-10-12 14:07:08 +08:00
sganggs 6bfc08270c 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.
2026-10-11 01:58:52 +08:00
sganggs 708caf7d06 fix: correct community-reported combat and strategy draft behavior
Guard lethal stuns against a replacement deployment; keep bard auras running
through stun; require an active Aegir bond for Clementia's strategy; allow
Compass SP to bypass recovery locks; and refresh Hidden Core gun mitigation
against current gun/spring companions. Set multiplayer strategy picks to 50s
and describe renderer fallback without diagnosing unsupported hardware.

Golden moves (full 285-scenario regeneration):
- roster-008: inactive Aegir no longer gains 18 strategy layers.
- boss-boss_4-solo: bard regeneration continues through stun.
- hidden-boss_9-pair: mitigation covers first hits/current companions.
- standin-07: hammer stun cannot follow an immediate revival deployment.
No ending-reason changes. Sources and report-by-report findings: DESIGN 28.25.
2026-10-10 00:45:41 +08:00
sganggs f3658a0dd4 0.2.3: prepare follow-up fixes and client features (#407, #408, #410, #413, #431, #435, #436, #440, #444)
Add special-target activation without bypassing attack cadence, cooperative
card preferences and emotes, skill sound banks, per-operator voice choices,
text sizing, install prompts, closed-tab recovery and unanimous setup rerolls.
Retain late deployment elapsed time and resolve echo/counter pulses without
recursive hook overflow. Independent final review remains pending.

Golden: roster-016, roster-035, roster-036, roster-045;
boss-boss_1-pair, boss-boss_3-pair, boss-boss_5-pair, boss-boss_7-pair,
hidden-boss_9-pair; solo-HARD-9-boosted: Lemuen attack cadence.
diy-132: Necras extra activation targets.
coop2-NORMAL-14-standins: cooperative purchase preference and simulation fixes.
hidden-boss_10-solo: echo pulse FIFO resolution.
See DESIGN 28.13-28.24 for assumptions, sources and contributor credit.
2026-10-09 22:55:24 +08:00
sganggs 2e122873f0 0.2.3: add Clementia and Shu/Ulpianus modules (#437)
Regenerate roster-019, roster-038 and diy-059 through diy-140 for added and regrouped loadouts; other golden families unchanged.
2026-10-09 17:10:30 +08:00
sganggs 0ced21d321 feedback7: merge fb7-loadout — per-operator 潜能 (1–6) and 练度 (未精英化 / 精英1 / 精英2 / 精英2 Lv.60) set in 干员调配, defaults 潜能 6 and 精英2 Lv.60 (the owner's decision of 2026-10-08); PR #301 ported as one aligned list; #398 the skill frame, #400 REA-Y's heal text
- Conflicts (the branch started at ae22335c): the four i18n packs (union of keys), game.js DetailPanel props (ops + the
  voices' voice=true), detailPanel.js resolveDetail (cultOpts + the voices' tap), match/views.js (both helpers),
  docs/PLAYING.md and design/network.md merged line by line against the base. test/match/bosshp.test.js's ATK formula
  now includes the unit's 练度 multiplier (cultMul).
- Grok review: MERGE AFTER FIXES — the note and the module card at the set potential fixed on the branch.
- Golden: every owned operator ×1.1 ATK / DEF / max HP by default — roster 49, bonds 46, fields 22, matches 18, diy 134
  (stand-in battles and prototype picks unchanged). Broad node --test 5666 (0 fail after the bosshp formula; 2 skipped);
  lint 0 errors; typecheck; i18n strict clean (1152 msgids).
2026-10-08 22:35:33 +08:00
sganggs 6629710632 feedback7 R22-LOADOUT: 圣约送葬人's REA-Y shows the trait's heal as 50 per enemy hit, as the battle heals (GitHub #400); golden: unchanged
#400 by @PCL1234: 干员调配 (and every card that shows the elite with REA-Y — 局内数值, the shop / detail card) read
「每攻击到一个敌人回复自身12生命」; the battle heals 50. Cause: official battle_equip_table uniequip_003_excu2 has a
DISPLAY part (display only) whose blackboard `value` 12 fills its own added line 「攻击范围内存在2名及以上敌人时攻击速度
+{value}」; tools/build-data.mjs applyModuleTraitParts merged that blackboard into the trait's before writing the class
trait 「…回复自身{value}生命…」, so the trait line took 12 (not potential, not the module level: the text template).
The sim already healed 50 (the kit reads traitBase for REA-Y). Now the trait line is written with the blackboards of
the parts that carry trait data (TRAIT / TRAIT_DATA_ONLY / OVERWRITE_BATTLE_DATA) or rewrite the line; a DISPLAY part
that only adds a line fills that line. `trait.bb` (what the kits read) is unchanged, as are tokens' traits.

- Data: chess.json — exactly chess_char_5_01_b REA-Y traitOverride desc / descRaw (12 → 50); backups / tokens and
  every other file identical. data/i18n rebuilt offline (en / ja / ko / zh-TW): only that text and the record hash.
- Docs: DATA.md `trait` row.
- Tests: test/data.test.js (REA-Y's line = the class trait's, its added line +12, REA-X 60; no module line anywhere
  differs from its class trait only in its own added line's numbers — fails on the old data); test/content/
  kits_alt_t5.test.js (the reaper heal 50 with REA-Y / none, 60 with REA-X); test/ui/loadout-rows.test.js (the
  干员调配 module card: 特性 50, 特性追加 +12). GOLDEN_FULL: unchanged.
2026-10-08 22:26:00 +08:00
sganggs 7e09c63da8 feedback7 R22-LOADOUT: the data carries every potential (潜能 1–6), not only full potential; golden: unchanged
Potential becomes a per-player setting (the owner's decision of 2026-10-08: 「调配干员里自己设置吧,默认满潜满加成」;
official: 调度手册 「卫戍协议中干员潜能由自身已持有干员潜能决定」). 0.2.1 baked full potential into the data (§26.14).

- tools/build-data.mjs runs the chess / backups / tokens builders once per potential rank (ctx.potRank, 0–5) and keeps
  the full-potential build annotated with what each lower rank changes: `potDown` { rank: { dotted.path: value } } on
  chess records, backups.json forms and token variants (stats, statsBase; 望's 棋子 deployLimit / deckStack, 多萝西's
  共振装置 count), and chained talent entries (`potMin` / `potBelow`: the candidates by requiredPotentialRank, the
  fields a lower rank changes) in talents / talentsBase / modules[].talentChanges / variant talents. A self-check proves
  shared/potential.js atRank rebuilds every rank exactly; the unit-form parity runs at every rank.
- shared/potential.js (new): atPotential / atRank, talentAtRank, stripPotential, and the 练度 helpers used next
  (cultivateMul from the effects.json CHAR_MAP records aceffect_char_1…4, cultivationOf, cultivatedStats).
- composeTalents / composeUnitRecord return potential-resolved lists (no chains): a composed record is built at one
  potential (its form resolved first).
- JSON compare: the new chess / backups / tokens minus the annotations equal the old files byte for byte; every other
  data file identical; data/i18n/* rebuilt (the chained talent texts translated at the old rates: en 95.4 %, ja 95.2 %,
  ko 95.2 %, zh-TW 90 %). Data 5.21 → 5.51 MB.
- Docs: DATA.md §2.3 (new), §2, §7, §14, §16, §18; research/03-operators.md; kits/README.md.
- Tests: test/potential.test.js (new, 7): every chess and 自选 form at every potential = the raw keyframes plus the
  potential steps up to it, every talent = the last candidate with requiredPotentialRank ≤ the rank, 刺玫 at each
  potential, summons at the owner's potential (Mon3tr 3 s / 1200, 望's 棋子 6 / 7, “小自在” 15), the 练度 table =
  cultivateEffectList; data.test.js compares the composed talents without annotations.
2026-10-08 20:29:06 +08:00
sganggs ddf8c39ed0 feedback7 R22-VOICES: the Japanese voice dub as a second tree beside the Chinese one — audio.voiceJp (the same slots and file names from ArknightsAssets2 voice/: 2674 files, 89.4 MB, for the 191 voiced operators), 设置 → 语音语言 中文 / 日本語 (default 中文, not tied to the interface language), a JP line the manifest or the host lacks plays the Chinese one; the full zip ships both dubs (one switch, tools/package.mjs FULL_ZIP_JP_VOICE), the lite zip stays art-free (the owner's request of 2026-10-08 「全套的日配语音」); golden: unchanged
- tools/assets/plan.mjs: one voiceTree() per dub — audio.voice (--voice-lang, cn by default) and audio.voiceJp
  (VOICE_JP_LANG, always the JP dub, audio/voice/jp/<charId>/cn_nnn.mp3); fetch-assets plans and downloads both
  (stats.voiceJpChars), so setup (checkAssets walks every listed URL) fetches both too.
- data/assets.json regenerated with the project's tool (node tools/fetch-assets.mjs --add-only, raw.githubusercontent.com,
  107 s): the only change is audio.voiceJp + stats (+2674 files, +89,388,041 bytes, voiceJpChars 191) + hash — the rest
  is byte-identical; the JP tree is the Chinese one with the folder swapped (191 × 14 files, every file a valid MP3).
  The audio files are not committed (public/assets/ is git-ignored).
- public/js/audio.js voiceLine(): 'jp' draws from voiceJp and falls back to the Chinese line per slot (a JP entry the
  manifest lacks) and per line at play time (the Chinese file of the same name when the host lacks the JP one —
  same token, same gate); operators without voice (stand-ins, 盟约·辅助干员, summons) stay silent. setVoiceLang().
- settings: voiceLang 'cn' | 'jp' (VOICE_LANGS, sanitizeSettings), the 语音语言 row under 干员语音 (each dub named in
  its own language, like the language switch), 语音语言 in the en / ja / ko / zh-TW packs.
- tools/package.mjs FULL_ZIP_JP_VOICE (true): false holds the JP files out of the full zip (and its update zip) —
  not missing, not orphans, never in an update's `removed`; setup then downloads them.
- Sizes measured: art download 548 MiB (was 463), full zip ≈ 505 MB (0.2.1: 428 MiB + 76 MiB of zipped JP voice),
  unzipped 711 MB (package --dry-run); lite zip unchanged. README, DEPLOY, ASSETS, setup's fallback size updated;
  PLAYING voice paragraph; §21.30 "Changed in 0.2.2" note.
Tests: test/feedback7-voices.test.js (new: plan, manifest, settings, package switch), test/ui/audio.test.js (voiceLine,
the manager's dub choice and fallback), test/ui/gameLogic.test.js, test/docs-consistency.test.js — all fail on the parent.
2026-10-08 19:09:52 +08:00
sganggs b05845f507 feedback6: merge R21P — every operator at full potential (潜能 6; GitHub #252, PR #255 by @SpiritedAwayCN, the owner's decision of 2026-10-07)
- tools/build-data.mjs applies every potentialRanks attribute step (COST, RESPAWN_TIME, ATK, MAX_HP, DEF,
  MAGIC_RESISTANCE, ATTACK_SPEED) to the chess, elites, 补位 and 自选 units and picks talent / trait / module-talent
  candidates up to requiredPotentialRank 5; summons take the owner's potential for their talents, not its stat steps.
  data/chess.json, backups.json, tokens.json and the en / ja / ko / zh-TW data translations rebuilt; op-wang.js reads
  her stock cap (8 at full potential). 刺玫 435 ATK / cost 15, 砾 16 s, 至简 70 s.
- No conflicts outside the golden files (regenerated). Golden vs HEAD: roster 49, bonds 46, fields 22, matches 18,
  diy 133 (standins and diy-012 / diy-135…138 unchanged: no potential ranks or never hit). Union check against the
  branch and the merge base: every scenario only the branch moved equals the branch, except roster-048 and
  solo-ABYSS-2: at full potential a 频次 器物 is reached there (roster-048: one more enemy dies instead of leaking, 86 → 87
  units), so R21H's hit count (data × hpMul ÷ supplyHpMul) applies where it did not before — with only that rule put back
  (archetypes.js times as at the merge base) both equal the branch exactly.
- Tests: broad node --test 5147 / 5147; lint 0 errors.
2026-10-07 18:48:38 +08:00
sganggs 806a047717 feedback6 R21P: every operator fights at full potential (潜能 6) — the owner's decision of 2026-10-07 (GitHub #252, PR #255; no host slider): tools/build-data.mjs OPERATOR_POTENTIAL adds every character_table potentialRanks attribute step (部署费用 / 再部署时间 / ATK / HP / DEF / RES / ASPD, all ADDITION, before rounding) to every chess (normal and elite), 补位 and 自选 unit form and picks talent / trait / module-talent candidates up to requiredPotentialRank 5 (「天赋效果增强」); a summon picks its talent candidates at its owner's potential (their requiredPotentialRank mirrors the owner's — PRTS 凯尔希: Mon3tr 3.5 s / 1400) and takes none of the owner's attribute steps; the 原型干员 stand-ins have no potential ranks (unchanged). 刺玫 413 / 17 → 435 / 15 as in the tournament video, 砾 18 → 16 s, 至简 80 → 70 s. data/chess.json (256 records), backups.json (the 71 owned picks, 8 summons), tokens.json (5 summons) and the data translations en / ja / ko / zh-TW rebuilt — only potential-driven fields (JSON-compared); the 干员调配 局内数值 and detail cards read the records. op-wang.js reads her stock cap 「最多拥有8(+1)枚」 through the potential step (the pattern fell back to 7: she sat at the cap from the start). Docs: DATA §2 / §18 / tokens, PLAYING (detail card), research 03, kits README, shared/diy.js / standIn.js, the 71 自选 kit headers and the kit comments that quoted potential-0 numbers. Tests: test/full-potential.test.js (new, fails on the parent); data.test.js re-derivation adds the potential steps (+ respawnTime); every test that hard-coded a potential-0 number carries the full-potential one (from the data and the test's own formula; no check loosened); golden: moves almost everywhere — roster 49/49, bonds 46/46, fields 22/22, matches 18/18, diy 133/138 (each battle parts on a stat: roster-001 / roster-020 at tick 1 on 角峰's HP (生命上限+250), bond-arcaneShip-high at 4.73 s and diy-001 at 3.70 s on an enemy's HP from a higher ATK; diy-110 / 111 also by 望's cap; the matches through those battles); unchanged: standins 10/10 and diy-135…138 (no potential ranks), diy-012 (twelve 夜莺 never hit, never redeployed) 2026-10-07 18:35:39 +08:00
sganggs a9fe794c3f feedback6: merge R21H — 器物 (频次) enemies take the 攻坚 HP share and not 补给线's (the data's exclusion list names exactly the 14 器物), leader summons take the round's enemy scaling (PR #272 by @CXUtk, re-implemented from the data); tools/golden.mjs keeps R21H's roundMods import and drops uniteStageId (removed by R21B); golden regenerated on the merge — vs the parent exactly R21H's 74 scenarios, vs the branch only the other streams' moves 2026-10-07 18:21:01 +08:00
sganggs e33ee3db8f feedback6 R21H: the round's enemy effects reach the 频次 器物 and the leaders' mid-fight summons (PR #272, 感谢 @CXUtk); golden: 74 moved
器物 (the 14 hit-count keys): hits = data × the spawn's hpMul ÷ supplyHpMul, rounded as before (setHits) — 攻坚装备 / II / III
leave out only 炎佑, 补给线 / 补给线II also exactly these 14 keys (activity_table aceffect_enemy_2 / 2_2 enemy_exclude,
data/effects.json); until now setHits(def.maxHp) overwrote the round's HP (青铜镜 30 hits at every difficulty). build-data
writes enemyScale[r].supplyHp = 1.2^(kHp − kAtk) · extra (the HP-only 补给线II steps and 补给线's 1.08; co-op 终极 R5–R15
only — the rebuild changed config.json alone), gamedata returns it as supplyHpMul and the wave / 悬赏 mods carry it
(waves.js roundMods; a 频次 enemy's death spawn inherits it). Not taken from the PR: its 1.08 / 1.2 back-calculation (it
counted the 补给线II steps as 攻坚装备) and its fractional-HP ceiling. Leader summons (死亡集群's 妖怪, 刺胄之弹,
“裂管之音”/“断弦之音”, 不祥幻影): the boss / hidden field carries the round's scale as flags.enemyScale (bossRounds.js,
golden fields, tools/balance.mjs) and bosses.js summonMods gives them HP / ATK / speed (死亡集群's summon.hp_ratio on
top; 刺胄之弹 / 余音 hit counts follow their HP); the leader's pool stays exempt; 王权号令's invulnerable equipment
unchanged; 炎佑 is an ally token, never scaled (no change). Unchanged and open: the 逐火 / 再生 husk counts (talent
prop_max_hp).

Golden — 器物 counts: roster 37 (002 003 004 005 007–020 022 023 025 026 029–034 036–041 043 045 049: each holds a 器物
extra spawn / 频次 wave / death spawn), bond-soloShip-high, diy 9 (036 040 056 062 068 073 091 114 115), boss-boss_6-solo
(俗心's 小说卷轴 escorts); matches 16 (all but solo-ABYSS-2 and coop2-NORMAL-70-diy: 频次 rounds / 悬赏 and the Final
Assault summons). Summons: boss-boss_1-pair/solo, hidden-boss_8-pair/solo (妖怪, 刺胄之弹), boss-boss_3-pair/solo,
hidden-boss_10-pair/solo (余音), boss-boss_5-pair/solo (不祥幻影). standins unchanged.
2026-10-07 18:05:42 +08:00
sganggs 76a2db7dd0 feedback6 R21F: enemy animation states, the client part of PR #275 by @xcdoge re-implemented — the resolver gives an enemy every numbered skill clip (anims.skills; the caller's first index stays the primary, operators unchanged, 宴's PREFAB_SPINE_ROLES fix kept), the stun spellings Stun_1 and Dizzy_Begin/Loop/End, a separate run role (Run_Begin/Loop/End); the renderer walks an enemy faster than moveSpeed 1 on its Run cycle (猎狗pro, 深池侦察犬 ×2; [ASSUMED] threshold), swaps an enemy's skill clip on a cast event (UnitView.setSkillSlot; a form in force is kept), and plays the 重生 of 巨大的丑东西 (Revive, then the fleeing 大祭司 Idle_2 / Move_2 / Stun_2) and 自在 (Revive_01); data/assets.json regenerated offline: 18 enemies gain anims.skills, 6 anims.run, 3 a stun clip (巨大的丑东西, 斩胄之剑, 破胄之锤), nothing else; the sim's cast slot (a new event) is not part of it; golden: unchanged 2026-10-07 17:59:11 +08:00
sganggs caee1dbed9 feedback5: 宴 stands during 落地斩·破门 — her one unnumbered skill set (Skill_Start / Loop / End) is S1 分神's sit-down rest, and the by-name resolver gave it to S2 too, so she knelt through the opening seconds of every battle (the owner's playtest of 2026-10-07); tools/assets/spine.mjs PREFAB_SPINE_ROLES now also fixes operator models by character id (front and back): 宴's S2 plays her ordinary clips (via 'attack'), S1 keeps the rest; data/assets.json rebuilt offline (only her entries changed); test/feedback5-utage-anims.test.js; CHANGELOG 界面, §25.22.9; golden unchanged (client art only) 2026-10-07 13:28:12 +08:00
sganggs d014b9ff0b feedback5: merge R19D — 5-阿戈尔 revives: the members the battle-start devour knocks out revive by board position once every devour pass is over (community report; replaces §24.3's knock-out order for that batch; scan 「左下到右上」 = columns from the left, bottom first [ASSUMED]); bond HP before the devour and one 5000 物理 (DEF) per mark confirmed official; golden unchanged 2026-10-07 12:46:03 +08:00
sganggs 2b0dfceabd feedback5 R19D: 5-阿戈尔 revives — the members the battle-start devour knocks out revive once every devour pass is over, by board position (columns from the left, bottom first: the [ASSUMED] reading of the community report's 「左下到右上」), not in knock-out order; later knock-outs take the slots left in time order, uneaten members none (community report relayed 2026-10-07); golden: unchanged
The report's steps 1-2 were verified and hold: the bond HP is on every member before the devour (an elite 深巡,
2904 HP / DEF 655, stands its 4345 from 15 layers on), and each mark is one 5000 物理流失 less DEF (PRTS), so a member
in the middle of a chain is marked by every 阿戈尔 behind it — that is what knocked out the reporter's 蓝蒂 / 小鲨.
Golden unchanged: the corpus's only 5-阿戈尔 battle (bond-egirShip-high, 999 layers) has no devour knock-out.
DESIGN §25.22.5.
2026-10-07 12:32:33 +08:00
sganggs f3a88427d5 feedback5: merge UI-KO — the Korean interface (every msgid translated with the official KR terms, 합니다체, marked machineTranslated); data/i18n/ko.json rebuilt (the UI pack's emote names); golden unchanged 2026-10-07 12:29:32 +08:00
sganggs 818d070668 feedback5: the Japanese game texts keep what the JP client writes like the Chinese — build-i18n's ja test is 'native' (a text identical to the Chinese is the client's own when every Han character of it appears in the client's translated texts: 炎 / 不屈 / 助力 / 速射手 stay, 甄选干员 is still untranslated), so the bonds 炎, 不屈 and 助力 no longer show their English names in a Japanese interface; data/i18n/ja.json rebuilt (97.5 %, bonds 100 %) and zh-TW.json (the UI pack's emote names); the CJK font stack follows <html lang> (Japanese kanji, Traditional Chinese, a Korean face); the lobby's difficulty lines drop the JP bullet ・ too; golden unchanged 2026-10-07 12:11:19 +08:00
sganggs 2e83a6b977 feedback5: Japanese, Korean and Traditional Chinese ship — the official game texts of the JP / KR / TW clients (data/i18n/ja.json 96.5 %, ko.json 97.4 %, zh-TW.json 91.1 % of 22 114 texts, built with build-i18n --lang from ArknightsAssets/ArknightsGamedata) and minimal UI packs public/i18n/ja.json, ko.json, zh-TW.json (a _meta manifest, no UI strings yet): ja / ko fall back to the English UI, zh-TW to the Simplified Chinese UI (no fallback; numbers in 萬 / 億); the owner's decision of 2026-10-07; UI translations welcome from the community; golden: unchanged (client text only)
- The packs: _meta = type lang, the code, its own and English name (日本語 / Japanese, 한국어 / Korean, 繁體中文 /
  Traditional Chinese), version 0.2.0, app >=0.2.0, authors, credits (the official client data, © Hypergryph (/ Yostar
  for JP and KR), via ArknightsAssets/ArknightsGamedata), fallback ["en"] for ja / ko and [] for zh-TW; formatted as
  `node tools/i18n.mjs template` writes them, so a translator runs it on the shipped file and keeps the manifest.
- Built offline from the tables W5AD downloaded and checked today (jp / kr 51.10.0, tw 51.2.0; copied into
  .cache/gamedata-<code>): coverage as W5AD measured; `build-i18n --lang <code> --check` up to date for en, ja, ko,
  zh-TW. `node tools/i18n.mjs check --all --strict`: 0 errors (en complete; ja / ko / zh-TW 0 of 1022 msgids, fallback).
  `node tools/packs.mjs list` lists the four packs with their game texts; `tools/package.mjs --dry-run --list` ships
  data/i18n and public/i18n of all four and the generated packs/index.json.
- With five languages the menu is a list (ui/lang.js SEGMENTED_MAX 4, W5AD's rule): test/ui/i18n.e2e.test.js reads and
  picks either form, expects the shipped languages, and checks each new pack in the browser (its official game text,
  the fallback UI, <html lang>) — SP_E2E=1: 3 / 3; the title page of the five devices (devices.e2e "title page") still
  fits: 5 / 5.
- Docs: docs/I18N.md (intro, §2, §5 "Shipped packs" with the call for UI translations), docs/PLAYING.md (语言),
  DESIGN §25.20 and the §25 intro's decisions of 2026-10-07.

Gate: non-browser suites 5024 / 5024 (test/i18n*, test/package, client-static 358 / 358), npm run golden ok,
test/golden.test.js 9 / 9, lint 0 errors, check:imports ok, typecheck ok.
2026-10-07 04:16:59 +08:00
sganggs 9ca52ba798 feedback5: merge CB1 — community reports (bonds / strategies / items): a pair of colds on an enemy becomes the freeze and leaves no cold (the 谢拉格 wind no longer freezes for good), a 复活 (埃芒加德's 命结之秘, M3茧甲) is a knock-out and an immediate free redeploy where the operator lies (砾's and 瑕光's 被击倒时 / 部署时 layers fire), 佩佩's special refresh is paid, the result card hides the layers of 调和 / 协防干员 / 独行 / 绝技, the 炎佑 keeps off 外勤医疗's slot, 凯瑟琳's 定向投放 offers every shop item; 烛煌's 绝处重燃 before the hammer's lock and the 寻呼模块 / 简易通讯机 tier cap kept as they are (the owner's decisions of 2026-10-07); §25.15 → §25.21 (§25.15 is the shortcuts'); golden: vs feedback5 CB1's own rules — roster-005/009/010/012/014/015/016/018/026/029/031/033/036/040/042/046/047/049, bond-egirShip-high, bond-indomShip-low, bond-kjeragShip-high, bond-maniShip-high, bond-raidShip-low, bond-steadShip-high, bond-suntShip-low, boss-boss_2/3/4/6-pair, hidden-boss_8/9/10-pair, standin-07, matches solo-FUNNY-1, solo-NORMAL-1, solo-HARD-1, solo-ABYSS-1, coop3-ABYSS-5, coop4-FUNNY-6, coop4-ABYSS-7; vs CB1 what feedback5 changed since its base (CB2, CB3, CB4, CB5) plus roster-014
Conflicts resolved by hand:
- server/sim/content/items/battle.js: CB3 had extended `revivedInPlace` (an in-place 复活 restarts a deploy-timed
  skill, item 44); CB1 replaced the in-place revive by PRTS's form — `reviveNow`, a `death` hook that redeploys the
  operator at once, free, where it lies — and removed `revivedInPlace`. CB1's side is kept: its redeploy resets the
  skill, so an `activateOnDeploy` skill starts anew by itself; CB3's tests (test/sim/feedback5-raid-revive.test.js:
  the jump at once after M3茧甲 / 埃芒加德, the window back to full, 砾's fresh barrier) pass on it unchanged. Their
  header, bonds_core's comment, DESIGN §25.17.5 say so.
- docs/SIM.md, docs/design/engine.md: CB1's `fatal` rows (the 复活 are `death` hooks now); the `death` rows also say a
  deploy-timed skill starts anew (§25.17.5).
- data/choices.json: no conflict; `node tools/build-data.mjs --offline` on the merged tree rewrites all 15 data files
  byte-identically, and the JSON compare with feedback5 shows only pools.pool_equip_kathe.maxTier removed (CB1).
- docs/history/0.2.0.md: CB1's section renumbered §25.21 (its §25.15.1–10 and two self-citations; no citation of it
  elsewhere), placed last; the owner's decisions of 2026-10-07 on items 5 and 45 recorded there, in the intro and in the
  two pin tests' headers (feedback5-blaze-hammer, feedback5-cb1-pins).

Golden: solo-FUNNY-1 (outside CB1's list) has 6 埃芒加德 revives and 85 freezes on feedback5's path (instrumented).
roster-014 differs from CB1's own digest by 玛恩纳's 无动于衷: CB3's rule (every enemy damage instance) answers the
萨卡兹枯朽战车's pollution that hits a 卡西米尔 operator in CB1's timeline — with that counter limited to attacks the merged
roster-014 equals CB1's digest exactly (checked).

Gate: non-browser suites 5021 / 5021, npm run golden ok, test/golden.test.js 9 / 9, lint 0 errors, check:imports ok,
typecheck ok.
2026-10-07 03:54:35 +08:00
sganggs d841d6ac22 feedback5: merge CB3 — community reports (operator kits): 砾's normal attack hits twice at 50 % 伤害倍率 (a 频次 enemy loses 2), 乌尔比安's S3 moves only onto his own board (never behind the one-helper 联防 map's red gate nor onto a boss field's other half), the 「受到攻击时」 counters answer every enemy damage instance (菲莱 S2 on 深溟巢涌者's pulse, 星熊, 泡泡, 刺玫, 余, 玛恩纳, 年, 斩业星熊), an in-place 复活 restarts a deploy-timed skill so a 突袭 member jumps at once, 银灰's normal attack plays its own impact (and 雷蛇 / 初雪 / 圣约送葬人 drop a skill mode's sound); five reports pinned; §25.17 between CB2's §25.16 and CB4's §25.18; data/assets.json lists 银灰's impact (p_imp_spear_n.mp3 fetched); golden: vs feedback5 CB3's own rules — roster-002/004/005/008/010/012/016/024/033/044, bond-indomShip-low/high, bond-kazimierzShip-low/high, bond-lateranoShip-low, boss-boss_2-solo, boss-boss_4-pair/-solo, hidden-boss_8-pair/-solo, hidden-boss_9-solo, diy-051, matches solo-FUNNY-2, coop2-NORMAL-3, coop4-ABYSS-7, coop2-ABYSS-10-boosted; vs CB3 exactly what feedback5 changed since its base (CB2, CB4, CB5)
The merge:
- server/sim/battle/players.js: CB3's onOwnBoard hunk is byte-identical to CB4's (git kept one); its comment and
  docs/SIM.md's onOwnBoard row now name 乌尔比安's S3 【移动】 next to the 突袭 landing (DESIGN §25.17.2 / §25.18).
- test/sim/facing-invariance.test.js: CB3's scenario setup (onOwnBoard off on the open field) and the CB4 merge's
  突袭 test (its enemy inside the board) merged cleanly, both kept.
- data/assets.json: CB3 had regenerated it offline without 银灰's entry (his official impact file was not on disk);
  `node tools/fetch-assets.mjs --add-only` (shared public/assets, add-only) downloaded p_imp_spear_n.mp3 — 8.8 KB,
  the only new file (ok 1, skipped 7968; the 117 misses are the known upstream gaps) — and rewrote the manifest.
  Field-wise JSON compare with CB3's manifest: only audio.sfx.units.char_172_svrash = { hit: p_imp_spear_n } plus hash
  and stats (files / bytes / sfxUnits +1); against feedback5: CB3's four operators (银灰 now the spear impact and no
  S3 swing, 雷蛇 / 初雪 / 圣约送葬人 without the skill-mode impact) plus hash / stats. §25.17.6 says so.
- docs/history/0.2.0.md: §25.17 placed in order, the intro's per-stream list and workstream list name CB3.

Golden moves outside CB3's commit list: coop2-NORMAL-3 fields 砾 from round 3 (her double hit) and 刺玫 in rounds 4-7
(instrumented); solo-FUNNY-1 (in CB3's list through the counters) fields no counter operator on feedback5's path, only
砾, whose two half hits change no kill, leak, LP or end stat there, so its digest stays.

Gate: non-browser suites 5003 / 5003, npm run golden ok, test/golden.test.js 9 / 9, lint 0 errors, check:imports ok,
typecheck ok.
2026-10-07 03:41:48 +08:00
sganggs fe2a0cbc29 feedback5 CB3: 银灰's normal attack no longer plays his S3 swing (and S2 / S3 impact); 雷蛇, 初雪 and 圣约送葬人 lose a skill mode's impact the same way (community report of 2026-10-06, item 54)
Official (excel/audio_data.json, local client charpack char_172_svrash): his normal attack is the Default mode's Combat —
ON_ABILITY_HIT.char_172_svrash.combat p_imp_spear_n, no swing bank; .attack.2 (p_atk_silver_n swing, p_imp_sword_n impact) is
his S3 mode, .attack.1 his S2 mode. Cause: tools/assets/audio.mjs pickUnitSfx took the numbered variants because their files
end in _n (its skill-mode test is by file name). Now an operator whose default mode is the unsuffixed ability (a plain
attack / combat bank of any event) never takes a numbered variant; operators that number their default mode (attack.0 …)
keep the earlier order. Over the 209 operators of the manifest it changes 4: 银灰 (charpack modes Default / S2 / S3), 雷蛇
(attack.1 = S2, lightning impact), 初雪 (attack.1 = her S1-2 mode) and 圣约送葬人 (attack.4 = S3_End).

data/assets.json regenerated offline (fetch-assets --offline --add-only --allow-shrink; JSON compare: exactly the 4 operators'
entries, hash and stats): 雷蛇 / 初雪 / 圣约送葬人 drop their wrong `hit`; 银灰's entry goes too, because his official impact
p_imp_spear_n.mp3 was never downloaded on this machine — one online `node tools/fetch-assets.mjs --add-only` adds it (needs
the owner's OK for that download). Golden: unchanged (the manifest is client-side). Tests: test/feedback5-operator-sfx.test.js
(3; 2 fail on the parent). Docs: docs/ASSETS.md.
2026-10-07 02:38:07 +08:00
sganggs 1d3c76b11c feedback5 CB1: 凯瑟琳's 定向投放 offers every shop item, not only those up to the shop level (community report 「凯瑟琳装备池没有超出商店等级的装备,原版凯瑟琳1升2都能有6本装备」, item 43)
The pool (pool_equip_kathe) is server-side; tools/build-data.mjs had capped it at the shop level [ASSUMED], so the 1 → 2
upgrade only ever offered tiers I–II (measured over 40 seeds: 55 × I, 65 × II). The players' first-hand account: tier VI
shows at that upgrade. Now every shop-eligible item, uniform [ASSUMED] (40 seeds: I 9, II 15, III 25, IV 31, V 16, VI 24);
pool_equip_narant keeps its cap (no report). data/choices.json rebuilt offline (build-data --offline): the JSON compare
shows only pools.pool_equip_kathe.maxTier removed. Test: test/match/feedback5-cathy-pool.test.js (fails on the parent
data). Docs: research 04 (the pool).

Golden: coop4-ABYSS-7 — a bot on 凯瑟琳 is offered other items at its upgrades (the match runs differently from there).
2026-10-07 02:27:54 +08:00
sganggs 714af994fc feedback5: merge W5AA — community reports of 2026-10-06: the 孤岛风云 prisoners leave the gate confined (grey) and change model as their prefabs do, the 4th attack hits freed; a bounty enemy that dies with no operator behind it pays in 联防 too (the helper whose half it fell on); 忍冬's trigger and 枯朽之种's bounty were already fixed (pinned by tests); DESIGN §25.14 after round 18's §25.13; data/enemies.json regenerated offline on the merged code (round 18's model quirks + the prisoners' clips); golden: vs feedback5 exactly W5AA's moves (26 battles, solo-ABYSS-2, coop2-NORMAL-3, coop3-ABYSS-5, solo-HARD-9-boosted), vs W5AA exactly round 18's boss-pool moves 2026-10-06 22:35:10 +08:00
sganggs 6372f2892b feedback5 WAA: the 孤岛风云 prisoners leave the gate confined and change model as their official prefabs do — grey while 【禁锢】, the blinking orange warning before the last confined attack, red once freed; the 4th attack already hits freed (community report of 2026-10-06 「囚徒类敌人出门就是已解放的模型」)
- Cause, client: the prisoner skeletons carry three clip sets whose collar light is grey, blinking orange
  and red. The official battle prefabs (local client battle/enm_pfb_6.ab: the Graphic component's anim key
  -> clip table, the modes' replace pairs, the clip the Spine starts on) draw mode Default (【禁锢】) on the
  grey set, mode R (the warning) on the orange set and mode L (【解放】) on the red one. The name-based role
  resolver gave 普通囚犯 / 老练囚犯 their unnumbered set — the red one — so they came out of the gate freed;
  no FORMS entry existed, so no prisoner ever changed (强壮囚犯 / 拳师囚犯 / 重犯 / 传奇重犯 stayed grey).
- Cause, sim: buff_template_data enemy_confinement[atk_cnt] spends a charge ON_BEFORE_ATTACK (not while
  麻痹) and switches to mode R when one is left; enemy_liberty_listener[warning] switches to mode L before
  the next attack (PRTS "进行第4次攻击前,切换至解放状态"). archetypes.js prisoner() counted on the 'attack'
  hook, after the damage, so the 4th attack still hit confined, and it sent no form.
- Now: prisoner() counts in `before` (an attack 麻痹 interrupts never gets there, PRTS 拳师囚犯), setForm
  'warning' (fx 'phase', drawn silently: kinds.js SILENT_PHASES) before attack times-1 and 'liberty' (fx
  'liberate') before attack times; 重犯's free-all and 杰斯顿's KO switch the freed ones too.
  render/units.js FORMS maps 'warning' / 'liberty' for the six skeletons (普通 / 老练囚犯 *2 / unnumbered,
  强壮囚犯 *2 / *3, 拳师囚犯 / 重犯 / 传奇重犯 *_orange / *_red). tools/assets/spine.mjs PREFAB_SPINE_ROLES gives
  普通囚犯 / 老练囚犯 their grey *3 set; data/assets.json regenerated (fetch-assets --offline --add-only, JSON
  compare: only those two anims and the hash), data/enemies.json too (build-data --offline: only their
  attackAnim.clip Attack -> Attack3, same length and strike frame). The 3D board draws the same Pixi views.
- Docs: ASSETS.md (PREFAB_SPINE_ROLES, the prisoner forms), SIM.md (the form fx), design/client.md (FORMS).
- Tests: test/content/feedback5-prisoners.test.js (the six: warning before attack 3, attack 4 hits with
  ATK +50 %, the forms reach the client and UnitInfo; free-all; 麻痹), test/render/feedback5-prisoners.test.js
  (manifest = the prefab's grey set, FORMS sets, view clips, PREFAB_SPINE_ROLES = the committed manifest) —
  both fail on the parent but the 麻痹 pin; test/render/feedback5-prisoners.browser.test.js (RENDER_E2E=1:
  three prisoners on the 2D and the 3D board, each model's set follows its sim form).
- Golden: 28 scenarios. Only the warning's new 'phase' fx (the prisoner fell before its 4th attack):
  roster-001, roster-003, roster-007, roster-024, roster-033, bond-miraShip-low. The 4th attack now hits
  freed, one attack earlier than before, so the fight after it moves: roster-004, roster-022, roster-026,
  bond-kazimierzShip-low, bond-raidShip-low, bond-soloShip-low, bond-victoriaShip-low, bond-visiShip-low,
  standin-01, diy-024, diy-061, diy-065, diy-066, diy-094, diy-097, diy-104, diy-105, diy-127; only the
  per-second snapshots besides the fx: roster-021, diy-017; and the bot matches whose battles field
  prisoners: solo-ABYSS-2, solo-HARD-9-boosted.
2026-10-06 21:57:51 +08:00
sganggs 66ae86b969 feedback5 WY: flying units hover 1.3 tiles (the client's 0.35 ÷ the standard prefab scale 0.27); the 帝国炮火先兆者 pair is drawn 1.263× taller and 木制瑞印 mirrored, as their official prefabs (from PR #211 by @xcdoge; the owner's decision of 2026-10-06)
Ported by hand from PR #211 by @xcdoge:
- render/units.js: FLY_HOVER 0.32 → 1.3, flat (the official fly offset is one model-independent Vector3(0, 0.35, 0) in
  the client's character space, whose unit is the standard battle-prefab scale 0.27; an official screenshot measures
  1.2–1.4 tiles); enemyModelScaleY multiplies the skeleton's Y scale and the head (bar) height, also in the impostor
  path; a mirrorX model flips on top of the direction flip. The body, its HP bar, damage numbers, projectile hits and
  skill rings ride `hover`, the shadow stays on the ground; one camera drives the units over the 2D and the 3D board.
- tools/build-data.mjs MODEL_STRETCH_Y / MIRRORED_PREFABS → enemies.json modelScaleY / mirrorX; data/enemies.json
  regenerated offline here (the PR's one-line blob was not taken) — JSON compare: only enemy_1112_emppnt /
  enemy_1112_emppnt_2 modelScaleY 1.263 and enemy_1196_msfyin mirrorX true.
- tools/local-extract/enemy_model_offsets.py (optional, host-side prefab reader) and
  docs/research/12-flying-visuals-official.md (without the claim that the owner said 「都要」 on 2026-10-05 — the owner's
  decision of 2026-10-06 is cited; where the quirk enemies appear corrected against 0.2.0's data: 帝国炮火先兆者 is a FLY
  special enemy of the mode, 帝国炮火中枢先兆者 comes with the bounty 战术特训·飞行III, 木制瑞印 is in no wave). No
  screenshot or extracted art committed.

Tests (from PR #211): test/render/unitview.test.js (FLY_HOVER ≈ 0.35 / 0.27; the same lift for every flyer; a flying
view lifts by FLY_HOVER — added here: its body and HP bar ride the lift, its shadow stays on the ground),
test/render/playtest6-enemies.test.js (the data keys; the 1.263 aspect and bar height; the mirrored model's x sign);
both fail without the renderer change; the 425 render unit tests pass. Docs: DATA §9, ASSETS, design client.md,
research 00 / 12, DESIGN §25.13.5 and the §25.10 table.
Golden unchanged (drawing only; the sim reads neither field).
2026-10-06 21:41:49 +08:00
sganggs 4e58481706 feedback5 WY: the Final Assault / Hidden Core leader pool is bloodPoint × the players alive when the fight starts (solo × 1), replacing 「保持固定血量」; 胄's drone share passes 限伤 (from PR #209 by @qingjingshenghuo; the owner's decision of 2026-10-06)
Ported by hand from PR #209 by @qingjingshenghuo (its one-line data/config.json was not taken):
- server/match/gamedata.js bossPoolShareOf (used by GameData.bossPoolShare and by finalAssault.bossPoolHp for a plain
  game-data object): solo × `solo` (1); co-op with `perPlayer` true × `coop` (1) × the players alive at the boss
  round's start (bots and AI 托管 seats count, eliminated / departed seats do not; at most aliveFull 4; a count left
  out = a full team). The fixed pool stays restorable through config: bossHpScale perPlayer false + solo 0.25 (and its
  optional aliveScaling).
- tools/build-data.mjs: the global bossHpScale carries the rule (perPlayer true, solo 1); the modes' entries keep only
  bloodPointKey / unaffectedByEnemyScale. data/config.json regenerated offline — JSON compare: only bossHpScale (global
  and the 9 mode entries) changed.
- The problem #209 documented: a 胄 drone death is 2 % of the pool and 限伤 cancels a hit of ceil ≥ 300000, so the
  hidden 胄 终极 pool at 3 / 4 players (21.6M / 28.8M) would cancel every drone (432000 / 576000). The drone link is
  a share of the pool, no hit: Battle.loseHp takes noHitLimit and the link passes the limit [ASSUMED: the official
  client checks every damage modifier and PRTS calls it 真实伤害, but which max HP it reads is undocumented]; a part's
  传递 and every hit stay under the limit.

Golden (regenerated; why: the pool size):
- fields: boss-boss_1..7-pair/-solo and hidden-boss_8..10-pair/-solo (all 20 boss / hidden scenarios) — a pair
  field's pool × 2 (two players), a solo template's × 4 (solo × 1, was × 0.25); boss-boss_1-pair, boss-boss_1-solo,
  boss-boss_3-pair, boss-boss_3-solo, boss-boss_5-solo, boss-boss_7-pair and hidden-boss_9-solo now end at the
  200 s cap instead of clearing; the two 联防 scenarios are unchanged.
- matches: solo-FUNNY-2, solo-NORMAL-1, solo-HARD-1, solo-HARD-2 now lose the Final Assault (solo leaders have 4× the
  HP: team LP 0 with 93088–176395 of the pool left); solo-FUNNY-1, solo-NORMAL-2, solo-HARD-9-boosted (its Hidden Core
  too), coop2-NORMAL-3, coop4-FUNNY-6, coop2-ABYSS-10-boosted, coop2-NORMAL-70-diy still win with more leader damage
  (pool × players alive; solo-FUNNY-1 / solo-HARD-9-boosted end with 6 / 1 team LP less). Unchanged:
  coop2-NORMAL-8-serverrun and coop2-NORMAL-14-standins (one player left at R14: × 1 as before) and the matches that
  end before R14; roster / bonds / standins / diy unchanged.

Tests: test/match/boss-hp-scaling.test.js (from PR #209, adapted — every leader and difficulty × 1–4 players and solo;
R14 / R15 leave out two departed players; AI 托管 and bots count, an eliminated player does not; config restores the
fixed pool, the opposite of the PR's test; the plain-object fallback agrees; only the leader's HP scales);
test/content/enemies_bosses.test.js (hidden 胄 终极 at 3 / 4 players: the drone share lands, a hit of the same size is
cancelled — fails without the change). Updated on purpose: finalAssault, balance, bosshp, connection, docs-consistency
(the §20.9 record points to §25.13.4; the data carries perPlayer true), sim/playtest6_limits (the drone share lands
past the line), match/playtest6-bosspool (the 5 % knob halved to keep the 2-player pool's size: that test is about the
pool's arithmetic). Docs: PLAYING §7, DATA, META, BALANCE, SIM, design engine.md / network.md, the §20.9 / §20.10
records, research 00 / 01 / 08, the code comments, DESIGN §25.13.4 and the §25.10 table.
2026-10-06 21:41:49 +08:00
sganggs 269d7b0bcf feedback5 WY: 华法琳's granted trait stops at the data's 7 / 14 layers per battle, not 12 / 24 (GitHub #175; from PR #192 by @kukiC; the owner's decision of 2026-10-06)
PRTS 卫戍协议:盟约 下半, 3月27日更新#2调整 (revision 439189): 「[Ⅳ阶]华法琳:赋予的特质的叠层上限从 初始12/精锐24
降低至 初始7/精锐14」 — a nerf; the current 参战干员 record says 至多7层 / 14层 and the client blackboard is 7 / 14.
Research 02 Addendum 1 had read the line backwards, so the remake overrode garrison_95's cap to 12 / 24.

Ported from PR #192 by @kukiC: GRANTED_CAP_OVERRIDE is removed from server/sim/content/garrisons/battle.js and from
the client-result layer bound (server/match/fields.js layerAllowanceOf); a granted trait keeps its data cap like a
native one. Tests from the PR: garrisons_battle (updated on purpose: the 7th cast reaches 7 / 14, the 8th adds
nothing), feedback1-gaps (the bound with 华法琳 + 古米), playtest3 (both cards show 7 / 14); the first two fail without
the fix. Docs: research 00 / 01 / 02 corrected (02-bonds.json's note; data/bonds.json regenerated offline — only
miraShip.spec.layerGain changed), history 0.1.1's pointer, DESIGN §25.13.2 and the §25.10 table.
Golden unchanged (no corpus battle casts 8 times in front of 华法琳).
2026-10-06 21:03:56 +08:00
sganggs 575333137c feedback5 WX: the 39 summon models no web dump carries come from the local client (extract.py TOKEN_SPINES) and are drawn instead of the avatar diamond when data/local-assets.json lists them
- tools/local-extract/extract.py TOKEN_SPINES (`--only spine/token`): each token's battle prefab in the
  battle token packs (pkgrps/btl_pfb_tokens_*.ab; the Windows build has all 39, the iOS build lacks
  btl_pfb_tokens_0), the skeleton of its Front (or only) Spine renderer, written to
  public/assets/local/spine/token/<id>/ like the enemy models (sized pma atlas, premultiplied pages;
  the newer RGBA pages keep their own alpha). The enemy writer is shared (write_spine; the two enemy
  models re-extract byte for byte). The skinpack job of 乌尔比安's block is gone: it extracted
  nothing, and that token draws no model in the game (nor do 圣聆初雪's, 酒神's, 贝洛内's and
  予愿安洁莉娜's hidden tokens: no Spine renderer, no avatar in either install).
- tools/assets/local-token-spines.json (committed, `fetch-assets --local-spines`) → data/assets.json
  tokens[id].spineLocal for 35 自选 summons, 凯瑟琳's 爬行号·防护单元 and 凛御银灰's three 风雪之眼; the
  manifest is the same with or without the extraction (JSON diff: only the 39 spineLocal entries and
  the hash). spine.mjs LOCAL_SPINE_ROLES maps clips the resolver cannot read (电弧's 戴乌 C_Skill1_*,
  酒神's 本能的召唤 Loop / End, 白铁's platforms End, 战术锚点 on its Default pose) [ASSUMED where named].
- assets.js spineEntry: a token resolves its spineLocal like an enemy (no web model behind it: the
  diamond stays when it is not listed or fails to load). Scale as the web tokens (UNIT.modelScale).
- setup reports an extraction without the summon models; docs: ASSETS.md "Token models from the local
  client", DEPLOY.md §6, DESIGN §13 (design/client.md), README.
- Tests: test/local-token-models.test.js (new), test/local-extract.test.js (job table, prefab walk,
  alpha merge), test/assets.test.js (the local token models load like the client does),
  test/package.test.js (the full zip ships them), test/static-local-art.test.js. Golden unchanged.
2026-10-06 20:16:20 +08:00
sganggs 6499f4b32d feedback5: data/assets.json gains the battle voices of the 71 自选 operators (fetch-assets --add-only: 994 lines, 25.5 MB; voiceChars 120 → 191); nothing else in the manifest changed 2026-10-06 18:41:28 +08:00
sganggs b8a86b88f1 feedback5 WU: module type icons get one lower-case file per type (dec-X and dec-x were two names for one file)
The official data spells one DEC X module 'dec-X' (uniequip_003_aglina) and the others 'dec-x' (WAH-Y is the other
mixed-case type id), and the asset plan stored each under its own case: module/dec-X.png and module/dec-x.png. On
Windows / macOS those are one file, so a release zip built there could hold only one of them and a case-sensitive
server (a Linux VPS) would miss the other — the release packager found it ("planned but not staged"). The local file
is now module/{typeIcon in lower case}.png; the upstream names keep their order (the id as spelled, then lower case).

data/assets.json regenerated offline (node tools/fetch-assets.mjs --offline --add-only). JSON diff: modules.dec-X
/assets/module/dec-X.png -> /assets/module/dec-x.png, modules.WAH-Y /assets/module/WAH-Y.png -> /assets/module/wah-y.png,
hash, stats.files 6979 -> 6978, stats.bytes 458334505 -> 458333444; nothing else.

fetch-assets compares its orphans (what --prune deletes) without case: on Windows / macOS module/WAH-Y.png on disk is
the listed module/wah-y.png and must not be deleted (orphanFiles, exported).

Tests: test/assets-diy.test.js (one lower-case file per type, no two manifest URLs differing only in case, orphans).
docs/ASSETS.md: the module icon file name.
2026-10-06 17:59:13 +08:00
sganggs 9bfac54c8f feedback5 WU: 焰狐龙梓兰 (MH05) leaves data/assets.json; a voice slot with no line on disk is dropped, not []
She left the 自选 pool in 0.2.0 (data/backups.json diy.excluded, a collab operator) but her art stayed in the
manifest because fetch-assets refuses to shrink it. Regenerated offline in this worktree, whose public/assets and
public/fonts are the shared ones: node tools/fetch-assets.mjs --offline --add-only --allow-shrink (--add-only so no
file on disk is rewritten and the fonts entry is kept). The run dropped exactly her 163 entries.

JSON diff against the previous manifest: removed chars.char_1048_orchd2, skills.skchr_orchd2_1..3,
skillsById.skchr_orchd2_1..3, audio.sfx.units.char_1048_orchd2; changed hash and stats (files 6994 -> 6979,
bytes 462620448 -> 458334505, chars 210 -> 209, charsWithBack 207 -> 206, spineModels 673 -> 671,
skills 525 -> 522, sfxUnits 484 -> 483); nothing added, nothing else changed.

The first regeneration also added 71 entries like audio.voice.char_134_ifrit = {select: [], place: []}: the 自选
operators' voice lines are planned but not downloaded on this machine, and resolveTemplate kept an array whose lines
were all missing as []. tools/assets/manifest.mjs now drops such an array like a missing leaf (and the entry it
empties); an array that is empty in the template stays.

Tests: test/assets.test.js (the array rule), test/assets-diy.test.js (no diy.excluded operator keeps art in the
manifest). docs/ASSETS.md: 71 自选 picks, 209 operators (206 with Back), 522 skill icons, the empty-slot rule.
2026-10-06 17:51:41 +08:00
sganggs 723ee72d38 feedback5: merge WE2 — fidelity (data / match / UI): summon hand counts from the tokens' hidden talents (麦哲伦 / 令 3, 白铁 2), 望's 棋子 on any tile, the 一会儿见! marker no hand card, TRY_SEARCH_ALLY_SKILL → SKILL_RANGE + allies, 斩业星熊's normal attack phys, IS / RA-only modules refused (SO-A / SO-B / RA-A), 黑键 S2 at full SP with a free tile, 重构体 / 战术锚点 placement, 塑心's cap per trait, random grants draw 自选 stock, diyBanned shown, AI 托管 buys 自选, 谬因 S2 / 薇薇安娜 S3 area triggers, #148 regression test, tier*.js / diyRecord shims removed; golden: coop2-NORMAL-70-diy, diy-045 / 078 / 114 / 115 / 116 moved (WE2's own), the W4B moves kept 2026-10-06 16:15:52 +08:00
sganggs 53ee0a1c6f feedback5 WE2: 重构体 only on the ground inside Mon3tr's range, 战术锚点 only on a 高台 outside 凯尔希·思衡托's (#26)
Mon3tr T1 "可以在攻击范围内的地面使用…重构体"; PRTS 战术锚点 特性 "仅可以部署在凯尔希·思衡托攻击
范围外的远程位". tools/build-data.mjs summonRecord: ownerRange also from an owner talent
naming the token, ownerRangeOutside / rangedTilesOnly from the token text. Regenerated
offline: 3 paths (重构体 ownerRange true; 战术锚点 ownerRangeOutside, rangedTilesOnly).
Match: board.js placement class 'high'; PlayerState.summonExcluded in _legal, the
re-orientation lift (+ toast), _roomForOutOfRange, the invariants and the bot; the
client mirror (piecePosition HIGH, summonExcluded, reasons; English strings added).
Golden: no scenario moved.
2026-10-06 15:34:20 +08:00
sganggs 75c98f1d93 feedback5 WE2: 驭法铁卫 (斩业星熊) — the data's normal attack is physical, arts only with a skill (#15)
tools/build-data.mjs classifyAttack: a trait whose 法术伤害 comes only "技能开启时" keeps
the normal attack's phys (display / AI only — her kit already attacks physically
off-skill). Regenerated offline: 3 paths, the three forms of char_1044_hsgma2 dmgType
arts -> phys. Golden: no scenario moved.
2026-10-06 15:15:15 +08:00
sganggs cd547b5178 feedback5 WE2: 黍 S3's TRY_SEARCH_ALLY_SKILL becomes SKILL_RANGE + allies in the data, her kit override goes (#17)
tools/build-data.mjs TRIGGER_ALLY_RULES (PRTS 特殊策略 "技能范围内存在可治疗的我方单位时释放技能")
writes the row as the engine's SKILL_RANGE on the skill range with allies: true; simdata
normalizeSkill passes allies into the def's trigger (skills.js reads trigger.allies).
Regenerated offline: 9 paths, the S3 trigger of 黍's three forms. op-shu.js no longer sets
the trigger. Golden: no scenario moved.
2026-10-06 15:13:33 +08:00
sganggs f50fd50273 feedback5 WE2: no hand card for 予愿安洁莉娜's “一会儿见!” — a summon no owner shows is not placeable (#24)
tools/build-data.mjs summonRecord: placeable also needs an owner that shows the summon
(the variants' display source, the owner's displayTokenDict). The S3 marker is the skill's
own object (PRTS 予愿安洁莉娜 S3 备注: the skill deploys it at her initial tile); every other
undisplayed summon is already HIDDEN. Regenerated offline: one path changed,
backups.tokens.token_10071_aglna2_agairp.placeable true -> false. The kit drops its
placed-marker branch (the skill always summons it). Golden: no scenario moved.
2026-10-06 15:10:59 +08:00
sganggs ad23320411 feedback5 WE2: 望's 棋子 may be placed on any tile, as PRTS records (#22)
tools/build-data.mjs TOKEN_POSITION_CORRECTIONS (PRTS 棋子 部署位置 "全部位", 备注
"游戏内召唤物信息与实际不符(显示为仅部署在近战位)") sets the 棋子 record's position to ALL;
validateAll checks every entry. Regenerated offline: one path changed,
backups.tokens.token_10064_wang_stone1.position MELEE -> ALL. Her stock / 阻回 unchanged
(an owner question). Golden: no scenario moved (none places 棋子).
2026-10-06 15:06:07 +08:00
sganggs 99d8807328 feedback5 WE2: 自选 summon hand counts include the tokens' own deploy talents (#21)
tools/build-data.mjs tokenTalentDeckBonus adds a summon's talent max_deploy_count /
max_deck_stack_cnt (the hidden "TOKEN数" talent; a module token part of the same talent
replaces it, matched by prefabKey) to its variant deployLimit / deckStack. Regenerated
offline: only data/backups.json tokens of 麦哲伦 (drones), 令 (souls), 白铁 (devices) and
夜莺 (幻影) changed — deployLimit 3 / 4 with SUM-Y stage 3, 2, 3; deckStack 5 (8), 3 (4).
The hand count (player/diy.js placeableTokens) now matches the official one for every
自选 summoner (PRTS 卫戍协议/帮助 "根据召唤物部署数量上限", the owners' talents, PRTS 幻影 备注).
The summoner kits read deckStack / deployLimit as they are (same decks as before).
Golden: no scenario moved (the diy family places no summon pieces).
2026-10-06 15:01:46 +08:00
sganggs c6827a0eaf feedback5: merge feedback4 (583899d) — W4B ported: 阿戈尔's devoured base ATK as a 最终加算 (atkFinal), a fallen marker's marks still resolve, 缇缇 S2 pulses re-enter sleep for her trait (applyStatus reenter in server/sim/battle/status.js; the 缇缇 kit in kits/ops/chess_char_5_02-titi.js; Battle.js / tier5.js stay feedback5's façade and shim); golden: roster-042, bond-egirShip-high, coop2-ABYSS-10-boosted moved, the same three as on feedback4 (bond-egirShip-high identical to it) 2026-10-06 14:47:13 +08:00
sganggs 7059528c47 feedback5: merge feedback4 (3af5b84) — PRs #186 / #134 / #185 / #24 / #183 ported to the split layout (terrainInfo / TERRAIN_TIPS into a new ui/gameLogic/terrain.js re-exported by the gameLogic.js barrel, closesOnFieldPress into ui/gameLogic/shortcuts.js, the rest in place; 42 strings through t(), #183's 设置 too); golden unchanged
Ported by hand:
- public/js/ui/gameLogic.js is a re-export shim on feedback5: #185's TERRAIN_TIPS / terrainInfo went into the new
  public/js/ui/gameLogic/terrain.js (the barrel gains one re-export line); closesOnFieldPress 'terrain' into
  ui/gameLogic/shortcuts.js.
- i18n (docs/I18N.md): every new user-visible string goes through t() with an English entry in public/i18n/en.json
  (42, after the 补位 strings): the terrain names / tags / fact table are N_() and translated where terrainInfo hands
  them out, the mechanism lines are msgids with their numbers as params (a line with an optional half is two whole
  msgids, the list joins use an array param), the card's 地形机制 / 这一格 titles in ui/detailPanel.js. Official EN
  terms where the EN client has them (stage_table tileInfo: Active Originium, Mire, Exhaust Grille, Deep Water Zone,
  Incursion Point, Protection Objective, Tunnel Entry / Exit, High Ground; Camouflage). The Chinese output is
  byte-identical to feedback4's terrainInfo on all 5187 tiles of the 13 stages and on synthetic stages.
- public/js/screens/game.js (MatchScreen still lives there): the import keeps feedback5's names plus terrainInfo /
  fieldTile; the terrain stage is the one view.setStage gets, so it includes feedback5's fieldStage — a 联防 field is
  played on its own map (GitHub #41), and a tap there explains that map's tile, not the round stage's. The tileClick
  handler and render/app.js emitTileClick / ui/fallbackField.js auto-merged in place. terrainInfo reads the stage only,
  so a 补位 / 自选 board explains its tiles the same way (their pieces only change a piece's art and name).
- public/js/ui/detailPanel.js: the terrain branch of resolveDetail before feedback5's stand-in / 自选 helpers.
- public/js/screens/title.js (#183): feedback5's LangToggle / t() imports plus GIcon / SettingsModal; the gear
  button's aria-label / title are t('设置') (en.json already has "Settings").
- tools/fetch-assets.mjs / tools/assets/downloader.mjs: --add-only (keepExisting, the font skip) beside #24's
  --asset-source / SP_ASSET_SOURCE and the shared MirrorPolicy; feedback5's extraOperators / moduleTypes and the
  voice plan unchanged.
- data/assets.json: feedback5's manifest plus #134's audio.sfx.battle.leak (after heal, the plan order); stats files
  6993 → 6994 and bytes +23 240 as measured on feedback4; the hash recomputed with the generator's contentHash
  (c01aa739a2d3 → 6a547fc5c937). A field-wise JSON diff against feedback5 shows only those four fields.
- docs: DESIGN §24 intro and §24.5 / §24.6 as on feedback4 (the rest of DESIGN.md is feedback5's); ASSETS.md,
  DEPLOY.md, PLAYING.md auto-merged.
- Auto-merged and checked: audio.js (the sim still emits ['leak', id], server/sim/battle/deploy.js), render/style.js,
  textures.js, tiles.js, board3d/materials.js, boardArt.js, tools/assets/*, tools/setup.mjs, extract.py, the tests.

Checks: the PRs' unit tests (audio 22, gameLogic 44, terrain-detail 1, originium-art 4, boardart 15,
board3d-extract 9, asset-network 21, fetch-assets-shrink 4), i18n 9 / i18n-data 8 / i18n-server 4, client-static 313,
docs-consistency 24, kits_layout 6 pass; lint 0 errors (no new warnings), check:imports, typecheck; golden: all 283
scenarios match, nothing regenerated.
2026-10-06 14:41:40 +08:00
sganggs 5bc2669407 feedback4: 阿戈尔's devoured base ATK is a 最终加算, and a marker knocked out during the devour still resolves its own marks (GitHub #165 points 2 and 3, PR #176 by @SpiritedAwayCN; the owner's decision of 2026-10-06)
- PRTS 卫戍协议:盟约 下半/PRTS盟约记录, 阿戈尔 ※: 「该付与来源获得所有标记单位的基础攻击力(最终加算)和阻挡数」. New
  additive mod key atkFinal (PRTS 游戏数据基础 A_f = F_t[(A + D_p)(1 + D_t) + F_p]):
  ATK = ((base + ΣatkFlat) × (1 + ΣatkPct) + ΣatkFinal) × ΠatkMul. The devour buff carries atkFinal instead of atkFlat:
  1000 base ATK, +100 % skill, +2000 devoured → 4000 (was 6000). Every other mod key keeps its meaning.
- 「标记按付与顺序触发【吞噬】效果,目标首次被击倒后解除自身被付与但还未触发的【吞噬】效果」 cancels only the knocked-out
  target's marks: a marker knocked out earlier in the pass now resolves its own marks, the kill credited to it
  (「击杀来源始终为对应标记的付与来源」). A → B → C with B devoured first: C takes B's 5000 and the kill is B's. The 3
  revive slots, the 联防 front-tile devour and the down-at-start rules (DESIGN §24.3 / §24.4) are unchanged.
- Point 5 (the 流失's own source is the target itself) stays open: the hooks still see the marker (DESIGN §24.7).
- Tests: bonds_core — new 最终加算 test (4000; a 直接加算 still scaled; ×0.5 scales the whole), new A → B → C test,
  the dead-marker test rewritten (its mark now lands); feedback3-egir-down, feedback4-egir-unite, feedback3-ulpia-move
  read atkFinal; match/bosshp recomputes ATK with the 最终加算.
- Docs: DESIGN §24.7 (and the §24 intro, §5.2 / §5.3, the §24.4 atkFlat lines marked), SIM.md §3, research 02 §3.6
  and its JSON spec; data/bonds.json regenerated with build-data --offline — only egirShip.spec.algorithm[2] / [3]
  changed.
- Golden: bond-egirShip-high (the devourers 深巡 / 幽灵鲨 / 斯卡蒂 no longer scale the devoured ATK by their ATK +%; the
  fight ends at 89.03 s instead of 74.03 s), coop2-ABYSS-10-boosted (from round 8 ai_0 has 3 more 阿戈尔 and 奥术
  layers — 海霓's first-kill trait — and both bots' boss damage moves). The marker rule moves no scenario.
2026-10-06 14:39:32 +08:00
sganggs 4f870013c7 feedback4: merge master — PR #186 (board textures as WebP), PR #134 (the leak alarm), PR #185 (terrain tap-to-explain, one 活性源石 material); DESIGN §24 intro lists §24.5 / §24.6 after the 0.1.4 sections; golden unchanged (client and tools only) 2026-10-06 14:10:29 +08:00
Cartethyia d582925816 The leak alarm: an enemy entering the blue gate plays the official stage sound (ON_ENEMY_REACHED_EXIT), one alarm per burst (#134)
Battle.leak emits its own 'leak' event, which no sound handled, so every leak was silent; the client now plays battle.ON_ENEMY_REACHED_EXIT (b_ui_alarmenter) with the bank's own one-at-a-time rule, leaks closer than the sound's length sharing one alarm. The manifest gains only audio.sfx.battle.leak. Contributed by @Convey123.
2026-10-06 14:06:43 +08:00
sganggs c5e8d13636 feedback5: merge feedback4 (beb0296) — PR #73 (operator battle voices) ported to the split layout (the voice setting into ui/gameLogic/settings.js, the gameLogic.js shim unchanged; onResult and DetailPanel voice stay in screens/game.js, which needed its store import back; the sim's 'engage' in server/sim/ai.js performAttack, still the one battle/combat.js and devices.js call; plan.mjs / fetch-assets.mjs merged with --add-only, extraOperators and moduleTypes; the 干员语音 slider through t() with English); golden: roster / bonds / fields / standins / diy differ only in events.engage, matches unchanged
Ported by hand:
- public/js/ui/gameLogic.js is a re-export shim on feedback5: #73's DEFAULT_SETTINGS / sanitizeSettings `voice`
  hunk went into public/js/ui/gameLogic/settings.js.
- public/js/screens/game.js: MatchScreen still lives there, so #73's onResult (battleRunner 'result' → resultSpeaker /
  resultVoiceSlot) and `voice=${combat}` on the DetailPanel auto-merged in place. feedback5's game.js no longer
  imported `store` (the split moved its other users), so onResult's store.get() would have thrown into its
  try/catch and the 结算 line would never have played: `store` is imported again. `localAsset` stays dropped.
- public/js/ui/settings.js (i18n phase 1): the slider is `label=${t('干员语音')}`, public/i18n/en.json
  "干员语音": "Operator Voices" (next to Music / Sound Effects).
- tools/assets/plan.mjs: buildPlan takes #73's charword / voiceLang / voiceSlots and feedback5's extraOperators /
  moduleTypes; the template has `modules` and audio { bgm, bossBgm, voice, sfx }. `chars` now includes the 自选 picks,
  so the voice loop's comment says so (the next `npm run assets` plans their lines too).
- tools/fetch-assets.mjs: parseArgs keeps --add-only beside --voice-lang / --voice-all.
- data/assets.json: feedback5's manifest plus #73's audio.voice (120 operators, after bossBgm, the plan order);
  stats files +1680 and bytes +42 041 118 as measured on feedback4, voiceChars 120; the hash is recomputed with
  the generator's contentHash. No other entry changed.
- docs/ASSETS.md: the stats line lists modules and voiceChars. DESIGN §21.30 stays where feedback4 put it; SIM.md's
  'engage' line and docs-consistency's §21.30 test auto-merged (game.js / detailPanel.js still hold the pinned code).
- Auto-merged and checked: audio.js, battle/runner.js emit('result'), components.js mic icon, detailPanel.js voice
  prop, shared/protocol.js EV.ENGAGE, server/sim/ai.js, tools/assets/audio.mjs / cache.mjs, #73's tests.

Where #73 met feedback5 work:
- 补位: a chess fielded as its stand-in shows the stand-in in the detail card, and audio.js keys battle lines by
  UnitInfo spine (the stand-in's model). The 选中干员 line now takes detail.standIn.charId first, so the stand-in
  speaks, not the operator it replaces (test/ui/standin-ui.test.js pins it). A 自选 record is already the pick's.
- The sim's 'engage': stand-in and 自选 units attack through the same performAttack, so it fires for them as well.

Golden regenerated: every moved scenario differs only in events.engage (the new event's count; no gameplay change),
proven by a field-path diff against feedback5:
- roster: all 49; bonds: all 46; fields: all 22; standins: all 10 (the stand-ins engage).
- diy: 101 of 109. Unmoved: diy-010/011/012/092/093 (闪灵, 夜莺, 凯尔希 squads: they only heal, and a heal never
  engages) and diy-077 (薇薇安娜), diy-080/081 (赫德雷), whose picks make no attack in those battles (already so on
  feedback5).
- matches: unchanged.
2026-10-06 04:31:38 +08:00
sganggs beb0296a52 feedback4: merge master — PR #73 (operator battle voices); golden regenerated: every moved roster / bonds / fields scenario differs only in events.engage (the sim's new 'engage' event for the voice slot; no gameplay change), matches unchanged 2026-10-06 01:55:26 +08:00
sganggs 78251f499c feedback5: trigger fixes from the wave-2 kit reports — 「攻击范围向前延伸」 and 「攻击范围朝…扩大」 are attack-range changes (帕拉斯 S2 DEFAULT → ACTIVE_RANGE on her range + 1, 司霆惊蛰 S1 SEARCH → ACTIVE_RANGE on the 3-19: the owner's larger-range rule); UNIT_TRIGGER_CORRECTIONS for a live-client change the text misses — 菲亚梅塔 S1 is DEFAULT since the 2026-08-01 client (PRTS 备注: no +1 range, no flyers); data regenerated offline (only these three skills' triggers in backups.json, chess.json unchanged); golden: only diy moved (diy-060/061/068/069/075/076: those three operators) 2026-10-06 01:53:09 +08:00
Cartethyia 54cdad2602 Operator battle voices: the official combat lines play by voice slot during battles, one at a time (#73)
Deploy, skill and result lines come from the operators' official voice slots; a newer line takes the channel over (stale callbacks of the replaced line no longer release it), and the result line is spoken by an operator of the player's own battle. Contributed by @Convey123.
2026-10-06 01:44:46 +08:00
sganggs 9ce5435373 feedback5: merge W5M — the nine 0.1.4 PRs (#150 #66 #146 #74 #72 #103 #149 #109 #160) and W4A (高台 per the trait, 阿戈尔 revive slots, 联防 devour) ported into the split layout
Conflicts: server/match/bot.js (W4A's comment + W5K's player data view pgd), test/golden/diy.json (regenerated). data/ equals an offline build of the merged tools/build-data.mjs. Golden regenerated on the merged code: against feedback5 the moved roster / bonds / fields / matches / standins scenarios are exactly W5M's per-PR attribution (#160 skill events, #109 deploy-timed lifecycle, #66 灵巧 sources and hidden layers, 83fc408 歌蕾蒂娅 placement), plus coop2-NORMAL-70-diy (fields operators those PRs touch) and diy-051 / diy-052 (events.skill only: Misery's deploy passives, #160); against fb5-merge4 only feedback5's own additions (the diy kits, coop2-NORMAL-70-diy).
2026-10-06 00:33:15 +08:00