Commit Graph
64 Commits
Author SHA1 Message Date
sganggs e7d957b27c feedback1 final: the loadout screen's background layer draws again (pointed out in PR #14)
css/screens/loadout.css: `.lo > * { position: relative }` (one class, a later rule) overrode `.lo__bg { position:
absolute }`, so the mint glow / grid layer was a 0-px flex item and never rendered. `.lo > :where(:not(.lo__bg))`
keeps the one-class specificity for every other layer and never matches the background.

Checked in headless Chrome at 1920x1080 and 844x390 (touch): the layer now covers the overlay (0 px tall before),
every other box of the screen is unchanged, no console errors. Tests: test/ui/loadout.test.js (the cascade; fails on
the old rule), opt-in test/ui/loadout.e2e.test.js (the layer's box and stacking at both sizes). DESIGN §21.25 credits
PR #14 and PR #10 (crossOrigin on the two new Image() loads); CHANGELOG 0.1.1 lines for both.
2026-10-03 19:17:27 +08:00
sganggs e6ab4e1ff8 feedback1 final: merge GitHub master (PR #10 crossOrigin on the two new Image() loads, PR #12 深巡 / 雷蛇 S2 cast with an enemy in range) 2026-10-03 18:54:16 +08:00
sganggs ff7ce30907 feedback1 final: merge the strategy draft's 查看禁用盟约与干员 dialog (GitHub issue #8 item 1; one matchInfo component for the briefing, the draft and the in-game 本局信息 tab)
Conflicts resolved keeping both sides:
- bandDraft.js header: the 本局禁用 mark of a strategy tied to a switched-off bond, then the 本局信息 dialog; the code
  merged cleanly (the card's 本局禁用 tag and the detail note sit beside the dialog's state and button).
- draft.css: the 本局禁用 tag / note rules, then the 本局信息 entry and dialog block (its header cites DESIGN §21.28).
- CHANGELOG 0.1.1 界面: the gaps and issue #5 / #8 lines, then the dialog line.
- PLAYING §6: the disabled-bond line says where to look again (draft dialog, in-game 🔍); the 变形同构体 line keeps its
  pairing explanation.
- DESIGN: the branch's "§21.26 Match info in the strategy draft" becomes §21.28; its two §10 references follow.
2026-10-03 18:51:37 +08:00
sganggs c61167e3aa feedback1 final: merge the client fixes for GitHub issues #5 (prep camera follows the folded shop) and #8 item 5 (operators no longer stay placeholders)
Conflicts resolved keeping both sides:
- CHANGELOG 0.1.1 界面: the three gaps lines, then the issue #5 and #8 lines.
- DESIGN: the branch's "§21.26 Client fixes for GitHub issues #5 and #8" follows the gaps' §21.26 as §21.27; its
  references in §9 (setCamera `shop`, the model fallback), §17.1 (the quiet budget) and §19.8 (the collapsed shop)
  now point at §21.27.
2026-10-03 18:49:39 +08:00
sganggs b7ac003e09 feedback1 ui: operators no longer stay placeholders after a reload or a battle begun in a hidden tab (GitHub #8)
A reload (a phone browser or Chrome's Memory Saver discarding the background tab) made the asset store download
/data/assets.json a second time; createFieldView waited at most 4 s for it, every view looked its model and avatar up
once, and a failed download kept an empty manifest for the page. Now the field host seeds the store with the game
data's copies (seedAssets); without one, ready() retries like data.js, never keeps a failure and tries again with a
bounded backoff, and onChange makes every view re-resolve (UnitView.retryAssets, ItemView.setIcon). A failed or
timed-out Spine load is retried by its view (SPINE_RETRY_MS, acquire { retry }) and at once when the tab is shown.
Battle mode holds the Spine cache (spine.hold()), so a battle that began in a hidden tab keeps its models; the idle
budget still applies and the quiet budget still frees everything in the lobby, room and result.
2026-10-03 16:15:01 +08:00
sganggs 82c54897c7 feedback1 ui: folding the shop in prep moves the own board to the official shop-collapsed camera (GitHub #5)
While the own prep board is shown and the shop bar is folded, the game asks for the prep camera with shop: false
(left_prepare_camera_param / the boss prepare params) and the view keeps the bench above the folded shop's HUD band:
the higher of the folded tab and the corner buttons' hit areas (hudBands(kind, size, { shop: false }), cornerBand).
Unfolding returns to the shop camera. Never over the pen, a teammate's board or a battle; deferred while a piece is
dragged or its direction is chosen (gameLogic prepCameraFor / foldCamera). Below 768 px of width the corner stays on
one row while the bar is folded. Tile px at row 10: 1920x1080 109.8 -> 130.7, 844x390 35.9 -> 44.3,
756x366 31.4 -> 40.1, every bench pad fully pressable.
2026-10-03 16:14:43 +08:00
sganggs 7188e0af89 feedback1 draft-info: the strategy draft shows the briefing's disabled bonds and banned operators again (GitHub issue #8 item 1)
One component, public/js/ui/matchInfo.js: matchInfoModel (the drawn set D and
the mode's inactive bonds via disabledBondSets, the briefing's bond order,
banned operators by tier, bannedPerBond) and the briefing's bond rows, legend
and banned-operator grid. The briefing renders it; the band draft opens it
read-only in a dialog (查看禁用盟约与干员 under the order list; 关闭, a tap
outside or Esc close it; its footer repeats the turn and the countdown; a turn
change closes it, the end of the draft unmounts it); the in-game 本局信息 tab
reads the same model, so its banned operators are listed by tier too. In the
dialog every size has a px floor, so phones keep readable text and a
scrollable body.

Tests: test/ui/match-info.test.js; opt-in test/ui/match-info.e2e.test.js
(SP_E2E=1: solo 标准 on desktop, co-op 绝境 with a desktop and a phone).
2026-10-03 16:08:32 +08:00
sganggs da7960261a feedback1 gaps: the strategy draft marks a band built around a switched-off bond 本局禁用
A band whose bondIds meet the mode's inactive bonds (gameLogic bandOffBonds,
the same field and rule as the bot) gets a 本局禁用 tag on its card and, in
the detail pane, "本局禁用【拉特兰】盟约,此策略效果可能无法发挥" with the bond
struck through. It stays selectable. In 标准 that is 潘格尼尼, 克莱门莎 and
玛恩纳; no band is marked in the other modes. A test pins the client mark to
the server's exclusion in every mode; the headless check covers the draft
at 1920x1080 and 844x390. DESIGN §21.26, META and the CHANGELOG say so.
2026-10-03 15:56:50 +08:00
sganggs 016fdb3804 feedback1 gaps: 变形同构体 lists its pairings; the bond popup explains 调和's +1
The 变形同构体 item card gets its 天赋 list (gameLogic morphPairings, from
the same giveBondId the server counts with): one line per bond with the
items that pair with it, 本局禁用 marked, and on a wearer's card the pairing
it wears highlighted. A bond item's card says which bond it gives a
变形同构体 wearer.

computeBonds marks a core bond state whose count holds 调和's +1
(harmony: 1) and both bond views send it. The popup reads it: 在场 n
(含调和 +1) and a 调和 row naming the 调和 operators on that board, for
the own strip and a teammate's; the strip and chip titles say it too.
The mock harness gets the funny / morph / harmony variants.
2026-10-03 15:07:14 +08:00
sganggs f213347ff2 feedback1 integrate: WV a knocked-out operator keeps its tile and redeploys there; 突袭 never lands on it 2026-10-03 13:36:40 +08:00
T1ipoca 15cceeb63a fix: set crossOrigin on new Image() loads in assets.js and guide.js
When /assets/ is served from a separate origin (CDN/object storage),
images loaded via new Image() are not CORS-approved, tainting canvases
and breaking WebGL textures (empty map, white 3D board).
2026-10-03 12:01:39 +08:00
sganggs 14e292f491 feedback1 integrate: hidden-tab and catch-up events keep their own game time
A catch-up frame or a hidden-tab step drains its events every EV_SLICE (15) ticks and each
batch is stamped with that game time; the held backlog is emitted batched by the time it was
drained at. The render engine then sees a late form fx as late and skips a change clip that
would already have ended (a 转译基底·α no longer replays A_Die_C 16 s after its change).
2026-10-03 11:52:52 +08:00
sganggs f142012033 feedback1 integrate: WB follow-up - bounty lists, 机密商店 and 战术决策 from 66 official screenshots (22 matches)
Merges the 7 WB commits after the first WB merge (d1f8a49..2cb84bd): R3 one of 10 fixed
sets (9 seen), R9 one of 6 boss groups picked by the matches they came in, R11 one of the
7 seen lists of 7; R11 families 14 / 4 / 4; the 机密商店 and the 战术决策 can offer the
same card twice (R11 shop: two VI, at least one V and one 盟约之币). data/choices.json
rebuilt with tools/build-data.mjs --offline (identical to the branch's). The tactic bot
test uses a real seat (the merged bot scores tactic cards on the player's bonds).
DESIGN §21.2 / §7 / §21.20 and CHANGELOG describe the 22-match model.
2026-10-03 11:27:46 +08:00
sganggs 67e862d2b3 feedback1 WB: 战术决策 drawn with replacement like the 4 official drafts; R11 ally cards weighted by the screenshots
The user: "战术决策也按官方改成可以重复吧". The 4 official 战术决策 (R11 of
matches 7, 9, 18 and 20) show six cards each; match 7 offers 补给 twice.

- Every 战术决策 card is drawn on its own (with replacement), so the same
  card can come twice. choices.js tacticDraftCards / tacticCard.
- R11 (绝境 / 终极, the round of the screenshots; choices.json tacticDraft,
  build-data TACTIC_DRAFT): only the ally cards, weighted 1 + the official
  cards each showed on. All 24 official cards are ally cards (no 排斥 /
  责罚 / 裁决, no terrain card: about 0.04 % for the previous draw) and
  列装 / 财富 / 补给 / 整备 / 升华 made 12 of them (uniform: about 4.6).
  Other rounds (标准 / 险境, no screenshot) keep every card, uniform, with
  replacement too. The weights and the R11 terrain exclusion are assumed.
- The header is the official "进行协同调整,做好迎战准备。".
- Identical cards are separate cards: own index, own object; a pick
  applies its card once and leaves the twin pickable; two picks of a team
  card stack. Match / bot / overlay already go by index.
- Tests: official drafts vs data, generated R11 / solo / earlier rounds,
  a seeded draft with 补给 twice, co-op and solo E2E picks of twins, the
  bot, the overlay, and a headless-Chrome render (game-mock variant=tactic
  is now the official match 7 draft). Tests that drive given tactic cards
  lay them out explicitly. The 奥术 Final Assault test takes the first of
  a few seeds whose bots pair two 奥术 players (the draws moved seed 12).
2026-10-03 09:10:39 +08:00
sganggs 4bab58e508 feedback1 integrate: a form fx handed out late skips a change clip that would already have ended; browser check stalls then lets the clips catch up 2026-10-03 08:36:16 +08:00
sganggs 0a15c6e41d feedback1 integrate: ticker lines by broadcast priority; AI 托管 keeps a human's items out of temp
- the strip queues by the official broadcast priority (BOSS_HIT 30 > CHAR_DAMAGE 20 > SHOP_LEVEL 11 > ...),
  match-flow notices at 25, never cutting the line on screen short
- on a human seat under AI 托管 an item left in temp with a full hand gets a hand slot (a bench operator sold)
2026-10-03 07:57:28 +08:00
sganggs d1f8a49829 feedback1 WB: bounty drafts and the 机密商店 from 66 official screenshots (22 matches)
Bounty drafts: every 悬赏决策 event is a fixed card list and the draft shows
6 different cards of it, drawn with weight 1 + the official drafts of its
group the card showed in.
- R3: 9 of the 10 fixed sets seen (two new: 20_1 + 20_5, and one with 17_6);
  3 x I + 2 x II + 1 x III in 22 of 22. The unseen 10th set is built by a
  rule whose III is 10_6 or 20_6, the only two-battle cards no draft showed.
- R9: 6 groups of 9 cards, one per bossInitial event. The 鼠王 group came in
  14 of 22 matches (every grey-board match among them), so groups are picked
  by the matches they came in. Named bosses no longer always come together.
- R11: lists of 7 cards, the draft leaves out one (matches 1 / 6 / 21 / 22
  leave out four different cards of one list); 7 of 15 lists seen, the rest
  and the 4 partial lists' 7th cards built by rule. Families 14 / 4 / 4.

机密商店 (the user: "机密商店按官方改成可以重复吧"): choices.json shopDraft,
six slots drawn with replacement - VI, VI, V, 盟约之币 and twice
V / IV / III / 盟约之币, items weighted by the official cards they showed on.
A repeated item now comes in about 61 % of shops (official 3 of 4). Two
identical cards stay two cards (picks by index): E2E, overlay and a
headless-Chrome test (game-mock ?variant=shop, the official match 8 shop).
2026-10-03 07:42:20 +08:00
sganggs 4e68100065 feedback1 integrate: form fx survive the render engine's stale-event drop; hidden-tab backlog compacted and flushed when a finished battle is shown; same-field re-entry buffered
- render/interp.js isCosmeticEvent: an fx with a form is state, never dropped as stale nor shed from a full queue;
  a late one switches the model without its telegraph, its closing clip shortened (render/app.js)
- battle/runner.js: a backlog past HELD_MAX keeps only the last status / skill toggle per unit; a battle that ended
  while the tab was hidden delivers its backlog and last snapshot when the tab is shown
- screens/game.js: a new field meta for the field on screen buffers its frames until the view re-enters it
- browser test stalls the main thread (blocking 1 s long tasks); Node tests drive the runner into the render buffer
2026-10-03 07:30:52 +08:00
sganggs 8de9002d1a feedback1f WV: the client draws a knocked-out operator on the tile it lies on
render/interp.js keeps the body tile of a b.snap `down` entry (row, col; only
when both are integers, so a 4-element entry is unchanged) and
render/units.js setDown moves the knocked-down view and its ring there: an
operator that fell on another piece's home lies on its own home (PRTS
卫戍协议/帮助 "…尝试返回其自身的初始位置"), and a view built from the unit's
deploy info (a field joined mid-battle) no longer stays on its first tile.

Tests: test/render/feedback1f-down-tile.test.js (fake PIXI, the sim's own
snapshot); opt-in test/render/feedback1f-down-tile.browser.test.js (real sim
frames in headless Chrome: drawn, picked and redeployed on its own home).
2026-10-03 07:16:34 +08:00
sganggs fcbccd4a32 feedback1 integrate: WR 阵法术师 / 轰击术师 attacks hit every enemy in range
# Conflicts:
#	docs/SIM.md
2026-10-03 07:04:07 +08:00
sganggs 313db2f55f feedback1 integrate: WP live skill range on the card; 烛煌 S3 target + 1.7 splash; 信仰搅拌机 S3 ignores 攻击距离 2026-10-03 07:00:41 +08:00
sganggs ff0f8d0211 feedback1 integrate: WK bond popup and card chips include 变形同构体 wearers
# Conflicts:
#	docs/SIM.md
#	public/js/ui/bondStrip.js
#	public/js/ui/detailPanel.js
#	server/sim/snapshot.js
2026-10-03 06:56:27 +08:00
sganggs c59b569dc7 feedback1 integrate: WJ BOSS_HIT share per boss round; stale-round ticker lines dropped 2026-10-03 06:54:47 +08:00
sganggs 1041b6ed7e feedback1 integrate: WG 奥术 shown 本局禁用 where the mode disables it; returned equipment auto-merges
# Conflicts:
#	public/js/ui/shopBar.js
2026-10-03 06:53:18 +08:00
sganggs 4b15919185 feedback1 integrate: WN 灼热/炽焰源石虫 models (local overlay, tinted alias); 暴鸰 bomb drop
# Conflicts:
#	docs/SIM.md
#	public/js/render/app.js
#	public/js/render/spine.js
#	public/js/render/units.js
#	server/sim/content/enemies.js
#	server/sim/snapshot.js
2026-10-03 06:45:59 +08:00
sganggs b1644f5ad7 feedback1 integrate: WC 深水区 refuses deployment; tactical points only inside the summoner's attack range
# Conflicts:
#	server/match/bot.js
2026-10-03 06:35:09 +08:00
sganggs 3328dedea2 feedback1 integrate: WD 转译基底 transforms, 逐火 embers beatable, knock-out forms kept by the client
# Conflicts:
#	docs/PLAYING.md
2026-10-03 06:34:25 +08:00
sganggs a5e78ee73b feedback1 integrate: WA per-copy 拉普兰德 refresh counter; 突变细胞 reusable 2026-10-03 06:32:26 +08:00
sganggs a657f809f1 feedback1e WP: review round 3 — 烛煌 S3 last bolt keeps the burst bonus, splash fx; prep overlay and wheel show the deployed range
- 烛煌 S3: the burn-burst bonus is gated on the attack's own isSkill (captured when the bolt was fired), not on the live
  skill, so the last bullet (it lands after end('ammo')) and bolts in flight when the skill ends early still carry it.
- 烛煌 S3: every landed bolt emits fx 'splash' (r 1.7, burn) at the main target, so the splash shows on screen.
- shared/loadoutRecord.js attackRangeGrid: the range a unit is deployed with — a selected passive range skill
  (引星棘刺 S3 3-9) and the 特性's permanent 攻击距离 (信仰搅拌机 SPT-Y +1; not 空弦 ISW-A's 集成战略-only one) —
  so the board overlay, the deploy wheel and the card agree with the prep live range. extendedGrid moves there
  (re-exported by targeting.js).
- runner.js header: unitStatsEntry carries the ally's live range.
2026-10-03 06:25:12 +08:00
sganggs a703800386 feedback1d WN: the web alias of 灼热/炽焰源石虫 is drawn tinted toward their own colours; bundle step documented 2026-10-03 05:55:29 +08:00
sganggs 5963a40d2d feedback1e WP: review fixes — 信仰搅拌机 S3 ignores 攻击距离, bounded range mini-map
- 信仰搅拌机 S3 退休前布道 attacks / counters on 3-13 exactly: SPT-Y's 攻击距离+1
  does not reach it (PRTS 技能3 备注 "此技能的攻击范围不受“攻击距离”属性影响";
  PRTS 修正 of the module text "(部分技能不受此影响)"). New SkillSpec flag
  targeting.noRangeExtend, read by Battle._refreshRange; S1 / S2 keep the +1.
- The detail card's 攻击范围 draws a grid larger than its box (远牙 S3's
  21-tile line) with smaller cells in the box's own space (rangeGridStyle,
  RANGE_FIT 6 columns × 7 rows), so the live stats beside it stay readable.
- 荒芜拉普兰德 S1's whole-field grid only selects targets (no rangeId, no 攻击范围
  text): targeting.showOwnRange keeps her 3-1 on the card.
- 烛煌 S3's bonus on burning enemies is dealt before the attack's damage
  (备注 "于攻击造成伤害前判定元素爆发并造成元素伤害"), main and splash.
- liveRangeGrid is the grid itself when nothing extends it (no copy per refresh).
- Audit test: 攻击距离加长 / 缩短 (深巡 S2, 山 S2) and every module of the loadout;
  real BattleSpec for 信仰搅拌机 SPT-Y.
2026-10-03 05:46:04 +08:00
sganggs f3a73fec6b feedback1e WR: 卡涅利安 charged S1 never attacks, S3 mark before the damage; review fixes
Review of the E3 fix (阵法术师 / 轰击术师 strike every enemy in range):

- 卡涅利安 S1 沙暴守卫 charged: PRTS 备注 "应用蓄力时:应用技能未开启时的特性"
  keeps the whole skill-off trait in force, 不攻击 included. A kit trait
  canAttack now stops her attacks while a charged S1 runs; the guard stays.
  The E3 test casts S1 uncharged and a new test pins both casts.
- 卡涅利安 S3 食噬之印 charged: the mark stacks before the attack's damage
  (PRTS 备注 "于攻击造成伤害前生效"): x1.2 on the first hit, x2.0 from the 5th
  (was one attack late). One mark per enemy: another 卡涅利安 only adds
  stacks, the bonus stays the setter's (PRTS 备注 popup).
- rangeAoe is applied after every override (kit trait included) and sets
  allInRange itself; SUB.phalanx / blastcaster carry rangeAoe only.
- 流形 copies (tokens.js and the 缪尔赛思 kit) turn a copied 'beam' into a
  plain bolt: the copy takes no attack shape.
- fx.js: the dead blastcaster shell colour is gone (and its test).
- SIM.md / comments cite PRTS 溅射半径一览 (no splash row for these
  branches), note that stealthed enemies are not struck unless revealed or
  blocked, and list the table's other radii as open deviations.
2026-10-03 05:38:06 +08:00
sganggs 04634f5bf7 feedback1d WN: the local-client slug models are an optional overlay; the manifest never depends on the extraction
data/assets.json pointed 灼热源石虫 / 炽焰源石虫 at /assets/local/ files that only exist
where tools/local-extract ran, with no fallback: without the extraction the
asset tests failed, setup re-ran fetch-assets (rewriting the tracked manifest)
and the slugs drew as icon diamonds.

- The web model stays the 源石虫 alias (spine + spineAliasOf). The official
  model is enemies[id].spineLocal: file names in the data/local-assets.json
  group spine/enemy/<id> plus the parsed metadata, from the committed
  tools/assets/local-enemy-spines.json (fetch-assets --local-spines refreshes
  it from the extracted files, read only). The manifest is byte-identical with
  or without the extraction and has no /assets/local/ URL.
- Client: assets.js spineEntry uses spineLocal only when the local manifest
  lists every file (createFieldView awaits assets.local() with the manifest);
  UnitView loads the web model when the local one fails.
- extract.py writes the atlas with size: / pma: true itself (the same text as
  atlas.mjs normalizeAtlas), so the extraction is usable without a fetch pass.
- setup notes when an older extraction lacks the enemy models.
2026-10-03 05:18:31 +08:00
sganggs 8b0e672bb8 feedback1e WP: live attack range on the battle card; 烛煌 S3 splash 1.7
Community report "干员烛煌开启3技能时候攻击范围不会变". The sim already attacked
with S3's 4-11 while it ran (real matches, and every attack-range change of
the mode); what stayed the same was the battle detail card: its 攻击范围
mini-map kept the base 3-1 grid while the live stats beside it moved.

