Commit Graph
295 Commits
Author SHA1 Message Date
Cloudnyco 119a04888a Hit tiles: positions round half to even (PRTS 作战机制); enemies held just inside the field edge 2026-10-11 21:33:44 +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 ba5b998a72 0.2.3: Clementia S2 releases a dead, hidden, uncarriable or pathless rider at once (slot and weight back before the same tick's boarding checks); same-browser match recovery never takes the seat of a window that is reloading or still starting (a tab keeps its own session token; seats are stamped at the server's welcome, the older welcome wins); golden: diy-135 moves (outcome unchanged) 2026-10-10 01:58:06 +08:00
sganggs 821ab827bd 修复赤刃明霄陈三技能对空自动开启并核实社区反馈
S3 的扩展范围含可选中的飞行目标时可以自动开启剑气;普攻保持仅对地。
[ASSUMED] 自动触发区域沿用扩展攻击格和永久射程延长,不扩张到未来剑气的整条路线。

补测部署技能与休整属性预览、后排协防蕾缪安真实锁定耗弹、诗怀雅落地金币、
莎草对炸弹的治疗链,以及予愿三种技能的普通地面溅射和无视可选性例外。
未复现的报告保留证据边界;诗怀雅被动落地投瓶符合 PRTS。

全 285 场 golden 重建并验证,仅 diy-074 变化:新增 4 次陈 S3,伤害 142376→163563,
时序/选敌改变后击杀 21→18、漏怪 96→99,223.83 秒和结束方式不变。
其余 284 场不变。

