feedback3: merge WJ — 高台 only for elite 歌蕾蒂娅 with HOK-Y, live prep watch, silenced 折射, grant toasts, emote timeout glyph
This commit is contained in:
commit
c9dd2a6392
41 files changed
+700
-216
No files matched your search
+1
-1
@@ -150,7 +150,7 @@ Top level: `{ season, seasonName, modes, economy, lpCapPerRound, bossOvertimeAft
|
||||
| `name`, `appellation` | `"隐现"`, `"Insider"` | |
|
||||
| `rarity` | `5` | stars 1–6 |
|
||||
| `profession`, `subProfessionId`, `subProfessionName`, `position` | `"SNIPER"`, `"fastshot"`, `"速射手"`, `"RANGED"` | |
|
||||
| `placement` | `"all"` | only on a MELEE chess whose branch trait (the character's own trait text, no module) reads 可以放置于远程位 — 钩索师 歌蕾蒂娅 / 崖心, 推击手 见行者, normal and elite: the prep placement also allows the ranged (高台) tiles (`server/match/board.js positionClass`); `position` stays MELEE for the battle (DESIGN §22.6). Absent otherwise |
|
||||
| `placement` | | not stored. A MELEE chess may stand on a 高台 only when it is elite 歌蕾蒂娅 (`char_474_glady`, `isGolden`) carrying HOK-Y 淡金坠饰 (`uniequip_003_glady`), decided at place time from the loadout (`shared/highGround.js`, `board.js placeClass`). The trait 「可以放置于远程位」 is not read. Owner's decision 2026-10-04; §22.6's `placement: "all"` is gone. `position` stays MELEE for the battle |
|
||||
| `nationId` | `"laterano"` | |
|
||||
| `bonds[]` | `["lateranoShip","swiftShip"]` | bondIds (→ `bonds.json`) |
|
||||
| `garrisonIds[]` | `["garrison_16_b"]` | 特质 (→ `garrisons.json`); first = displayed trait |
|
||||
|
||||
+2
-2
@@ -131,7 +131,7 @@ Ownership rule for parallel agents: **only edit files assigned to you**; if you
|
||||
- **Partner display** cols 11–18 of rows 9–12 (the unite field uses them).
|
||||
- **Boss field**: rows 1–5; left half cols 2–10, right half cols 10–18.
|
||||
- Enemy preview pen rows 14–18 × cols 7–13 (row 16 empty): during prep the next round's enemies idle there (upper-gate enemies rows 17–18, lower-gate rows 14–15, ≤ 50 models, spawn-time order) — research 08 §4 / 09 §2.
|
||||
- Tile semantics come from `data/stages.json` legend: height (LOW/HIGH), buildable (ALL/MELEE/RANGED/NONE — the **effective** deploy type: the 深水区 `tile_deepsea` refuses deployment, NONE with the level's `buildableType` ALL kept, PRTS 深水区 地形信息 "拒绝部署(待补充)"; an active 特制水上平台 makes its tile deployable in the prep deploy map only, §21.3), ground-passable, fly-only, special terrain (mire, smog, deepsea, infection). The fenced tiles (围墙 `tile_fence_bound` / 围栏 `tile_fence`, legend `b`: LOW, buildable ALL, passable to flyers only) take units, which attack normally from there but block no ground enemy (PRTS 地形机制, §21.23). Melee chess may stand only on LOW tiles with buildable ALL/MELEE — except a branch whose own trait reads "可以放置于远程位" (钩索师 歌蕾蒂娅 / 崖心, 推击手 见行者: chess.json `placement` 'all'), which may use the ranged tiles too (the remake's reading, §22.6); ranged chess on ALL/RANGED **and** on LOW ALL/MELEE tiles ("所有行动内远程干员可部署在近战位"). Tokens follow their own `position`; a summon marked `ownerRange` (狼群, 流形: "只能部署在召唤者攻击范围内") goes only on a tile of its owner's attack range — the loadout grid rotated by the owner's facing around its tile (`PlayerState.summonRange`, §21.3).
|
||||
- Tile semantics come from `data/stages.json` legend: height (LOW/HIGH), buildable (ALL/MELEE/RANGED/NONE — the **effective** deploy type: the 深水区 `tile_deepsea` refuses deployment, NONE with the level's `buildableType` ALL kept, PRTS 深水区 地形信息 "拒绝部署(待补充)"; an active 特制水上平台 makes its tile deployable in the prep deploy map only, §21.3), ground-passable, fly-only, special terrain (mire, smog, deepsea, infection). The fenced tiles (围墙 `tile_fence_bound` / 围栏 `tile_fence`, legend `b`: LOW, buildable ALL, passable to flyers only) take units, which attack normally from there but block no ground enemy (PRTS 地形机制, §21.23). Melee chess may stand only on LOW tiles with buildable ALL/MELEE — except elite 歌蕾蒂娅 carrying module HOK-Y 淡金坠饰 (`uniequip_003_glady`), who may use the ranged tiles too (owner's decision 2026-10-04; the branch trait 「可以放置于远程位」 is not read, §22.6 reversed); ranged chess on ALL/RANGED **and** on LOW ALL/MELEE tiles ("所有行动内远程干员可部署在近战位"). Tokens follow their own `position`; a summon marked `ownerRange` (狼群, 流形: "只能部署在召唤者攻击范围内") goes only on a tile of its owner's attack range — the loadout grid rotated by the owner's facing around its tile (`PlayerState.summonRange`, §21.3).
|
||||
- **Facing (corrected, see research 09 §1.2):** like standard Arknights, every board piece has a direction `dir ∈ UP|RIGHT|DOWN|LEFT` chosen with the 4-direction deploy wheel after dropping it on a tile (also re-orientable in place); default `RIGHT`; persists across rounds. Range grid entries are `[dRow, dCol]` relative to facing RIGHT and are rotated: RIGHT `(dr,dc)`, UP `(dc,−dr)`, LEFT `(−dr,−dc)`, DOWN `(−dc,dr)` (row 0 = bottom); `rangeExtend` applies along +dCol before rotating — to a running skill's range too, unless that skill ignores 攻击距离 (`targeting.noRangeExtend`, 信仰搅拌机 S3, §21.16). The right-side Final Assault player is mirrored col `c→20−c` with RIGHT↔LEFT (UP/DOWN unchanged).
|
||||
- **Range test:** an enemy is inside a grid range if the tile containing it (`round(y), round(x)`) is one of the range tiles; a huge enemy (data `hitArea`: 巨型单位, a 4.95 × 2.95 rectangle moved 1.0 up) if any tile its hit rectangle overlaps is one (PRTS 作战机制 "巨型BOSS单位的每一个占据的格子都可以让其本身通过格子判定"; `sim/body.js`, §19.4). Radius ranges (enemies, auras, AoE) use Euclidean distance in tiles — to a huge enemy's rectangle [ASSUMED] — except splash around a struck target, a 中点判定 on positions (PRTS 作战机制 "中点判定…案例:阻挡,酒神1天赋的1.3溅射半径"). A ranged enemy's normal attack takes an ally whose collider (radius 0.25, PRTS 作战机制 §碰撞体积 "我方干员碰撞体积基本均为以0.25格为半径的圆形") touches its range circle: centre distance ≤ `rangeRadius` + 0.25 (`constants.js ALLY_COLLIDER_RADIUS`, `ai.js enemyAttack`; §20.4).
|
||||
- **Fields at runtime:** a `Battle` receives a **field rect** (rows/cols subset) and the full stage grid. Normal battles use rows 9–12 × cols 0–10; unite uses rows 9–12 × cols 0–20; boss uses rows 0–5 × cols 0–20 (solo boss uses the left half only). Pathfinding never leaves the rect.
|
||||
@@ -561,7 +561,7 @@ Audio: autochess BGM per phase, UI SFX (buy/sell/refresh/level/merge/ready/timer
|
||||
|
||||
**Solo pause (official `PauseUp` / `ResumeUp`; `Match.setPause`).** C→S `g.pause { on }`: solo matches only (co-op → `WRONG_PHASE 'co-op battles never pause'`), and `on: true` only while a battle runs (COMBAT / FINAL_ASSAULT / HIDDEN_CORE with a live field, not once the Final Assault is ending — else `WRONG_PHASE 'no battle running'`); `on: false` is always accepted. While `m.public.paused` is true everything of the battle is frozen: the field clock (`b.start elapsed`, the boss plausibility budgets and the overtime drain), the authority deadline and the server-run release timers, the boss clock, the HUD `deadline` / `overtimeAt` (shifted by the paused time on resume) and the server-run pacers (FieldRunner / HeadlessPacer skip their intervals); the browser's runner stops its local clock. In solo battles the top bar shows a 暂停 / 继续作战 button (`ui/hud.js PauseButton`, `ui/matchStatus.js pauseAvailable`; `Space` toggles it), a paused overlay offers 继续作战 / 放弃模拟, and the HUD clocks freeze at the pause moment. A disconnect or leave resumes (the server takes the field over — nobody is left to resume it); the battle phase ending drops the pause.
|
||||
|
||||
**Spectating (research 09 §3.1 / §6.3).** No live spectating while your own normal battle runs (`g.watch` → `WRONG_PHASE 'own battle running'`; the UI toasts "作战中无法查看队友"). After your own battle ends you see "⌛ 作战结束,等待队友完成作战" with each teammate's live progress (`m.public.fields[].progress`); tapping a teammate's avatar expands **前往查看** → `g.watch` → `b.start` (display replica fast-forwarded to the field clock); the own row shows **返回战场**. Prep: the same flow shows the teammate's board (`m.field` with `prep: true`, unchanged). 联防: every human receives the unite spec (helpers + observers). Final Assault: each human sees its own pair field; the other pair → `BAD_TARGET 'other group hidden'`. In 联防/FA fields the ‹ › pill switches the camera LEFT half / 全景 / RIGHT half ("你自己" / "👁 name" / "全景" / "无人在家"); there is **no** view switcher during normal combat. Eliminated players start each combat phase on the first field (auto-observe) and may watch any field.
|
||||
**Spectating (research 09 §3.1 / §6.3).** No live spectating while your own normal battle runs (`g.watch` → `WRONG_PHASE 'own battle running'`; the UI toasts "作战中无法查看队友"). After your own battle ends you see "⌛ 作战结束,等待队友完成作战" with each teammate's live progress (`m.public.fields[].progress`); tapping a teammate's avatar expands **前往查看** → `g.watch` → `b.start` (display replica fast-forwarded to the field clock); the own row shows **返回战场**. Prep: the same flow shows the teammate's board (`m.field` with `prep: true`) and sends it again when that board changes (GitHub #87). 联防: every human receives the unite spec (helpers + observers). Final Assault: each human sees its own pair field; the other pair → `BAD_TARGET 'other group hidden'`. In 联防/FA fields the ‹ › pill switches the camera LEFT half / 全景 / RIGHT half ("你自己" / "👁 name" / "全景" / "无人在家"); there is **no** view switcher during normal combat. Eliminated players start each combat phase on the first field (auto-observe) and may watch any field.
|
||||
|
||||
**Client runner.** `public/js/battle/runner.js` owns the local Battles: fixed-step clock at the battle speed (60 ticks per real second at 2×, at most `max(8, 4·speed)` ticks per frame, bounded fast-forward of ≤ 240 ticks per frame when far behind; a new battle is caught up silently before it is shown), feeds the existing renderer through the same `snapshot()`/`drainEvents()` wire formats every frame (`view.setLocalFeed` shrinks the interpolation buffer to ~2 frames), publishes the field meta (m.field shape + `local`, `battleId`, `players`, `sides`, `speed`) into `store.match.field` and its state into `store.match.battle` (with `leaks: { [fieldId]: counted leaks so far }` of every normal field it simulates and, while the 联防 field is on screen, `uniteLeft` per leaker (§20.6), authoritative or display replica — the settle rule's count, `/sim/spec.js battleProgress`; published in the frame a count changes: the live LP of §17.5), sends `b.progress`/`b.result` when authoritative (results retried once on timeout; a result lost with the socket — the request failed `DISCONNECTED` / `OFFLINE` or timed out twice — is kept and sent again when the session is back online and whenever a `b.start` still names that finished battle `authoritative: true`; the server answers a duplicate `ok` and changes nothing; a server refusal is final), follows `m.public.paused` (solo pause: every local clock stands still, resume shifts it by the paused time), handles `b.pool`/`b.end`, fast-forwards on reconnect/observe, and survives tab backgrounding (a 250 ms interval pump keeps authoritative battles on their clock while hidden; the server deadline + takeover cover extreme cases). Catch-up frames keep the state events and every enemy form fx (`keepsState`); while hidden, the battle on screen holds them for the first frame back (`hold`; past `HELD_MAX` the superseded status / skill toggles are dropped, `compactHeld`, and only a backlog still past it re-enters the view from the field meta), and a battle that ended while hidden delivers them when the tab is shown; a catch-up frame or a hidden step drains its events every `EV_SLICE` (15) ticks, each batch stamped with its own game time (`gt`), so a late form fx reaches the render engine as late as it is; the game screen's pre-entry buffer (`keepEarly`, also while a re-sent field meta re-enters the field on screen) and the render engine's event queue (`render/interp.js isCosmeticEvent`) never drop a form fx either (§21.4). Sim content errors are logged as console warnings (the server logs its own). The sim loader fetches the ten data files (one retry each) and fails when any is missing — a battle on partial data would report a plausible wrong result — so the next `b.start` retries and the server's deadline covers the field meanwhile. `public/js/battle/observe.js` holds the observing rules and labels.
|
||||
|
||||
|
||||
+5
-4
@@ -11,7 +11,8 @@ server/match/
|
||||
gamedata.js typed, defaulted view of data/*.json (config tunables with research defaults) + the balance layer
|
||||
(data/tuning.json, §3.1)
|
||||
pool.js SharedPool (copies per base chess, across players), per-match bans, copy-weighted rolls
|
||||
board.js placement legality from the stage legend on the deploy field (own board / boss half), slot helpers,
|
||||
board.js placement legality from the stage legend on the deploy field (own board / boss half); a 高台
|
||||
also takes elite 歌蕾蒂娅 with HOK-Y (shared/highGround.js), slot helpers,
|
||||
reading order (boardOrder), a merge's elite tile in deployment order (mergeTile)
|
||||
bondsMeta.js bond counting modes, tiers, 调和 / 独行 / 助力 / 绝技, layers
|
||||
effectsMeta.js MetaRegistry + EffectDispatcher + the handler ctx (this document, §2)
|
||||
@@ -212,7 +213,7 @@ no battle effect), it gets the settlement's `m.result`, and `handle()` answers o
|
||||
The rest of this section is the legacy server-run mode
|
||||
(`SP_COMBAT=server`):
|
||||
`g.watch { fieldId }`: any live field during COMBAT / 联防; while no battle field is up (PREP, drafts, SETTLE)
|
||||
`'n:<pid>'` returns a one-shot board view — during a battle phase an `'n:<pid>'` id must name a live field
|
||||
`'n:<pid>'` keeps the viewer scouting that board and pushes `prepFieldMeta` again when it changes (GitHub #87) — during a battle phase an `'n:<pid>'` id must name a live field
|
||||
(`BAD_TARGET 'no such field'` otherwise, and the viewer keeps its stream). In the
|
||||
最终攻势 / 隐秘核心 a player fighting in a boss field may only watch its own field ("两名参与者会处于同一个战场,但无法查看
|
||||
另一组队友的战场情况" → `BAD_TARGET 'other group hidden'`); eliminated / departed players spectate any field.
|
||||
@@ -709,8 +710,8 @@ same counts (its input's `bonds` come from `bondsView()`, PlayerState.battleInpu
|
||||
`ps.layers` (rules, `activatedLayers`) are untouched; SETTLE clears the pending gains as it adds them to `ps.layers`
|
||||
(once); the next round start clears them too.
|
||||
|
||||
`m.field` = `{ fieldId, kind, rect, stageId, units, live }`; during prep `g.watch 'n:<pid>'` returns a one-shot board
|
||||
view with `prep: true` (scouting a teammate).
|
||||
`m.field` = `{ fieldId, kind, rect, stageId, units, live }`; during prep `g.watch 'n:<pid>'` returns that board
|
||||
with `prep: true` and sends it again when the board changes (GitHub #87).
|
||||
|
||||
**`b.snap` / `b.ev` game time**: every frame is `{ t: '<type>', … }`, so the snapshot's game time (DESIGN `b.snap.t`)
|
||||
is sent as **`gt`** (game seconds); `b.ev` carries the same `gt`. The client reads `gt` (`render/interp.js frameTime`,
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@
|
||||
|
||||
## 4. 摆阵与朝向
|
||||
|
||||
- 从整备区把干员拖到棋盘:近战位 / 远程位高亮为可放置格。**钩索师和推击手**的特性写着「可以放置于远程位」,地面和高台都能放(本赛季卡池里只有歌蕾蒂娅,崖心、见行者是隐藏干员);站在高台上时照常攻击,但不阻挡敌人。**水里不能部署**:战场#08(涨潮控制)中间的那条水池(深水区)和官方一样拒绝部署,任何干员和召唤物都放不上去;突袭盟约的干员再部署、战术家的援军自动选战术点时也只会落在岸上。松手后出现**方向轮盘**,向上 / 右 / 下 / 左滑动,棋盘上会用橙色条纹预览旋转后的攻击范围,松手确认;松在中心或点「✕ 点击取消」取消。
|
||||
- 从整备区把干员拖到棋盘:近战位 / 远程位高亮为可放置格。**只有精锐歌蕾蒂娅、并且装备了模组 HOK-Y「淡金坠饰」,才能放到高台上**;崖心、见行者、没晋升的歌蕾蒂娅、换了别的模组或者不装备模组,都只能放在地面。站在高台上时照常攻击,但不阻挡敌人。**水里不能部署**:战场#08(涨潮控制)中间的那条水池(深水区)和官方一样拒绝部署,任何干员和召唤物都放不上去;突袭盟约的干员再部署、战术家的援军自动选战术点时也只会落在岸上。松手后出现**方向轮盘**,向上 / 右 / 下 / 左滑动,棋盘上会用橙色条纹预览旋转后的攻击范围,松手确认;松在中心或点「✕ 点击取消」取消。
|
||||
- 想只改朝向:把干员拖回它自己所在的格子再选方向。朝向会一直保留到下一回合。
|
||||
- **点选按地上的方格**:点哪个方格就选中站在那个方格上的单位,点空方格不选任何单位(点到后一格干员画出来的头部,算作点了后面那一格)。作战中友方同样按方格;敌人在格子之间走动,点它的身体或脚下附近(0.6 格内)即可,飞行敌人点它的身体。
|
||||
- 拖动时模型一直在指针 / 手指下(脚在指针下方约半格,鼠标和触屏一样),**指针所在的格子**就是落点并高亮;装备拖到哪个格子,就配发给那个格子上的干员;在商店栏上松手则放回原位。
|
||||
|
||||
@@ -1981,7 +1981,7 @@ Consequences for the current pool:
|
||||
- Tokens marked `DEFAULT` in `shopStateTokenDict` are these placeable pieces: 医疗探机, 诅咒娃娃, 狼群, 斯卡蒂的海嗣, 流形. `HIDDEN` tokens exist only in battle.
|
||||
- [ASSUMED] Summons do **not** use one of the 8 deploy slots, as in the base game. Keep this as a config flag.
|
||||
- **Battle start:** every board unit deploys for free, in order **从上到下>从左到右** (下半): down each column, the columns left to right (research 01 §4.3). In the boss round the order is mirrored for the right-side player. After that, knocked-out units redeploy automatically on their tile when the respawn timer is done and DP ≥ `cost` (DP starts at 10, +1/s, cap 99).
|
||||
- **Ranged units may stand on melee tiles** ("所有行动内远程干员可部署在近战位"). Melee units may **not** use ranged-only tiles (HIGH `h`) [ASSUMED standard] — except the branches whose own trait reads 可以放置于远程位 (钩索师 歌蕾蒂娅 / 崖心, 推击手 见行者; PRTS 新人入门 "可部署在高台和地面"). That line is the branch trait, not a 部署效果 like the Y-module 教官's talent "可以额外部署在远程位" (the 帮助: "携带Y模组的教官仍无法部署至高台位"), so it still applies in prep — the remake's reading [ASSUMED], GitHub issue #32 item 4, DESIGN §22.6. Maps: see 05.
|
||||
- **Ranged units may stand on melee tiles** ("所有行动内远程干员可部署在近战位"). Melee units may **not** use ranged-only tiles (HIGH `h`) — except elite 歌蕾蒂娅 carrying HOK-Y 淡金坠饰 (`uniequip_003_glady`). The branch trait 「可以放置于远程位」 (钩索师 / 推击手; PRTS 新人入门 "可部署在高台和地面") is on every variant and is **not** read (owner's decision 2026-10-04, reversing the §22.6 reading of GitHub #32 item 4). 崖心 has only HOK-X; 见行者, a normal record, any other module and no module stay on the ground. Maps: see 05.
|
||||
|
||||
### C3. Pool membership per match
|
||||
The per-match ban removes every visible chess whose bonds are **all** in the disabled set. The rule is verified; see 01 Addendum A2. Elites of banned chess are also unobtainable. Hidden chess (17) stay out of the shop as §1.2 says.
|
||||
|
||||
Reference in new issue
Block a user