二七王:庄家算奖统一口径为「冲关」

design §8.1 的「常规算奖」全面改称「冲关」,与服务端既有字段 chongguan、
界面「冲关分」「冲关牌型」对齐。理清三层关系并写进三份文档的术语表:

  冲关 = §8.1,只计庄家(旧称常规算奖)
  傍王 = §8.3,可选,庄闲都算
  算奖 = 上位概念 = 冲关 + 傍王 → naward(总奖数)、grade_aw(算奖得分)

「算奖」作为上位概念保留——naward / grade_aw / §8.4 的结算模型都建立在
合并概念之上,去掉它这些字段无从命名。故未做无差别替换,而是逐处甄别:
指 §8.1 的改冲关,指合计的留算奖。

design:17 处「常规算奖」→「冲关」,另修正 §7.0 第 4 层一处笔误
(「8.2 傍王」应为「8.3 傍王」,§8.2 是亮牌);§8.1 开头加改名说明。
protocol:新增 §0.0c 算奖层级表;chongguan / naward / grade_aw 注释同步。
前端清单:界面文案与精灵键名统一(算奖牌型→冲关牌型、BTN_AWARD_CARDS→
BTN_CG_CARDS、AWARD_*→CG_* 等),§0.0 补层级表。

据更新后的 小局结算.png:「算奖分」→「冲关分」、「算奖牌型」→「冲关牌型」。
参考图 算奖牌型显示.png 已随之更名为 冲关牌型显示.png,文档 6 处引用同步;
已逐一核对 16 张图的文件名在文档中都能对上。

