diff --git a/docs_dev/uiref/叫分按钮面板.png b/docs_dev/uiref/叫分按钮面板.png index d28fc5b..9b07448 100644 Binary files a/docs_dev/uiref/叫分按钮面板.png and b/docs_dev/uiref/叫分按钮面板.png differ diff --git a/docs_dev/二七王-UI资源与精灵清单.md b/docs_dev/二七王-UI资源与精灵清单.md index f7be01d..d8faa3f 100644 --- a/docs_dev/二七王-UI资源与精灵清单.md +++ b/docs_dev/二七王-UI资源与精灵清单.md @@ -13,6 +13,7 @@ ## 目录 - [0. 总则](#0-总则) + - [0.0 术语(本项目修订版)](#00-术语本项目修订版优先于-designmd) - [0.1 设计基准与座位映射](#01-设计基准与座位映射) - [0.2 平台已提供、子游戏不重建的部分](#02-平台已提供子游戏不重建的部分) - [0.3 ID 号段规划](#03-id-号段规划) @@ -38,6 +39,21 @@ ## 0. 总则 +### 0.0 术语(本项目修订版,优先于 design.md) + +**2026-08-25 修订**:原 design.md 里「暗牌 / 底牌」的命名与界面按钮倒挂,现统一为: + +| 术语 | 指哪 8 张 | design.md 原称 | 当前协议字段 | +| --- | --- | --- | --- | +| **底牌** | 发牌时**没有发给玩家**、留在桌面的 8 张 | ~~暗牌~~ | `shangzhuang.bottomcards`、`ChooseMain`/`BuryCards.bottomcards` | +| **埋牌底牌** | 庄家埋牌时从手里扣下的 8 张 | ~~底牌~~ | `maipai.bottomcards`、`PushCards.bottomcards`、结算 `bottom.cards` | + +其余术语(埋牌、扣底、甩牌、毙牌、垫牌、捡分、子、奖…)沿用 design.md §1 不变。注意「**扣底**」仍指 design §6.3 那条规则——闲家用主牌赢下最后一轮后翻开**埋牌底牌**计分;底栏那个 `扣底` 按钮是「查看埋牌底牌」的入口,两者同名但不同义。 + +> ⚠️ **design.md 与 packet_protocol.md 尚未同步此变更**(见 §7.5 **S-5**)。在同步前,读那两份文档时要做一次心算转换;协议里两批牌**共用 `bottomcards` 字段名**,需按所在包判断语义(拆分建议见 **S-4**)。 + +--- + ### 0.1 设计基准与座位映射 | 项 | 值 | 来源 | @@ -129,9 +145,9 @@ get_nextseat: function(seat){ return (seat + 1) % 3; } | --- | --- | --- | | **101** | `EQW_Table_Static` | 牌桌常驻:顶部信息条、玩家位附加标记、亮牌信息条、底栏(局数 + 功能钮) | | **102** | `EQW_Hand` | 自己手牌区(单排 / 埋牌双排) | -| **103** | `EQW_TableCards` | 桌面牌:暗牌区、三家已出牌区、底牌展示区 | +| **103** | `EQW_TableCards` | 桌面牌:底牌区、三家已出牌区、埋牌底牌展示区 | | **104** | `EQW_Action` | 阶段操作区:叫分面板、选主/投降面板、埋牌/出牌操作条、倒计时 | -| **105** | `EQW_Overlay` | 桌面浮层:提示气泡、报无主、甩错、捡分飘字、70 分暗牌亮 3 秒 | +| **105** | `EQW_Overlay` | 桌面浮层:提示气泡、报无主、甩错、捡分飘字、70 分底牌亮 3 秒 | | **302** | `EQW_Popup_AsetResult` | 小局结算 | | **303** | `EQW_Popup_Account` | 大局总结算 / 解散结算 | | **304** | `EQW_Popup_History` | 出牌历史面板 | @@ -149,9 +165,9 @@ get_nextseat: function(seat){ return (seat + 1) % 3; } | 205 | 底栏功能按钮组(明牌 / 已出牌 / 上一轮 / 底牌) | | 206 | 亮牌信息条 | | 210 | 自己手牌 | -| 211 | 暗牌区(8 张) | +| 211 | 底牌区(发牌留桌 8 张) | | 212 / 213 / 214 | 自己 / 左上家 / 右上家 的已出牌区 | -| 215 | 底牌展示区(结算时 8 张) | +| 215 | 埋牌底牌展示区(结算时 8 张) | | 220 | 叫分面板 | | 221 | 选主 / 投降面板 | | 222 | 埋牌操作条 | @@ -171,7 +187,7 @@ get_nextseat: function(seat){ return (seat + 1) % 3; } | 1001–1099 | 顶部信息条 + 亮牌条 + 底栏(局数、功能钮) | ~30 | | 1100–1199 | 三家玩家位附加标记 + 三处倒计时 | ~24 | | 1200–1249 | 自己手牌 36 张 + 牌上标记 | ~45 | -| 1250–1299 | 暗牌 8 张 + 底牌 8 张 | 16 | +| 1250–1299 | 底牌 8 张 + 埋牌底牌 8 张 | 16 | | 1300–1399 | 自己已出牌区(28 张 + 牌型标签) | ~30 | | 1400–1499 | 左上家已出牌区(28 张 + 牌型标签) | ~30 | | 1500–1599 | 右上家已出牌区(28 张 + 牌型标签) | ~30 | @@ -269,9 +285,9 @@ var CARD_BACK_FRAME = 55; // 牌背(二七王固定用牌背 | 资源 ID | 键名 | 用途 | 单帧尺寸 | 整图尺寸 (10×6) | | --- | --- | --- | --- | --- | -| 501 | `CARD_FACE_L` | 自己手牌、暗牌区 | **110 × 190** | 1100 × 1140 | +| 501 | `CARD_FACE_L` | 自己手牌、底牌区 | **110 × 190** | 1100 × 1140 | | 502 | `CARD_FACE_M` | 三家已出牌区 | **90 × 155** | 900 × 930 | -| 503 | `CARD_FACE_S` | 结算底牌区 | **50 × 70** | 500 × 420 | +| 503 | `CARD_FACE_S` | 结算埋牌底牌区 | **50 × 70** | 500 × 420 | > 单帧尺寸为参考图实测估值(§6),出图前请与最终设计稿核对。三套的**帧排列完全一致**,只有尺寸不同,`cardIdToFrame` 对三套通用。 @@ -290,7 +306,7 @@ var CARD_BACK_FRAME = 55; // 牌背(二七王固定用牌背 本节按 design §12.3 的阶段顺序走,每节说明**该阶段收哪些包、渲染什么、哪些 UI 显隐**。资源与精灵的完整表在 §3 / §5,本节只引用不重复。 ``` -建房(§1.1) → 发牌(§1.2) → 叫分坐庄(§1.3) → 看暗牌·上庄(§1.4) → 选主/投降(§1.5) → 埋牌(§1.6) +建房(§1.1) → 发牌(§1.2) → 叫分坐庄(§1.3) → 看底牌·上庄(§1.4) → 选主/投降(§1.5) → 埋牌(§1.6) → 出牌对局(§1.7) → 末轮扣底 + 小局结算(§1.8) → 大局结算(§1.9) → 解散(§1.10) → 重连(§1.11) ``` @@ -409,7 +425,7 @@ EQW_RoomOptions = { | --- | --- | | 底栏局数显示 `1/4 局` | §2.6 底栏 · 局数文字 | | 自己手牌 28 张,按主牌顺序排序后铺开 | §2.7 手牌区(群组 210) | -| 桌面中央 8 张暗牌**背面** | 暗牌区(群组 211,帧 = 牌背 55) | +| 桌面中央 8 张底牌**背面** | 底牌区(群组 211,帧 = 牌背 55) | | 顶部信息条清零:主 = 无、叫分 = 0、抓分 = 0 | §2.1 顶部信息条 | | 三家玩家位状态文字清空,`主N/对N` 角标隐藏 | §2.2 玩家位附加标记 | | 倒计时显示在 `seat` 对应的位置 | §2.4 倒计时 | @@ -425,14 +441,14 @@ EQW_RoomOptions = { | 状态 | 参考图 | 表现 | | --- | --- | --- | -| 等待他家叫分 | `等待叫分.png` | 中央保持 8 张暗牌背面;倒计时数字显示在**当前叫分者**的位置旁;已叫分的玩家位显示金色 `60分` 大字,未叫的为空 | +| 等待他家叫分 | `等待叫分.png` | 中央保持 8 张底牌背面;倒计时数字显示在**当前叫分者**的位置旁;已叫分的玩家位显示金色 `60分` 大字,未叫的为空 | | 轮到自己叫分 | `自己叫分.png` | 中央弹出**叫分面板**(14 档按钮,两行 × 7)+ `不叫` 按钮;顶部一条提示 `70分坐庄才可投降`;倒计时移到自己操作区 | | 自己已叫、轮到下家 | `自己已经叫分轮到下家叫分.png` | 叫分面板收起,中央显示自己刚叫的 `50分` 金色大字;已表态的玩家位显示 `不叫` 白色大字 | **叫分面板规格**(群组 220,号段 1600–1649): - 14 档:`70 65 60 55 50 45 40 35 30 25 20 15 10 5`,两行 × 7(行1 = 70…40,行2 = 35…5)。 -- 每档 4 个精灵:按钮底 + 分数文字 + 角标底 + **子数角标文字**。 +- 每档 3 个精灵:按钮底(**含角标底,同一张图**)+ 分数数字精灵 + 角标子数文字精灵。 - 角标显示该档的 `multiple`,**随房间「爬坡」开关取值**(协议 §3): - 常规算子:65→2、60→3、55→4、**50 及以下统一 →6**、70→2 - 爬坡:65→2、60→3、55→4、50→6、45→7、40→8、35→9、30→10、25→11、20→12、15→13、10→14、5→15、70→2 @@ -449,14 +465,25 @@ EQW_RoomOptions = { > > 反证:常规算子下 50/45/40 与 35…5 的 `multiple` 同为 6 子,但参考图里它们是两种颜色。 -**灰色 = 已经叫过的分数**(不可再叫)。故按钮底与角标底各 **4 帧**: +**灰色 = 已经叫过的分数**(不可再叫)。**颜色只因「不可叫」变灰,不随子数档位变化。** -| 帧 | 按钮底 | 角标底 | +**按钮底与右上角角标(不含文字)画在同一张图上**,即一个精灵一帧就同时包含按钮底色和角标底色。共 **4 帧**: + +| 帧 | 内容 | +| --- | --- | +| 1 | 浅黄按钮底 + 蓝角标底(高分档 70/65/60/55) | +| 2 | 金黄按钮底 + 绿角标底(中分档 50/45/40) | +| 3 | 橙按钮底 + 深橙角标底(低分档 35…5) | +| 4 | **灰按钮底 + 灰角标底(已叫过 / 不可选)** | + +**两种数字,两种精灵**: + +| 元素 | 精灵类型 | 说明 | | --- | --- | --- | -| 1 | 浅黄(高分档) | 蓝 | -| 2 | 金黄(中分档) | 绿 | -| 3 | 橙(低分档) | 深橙 | -| 4 | **灰(已叫过 / 不可选)** | 灰 | +| **叫分的分数**(70/65/…/5) | **数字精灵**(图片多帧,资源 `NUM_CALL_SCORE`) | 带描边、需与图一致的美术字 | +| **角标的子数**(`2子`/`7子`…) | **文字精灵**(`SpriteManager.setText`) | 随爬坡开关动态变,值域 2–15,用文字精灵最省 | + +故每档 **3 个精灵**:按钮底(含角标底)+ 分数数字精灵 + 角标文字精灵。 - 可选性规则(design §4.2,**由服务端权威 `currcall` 决定,前端只据其置灰、不自行推导规则**): - 暂定庄家首叫:5–70 全部可选,**无 `不叫`**; - 其后:只有**严格低于 `currcall`** 的档位可选,`不叫` 可选。 @@ -465,16 +492,16 @@ EQW_RoomOptions = { **上方提示条** `70分坐庄才可投降`:静态文字条,仅在叫分面板展开时显示。 -### 1.4 看暗牌 / 上庄 `shangzhuang` 【部分待设计】 +### 1.4 看底牌 / 上庄 `shangzhuang` 【部分待设计】 **收包字段**:`seat`、`call`、`banker`、`grade`(庄家叫分)、`multiple`、`bottomcards`、`ancard3s`、`cards`、`countdown`、`touxiang`。 | 分支 | 条件 | 表现 | | --- | --- | --- | -| 常规坐庄 | 无 `ancard3s` | 庄家收到 `bottomcards`(8 张)与 `cards`(36 张)→ 暗牌翻正面短暂展示后并入手牌;闲家**收不到** `bottomcards`,暗牌区直接收起 | -| **70 分坐庄** | `ancard3s === 1` | **全场三家都收到 `bottomcards`** → 8 张暗牌翻正面**向所有玩家亮 3 秒**(design §4/§7.1),3 秒后庄家摸入手牌、闲家侧收起 | +| 常规坐庄 | 无 `ancard3s` | 庄家收到 `bottomcards`(8 张)与 `cards`(36 张)→ 底牌翻正面短暂展示后并入手牌;闲家**收不到** `bottomcards`,底牌区直接收起 | +| **70 分坐庄** | `ancard3s === 1` | **全场三家都收到 `bottomcards`** → 8 张底牌翻正面**向所有玩家亮 3 秒**(design §4/§7.1),3 秒后庄家摸入手牌、闲家侧收起 | -- **70 分亮 3 秒** 【待设计】:需要一个覆盖提示(如「70 分坐庄 · 暗牌公示」标题 + 3 秒倒计时),图层 105 群组 230。 +- **70 分亮 3 秒** 【待设计】:需要一个覆盖提示(如「70 分坐庄 · 底牌公示」标题 + 3 秒倒计时),图层 105 群组 230。 - 上庄后统一更新:顶部信息条 `叫分` 列 = `grade`、角标 = `multiple`;`banker` 对应玩家位显示 **`庄` 印章**(含底栏自己位)。 - 三处 `庄` 印章是三个独立精灵(左上 / 右上 / 底栏),按 `banker` 显隐其一。 - **重连不重放**:协议明确 70 分的 3 秒亮牌是上庄时的一次性事件,`deskinfo` 重连**不重放**——前端不得在重连时补播。 @@ -634,7 +661,7 @@ EQW_RoomOptions = { **结算包三种来源**(协议 §14):正常出牌结算(`chupai` + `bottom` + `aset`)、投降结算(只 `aset`)、解散结算(见 §1.10,投递方式完全不同)。 **扣底表现**(`bottom` 分组,design §6.3): -- `cards`(8 张底牌)**恒有** → 底牌区(群组 215,资源 `CARD_FACE_S`)翻开展示,design §11 明确「牌局结束需要亮出底牌」; +- `cards`(8 张**埋牌底牌**)**恒有** → 埋牌底牌区(群组 215,资源 `CARD_FACE_S`)翻开展示,design §11 明确「牌局结束需要亮出底牌」; - `multiple` / `grade1` / `grade2` **仅闲家扣底时才有** → 展示 `底牌 20 × 4` 之类的翻倍算式。 - 文案格式:`叫分{aset.multiple}子 底牌 {bottom.grade1}x{bottom.multiple}`——**`x` 后面是扣底倍数**(design §6.3:单张 ×1、主对 ×2、N 连对 ×2N)。参考图 `底牌 20x0` 即底牌有 20 分、扣底倍数 0(本局闲家未扣底)。 - 闲家未扣底时 `bottom` 只有 `cards`,`multiple`/`grade1`/`grade2` 都不下发 → 倍数位显示 **0**。 @@ -746,7 +773,7 @@ EQW_RoomOptions = { **关键点**: - `playproc.cards`(当前轮桌面上的牌)**两种查牌模式下都有** —— 否则后出的人无从跟牌; - `pushlist`(往轮历史)与 `seatlist` **仅可查牌模式有** —— 不查牌模式下前端不得渲染出牌历史; -- 70 分的 3 秒亮暗牌**不重放**; +- 70 分的 3 秒亮底牌**不重放**; - **验收判据**(前端 05 §6.2):任意时刻丢弃 `this.data`、仅凭最近一次服务端快照重画,界面必须完全一致。做不到即「前端私存了状态」或「服务端漏发了字段」,两者都要修。 ### 1.12 准备 `zhunbei` @@ -837,23 +864,28 @@ y≈648–720 深色条。左侧头像/昵称/分数由平台渲染(§0.2) | `上一轮` | **上一轮**所有人出的牌 | 可查牌 + 出牌阶段 + 已打过至少一轮 | | `出牌历史` | 所有人**出过的全部牌** | 可查牌 + 出牌阶段 | | `明牌` | 另两家手中全部主牌的具体牌面 | 可查牌 + 出牌阶段 + **已报无主** | -| **`扣底`** | **庄家查看自己埋的 8 张底牌** | **仅庄家** + 已埋牌之后 | -| **`底牌`** | **发牌时桌面留下的 8 张暗牌** | 见下方可见性问题 S-3 | +| **`扣底`** | **埋牌底牌**:庄家埋下的 8 张 | **仅庄家** + 已埋牌之后 | +| **`底牌`** | **底牌**:发牌时没发给玩家、留在桌面的 8 张 | 庄家全程;闲家仅 70 分坐庄局(S-3) | -> ### ⚠️ 术语陷阱:底栏「底牌」按钮看的不是「底牌」 +> ### 术语已统一:按钮名 = 术语名 > -> design 术语表:**暗牌** = 发牌时留在桌面的 8 张;**底牌** = 庄家埋牌时重新扣下的 8 张。两者是**不同批的牌,不通用、不互换**。 +> **本项目采用修订后的术语**(2026-08-25 定,取代 design.md 原表述): > -> 底栏按钮的命名恰好**与术语相反**: +> | 新术语 | 指哪 8 张 | design.md 原称 | +> | --- | --- | --- | +> | **底牌** | 发牌时**没有发给玩家**、留在桌面的 8 张 | ~~暗牌~~ | +> | **埋牌底牌** | 庄家埋牌时从手里扣下的 8 张 | ~~底牌~~ | > -> | 按钮 | 实际展示 | design 术语 | 协议字段 | +> 改后底栏按钮**名实相符**:`底牌` 按钮看底牌、`扣底` 按钮看埋牌底牌,不再有命名倒挂。 +> +> **但协议字段目前仍两批共用 `bottomcards`**,只靠「在哪个包」区分语义,仍是易错点: +> +> | 按钮 | 展示 | 当前协议字段 | 建议改名(S-4) | > | --- | --- | --- | --- | -> | `扣底` | 庄家埋的 8 张 | **底牌** | `maipai.bottomcards` / `PushCards.bottomcards`(仅庄家)/ 结算 `bottom.cards` | -> | `底牌` | 发牌留桌的 8 张 | **暗牌** | `shangzhuang.bottomcards`(庄家恒有,闲家仅 70 分时有)/ `ChooseMain`·`BuryCards.bottomcards`(仅庄家) | +> | `底牌` | 底牌(发牌留桌 8 张) | `shangzhuang.bottomcards`(庄家恒有,闲家仅 70 分时有)、`ChooseMain`/`BuryCards.bottomcards`(仅庄家) | 保持 `bottomcards` | +> | `扣底` | 埋牌底牌(庄家埋的 8 张) | `maipai.bottomcards`、`PushCards.bottomcards`(仅庄家)、结算 `bottom.cards` | 改为 **`burycards`** | > -> 更容易踩的是:协议里这**两批牌用了同一个字段名 `bottomcards`**,只靠「在哪个包/哪个阶段」区分语义。 -> -> **实现要求**:前端内部一律用 `anCards`(暗牌)/ `diCards`(底牌)两个不同变量名,**不要跟着按钮文案命名**;取值时按所在包判断语义。已列入验收清单(§7.3)。 +> **实现要求**:前端内部用 `bottomCards`(底牌)/ `buryCards`(埋牌底牌)两个变量名区分;在 S-4 落地前,取值时必须按**所在包**判断 `bottomcards` 的语义。已列入验收清单(§7.3)。 - 精灵:群组 205,号段 1040–1069(5 个按钮 × 2 精灵 = 10)。 @@ -864,7 +896,7 @@ y≈648–720 深色条。左侧头像/昵称/分数由平台渲染(§0.2) | **单排**(叫分 / 出牌) | 最多 36 | y≈455–645,x≈35–1250,重叠排列 | | **双排**(庄家埋牌) | 36(17 + 19) | 上排 y≈285–455,下排 y≈455–645 | -- 建 **36 个手牌精灵**(庄家摸暗牌后的上限),资源 `CARD_FACE_L`。 +- 建 **36 个手牌精灵**(庄家摸底牌后的上限),资源 `CARD_FACE_L`。 - 张数少于 36 时隐藏多余精灵并重算间距。 - 选中态:牌**上浮**(Y 偏移),另可叠加选中标记。 - 牌上标记(`拖` 圆标、⭐、🔵)见 T-8。 @@ -881,9 +913,9 @@ y≈648–720 深色条。左侧头像/昵称/分数由平台渲染(§0.2) | ID | 键名 | 用途 | 帧数 | 帧说明 | 单帧尺寸 | 整图 | | --- | --- | --- | --- | --- | --- | --- | -| 501 | `CARD_FACE_L` | 手牌、暗牌 | **60** | 见 §0.4 帧表(10×6 通用排版) | 110 × 190 | 1100 × 1140 | +| 501 | `CARD_FACE_L` | 手牌、底牌 | **60** | 见 §0.4 帧表(10×6 通用排版) | 110 × 190 | 1100 × 1140 | | 502 | `CARD_FACE_M` | 已出牌区 | **60** | 同上 | 90 × 155 | 900 × 930 | -| 503 | `CARD_FACE_S` | 结算底牌区 | **60** | 同上 | 50 × 70 | 500 × 420 | +| 503 | `CARD_FACE_S` | 结算埋牌底牌区 | **60** | 同上 | 50 × 70 | 500 × 420 | ### 3.2 花色图标 @@ -898,7 +930,7 @@ y≈648–720 深色条。左侧头像/昵称/分数由平台渲染(§0.2) | ID | 键名 | 用途 | 帧数 | 帧说明 | 尺寸 | | --- | --- | --- | --- | --- | --- | -| 531 | `BTN_CALL_SCORE` | 叫分档位按钮底 | 3 | 帧1=可选(亮黄) 帧2=不可选(灰) 帧3=高亮(橙)【T-6】 | 74 × 56 | +| 531 | `BTN_CALL_SCORE` | 叫分档位按钮底 **+ 右上角角标底(同一张图,不含文字)** | **4** | 帧1=浅黄+蓝角标(70/65/60/55) 帧2=金黄+绿角标(50/45/40) 帧3=橙+深橙角标(35…5) 帧4=**灰**(已叫过/不可选)。**颜色按档位位置固定,只因不可叫变灰** | 74 × 56 | | 532 | `BTN_NO_CALL` | `不叫` | 1 | 蓝色渐变 | 184 × 57 | | 533 | `BTN_SUIT_CHOOSE` | 选主花色按钮底 | 1 | 金黄底 | 128 × 55 | | 534 | `BTN_SURRENDER` | `投降` | 1 | 金黄底 | 128 × 55 | @@ -943,11 +975,13 @@ y≈648–720 深色条。左侧头像/昵称/分数由平台渲染(§0.2) | ID | 键名 | 用途 | 帧数 | 帧说明 | 尺寸 | | --- | --- | --- | --- | --- | --- | | 631 | `NUM_COUNTDOWN` | 倒计时数字 | 10 | 帧1–10 = 0–9 | 44 × 60 | +| 635 | `NUM_CALL_SCORE` | **叫分档位的分数数字**(深棕描边美术字) | 10 | 帧1–10 = 0–9 | 30 × 40 | | 632 | `NUM_RESULT_WIN` | 结算得分数字(赢,橙) | 12 | 帧1–10 = 0–9,帧11 = `+`,帧12 = `-` | 46 × 62 | | 633 | `NUM_RESULT_LOSE` | 结算得分数字(输,蓝) | 12 | 同上 | 46 × 62 | | 634 | `TXT_JUDGE` | 判定结果文字 | ≥5 | 帧1=大光 帧2=小光 帧3=过庄 帧4=升级 帧5=投降【待设计】 | 待定 | -> **数字一律用图片多帧精灵**(不用 `SpriteManager.setText`)——参考图里的数字都带描边与渐变,文字精灵做不出这种效果。故 631–634 全部需要出图。 +> **带描边/渐变的美术字用图片多帧精灵**(倒计时、结算得分、叫分分数),文字精灵做不出这种效果——631–635 都要出图。 +> **纯数据型小字用文字精灵**(`SpriteManager.setText`):叫分角标的子数(值域 2–15,随爬坡开关变)、`主N`/`对N` 角标、局数、亮牌统计等。 ### 3.7 浮层与气泡 @@ -957,7 +991,7 @@ y≈648–720 深色条。左侧头像/昵称/分数由平台渲染(§0.2) | 652 | `TXT_BAOZHU` | 「报无主」提示【待设计】 | 1 | 待定 | 待定 | | 653 | `TXT_SHUAICUO` | 「甩错」提示【待设计】 | 1 | 待定 | 待定 | | 654 | `TXT_GRADE_FLOAT` | 捡分飘字底(`20分` 金色) | 1 | 待定 | 待定 | -| 655 | `PANEL_ANCARD_3S` | 70 分暗牌公示 3 秒的标题/边框【待设计】 | 1 | 待定 | 待定 | +| 655 | `PANEL_BOTTOM_3S` | 70 分底牌公示 3 秒的标题/边框【待设计】 | 1 | 待定 | 待定 | ### 3.8 建房选项 @@ -1056,8 +1090,8 @@ design 与协议均**未定义任何音效**。以下是按牌类游戏常规推 | 群组 | 精灵 ID | 键名 | 类型 | 用途 | 资源 / 帧 | | --- | --- | --- | --- | --- | --- | -| **211** 暗牌 | 1250–1257 | `DARK_CARD_1..8` | 图片 ×8 | 8 张暗牌;未揭示时帧 = 55 牌背,70 分公示 / 庄家查看时翻正面 | `CARD_FACE_L` | -| **215** 底牌 | 1258–1265 | `BOTTOM_CARD_1..8` | 图片 ×8 | 结算时亮出的底牌 | `CARD_FACE_S` | +| **211** 底牌 | 1250–1257 | `BOTTOM_CARD_1..8` | 图片 ×8 | 底牌(发牌留桌 8 张);未揭示时帧 = 55 牌背,70 分公示 / 庄家查看时翻正面 | `CARD_FACE_L` | +| **215** 埋牌底牌 | 1258–1265 | `BURY_CARD_1..8` | 图片 ×8 | 结算时亮出的埋牌底牌 | `CARD_FACE_S` | | **212** 自己出牌 | 1300–1327 | `PLAY_SELF_1..28` | 图片 ×28 | 本轮打出的牌 | `CARD_FACE_M` | | | 1328 | `PLAY_SELF_TYPE_BG` | 图片 | 牌型标签 | `LABEL_CARDTYPE` | | | 1329 | `PLAY_SELF_TYPE_TEXT` | 文字 | 标签文案 | —— | @@ -1071,9 +1105,9 @@ design 与协议均**未定义任何音效**。以下是按牌类游戏常规推 | **220** 叫分面板 | 1600 | `CALL_PANEL_BG` | 图片 | 面板底 | `PANEL_CALL_SCORE` | | | 1601 | `CALL_HINT_BG` | 图片 | 提示条底 | `BAR_HINT_TOP` | | | 1602 | `CALL_HINT_TEXT` | 文字 | `70分坐庄才可投降` | —— | -| | 1603–1616 | `CALL_BTN_1..14` | 图片 ×14 | 档位按钮底(70…5) | `BTN_CALL_SCORE` 帧1可选/帧2灰/帧3高亮 | -| | 1617–1630 | `CALL_BTN_TEXT_1..14` | 文字 ×14 | 档位分数 | —— | -| | 1631–1644 | `CALL_BTN_BADGE_1..14` | 文字 ×14 | 该档 `multiple` 子数角标 | —— | +| | 1603–1616 | `CALL_BTN_1..14` | 图片 ×14 | 档位按钮底(**含角标底**,70…5) | `BTN_CALL_SCORE` 帧1–3 按档位位置固定 / 帧4 灰 | +| | 1617–1630 | `CALL_BTN_NUM_1..14` | **图片(数字精灵)** ×14 | 档位分数(70…5) | `NUM_CALL_SCORE` | +| | 1631–1644 | `CALL_BTN_BADGE_1..14` | **文字** ×14 | 该档 `multiple` 子数(`2子`…`15子`),随爬坡开关变 | —— | | | 1645 | `CALL_BTN_NONE` | 图片 | `不叫` | `BTN_NO_CALL` | | | 1646 | `CALL_BTN_NONE_TEXT` | 文字 | —— | —— | | **221** 选主面板 | 1650 | `MAIN_TITLE_BG` | 图片 | `亮主` 斜角条 | `BAR_CHOOSE_MAIN` | @@ -1106,7 +1140,7 @@ design 与协议均**未定义任何音效**。以下是按牌类游戏常规推 | 1754 | `TXT_SHUAICUO` | 图片 | 甩错提示【待设计】 | `TXT_SHUAICUO` | | 1755 | `GRADE_FLOAT_BG` | 图片 | 捡分飘字底 | `TXT_GRADE_FLOAT` | | 1756 | `GRADE_FLOAT_TEXT` | 文字 | `20分` | —— | -| 1757 | `ANCARD_3S_PANEL` | 图片 | 70 分暗牌公示框【待设计】 | `PANEL_ANCARD_3S` | +| 1757 | `BOTTOM_3S_PANEL` | 图片 | 70 分底牌公示框【待设计】 | `PANEL_BOTTOM_3S` | | 1758 | `ANCARD_3S_TEXT` | 文字 | 公示标题 + 3 秒倒计时 | —— | ### 5.6 Layer 302 · 小局结算(群组 240) @@ -1173,7 +1207,7 @@ for (var i = 0; i < cards.length; i++) { | **算奖牌型** | **复制** | 张数不定、无小上限,多数局用不满 | | 自己手牌(36) | 预置 | 上限确定;需逐张选中上浮、独立动画与点击 | | 已出牌区(28 × 3) | 预置 | 需叠压 z 序与出牌动画,逐张独立控制 | -| 暗牌(8)/ 底牌(8) | 预置 | 固定 8 张 | +| 底牌(8)/ 埋牌底牌(8) | 预置 | 固定 8 张 | | 建房规则选项 | 预置 | 选项集固定(4 组 8 项),数量小 | > 精灵段 1001–2999 有近 2000 个空位(§0.3),预置的 ID 开销不构成压力;复制只用在「数量真的不定」的地方,避免给每处都背上显式清理的负担。 @@ -1252,7 +1286,7 @@ for (var i = 0; i < cards.length; i++) { #### `line` — 等距排列 -数量可变但**间距固定**的一排(暗牌 8 张、底牌 8 张)。 +数量可变但**间距固定**的一排(底牌 8 张、埋牌底牌 8 张)。 ```js { kind: 'line', direction: 'horizontal', @@ -1359,9 +1393,9 @@ 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' } // 结算底牌 + S: { w: 50, h: 70, res: 'CARD_FACE_S' } // 结算埋牌底牌 } ``` @@ -1419,8 +1453,8 @@ CARD_SIZE: { | **自己手牌 · 单排** | `fan` | `anchorX:640 anchorY:455 maxWidth:1215 size:L spacingMax:0 spacingMin:-78 anchor:center overlapFrom:left`。36 张时算出 `spacing = 1215−110)/35 − 110 ≈ −78`,即每张露 32px,与参考图实测 33px 吻合 | | **自己手牌 · 双排(埋牌)** | `fan` ×2 | 上排 `anchorX:644 anchorY:285 maxWidth:928 size:L spacingMin:-65`;下排 `anchorX:644 anchorY:455 maxWidth:928 size:L spacingMin:-65`。**分行策略:上排 `floor(n/2)`、下排 `ceil(n/2)`**(36 张 = 18/18)。参考图的 17/19 无规则依据,按 mock 处理 | | 手牌 · 选中上浮 | —— | `selectedOffsetY: -40`(配置项,不写死) | -| **暗牌区** | `line` | `anchorX:655 anchorY:110 size:L spacing:-36 anchor:center`(8 张) | -| **底牌区(结算)** | `line` | `anchorX:640 anchorY:163 size:S spacing:2 anchor:center`(8 张) | +| **底牌区** | `line` | `anchorX:655 anchorY:110 size:L spacing:-36 anchor:center`(8 张) | +| **埋牌底牌区(结算)** | `line` | `anchorX:640 anchorY:163 size:S spacing:2 anchor:center`(8 张) | | **已出牌区** | `fan` | 见 §6.2 的 `bySeat` 示例(三家共用 base,LEFT 镜像) | | 已出牌 · 牌型标签 | `attach` | `target:该区首张牌, corner:bottomLeft, offsetX:0, offsetY:-24` | | 已出牌 · 牌角 `庄`/`大` 标 | `attach` | `target:对应牌, corner:topRight, offsetX:-28, offsetY:0` | @@ -1529,7 +1563,7 @@ codes/config/ | 编号 | 界面 | 所属 | 说明 | | --- | --- | --- | --- | | D-1▲ | 建房规则选项区 | §1.1 | 样式范式与内容已定(3 类别 / 4 选项组),缺二七王定稿与在 Layer 27 内的确切尺寸位置 | -| D-2 | 70 分暗牌公示(3 秒) | §1.4 | 全场可见的暗牌展示 + 倒计时 | +| D-2 | 70 分底牌公示(3 秒) | §1.4 | 全场可见的底牌展示 + 倒计时 | | D-3 | 甩错提示 | §1.7 | 整套收回、只出最小一张的表现 | | D-4 | 报无主提示 | §1.7 | 玩家主牌出空时的全场提示 | | ~~D-5~~ | ~~踩 / 没分 / 有分 气泡与入口~~ | §1.7 | **已定**:入口 = 底栏三按钮(占庄标区);气泡 3×2 六帧、按头像相对位置选朝向 | @@ -1540,7 +1574,7 @@ codes/config/ | D-10 | 解散结算 | §1.10 | 投票界面平台全包(Layer 420),只剩结算面板,可复用 D-9 | | ~~D-11~~ | ~~准备标识~~ | §1.12 | **已定**:用平台准备标识,子游戏不做 | | ~~D-12~~ | ~~左上家已出牌区~~ | §2.3 | **已定**:与右上家左右镜像 | -| **D-13** | **`扣底` 按钮的查看面板** | §2.6 | 新增:庄家查看自己埋的 8 张底牌;可与 `底牌`(看暗牌)复用同一个「8 张牌」展示面板,仅数据源不同 | +| **D-13** | **`扣底` 按钮的查看面板** | §2.6 | 庄家查看自己埋的 8 张**埋牌底牌**;可与 `底牌` 按钮复用同一个「8 张牌」展示面板,仅数据源不同 | ### 7.2 待确认的规格问题 @@ -1569,9 +1603,9 @@ codes/config/ | ~~T-13~~ | 结算两个小字 = `牌局分`(`grade_jf`) / `算奖分`(`grade_aw`) | | ~~T-14~~ | 算奖明细走独立的**算奖牌型叠加层** | | ~~T-15~~ | 准备标识**用平台的** | -| ~~T-16~~ | `抓分` 角标 = **当前抓分的倍数**;协议现无此字段 → **S-1** | +| ~~T-16~~ | `抓分` 角标 = **当前捡分对应判定倍率的实时预览**(大光×3/小光×2/过庄×1/升N级×N);协议现无此字段,需服务端随现有包下发 → **S-1** | | ~~T-17~~ | 倒计时归零**停在 `0`** 不隐藏 | -| ~~T-18~~ | 底栏 5 按钮:`上一轮`/`出牌历史`/`明牌`/`扣底`(庄家看底牌)/`底牌`(**看暗牌**);**术语陷阱见 §2.6**;暗牌可见性 → **S-3** | +| ~~T-18~~ | 底栏 5 按钮:`上一轮`/`出牌历史`/`明牌`/`扣底`(看**埋牌底牌**)/`底牌`(看**底牌**);术语已统一见 §2.6;可见性按手册 → **S-3** | | ~~T-19~~ | 数字**一律用图片多帧精灵**(参考图数字带描边渐变,文字精灵做不出),资源 631–634 全部要出 | | ~~T-21~~ | 手牌单排 `spacingMin:-78`、双排 `-65`(§6.7) | | ~~T-22~~ | 算奖叠加层:**全屏半透明遮罩本身即关闭热区,点击遮罩关闭**,不另设关闭钮 | @@ -1610,7 +1644,7 @@ codes/config/ | 10 | `EQW_Layout` 与 `Game_Modify.PLAYER_INFO_LAYOUT` 的头像框坐标一致 | §6.11 | | 11 | 丢弃 `this.data`、仅凭最近一次服务端快照重画,界面完全一致 | 前端 05 §6.2 | | 12 | 所有布局参数都在配置文件里,业务代码无裸值 | §6 | -| 13 | **暗牌 / 底牌未写反**:`底牌` 按钮显示暗牌、`扣底` 按钮显示底牌;内部变量用 `anCards`/`diCards` 区分 | §2.6 术语陷阱 | +| 13 | **底牌 / 埋牌底牌未写反**:`底牌` 按钮显示底牌(发牌留桌)、`扣底` 按钮显示埋牌底牌;内部变量用 `bottomCards`/`buryCards` 区分;S-4 落地前按「所在包」判断 `bottomcards` 语义 | §2.6 | | 14 | 叫分按钮配色按**档位位置**取(非按子数),已叫过的档位置灰 | §1.3 | | 15 | 自己发的提示本地回显后,收到失败回包时能撤掉 | §1.7 | @@ -1634,24 +1668,36 @@ codes/config/ 以下 3 条来自本轮确认的需求,**当前协议/服务端不支持**,需在服务端补齐后前端才能实现。三条都要同步更新 `packet_protocol.md`。 -#### S-1 · 「当前抓分的倍数」字段(对应 T-16) +#### S-1 · 「当前抓分的倍数」字段(对应 T-16)—— 语义已确认,待服务端实现 -**需求**:顶部信息条 `抓分` 列的角标要显示「当前抓分的倍数」(参考图 `45 [1倍]`)。 +**需求**:顶部信息条 `抓分` 列的角标显示「当前抓分的倍数」(参考图 `45 [1倍]`),且**牌局过程中可见并正确更新**。 -**现状**:服务端**没有任何**下发此值的字段。`chupai1/2/3` 只带 `grade`(本轮闲家得分),倍数类字段(`aset.upgrade`、`bottom.multiple`)**都要到结算包才有**——出牌过程中前端拿不到。 +**语义(已确认)**:**当前捡分对应的判定倍率的实时预览**——即「若此刻结束,是几倍」: -**建议实现**:服务端已有 `class.arith.js` 的 `get_upgrade(call, grade, q)`(返回带符号判定倍率:3 大光 / 2 小光 / 1 过庄 / −N 升 N 级),出牌过程中随时可算。在 `chupai1/2/3`(以及重连包 `PushCards`)里增加一个字段,例如: - -| 字段 | 类型 | 说明 | +| 当前捡分 `grade` 相对叫分 `call` | 判定 | 倍率 | | --- | --- | --- | -| `curmultiple` | 整数 | 按当前累计捡分实时算出的判定倍率绝对值,供顶部 `抓分` 角标显示 | +| `grade == 0` | 庄家:大光 | **×3** | +| `0 < grade < Q` | 庄家:小光 | **×2** | +| `Q ≤ grade < call` | 庄家:过庄 | **×1** | +| `grade ≥ call` | 闲家:升 N 级 | **×N** | -**需先确认语义**(本条尚未完全定死):角标要显示的到底是 -(a)**当前捡分对应的判定倍率**(大光×3 / 小光×2 / 过庄×1 / 升N级×N)的实时预览——即「若现在结束是几倍」;还是 -(b)别的口径。 -按字面「当前抓分的倍数」以及 `get_upgrade` 现成可用,(a) 最可能。**确认 (a) 之后即可动工**。 +(`Q` = 小光/过庄分界兼升级级距:常规算子固定 40,爬坡按叫分分段,见 design §7.2.0 / §7.3.2。) -> 前端**不得自算**这个值——判定倍率属服务端权威裁定(红线:服务器权威、前端只显示不自算)。 +**现状**:服务端**没有任何**下发此值的字段。`chupai1/2/3` 只带 `grade`(本轮闲家得分),倍数类字段(`aset.upgrade`、`bottom.multiple`)**都要到结算包才有**。 + +**实现要求**: + +1. 算法**已存在**:`class.arith.js` 的 `get_upgrade(call, grade, q)` 返回带符号判定倍率(3 大光 / 2 小光 / 1 过庄 / −N 升 N 级),出牌过程中随时可算。 +2. **不新开推送包**——随现有包一起下发,避免多一条推送链路: + +| 包 | 增加字段 | 类型 | 说明 | +| --- | --- | --- | --- | +| `chupai1` / `chupai2` / `chupai3` | `curmultiple` | 整数 | 按当前累计捡分实时算出的判定倍率**绝对值**(`Math.abs(get_upgrade(...))`) | +| `deskinfo.PushCards` | `curmultiple` | 整数 | 同上,供重连后立即正确显示 | +| `shangzhuang` | `curmultiple` | 整数 | 叫分刚定、`grade == 0` 时即为大光 ×3,需要一个初始值 | + +3. 三家**同值**,可整表下发,不涉及泄露(`grade` 本来就是公开信息)。 +4. 前端**不得自算**——判定倍率属服务端权威裁定(红线:服务器权威、前端只显示不自算)。 #### S-2 · 下发「应当选中的牌」(对应 T-10) @@ -1675,39 +1721,47 @@ codes/config/ **不违反「请求包只带意图」**:方向是服务端 → 前端的建议,前端仍只回传 `cards`,合法性最终由服务端校验。 -#### S-3 · 底栏「底牌」按钮的暗牌可见性(对应 T-18)⚠️ 与 design 冲突 +#### S-3 · 底牌的可见性:按手册办(对应 T-18)—— 已定 -**需求**:底栏 `底牌` 按钮让**所有人**查看发牌时的 8 张**暗牌**。 +**结论:按 design 手册**,即前述方案 (a)。底栏 `底牌` 按钮只在**能合法看到底牌**时可用: -**冲突**:design §4 明确—— - -> **非 70 分坐庄**:桌面 8 张暗牌**只有庄家可见**,庄家查看后摸入手牌。 -> **70 分坐庄**:摸暗牌之前先向所有玩家亮出 3 秒。 - -协议也与之一致:`shangzhuang.bottomcards` **庄家恒有、闲家仅 70 分坐庄时才有**;重连包 `ChooseMain` / `BuryCards` / `PushCards` 的 `bottomcards` 全部标注「**只有庄家有此属性**」。 - -**因此闲家在非 70 分局根本收不到暗牌数据,「所有人可查看」在当前协议下无法实现。** 且这属于服务端红线「**下发即泄露**——包到了客户端就能被抓包看到,『前端拿到但不渲染』不算防护」,不能靠前端自觉。 - -**需要在三种方案里选一个**: - -| 方案 | 含义 | 影响 | -| --- | --- | --- | -| **(a) 限定可见范围**(推荐) | `底牌` 按钮只在**能合法看到暗牌**时可用:庄家全程可用;闲家**仅 70 分坐庄局**(已公示过)可用,其余局按钮置灰或不显示 | 协议无需改,只改前端显隐条件;不破坏 design | -| **(b) 局末开放** | 牌局结束后向所有人下发暗牌,`底牌` 按钮在结算阶段才可用 | 需在 `jiesuan` 包补暗牌字段;不影响对局中的信息对称 | -| **(c) 改规则** | 暗牌对所有人全程可见 | **与 design §4 直接冲突**,需先改 design;且削弱 70 分公示这条规则的意义 | - -**在此确认前,前端按 (a) 实现**(最保守、不需要改服务端、不违反任何红线),并在代码里留注释指向本条。 - - ---- - -## 附:本文与其他文档的关系 - -| 文档 | 关系 | +| 谁 | 何时可用 | | --- | --- | -| `server/games/erqiwang/docs/design/design.md` | **玩法规则权威源**。本文引用其条款,不重新定义规则 | -| `server/games/erqiwang/docs/protocol/packet_protocol.md` | **协议字段权威源**。本文的「渲染什么」全部溯源到具体字段 | -| `docs/client/development-guide/` | **前端规范权威源**。ID 范围、组件范式、红线均以其为准 | -| `docs_dev/uiref/*.png` | 参考图,13 张(11 张牌桌态 + 叫分按钮面板 + 1 张建房**样式范式**,末者内容属他游戏、不可照抄) | -| `client/js/gameabc-framework/ui/AlignmentUtils.js` | **布局求解的框架能力**。§6 的配置参数名与其入参一一对应,配置可原样喂入 | -| `client/js/gameabc-framework/templates/*.template.js` | 常量文件写法蓝本。本清单落地为常量文件时按其格式 | +| 庄家 | **全程可用**(他本来就摸过这 8 张) | +| 闲家 | **仅 70 分坐庄局**可用(这 8 张已向全场公示过 3 秒);其余局**按钮不显示** | + +依据 design §4:非 70 分坐庄时这 8 张**只有庄家可见**;协议也一致(`shangzhuang.bottomcards` 闲家仅 70 分时才有,重连包的同名字段标注「只有庄家有此属性」)。 + +**服务端无需改动**——现有下发面正好支持这条规则:闲家在非 70 分局本来就收不到数据,按钮不显示即可,不存在「拿到了但不渲染」的泄露风险(服务端红线:下发即泄露)。 + +#### S-4 · 拆分 `bottomcards` 字段名(新增) + +**需求**:底牌与埋牌底牌是两批不同的牌,协议里却共用 `bottomcards`,只靠所在包区分语义——易错,需要拆开。 + +**建议改法**(与新术语对齐,`bottomcards` 留给字面意义相符的「底牌」): + +| 包 / 分组 | 当前字段 | 实际含义 | 建议 | +| --- | --- | --- | --- | +| `shangzhuang` | `bottomcards` | **底牌**(发牌留桌 8 张) | 保持 `bottomcards` | +| `deskinfo.ChooseMain` | `bottomcards` | **底牌** | 保持 | +| `deskinfo.BuryCards` | `bottomcards` | **底牌** | 保持 | +| `maipai` | `bottomcards` | **埋牌底牌**(庄家埋的 8 张) | 改为 **`burycards`** | +| `deskinfo.PushCards` | `bottomcards` | **埋牌底牌** | 改为 **`burycards`** | +| 结算 `bottom` 分组 | `bottom.cards` | **埋牌底牌** | 分组名可一并改为 `bury`,或保持 `bottom.cards` 但在文档注明 | + +**影响面**:`packet_protocol.md`、服务端 `mod.js` / `class.paiju.js` / `class.desk.js` 的组包处,以及尚未开工的前端。**前端未开工,现在改代价最小。** + +#### S-5 · 同步 design.md 与 packet_protocol.md 的术语(新增) + +术语变更(暗牌→**底牌**、底牌→**埋牌底牌**)目前**只在本文生效**。`design.md` 是玩法**唯一权威源**,`packet_protocol.md` 是协议权威源,两者仍用旧术语——**三份文档术语打架会直接违反 SSOT**。 + +需要同步修订的位置(初步): + +| 文档 | 位置 | +| --- | --- | +| `design.md` | §1 术语约定表(「暗牌」「底牌」「埋牌」「扣底」四条);§4 开局与坐庄流程 3/5 步;§6.3 扣底;§7.1 70 分说明;§8 算奖快照;§9 查牌;§12.1 流程 4/6/8 步;§12.3 阶段速览 | +| `packet_protocol.md` | `shangzhuang` / `maipai` / `deskinfo` 各分组的 `bottomcards` 说明;结算 `bottom` 分组;与 S-4 的字段改名一并做 | +| 服务端代码 | 注释与变量名(非必须,但建议一并对齐) | + +> **本文已先行采用新术语**,并在此显式记录差异,避免读者误以为 design.md 也已改。**建议尽快同步**,否则「底牌」一词在两份权威文档里指两批不同的牌,是最危险的那类不一致。 +