CI:5879 tests,5876 pass,0 fail,3 skip;setup/smoke/lint/imports/typecheck 均通过。
新增 16 项回归,相关 6 文件 63/63,补充 2 文件 20/20,文档 31/31。
2026-10-10 01:02:23 +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 e86c7c8304 Let charged guardian heals act without enemies and fix mixed S2 triggers (#406) 2026-10-09 17:31:42 +08:00
sganggs 85b694f206 Fix source-owned Lemuen detection and wanted skill triggers (#428) 2026-10-09 17:29:46 +08:00
sganggs 4980ee786f Preserve enemy facing through push and pull slides (#418, #427) 2026-10-09 17:16:49 +08:00
sganggs 3f19b5981d Count Fartooth granted layers on doll swaps (#415, #429) 2026-10-09 17:12:18 +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 e1b75e1308 feedback7: merge fb7-tick — whole-frame attack intervals and time-SP costs take exactly that many frames, 1 s = 30 not 31 (PR #402 by @Cloudnyco, ported onto 0.2.2: 1e-9 on the ally / enemy attack countdown, the 双眼皮 turret and 寒檀's icicles, gainSp / _normalize; PRTS 作战机制 帧对齐); golden: every family moves (281 of 283, end-result flips in §27.61); union OK 2026-10-09 01:42:16 +08:00
sganggs 227ab9e7ca feedback7 R23-TICK: an attack interval or a time-SP cost of a whole number of frames takes exactly that many — 1 s is 30 frames, not 31 (PR #402 by @Cloudnyco, ported onto 0.2.2); golden: every family moves (roster, bonds, fields, matches, standins, diy — regenerated in the next commit)
Seen (PR #402, measured again on 0.2.2): TICK = 1/30 is not a binary fraction. An attack cooldown counted down from 1 s
stops at 2.1e-16 after thirty steps and the fire check `atkCd > 0` waited a 31st frame; 300 time gains of 1/30 SP add up
to 9.999999999999975 and `sp >= cost` charged a 10-SP skill a frame late. Over the 265 golden battles 30.85 % of the
consecutive attacks on a whole-frame interval came a frame late (control, other intervals: 0.09 %), and 4 157
end-of-tick states sat within 1e-9 under a cost. The engine already took timers within 1e-9 as done (skill timeLeft,
buffs, every() / after(), enemy abilities, nextCastAt, the 失衡 end); these two did not.

Official: PRTS 作战机制/sandbox 「帧对齐机制对攻速的影响」 — one frame = 1/30 s; since 2019-12-24 a non-integer frame count
is rounded (四舍五入); an exact 1 s is 30 frames under any rule.

Now: ai.js attackCountdown(cd, dt) (left within 1e-9 of 0 is 0) for the operators' cooldown (the canAct guard kept) and
the enemies' (not while stunned or hidden; the 0.2.2 失衡 swing cut untouched) — an enemy's whole-frame wind-up is exact
too (0.4 s: 12 frames, 13 before). The same countdown for the two strict `cd -= dt; if (cd > 0)` attack clocks of the
same shape: the 双眼皮 turrets (content/devices.js; BAT 4 s: 121 → 120 frames) and 寒檀's S2 icicles (0.5 s: 16 → 15).
SkillRuntime.gainSp takes SP within 1e-9 of the cost as full for every charge (a tiny negative remainder → 0);
_normalize compares the same way. Left as they are: a non-integer count still ends on the frame that crosses 0
(⌈30 × interval⌉ — the official 四舍五入 is an older, separate difference); the count-up content clocks that restart from
0 (bosses.js self-timers, kit auras — PR #402's list); attack / hurt SP (+1 on an integer cost) unchanged.

Tests: test/sim/tick-tolerance.test.js (new, 7: the PR's four adapted — residue, attackCountdown over bat 0.1–10 s ×
14 ASPD = ⌈30 × interval⌉, 1 s operator every 30 / 3 s ranged enemy every 90, time SP 4/10/16/20/30/50 at exactly 30 × N
gains for one and two charges — plus the 1.2 s / 1.25 s control (36 / 38), the turret at 0 layers (120) and 寒檀's
icicles (15); the four engine tests fail on the parent: 31 / 91, cost 4 at 121, 121, 16). The PR's seven test edits,
re-run: the same 8 assertions failed on the new timing and each edit passes on the parent and on the fix —
feedback2-surtr-stealth (count once no arrow is in flight), kits_alt_t2 拉普兰德 S1 (dummy ATK 300 → 250: 120 × 15 = her
1791 HP by 59.5 s), kits_alt_t6 (medic smoke at half HP; 余 S1 up to the first 燃烧 burst), op_jesca2 (the T6 shield
returns a tick after the cast), op_lmlee (hits before the burst), op_logos (count after the clear), op_narant (the first
attack thrown after the new enemies). node --test (with the golden of the next commit): 5703 tests, 5701 pass, 0 fail,
2 skipped; eslint 0 errors (135 warnings, the parent's 135); typecheck, check:imports, smoke ok.

feedback7 R23-TICK: golden for whole-frame attack intervals and SP costs (PR #402) — 281 of 283 scenarios move: roster 49/49, bonds 46/46, fields 22/22, matches 18/18, standins 10/10, diy 136/138; solo-NORMAL-1 now loses its Final Assault (below)

npm run golden:update on the previous commit. Every family moves because both sides attack on time (more enemy kinds
than operator forms sit on whole-frame intervals: 3 s, 4 s, 1 s …) and time SP charges a frame sooner. Measured over
the 265 battles: whole-frame consecutive attacks a frame late 30.85 % → 0.04 % (control 0.09 % → 0.13 %; 1 s gaps at
30 frames 256 → 3 776 of ~3 800, 3 s at 90 frames 0 → 6 657 of 6 657), SP float-short states 4 157 → 0. Moved battles'
totals: kills 10 647 → 10 625, leaks 12 398 → 12 445, deaths 2 913 → 2 944. Unchanged: diy-040, diy-069.

End results that flip (one frame cascades; the causes as measured with the matches' battles instrumented):
- solo-NORMAL-1: won → lost in round 14 (passed 14 → 13, team LP 8 → 0): the Final Assault on 卢西恩 (pool 390 000) runs
  as before for two minutes (his 0.4 s wind-up a frame shorter), then the team's damage on the pool trails — 884 left
  when the overtime drain (from 300 game s) takes the last of the 17 LP at 334 s; before, it emptied at 318 s, 8 LP left.
- solo-HARD-1: LP 10 → 12 — round 8 lets one more through (26 → 25; rounds 11–12 even it out) and the Final Assault ends
  at 300.6 s, before the overtime drain (304.8 s and 2 LP before).
- solo-NORMAL-2: LP 9 → 25 — round 5 lets one more through (26 → 25, a coin less), the bot's shop path parts from round
  6 and its later board (突袭, 232 layers at round 13 against 94) clears rounds 12–13 with no leak (7 + 18 before).
- coop2-NORMAL-3: team LP 63 → 68 — ai_1's round-13 battle leaks 1 instead of 6 (its round-12 leaker now goes to 联防).
- coop2-ABYSS-10-boosted: team LP 583 → 630 — the Final Assault ends at 606.6 s (639.6) and the Hidden Core at 335.9 s
  (397.8): 47 LP less of overtime drain.
- coop2-NORMAL-14-standins: team LP 41 → 40 — ai_0's round-13 battle lets one 潜伏者 through (23 → 22).
- roster-016: cleared at 220.3 s → time-out at 230 s (主角阵营角色 leaks instead of falling; kills 101 → 105, leaks 26 → 22).
- roster-041: time-out → cleared at 189.0 s, perfect (the last 粉碎攻坚组长 falls inside the 190 s).
- bond-suntShip-high: cleared at 164.2 s → time-out at 190 s (kills 11 → 13, deaths 4 → 2).
- standin-04: perfect → 10 leaks (deaths 8 → 10; 萨卡兹大剑组长 / 萨卡兹穿刺手 / 澪 get through).
- diy-005 / diy-008 (艾丽妮 / 赫拉格): cleared at 225.3 s → time-out at 230 s (a last 宿主重装士兵 / 深池方阵指挥官 walking).
- diy-127 (白铁 / 酒神): time-out → cleared at 225.8 s (deaths 7 → 13, leaks 57 → 72).
- diy-131 (死芒): perfect → 1 leak (a 掠海漂移体).
The other matches keep their ends (solo-FUNNY-1/2, solo-HARD-2, solo-ABYSS-1/2, coop2-HARD-4, coop3-ABYSS-5,
coop4-FUNNY-6, coop4-ABYSS-7, coop2-NORMAL-8-serverrun, solo-HARD-9-boosted, coop2-NORMAL-70-diy). PR #402's own
0.2.1 table (coop2-NORMAL-14-standins loss → win, solo-HARD-2 / solo-ABYSS-2 earlier exits) was measured before §27 and
does not repeat here.
2026-10-09 01:37:32 +08:00
sganggs 8c76309796 feedback7 R23-TOAST: 拟态物质 / 简易通讯机 / 寻呼模块 that grant nothing say why — 「{who}:卡池中已没有{name}」 (拟态物质 with 2 copies owned and the shared pool out: 1 elite + 2 normal 溯光星源 hold all 5 of the Ⅵ阶's copies) or 「{who}:没有可获得的同盟约干员」; the item is still destroyed (装备时销毁). GitHub #401, the owner's OK of 2026-10-09; en / ja / ko / zh-TW; golden: unchanged 2026-10-09 01:05:07 +08:00
sganggs 0ae2fac2b1 feedback7: merge fb7-unbalance — the official 失衡 (UNBALANCE) after a push / pull (the idea of PR #392 by @xcdoge, re-implemented from PRTS): no walking, attacking or skills while it lasts; pushes by the 推力-位移 time table, pulls by the force window (0.5 / 1 s), static bodies 0.1 s pushed / the window pulled; 弧光锋卫 bleeds 400 / 0.066 s while unbalanced; the client slide uses the same time
- The owner asked to verify the official rule before deciding (research: PRTS 失衡位移机制 / 推与拉 / 游戏数据基础 / 特殊机制,
  the client's Rigidbody2D data); the PR's 0.6387·√tiles formula and fear exemption were not taken.
- Grok review: MERGE AFTER FIXES — two HIGH (static pulls, 弧光锋卫's bleed), skills during the hold, husk 重生, exact
  frames — fixed on the branch (1db84d79).
- Golden union: bond-miraShip-low differs from HEAD (fewer enemy attacks: 169 → 166 events, same kills) though the
  branch alone left it — HEAD's ×1.1 练度 path now displaces an enemy there. Broad node --test 5681 (5679 pass, 0 fail,
  2 skipped); lint 0 errors.
2026-10-08 22:47:33 +08:00
sganggs 1db84d799d feedback7 R22-UNBAL: 失衡 review fixes — a pulled 静态刚体 is held for the pull's window, 弧光锋卫 bleeds 400 every 0.066 s while the state lasts, no enemy skill / blink / scripted move during it, a route APPEAR or a 逐火 重生 ends it, every push row holds its exact frames; golden: 32 move, 8 in outcomes (below)
Branch review of fb7-unbalance (MERGE AFTER FIXES):
1. A 静态刚体 pulled got the 0.1 s floor: _staticForce now knows push from pull — a push's force is instant (推与拉), so
   0.1 s; a pull's lasts its window (pullUnbalance: 1 s, 0.5 s below −1) — PRTS 特殊机制 静态刚体 「在失去施力后立刻」 out,
   「0.1 秒保底」. pull() checks the puller's own block before the static case.
2. 弧光锋卫 (PRTS 天赋 「处于失衡状态时,每0.066s受到400点无来源真实持续伤害」, data unbalanced_bleed): a tick bleed of 400 every
   0.066 s while unbalancedNow holds; the per-tile one-shot from the position jump ([ASSUMED], UNBALANCE_SPEED) is gone.
   A 受力等级 0 push (0.8 s) → 12 hits = 4800 (was 2037), a 急停 pull with no movement (1 s) → 15 = 6000 (was 0), a
   wall-shortened slide keeps the 0.8 s row → 4800.
3. 失衡免疫 「失衡期间无法自主移动、发动攻击、使用技能」: enemies/helpers.js unbalancedNow; canCast(e, sil, battle) refuses while it
   runs (content skills; the boss parts' calls pass the battle), blinkForward returns null, 枯朽之种's dive / blast and the
   铳 / 碎铳之簧 charges wait, 乌顶巨角卢鲁's clash waits for its end. A route APPEAR relocation clears it (a forced state
   switch, 失衡位移机制). Left running on purpose (docs/SIM.md): 水遁忍者's damage check (异常效果 「仍然能正常造成伤害」), passive
   auras and terrain / periodic effects, death / damage-taken triggers, skill cooldowns, 弧光锋卫's bleed itself.
4. husk() (逐火 余烬 重生) clears the state like reborn().
5. The 35/30 row held 36 frames (t0 + 35/30 overshoots in floats): every check compares with 1e-9; the frames are asserted.

Tests: test/sim/unbalance.test.js +6 (exact frames 6 / 12 / 24 / 27 / 32 / 35 with the walk on the next frame; static pull
1 s / 0.5 s, push 0.1 s; 弧光锋卫 4800 / 6000 / 4800; canCast / blinkForward refused, 枯朽之种 held then diving; the elk's clash
after the state; APPEAR and a 逐火 重生 clear it — all six fail on the parent); enemies_bosses (失衡 kit test) and
feedback1d-solvent (BUFF damage) updated to the state bleed. test/sim + test/content + test/render pass. Docs: SIM.md
(push / pull row), PLAYING.md, design/engine.md (helpers, enemy AI), constants / displacement comments.

Golden against the previous commit — outcome moves: roster-010 (歌蕾蒂娅 pulls 妖怪 drones, now held 1 s: killed 44→45,
leaks 58→57), roster-040 (static pulls of 妖怪: killed 28→25, leaks 37→40, deaths 29→30), roster-043 / 044 (山: deaths 14→16 /
14→13), hidden-boss_9-pair (锏: boss HP 3636991→3586929), coop4-ABYSS-7 (ai_2 LP +1 from round 5), diy-115 (黑键: leaks
70→75), diy-116 (黑键: killed 2→3, leaks 121→120) — the static pulls (probe) and the 1e-9 end (a frame shorter where the float
sum overshot: the 35/30 row, some pull windows); other moves (damage / snapshots only): roster-008 / 017 / 039, 9 bonds,
boss-boss_4-pair / boss_6-pair / hidden-boss_10-pair, coop2-NORMAL-14-standins / coop2-NORMAL-3 / solo-ABYSS-1 /
solo-HARD-1 / solo-HARD-9-boosted / solo-NORMAL-1, diy-053 / 085 / 102.
2026-10-08 22:42:26 +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 2de2feee3c feedback7: merge fb7-dobermann — 教鞭 is the official three-choice (PR #353 by @Sukvii, the owner's decision), the Final Assault / Hidden Core pay a 战术特训 card's perfect coins (guarded by b.progress leaksBy), the bots put zero-range heavy guards on the road first (PR #339 by @IceCodeNew, placement only)
- Conflicts (the branch started at ae22335c): spec.js / protocol.js b.progress (resolved from fb7-ui-backlog + leaksBy),
  gameLogic.js / game.js exports (device tips + normalizePersonalChoice), docs/PLAYING.md / design/network.md lines
  merged against the base, META.md (画卷 note + 教鞭), test/docs-consistency.test.js pin (both fields).
- Grok review: MERGE AFTER FIXES — the HIGH (a forged boss result paid the cards) fixed on the branch (66a228c6), the
  META wording (1ab12763).
- Golden: matches 10 (the 杜宾 bot picks and the guard placement); union: coop3-ABYSS-5 differs from HEAD only in ai_2's
  dmgDealt (1238011 → 1186269), no outcome change — HEAD's side had moved it, the new placement applies on that path.
- Broad node --test 5623 (5621 pass, 0 fail, 2 skipped); lint 0 errors; typecheck; i18n strict clean.
2026-10-08 22:11:49 +08:00
sganggs cee3784321 feedback7: merge fb7-late follow-ups — 画卷's copied items always arrive unequipped (PRTS 「获得的装备为未装备状态」; hand, then temp, destroyed with the toast when both are full), 度算浪波 breaks an HP-ratio tie by the latest deployment (PRTS)
- Golden union OK (roster-033 / roster-034 again); broad node --test 5602 (5600 pass, 0 fail, 2 skipped); lint 0 errors.
2026-10-08 22:04:15 +08:00
sganggs 03688c8297 feedback7 R22-LATE: 引星棘刺 S1 度算浪波 breaks an HP-ratio tie by the latest deployment; golden: roster-033, roster-034 move
PRTS 引星棘刺 技能1 度算浪波 备注: 「※优先选择生命比例最低>最晚部署的我方单位(不含装置职业单位)」. The kit took the ally
with the lowest HP ratio but broke a tie by more blocking, then the nearer one, then the unit id. A tie now goes to
the latest deployment (the highest deploySeq: a redeployed operator counts from its new deployment), the id last.
「不含装置职业单位」 was already met: alliesInGrid never returns a device.

Golden: roster-033 (a normal 引星棘刺 with S1) and roster-034 (an elite one) move — at the start every ally is at full
HP, so the first units now land on the latest deployed ally instead of the nearest one (033: killed 64 → 47, leaks
103 → 120; 034: 5_14_b damage taken 14691 → 11676 …).
Tests: test/content/kits_alt_t5.test.js +1 (two allies at 50 %: the later deployment, though farther, gets the unit;
a lower ratio still wins) — fails on the parent; all 引星棘刺 tests pass (9).
2026-10-08 21:57:48 +08:00
sganggs 2492966c4f feedback7: merge fb7-late — #389 / PR #390 画卷 keeps the items to copy across a merge, #385 / PR #387 spectator bond details count the hand like the own popup, #394 / PR #395 Enter during facing selection follows the focus, #281 the attack range drawn on a tapped operator, #388 引星棘刺 S1 DEF stacks, PR #386 谢拉格 寒风 blows bottom-up (owner)
- Golden union OK (roster-033 / roster-034 moved on both sides: #298 and #388); broad node --test 5598 (5596 pass, 0 fail,
  2 skipped); lint 0 errors.
2026-10-08 21:54:03 +08:00
sganggs ac4231846f feedback7 R22-LATE: 画卷 never puts the copied items on the copy — they are gained unequipped into the hand / temp like any item; golden: unchanged
PRTS 卫戍协议:盟约 PRTS盟约记录, 法术编纂集, 画卷 备注: 「选择策略<夕>时可获得<br>使用后销毁,获得的装备为未装备状态」.
Without a promotion the 画卷 handler still equipped every copied item that did not merge (an advanced item, a
变形同构体) onto the copy in the hand (the promotion case was fixed for #389). Now each copied item is only gained
(ctx.grantItem → acquireItem): the hand, overflow temp, and with both full it is destroyed with the usual toast
「整备区已满,获得的装备已销毁」, as for any gained item. A copied normal item that completes a pair still merges at once
(the golden in the hand), and the copy itself still follows the chess gain rules (a full hand and temp refuse the
scroll: HAND_FULL, the scroll kept). Full-hand check: a full hand with 3 free temp slots holds the copy and both
copied advanced items; with 2 free slots the copy and one item fit and the other is destroyed with the toast (before,
both rode on the copy).

Docs: META.md (Arts list), research/04-items.md (画卷 copy). The content test that pinned the old behaviour
(test/content/items.test.js: 变形同构体 "the copy wears it too") now expects it in the hand.
Tests: test/match/scroll-copy-merge.test.js +3 (no promotion, normal and elite targets with advanced items; the full
hand at 3 / 2 free temp slots) — all 3 fail on the parent; every test mentioning 画卷: 177 pass. Golden unchanged.
2026-10-08 21:53:51 +08:00
sganggs 1a67ecc35f feedback7 R22-LATE: 引星棘刺 S1 度算浪波 — two alchemy units on one ally add their DEF (+60 +60), as their heals already did; golden: roster-033, roster-034 move
GitHub #388 (claim 1). Every S1 alchemy unit applied its DEF buff under one shared key ('thorn2:bastion'), so a second
unit over the same ally replaced the first one's buff (two units: DEF +60, not +120; a normal and an elite: +75, not
+135) while both units' heals landed. PRTS 引星棘刺 技能1 备注: 「效果均可叠加」. Each alchemy unit now has its own
DEF buff key (assigned at its first tick), so the buffs add (aggregateMods sums defFlat) and each lapses with its own
unit. S3's 不叠加 debuff is untouched.

Golden: roster-033 (a normal 引星棘刺 with S1, pass 1) and roster-034 (an elite one, pass 1) move — one operator's
consecutive S1 units overlap for a few seconds (6 / 7 s + 3 s 心相 against a 7 / 6 SP cost) and now add their DEF on
an ally both cover (033: killed 46 → 64, leaks 121 → 103; 034: damage taken by 5_13_b 41498 → 14903 …).
Tests: test/content/kits_alt_t5.test.js (+1: normal + elite on one ally = +135, the longer unit's +75 stays alone,
nothing afterwards; fails on the parent with +75).
2026-10-08 21:45:09 +08:00
sganggs 52f56319ac feedback7: merge fb7-gh-sim — PR #348 (take-the-highest chains), PR #293 (REA-Y in the engine), #329 ports (异客 13 tiles, 歌蕾蒂娅 net radius 1, 搅拌机 latest first, 大帝 uncapped), PR #365 (骨刺 forms + PRTS targeting), #298 (instant non-attack skills recast at most once per attack interval, attacks untouched), #364 (先兆者 shell 3×3), #220 (速射手 air first), 余 skips noStack bonds (owner)
- Conflict: docs/PLAYING.md 技能自动释放 bullet — both insertions kept (the 铁钳号 rule from fb7-owner-sim, the #298
  pacing sentence).
- Grok review: MERGE AFTER FIXES — the HIGH #298 finding (the cast replaced the due attack) fixed on the branch
  (db29acf9: per-skill nextCastAt; golden of #298 alone shrank from 84 scenarios to 2).
- Golden union: 4 matches differ from HEAD though the branch alone left them (coop2-NORMAL-3, coop4-ABYSS-7,
  coop2-NORMAL-8-serverrun, solo-HARD-9-boosted): HEAD's side had moved all four (#333's shop RNG …) and on those new
  bot paths the merged rules apply — the diffs are in-battle layer gains / damage (卡西米尔 50 → 45, 精准 80 → 76,
  叙拉古 176 → 168, kills ±2, solo-HARD-9 LP 397 → 399), no outcome change.
- Broad node --test 5571 (5570 pass, 0 fail, 1 skipped); lint 0 errors; typecheck.
2026-10-08 21:27:04 +08:00
sganggs 31fee55c6c feedback7: merge fb7-fields — PR #337 boss-field portals teleport (route-end portals: hidden 3 s, out of [5,10], leak at the side's door), PR #347 碎铳之簧 chases the full 5 s, #370 耀骑士临光's redeploy reduction floored at 0, #375 the water-map patrol takes the official upper road
- Grok review: MERGE AFTER FIXES — the end-portal wait (0 s → 3 s, the data's modal crossing) fixed on the branch
  (1205336a). solo-NORMAL-1 still fails the Hidden Core (explained in the branch commits).
- Golden union OK; broad node --test 5517 (5516 pass, 0 fail, 1 skipped); lint 0 errors.
2026-10-08 21:20:37 +08:00
sganggs f5595a7a31 feedback7: merge fb7-owner-sim — community reports via the owner: 白铁's 铁钳号 opens only the skills that act on it (圣约送葬人 spends and stacks), 伊内丝 S3 after a 突袭 jump, 引星棘刺 alchemy units as HP regen (不屈者 / 禁疗), 不可对空 effects spare flying allies (炎佑), 望's 跟子 at battle start, 香槟炸弹 unhealable / no HP loss (owner decision) and not set off by unrevealed 隐匿 or sleeping enemies
- Grok review: MERGE AFTER FIXES — the HIGH finding (skills opened on the device but spending nothing) fixed on the branch
  (69d791f9: skills.js allyTargetsOk, per-kit allyTargets flags).
- Golden union OK; broad node --test 5500 (5499 pass, 0 fail, 1 skipped); lint 0 errors.
2026-10-08 21:14:27 +08:00
sganggs db29acf907 feedback7 R22-GHSIM: #298 rework — the one-interval gap of an instant skill with no attack of its own sits on the skill (nextCastAt), not on the operator's attack cooldown: its casts no longer replace the attacks / heals that were due; golden: back to 2 moves against the code before #298 (roster-033, roster-034)
Review of fb7-gh-sim (MERGE AFTER FIXES, high): 4128965a wrote u.atkCd after such a cast and gated the tick casts on it,
so each cast took the attack that was due — 度算浪波 with 迅捷: 15 casts, 0 attacks in 20 s (silenced: 15 attacks);
冲锋号令·γ型 and 医疗无人机 lost one attack / heal per cast; after an idle cast the next attack waited the armed cooldown.
PRTS 度算浪波 is an automatic instant throw, not an attack.

Now (skills.js): such a cast (instant / charges, no spec.attack, not the DEFAULT cast right before an attack) sets
skill.nextCastAt = now + the unit's attack interval, and the casts checked in skill.tick wait for it; the attack cooldown
is not touched (reset on deployment, like opReadyAt). Measured (20 s, 引星棘刺 S1, 迅捷 229 layers): 12 casts — the first at
4 s as SP fills (#124), then one per 1.36 s — and 14 attacks, as many as silenced; without 迅捷 3 casts and 14 attacks; an
idle cast does not delay the next attack (1 tick). [ASSUMED] one attack interval stays.

Tests: bonds_addon «迅捷 refills 引星棘刺 S1 at once …» now asserts the casts take no attack (attacks = the silenced run's;
fails on 4128965a: 0 vs 4, and before it: 180 casts in 6 s); op_wang waits skill.nextCastAt; playtest6-skills (锏) back to
its original timing. test/content + test/sim: 2835 pass. Docs: SIM.md §7, PLAYING.md 技能自动释放 (no attack is taken).

Golden: against 4128965a's files roster (21) bonds (9) fields (9) matches (16) standins (6) diy (22) scenarios move back; against the
same code with the gap disabled only roster-033 and roster-034 differ (引星棘刺 S1 recast within one interval) — the
84-scenario move of 4128965a came from the attack cooldown, now gone.
2026-10-08 21:06:45 +08:00
sganggs 69d791f9c6 feedback7 R22-OSIM: a skill that 白铁's 铁钳号 opens now acts on it — 蕾缪安 S3 / 艾丽妮 S3 / 陈 S2 / 引星棘刺 S2 spend on it, skills that pick enemies only stay closed; golden: unchanged
Grok's review of the 铁钳号 change (HIGH): the device opened every non-heal skill, but kits that pick their victims
with enemiesInKeys only were spent on nothing — 蕾缪安 S3 went active with 0 locks, 艾丽妮 S3 and 陈 S2 struck nothing,
引星棘刺 S2 threw at the empty far tile. Audit: every skill of every chess (loadouts) and of the 自选 pool, placed with
only the device in range; of the 351 skills the device opened, 67 never touched it.

- skills.js `allyTargetsOk`: the device counts for a skill's start only if the skill acts on it — SkillSpec
  `allyTargets` (true / false) from the kit, else [ASSUMED] a skill acting through the unit's own attacks (timed and
  still attacking, or a cast that is the next attack) on a unit that attacks. An onStart-only cast or a no-attack timed
  skill picks enemies itself and waits for one (德克萨斯 S2 剑雨, 锡人 S1/S2, 铃兰 S3 … about 50 skills).
- Spend on the device (allyTargets: true; its kit cancels the hits, its 受击回复 counts): 蕾缪安 S3 locks it and spends
  her bullets (ammoUsed, so the per-bullet layers come) and shells it; 艾丽妮 S3 strikes it; 陈 S2 draws on it after
  every enemy; 引星棘刺 S2 throws onto it and its pulses hit it. queries.js allyTargetsInRadius for their areas.
- Explicitly closed ([ASSUMED], allyTargets: false): 普罗旺斯 S2 (never shoots above 80 % HP), 卡涅利安 S1 (charged: no
  attack), 山 S2 (blocked enemies), 余 S2 / S3, 迷迭香 S3 (blocked only), 荒芜拉普兰德 S1 / S2 (drone locks), 淬羽赫默 S1–S3
  and 遥 S1–S3 (heal attacks), 机械师 S3, 珊比 S2 / S3, 陈 S3 / 艾丽妮 S2 (their guards already refused).
- 雪猎's empty-magazine cast back to enemies only (its S2 does not act on the device).
Re-audit: 281 skills open on the device alone and all act on it (蕾缪安 S3 through her locks); none of those that
acted on it before stopped. Docs: SIM.md, design/engine.md, PLAYING.md.

Tests: test/content/feedback7-allytarget-kits.test.js (5; all fail on the parent).
2026-10-08 20:53:24 +08:00
sganggs cf98f4c3f8 feedback7: merge fb7-render — #382 赤刃明霄陈 S3 sword-qi drawn (sim chen3Wave fx), #381 enemy attack recovery held in interpolation, #380 push / pull slide (corpse stays where pushed; same-step kills finish the slide), #384 eye masks, 香槟炸弹 HP bar hidden, #246 an unwound attack plays its whole clip
- Conflicts with the merged fb7-hud (both added display-only snapshot lists): server/sim/battle/events.js, types/core.js,
  public/js/render/interp.js, docs/SIM.md, docs/design/network.md — union of ammo / wolves / neg and stand / standCut.
- Grok review: MERGE AFTER FIXES — the HIGH finding (same-step push kill) fixed on the branch (7a33bc7e).
- Golden: diy-073 / diy-074 (fx counts only; union OK); broad node --test 5442 (5441 pass, 0 fail, 1 skipped); lint 0
  errors; typecheck.
2026-10-08 20:51:11 +08:00
Sukvii 56a7b918a9 feedback7 dober: 教鞭 is the official personal choice of three 战术特训 cards again, not a random one (PR #353 by @Sukvii, the owner's decision of 2026-10-08); golden: coop2-NORMAL-8-serverrun and coop2-ABYSS-10-boosted move
Seen: the Art 教鞭 (杜宾's strategy) drew three 战术特训 cards and added a random one — a documented simplification (docs/META.md
§2.5: a personal choice would need its own phase, protocol message, timer and AI takeover). Official: act2autochess
choice_event hunter_band_1 is a PERSONAL_CHOOSE; PRTS 下半 记录 §法术 教鞭 "使用后销毁,于3个战术特训的悬赏任务中选择一项". The
owner decided on 2026-10-08 to follow it. Taken from PR #353 (code and tests by @Sukvii), ported to the split 0.2.2 modules.
Now: ctx.offerBountyChoice -> Match.offerBountyChoice keeps up to three different mode-eligible cards (15 of 20 in 标准 /
险境, 20 in 绝境 / 终极; one meta-rng shuffle) in PlayerState.personalChoice, m.private only (same cards after a
reconnect); g.choice { idx, choiceId } confirms it (Match.pickPersonalChoice: owner, id, round, index; a request without
a choiceId is still the public draft, a stale id never falls through to it). No new phase or timer: Ready is refused while
it is open, the prep's deadline picks at random before the temp pieces and Ready, a bot or a 托管 seat picks with the bounty
scorer (botPickCard, the bots' seeded rng; at the prep's start, after the cast, before Ready; the scheduler's fallback
picks at random if a step fails). The client reuses ChoiceOverlay (personal: no order, no turns, the prep's countdown) over
a locked prep, the Ready reasons, the mock harness; six UI strings in en / ja / ko / zh-TW. An eliminated player's offer
goes with it; invariants.js flags an offer outside its owner's own open prep.
Not taken from the PR: its §25.24 in the released docs/history/0.2.0.md (the 0.2.2 section is the integrator's), its edits
of the Ready toggle beyond the personal-choice case, its tail placement of the i18n keys.
Golden: coop2-NORMAL-8-serverrun (ai_0 杜宾 casts 教鞭 from R2 on and now scores the three cards: teamLp 39 -> 34, virtualMs
121400 -> 118400, rng shop 511 -> 483 / bots 18063 -> 18070 / meta 112 -> 103) and coop2-ABYSS-10-boosted (ai_1 杜宾: virtualMs
121650 -> 124650, shop 590 -> 589 / bots 22075 -> 22096 / meta 141 -> 154); both first differ in round 2, every other scenario
and family is unchanged; node tools/golden.mjs --twice is identical.
Tests: items.test.js (three distinct cards, the tapped one applied once, nothing before the confirm, a refused cast keeps
the Art / count / rng / uid, an eliminated player's offer), economy.test.js (Ready refused, the deadline picks before
endPrep, solo prep untimed), connection.test.js (two players' offers, reconnect, foreign / duplicate / old ids, an offline
player's pick at the deadline), bot.test.js (托管 takeover incl. the failing-step fallback), bot-smarter.test.js (the scorer's
pick, deterministic per seed, no rng draw when nothing is pending), followups.test.js (R14 / R15), draft.test.js,
unitStats.test.js (protocol), hardening.test.js (invariant), gameLogic / playtest3 / playtest4 (view model, Ready reason,
ChoiceView, actions), mock.e2e.test.js and playtest2.real.e2e.test.js (browser, SP_E2E=1).
2026-10-08 20:45:54 +08:00
sganggs 38d4c3e4b5 feedback7 R22-GHSIM: 余 【文火慢炖】 adds no layers to a bond without layers (noStack: 绝技, 独行, 调和, 协防干员) — with one such bond the only one active, nothing is added (the owner's decision of 2026-10-08); golden: unchanged
The owner's decision (relayed 2026-10-08) overrides PRTS 下半/PRTS盟约记录 「部分盟约不会显示叠加层数,但是叠加层数的特质/策略/
装备等效果仍然对其生效」 for this strategy. bands/meta.js round_start_bond_check_gain_layer skips every bonds.json noStack bond;
the 「仅激活了1个盟约」 count stays the sentence's (every active bond), so: 独行 / 绝技 alone → nothing; 独行 + one layered
bond → the layered one +12 (count2), 独行 none. Repro: 独行 alone got 36, 绝技 alone 36, 独行 + 炎 got 12 each.

Only 余: 协防 (bonds/addon/meta.js deputShip, 「使所有已激活的盟约层数+N」) and 华法琳 【重点监护】
(prep_finish_char_bond_add_layer, a random operator's bonds, 无需激活) each pick their own bonds and call addLayers; they
share no helper with 余 beyond the generic Player.addLayers sink, which every layer gain uses — left unchanged, so both
still add to noStack bonds as PRTS says. Docs: PLAYING.md 层数. Golden: unchanged (no corpus 余 at round 8 with such a bond).
2026-10-08 20:34:51 +08:00
sganggs 895653fc10 feedback7 R22-GHSIM: the 帝国炮火先兆者 shells hit every ally whose collider touches their 1.2 circle — the impact tile and the 8 around it, not just the cross (GitHub #364); golden: roster-001, roster-019, diy-020 move
Seen (#364, FrogThai): the 中枢先兆者's shell hit the target and its orthogonal neighbours only — repro: a diagonal
neighbour (√2 ≈ 1.414 from the impact) took nothing, as did a tile two away; the reporter saw the 3×3 in the official game.

Official: PRTS 天赋 of both 先兆者 (one shared kit) 「弹道对半径1.2范围内的所有我方单位造成攻击力100%的无来源物理伤害(此弹道
不会强制击中主目标,碰撞无视迷彩)」. The landing is a 碰撞; PRTS 作战机制 §碰撞体积 (docs/SIM.md, constants.js): collider tests are
the common way and an ally's collider is a 0.25 circle — the rule the engine already applies to ranged enemies' reach.

Now (content/enemies/fly.js kitShell): an ally is hit when its collider touches the 1.2 circle — centre distance ≤ 1.45
(SHELL_REACH = SHELL_RADIUS + ALLY_COLLIDER_RADIUS): the impact tile and the 8 around it, never two tiles away. The
telegraph and the blast are drawn at that reach. [ASSUMED] for this shell (its text names the 碰撞); other content zones
keep their point radius as before. Golden: the three battles with a 先兆者 whose shells land beside a diagonal operator
(roster-001 中枢先兆者, roster-019 and diy-020 先兆者).
2026-10-08 20:21:19 +08:00
sganggs e733171b13 feedback7 R22-OSIM: 香槟炸弹 no longer goes off on an unrevealed 隐匿 enemy (nor a sleeping one) — it selects like the other contact traps; golden: bond-yanShip-high, coop2-HARD-4 move
Community report relayed by the owner: 「有人反馈香槟炸到没有破隐的隐匿敌人了」. Reproduced: a 隐匿 walker crossing
琳琅诗怀雅's bombs set them off (both kits checked hidden / flying / untargetable only). The rule: PRTS 作战机制 §隐匿
"隐匿效果使得获得该效果的单位无法被任何敌方的能力索敌选中…要选中隐匿的目标,则该单位自身需拥有无视隐匿的效果"; 异常效果 lists
隐匿 and 无敌 among the 无法选择 effects (沉睡 = "无敌且无法行动", gamedata_const ba.sleep). Neither the 香槟炸弹 page nor
琳琅诗怀雅's S2 carries a 无视隐匿 / 无视可选性 note, and the other contact traps of the sim (多萝西's 共振装置, 望's 棋子)
already select through canTargetEnemy.

Now both kits go off on a ground enemy canTargetEnemy accepts (tokens.js CHAMPAGNE_TRIGGER): a 隐匿 enemy sets one off
once it is revealed (反隐) or blocked (its 隐匿 lifts), a sleeping one once it wakes (until now the bomb was spent on it
for no damage). Placement is unchanged (it already aimed at selectable enemies only).

Golden: bond-yanShip-high and coop2-HARD-4 (bombs under 隐匿 enemies of rounds 10–11 — 隐形弩手组长, 访问团强攻冠军,
重弩突袭者 — and sleeping ones of round 7 — 宿主士兵, 粉碎攻坚手 — now wait).

Tests: test/content/feedback7-champagne-stealth.test.js (2; both fail on the parent).
2026-10-08 20:15:17 +08:00
sganggs 4128965a9f feedback7 R22-GHSIM: an instant skill with no attack of its own takes one attack cycle — 引星棘刺 S1 under 迅捷 no longer recasts every tick, and attack speed paces such casts (GitHub #298); golden: 84 scenarios move (below)
Seen (#298, FrogThai): 度算浪波 (AUTO, instant, SP_FULL, cost 6, no attack) with 迅捷's refund (12 + 15 at ≥ 40 layers)
cast 60 times in 2 s — every tick — at ASPD 100 and at ASPD 600 alike (repro): skill.tick checks tick rules before the
attack loop and an instant cast ended without touching the attack cooldown.

Now (skills.js): such a cast (instant / charges, no spec.attack) sets atkCd to at least the attack interval, and the
casts checked in skill.tick (the tick rules, the DEFAULT of units that never attack, content trigger ranges) wait while
the cooldown runs beyond this tick — a remainder ≤ dt is this tick's slot, which the cast claims before updateAlly's
attack. A cast right before an attack (onAboutToAttack, DEFAULT) is followed by that attack as before; timed skills,
"next attack" skills and TAKE_DAMAGE / kit casts' gating are unchanged (a TAKE_DAMAGE or kit cast also takes the cycle).
[ASSUMED] one attack interval (PRTS prints no 前后摇 for such casts). Measured: 2 casts / 0 attacks in 2 s at interval
1.36 s, 9 at 0.25 s; with no enemy it still fires at full SP (#124). Not taken: PR #313's 3 s operation cooldown for
AUTO skills (it conflicts with #124). Docs: SIM.md §7 trigger rules, PLAYING.md 技能自动释放.

Golden — every moved battle fields an instant no-attack skill cast from the tick, which now waits for / takes the
attack cycle (德克萨斯 S2, the 先锋 DP skill skcom_charge_cost, 赫默 S2, 雪猎 S2, 莱恩哈特 S2, 凛御银灰 S1 / S2, 异客 S3,
锏 S2, 伺夜 S1 / S2, 焰尾 S1 / S2, 引星棘刺 S1, 忍冬 S2, 郁金香 S3 (补位); 自选 陈 / 艾丽妮 / 嵯峨 S2, 左乐 S3, 重岳 S2,
温蒂 S3, 望 S1 / S2, 多萝西, 黑键 S2): roster (22): roster-001 roster-003 roster-005 roster-008 roster-010 roster-012 roster-014 roster-015 roster-016 roster-018 roster-020 roster-021 roster-028 roster-029 roster-031 roster-033 roster-034 roster-039 roster-040 roster-041 roster-042 roster-048;bonds (9): bond-deputShip-low bond-indomShip-low bond-raidShip-high bond-skillfulShip-low bond-soloShip-high bond-suntShip-low bond-victoriaShip-high bond-visiShip-high bond-visiShip-low;fields (9): boss-boss_1-pair boss-boss_2-pair boss-boss_3-pair boss-boss_4-pair boss-boss_5-pair boss-boss_6-pair hidden-boss_10-pair hidden-boss_8-pair hidden-boss_9-solo;matches (16): coop2-ABYSS-10-boosted coop2-HARD-4 coop2-NORMAL-14-standins coop2-NORMAL-3 coop2-NORMAL-70-diy coop2-NORMAL-8-serverrun coop3-ABYSS-5 coop4-ABYSS-7 coop4-FUNNY-6 solo-ABYSS-1 solo-FUNNY-1 solo-FUNNY-2 solo-HARD-1 solo-HARD-2 solo-HARD-9-boosted solo-NORMAL-1;standins (6): standin-01 standin-03 standin-04 standin-08 standin-09 standin-10;diy (22): diy-001 diy-002 diy-003 diy-004 diy-005 diy-007 diy-013 diy-014 diy-015 diy-033 diy-034 diy-035 diy-036 diy-037 diy-109 diy-110 diy-111 diy-112 diy-114 diy-115 diy-116 diy-137
Tests adapted to the rule: op_wang (the second 立即获得两枚棋子 waits out her cycle), playtest6-skills (锏 S2's first cast
may wait one attack interval).
2026-10-08 20:15:14 +08:00
sganggs 5f98baecc1 feedback7 R22-OSIM: 琳琅诗怀雅's 香槟炸弹 holds 禁疗, loses no HP and never leaves because of its HP (the owner's decision D2); golden: bond-yanShip-high, coop2-HARD-4 move
The owner's decision D2 of 2026-10-08, a deliberate deviation: PRTS 香槟炸弹 gives it 1000 HP and the note
"即使自身生命值未满,模型下方也不会显示生命值槽" (officially it can lose HP), and it had no 无敌 / 禁疗. Now
(tokens.js champagneHold, installed by the token kit and by 琳琅诗怀雅's own bomb):
- 禁疗: no heal reaches it, no healer picks it (flags noHeal + healFree, no status icon);
- no HP loss: every damage to it is cancelled in its `hit` / `elementHit` hooks (活性源石, 污染秽蚀, …) and a 流失
  is given back before the knock-out check, so it never leaves because of its HP;
- its 见面礼 is unchanged: the first ground enemy that touches it, then it is gone. No 无敌 flag (that would put a
  badge over it); the client side (its hidden HP bar) belongs to the render stream.

Golden: bond-yanShip-high (a healer of that team spent 27 heals — 5040 HP — on a bomb standing on 活性源石; now it
attacks nothing there) and coop2-HARD-4 (ai_1's bombs from round 6 on stood on 活性源石 / 污染秽蚀; their longer life
changes later rounds' layers).

Tests: test/content/feedback7-champagne-hold.test.js (3; 2 fail on the parent, the 见面礼 guard passes on both).
2026-10-08 20:07:06 +08:00
sganggs f14b3a062f feedback7 R22-FIELDS: 耀骑士临光's 卡西米尔 redeploy reduction (garrison 144) has no 5 % floor — the multiplier clamps at 0 like every other redeploy multiplier, so a knock-out timer can reach 0 s (GitHub #370); golden: unchanged
GitHub #370 (FrogThai): 「耀骑士临光特性赋予身前干员减再部署有上限,最多减至5秒」. Cause: content/garrisons/battle.js
applyReader, act1autochess_gar_eff_respawnTimeByBond, wrote redeployMul = max(0.05, 1 + respawn_time × steps), so the
timer stopped at 5 % of the base time — from 192 卡西米尔 layers for 144_a (raw 0.04) and from 96 for 144_b. Measured on
a 100 s base (notes repro-370.mjs): 144_a 192 / 300 layers → 5.00 s / 5.00 s, 144_b 96 / 192 / 300 → 5.00 s each.
Official: data/garrisons.json garrison_144_a bb { divide_num 3, respawn_time −0.015 } 「每叠加3层,本干员再部署时间-1.5%」,
144_b −0.03 「-3%」 — no minimum key; PRTS 耀骑士临光 has no 卫戍 note on a minimum. Now max(0, …) as items/battle.js,
bands, the 协防 bond and svrash; deploy.js already clamps the timer at 0: 144_a 192 / 300 layers → 4.00 s / 0 s,
144_b 96 / 192 / 300 → 4.00 s / 0 s / 0 s. A 0 s timer brings the operator back on the next tick, no error (notes
probe-370-redeploy.mjs). The ASPD part (garrison 159 / 160) is untouched. Patch from the Grok triage
(scratch-i1b/370.patch), the test extended with 96 layers and the 0 s return.

Tests: test/content/garrisons_battle.test.js 26/26 — the new #370 test (144_a / 144_b at 9, 96, 192, 300 layers: the
multiplier, the knock-out timer, the 0 s return) fails on the parent.
2026-10-08 19:56:44 +08:00
sganggs 5a045731f1 feedback7 R22-OSIM: 望's placed 棋子 drop their 铸子 跟子 at the battle start (undeployable ground first, 上 > 右 > 下 > 左); a deployment on a 跟子's tile removes it; S3's overflow follows the same order; golden: unchanged
Community report relayed by the owner: 望的天赋以及3技能增强的天赋提供的额外棋子是可以出现(官方好像有出现的前后左右先后
顺序的规则)在不可部署地块的. The placement rule was already PRTS 望 铸子 备注's ("有敌人的>没有敌人的;不可部署地块>可部
署地面地块>可部署高台地块…相同优先级时按棋子上>右>下>左"), but only a 棋子's return dropped a 跟子: the battle-start
deployment of the pieces the player placed — their 手动部署 in this mode (PRTS 卫戍协议/帮助: a placement in 休整 fires
no deployment effect; the piece deploys when the combat starts) — dropped none, so no extra piece appeared, a lone 棋子
never connected and never set off. Now:
- the stone kit's deploy hook drops one 跟子 when `ctx.initial` (a return still drops its own in scheduleReturn);
- "跟子所在格进行部署(或进行类似部署的行为)时,该跟子会随之消失": any ally deploying on a 跟子's tile removes it (the
  battle start deploys one piece after another, so a 跟子 may first land on a piece still to come);
- S3's overflow (备注 "采用相同的位置选择优先顺序"): enemy tiles first, then the tile class, then her target order /
  distance / tile [ASSUMED ties] — an enemy on undeployable floor now comes before one on the road.
Her stock rule (the owner's decision of 2026-10-06) is unchanged; a 跟子 takes no stock.

Tests: test/content/op_wang.test.js — the four tests that encoded "the battle start drops no 跟子" updated, a removal
case and an S3 order test added (10; 5 fail on the parent).
2026-10-08 19:36:35 +08:00
sganggs 977215e14d feedback7 R22-OSIM: enemy effects PRTS marks 不可对空 no longer hit the flying 炎佑 (death blasts, 水遁忍者's vortex, 鼎沸, 祈祷邀约, the 胄 blades); golden: unchanged
Community report relayed by the owner: 炎祐好像吃到了不该吃到的地面伤害. 炎佑 is a flying ally (PRTS “炎佑”
行动方式 飞行). The ground terrain (活性源石), 烹泉 / 沏虹, 庞贝 and 集团军重型火炮 already skipped it, but these
不可对空 effects (PRTS, read for every enemy of data/enemies.json) went through areaAllies / fieldAllies /
targetsNear, which exclude 起飞 allies only:
- 死亡爆炸 of 高能源石虫 / 冰爆源石虫 / 卷心籽 (archetypes deathBoom: `noAir`, on by default; 寒冷 too);
- 水遁忍者 漩涡形态 "每秒对半径1.0范围内的所有我方单位造成…(无视迷彩,不可对空)";
- 鼎沸 "攻击范围内的所有我方单位每秒受到…法术持续伤害与…灼燃损伤(不可对空)";
- “萨科塔昂首” 祈祷邀约 "令全场我方单位(不可对空,无视迷彩)获得15s【受邀祈祷】攻击速度-30";
- “斩胄之剑” / “破胄之锤” "普通攻击对攻击范围内的所有我方单位造成…物理普通伤害,不可对空" (its target rule too).
A ground enemy's normal attack and the 不可对空-free effects still reach it (PRTS: enemies that hit air target it).

Tests: test/content/feedback7-yanyou-noair.test.js (8; all fail on the parent).
2026-10-08 19:36:35 +08:00
sganggs 42caca3be8 feedback7 R22-OSIM: 引星棘刺's S1 / S2 alchemy units restore HP as 生命回复速度, so 不屈者 and 禁疗 operators recover too; golden: 12 scenarios move (each fields 引星棘刺)
Community report relayed by the owner: 炼金师分支干员的炼金单元无法给不屈者等禁疗的干员提供生命恢复. The
alchemist branch is 锡人 and 引星棘刺. 锡人 S2's recovery was already an hpRegen buff (PRTS 锡人 备注:
"生命恢复的提供方式为增加目标的“生命回复速度”属性,不受治疗加成和禁疗影响"). 引星棘刺 S1 度算浪波 ("每秒回复相当于
攻击力…的生命值") and S2 解构涌潮 ("友方单位每秒恢复相当于攻击力…的生命") carry the same wording and blackboard key
(hp_recovery_per_sec_ratio[_chr]) but called battle.heal, which 不屈者 (no heal from others) and 禁疗 refuse.
Both are now an hpRegen buff per alchemy unit, set at each 1 s pulse until the next (锡人's pattern): the
same amount per second, not scaled by heal bonuses, credited to the target's own regen; S2 skips 孤立
units like every ally effect. Her PRTS page has no 备注 on this; the classification rests on 锡人 and the report.

Golden: roster-014, roster-015, roster-033, roster-034, bond-maniShip-high, bond-soloShip-high,
boss-boss_2-pair, boss-boss_4-pair, boss-boss_6-pair, hidden-boss_8-pair, hidden-boss_10-pair (引星棘刺 on
the board, S2 by default) and coop2-NORMAL-14-standins (h_0 fields her from round 11): her allies' HP
now rises over each second instead of in one lump, and the heal stats move from her to them.

Tests: test/content/feedback7-thorn2-regen.test.js (2; both fail on the parent); the S1 case of
kits_alt_t5 asserts the regen buff instead of a heal of hers.
2026-10-08 19:36:35 +08:00
sganggs 6d6fbe9277 feedback7 R22-OSIM: 伊内丝 S3 starts again on a 突袭 landing (keepSp no longer overwrites the charge a free skill gets at every deployment); golden: unchanged
Community report relayed by the owner: 伊内丝激活突袭瞬移以后3技能被吞. The 突袭 jump retreats the operator,
which ends her running S3 独影归途 (PASSIVE, spCost 0, "部署后…", cast by her kit's deploy hook), and
redeploys her with keepSp (activity_table bondeffect_raid "保留技力立即再部署"). The snapshot taken after
the retreat held 0 charges and was written over the charge reset() had just given the free skill, so
the landing's activate('deploy') failed and S3 never ran again. keepSp now applies to skills that cost
SP only; 伊内丝 S2 (27 SP) keeps a full charge and a partial bar as before. The other free skills set
activateOnDeploy and were already running at that point (not affected).

Tests: test/content/feedback7-ines-raid.test.js (2; the S3 one fails on the parent).
2026-10-08 19:36:35 +08:00
Sukvii c250ff66f4 feedback7 R22-GHSIM: 假想敌:骨刺 targets as PRTS writes — its normal attack ignores its block (by priority, not the blocker first), never a flying unit, and its 3 hidden targets come from its normal attack's reach (PR #365 by @Sukvii, sim part, each line checked against PRTS); golden: roster-018 moves
The sim lines are the PR's (content/enemies/invisible.js kitBoneSpike: profile blockFree and canTarget, the hidden
selection over rangeRadius + the ally collider), so the contributor is the author of this commit; the maintainer side
checked each rule, kept the engine's single target when the hidden list is empty, and wrote the tests.

Official: PRTS 假想敌:骨刺, 级别0 天赋 (on the page since 2025-11, PRTS editors): 「自身普通攻击索敌不受阻挡影响」 「不会攻击
飞行单位,隐匿(解除阻挡0秒后恢复)」 「隐匿期间可同时攻击3个目标」; enemy_database's level description 「隐匿;隐匿状态下同时攻击
3个目标。」 (the handbook line keeps 「数个目标」) — the 3 is no longer [ASSUMED]. blockFree works as for 自制投石机 (a 隐匿 /
迷彩 blocker is no target); canTarget as the engine's other 不会攻击飞行单位 enemies; the hidden 3 are picked among the
allies its normal attack could hit (ai.js attackTargets: rangeRadius + ALLY_COLLIDER_RADIUS, PRTS 作战机制 碰撞体积) — they
were picked within the bare 2.0. Stealth back 0 s after a block was already so.

Golden: roster-018 — the 骨刺 in it lands one more attack (on 异客; dmg 2434 → 2771), the same move PR #365 reported.
2026-10-08 19:28:53 +08:00
IceCodeNewandConvey123 8ae891f1f3 feedback7 R22-HUD: the HP bar shows the ammo skill's rounds as yellow cells (隐现 S2: 14), 伺夜's 狼影 left as diamonds and 斩业星熊's 我执 pool as a red bar — one snapshot change for PR #303 and #378 by @IceCodeNew and PR #383 by @Convey123; golden: unchanged
The three PRs patched the same snapshot and HUD lines (Grok's review: do not merge three diffs), so this is one design
built from their code and tests; IceCodeNew is the commit author (#303, #378), Convey123 co-author (#383).

- b.snap gains three optional, display-only lists beside the unchanged 9-field tuples (snapshot.js ammoView / wolfView /
  negView, called from battle/events.js snapshot(); a living, deployed, visible ally, only when it has one):
  ammo [[id, rounds left, magazine]] (whole rounds; the magazine is the activation's real total that unitTuple's SP
  fraction runs on, extras and refills included), wolves [[id, 狼影 left, talent maximum]] (mem.shadows of the new
  mem.wolfCapacity, set by tokens.js wolfPack and the managed vigil kit), neg [[id, fill]] (unit.negFill(), a function
  op-hsgma2.js sets: the pool is read when the snapshot is taken, no per-tick sync). UnitInfo.ammoSkill (an ally whose
  skill is an ammo magazine) is known from the first appearance: fx events run before the frame's sample, so the aura
  cannot wait for the first ammo row.
- render/interp.js keeps the lists per snapshot (malformed rows / unknown ids dropped) and sample() hands them out from the
  older snapshot like flags (they step with the skill flag); render/units.js draws them: the ammo magazine replaces the
  SP bar (a cell per round, thin cuts, exact fill, no cuts under 2 px a cell), a row of diamonds under the bars for the
  wolves (the element gauge row moves below), the red bar over the drained HP bar for the pool. An ammo skill draws no
  standing aura (rings.js _aura; the activation burst stays).
- PR #378's wolf-head avatars are NOT taken: the count is data (the talent text 至多3只, mem.shadows), the HUD art of the
  official counter is in no game data we have, so the pips are plain diamonds [ASSUMED look]. The PRs' own tests are
  folded in and extended (test/sim/hud-readouts.test.js, test/render/hud-readouts.test.js, op_hsgma2.test.js).
- Docs: network.md, SIM.md §9, client.md, PLAYING.md, types/core.js.
- Golden: unchanged (283 scenarios; the canon hashes units / down / elem only, no sim state moved).
- Tests: 4 + 14 new + 1 in op_hsgma2 (12), all fail on the parent; 344 related tests pass; lint 0 errors, typecheck,
  check:imports, docs tests.

Co-authored-by: Convey123 <Convey123@users.noreply.github.com>
2026-10-08 19:22:08 +08:00
sganggs ca671f2fd0 feedback7 R22-GHSIM: 大帝 加急调派 stacks without a cap — the 21st deployment and every later one still halve the next redeploy (GitHub #328, PR #329 by @IceCodeNew, re-implemented); golden: unchanged
PRTS 卫戍协议:盟约 下半 and its PRTS盟约记录: 「我方干员每次部署后再部署时间减少50%」 with the note 「※该策略效果可无限
叠加」; the data's buff (act1autochess_band16_buff, respawn_time −0.5) names no cap. The per-deployment ×0.5 stack was
capped at 20 (since the initial import, no source); maxStacks is now unbounded, the multiplicative stack itself is
unchanged (the "each deployment" reading was [ASSUMED] cumulative — the 无限叠加 note backs it). Golden: unchanged (no
corpus battle deploys one operator more than 20 times under 大帝).
2026-10-08 19:16:34 +08:00
sganggs 7e8b435f7c feedback7 R22-GHSIM: 信仰搅拌机 S1 reloads the latest-deployed 拉特兰 ammo user on his 8 surrounding tiles, not the nearest (GitHub #325, PR #329 by @IceCodeNew, re-implemented); golden: unchanged
PRTS 信仰搅拌机 S1 备注: 「补弹范围为周围8格,仅选择可补弹的干员为目标,优先选择最后部署的干员」. The candidates (his own
拉特兰 operators within 1.5 tiles — the 8 surrounding tiles — whose ammo skill runs) are now sorted by the battle-wide
deploySeq, latest first (a redeploy is a new deployment), ties by unit id; until now by distance [ASSUMED]. The unused
detmath hypot import goes. Golden: unchanged (no corpus battle has two such candidates in a different order).
2026-10-08 19:13:30 +08:00
CXUtk f2aec39e93 feedback7 R22-FIELDS: the Hidden Core 铳's 碎铳之簧 chase the casting gun for the whole 5 s of 末日布道 instead of stopping on arrival; each gun keeps its data timer, the later call takes the springs (PR #347 by @CXUtk, its pair stagger and lock not taken); golden: hidden-boss_9-pair, hidden-boss_9-solo, coop2-ABYSS-10-boosted
PR #347 by @CXUtk, applied with changes. Kept: 追逐模式 lasts the gain's whole 5 s — PRTS 假想敌:铳 末日布道 "令全场的
“碎铳之簧”获得5秒增益…增益期间切换为追逐模式", “碎铳之簧” 追逐模式 "持续追踪令其进入该形态的场上的假想敌:铳移动" (no
arrival clause, unlike the 铳's own 冲锋模式, which ends "到达目标所在位置后"); data skill 2: cooldown 45, initCooldown 20,
dog_duration 5, move_speed 8. kitSpring no longer ends the chase when it reaches the gun or comes within 1 tile; with no
gun left on the field the spring holds still until the gain ends (until 0.2.1 that ended the chase at once).
Not taken (the maintainer's decision on the Grok triage): the second gun's half-cooldown first-call delay and the cond
that refused a call while any spring was chasing — neither is in the data, and the lock contradicts the handbook's
「持续召唤场上所有“碎铳之簧”向自身移动」 (a call takes every spring to its caster). Both guns keep their data timers, so on a
pair field the mirrored gun's call, a tick after the first, retargets the springs for a new 5 s.

Measured (notes repro-347.mjs): a spring 0.2 tile from the gun chased 0.03 s, one 5 tiles away 2.97 s; now 5.03 s both.

Tests: test/content/hidden-gun-pursuit.test.js (new, 5; the arena harness and two tests are the PR's): the full 5 s
next to a moving gun and with no gun left fail on the parent; the pair timing (20 s after each gun's spawn, then every
45 s, the two calls a tick apart), a mid-chase call retargeting the springs for a new 5 s and the solo timing guard
against the stagger / lock. test/sim/feedback1e-healers.test.js E2 audit: the fields whose leaders / parts a healer must
block run 200 s instead of 120 — on the solo 铳 field the springs now first meet a healer at 145 s (at 21 s until now).

Golden (on top of the portal commit):
- fields hidden-boss_9-pair: the springs spend 5 s invulnerable per call, so they take less (actrpa 855522 → 722451,
  actrpb 798033 → 660498, actrpc 1384683 → 1168947) and pass less on; leader left 3511007 → 3747749; p2's deaths
  7 → 12 (longer tramples); still 8 / 8 kills, no leak.
- fields hidden-boss_9-solo: leader left 1932856 → 2011732; the springs take less; 隐德来希's candles (5601_entlec, an
  enemy-side summon) 6 → 8.
- matches coop2-ABYSS-10-boosted (hidden boss_9): still cleared at 800 LP; the seats' leader damage shifts
  (7523075 / 6369365 → 6992346 / 6900614).
2026-10-08 19:13:21 +08:00
sganggs b2510524b0 feedback7 R22-GHSIM: 歌蕾蒂娅 S3's skill-end 捕网 pulls the enemies within 1 tile of the tornado, not 1.5 — the tornado keeps 1.5 (GitHub #324, PR #329 by @IceCodeNew, re-implemented); golden: fields boss-boss_4-pair moves
PRTS 歌蕾蒂娅 S3 备注: 「龙卷风半径1.5」 and 「技能结束时的拖拽为捕网,捕网半径为1,无伤害」. The kit reused the tornado's
radius for the final pull (its 1.5 was marked [ASSUMED]; PRTS now backs it). The slow and the pulses keep 1.5; only the
skill-end pull (to her front, as before) uses 1. Golden: boss-boss_4-pair fields 歌蕾蒂娅 — fewer enemies are dragged to
her front at the skill end, the fight runs differently (11 kills instead of 14, one leak).
2026-10-08 19:10:37 +08:00
sganggs a0cd6826e5 feedback7 R22-GHSIM: 异客 S3's 雷暴 covers range x-1 — the 13-tile diamond — around the tile of the target's centre, not a 1.5-tile circle around its position (GitHub #322, PR #329 by @IceCodeNew, re-implemented); golden: roster-016/018/048, fields boss-boss_1/3/5-pair + hidden-boss_9-pair, matches solo-HARD-1, solo-ABYSS-1, coop2-HARD-4, coop2-ABYSS-10-boosted, coop2-NORMAL-70-diy move
PRTS 异客 S3 备注: 「开启技能时选择技能范围内的目标,以其判定中心所在格为中心生成一个x-1的雷暴区域」; range_table x-1 is the
13-tile diamond (|Δrow| + |Δcol| ≤ 2); x-3 (|技能范围|) stays the search range. The storm's tile is the rounding of the
target's centre (body.js posKey), fixed for its 4 s; a strike picks among the enemies she can select whose body is on
those tiles (enemiesInKeys, as her other range checks); each strike still chains on its own bounce radius. The fx ring is
drawn at radius 2 (visual only). Until now: [ASSUMED] radius 1.5 around the target's exact position — an enemy two tiles
straight off the target's tile was never struck, one at (+1.55, +1.05) off the tile centre was.

Re-implemented from the PR's claim (its golden files were not taken). Golden: every moved scenario fields 异客 casting
S3 — the zone holds other enemies and the random pick draws from another list.
2026-10-08 19:03:55 +08:00
Convey123 ffa538c39d feedback7 R22-RENDER: 赤刃明霄陈 S3's sword wave is drawn along its path — the sim sends its position as a chen3Wave fx every 0.12 s, the client draws a 'qi' blade (PR #382 by @Convey123, owner item 12); golden: diy-073 / diy-074 events.fx and fx.chen3Wave only
The 赤霄·天喟 wave is a kit-managed probe (it turns corners and lives as long as the skill), not a snapshot
projectile, and the sim emitted one `dash` at the cast and a `slash` per hit — nothing along the way, so the client
drew no wave. op-chen3.js now emits fx('chen3Wave', { x, y, fromX, fromY, dr, dc, id }) every WAVE_FX_EVERY (0.12 s;
4 ticks), the trail restarting at a corner; render/fx registers chen3Wave → 'qi' (pt: drawn at the event, never on
her) and draws a streak plus a crescent head turned the way it travels. The look is a procedural stand-in, not the
official particle prefab.

Substantially @Convey123's code (PR #382), authored as theirs. Changed on review: the head is projected after
streak() — streak() reuses the effect system's projection scratch, so the PR drew the crescent on the trail's start,
one event behind the wave — and the trail, head and heading share one height; an unused test variable dropped.

Golden: diy-073 (5_diy*=chen3 S3 in two slots) events.fx 508 → 1558, fx.chen3Wave → 1050; diy-074 (6_diy*=chen3 S3)
events.fx 272 → 872, fx.chen3Wave → 600. HP, kills, damage, hooks and snapshot hashes unchanged: battle.fx only
records an event.

Tests: test/content/op_chen3.test.js (+1: the events, their cadence, id, direction, trail start, silence after the
skill) 12/12; test/render/fxchen3wave.test.js (new, 6: the archetype, drawn at the wave not at her, the head on the
wave and turned with it, a sweep joining into one trail, junk input, nothing left after) 6/6; boardart 15/15.
2026-10-08 18:48:53 +08:00
siruimei07 3356b340a7 feedback7 R22-GHSIM: three or more overlapping 同名效果取最高 applications resume strongest first — the middle one no longer drops out when the strongest ends (GitHub #342, PR #348 by @siruimei07); golden: diy-059, diy-122, diy-123, diy-124, diy-133, diy-138 move
The contributor's code (status.js _applyValuedStatus and both test files, applied as written from PR #348), so they are
the author of this commit; the maintainer side added the 同名效果取最高 label back to the JSDoc and a docs/SIM.md line.

buff.data.tail held ONE waiting application (the later-ending one): a third, weaker but longer one replaced a middle one
that was still running, so when the strongest ended the effect jumped to the weakest (#342: 30 % / 25 % / 20 % 减防 —
DEF 1000 → 700 → 800 instead of 750 → 800 → 1000). The tail is now a chain ordered by strength (decreasing) and end
(increasing): a weaker application is inserted in it, a stronger one takes over with the old value and its chain behind
it, an equal refresh trims waiters that end before it, and an expiry resumes the next live waiter with the rest of the
chain. removeStatus / removeBuff still drop the whole chain; two-application data shapes are unchanged.

Golden: six 自选 battles that stack three same-name applications on one unit — diy-059 / diy-122 / diy-123 / diy-124
(庇护 from several operators), diy-133 (Mon3tr's ASPD talent buff talent:monstr:aspd), diy-138 (脆弱) — the middle
application now resumes.
2026-10-08 18:48:26 +08:00