- Battle._refreshRange keeps the relative grid behind rangeKeys as
  unit.liveRangeGrid (targeting.js extendedGrid: rangeExtend grown on);
  shared/protocol.js unitStatsEntry carries it as `range`; the detail card
  draws it (cardRangeGrid) in battle and in the prep preview, and names a
  whole-field range (纯烬艾雅法拉 S3) 全场 instead of drawing it.
- 烛煌 S3 "攻击变为群体攻击" is one target + a 1.7 splash (PRTS 技能3 备注
  "攻击溅射半径1.7"), not every enemy inside 4-11; the burst bonus hits
  every enemy of the attack; a burn burst's +2 ammo stops at the skill's
  ammo ("补充后的弹药数量无法超过上限").
- Tests: test/sim/feedback1e-skillrange.test.js (S3 range, splash, ammo
  cap, live grid, the audit of every attack-range change, a real spec),
  test/ui/feedback1e-range.test.js (the card).
2026-10-03 05:03:07 +08:00
sganggs 27181d88bd feedback1e WR: 阵法术师 / 轰击术师 strike every enemy in range (卡涅利安 E3)
Community report E3 "卡涅利安的攻击不是真群攻" was real: the phalanx trait
"技能开启时攻击造成群体法术伤害" was read as one bolt at the priority target
plus a 1.1-tile splash, so spread enemies took one hit per attack (act2 m01,
round 10: 2.3 of 12.4 enemies on her range per attack, never all).

