diff --git a/docs_dev/uiref/叫分按钮面板.png b/docs_dev/uiref/叫分按钮面板.png new file mode 100644 index 0000000..d28fc5b Binary files /dev/null and b/docs_dev/uiref/叫分按钮面板.png differ diff --git a/docs_dev/二七王-UI资源与精灵清单.md b/docs_dev/二七王-UI资源与精灵清单.md index b92e0f3..f7be01d 100644 --- a/docs_dev/二七王-UI资源与精灵清单.md +++ b/docs_dev/二七王-UI资源与精灵清单.md @@ -6,7 +6,7 @@ > > **权威源**:玩法规则以 `server/games/erqiwang/docs/design/design.md` 为准;下发字段以 `server/games/erqiwang/docs/protocol/packet_protocol.md` 为准;前端规范以 `docs/client/development-guide/` 为准。本文只做「规则/协议 → 界面资源」的映射,**不重新定义规则**。 > -> **参考图**:`./uiref/*.png`,共 12 张,设计分辨率 1280×720。 +> **参考图**:`./uiref/*.png`,共 13 张,设计分辨率 1280×720。 --- @@ -32,6 +32,7 @@ - [6.10 配置文件组织](#610-配置文件组织) - [6.11 与平台布局配置的衔接](#611-与平台布局配置的衔接) - [7. 待补充清单](#7-待补充清单) + - [7.5 服务端待补项](#75-服务端待补项需改服务端才能实现的前端需求) --- @@ -41,7 +42,7 @@ | 项 | 值 | 来源 | | --- | --- | --- | -| 设计分辨率 | **1280 × 720** | `client/output/gameabc_Project.json` `ScreenWidth/ScreenHeight`;11 张牌桌参考图均为 1280×720;建房参考图为局部截图,不含整屏尺寸 | +| 设计分辨率 | **1280 × 720** | `client/output/gameabc_Project.json` `ScreenWidth/ScreenHeight`;11 张牌桌参考图均为 1280×720;叫分按钮面板与建房参考图为局部截图 | | 适配模式 | `ScreenFitMode: 1` | 同上 | | 帧率 | 30 fps | 同上 | | 玩家数 | **3 人** | design §2(三家各摸 28 张) | @@ -413,7 +414,7 @@ EQW_RoomOptions = { | 三家玩家位状态文字清空,`主N/对N` 角标隐藏 | §2.2 玩家位附加标记 | | 倒计时显示在 `seat` 对应的位置 | §2.4 倒计时 | -- **发牌动画**【待确认 T-4】:是否需要逐张飞入动画。若做,须遵守 client 02 §3「数据优先、表现延后」——先 `setHandCards()` 写数据,再播动画;动画回调里只刷界面、不写数据。 +- **发牌动画(需要做)**:**从右往左铺开**。须遵守 client 02 §3「数据优先、表现延后」——先 `setHandCards()` 把 28 张写进 `this.data`,再播铺开动画;动画的开始/结束/出错回调里**只刷界面、不写核心数据**。动画缺失或卡住时,数据与界面仍须正确。动画时长、每张延迟进配置(§6.7)。 - **排序**:手牌排序规则(主牌在左还是在右、副牌花色顺序)由前端自行决定,**但选主前后主牌集合会变**,选主后必须重排。见 §7 T-5。 ### 1.3 叫分坐庄 `jiaofen` 【图:等待叫分.png / 自己叫分.png / 自己已经叫分轮到下家叫分.png】 @@ -431,11 +432,31 @@ EQW_RoomOptions = { **叫分面板规格**(群组 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)。 -- 每档 3 个精灵:按钮底(多帧,见下)+ 分数文字 + **子数角标文字**。 +- 每档 4 个精灵:按钮底 + 分数文字 + 角标底 + **子数角标文字**。 - 角标显示该档的 `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 -- 按钮底帧:**帧1 = 可选(亮黄)、帧2 = 不可选(灰)、帧3 = 高亮/当前**【待确认 T-6:参考图第二行为橙色,含义待定】。 + +**按钮配色:按档位位置固定,不随状态或数据变** 【图:叫分按钮面板.png】 + +| 位置 | 档位 | 按钮底 | 角标底 | +| --- | --- | --- | --- | +| 1–4 | 70 / 65 / 60 / 55 | 浅黄 | 蓝 | +| 5–7 | 50 / 45 / 40 | 金黄 | 绿 | +| 8–14 | 35 / 30 / 25 / 20 / 15 / 10 / 5 | 橙 | 深橙 | + +> ⚠️ 参考图里角标写的 `1子`/`2子`/`4子` 是 **mock 数值**,恰好与三组配色一一对应,**不要据此以为「颜色随子数变」**——颜色按档位位置写死,角标数值才随爬坡开关变。叫分越低(承诺越苛刻、子数越高)颜色越热。 +> +> 反证:常规算子下 50/45/40 与 35…5 的 `multiple` 同为 6 子,但参考图里它们是两种颜色。 + +**灰色 = 已经叫过的分数**(不可再叫)。故按钮底与角标底各 **4 帧**: + +| 帧 | 按钮底 | 角标底 | +| --- | --- | --- | +| 1 | 浅黄(高分档) | 蓝 | +| 2 | 金黄(中分档) | 绿 | +| 3 | 橙(低分档) | 深橙 | +| 4 | **灰(已叫过 / 不可选)** | 灰 | - 可选性规则(design §4.2,**由服务端权威 `currcall` 决定,前端只据其置灰、不自行推导规则**): - 暂定庄家首叫:5–70 全部可选,**无 `不叫`**; - 其后:只有**严格低于 `currcall`** 的档位可选,`不叫` 可选。 @@ -466,7 +487,7 @@ EQW_RoomOptions = { - 标题斜角条:`亮主` 金色字 + 倒计时数字。 - **4 个花色按钮**,每个含 4 个精灵:按钮底 + 花色大图标 + **中央大数字** + **右上角蓝色角标**。 - - 中央大数字 = 该花色在庄家 36 张手牌中的**总张数**【待确认 T-7:参考图为 6/8/6/7,与角标 `2对` 并存,推定为张数】 + - 中央大数字 = 该花色在庄家 36 张手牌中的**总张数** - 右上角标 = 该花色的**对子数**(design §4/§11 明确要求) - **两个数字都由前端据 `MyCards`/`cards` 自行统计**,协议 §「ChooseMain」明确「服务端不额外下发」。 - **投降按钮**:仅 `touxiang === 1`(即叫分 70)时显示,与 4 个花色按钮并列。 @@ -486,7 +507,12 @@ EQW_RoomOptions = { - 手牌从**单排 36 张**改为**双排**(上排 17 + 下排 19,实测估值)。 - 操作条(群组 222):`提示` 按钮 + 倒计时 + **`埋牌 (N/8)`** 按钮,N 为已选张数,`N < 8` 时按钮置灰不可提交。 - 选中的牌**上浮**表示待埋。 -- 参考图中牌面上有 `拖` 红色圆标、⭐橙星、🔵蓝星等标记 —— 推定为「提示」功能标出的牌型分组【待确认 T-8:标记种类与含义未定义于 design/协议】。 +- 牌面上的三种标记(资源 `MARK_CARD_GROUP` 3 帧): + - **`拖` 红色圆标** = 该牌属于一组**拖拉机** + - **橙色五角星** = **正 2 / 正 7**(选定花色的 2 和 7,design §3 里大小仅次于双王) + - **蓝色五角星** = 除正2正7外的**其他主牌**(双王、副2、副7、主花色普通牌) + + 三种标记互斥、每张牌至多一个;由前端据 `flower`(主牌花色)在本地标注,**不需要服务端下发**。 **收到 `maipai` 推送后**(字段 `cards`、`bottomcards`、`seat`、`countdown`、`liangpai`): - 庄家手牌回到单排 28 张; @@ -508,7 +534,13 @@ EQW_RoomOptions = { 这是最复杂的阶段。 -**出牌操作条**(群组 223):倒计时 + `出牌` 按钮(选中牌数为 0 时置灰)。参考图另有 `提示` 按钮(埋牌图里出现,出牌阶段是否保留待确认 T-10)。 +**出牌操作条**(群组 223):倒计时 + `出牌` 按钮(选中牌数为 0 时置灰)+ **`提示` 按钮(出牌阶段必须有)**。 + +**自动选中**:某些情况下(如跟牌时存在**必出牌**、或整手只有唯一合法出法),服务端会在下发包里带上**应当选中的牌**,前端收到后**自动把这些牌选中**(上浮),玩家确认后点 `出牌` 即可。 + +> ⚠️ **该字段目前协议里没有,需服务端补**——见 §7.5 **S-2**。好消息是服务端已经算过了:`class.arith.js:737` `get_followcard()` 返回 `{ mustcard, cancard, cantype }`,其中 `mustcard` 就是「必出的牌列表」,现在只用于内部校验(`class.arith.js:1055`)、未下发。补一个下发字段即可,无需新增算法。 +> +> 这条**不违反**「请求包只带意图」红线——方向是**服务端 → 前端**的建议选中,前端仍只回传 `cards`;且合法性最终仍由服务端校验。 **自己出牌**:点手牌选中(上浮)→ 点 `出牌` → 发 `chupai { seat, cards }`。 - `cards` 必须是**非空、元素为 0–107 整数、互不重复**的数组(协议 §0.2),否则服务端按 `PARAM` 拒绝。 @@ -541,9 +573,12 @@ EQW_RoomOptions = { **闲家提示 `tishi`** 【图:自己是闲家时,底下的踩有分没分按钮.png】(design §11): - 闲家在出牌阶段可向**对家**(另一闲家)发三种提示:`1 = 踩`(我能大过庄家)、`2 = 没分`、`3 = 有分`。 -- 发送方**收不到成功回执**(协议 §13.7),只有失败才回包 → **前端不得在点击时乐观显示自己发过提示**。 +- 发送方**收不到成功回执**(协议 §13.7),只有失败才回包。 - 接收方(对家)收到 `tishi { seat, tip }` → 在发送者的玩家位弹出气泡。 - 庄家无对家,不提供此功能。 +- **自己发的提示需要本地回显**:服务端只把提示转发给对家、不回执给发送者,所以**发送者自己的气泡由前端在点击时本地弹出**。 + + > 这是「悲观 UI」红线的一处**受控例外**,成立的理由是:提示**不含任何对局状态**,服务端明确「不校验提示真实性」(协议 §13.7、design §11),它既不改阶段、不改控制权、不改分数,纯属玩家间的主观喊话。因此本地回显不会造成与服务端状态不一致。仍须遵守:失败回包(`RULE`/`STEP`/`PARAM`)到达时要把本地回显撤掉。 **发起入口**:底栏三个按钮 `踩` `有分` `没分`,**位置就是庄标的位置**——自己是闲家时没有 `庄` 印章,这块区域正好空出来给这三个按钮。 @@ -601,7 +636,8 @@ EQW_RoomOptions = { **扣底表现**(`bottom` 分组,design §6.3): - `cards`(8 张底牌)**恒有** → 底牌区(群组 215,资源 `CARD_FACE_S`)翻开展示,design §11 明确「牌局结束需要亮出底牌」; - `multiple` / `grade1` / `grade2` **仅闲家扣底时才有** → 展示 `底牌 20 × 4` 之类的翻倍算式。 -- 参考图底牌面板下方文字为 `叫分2子 底牌 20x0`,即 `叫分{multiple}子 底牌 {grade1}x{multiple}`【待确认 T-12:`x0` 说明该局闲家未扣底,此时的文案规则待定】。 +- 文案格式:`叫分{aset.multiple}子 底牌 {bottom.grade1}x{bottom.multiple}`——**`x` 后面是扣底倍数**(design §6.3:单张 ×1、主对 ×2、N 连对 ×2N)。参考图 `底牌 20x0` 即底牌有 20 分、扣底倍数 0(本局闲家未扣底)。 +- 闲家未扣底时 `bottom` 只有 `cards`,`multiple`/`grade1`/`grade2` 都不下发 → 倍数位显示 **0**。 **三家结算数字**(`aset.seatlist`,每家两行): @@ -643,7 +679,9 @@ EQW_RoomOptions = { **算奖牌型叠加层** 【图:算奖牌型显示.png】: -点 `算奖牌型` 后,在结算面板之上盖一层**半透黑遮罩**,三家各展示自己的 `aset.seatlist[i].cards`,资源用 `CARD_FACE_L`、重叠排列。`下一局` 按钮在遮罩层上**继续可见可点**,`算奖牌型` 按钮本身被遮住。再点一次或点遮罩空白处关闭【待确认 T-22:关闭方式】。 +点 `算奖牌型` 后,在结算面板之上盖一层**半透黑遮罩**,三家各展示自己的 `aset.seatlist[i].cards`,资源用 `CARD_FACE_L`、重叠排列。`下一局` 按钮在遮罩层上**继续可见可点**,`算奖牌型` 按钮本身被遮住。 + +**关闭方式:整块全屏半透明黑遮罩本身就是关闭热区,点击遮罩即关闭。** 不另设关闭按钮。因此 `AWARD_MASK` 必须注册点击事件,且 `下一局` 的层级要高于它、点它不被遮罩吃掉。 - 三家牌位:左上家、右上家在各自头像内侧;自己在中央偏下。 - 布局配置见 §6.7。 @@ -660,7 +698,7 @@ EQW_RoomOptions = { | `upgrade` | **判定倍率(带符号)**:`3` 大光 / `2` 小光 / `1` 过庄 / `-N` 升 N 级(倒庄)/ `-99` 投降 / `0` 解散 → 需要一组判定文字或图标:`大光` `小光` `过庄` `升N级` `投降`【待设计 D-8】 | | `bangwang` / `climb` | 本局规则开关,用于结算面板上标注 | | **`cards`** | **算奖牌型叠加层**的牌(见上) | -| `chongguan` / `wang` / `naward` | 常规算奖奖数 / 王数 / 总奖数 —— 是否在叠加层上并列显示数字【待确认 T-23】 | +| `chongguan` / `wang` / `naward` | 常规算奖奖数 / 王数 / **总奖数**。叠加层**需要并列显示奖数**——以 `naward`(该家总奖数 N,8.4 节的支付基数)为主;`chongguan` / `wang` 作为明细可选展示 | **投降结算**:只有 `aset`,无 `chupai`、无 `bottom` → 结算面板必须容忍**底牌区缺失**,不能因为读不到 `bottom.cards` 就崩或显示空框。 @@ -713,7 +751,7 @@ EQW_RoomOptions = { ### 1.12 准备 `zhunbei` -小局结算后各家点准备进入下一局。收 `zhunbei { seat }` → 该家玩家位显示「已准备」标记【待设计:参考图未出现,可能复用平台准备标识,见 T-15】。 +小局结算后各家点 `下一局` 进入下一局(§1.8),发 `zhunbei { seat }`。收 `zhunbei { seat }` → 该家玩家位显示「已准备」标记——**用平台的准备标识**(§0.2),子游戏不另做资源。 --- @@ -792,12 +830,32 @@ y≈648–720 深色条。左侧头像/昵称/分数由平台渲染(§0.2) | `庄` 印章 | x≈338–370 | **自己是庄**时显示 | | `踩` / `有分` / `没分` 按钮 | x≈335–573(占用同一区域) | **自己是闲家 + 出牌阶段**时显示,与 `庄` 印章互斥(§1.7) | | 局数 `1/4 局` | 居中 x≈635–700 | 常驻,`asetidx / asetcount` | -| `明牌` 按钮 | x≈876–950, y≈672–702 | **仅可查牌模式 + 出牌阶段 + 已报无主** | -| `已出牌` 按钮 | x≈965–1052 | **仅可查牌模式 + 出牌阶段** | -| `上一轮` 按钮 | x≈1067–1160 | 同上 | -| `底牌` 按钮 | x≈1172–1250 | 常驻【待确认 T-18:庄家看自己埋的底牌?闲家点了看什么?】 | +**右侧功能按钮共 5 个**,按情况显隐(不是全部常驻): -- 精灵:群组 205,号段 1040–1069。 +| 按钮 | 看什么 | 显示条件 | +| --- | --- | --- | +| `上一轮` | **上一轮**所有人出的牌 | 可查牌 + 出牌阶段 + 已打过至少一轮 | +| `出牌历史` | 所有人**出过的全部牌** | 可查牌 + 出牌阶段 | +| `明牌` | 另两家手中全部主牌的具体牌面 | 可查牌 + 出牌阶段 + **已报无主** | +| **`扣底`** | **庄家查看自己埋的 8 张底牌** | **仅庄家** + 已埋牌之后 | +| **`底牌`** | **发牌时桌面留下的 8 张暗牌** | 见下方可见性问题 S-3 | + +> ### ⚠️ 术语陷阱:底栏「底牌」按钮看的不是「底牌」 +> +> design 术语表:**暗牌** = 发牌时留在桌面的 8 张;**底牌** = 庄家埋牌时重新扣下的 8 张。两者是**不同批的牌,不通用、不互换**。 +> +> 底栏按钮的命名恰好**与术语相反**: +> +> | 按钮 | 实际展示 | design 术语 | 协议字段 | +> | --- | --- | --- | --- | +> | `扣底` | 庄家埋的 8 张 | **底牌** | `maipai.bottomcards` / `PushCards.bottomcards`(仅庄家)/ 结算 `bottom.cards` | +> | `底牌` | 发牌留桌的 8 张 | **暗牌** | `shangzhuang.bottomcards`(庄家恒有,闲家仅 70 分时有)/ `ChooseMain`·`BuryCards.bottomcards`(仅庄家) | +> +> 更容易踩的是:协议里这**两批牌用了同一个字段名 `bottomcards`**,只靠「在哪个包/哪个阶段」区分语义。 +> +> **实现要求**:前端内部一律用 `anCards`(暗牌)/ `diCards`(底牌)两个不同变量名,**不要跟着按钮文案命名**;取值时按所在包判断语义。已列入验收清单(§7.3)。 + +- 精灵:群组 205,号段 1040–1069(5 个按钮 × 2 精灵 = 10)。 ### 2.7 手牌区 【图:全部】 @@ -848,7 +906,7 @@ y≈648–720 深色条。左侧头像/昵称/分数由平台渲染(§0.2) | 536 | `BTN_BURY` | `埋牌 (N/8)` | 2 | 帧1=可提交(金黄) 帧2=置灰(未满 8 张) | 180 × 63 | | 537 | `BTN_PLAY` | `出牌` | 2 | 帧1=可出 帧2=置灰 | 157 × 55 | | 538 | `BTN_BOTTOM_FUNC` | 底栏功能钮底(明牌/已出牌/上一轮/底牌共用) | 1 | 深色圆角 | 88 × 30 | -| 539 | `BTN_READY` | 准备【T-15】 | 1 | 待设计 | 待定 | +| ~~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 | @@ -862,8 +920,8 @@ y≈648–720 深色条。左侧头像/昵称/分数由平台渲染(§0.2) | 573 | `MARK_JOKER_BIG` | 大王 `大` 圆标 | 2 | 帧1=大王 帧2=小王 | 34 × 34 | | 574 | `BADGE_ZHU_PAIR` | `主N` / `对N` 角标底 | 2 | 帧1=黄底(主) 帧2=白底(对) | 44 × 20 | | 575 | `BADGE_MULTIPLE` | 子数/倍数角标底 | 2 | 帧1=蓝底 帧2=橙底 | 34 × 18 | -| 576 | `LABEL_CARDTYPE` | 牌型标签 | ≥6 | 帧1=单张 帧2=对子 帧3=拖拉机 帧4=甩牌 帧5=毙 帧6=垫【T-11】 | 76 × 24 | -| 577 | `MARK_CARD_GROUP` | 手牌牌型分组标记(`拖`圆标 / ⭐ / 🔵)【T-8】 | ≥3 | 待定 | 26 × 26 | +| 576 | `LABEL_CARDTYPE` | 牌型标签 | **1** | **只做「毙」一种**(前端只展示这一个标签)。数据层仍保留 毙 / 垫 / 混合出牌 三种标识以备扩展,但当前不出图、不显示 | 76 × 24 | +| 577 | `MARK_CARD_GROUP` | 手牌牌型标记 | **3** | **帧1=`拖`(拖拉机)帧2=橙色五角星(正2 / 正7)帧3=蓝色五角星(除正2正7外的其他主牌)** | 26 × 26 | | 578 | `MARK_SELECTED` | 手牌选中标记 | 1 | 待定(也可只用上浮,不出图) | 待定 | ### 3.5 面板底图 @@ -889,7 +947,7 @@ y≈648–720 深色条。左侧头像/昵称/分数由平台渲染(§0.2) | 633 | `NUM_RESULT_LOSE` | 结算得分数字(输,蓝) | 12 | 同上 | 46 × 62 | | 634 | `TXT_JUDGE` | 判定结果文字 | ≥5 | 帧1=大光 帧2=小光 帧3=过庄 帧4=升级 帧5=投降【待设计】 | 待定 | -> 若改用文字精灵(`SpriteManager.setText`)而非图片数字,631–634 可省。见 T-19。 +> **数字一律用图片多帧精灵**(不用 `SpriteManager.setText`)——参考图里的数字都带描边与渐变,文字精灵做不出这种效果。故 631–634 全部需要出图。 ### 3.7 浮层与气泡 @@ -1022,7 +1080,7 @@ design 与协议均**未定义任何音效**。以下是按牌类游戏常规推 | | 1651 | `MAIN_TITLE_TEXT` | 文字 | `亮主` | —— | | | 1652–1655 | `MAIN_SUIT_BTN_1..4` | 图片 ×4 | 花色按钮底 | `BTN_SUIT_CHOOSE` | | | 1656–1659 | `MAIN_SUIT_ICON_1..4` | 图片 ×4 | 花色图标 | `SUIT_ICON_L` 帧1–4 | -| | 1660–1663 | `MAIN_SUIT_COUNT_1..4` | 文字 ×4 | 该花色**张数**【T-7】 | —— | +| | 1660–1663 | `MAIN_SUIT_COUNT_1..4` | 文字 ×4 | 该花色在庄家手中的**张数** | —— | | | 1664–1667 | `MAIN_SUIT_PAIR_BG_1..4` | 图片 ×4 | 对数角标底 | `BADGE_MULTIPLE` 帧1 | | | 1668–1671 | `MAIN_SUIT_PAIR_TEXT_1..4` | 文字 ×4 | `N对` | —— | | | 1672 | `MAIN_BTN_SURRENDER` | 图片 | `投降` | `BTN_SURRENDER` | @@ -1033,7 +1091,8 @@ design 与协议均**未定义任何音效**。以下是按牌类游戏常规推 | | 1703 | `BURY_BTN_SUBMIT_TEXT` | 文字 | `埋牌 (N/8)` | —— | | **223** 出牌操作条 | 1710 | `PLAY_BTN_SUBMIT` | 图片 | `出牌` | `BTN_PLAY` 帧1可出/帧2灰 | | | 1711 | `PLAY_BTN_SUBMIT_TEXT` | 文字 | —— | —— | -| | 1712 | `PLAY_BTN_TIP`【T-10】 | 图片 | `提示` | `BTN_TIP` | +| | 1712 | `PLAY_BTN_TIP` | 图片 | `提示`(出牌阶段必备) | `BTN_TIP` | +| | 1713 | `PLAY_BTN_TIP_TEXT` | 文字 | 按钮文案 | —— | | **224** 倒计时 | 1150 | `CD_LEFT` | 文字 | 左上家位倒计时 | —— | | | 1151 | `CD_RIGHT` | 文字 | 右上家位倒计时 | —— | | | 1152 | `CD_SELF` | 文字 | 自己操作区倒计时 | —— | @@ -1055,7 +1114,7 @@ design 与协议均**未定义任何音效**。以下是按牌类游戏常规推 | 精灵 ID | 键名 | 类型 | 用途 | 资源 / 帧 | | --- | --- | --- | --- | --- | | 1800 | `RESULT_BOTTOM_PANEL` | 图片 | 底牌区面板底 | `PANEL_BOTTOM_CARDS` | -| 1801 | `RESULT_BOTTOM_TEXT` | 文字 | `叫分N子 底牌 GxM`【T-12】 | —— | +| 1801 | `RESULT_BOTTOM_TEXT` | 文字 | `叫分{multiple}子 底牌 {grade1}x{bottom.multiple}` | —— | | 1802–1804 | `RESULT_GLOW_LEFT/RIGHT/SELF` | 图片 ×3 | 三家分数光晕 | `GLOW_RESULT` 帧1赢/帧2输 | | 1805–1807 | `RESULT_SCORE_LEFT/RIGHT/SELF` | 文字 ×3 | 三家总分(`aset.seatlist[i].grade`) | —— | | 1808–1810 | `RESULT_JF_LEFT/RIGHT/SELF` | 文字 ×3 | 捡分子数得分 `grade_jf`【T-13】 | —— | @@ -1081,7 +1140,7 @@ design 与协议均**未定义任何音效**。以下是按牌类游戏常规推 | 1822 | `AWARD_BOX_RIGHT` | **容器** | 右上家算奖牌容器 | —— | | 1823 | `AWARD_BOX_SELF` | **容器** | 自己算奖牌容器 | —— | | 1824 | `AWARD_CARD_TPL` | **模板** | 算奖牌模板(编辑器里放好、默认隐藏,只作样式来源) | `CARD_FACE_L` | -| 1825–1827 | `AWARD_COUNT_LEFT/RIGHT/SELF` | 文字 ×3 | 奖数 `naward` 等【T-23】 | —— | +| 1825–1827 | `AWARD_COUNT_LEFT/RIGHT/SELF` | 文字 ×3 | **奖数**,与该家的算奖牌**并列显示**(取 `aset.seatlist[i].naward`;是否另列 `chongguan`/`wang` 明细见下) | —— | **生成方式**: @@ -1462,56 +1521,76 @@ codes/config/ ## 7. 待补充清单 -### 7.1 待出设计稿的界面 +> **状态汇总**(2026-08-25):待确认规格 29 项**已答 27 项**,剩 T-9(亮牌条文案)与 T-20(音效,已明确后续补充)。 +> 新增 **§7.5 服务端待补项**——3 条需要改服务端才能实现的前端需求。 + +### 7.1 待出设计稿的界面(后续统一补充) | 编号 | 界面 | 所属 | 说明 | | --- | --- | --- | --- | -| D-1▲ | 建房规则选项区 | §1.1 | **已有样式范式**(他游戏参考图)+ 内容已定(4 行);仍缺**二七王自己的定稿**与在平台建房界面里的确切尺寸/位置 | +| D-1▲ | 建房规则选项区 | §1.1 | 样式范式与内容已定(3 类别 / 4 选项组),缺二七王定稿与在 Layer 27 内的确切尺寸位置 | | D-2 | 70 分暗牌公示(3 秒) | §1.4 | 全场可见的暗牌展示 + 倒计时 | | D-3 | 甩错提示 | §1.7 | 整套收回、只出最小一张的表现 | | D-4 | 报无主提示 | §1.7 | 玩家主牌出空时的全场提示 | -| ~~D-5~~ | ~~踩 / 没分 / 有分 气泡与发起入口~~ | §1.7 | **已定**:入口 = 底栏三按钮(占庄标区,闲家时显示);气泡 = 3×2 六帧、按头像相对位置选朝向 | +| ~~D-5~~ | ~~踩 / 没分 / 有分 气泡与入口~~ | §1.7 | **已定**:入口 = 底栏三按钮(占庄标区);气泡 3×2 六帧、按头像相对位置选朝向 | | D-6 | 明牌面板 | §1.7 | 另两家未出主牌的具体牌面 | -| D-7 | 出牌历史面板 | §1.7 | 按轮次 × 3 家 | +| D-7 | 出牌历史面板 | §1.7 | 按轮次 × 3 家;另需 `上一轮` 的单轮视图 | | D-8 | 判定结果文字(大光/小光/过庄/升N级/投降) | §1.8 | 结算时的判定展示 | | D-9 | 大局总结算 | §1.9 | 三家 × N 局成绩表 | -| D-10 | 解散结算 | §1.10 | **投票界面平台全包**(Layer 420),只剩结算面板,可直接复用 D-9 | -| D-11 | 准备标识 | §1.12 | 或复用平台准备标识;**`下一局` 按钮已有图**(§1.8),准备状态标识仍缺 | -| ~~D-12~~ | ~~左上家已出牌区~~ | §2.3 | **已定**:与右上家左右镜像,无需单独设计稿 | +| D-10 | 解散结算 | §1.10 | 投票界面平台全包(Layer 420),只剩结算面板,可复用 D-9 | +| ~~D-11~~ | ~~准备标识~~ | §1.12 | **已定**:用平台准备标识,子游戏不做 | +| ~~D-12~~ | ~~左上家已出牌区~~ | §2.3 | **已定**:与右上家左右镜像 | +| **D-13** | **`扣底` 按钮的查看面板** | §2.6 | 新增:庄家查看自己埋的 8 张底牌;可与 `底牌`(看暗牌)复用同一个「8 张牌」展示面板,仅数据源不同 | ### 7.2 待确认的规格问题 +**仍未决(2 项)** + | 编号 | 问题 | 影响 | | --- | --- | --- | -| ~~T-1~~ | ~~逆时针方向:下家是 `(seat+1)%3` 还是 `(seat+2)%3`~~ | **已定论**,见 §0.1:`class.paiju.js:264` `get_nextseat = (seat+1)%3`,下家显示在右上 | -| ~~T-2~~ | ~~解散投票界面是平台提供还是子游戏自建?~~ | **已定论**:**平台全包**(`Layer 420 CheckFree_Layer` + `GameUI.openCheck` + `Desk.*_free_room` 一族),子游戏只处理解散结算包 | -| ~~T-3~~ | ~~平台创建房间界面在哪个图层?~~ | **已定论**:**Layer 27 `CreateRoom_Layer`**(`Layer 28 SeniorOptions_Layer` 是代开房/抽水,与玩法规则无关) | -| **T-4** | 是否需要发牌动画? | 动画配置与工期 | -| **T-5** | 手牌排序规则(主牌左/右、副牌花色顺序);选主后重排的动画表现 | 布局算法 | -| **T-6** | 叫分档位按钮第 3 帧(参考图第二行橙色)的含义 | `BTN_CALL_SCORE` 帧数 | -| **T-7** | 选主按钮中央大数字是该花色**张数**还是别的?(design 只要求显示对子数) | `MAIN_SUIT_COUNT_*` 的取值 | -| **T-8** | 埋牌图中牌面上的 `拖` 圆标 / ⭐ / 🔵 是什么?「提示」功能的分组标记? | `MARK_CARD_GROUP` 帧数与含义 | -| **T-9** | 亮牌条文案 `主牌对子: 1对` 与 design §8.2 的四类信息(主/王/7/2)对应关系 | 文案模板 | -| **T-10** | 出牌阶段是否保留 `提示` 按钮?提示什么? | 精灵 1712 是否需要 | -| **T-11** | 牌型标签种类:除单张/对子/拖拉机/甩牌外,是否还要标「毙」「垫」「混合出牌」? | `LABEL_CARDTYPE` 帧数 | -| **T-12** | 结算底牌文案 `叫分2子 底牌 20x0` 的完整规则(未扣底时怎么显示) | 文案模板 | -| ~~T-13~~ | ~~结算面板两个小字标签的正式文案~~ | **已定论**:`牌局分`(`grade_jf`) / `算奖分`(`grade_aw`),见更新后的 `小局结算.png` | -| ~~T-14~~ | ~~结算面板是否展示算奖明细~~ | **已定论**:走独立的**算奖牌型叠加层**(`算奖牌型` 按钮打开),见 `算奖牌型显示.png` | -| **T-15** | 准备状态用平台标识还是自建? | D-11 | -| **T-16** | 顶部 `抓分` 列角标:早期图为 `1子`、三张新图均为 `1倍`。**推定为 `1倍`**,但语义待定:是 `aset.upgrade` 判定倍率,还是 `bottom.multiple` 扣底倍数? | 精灵 1008 的数据源 | -| ~~T-17~~ | ~~倒计时归零后显示 `0` 还是隐藏?~~ | **已定**:**停在 `0` 继续显示**。协议 §0.3 明确归零不触发任何动作、牌局原地等待;隐藏会被误读为「已超时/已跳过」 | -| **T-18** | 底栏 `底牌` 按钮:庄家点了看自己埋的 8 张?闲家点了看什么?未埋牌时呢? | 交互定义 | -| **T-19** | 数字用图片精灵(多帧)还是文字精灵(`setText`)? | 是否需要资源 631–634 | -| **T-20** | **整套音效**:清单、是否需要语音包、是否分男女声 | §4 全节 | -| ~~T-21~~ | ~~手牌 `fan` 的 `spacingMin`/`spacingMax` 取值~~ | **已按参考图算定**:单排 `spacingMax:0, spacingMin:-78`(36 张时露 32px,与参考图实测 33px 吻合);埋牌双排 `spacingMin:-65`。见 §6.7 | -| **T-22** | 算奖牌型叠加层的关闭方式(再点按钮 / 点遮罩 / 独立关闭钮) | §1.8 交互 | -| **T-23** | 算奖叠加层是否并列显示奖数(`chongguan` / `wang` / `naward`) | 精灵 1825–1827 是否需要 | -| ~~T-24~~ | ~~算奖牌 `cards` 超过 8 张时怎么排~~ | **已定论**:改用**精灵复制**(§5.6a),张数不设上限,`fan` 自适应压缩 | -| ~~T-25~~ | ~~`line` 是否支持「逐项不等宽」~~ | **已定**:支持。`line` 增加可选 `items:[{width},…]`,给出时逐项取宽、不给时用统一 `itemWidth`。见 §6.1 | -| **T-26** | 自己发的提示是否需要本地回显气泡(协议不回执,默认看不到) | §6.6 SELF 气泡 | -| ~~T-27~~ | ~~埋牌双排分行策略~~ | **已定**:上排 `floor(n/2)`、下排 `ceil(n/2)`(36 张即 18/18)。参考图的 17/19 无规则依据,按 mock 处理 | -| ~~T-28~~ | ~~两份布局配置的坐标一致性~~ | **已定**:`EQW_Layout` 为权威,`01_SubGame_modify.js` 配置区手工同步并加注释;一致性列入验收清单(§7.3 第 10 条) | -| **T-29** | 建房界面的整体位置与可用尺寸(依赖平台创建房间界面,与 T-3 同源) | §6.9b 的 anchor 起点 | +| **T-9** | 亮牌条文案 `主牌对子: 1对` 与 design §8.2 四类信息(主牌总数/对子数/拖拉机数、王数、7 数、2 数)的对应关系与组合展示格式 | 文案模板;`liangpai` 各字段怎么拼成一行 | +| **T-20** | **整套音效**:清单、是否需要语音包、是否分男女声、倒计时提示音从第几秒起 | §4 全节;**已明确「等待后续补充」** | + +**已定论(27 项)** + +| 编号 | 结论 | +| --- | --- | +| ~~T-1~~ | `class.paiju.js:264` `get_nextseat = (seat+1)%3`,下家显示在右上(§0.1) | +| ~~T-2~~ | 解散投票**平台全包**(Layer 420 + `GameUI.openCheck` + `Desk.*_free_room`),子游戏只处理结算包 | +| ~~T-3~~ | 建房界面 = **Layer 27 `CreateRoom_Layer`**(Layer 28 是代开房/抽水,无关) | +| ~~T-4~~ | **需要发牌动画**:从右往左铺开(§1.2) | +| ~~T-5~~ | 见下方「T-5 手牌排序」小节 | +| ~~T-6~~ | 叫分按钮**按档位位置固定三档配色**(浅黄/金黄/橙)+ 灰=已叫过;按钮底与角标底各 4 帧(§1.3) | +| ~~T-7~~ | 选主按钮中央大数字 = 该花色**张数**,右上角标 = 该花色**对数**(§1.5) | +| ~~T-8~~ | 手牌标记 3 帧:`拖`=拖拉机 / 橙星=**正2正7** / 蓝星=**其他主牌**;前端据 `flower` 本地标注(§1.6) | +| ~~T-10~~ | 出牌阶段**必有** `提示` 按钮;另需服务端下发「应选中的牌」以实现自动选中 → **S-2** | +| ~~T-11~~ | 牌型标签**只做「毙」一种**;数据层保留 毙/垫/混合出牌 三种标识备扩展,当前不出图 | +| ~~T-12~~ | `底牌 20x0` 的 `x` 后面是**扣底倍数**(`bottom.multiple`);未扣底显示 0(§1.8) | +| ~~T-13~~ | 结算两个小字 = `牌局分`(`grade_jf`) / `算奖分`(`grade_aw`) | +| ~~T-14~~ | 算奖明细走独立的**算奖牌型叠加层** | +| ~~T-15~~ | 准备标识**用平台的** | +| ~~T-16~~ | `抓分` 角标 = **当前抓分的倍数**;协议现无此字段 → **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-23~~ | 叠加层**需要并列显示奖数**(以 `naward` 为主) | +| ~~T-24~~ | 算奖牌用**精灵复制**,张数不设上限 | +| ~~T-25~~ | `line` 支持可选 `items` 逐项不等宽 | +| ~~T-26~~ | 自己发的提示**需要本地回显**(受控例外,理由见 §1.7) | +| ~~T-27~~ | 埋牌双排 `floor(n/2)` / `ceil(n/2)` | +| ~~T-28~~ | `EQW_Layout` 为权威,配置区手工同步 + 验收检查 | +| ~~T-29~~ | 建房整体位置尺寸随 Layer 27 定,编辑器建好后回填 | + +#### T-5 手牌排序(已定) + +前端排序**对齐服务端主牌序**(design §3),不另造一套——服务端 `class.arith.js` 的 `order_cards(mainflower, cards)` 即权威顺序(从大到小),下发的 `pushlist` 等字段也已按此排好。 + +- **选主前**(叫分阶段):`flower` 未定,只有固定主牌(双王 + 全部 2、7)是主牌,其余按花色分组。 +- **选主后**:`flower` 确定,正 2 / 正 7 升格、主花色普通牌并入主牌段,**必须整体重排**。重排动画暂不做(先直接重画),后续可加。 +- 主牌段落在**左侧**——排序从大到小、主牌最大,自然靠左。 + ### 7.3 验收检查清单 @@ -1531,6 +1610,9 @@ 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 术语陷阱 | +| 14 | 叫分按钮配色按**档位位置**取(非按子数),已叫过的档位置灰 | §1.3 | +| 15 | 自己发的提示本地回显后,收到失败回包时能撤掉 | §1.7 | ### 7.4 开发前置条件 @@ -1548,6 +1630,75 @@ codes/config/ - **布局配置骨架与布局求解器**(§6)——`kind` 五型的参数结构与求解逻辑是设计决定、不依赖具体数值,可先写好并用占位坐标跑通,等设计稿到位只改配置值 - `shared/` 同步机制 +### 7.5 服务端待补项(需改服务端才能实现的前端需求) + +以下 3 条来自本轮确认的需求,**当前协议/服务端不支持**,需在服务端补齐后前端才能实现。三条都要同步更新 `packet_protocol.md`。 + +#### S-1 · 「当前抓分的倍数」字段(对应 T-16) + +**需求**:顶部信息条 `抓分` 列的角标要显示「当前抓分的倍数」(参考图 `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`)里增加一个字段,例如: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| `curmultiple` | 整数 | 按当前累计捡分实时算出的判定倍率绝对值,供顶部 `抓分` 角标显示 | + +**需先确认语义**(本条尚未完全定死):角标要显示的到底是 +(a)**当前捡分对应的判定倍率**(大光×3 / 小光×2 / 过庄×1 / 升N级×N)的实时预览——即「若现在结束是几倍」;还是 +(b)别的口径。 +按字面「当前抓分的倍数」以及 `get_upgrade` 现成可用,(a) 最可能。**确认 (a) 之后即可动工**。 + +> 前端**不得自算**这个值——判定倍率属服务端权威裁定(红线:服务器权威、前端只显示不自算)。 + +#### S-2 · 下发「应当选中的牌」(对应 T-10) + +**需求**:某些情况下(跟牌存在必出牌、或唯一合法出法)服务端下发应选中的牌,前端收到后自动选中。 + +**现状**:`chupai1/2/3` 下发包里没有此字段。 + +**好消息——算法已存在,只差下发**:`class.arith.js:737` `get_followcard(mainflower, inhandcards, startcount, startflower, startcardtype)` 已经返回 + +``` +{ mustcard: 必出的牌列表, cancard: 可出的牌列表, cantype: 可出牌需要的牌型 } +``` + +目前只在 `class.arith.js:1055` 用于内部合法性校验,**从未下发**。建议在 `chupai1/2/3` 里**按座位差异化**下发给「下一个出牌者」: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| `mustcard` | 数组 | 该座位本轮的必出牌 id 列表;**只发给 `nextseat` 对应的那一家**,其他两家不带 | + +**下发面注意**(红线:发全 ≠ 发多):`mustcard` 是**该玩家自己手牌**的子集,只发给他本人不泄露任何信息;**绝不可整表下发三家的 `mustcard`**——那等于把另两家的手牌结构透露出去。 + +**不违反「请求包只带意图」**:方向是服务端 → 前端的建议,前端仍只回传 `cards`,合法性最终由服务端校验。 + +#### S-3 · 底栏「底牌」按钮的暗牌可见性(对应 T-18)⚠️ 与 design 冲突 + +**需求**:底栏 `底牌` 按钮让**所有人**查看发牌时的 8 张**暗牌**。 + +**冲突**: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) 实现**(最保守、不需要改服务端、不违反任何红线),并在代码里留注释指向本条。 + + --- ## 附:本文与其他文档的关系 @@ -1557,6 +1708,6 @@ codes/config/ | `server/games/erqiwang/docs/design/design.md` | **玩法规则权威源**。本文引用其条款,不重新定义规则 | | `server/games/erqiwang/docs/protocol/packet_protocol.md` | **协议字段权威源**。本文的「渲染什么」全部溯源到具体字段 | | `docs/client/development-guide/` | **前端规范权威源**。ID 范围、组件范式、红线均以其为准 | -| `docs_dev/uiref/*.png` | 参考图,12 张(11 张牌桌态 + 1 张建房**样式范式**,后者内容属他游戏、不可照抄) | +| `docs_dev/uiref/*.png` | 参考图,13 张(11 张牌桌态 + 叫分按钮面板 + 1 张建房**样式范式**,末者内容属他游戏、不可照抄) | | `client/js/gameabc-framework/ui/AlignmentUtils.js` | **布局求解的框架能力**。§6 的配置参数名与其入参一一对应,配置可原样喂入 | | `client/js/gameabc-framework/templates/*.template.js` | 常量文件写法蓝本。本清单落地为常量文件时按其格式 |