From e846519fb06c64a35c8642b17e753d859bbe7936 Mon Sep 17 00:00:00 2001 From: sganggs Date: Sat, 3 Oct 2026 23:03:26 +0800 Subject: [PATCH] =?UTF-8?q?feedback2=20WF:=20docs=20for=20=E9=92=A9?= =?UTF-8?q?=E7=B4=A2=E5=B8=88=20/=20=E6=8E=A8=E5=87=BB=E6=89=8B=20on=20a?= =?UTF-8?q?=20=E9=AB=98=E5=8F=B0=20(DESIGN=20=C2=A722.6,=20=C2=A73,=20?= =?UTF-8?q?=C2=A76.6;=20DATA=20placement;=20PLAYING=20=C2=A74;=20research?= =?UTF-8?q?=2003=20C2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/DATA.md | 1 + docs/DESIGN.md | 15 +++++++++++---- docs/PLAYING.md | 2 +- docs/research/03-operators.md | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/docs/DATA.md b/docs/DATA.md index 9723da8c..6e428a75 100644 --- a/docs/DATA.md +++ b/docs/DATA.md @@ -150,6 +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 | | `nationId` | `"laterano"` | | | `bonds[]` | `["lateranoShip","swiftShip"]` | bondIds (→ `bonds.json`) | | `garrisonIds[]` | `["garrison_16_b"]` | 特质 (→ `garrisons.json`); first = displayed trait | diff --git a/docs/DESIGN.md b/docs/DESIGN.md index 41c932cb..73b4174e 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -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; 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 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). - **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. @@ -384,7 +384,7 @@ Per match: pick stage (weighted among the mode's `config.modes[m].stages`, weigh ### 6.6 AI players (bot.js) -Deterministic-ish heuristic player used for (a) AI teammates, (b) auto-play for disconnected humans (only auto-ready + auto-picks, not shopping, unless "AI 托管" is toggled), (c) tests. Strategy (§21.6): pick a band (weighted by starting LP; never one built around a bond the mode switches off — `gd.bandBondIds`, §21.26); each prep: take offers, sell dead bench weight, fill the board, complete affordable merges, level on the curve, then buy only merge progress / lineup upgrades worth more than the refreshes their price would buy (shop odds of completing held pairs), freeze for an unaffordable third copy (坎诺特 keeps 5 funds back); build around a committed focus core bond (a teammate's main bond on its strip counts against it; bonds the mode switches off never) + a second bond; value dealers by DPS vs the round's DEF / RES (an attack on every enemy in range counts double — 阵法术师 / 轰击术师), with the range the unit is deployed with; place by the exposure model + rehearsal on the server's deploy map (no 深水区; a tactician's 援军 within `PlayerState.summonRange`; `g.move` judges legality); items by effect (META §1.5: 突变细胞 on the least valuable normal single below 6阶, a cell left in temp gets a hand slot made for it, the operator its transformation gains is deployed by the next prep's lineup step like any owned unit — AI 托管 too; the buy loop's bench shed never sells a piece gained since the bot's last prep, §21.1); 机变 bounties by expected payout − expected LP loss over the offered cards; resolve temp — on a human seat under AI 托管 never by destroying an item while a bench operator can be sold for the slot —; ready. A bot's whole prep — shop decisions and layout planning (`botPrepBeginSteps`, 25–70 ms late in a 4-bot match), the layout rehearsal and `botPrepEndSteps` — runs in wall-clock slices of `botSliceMs` (8 ms) per scheduler callback on a real host (step generators that yield between whole actions, never with a transient board; the same actions in the same order, so decisions are unchanged; at once in virtual time). +Deterministic-ish heuristic player used for (a) AI teammates, (b) auto-play for disconnected humans (only auto-ready + auto-picks, not shopping, unless "AI 托管" is toggled), (c) tests. Strategy (§21.6): pick a band (weighted by starting LP; never one built around a bond the mode switches off — `gd.bandBondIds`, §21.26); each prep: take offers, sell dead bench weight, fill the board, complete affordable merges, level on the curve, then buy only merge progress / lineup upgrades worth more than the refreshes their price would buy (shop odds of completing held pairs), freeze for an unaffordable third copy (坎诺特 keeps 5 funds back); build around a committed focus core bond (a teammate's main bond on its strip counts against it; bonds the mode switches off never) + a second bond; value dealers by DPS vs the round's DEF / RES (an attack on every enemy in range counts double — 阵法术师 / 轰击术师), with the range the unit is deployed with; place by the exposure model + rehearsal on the server's deploy map (no 深水区; a tactician's 援军 within `PlayerState.summonRange`; a 钩索师 / 推击手 on the ground tiles, as a blocker — §22.6; `g.move` judges legality); items by effect (META §1.5: 突变细胞 on the least valuable normal single below 6阶, a cell left in temp gets a hand slot made for it, the operator its transformation gains is deployed by the next prep's lineup step like any owned unit — AI 托管 too; the buy loop's bench shed never sells a piece gained since the bot's last prep, §21.1); 机变 bounties by expected payout − expected LP loss over the offered cards; resolve temp — on a human seat under AI 托管 never by destroying an item while a bench operator can be sold for the slot —; ready. A bot's whole prep — shop decisions and layout planning (`botPrepBeginSteps`, 25–70 ms late in a 4-bot match), the layout rehearsal and `botPrepEndSteps` — runs in wall-clock slices of `botSliceMs` (8 ms) per scheduler callback on a real host (step generators that yield between whole actions, never with a transient board; the same actions in the same order, so decisions are unchanged; at once in virtual time). --- @@ -1487,6 +1487,13 @@ TBD-22.4 TBD-22.5 -### 22.6 钩索师 and 推击手 on 高台 (#32 item 4) +### 22.6 钩索师 and 推击手 on 高台 (#32 item 4) — `tools/build-data.mjs PLACE_ON_RANGED_RE / branchTraitText / validateAll`, chess.json `placement`, `match/board.js positionClass / basePositionClass`, `ui/gameLogic.js piecePosition`, `match/bot.js isBlocker / planLayoutSteps`, `tools/balance.mjs` -TBD-22.6 +- **Seen**: public issue #32 item 4 — "哥蕾蒂娅无法部署到高台". 0.1.1 refused every 高台 tile for her (server `BAD_TILE`; the client lit no 高台 and said 近战单位只能部署在地面), and the same for 崖心 (钩索师) and 见行者 (推击手), normal and elite. +- **Official**: the branch trait of both 钩索师 chess (歌蕾蒂娅 `chess_char_4_12`, 崖心 `chess_char_2_03`) reads 「技能可以使敌人产生位移\n可以放置于远程位」, the 推击手 见行者's (`chess_char_3_07`) 「同时攻击阻挡的所有敌人\n可以放置于远程位」 — character_table `description` (their `trait` is null: the branch's own text), position MELEE; act2autochess `charChessDataDict` sets only status, bonds and garrisons for them. PRTS 新人入门 (branch table): 钩索师 and 推击手 "可部署在高台和地面". PRTS 卫戍协议/帮助 §战斗部署: "所有行动内远程干员可部署在近战位", and 部署效果 do not apply in this placement — "携带Y模组的教官仍无法部署至高台位". That 教官 ability is a module talent ("可以额外部署在远程位", battle_equip_table uniequip_003_pallas / uniequip_002_doberm / uniequip_002_rdoc, blackboard `buildable_type` 2), a deploy effect; the 钩索师 / 推击手 line is the branch trait itself — no talent, no blackboard, and every module of the three keeps it (HOK-X, HOK-Y, PUS-X). No Y-module 教官 is in the pool (诗怀雅 has INS-X). No source states the 钩索师 case for 卫戍协议 in so many words: **the remake reads the branch trait as still applying** [ASSUMED]; the old "melee never on ranged-only tiles" was itself an assumption (research 03 C2). +- **Cause**: build-data copied position MELEE and nothing read 可以放置于远程位; `board.js positionClass` mapped MELEE to 'melee' (melee tiles only), so `PlayerState._legal` refused the 高台 (`g.move` → `BAD_TILE`), and the client mirror (`gameLogic.js piecePosition` / `tileAllows`) agreed. +- **Now**: build-data sets `placement: 'all'` on a chess whose branch trait without module (`branchTraitText`: the trait candidate's text, else the description) contains 可以放置于远程位 — exactly 崖心, 见行者 and 歌蕾蒂娅, normal and elite (6 records, the only data change; `validateAll` allows it on a MELEE record only; module-only text never counts). `positionClass` returns 'all' for them, so the server takes them on every deployable tile — `g.move`, swaps, a merge's elite (`mergeTile`), the terrain re-check (`_evictIllegal`), invariants and audit —, and the client's `piecePosition` 'ALL' lights the 高台 while dragging; every other melee unit keeps the refusal and its text. The battle keeps position MELEE: on a ground tile they block as before; on a 高台 (`unit.ground` false) they block nothing and attack from there — the sim needed no change (act2 m01, one 萨卡兹枯朽前锋 on the lower lane, 40 s: 歌蕾蒂娅 on (10,4) facing it 2 hits, no block, on (9,5) 12 hits, blocking; 崖心 and 见行者 alike; no errors). +- **Bots** read the record's own position (`basePositionClass`): they still count these units as blockers (`isBlocker`; with the widened class they would not, and the planner put 歌蕾蒂娅 and 崖心 on the 高台 and the ranged dealer off it) and plan them on the ground tiles, as in 0.1.1 [ASSUMED]: offered the 高台, the planner still chose road tiles in the cases measured, but the lineup's blocker count assumes they block and a greedy 高台 pick could take a ranged dealer's tile — not benchmarked. `tools/balance.mjs` uses the same blocker test. Tokens are unchanged; the sim's automatic placements (the 突袭 landing tile, summon / device tiles) still treat them as melee, ground tiles only [ASSUMED]. +- **Players notice**: 歌蕾蒂娅, 崖心 and 见行者 can be dragged onto a 高台 (PLAYING §4); there they attack but block nothing. +- Normative lines rewritten with it: §3 (placement), §6.6 (the bot); research 03 C2; DATA §2 (`placement`). +- Tests: `test/match/feedback1-placement.test.js` (#32-4: the data rule, cross-checked against character_table when the cache exists; `g.move` onto (10,4) / (11,4) / (12,4) of 战场#01(下半) for the six records; a 重装 refused with its text; ranged unchanged; client highlights = the server's tiles; swaps; the merge's elite on the 高台; the battle input and the sim on / off the 高台; bots), `test/match/board.test.js` (`positionClass` / `basePositionClass`), `test/ui/gameLogic.test.js` (the client mirror). diff --git a/docs/PLAYING.md b/docs/PLAYING.md index e0e57bad..08924da9 100644 --- a/docs/PLAYING.md +++ b/docs/PLAYING.md @@ -62,7 +62,7 @@ ## 4. 摆阵与朝向 -- 从整备区把干员拖到棋盘:近战位 / 远程位高亮为可放置格。**水里不能部署**:战场#08(涨潮控制)中间的那条水池(深水区)和官方一样拒绝部署,任何干员和召唤物都放不上去;突袭盟约的干员再部署、战术家的援军自动选战术点时也只会落在岸上。松手后出现**方向轮盘**,向上 / 右 / 下 / 左滑动,棋盘上会用橙色条纹预览旋转后的攻击范围,松手确认;松在中心或点「✕ 点击取消」取消。 +- 从整备区把干员拖到棋盘:近战位 / 远程位高亮为可放置格。**钩索师和推击手**(歌蕾蒂娅、崖心、见行者)的特性写着「可以放置于远程位」,地面和高台都能放;站在高台上时照常攻击,但不阻挡敌人。**水里不能部署**:战场#08(涨潮控制)中间的那条水池(深水区)和官方一样拒绝部署,任何干员和召唤物都放不上去;突袭盟约的干员再部署、战术家的援军自动选战术点时也只会落在岸上。松手后出现**方向轮盘**,向上 / 右 / 下 / 左滑动,棋盘上会用橙色条纹预览旋转后的攻击范围,松手确认;松在中心或点「✕ 点击取消」取消。 - 想只改朝向:把干员拖回它自己所在的格子再选方向。朝向会一直保留到下一回合。 - **点选按地上的方格**:点哪个方格就选中站在那个方格上的单位,点空方格不选任何单位(点到后一格干员画出来的头部,算作点了后面那一格)。作战中友方同样按方格;敌人在格子之间走动,点它的身体或脚下附近(0.6 格内)即可,飞行敌人点它的身体。 - 拖动时模型一直在指针 / 手指下(脚在指针下方约半格,鼠标和触屏一样),**指针所在的格子**就是落点并高亮;装备拖到哪个格子,就配发给那个格子上的干员;在商店栏上松手则放回原位。 diff --git a/docs/research/03-operators.md b/docs/research/03-operators.md index 0857beff..34baa2af 100644 --- a/docs/research/03-operators.md +++ b/docs/research/03-operators.md @@ -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 **top→bottom, then left→right** (下半). 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]. Maps: see 05. +- **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. ### 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.