Officially a 阵法术师 attack hits every enemy inside the attack range at
once, the same damage near and far (Arknights Terra Wiki, Phalanx Caster;
PRTS 林 S3 note; PRTS 作战机制 AOE), and so does the 轰击术师 line
(Terra Wiki, Blast Caster; PRTS 作战机制: 伊芙利特's 炎爆 is a range-locked
AoE). The 扩散术师 keep their 1.1-tile splash around the target.

- professions.js: phalanx and blastcaster get allInRange + rangeAoe
  (instant 'beam' hits, no projectile) instead of the 1.1 splash.
- 卡涅利安 S3 食噬之印: ATK climbs in 1 s steps to the full bonus at 20 s
  (PRTS note) instead of continuously over the 21 s duration.
- fx.js: phalanx / blastcaster leave the splash-ring list.
- Tests: real battles counting damaged enemies per attack for every
  phalanx skill, both blast casters, a splash-caster guard, a real stage
  and wave, the S3 ramp; opt-in headless-Chrome check of the strikes.
- SIM.md profession rows and kit comments updated.
2026-10-03 04:59:08 +08:00
sganggs 2591b8638e feedback1 WD: form changes survive the client's catch-up frames, hidden tab and pre-entry buffer
Every setForm fx now carries 'form' (shared/protocol.js fxForm). The runner keeps
these fx in catch-up frames (keepsState), holds the state-bearing events of the
battle on screen while the tab is hidden and delivers them with the first frame
back (re-entering from the field meta past HELD_MAX); screens/game.js buffers
them before a field is entered. A husk beaten while its stand-up clip plays dies
on the husk's clip. 幽灵 form cited from PRTS; 特战术师 flyer question recorded.
2026-10-03 04:27:24 +08:00
sganggs cc57afa8c4 feedback1d WN: a field opened after 暴鸰's drop draws it without its bomb (UnitInfo.form)
The bomb-less mode lived only in the client that saw the fx 'phase' event. UnitInfo now
carries an enemy's recorded mode (unit.form, set by kitBombd at the release), and the
renderer keeps it on the unit info, so a field watched or rejoined later starts on the
*_2 clips.
2026-10-03 04:22:36 +08:00
sganggs 901d5b9613 feedback1d WN: 暴鸰 drops its bomb as a projectile and flies on without it (D4)
The drone triggered its one bomb, but the damage and the blast landed in the trigger tick
while the model kept the bomb hanging under it for good. Official (PRTS 暴鸰; the client's
battle prefab enemy_1040_bombd and projectile_bombd): the cast plays the Attack clip, the bomb
leaves on its OnAttack event (0.267 s), flies to the target at 5 tiles/s and explodes on it
and the 8 tiles around; the drone switches to its bomb-less clips and speeds up.

