feedback5: merge R19C — GitHub #235: the official 「作战结束」 result box (全员无伤! / 生命值减少 −N) and the three battle-over sounds at settlement, PR #112 by @Convey123 ported onto the 0.2.0 layout (test/ui/gameLogic.test.js: both streams' tests kept); golden unchanged
This commit is contained in:
commit
93a45f733f
21 files changed
+705
-14
No files matched your search
+2
-1
@@ -23,7 +23,7 @@
|
||||
- **特殊地形点一下就有说明**:战场上的**活性源石**、**沼泽**、**排气格栅**、**深水区**,以及**红门 / 蓝门 / 传送点**,点一下就会弹出它自己的说明卡——名称、机制,以及**这一关自己的数值**(比如战场#04 的活性源石:每秒 70 点真实伤害、攻击力 +20%、攻击速度 +20、持续 300 秒)。休整期和作战期都能点。普通地板 / 道路 / 高台点了不会弹东西,所以点一下仍然只是「取消选中、关掉卡片」。
|
||||
| 作战 | 每人在自己的战场各自作战(战斗在你的浏览器里模拟,2 倍速)。干员按**逐列从左到右、每列从上到下**的顺序(官方「从上到下>从左到右」:最左一列最先)自动部署并消耗部署费用(初始 10,+1/秒)。时限 45–115 秒(实际秒数,即屏幕上的倒计时),时间到仍存活的敌人算漏怪。有敌人进入蓝门时,顶栏的目标生命值会**立即**显示扣除后的数值(红字 + 「−N」,每回合至多 10 点),结算时确定;联防阶段标注「联防中」,队友拦下的部分最后不扣。左侧队伍栏同样显示队友的待扣生命值。被击倒的干员**留在倒下的格子上**(倒地姿势、略微变灰),之后也在这一格再部署(与官方一样;倒在其他干员或召唤物初始位置上的,会回到自己的初始位置躺下,召唤物已经消失也一样;唯一的例外是乌尔比安:三技能把他移到船锚处期间被击倒时,他回到自己的部署位躺下、再部署——这是项目维护者 2026-10-07 应社区反馈有意做出的改动,与官方「原地倒下」不同);因自身效果强制退场的干员(史尔特尔「余烬」结束、耀骑士临光 2 技能结束等)同样倒在原地、在原地再部署;倒地干员所在的格子**不会被占用**,突袭盟约的再部署、援军、召唤物都会避开它。头上的圆圈是再部署倒计时:绿色圆环 + 秒数;变成黄色「DP」表示部署费用不够。血条下方的一行是**元素损伤**(与原版一致:元素图标 + 白条):干员为带图标的彩色圆盘,敌人为小号纯色圆盘,右侧白条是剩余元素值,像血条一样从右往左减少,白条耗尽的那一下就是爆条(被大额元素损伤一次打掉一截时白条也会一次少一截,例如掠海漂移体每击约为 25%–50%);爆条后进入爆发冷却(灼燃 / 神经 / 侵蚀 10 秒,敌方侵蚀 8 秒,凋亡 15 秒),这时白条变成**元素颜色**(神经青绿、侵蚀蓝、灼燃橙红、凋亡灰紫)并在冷却期间慢慢回满、图标闪烁——彩色条表示已经爆条、正在承受爆发效果,不是还剩的元素值;期间所有元素都不会累积也无法被治疗,结束后清零。元素爆发造成的是**无来源伤害**,不吃干员的增伤、穿透和装备加成(例如深巡打海嗣时灼燃爆发固定 7000),击杀仍记在爆条的干员名下;元素脆弱只提高元素伤害,不加快元素条;脆弱不影响元素伤害。已被击杀的敌人不会再被附加元素损伤。 |
|
||||
| 联防 | 见第 5 节。 |
|
||||
| 结算 | 扣 LP、发放悬赏资金、结算层数;LP ≤ 0 的玩家淘汰(其干员回到公共卡池)。 |
|
||||
| 结算 | 扣 LP、发放悬赏资金、结算层数;LP ≤ 0 的玩家淘汰(其干员回到公共卡池)。结算开始时屏幕正中跳出官方的「**作战结束**」框(约 3 秒后自己消失,不挡操作),下面一行只写**你自己**这一回合被扣的目标生命值:没扣是「**全员无伤!**」,扣了是「**生命值减少 −N**」;同时播官方的战斗结束音效(扣了、联防里没扣、普通回合没扣各一种)。联防回合见第 5 节。最终攻势和隐秘核心没有这一框(之后直接是结算称号或隐秘核心);已淘汰的玩家和观战者不弹框。 |
|
||||
|
||||
**断线与离开**:同盟模拟断线后 10 分钟内重新打开页面即可回到原座位;期间你的阵容照常自动作战,机变和休整期到时自动选择 / 准备,但不会替你购买(想让 AI 代打,请在「离开模拟」里选「暂离(AI 托管)」;AI 托管不会为了腾地方销毁你的道具,整备区满时它会卖掉备战的干员来放道具)。独立模拟的休整期与机变不计时,断线或关掉页面后 **24 小时内**用同一个浏览器打开即可继续;独立模拟的作战(含最终攻势 / 隐秘核心)还可以点顶栏的「暂停」(或按 Space)随时暂停,倒计时和领袖战的加时扣血一起停下(暂停中断线会自动继续,由服务器接着打完这场作战)。同盟模拟的作战不能暂停。「放弃模拟」:独立模拟立即结束本局;同盟模拟中视为你被淘汰(干员回到公共卡池),队友继续。服务器重启会结束所有对局。
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
- 联防在官方的**联防专用地图**上进行(与官方相同,不是本回合的战场):一整片道路,没有水池、箱子、装置等地形;干员按休整期的位置站好。一人协防时敌人从中间的入口进入左半场;两人协防时敌人从最右侧进入,先经过右半场,再穿过中间进入左半场。
|
||||
|
||||
- 只有完美作战的队友能参与联防;联防中**盟约不会叠加层数**。
|
||||
- 联防的结果**只在结算的「作战结束」框里报**(与官方一样,没有「联防成功 / 联防失败」之类的字幕)。框里的数字是服务器结算时**真正扣到你头上**的点数:漏怪的玩家按联防后还剩下的敌人扣,不是自己那场漏了几只。**「全员无伤!」只在联防一只都没放过去时出现**(这一轮谁都没被扣);联防没守住、而你自己没被扣(你是去帮忙的队友,或你漏的敌人都被拦下了),框里只有「作战结束」这个标题——掉血的队友并不是无伤,官方对话框里也没有别的句子。框的颜色:青色=联防全部拦下,橙色=联防没守住但你没掉血,红色=你被扣了。漏了几只仍然看顶栏的橙色「×N」。
|
||||
- 联防中击杀悬赏敌人,资金归击杀者;没有干员击倒它时(无来源伤害、它自己扣血、其他敌人的伤害等),资金归它倒下处所在半场的队友。悬赏敌人在自己的战场上被地形(如活性源石)烫死,资金照样归你。
|
||||
- 联防后仍然存活的敌人,按原主人扣 LP;没人完美作战时直接扣。
|
||||
- 漏怪的玩家在顶栏中间(击倒数旁)看到橙色的「×N」标签:你漏过、仍在联防战场上的敌人数(含还没出场的,**不设上限**),队友每击倒一个就减一(会分裂或召唤的敌人被击倒时,分裂出的敌人也算你的,数字会相应增加);目标生命值同时显示为扣除 min(N, 10) 后的数值。左侧队伍栏里漏怪队友的行也显示 ×N(与战场上的击倒同步更新;鼠标悬停可看到是谁漏过的敌人)。
|
||||
|
||||
@@ -37,7 +37,7 @@ Visuals: oblique perspective board (tilted ~30°, trapezoid tiles), raised highl
|
||||
|
||||
Look & feel: research 06 §11–§12 (near-black green-grey panels, mint `#4ed8af` accents, gold prices, bracket frames, hexagon badges, bond discs, 7-segment countdown). Fonts: Noto Sans SC (Google Fonts with local fallback), Bender/Novecento self-hosted for numerals and Latin micro-labels.
|
||||
|
||||
Screens: **Title** (season art backdrop, 开始 → nickname), **Lobby** (独立模拟 / 同盟模拟 → create or join; recent rooms), **Room** (4 seats, invite code + copy link, difficulty picker (host), add/remove AI, ready, start), **Briefing** (INFO_CHECK: stage, factions, disabled bonds, banned chess, boss silhouette, ready x/4), **Band draft** (grid of 40 bands with icon/name/LP/effect; turn order list; skip; 查看禁用盟约与干员 under the order list opens the briefing's bond rows, legend and banned operators again in a read-only dialog — one component, `ui/matchInfo.js`, §21.28), **Game** (Pixi field + DOM HUD: top bar with round/phase capsule/LP (live during the own battle, §17.5)/timer/ready; bond strip + popups; left team panel with LP/status/emote bubbles, click to watch (a boss round frames the viewer's pair in green, §15); bottom shop bar (level card, 3–5 chess cards, item card, funds, refresh, freeze, collapse); detail panel on click/hover (header with bonds, then 特质 — the operator's own effect — right under it, 特性, stats (live: the battle's own numbers / the start-of-battle ones in prep, §18.5), skill, module, equipped items, talents: §17.5); enemy preview drawer (next round enemies with counts, factions; its 本局信息 tab lists the briefing's disabled bonds and banned operators, §21.28); 机变 overlay (the official card: framed icon + name, the effect text — data `descRaw` — under it, the taker's round avatar at the top-right; two taps, §18.2, §20.7); merge reward overlay (the promotion reward, or a special offer — 凯瑟琳's 定向投放 … — as item / chess cards under its source's label, with the count of offers queued behind it, §21.2); phase banners; ticker (by broadcast priority, highest first; a leader-damage line plays only in its round and a player's newer one replaces the older, §21.10); toasts; emote wheel; settings (volume, quality, show damage numbers)), **Result** (victory/defeat, rounds, per-player lineup, stats, titles, back to room).
|
||||
Screens: **Title** (season art backdrop, 开始 → nickname), **Lobby** (独立模拟 / 同盟模拟 → create or join; recent rooms), **Room** (4 seats, invite code + copy link, difficulty picker (host), add/remove AI, ready, start), **Briefing** (INFO_CHECK: stage, factions, disabled bonds, banned chess, boss silhouette, ready x/4), **Band draft** (grid of 40 bands with icon/name/LP/effect; turn order list; skip; 查看禁用盟约与干员 under the order list opens the briefing's bond rows, legend and banned operators again in a read-only dialog — one component, `ui/matchInfo.js`, §21.28), **Game** (Pixi field + DOM HUD: top bar with round/phase capsule/LP (live during the own battle, §17.5)/timer/ready; bond strip + popups; left team panel with LP/status/emote bubbles, click to watch (a boss round frames the viewer's pair in green, §15); bottom shop bar (level card, 3–5 chess cards, item card, funds, refresh, freeze, collapse); detail panel on click/hover (header with bonds, then 特质 — the operator's own effect — right under it, 特性, stats (live: the battle's own numbers / the start-of-battle ones in prep, §18.5), skill, module, equipped items, talents: §17.5); enemy preview drawer (next round enemies with counts, factions; its 本局信息 tab lists the briefing's disabled bonds and banned operators, §21.28); 机变 overlay (the official card: framed icon + name, the effect text — data `descRaw` — under it, the taker's round avatar at the top-right; two taps, §18.2, §20.7); merge reward overlay (the promotion reward, or a special offer — 凯瑟琳's 定向投放 … — as item / chess cards under its source's label, with the count of offers queued behind it, §21.2); phase banners; the round's result box at SETTLE (the official 「作战结束」 + 「全员无伤!」 / 「生命值减少 −N」 for the viewer's own LP — after a 联防 the server's charge, `m.public.uniteResult.losses` — with the matching BATTLEOVER sound; none in the boss rounds or for a viewer not in the round; GitHub #235, PR #112); ticker (by broadcast priority, highest first; a leader-damage line plays only in its round and a player's newer one replaces the older, §21.10); toasts; emote wheel; settings (volume, quality, show damage numbers)), **Result** (victory/defeat, rounds, per-player lineup, stats, titles, back to room).
|
||||
|
||||
盟约栏支持「收起/展开盟约」(GitHub #142):收起时隐藏完整列表并关闭由列表打开的浮层,让原图标区域的指针事件到达棋盘,只保留至少 44×44 CSS px 的恢复按钮。折叠状态在本局阶段变化、观看队友时保留;展开后仍按当前观看对象显示最新盟约。按钮支持 Enter / Space,聚焦按钮时 Space 不触发准备或暂停。
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ LOBBY(room) → INFO_CHECK (co-op 25 s; solo and any single-human match untimed
|
||||
the layers their own combat reached (the round's pending gains, PRTS "以其阵地当前的状态" [ASSUMED]);
|
||||
a helper's operator knocked out at the end of its own combat enters down — carryState { down: true },
|
||||
PRTS "上一阶段为退场状态的干员强制退场", its full redeploy timer — confirmed by the user (§19.3))
|
||||
SETTLE (LP −min(leaks,10) per player (unite survivors to their source); eliminations; layer gains applied; coins; broadcast)
|
||||
SETTLE (LP −min(leaks,10) per player (unite survivors to their source); eliminations; layer gains applied; coins; broadcast;
|
||||
after a 联防 the outcome and every player's charge ride the SETTLE m.public as `uniteResult`, GitHub #235)
|
||||
R14 FINAL_ASSAULT (merged team LP; pairs by seat; shared boss pool; 120 real s countdown, no hard stop; overtime −1 team LP per
|
||||
real s after 150 real s (§4, m.public.overtimeAt); no layer gains; team LP 0 ⇒ defeat at once (PRTS 直接失败),
|
||||
pool 0 ⇒ victory — the first end the server registers decides, §20.5)
|
||||
|
||||
@@ -17,7 +17,7 @@ Platform additions (implemented): `welcome.{resumed, version}`, `welcome.diyKitt
|
||||
### 8.2 Match
|
||||
C→S (all carry `rid`): `g.infoReady` · `g.band {bandId}` · `g.bandSkip` · `g.bandFocus {bandId?}` (the strategy highlighted in the draft screen — what a timed-out turn takes; absent / null clears it; `WRONG_PHASE` outside BAND_DRAFT, `ALREADY` after the pick, `BAD_TARGET` for a band not allowed; §18.2) · `g.buy {slot}` · `g.refresh` · `g.freeze` · `g.levelUp` · `g.sell {uid}` · `g.move {uid, to:{area:'board', row, col}|{area:'hand', idx}, dir?}` · `g.equip {itemUid, targetUid, replaceUid?}` (`replaceUid`: which equipped item a third one replaces, §6.2) · `g.art {itemUid, row, col, dir?}` (`dir` ∈ UP|RIGHT|DOWN|LEFT from the deploy wheel, §3; absent ⇒ `to.dir`, then RIGHT; `g.move` onto the piece's own tile re-orients it; board pieces in `m.private` / `m.field {prep:true}` carry `dir`) · `g.destroy {uid}` (hand / temp items only; equipped items are locked, §6.2) · `g.reward {idx}` · `g.choice {idx}` · `g.ready {ready}` · `g.emote {id}` · `g.watch {fieldId, playerId?}` (`playerId`: the player tapped — a shared 联防 / boss pair field shows two; what an eliminated viewer follows, §25) · `g.autoplay {on}` · `g.pause {on}` (solo battles only, §14 Solo pause) · `g.unitStats {seq?}` (ROUND_START / SP_DRAFT / PREP, else `WRONG_PHASE`; eliminated: `ELIMINATED`) → push `m.unitStats` (§18.5) · `g.leave`
|
||||
S→C:
|
||||
- `m.public` — full public state on every change (throttled ≤ 10/s): `{ phase, round, lastRound, deadline, serverNow, modeId, difficulty, stageId, factions, disabledBonds, bannedChess, bossId, hiddenBossId?, teamLp?, bossHp?:{hp,max}, overtimeAt? /* FA / HC: ms epoch the overtime drain starts, §4 */, paused /* solo pause, §14 */, draft?:{order,turn,picks,skipsLeft,turnDeadline,turnSeconds /* one turn's length, 0 untimed; deadline = turnDeadline (§18.2) */,untimed}, sp?:{family,cards /* bounty cards carry descRaw?, §20.6 */,turn,picks}, players:[{playerId, seat, name, isBot, connected, alive, lp, bandId, shopLevel, boardCount, ready, bonds:[{bondId,count,active,tier,layers,harmony? /* 调和's +1 is in count, §21.26 */}], fieldId, status, pendingLp? /* COMBAT / 联防 of a normal round: the LP the player's own battle will cost at settlement so far, min(lpCapPerRound, counted leaks) — in 联防 min(lpCapPerRound, uniteLeft) — omitted when 0 and in every other phase (§17.5 live LP) */, uniteLeft? /* 联防: the leaker's enemies still standing — not spawned yet + alive + counted leaks, uncapped, live (§20.6) */}] , fields:[{fieldId, kind, players:[playerId...]}] }`
|
||||
- `m.public` — full public state on every change (throttled ≤ 10/s): `{ phase, round, lastRound, deadline, serverNow, modeId, difficulty, stageId, factions, disabledBonds, bannedChess, bossId, hiddenBossId?, teamLp?, bossHp?:{hp,max}, overtimeAt? /* FA / HC: ms epoch the overtime drain starts, §4 */, paused /* solo pause, §14 */, draft?:{order,turn,picks,skipsLeft,turnDeadline,turnSeconds /* one turn's length, 0 untimed; deadline = turnDeadline (§18.2) */,untimed}, sp?:{family,cards /* bounty cards carry descRaw?, §20.6 */,turn,picks}, players:[{playerId, seat, name, isBot, connected, alive, lp, bandId, shopLevel, boardCount, ready, bonds:[{bondId,count,active,tier,layers,harmony? /* 调和's +1 is in count, §21.26 */}], fieldId, status, pendingLp? /* COMBAT / 联防 of a normal round: the LP the player's own battle will cost at settlement so far, min(lpCapPerRound, counted leaks) — in 联防 min(lpCapPerRound, uniteLeft) — omitted when 0 and in every other phase (§17.5 live LP) */, uniteLeft? /* 联防: the leaker's enemies still standing — not spawned yet + alive + counted leaks, uncapped, live (§20.6) */}] , fields:[{fieldId, kind, players:[playerId...]}] }` · `m.public.uniteResult` — SETTLE after a 联防 only, its outcome as data: `{ through /* the leakers' enemies that still got through, uncapped */, helpers:[playerId...], leakers:[playerId...], losses:{playerId: the LP settlement charged this round — every alive player} }`; absent when no 联防 resolved (the client's result box then reads the round's own battle; GitHub #235, PR #112)
|
||||
- `m.private` — the recipient's full PlayerState view (§6.2 minus server-only data) on every change; in a boss round's prep also `bossMate { playerId, side, units }` — the pair partner's board on its half of the boss field (UnitInfo, mirrored on the right half), re-sent when the partner moves (0.2.0, community report item 51).
|
||||
- `m.field` — field meta when watching starts: `{ fieldId, kind, rect, stageId, units: [UnitInfo], effects? }` (the units on the field, knocked-out operators waiting to redeploy included — `Battle.fieldMeta`, §18.3). The prep-scouting field (`Match.prepFieldMeta`) puts the scouted player's **hand (整备区) and 临时整备区 into `units` as well**: held pieces as units on the hand row (row 7, col = hand slot) and temp pieces on the temp row (row 8, cols 4..8 = the temp slots; PRTS 帮助 counts the temp area with the hand; a held item is a `kind: 'item'` unit the client draws as its floating plate) — the scout renders exactly like the own prep bench, for every watcher alike, the spectator seat's copy equal to a teammate's (§23.19's "never a private view" stays the no-`m.private` rule); the scout signature `_prepScoutSig` carries the hand / temp slots, so a piece moved to another slot is a change — and carries `effects`: the scouted player's effects view (策略 / 机变 / 悬赏 …), the watched player's effects column ready-made
|
||||
- NOTE: game time in `b.snap`/`b.ev` is carried as **`gt`** (the frame's `t` is the message type).
|
||||
|
||||
@@ -1902,3 +1902,36 @@ are.
|
||||
- Golden: unchanged (client only). Tests: `test/ui/feedback5-loadout-data-missing.test.js` (4, all fail on the parent:
|
||||
the tab's files, the refusals, the screen's guard order, the message in Chinese and English); loadout, loadout-stats,
|
||||
module-trait, moduleIcons, diy-ui and standin-ui tests pass unchanged.
|
||||
#### 25.22.4 「提问:联防结算播报没了」 (GitHub #235; PR #112 by @Convey123, approved, never merged): the official 「作战结束」 box and the three BATTLEOVER sounds at settlement — `match/settle.js`, `match/views.js`, `ui/gameLogic/phases.js`, `ui/components.js ResultDialog`, `screens/game.js`
|
||||
|
||||
- **Seen**: 0.1.4 and 0.2.0 have no result box and never play the battle-over sounds. A co-op 联防 round run to SETTLE
|
||||
through the match harness: the SETTLE m.public carries nothing about the 联防; `public/js` names none of the three
|
||||
sounds, though `data/assets.json` `audio.sfx.ui` lists all three and they are on disk (so the full zip, which packs
|
||||
every file the manifest lists, already carries them). PR #112 targeted 0.1.4's layout; the owner approved it on
|
||||
2026-10-05 once the remake's own 「联防成功 / 联防失败:还有 N 只突破防线」 line went (the author removed it, then made
|
||||
「全员无伤!」 true-only).
|
||||
- **Official**: research 09 §3.1 "Round result dialog": 「作战结束」 + 「全员无伤!」, or 「生命值减少」 and the LP lost; the
|
||||
client's audio data names `ON_ACT1AUTOCHESS_BATTLEOVER_REDUCE / _NOREDUCE / _NORMAL`, not when each plays. No EN client
|
||||
text for the three lines in `data/i18n/en.json`: plain translations (Battle over — the existing msgid —, All unharmed!,
|
||||
LP reduced by {n}).
|
||||
- **Now** (ported by hand onto the 0.2.0 modules, every line reviewed): `settle()` keeps `uniteResultView` — `through`
|
||||
(the leakers' enemies that still got through), helpers, leakers and `losses` (every alive player's own charge, the very
|
||||
`loss` deducted) — which the SETTLE m.public carries as `uniteResult` (cleared at the round start; design/network.md
|
||||
§8.2). At SETTLE (the moment is [ASSUMED] — the sources do not time the dialog, and a leaker's number exists only
|
||||
after the 联防) the screen pops `ResultDialog` for 2.8 s (inside SETTLE's 3 s; click-through, under the phase banner):
|
||||
「作战结束」 and the viewer's own line — after a 联防 from `losses`: charged → 「生命值减少 −N」 (red); nothing got through
|
||||
→ 「全员无伤!」 (mint, true for everyone); the 联防 leaked but the viewer paid nothing (a helper, a spared leaker) → the
|
||||
title alone (orange); without a 联防, the own battle's `min(cap, leaks)` as kept while it ran (`roundLossRef`, the
|
||||
live LP's own inputs). Sound: Reduce when charged, NoReduce when a 联防 ran and the viewer paid 0, Normal otherwise
|
||||
[ASSUMED mapping, PR #112's; the owner called the three right]. No ticker line for the outcome.
|
||||
- **Who sees it**: solo — every normal round (no 联防 there) [ASSUMED: the same dialog]; bots — nothing to show, listed
|
||||
in `losses`; a spectator seat or a player eliminated earlier — no box and no sound in any round, where PR #112's last
|
||||
commit gave them the title alone after a 联防 although its own rule gave them nothing in an ordinary round (and no sound
|
||||
either) [ASSUMED]; 最终攻势 / 隐秘核心 — no SETTLE phase (`_finishFinal` → the result screen or the Hidden Core round)
|
||||
and the merged team LP has no per-player loss, so no box [ASSUMED]; a reconnect landing on SETTLE — the 联防 box (the
|
||||
server's figure) without sound, nothing in an ordinary round.
|
||||
- Left out of the PR: ResultDialog's unused `icon` prop and gold / ice tones. Golden: unchanged (283 scenarios). Tests:
|
||||
`test/ui/gameLogic.test.js` (5 new: sounds, loss, words in zh and en, 联防 cases, no-联防 box; the file does not load on
|
||||
the parent), `test/match/playtest6-matchflow.test.js` #235 (2; the 联防 one fails on the parent: losses = the LP
|
||||
settled, no result ticker, gone in the next phase), SP_E2E `test/ui/resultbox.e2e.test.js` (3, mock variants
|
||||
`unite[,through][,helper|,dead]`). Docs: PLAYING.md §1 / §5, design/network.md, design/client.md, design/match.md.
|
||||
Reference in new issue
Block a user