顺带记录一处标签不严谨:小局结算的「冲关分」取的是 grade_aw,而后者是按
合计后的 N 算出来的。没开傍王时两者相等;开了傍王时该数含傍王贡献,叫
「冲关分」偏窄。根因与 S-6 同源(两分量算钱前已合并、事后拆不开),待
S-6 落地后此标签才名副其实。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-26 00:25:11 +08:00
co-authored by Claude Opus 5
parent b98f58effc
commit 50e6fd3ca4
5 changed files with 102 additions and 72 deletions
+67 -55
View File
@@ -52,6 +52,18 @@
> ✅ `design.md` 与 `packet_protocol.md` **已同步此变更**(S-5 完成),协议字段名也已拆分为 `bottomcards` / `burycards`(S-4 完成)。
#### 算奖 = 冲关 + 傍王
| 术语 | 范围 | 界面 | 字段 |
| --- | --- | --- | --- |
| **冲关** | design §8.1,**只计庄家**(旧称「常规算奖」) | 小局结算「**冲关分**」、「**冲关牌型**」按钮 | `chongguan`、`cards` |
| **傍王** | design §8.3,可选规则,勾选后**庄闲都算**,每张王 1 奖 | 大局结算「傍王分」 | `wang`、`bangwang` |
| **算奖** | **上位概念** = 冲关 + 傍王 | —— | `naward`(总奖数 N)、`grade_aw`(算奖得分) |
说「**冲关**」指庄家那一份,说「**算奖**」指两者合计。
> ⚠️ **小局结算的「冲关分」标签有一处不严谨**:它取的是 `grade_aw`,而 `grade_aw` 是按**合计后**的 `N`(冲关+傍王)算出来的。房间**没开傍王**时两者相等、标签准确;**开了傍王**时这个数其实含傍王的贡献,叫「冲关分」就偏窄了。根因与 S-6 同源——两个分量在算钱前就已合并、事后拆不开。**待 S-6 落地后此标签才能名副其实。**
#### 四类「公开信息」——名字像、含义差很远
| 术语 | 谁公开给谁 | 给的是什么 | 触发 | 界面位置 | 字段 |
@@ -220,7 +232,7 @@ get_nextseat: function(seat){ return (seat + 1) % 3; }
| 1700–1749 | 埋牌 / 出牌操作条 | ~8 |
| 1750–1799 | 桌面浮层(气泡 / 飘字 / 报无主 / 甩错) | ~15 |
| 1800–1819 | 小局结算面板 | ~20 |
| 1820–1829 | 算奖牌型叠加层(**精灵复制**:遮罩 1 + 容器 3 + 模板 1 + 奖数 3) | **8** |
| 1820–1829 | 冲关牌型叠加层(**精灵复制**:遮罩 1 + 容器 3 + 模板 1 + 奖数 3) | **8** |
| 1900–1949 | 大局总结算 / 解散结算 | 待设计 |
| 1950–1999 | 出牌历史面板 | 待设计 |
| 2000–2049 | 明牌面板 | 待设计 |
@@ -599,7 +611,7 @@ EQW_RoomOptions = {
| 查牌模式 | 仅可查牌模式下发;不查牌时闲家收不到该字段 |
| 谁能看 | 只有两个闲家收到(庄家自己的牌自己本来就看得见) |
**展示形式**:与**明牌**同一套版式(半透黑遮罩 + 一排牌,照 `算奖牌型显示.png`),只是这里只有一排(庄家的)。可与 §5.7b 的明牌面板复用同一套精灵与渲染,仅数据源不同。
**展示形式**:与**明牌**同一套版式(半透黑遮罩 + 一排牌,照 `冲关牌型显示.png`),只是这里只有一排(庄家的)。可与 §5.7b 的明牌面板复用同一套精灵与渲染,仅数据源不同。
**数量前端自己数**——协议不再下发 `zhu`/`zhupair`/`wang`/`qi`/`er` 等统计,需要显示「x 张王」之类就从 `cards` 里算。
@@ -692,14 +704,14 @@ EQW_RoomOptions = {
> ⚠️ 这比 design §9 更严格,且与服务端当前校验不一致,见 §7.5 **S-7**。design 原文是「一旦有玩家的主牌全部打空……界面上会出现一个『明牌』按钮」,读作**全体三人**都出现;服务端 `mingpai` 的受理条件也是 `have_baofu()`(任一玩家报无主)。按新规则则应改成「**请求者本人**无主」。
- 点击 → 发 `mingpai { seat }` → 收 `mingpai { seat, others: [{seat, zhucards}] }` → 弹出面板展示另两家全部未出主牌的**具体牌面**。
- **再点一次取消是纯前端开关**,不再请求服务端(协议 §13.6)。
- **展示形式(D-6 已定)**:**照 `算奖牌型显示.png` 那一套**——半透黑遮罩 + 两家各一排牌(`CARD_FACE_L`、`fan` 重叠排列),点遮罩关闭。与算奖牌型叠加层是同一种版式,可复用同一套渲染逻辑,仅数据源与座位数不同(明牌是**另两家**,算奖是**三家**)。
- **展示形式(D-6 已定)**:**照 `冲关牌型显示.png` 那一套**——半透黑遮罩 + 两家各一排牌(`CARD_FACE_L`、`fan` 重叠排列),点遮罩关闭。与冲关牌型叠加层是同一种版式,可复用同一套渲染逻辑,仅数据源与座位数不同(明牌是**另两家**,冲关牌型是**三家**)。
- 面板:图层 305,群组 243;牌**用精灵复制**(张数不定,同 §5.6a 的判据)。
**出牌历史**(design §9.1):
- 仅可查牌模式;底栏 `出牌历史` / `上一轮` 两个按钮(§2.6)。
- 数据来自重连包 `pushlist`(按轮次 × 3 家),**出牌过程中前端需自行累积**(`chupai1/2/3` 逐包记录)。
- **展示形式(D-7 已定)**:**不按轮次分组**。把每家出过的牌全部**摊平聚合到该玩家名下**,再**按手牌那套主牌序排序**(同 §7.2 T-5 的 `order_cards` 顺序),三家各显示一排——版式**照 `算奖牌型显示.png`**(遮罩 + 三家各一排牌)。
- **展示形式(D-7 已定)**:**不按轮次分组**。把每家出过的牌全部**摊平聚合到该玩家名下**,再**按手牌那套主牌序排序**(同 §7.2 T-5 的 `order_cards` 顺序),三家各显示一排——版式**照 `冲关牌型显示.png`**(遮罩 + 三家各一排牌)。
> 前端自行摊平 + 排序即可,**不需要改服务端**:`pushlist` 已含全部轮次数据,且各轮内部已按本局主牌花色排好。
- `上一轮` 按钮则只取**最近一轮**的三家出牌(`pushlist` 末尾一项),版式同上。
- 面板:图层 304,群组 242;牌**用精灵复制**(张数不定)。
@@ -734,43 +746,43 @@ EQW_RoomOptions = {
| --- | --- | --- | --- |
| 大字 | 本局总分 | `grade` | `+20` 橙色(赢)/ `-10` 蓝色(输),底带光晕 |
| 小字左 | **`牌局分 N`** | `grade_jf`(捡分子数得分) | 白标签 + 数值 |
| 小字右 | **`算奖分 N`** | `grade_aw`(算奖得分) | 白标签 + 数值 |
| 小字右 | **`冲关分 N`** | `grade_aw`(算奖得分) | 白标签 + 数值 |
> 两个标签的文案已由更新后的 `小局结算.png` 确定(原图两个都写「牌局分」是 mock 重复,现已修正为 `牌局分` / `算奖分`)。
> 两个标签的文案已由更新后的 `小局结算.png` 确定(原图两个都写「牌局分」是 mock 重复,现已修正为 `牌局分` / `冲关分`)。
**两个按钮**:
| 按钮 | 位置 | 作用 |
| --- | --- | --- |
| `算奖牌型`(蓝色) | 中央偏左 | 打开算奖牌型叠加层(见下) |
| `冲关牌型`(蓝色) | 中央偏左 | 打开冲关牌型叠加层(见下) |
| `下一局`(金黄) | 中央偏右 | 发 `zhunbei { seat }` 进入下一局(§1.12) |
#### 「冲关」是什么(`chongguan` 字段的准确定义)
服务端 `class.arith.js:1277` `get_chongguan(mainflower, cards)`。**「冲关」就是 design §8.1「常规算奖」的服务端命名**——`chongguan` 的值即该玩家常规算奖的**奖数**,不是另一套独立规则。函数返回三项:
服务端 `class.arith.js:1277` `get_chongguan(mainflower, cards)`。`chongguan` 即 design §8.1 **冲关**的奖数(该规则旧称「常规算奖」,现统一叫冲关)。函数返回三项:
| 返回字段 | 含义 | 去向 |
| --- | --- | --- |
| `count` | 关数 = 常规算奖奖数 | `aset.seatlist[i].chongguan` |
| `count` | 关数 = 冲关奖数 | `aset.seatlist[i].chongguan` |
| `wang` | 手牌中的王数 | `aset.seatlist[i].wang`(傍王按此计奖) |
| `cards` | **王牌 + 所有参与冲关的牌**,已按主牌序从大到小排好 | `aset.seatlist[i].cards` → **算奖牌型叠加层要显示的就是它** |
| `cards` | **王牌 + 所有参与冲关的牌**,已按主牌序从大到小排好 | `aset.seatlist[i].cards` → **冲关牌型叠加层要显示的就是它** |
计数规则(与 design §8.1 逐条对应):
1. **前置**:`cards.length < 28` 直接返回 0 —— 手牌不足 28 张不参与算奖。
1. **前置**:`cards.length < 28` 直接返回 0 —— 手牌不足 28 张不参与冲关。
2. **三王 / 四王**:≥3 王 → `count = 1`;= 4 王 → `count = 3`。
3. **连对链续奖**:**必须先满足 ≥3 王**(整段逻辑在 `if (_wlist.length >= 3)` 内)。从小王编码 `9553` 起,沿主牌序往下逐对扫描,每遇到一个与上一节**位置相邻**的对子就 `count + 1`,链条为 `正7 → 副7 → 正2 → 副2 → 主A → 主K → …`,断则止。**没有三王就没有连对链奖**。
4. **六/七/八个 7**:`count += 张数 − 5`(6→1、7→2、8→3 奖)。
5. **六/七/八个 2**:同上。
6. **固定主牌 ≥10 张不算奖**——它只触发 design §8.2 的「亮牌」,代码里有明确注释。§1.6 的亮牌与这里的算奖是两回事。
6. **固定主牌 ≥10 张不产生冲关奖**——它只触发 design §8.2 的「亮牌」,代码里有明确注释。§1.6 的亮牌与这里的冲关是两回事。
> 前端**不重算冲关**,`chongguan` / `wang` / `naward` / `cards` 一律直接取服务端下发值(服务端权威,红线)。上面的规则只用于理解要显示什么。
**算奖牌型叠加层** 【图:算奖牌型显示.png】:
**冲关牌型叠加层** 【图:冲关牌型显示.png】:
点 `算奖牌型` 后,在结算面板之上盖一层**半透黑遮罩**,三家各展示自己的 `aset.seatlist[i].cards`,资源用 `CARD_FACE_L`、重叠排列。`下一局` 按钮在遮罩层上**继续可见可点**,`算奖牌型` 按钮本身被遮住。
点 `冲关牌型` 后,在结算面板之上盖一层**半透黑遮罩**,三家各展示自己的 `aset.seatlist[i].cards`,资源用 `CARD_FACE_L`、重叠排列。`下一局` 按钮在遮罩层上**继续可见可点**,`冲关牌型` 按钮本身被遮住。
**关闭方式:整块全屏半透明黑遮罩本身就是关闭热区,点击遮罩即关闭。** 不另设关闭按钮。因此 `AWARD_MASK` 必须注册点击事件,且 `下一局` 的层级要高于它、点它不被遮罩吃掉。
**关闭方式:整块全屏半透明黑遮罩本身就是关闭热区,点击遮罩即关闭。** 不另设关闭按钮。因此 `CG_MASK` 必须注册点击事件,且 `下一局` 的层级要高于它、点它不被遮罩吃掉。
- 三家牌位:左上家、右上家在各自头像内侧;自己在中央偏下。
- 布局配置见 §6.7。
@@ -786,8 +798,8 @@ EQW_RoomOptions = {
| `grade` | 闲家最终捡分(含扣底)→ 顶部 `抓分` 列 |
| `upgrade` | **判定倍率(带符号)**:`3` 大光 / `2` 小光 / `1` 过庄 / `-N` 升 N 级(倒庄)/ `-99` 投降 / `0` 解散 → 需要一组判定文字或图标:`大光` `小光` `过庄` `升N级` `投降`【待设计 D-8】 |
| `bangwang` / `climb` | 本局规则开关,用于结算面板上标注 |
| **`cards`** | **算奖牌型叠加层**的牌(见上) |
| `chongguan` / `wang` / `naward` | 常规算奖奖数 / 王数 / **总奖数**。叠加层**需要并列显示奖数**——以 `naward`(该家总奖数 N,8.4 节的支付基数)为主;`chongguan` / `wang` 作为明细可选展示 |
| **`cards`** | **冲关牌型叠加层**的牌(见上) |
| `chongguan` / `wang` / `naward` | 冲关奖数 / 王数 / **总奖数**。叠加层**需要并列显示奖数**——以 `naward`(该家总奖数 N,8.4 节的支付基数)为主;`chongguan` / `wang` 作为明细可选展示 |
**投降结算**:只有 `aset`,无 `chupai`、无 `bottom` → 结算面板必须容忍**底牌区缺失**,不能因为读不到 `bottom.cards` 就崩或显示空框。
@@ -801,7 +813,7 @@ EQW_RoomOptions = {
| 区 | 内容 |
| --- | --- |
| 标题栏(青绿底) | `二七王-3人 房号{roomcode} 共{asetcount}局 {开战时间}` + 右上角关闭钮 |
| 玩家栏 ×3(按名次排序,行间分隔线) | 名次徽章 → 头像 → 昵称 / `ID:{playerid}`(两行)→ `基础分{n}` / `总得分{n}`(两行)→ `算奖分{n}` → `傍王分{n}` → 右侧大字总分 |
| 玩家栏 ×3(按名次排序,行间分隔线) | 名次徽章 → 头像 → 昵称 / `ID:{playerid}`(两行)→ `基础分{n}` / `总得分{n}`(两行)→ `冲关分{n}` → `傍王分{n}` → 右侧大字总分 |
| 规则栏(浅绿底) | `规则:可查牌、傍王、爬坡算子` —— 据 `roomtype` 位串拼出已启用项 |
| 面板外底部 | `再来一局`(黄) `分享好友`(蓝) `复制战绩`(蓝) `退出房间`(红) |
@@ -809,8 +821,8 @@ EQW_RoomOptions = {
- **总分大字**:正分橙色带 `+`、负分蓝色带 `-`,复用 §3.6 的 `NUM_RESULT_WIN` / `NUM_RESULT_LOSE`。
> ⚠️ **四项分数当前协议给不出,需服务端补**,见 §7.5 **S-6**:
> `account` 只有「累积得分 + 每局得分数组」,没有「基础分 / 算奖分 / **傍王分**」这三项分解。
> 尤其 **傍王分无法从现有字段拆出**——`naward = 常规算奖 + 傍王王数` 已经把两者合并,`grade_aw` 是按合并后的 `N` 算出来的。
> `account` 只有「累积得分 + 每局得分数组」,没有「基础分 / 冲关分 / **傍王分**」这三项分解。
> 尤其 **傍王分无法从现有字段拆出**——`naward = 冲关 + 傍王王数` 已经把两者合并,`grade_aw` 是按合并后的 `N` 算出来的。
### 1.10 解散结算 `free_room` 【待设计】
@@ -1051,7 +1063,7 @@ y≈648–720 深色条。左侧头像/昵称/分数由平台渲染(§0.2)
| ~~539~~ | ~~`BTN_READY`~~ | **不需要**:准备标识用平台的(§0.2) | —— | —— |
| 540 | `BTN_TISHI` | 底栏 `踩` / `有分` / `没分` 按钮底(三者共用) | 1 | 深色圆角,同 `BTN_BOTTOM_FUNC` 风格但更窄 | 52 × 30 |
| 541 | `BTN_NEXT_ASET` | 结算 `下一局` | 1 | 金黄渐变 | 180 × 65 |
| 542 | `BTN_AWARD_CARDS` | 结算 `算奖牌型` | 1 | 蓝色渐变 | 183 × 63 |
| 542 | `BTN_CG_CARDS` | 结算 `冲关牌型` | 1 | 蓝色渐变 | 183 × 63 |
| 543 | `BTN_ACCOUNT_AGAIN` | 大局结算 `再来一局` | 1 | 黄色渐变 | 190 × 60 |
| 544 | `BTN_ACCOUNT_SHARE` | 大局结算 `分享好友` | 1 | 蓝色渐变 | 190 × 60 |
| 545 | `BTN_ACCOUNT_COPY` | 大局结算 `复制战绩` | 1 | 蓝色渐变 | 190 × 60 |
@@ -1084,7 +1096,7 @@ y≈648–720 深色条。左侧头像/昵称/分数由平台渲染(§0.2)
| 606 | `PANEL_BOTTOM_CARDS` | 结算底牌区面板底 | 1 | 420 × 148 |
| 607 | `GLOW_RESULT` | 结算分数光晕背景 | 2 | 帧1=赢(橙) 帧2=输(蓝) | 225 × 100 |
| 608 | `BAR_FOOTER` | 底栏深色条 | 1 | 1280 × 72 |
| 609 | `MASK_DIM` | 半透黑遮罩(算奖牌型 / 出牌历史 / 明牌 共用) | 1 | 1280 × 720(纯色可拉伸,出 1 张小图即可) |
| 609 | `MASK_DIM` | 半透黑遮罩(冲关牌型 / 出牌历史 / 明牌 共用) | 1 | 1280 × 720(纯色可拉伸,出 1 张小图即可) |
| 610 | `PANEL_ACCOUNT` | 大局总结算面板底(圆角浅灰绿) | 1 | 1100 × 540 |
| 611 | `BAR_ACCOUNT_TITLE` | 大局结算标题栏(青绿底,含圆角上沿) | 1 | 1100 × 56 |
| 612 | `BAR_ACCOUNT_RULE` | 大局结算底部规则栏(浅绿底,含圆角下沿) | 1 | 1100 × 62 |
@@ -1275,14 +1287,14 @@ design 与协议均**未定义任何音效**。以下是按牌类游戏常规推
| 1808–1810 | `RESULT_JF_LEFT/RIGHT/SELF` | 文字 ×3 | 捡分子数得分 `grade_jf`【T-13】 | —— |
| 1811–1813 | `RESULT_AW_LEFT/RIGHT/SELF` | 文字 ×3 | 算奖得分 `grade_aw`【T-13】 | —— |
| 1814 | `RESULT_JUDGE_TEXT` | 文字 | 判定结果(大光/小光/过庄/升N级/投降,据 `aset.upgrade`) | —— |
| 1815 | `RESULT_BTN_AWARD` | 图片 | `算奖牌型` 按钮 | `BTN_AWARD_CARDS` |
| 1816 | `RESULT_BTN_AWARD_TEXT` | 文字 | 按钮文案 | —— |
| 1815 | `RESULT_BTN_CG` | 图片 | `冲关牌型` 按钮 | `BTN_CG_CARDS` |
| 1816 | `RESULT_BTN_CG_TEXT` | 文字 | 按钮文案 | —— |
| 1817 | `RESULT_BTN_NEXT` | 图片 | `下一局` 按钮 | `BTN_NEXT_ASET` |
| 1818 | `RESULT_BTN_NEXT_TEXT` | 文字 | 按钮文案 | —— |
> 底牌 8 张精灵复用 §5.3 群组 215(1258–1265),不在此重复。
### 5.6a 算奖牌型叠加层(Layer 302,群组 **244**,**精灵复制**)
### 5.6a 冲关牌型叠加层(Layer 302,群组 **244**,**精灵复制**)
**本层的牌用 `SpriteCopyUtils` 运行时复制,不预置固定张数。** `aset.seatlist[i].cards` 的长度不定(四王 + 长连对链 + 八个 7 + 八个 2 可达 20 余张),预置既可能不够、又在多数局里白占 ID。
@@ -1290,27 +1302,27 @@ design 与协议均**未定义任何音效**。以下是按牌类游戏常规推
| 精灵 ID | 键名 | 类型 | 用途 | 资源 / 帧 |
| --- | --- | --- | --- | --- |
| 1820 | `AWARD_MASK` | 图片 | 半透黑遮罩(拉伸满屏,兼作点击关闭热区) | `MASK_DIM` |
| 1821 | `AWARD_BOX_LEFT` | **容器** | 左上家算奖牌容器(复制的父精灵) | —— |
| 1822 | `AWARD_BOX_RIGHT` | **容器** | 右上家算奖牌容器 | —— |
| 1823 | `AWARD_BOX_SELF` | **容器** | 自己算奖牌容器 | —— |
| 1824 | `AWARD_CARD_TPL` | **模板** | 算奖牌模板(编辑器里放好、默认隐藏,只作样式来源) | `CARD_FACE_L` |
| 1825–1827 | `AWARD_COUNT_LEFT/RIGHT/SELF` | 文字 ×3 | **奖数**,与该家的算奖牌**并列显示**(取 `aset.seatlist[i].naward`;是否另列 `chongguan`/`wang` 明细见下) | —— |
| 1820 | `CG_MASK` | 图片 | 半透黑遮罩(拉伸满屏,兼作点击关闭热区) | `MASK_DIM` |
| 1821 | `CG_BOX_LEFT` | **容器** | 左上家冲关牌容器(复制的父精灵) | —— |
| 1822 | `CG_BOX_RIGHT` | **容器** | 右上家冲关牌容器 | —— |
| 1823 | `CG_BOX_SELF` | **容器** | 自己冲关牌容器 | —— |
| 1824 | `CG_CARD_TPL` | **模板** | 冲关牌模板(编辑器里放好、默认隐藏,只作样式来源) | `CARD_FACE_L` |
| 1825–1827 | `CG_COUNT_LEFT/RIGHT/SELF` | 文字 ×3 | **奖数**,与该家的冲关牌**并列显示**(取 `aset.seatlist[i].naward`;是否另列 `chongguan`/`wang` 明细见下) | —— |
**生成方式**:
```js
// 每个座位一个容器,tag 用牌在 cards 里的下标(父精灵内唯一即可)
var pos = LayoutSolver.solve(EQW_Layout.AWARD_CARDS, seatKey, cards.length); // fan 布局,见 §6.7
var pos = LayoutSolver.solve(EQW_Layout.CG_CARDS, seatKey, cards.length); // fan 布局,见 §6.7
for (var i = 0; i < cards.length; i++) {
var sid = SpriteCopyUtils.create(boxId, sprites.AWARD_CARD_TPL, pos[i].x, pos[i].y, i);
var sid = SpriteCopyUtils.create(boxId, sprites.CG_CARD_TPL, pos[i].x, pos[i].y, i);
SpriteManager.setFrame(sid, cardIdToFrame(cards[i])); // §0.4
}
```
**清理是硬要求**:关闭叠加层 / 组件 `onDestroy` 时必须 `SpriteCopyUtils.removeRange(boxId, 0, cards.length)`,否则复制精灵残留(client 02 §6)。
> `RESULT_BTN_NEXT`(1817/1818)在遮罩之上仍需可见可点 —— 其图层内层级须高于 `AWARD_MASK`。
> `RESULT_BTN_NEXT`(1817/1818)在遮罩之上仍需可见可点 —— 其图层内层级须高于 `CG_MASK`。
#### 预置 vs 精灵复制的选用判据
@@ -1321,11 +1333,11 @@ for (var i = 0; i < cards.length; i++) {
| 逐个控制 | 需要独立 z 序 / 动画 / 命名引用 | 只需批量摆位 + 设帧 |
| 清理成本 | 无 | 必须显式 `remove`,忘了就残留 |
据此,本清单的选用——**全项目只有「算奖牌型」一处用复制,其余一律预置**:
据此,本清单的选用——**全项目只有「冲关牌型」一处用复制,其余一律预置**:
| 区域 | 方式 | 理由 |
| --- | --- | --- |
| **算奖牌型** | **复制** | 张数不定、无小上限,多数局用不满 |
| **冲关牌型** | **复制** | 张数不定、无小上限,多数局用不满 |
| 自己手牌(36) | 预置 | 上限确定;需逐张选中上浮、独立动画与点击 |
| 已出牌区(28 × 3) | 预置 | 需叠压 z 序与出牌动画,逐张独立控制 |
| 底牌(8)/ 埋牌底牌(8) | 预置 | 固定 8 张 |
@@ -1360,7 +1372,7 @@ for (var i = 0; i < cards.length; i++) {
### 5.7b Layer 304 / 305 · 出牌历史与明牌(群组 242 / 243,**牌用精灵复制**)
两者版式相同(遮罩 + 每家一排牌,照 `算奖牌型显示.png`),差别只在数据源与家数,**共用同一套渲染**:
两者版式相同(遮罩 + 每家一排牌,照 `冲关牌型显示.png`),差别只在数据源与家数,**共用同一套渲染**:
| 精灵 ID | 键名 | 类型 | 用途 | 资源 / 帧 |
| --- | --- | --- | --- | --- |
@@ -1468,7 +1480,7 @@ for (var i = 0; i < cards.length; i++) {
#### `fan` — 自适应压缩排
张数可变、**总宽受限**、需要动态压缩间距的牌排(手牌、出牌区、算奖牌)。
张数可变、**总宽受限**、需要动态压缩间距的牌排(手牌、出牌区、冲关牌)。
```js
{ kind: 'fan', direction: 'horizontal',
@@ -1552,7 +1564,7 @@ PLAY_AREA: {
```js
CARD_SIZE: {
L: { w: 110, h: 190, res: 'CARD_FACE_L' }, // 手牌、底牌、算奖牌
L: { w: 110, h: 190, res: 'CARD_FACE_L' }, // 手牌、底牌、冲关牌
M: { w: 90, h: 155, res: 'CARD_FACE_M' }, // 已出牌区
S: { w: 50, h: 70, res: 'CARD_FACE_S' } // 结算埋牌底牌
}
@@ -1617,7 +1629,7 @@ CARD_SIZE: {
| **已出牌区** | `fan` | 见 §6.2 的 `bySeat` 示例(三家共用 base,LEFT 镜像) |
| 已出牌 · 牌型标签 | `attach` | `target:该区首张牌, corner:bottomLeft, offsetX:0, offsetY:-24` |
| 已出牌 · 牌角 `庄`/`大` 标 | `attach` | `target:对应牌, corner:topRight, offsetX:-28, offsetY:0` |
| **算奖牌(叠加层)** | `fan` | `size:L spacingMax:-40 spacingMin:-88 maxWidth:420`;`bySeat{ LEFT:{anchorX:260,anchorY:120}, RIGHT:{anchorX:1035,anchorY:120}, SELF:{anchorX:640,anchorY:400} }`。**精灵复制**(§5.6a):求解结果直接作为 `SpriteCopyUtils.create` 的 `x/y`(相对容器)。`spacingMin` 放宽到 `-88`(即最窄只露 22px)以容纳 20+ 张的极端情况 |
| **冲关牌(叠加层)** | `fan` | `size:L spacingMax:-40 spacingMin:-88 maxWidth:420`;`bySeat{ LEFT:{anchorX:260,anchorY:120}, RIGHT:{anchorX:1035,anchorY:120}, SELF:{anchorX:640,anchorY:400} }`。**精灵复制**(§5.6a):求解结果直接作为 `SpriteCopyUtils.create` 的 `x/y`(相对容器)。`spacingMin` 放宽到 `-88`(即最窄只露 22px)以容纳 20+ 张的极端情况 |
### 6.8 阶段操作区配置
@@ -1650,10 +1662,10 @@ CARD_SIZE: {
| **三家分数光晕** | `point` | `bySeat{ LEFT:{x:175,y:150}, RIGHT:{x:865,y:150}, SELF:{x:490,y:340} }`,`w:225 h:100` |
| 三家总分大字 | `attach` | `target:对应光晕, hAlign:center, vAlign:middle`,`textStyle{fontSize:56, align:center}` |
| 三家 `牌局分` | `attach` | `target:对应光晕, hAlign:left, vAlign:bottom, offsetX:-15, offsetY:24` |
| 三家 `算奖分` | `attach` | `target:对应光晕, hAlign:right, vAlign:bottom, offsetX:15, offsetY:24` |
| `算奖牌型` 按钮 | `point` | `x:535 y:515 w:183 h:63` |
| 三家 `冲关分` | `attach` | `target:对应光晕, hAlign:right, vAlign:bottom, offsetX:15, offsetY:24` |
| `冲关牌型` 按钮 | `point` | `x:535 y:515 w:183 h:63` |
| `下一局` 按钮 | `point` | `x:835 y:518 w:180 h:65` |
| 算奖遮罩 | `point` | `x:0 y:0 w:1280 h:720`,`opacity:0.72`(透明度也是配置项) |
| 冲关遮罩 | `point` | `x:0 y:0 w:1280 h:720`,`opacity:0.72`(透明度也是配置项) |
### 6.9b 建房规则选项配置(§1.1)
@@ -1732,7 +1744,7 @@ codes/config/
| ~~D-3~~ | 甩错提示 | ✅ 定稿:桌面中央深色半透条 **`强甩失败`**(`强甩失败提示.png`),**不做收回动画**,直接落下那张被强制打出的最小主牌 |
| ~~D-4~~ | 报无主 | ✅ 定稿:**不做全场提示**。只让他家 `主N`/`对N` 角标出现;自己的主牌统计条本来就常显(§2.5) |
| ~~D-5~~ | 踩 / 没分 / 有分 | ✅ 定稿:底栏三按钮(占庄标区)+ 3×2 六帧气泡 |
| ~~D-6~~ | 明牌面板 | ✅ 定稿:版式照 `算奖牌型显示.png`(遮罩 + 每家一排牌)。**按钮显示条件收紧为「可查牌 + 自己是无主玩家」** → 见 **S-7** |
| ~~D-6~~ | 明牌面板 | ✅ 定稿:版式照 `冲关牌型显示.png`(遮罩 + 每家一排牌)。**按钮显示条件收紧为「可查牌 + 自己是无主玩家」** → 见 **S-7** |
| ~~D-7~~ | 出牌历史面板 | ✅ 定稿:版式同上。**不按轮次**,按玩家聚合、用主牌序排序。前端摊平 `pushlist` 即可,无需改服务端 |
| ~~D-9~~ | 大局总结算 | ✅ 定稿:`大局结算.png`,玩家栏用精灵复制(§5.7a)。**四项分数协议缺** → 见 **S-6** |
| ~~D-10~~ | 解散结算 | ✅ 复用 D-9 面板;投票界面平台全包(Layer 420) |
@@ -1765,17 +1777,17 @@ codes/config/
| ~~T-10~~ | 出牌阶段**必有** `提示` 按钮;服务端已下发 `mustcard` 供自动选中(S-2 ✅) |
| ~~T-11~~ | 牌型标签**只做「毙」一种**;数据层保留 毙/垫/混合出牌 三种标识备扩展,当前不出图 |
| ~~T-12~~ | `底牌 20x0` 的 `x` 后面是**扣底倍数**(`bottom.multiple`);未扣底显示 0(§1.8) |
| ~~T-13~~ | 结算两个小字 = `牌局分`(`grade_jf`) / `算奖分`(`grade_aw`) |
| ~~T-14~~ | 算奖明细走独立的**算奖牌型叠加层** |
| ~~T-13~~ | 结算两个小字 = `牌局分`(`grade_jf`) / `冲关分`(`grade_aw`) |
| ~~T-14~~ | 冲关明细走独立的**冲关牌型叠加层** |
| ~~T-15~~ | 准备标识**用平台的** |
| ~~T-16~~ | `抓分` 角标 = **当前捡分对应判定倍率的实时预览**;服务端已下发 `curmultiple`(S-1 ✅) |
| ~~T-17~~ | 倒计时归零**停在 `0`** 不隐藏 |
| ~~T-18~~ | 底栏 5 按钮:`上一轮`/`出牌历史`/`明牌`/`扣底`(看**埋牌底牌**)/`底牌`(看**底牌**);术语已统一见 §2.6;可见性按手册 → **S-3** |
| ~~T-19~~ | 数字**一律用图片多帧精灵**(参考图数字带描边渐变,文字精灵做不出),资源 631–634 全部要出 |
| ~~T-21~~ | 手牌单排 `spacingMin:-78`、双排 `-65`(§6.7) |
| ~~T-22~~ | 算奖叠加层:**全屏半透明遮罩本身即关闭热区,点击遮罩关闭**,不另设关闭钮 |
| ~~T-22~~ | 冲关牌型叠加层:**全屏半透明遮罩本身即关闭热区,点击遮罩关闭**,不另设关闭钮 |
| ~~T-23~~ | 叠加层**需要并列显示奖数**(以 `naward` 为主) |
| ~~T-24~~ | 算奖牌用**精灵复制**,张数不设上限 |
| ~~T-24~~ | 冲关牌用**精灵复制**,张数不设上限 |
| ~~T-25~~ | `line` 支持可选 `items` 逐项不等宽 |
| ~~T-26~~ | 自己发的提示**需要本地回显**(受控例外,理由见 §1.7) |
| ~~T-27~~ | 埋牌双排 `floor(n/2)` / `ceil(n/2)` |
@@ -1815,7 +1827,7 @@ codes/config/
| 6 | 投降结算(无 `bottom`)与解散结算(无 `deskfree` 的情形)都不崩、不显示空框 | §1.8 / §1.10 |
| 7 | 解散包从 `data.deskfree.data.aset` 取值,不是 `data.aset` | §1.10 |
| 8 | 倒计时归零不做任何界面推进 | 协议 §0.3 |
| 9 | 算奖牌型叠加层关闭时 `SpriteCopyUtils.removeRange` 已清理 | §5.6a |
| 9 | 冲关牌型叠加层关闭时 `SpriteCopyUtils.removeRange` 已清理 | §5.6a |
| 10 | `EQW_Layout` 与 `Game_Modify.PLAYER_INFO_LAYOUT` 的头像框坐标一致 | §6.11 |
| 11 | 丢弃 `this.data`、仅凭最近一次服务端快照重画,界面完全一致 | 前端 05 §6.2 |
| 12 | 所有布局参数都在配置文件里,业务代码无裸值 | §6 |
@@ -1936,9 +1948,9 @@ data.bottom.cards // 结算包
| `docs/compliance/*.md`(3 份,24 处) | ⬜ **有意不改**——这三份是历次核对的**历史记录**,反映当时的 design 表述;下轮核对按新 design 重做即可,不追溯修改 |
| `test/*.js` 其余注释(约 14 处) | ⬜ 仅注释、不影响行为,后续顺手清理 |
#### S-6 · 大局结算缺「基础分 / 算奖分 / 傍王分」三项分解(新增,⚠️ 阻塞 D-9)
#### S-6 · 大局结算缺「基础分 / 冲关分 / 傍王分」三项分解(新增,⚠️ 阻塞 D-9)
**需求**:大局结算面板每行要显示 `基础分{n}` / `总得分{n}` / `算奖分{n}` / **`傍王分{n}`** 四项(见 `大局结算.png`)。
**需求**:大局结算面板每行要显示 `基础分{n}` / `总得分{n}` / `冲关分{n}` / **`傍王分{n}`** 四项(见 `大局结算.png`)。
**现状**:协议 `account` 分组只有
@@ -1949,14 +1961,14 @@ data.bottom.cards // 结算包
拿不出上面四项中的任何一项分解。小局包 `aset.seatlist[i]` 虽有 `grade_jf`(捡分子数得分)与 `grade_aw`(算奖得分),但:
1. **只有小局值,没有大局累计**——大局要的是全部局数的累加;
2. **傍王分拆不出来**。这是最麻烦的一条:`naward = (庄家?常规算奖:0) + (傍王?王数:0)`,两个来源在**求和之后**才拿去算钱(`grade_aw = X×(2Ni−Nj−Nk)`)。等于说常规算奖与傍王的贡献在算钱前就已经混在一个 `N` 里,**事后无法从 `grade_aw` 反推各自占多少**。
2. **傍王分拆不出来**。这是最麻烦的一条:`naward = (庄家?冲关:0) + (傍王?王数:0)`,两个来源在**求和之后**才拿去算钱(`grade_aw = X×(2Ni−Nj−Nk)`)。等于说冲关与傍王的贡献在算钱前就已经混在一个 `N` 里,**事后无法从 `grade_aw` 反推各自占多少**。
**建议实现**:在 `class.paiju.js` 算 `grade_aw` 的地方,把 `N` 拆成 `N_chongguan` 与 `N_bangwang` **分别代入同一公式**各算一次,得到两个分量后再相加(相加结果必须等于现在的 `grade_aw`,可作为回归断言)。然后在 `account` 里逐项累计下发,例如:
**建议实现**:在 `class.paiju.js` 算 `grade_aw` 的地方,把 `N` 拆成 `N_chongguan`(冲关)与 `N_bangwang`(傍王)**分别代入同一公式**各算一次,得到两个分量后再相加(相加结果必须等于现在的 `grade_aw`,可作为回归断言)。然后在 `account` 里逐项累计下发,例如:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `grade_base_total` | 整数 | 基础分(捡分子数得分 `grade_jf`)的大局累计 |
| `grade_aw_total` | 整数 | 常规算奖分的大局累计(**不含**傍王) |
| `grade_cg_total` | 整数 | **冲关分**的大局累计(**不含**傍王) |
| `grade_bw_total` | 整数 | 傍王分的大局累计 |
| `score` | 整数 | 总得分(已有) |
@@ -1995,5 +2007,5 @@ data.bottom.cards // 结算包
| `docs/client/development-guide/` | **前端规范权威源**。ID 范围、组件范式、红线均以其为准 |
| `docs_dev/uiref/*.png` | 参考图,16 张(牌桌态 + 叫分按钮面板 + 大局结算 + 强甩失败 + 等待庄家选主 + 1 张建房**样式范式**,末者内容属他游戏、不可照抄) |
| `client/js/gameabc-framework/ui/AlignmentUtils.js` | **布局求解的框架能力**。§6 的配置参数名与其入参一一对应,配置可原样喂入 |
| `client/js/gameabc-framework/ui/SpriteCopyUtils.js` | 精灵复制。用于算奖牌型、大局结算玩家栏、出牌历史 / 明牌(§5.6a 判据表) |
| `client/js/gameabc-framework/ui/SpriteCopyUtils.js` | 精灵复制。用于冲关牌型、大局结算玩家栏、出牌历史 / 明牌(§5.6a 判据表) |
| `client/js/gameabc-framework/templates/*.template.js` | 常量文件写法蓝本。本清单落地为常量文件时按其格式 |