Sim (kitBombd): release after BOMBD_RELEASE with an 'atk' event of kind 'droneBomb' and fx
'phase' {kind: 'bombed'}, a homing projectile (PROJECTILE_SPEEDS.droneBomb 5) whose arrival
deals the damage, then the speed buff. Render: FORMS.enemy_1040_bombd.bombed (*_2 clips),
PROJ.droneBomb (a falling shell), a one-off cast plays the attack clip once at its own
speed instead of the drone's 5 s attack rhythm, no puff for the silent mode change.
2026-10-03 04:21:19 +08:00
sganggs e1ce0316dd feedback1 WD: late views keep the form in the client, 重生 clears statuses, blocked 隐匿 drawn solid
- render/app.js: the views' unit info is built by the exported renderInfo(UnitInfo), which now keeps `form`;
  addInfo dropped it, so a view built from fieldMeta (a teammate's field watched later, 联防 observers, a
  reconnect) still drew the first form. Tested through renderInfo (fake PIXI) and the real enterBattle(meta)
  path in headless Chrome (opt-in).
- content/enemies.js: rebirthCleanse at every 重生 (reborn, husk, statue): operator-applied buffs and
  source-less statuses go, own talents / enemy-given buffs / field state stay (PRTS 特殊机制 §重生). A 逐火
  knocked out while feared is no longer an unblockable ember.
- snapshot.js: an enemy's stealth bit only while its 隐匿 is on (not blocked, not revealed).
- Docs: area damage reaching an unblocked 隐匿 enemy is documented as an engine deviation (PRTS 作战机制
  §AOE伤害判定), not as the rule.
2026-10-03 03:44:17 +08:00
sganggs 93afe2ccf2 feedback1c WJ: ticker queue helpers; a newer leader-damage line replaces the older one
Review follow-up for the Hidden Core broadcast fix. The strip's queue rules are
now pure, exported helpers (tickerSupersedes, enqueueTickerLines,
pruneTickerLines, nextTickerLine) with unit tests across a round 14 -> 15
change, instead of source regex checks only.

A player's newer BOSS_HIT line of the same round replaces their older one,
queued or on screen (it names a higher threshold), so a burst finish shows its
highest milestone before the round ends and the last round's lines are dropped.
Lines now carry playerId from main.js. The solo match test is labelled 绝境
(HARD), the difficulty it runs.
2026-10-03 03:16:44 +08:00
sganggs 695ece2653 feedback1b WG: review fixes - off popup without 当前效果, destroyPiece merge test, 奥术 refresh noted
- The popup of a bond the mode never activates no longer shows the 当前效果
  block (its +20 % / +68 % promised an effect 本局禁用 denies); the bond
  text stays. The popup test asserts it.
- ctx.destroyPiece's auto-merge of returned equipment has its own test
  (constructed pair; fails without the call).
- SIM.md and the 奥术 header: an earlier PRTS revision (oldid 386936) forbade
  a unit re-applying while its own instance lasts; an equal hit here
  refreshes it - recorded as a known [ASSUMED] deviation, slightly stronger.
2026-10-03 03:08:03 +08:00
sganggs 5c23eeb804 feedback1 WD: forms reach late views, stable enemy shapes, review fixes
- Every form change goes through content setForm(): the unit keeps it (e.form)
  and UnitInfo publishes it, so a view built mid-battle from fieldMeta (a
  watched teammate's field, 联防 observers, a reconnect) starts in the
  current form instead of the first-form model.
- Enemy profile (dmgType) and Unit moving / form are initialised at spawn:
  one object shape for the sim's hot loop (the boss-field bench is back at
  the base speed).
- 转译基底·α: an HP loss cannot knock out its original form (no death clip).
- 假想敌:再生: 1 s 重生 and walking 傀儡 cited from PRTS; shields within 1.8
  as the 再生状态 begins.
- Renderer: a 重生's closing clip (and the ember's stand-up clip) is timed
  from the fx dur to end with it, so the next form attacks on its own clips.
- Docs: ASSETS FORMS list, SIM form fx, PLAYING 隐匿 wording.
2026-10-03 03:02:46 +08:00
sganggs b9bbf3a040 feedback1c WK: a 同构 row opens the wearer's card with its pair
Review follow-up. A teammate's card showed the dashed 同构 chip but not the
items behind it, and the card a bond popup's 同构 row opened was the plain
record card, without the chip.

- gameLogic.bondMembers: a 变形同构体 row carries the wearer's item ids.
- BondPopup passes them to onMember; the screen hands them to the card
  ({ kind: 'chess', id, owner, items }), resolveDetail turns them into
  unitItems.
- ChessDetail: a card without an own piece lists the carried items read-only
  under 装备 (a teammate's unit, the card a 同构 row opens).
- META: the card side, and the operator-talent checks that still read the
  record's bonds [ASSUMED].
2026-10-03 02:52:38 +08:00
sganggs 60ed4fdab9 feedback1 WC: tactician summons never left out of range with a full hand; source fixes
Review follow-up to the water / tactical point change.

- Re-orienting 伺夜 / 缪尔赛思 in place while hand and temp are full could leave
  a placed 狼群 / 流形 outside the new range (it had nowhere to go and stayed
  put). The re-orientation is now refused with HAND_FULL when a summon it
  would leave out has no stack and no free slot. On the other paths
  (promotion, an owner moved with no room) such a summon leaves the board and
  its stack comes back at the next round start (grantTokensFor), so no
  out-of-range placement reaches the battle.
- Citation corrected: the 深水区 rule comes from the PRTS page 深水区 (地形信息
  tile_deepsea: 部署类型 全部位, 地形机制 "拒绝部署(待补充)"), corroborated by
  PRTS 作战机制 (地形标记 AdvancedBuildableMask lists 深水). There is no PRTS
  page 地形.
- grid.js: the tie-break note now says what changed on 战场#08 (no gate
  route; a few off-route smoothed steps of the boss field go around the water).
- Documented the known limit of the inactive act1 m05: its 特制水上平台 tiles
  are deployable in the prep's deploy map only; the sim does not model the
  canoes and keeps those tiles non-standable.
- gameLogic.summonRange reuses facing.js rangeTiles.
2026-10-03 02:46:07 +08:00
sganggs 6e0c26af9e feedback1 WB: bounty-half evidence stated as a trend with its counter-evidence; queued free offers counted on the pill and header
- tools/build-data.mjs bountyDraftHalf: exact faction-series counts (12 of 18 two-battle cards bring first-half
  enemies, 5 outside the wave tables, enemyeffect_12_4 a second-half attachment), base-HP gradient, the user's
  two-battle recall; counter-evidence (假想敌 named enemyInitial_*, the unread NGA R3 guide); the split marked
  [ASSUMED] with its flip; data unchanged
- server/match/choices.js, docs/META.md, docs/DATA.md: the split marked [ASSUMED]
- m.private shop.rewardOffer.queued: offers waiting behind the shown one; the header says 之后还有 N 项 and the
  reminder pill +N (a 定向投放 behind a promotion reward put off)
- tests: corrected headers, the stale bountyTiers fixture dropped, queued checks (unit + opt-in e2e on desktop
  and 756x366)
2026-10-03 02:38:42 +08:00
sganggs b4fa21a0a6 feedback1b WG: 奥术 re-measured; bonds the mode never activates read 本局禁用
Player report after 0.1.0: "奥术盟约不生效". Measured on a real 险境 battle
(Match._normalOpts) and the same battle from its BattleSpec (browser path):
the bond works - member arts hits debuff the target x(1.2 + 0.01*L) for 3 s,
later arts hits land multiplied, the 3-member tier gives x1.4 below 50 % HP,
in-battle layer gains apply live, browser = server.

What a player sees instead: 标准模拟 switches 奥术 off (official
inactiveBondIdList, with 9 other bonds) while 深靛 洛洛 阿罗玛 夕 圣聆初雪 stay in
the pool through their other bond; their cards showed 奥术 like any bond and
the detail chip read "0/2 未激活" with three deployed. Shop / reward cards,
the detail card's bond chips and the bond popup now mark such a bond
本局禁用 (gameLogic modeOffBonds over config.modes[modeId].inactiveBondIds).

The PRTS 盟约记录 奥术 note (one instance per unit and target) is documented
next to the one-effective-instance rule it fits (SIM.md, bond header).
2026-10-03 02:31:35 +08:00
sganggs 0c898bb524 feedback1c WK: 变形同构体 wearers in the bond popup's members and on their card
Player report: with 变形同构体 and the matching bond item the wearer gets the
bond's effect, but the bond's member count leaves the converted operator out.

The count that activates the bond already included the wearer on every server
path (bondsMeta.pieceBonds: prep count, views, battle input; support.unitBonds:
the battle). The client did not: the bond popup's member list (成员 x/y) and the
wearer's card read only the chess records' bonds, so the popup said 在场 3 but
成员 2/10 without the wearer, and the card had no chip for the bond.

- gameLogic.grantedBonds / pieceBondIds: the server's 变形同构体 rule on the
  client; bondMembers lists wearers (tagged 同构, one row per operator, on the
  board or owned), so 成员 x/y agrees with 在场.
- detailPanel: the card's chips include the granted bond (dashed, 同构).
- Teammates: UnitInfo carries an ally operator's item ids (sim unitInfo,
  Match.prepFieldMeta); ownerBoard / runner.ownerOps keep them.
- Tests: every pairing on real matches (prep, views, battle input, the real
  battle), bench vs board, half pairs, distinct members; the client rule
  against the server's; popup / card rendering.
2026-10-03 02:29:28 +08:00
sganggs 85d8bd40b4 feedback1 WA: return the Mutation Cell before summon cards; bots keep it
Review follow-ups for reports #1 and #4.

- transformChess: the returned equipment is stowed before the new operator's
  summon stack is granted (as in _mergeChess); when the transformation
  completes a merge, the carrier's equipment goes through _mergeChess, which
  also returns it before the elite's summons. A summon card no longer pushes
  the returned 突变细胞 into temp, where it would be lost at the deadline.
- bot: a 突变细胞 left in temp with a full hand gets a hand slot (sell the
  weakest single hand chess, else destroy the cheapest other hand item, else
  sell any hand chess) instead of being destroyed.
- 拉普兰德's per-piece counter key is module-prefixed; the re-bought copy
  case is marked [ASSUMED] in the code and docs/META.md.
- .dhint--rule gets a style; sources quote PRTS 卫戍协议/帮助 exactly
  ("在失去该干员(干员出售、销毁、合并等)…时自动卸除").
2026-10-03 02:28:39 +08:00
sganggs 7b1964707d feedback1c WJ: Hidden Core damage broadcasts count only the hidden leader
Player report: "隐藏boss还没打就出了造成50%伤害播报". The BOSS_HIT ticker
("{0}博士对敌方领袖造成的伤害超过20/50/80%!") divided the player's boss damage of
the whole match (stats.bossDamage, Final Assault + Hidden Core) by the hidden
leader's pool, so the Hidden Core's first hit already announced 50 % or 80 %.
The share is now the player's damage to the current round's pool
(SharedBossPool.byPlayer) over its size; 领袖伤害 on the result keeps both rounds.

The browser's ticker strip plays its queue 5.2 s per line, so a Final Assault
line could still play over the fresh hidden leader: a BOSS_HIT line is now
dropped once the round it came in is over (ui/ticker.js tickerLineLive; lines
carry their type and round from main.js).
2026-10-03 02:22:17 +08:00
sganggs 06be81f67e feedback1 WD: a form change clip plays out; browser check of the forms
- render/spine.js: no attack (wind-up or 'atk') cuts a form's change clip short;
  a knocked-out 逐火 no longer reports its last attack in the snapshot.
- test/render/feedback1-forms.browser.test.js (opt-in RENDER_E2E=1): the real
  sim in headless Chrome on 战场#01 — 转译基底·α A_* → A_Die_B → B_* → B_Die,
  a 深池逐火战士 knocked out in front of its blocker: Die → the 隐匿 ember on
  Idle_2, beaten → Die_2.
- PLAYING.md: the 余烬 and 转译基底 rules for players.
2026-10-03 02:07:59 +08:00