Files
erqiwang_youle/docs_dev/二七王-UI资源与精灵清单.md
joywayerandClaude Opus 5 8dba099717 二七王:HIST_FAN/MING_FAN maxWidth 由 490 改判定为 480,让 spacingMin 真正生效
上一版把 maxWidth 收窄到 490 只是让 RIGHT 座位恰好贴住画布边界(零余量),且
spacingMin:-96 在 28 张时永远不触底、成了死参数。裁定改为 480:
(480-110)/27-110≈-96.30 超过 spacingMin,spacing 被截断为 -96,总宽变为
28×110+27×(-96)=488,与清单原注释「每张露14px、总宽488」精确对齐——500 是笔误,
488 才是当初想要的值。

求解器验证(count=28):LEFT 16→504、RIGHT 791→1279、SELF 396→884,三座位均落在
0-1280 内且有余量。同步订正 Layout_Result.js 注释与清单 §6.9c 文字/数值。

client/tests/run.js 与 server/games/erqiwang/test/run.js 均全绿,精灵总数(380)/
布局节点数(83) 未变。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 09:08:48 +08:00

157 KiB
Raw Permalink Blame History

二七王 · 前端 UI 资源与精灵清单

本文用途:把二七王的完整游戏流程翻译成「前端需要哪些图片资源、声音、精灵、图层、群组、坐标」的可执行规格书,供美术出图与 gameabc 编辑器建资源使用。

本文不是代码。文中给出的 ID 是规划建议值(相应号段已核实为空闲,见 §0.3),用途是指导在编辑器里按此建立;代码里引用的 ID 必须与编辑器中实际建成的完全一致,若编辑器实际取值与本文不同,以编辑器为准并回头修订本文。前端红线明令「绝不编造 ID」,指的就是代码侧。

权威源:玩法规则以 server/games/erqiwang/docs/design/design.md 为准;下发字段以 server/games/erqiwang/docs/protocol/packet_protocol.md 为准;前端规范以 docs/client/development-guide/ 为准。本文只做「规则/协议 → 界面资源」的映射,不重新定义规则。

参考图:./uiref/*.png,共 16 张,设计分辨率 1280×720。


目录


0. 总则

0.0 术语(本项目修订版,优先于 design.md)

2026-08-25 修订:原 design.md 里「暗牌 / 底牌」的命名与界面按钮倒挂,现统一为:

术语 指哪 8 张 design.md 原称 当前协议字段
底牌 发牌时没有发给玩家、留在桌面的 8 张 暗牌 bottomcards
埋牌底牌 庄家埋牌时从手里扣下的 8 张 底牌 burycards(结算包为 bottom.cards)

其余术语(埋牌、扣底、甩牌、毙牌、垫牌、捡分、子、奖…)沿用 design.md §1 不变。注意「扣底」仍指 design §6.3 那条规则——闲家用主牌赢下最后一轮后翻开埋牌底牌计分;底栏那个 扣底 按钮是「查看埋牌底牌」的入口,两者同名但不同义。

✅ 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_cg(S-6 已把算奖得分拆成冲关 / 傍王两个分量),开傍王时也不会把傍王的贡献算进来。

四类「公开信息」——名字像、含义差很远

术语 谁公开给谁 给的是什么 触发 界面位置 字段
亮牌 庄家 → 两个闲家 具体牌面(庄家全部固定主牌) 庄家埋牌后固定主牌达门槛(design §8.2) 遮罩面板,同明牌版式(§1.6) liangpai.cards
余主公示 全体 → 全体 只有数量(剩余主牌数、主对数) 任一玩家报无主(design §9) 他家头像下 主N 对N 角标(§2.5) seatlist[seat][4]、baozhu
明牌 他家 → 请求者 具体牌面 可查牌 + 场上有人报无主,三家均可点、随时可查(design §9) 遮罩面板(§1.7 D-6) mingpai.others[].zhucards
开底 桌面 → 所有玩家 具体牌面(8 张底牌) 70 分坐庄,摸底之前 3 秒(design §4) 复用底牌区翻牌(§1.4 D-2) ancard3s + bottomcards

一句话记:只有「余主公示」是统计类(给数字),「亮牌」「明牌」「开底」都给具体牌面——区别在给谁的牌:亮牌给庄家自己的、明牌给他家的、开底给桌上那 8 张。

另有一组「底」字族专管发牌留桌的那 8 张牌:

术语 含义 前端对应
摸底 庄家坐定后把 8 张底牌摸起查看并入手牌 底牌区翻正面(非 70 分只有庄家看得到)
开底 70 分坐庄,摸底之前向全场翻开 3 秒 同上,但闲家侧也翻开
查底牌 对局中随时回看这 8 张 底栏 底牌 按钮(§2.6)
扣底 末轮闲家用主牌赢下,翻开埋牌底牌计分 底栏 扣底 按钮看的是埋牌底牌

「亮主」不是术语——它是选主界面的标题文案(庄家选主牌花色那一步,见 亮主.png),与上表四项都无关。文档与代码里不要拿它指代任何规则。

另:自己的主牌统计条(手牌上方 x对 x主,§2.5)不属于上表任何一项——那是本地统计、始终显示,不涉及"公开"。它在代码里叫 ZHU_STAT_*(群组 206);2026-08-27 前叫 LIANGPAI_*,因与上表第一项「亮牌」同名异实而改名,见 §0.3 群组表下的修订说明。


0.1 设计基准与座位映射

项 值 来源
设计分辨率 1280 × 720 client/output/gameabc_Project.json ScreenWidth/ScreenHeight;11 张牌桌参考图均为 1280×720;叫分按钮面板与建房参考图为局部截图
适配模式 ScreenFitMode: 1 同上
帧率 30 fps 同上
玩家数 3 人 design §2(三家各摸 28 张)

座位映射:服务端座位是绝对序号 0/1/2;前端一律把自己放在底部,另两家按 design §4 的逆时针顺序分居左上、右上。

              右上 = (mySeat + 1) % 3        左上 = (mySeat + 2) % 3
                    ┌───────────┐
        [左上玩家]  │   桌面中央 │  [右上玩家]
                    └───────────┘
                    [ 自己 · 底部 ]

方向已定论(server/games/erqiwang/class.paiju.js:264):

get_nextseat: function(seat){ return (seat + 1) % 3; }

即下家 = (seat + 1) % 3。逆时针出牌在屏幕视觉上「下家在右手边」(时钟 6 点逆时针走向 3 点),与中式牌桌「下家 = 右手边」的惯例一致。因此:

显示位 座位
底部(自己) mySeat
右上(下家) (mySeat + 1) % 3
左上(上家) (mySeat + 2) % 3

本文各表均按此书写。轮庄「顺延到其下家」(design §4.6)走的也是同一个 get_nextseat。

0.2 平台已提供、子游戏不重建的部分

参考图里有若干元素来自平台框架,美术不必重复出图、编辑器不必重复建精灵:

元素 平台提供方式 精灵/资源 子游戏要做的
头像框 / 头像 / 昵称 / 分数 02_SubGame_Input.js 转发壳 updatePlayerInfoUI 的 D 类默认渲染 底框 346+ind、头像框 376+ind、昵称 406+ind、分数 436+ind、头像图 116+ind、群组 43+ind 只在 01_SubGame_modify.js 配置区调 Game_Modify.PLAYER_INFO_LAYOUT 的坐标(三人局用 ind0 南 / ind1 东 / ind3 西)
桌面聊天气泡 / 语音气泡 同上,ShowChat / gameui_play_voice / gameui_stop_voice 聊天 背景 552+ind 文字 582+ind;语音 背景 612+ind 内容 642+ind 只调 Game_Modify.BUBBLE_LAYOUT 坐标
右侧语音圆钮 / 聊天圆钮 平台外壳 参考图右侧 (1210,310)/(1210,385) 两枚圆钮 无(仅坐标核对)
Loading / Message / Confirm 全局弹窗 框架 UIManager 全局 UI 由子游戏在 UIManager.init 注入精灵常量 若要用,需另建这三套弹窗精灵并注入;不用则跳过
战绩列表 框架 RecordView 组件 + 平台入口精灵 13 gameabc-framework/ui/RecordView.js 提供 RecordView 配置;战绩数据结构见协议「gameinfo1 / gameinfo2」
帮助界面 平台 GameUI.OpenHelp(),入口精灵 150 —— 提供二七王玩法说明文案
创建房间界面骨架 平台界面 Layer 27 CreateRoom_Layer + 约定精灵 25(确认/提交按钮) 见 01_SubGame_modify.js 顶部注释 规则选项区要子游戏自建(§1.1):渲染选项、拼 roomtype 串、注册 25 号点击后 Net.Send_create_room
解散申请 / 投票 / 同意拒绝 平台全包:Layer 420 CheckFree_Layer + GameUI.openCheck/closeCheck + Desk.self_apply_free_room / other_apply_free_room / self_agree_free_room / self_refuse_free_room / agreefree / free_room —— 无。子游戏只需处理解散结算包(§1.10),投票界面不用做
高级选项 / 代开房 Layer 28 SeniorOptions_Layer + GameUI.openSeniorOptions —— 无。它管短号 / 抽水 / 房间列表,与玩法规则选项无关,二七王的规则选项不走这里

平台已占用的图层一览(读 gameabc_Layer.json,凡此列出者子游戏都不必重建):

图层 名称 用途
27 / 28 CreateRoom_Layer / SeniorOptions_Layer 创建房间 / 高级选项
50 MainScene_Layer 牌桌主场景
202 / 416 Player_Head_Score_Layer / MainScene_PlayerInfo_Layer 玩家头像与分数
409 / 410 / 418 Chat_Voice_Layer / Chat_Text_Layer / ChatPannel_Layer 聊天与语音
420 CheckFree_Layer 解散投票
608 / 609 Help_Layer / Setting_Layer 帮助 / 设置
612 Tips_Layer 通用提示
613 updateRoomCard_Layer 房卡更新
614 / 615 Loading_Layer / Reconnect_Layer 加载 / 断线重连
616 / 619 Kick_Layer / BackHall_Layer 踢人 / 返回大厅
620 recordLayer 战绩

这些都落在框架保留段(1–100 / 201–300 / 401–500 / 601–700),与子游戏段 101–200 / 301–400 不冲突。

⚠️ 参考图底栏左侧的「头像 + 玩家昵称 + 10 + 庄」一行里,头像/昵称/分数是平台的,只有 庄 印章是二七王专属、需子游戏新建。左上/右上玩家位同理:头像框是平台的,庄 印章、主N、对N 角标、状态文字是子游戏的。

0.3 ID 号段规划

占用现状核实(读 client/output/gameabc_*.json,日期 2026-08-24):

类别 已占用 子游戏合法段 段内空闲情况
精灵 ObjectID 1–3292 中 991 个 1001–3000 段内仅 3000 被占(Spirit3000,Layer 602 inputPannel,群组 87)→ 实际可用 1001–2999
图层 LayerID 1–29, 50, 202, 402–420, 601–620 101–200 / 301–400 / 501–600 / 701+ 全部空闲
群组 GroupID 0–79 ≥ 201 全部空闲
图片资源 ID 1–439 ≥ 501 全部空闲
声音资源 ID 1–5 ≥ 101 全部空闲

二七王的分段规划:

图层(Layer)

图层 名称 用途
101 EQW_Table_Static 牌桌常驻:顶部信息条、玩家位附加标记、主牌统计条、底栏(局数 + 功能钮)
102 EQW_Hand 自己手牌区(单排 / 埋牌双排)
103 EQW_TableCards 桌面牌:底牌区、三家已出牌区、埋牌底牌展示区
104 EQW_Action 阶段操作区:叫分面板、选主/投降面板、埋牌/出牌操作条、倒计时
105 EQW_Overlay 桌面浮层:提示气泡、报无主、甩错、捡分飘字、70 分底牌亮 3 秒
302 EQW_Popup_AsetResult 小局结算
303 EQW_Popup_Account 大局总结算 / 解散结算
304 EQW_Popup_History 出牌历史面板
305 EQW_Popup_MingPai 明牌面板
306 EQW_Popup_Disband 解散投票面板 —— T-2:是否由平台提供待确认

建房规则选项区(§1.1)的精灵挂在平台创建房间界面所在的图层上,不新开图层;具体图层号需在编辑器里查证后回填(T-3)。

群组(Group)

群组 用途
201 顶部信息条(主 / 叫分 / 抓分)
202 / 203 / 204 左上家 / 右上家 / 自己 的附加标记(庄印章、主N对N、状态文字)
205 底栏功能按钮组(明牌 / 已出牌 / 上一轮 / 扣底 / 底牌)
206 主牌统计条(自己的 x对 x主,§2.5)—— 常量名 ZHU_STAT_BAR
210 自己手牌
211 底牌区(发牌留桌 8 张)
212 / 213 / 214 自己 / 左上家 / 右上家 的已出牌区
215 埋牌底牌展示区(结算时 8 张)
220 叫分面板
221 选主 / 投降面板
222 埋牌操作条
223 出牌操作条
224 倒计时(三位置)
230 桌面浮层(气泡 / 飘字 / 报无主 / 甩错)
240 小局结算
241 大局总结算
242 出牌历史
243 明牌面板
244 冲关牌型叠加层(§5.6a)
250 建房规则选项

2026-08-27 修订 · 群组 206 改名:原名「亮牌信息条 / LIANGPAI_BAR」,实为 §2.5 的自己的主牌统计条(手牌上方 x对 x主,本地统计、有手牌时常显),与 design §8.2 的「亮牌」(庄家埋牌后向两个闲家亮出自己全部固定主牌的具体牌面,走遮罩面板、群组 242)同名异实——§0.0 已专门花一节区分「亮牌 / 余主公示 / 明牌 / 开底」四类公开信息,名字撞车极易把渲染写到错误的界面上。 故统一改名为主牌统计条:群组 ZHU_STAT_BAR、精灵 ZHU_STAT_BG / ZHU_STAT_TEXT、布局节点 ZHU_STAT_BG、图片资源 BAR_ZHU_STAT(605,ID 不变)。 「亮牌」一词自此只指 design §8.2 的那件事(协议字段 liangpai、群组 242、EQW_Anim.LIANGPAI_AUTO_CLOSE),不再指本条。

精灵(Sprite,1001–2999)

号段 用途 预估用量
1001–1099 顶部信息条 + 主牌统计条 + 底栏(局数、功能钮) ~30
1100–1199 三家玩家位附加标记 + 三处倒计时 ~24
1200–1249 自己手牌 36 张 + 牌上标记 ~45
1250–1299 底牌 8 张 + 埋牌底牌 8 张 16
1300–1399 自己已出牌区(28 张 + 牌型标签) ~30
1400–1499 左上家已出牌区(28 张 + 牌型标签) ~30
1500–1599 右上家已出牌区(28 张 + 牌型标签) ~30
1600–1649 叫分面板 ~46
1650–1699 选主 / 投降面板 ~21
1700–1749 埋牌 / 出牌操作条 ~8
1750–1799 桌面浮层(气泡 / 飘字 / 报无主 / 甩错) ~15
1800–1819 小局结算面板 ~20
1820–1829 冲关牌型叠加层(精灵复制:遮罩 1 + 容器 3 + 模板 1 + 奖数 3) 8
1900–1949 大局总结算 / 解散结算 待设计
1950–1999 出牌历史面板 待设计
2000–2049 明牌面板 待设计
2050–2099 建房规则选项(3 类别标题 + 8 选项 × 2 + 房卡附注) 20
2100–2999 预留 ——

图片资源(Image,≥501)

号段 用途
501–510 牌面(3 套尺寸,见 §0.4)
511–530 花色图标(小 / 大两种尺寸)
531–570 按钮类
571–600 标记类(庄印章、角标底、牌型标签、选中标记等)
601–630 面板底图 / 光晕
631–650 数字与符号图
651–680 提示气泡 / 报无主 / 甩错
681–700 建房选项控件
701+ 预留

声音(Voice,≥101)

见 §4,整节标【待确认】。

0.4 牌面资源与 cardId → 帧号映射(唯一权威转换)

帧排列(通用规范,跨游戏统一)

牌面资源统一按 10 列 × 6 行 = 60 帧排版,行优先编号:

帧 内容
1–13 黑桃 A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K
14–26 红桃 A – K
27–39 梅花 A – K
40–52 方块 A – K
53 小王
54 大王
55–60 牌背 1 – 6(预留多套牌背,二七王使用帧 55)

二七王规则去掉了 3 和 4(design §2),因此不引用帧 3, 4, 16, 17, 29, 30, 42, 43;但资源仍按 60 帧通用排版照常出图,不留空、不重排——这套排版是所有牌类游戏共用的。

cardId → 帧号(前端只此一处实现)

服务端牌 id 的编码(server/games/erqiwang/class.paiju.js:57):

id = (deck - 1) * 54 + (flower - 1) * 13 + (number - 1)      // deck 1..2, flower 1..4, number 1..13(1=A)
小王 id = (deck - 1) * 54 + 52
大王 id = (deck - 1) * 54 + 53

服务端 flower 编号是 1 = 方块、2 = 梅花、3 = 红心、4 = 黑桃(class.pai.js:16、协议 §6),因此 id 的花色段序为 方块 → 梅花 → 红心 → 黑桃,与美术帧的花色顺序(黑桃 → 红桃 → 梅花 → 方块)正好相反。点数在段内是一致的(都 A → K)。转换必须把花色段反过来数:

// 唯一权威转换:cardId → 牌面资源帧号。全前端只此一处实现,其余模块调用它。
function cardIdToFrame(cardId) {
    var n = cardId % 54;                    // 去掉副数,deck1 / deck2 共用同一帧
    if (n === 52) { return 53; }            // 小王
    if (n === 53) { return 54; }            // 大王
    return (3 - Math.floor(n / 13)) * 13 + (n % 13) + 1;
}
var CARD_BACK_FRAME = 55;                   // 牌背(二七王固定用牌背 1)

校验样例(建资源后必须逐条对上):

cardId (deck1) 牌 n = id % 54 期望帧
0 方块 A 0 40
4 方块 5 4 44
12 方块 K 12 52
13 梅花 A 13 27
26 红桃 A 26 14
39 黑桃 A 39 1
51 黑桃 K 51 13
52 小王 52 53
53 大王 53 54
106 小王(deck2) 52 53

deck1 与 deck2 的同一张牌共用同一帧(牌面完全相同)。区分两副牌靠 cardId 本身,不靠帧。

三套尺寸

按 client 02 §2「不同显示区域尺寸不同,各自用一个独立资源 ID」的要求,开 3 套:

资源 ID 键名 用途 单帧尺寸 整图尺寸 (10×6)
501 CARD_FACE_L 自己手牌、底牌区 110 × 190 1100 × 1140
502 CARD_FACE_M 三家已出牌区 90 × 155 900 × 930
503 CARD_FACE_S 结算埋牌底牌区 50 × 70 500 × 420

单帧尺寸为参考图实测估值(§6),出图前请与最终设计稿核对。三套的帧排列完全一致,只有尺寸不同,cardIdToFrame 对三套通用。

0.5 标注约定

标记 含义
【图】 该界面/元素在 ./uiref/ 有参考图,规格按图写
【待设计】 流程/协议要求存在,但尚无设计稿,本文只列出「必须有什么」,具体视觉待美术出稿后补
【待确认】 规格本身尚未定论,需与规则设计者/美术确认,编号见 §7

怎么读参考图(重要)

参考图是界面设计示意,只看版式、位置、样式,不看数值与状态组合:

图上的东西 是否可信
元素的位置、尺寸、层级、配色、字体样式 ✅ 按图做
元素长什么样(按钮形态、角标形状、牌面排布方式) ✅ 按图做
具体数值(分数、张数、倍数、局数、ID…) ❌ 一律是填充用的假数据,不要据此反推规则或校验自洽性
同时出现的互斥元素 ❌ 是为了在一张图里把各种情况都标出来。典型:多个玩家位同时挂庄标——那是在告诉你「庄标在每个位置分别摆哪儿」,不是真会同时出现三个庄
同一张图里跨阶段并置的状态 ❌ 同上,属于叠画示意
底栏右侧那排功能按钮 ❌ 只是示意,不代表该阶段的实际显隐;显隐规则以 §2.6 为准

所以:发现图上数值算不通、或两个不该同时出现的东西同时出现,不要当成待确认项——那是示意画法。真正需要确认的是「规则本身没定」的地方。


1. 按阶段的界面清单

本节按 design §12.3 的阶段顺序走,每节说明该阶段收哪些包、渲染什么、哪些 UI 显隐。资源与精灵的完整表在 §3 / §5,本节只引用不重复。

建房(§1.1) → 发牌(§1.2) → 叫分坐庄(§1.3) → 看底牌·上庄(§1.4) → 选主/投降(§1.5) → 埋牌(§1.6)
   → 出牌对局(§1.7) → 末轮扣底 + 小局结算(§1.8) → 大局结算(§1.9) → 解散(§1.10) → 重连(§1.11)

1.1 建房 / 房间设置 【图:创建房间选项的UI参考内容根据实际二七王游戏改动.png(样式范式,非内容)】

平台提供界面骨架 + 确认按钮(精灵 25);子游戏提供规则选项区。

⚠️ 参考图是另一个游戏的建房选项(局数 8/16/24、人数 2/3/4、霸王 ×2/×4 等,二七王都没有)。 如文件名所示:只照搬视觉范式与控件样式,内容一律按二七王的 roomtype 重写。

结构模型:类别标题 + 选项组

界面由类别纵向堆叠而成,每个类别是「类别标题 + 若干选项组」:

[类别标题]  选项组1                      选项组2 …
  牌局      ◉6局  ◯12局                  ◉房主扣卡 ◯AA每人  【2张】
  模式      ◉可查牌 ◯不查牌
  规则      ▣傍王  ▣爬坡

选项组有三种类型(这是通用控件规格,不只为二七王):

类型 语义 用的选择框图
单选 组内必选其一,互斥 单选(圆钮)
多选 组内各项独立开关,可全不选、可全选 复选(方框)
单选(可不选) 组内至多选一,也可一个都不选 复选(方框)——因为它需要能表达「全不选」,视觉上不适合用单选圆钮

每个选项 = 选择框(图片精灵)+ 文字精灵,两者成对出现。

选择框图片资源为 2 × 2 = 4 帧:

帧 内容
1 单选 · 未选中
2 单选 · 已选中
3 复选 · 未选中
4 复选 · 已选中

帧号计算:frame = (useCheckbox ? 3 : 1) + (selected ? 1 : 0),其中 useCheckbox = (类型 === 多选 || 类型 === 单选可不选)。

类别标题放在一张图上多帧,一个标题一帧:

帧 内容
1 牌局
2 模式
3 规则

其余视觉细节照搬参考图:标题青绿粗体、选中项文字变橙、灰色小字附注(参考图的 【3张/人】,二七王用来显示房卡消耗)、选项多时可折行。

内容(二七王实际,对应 roomtype 5 位,协议 §0.5)

类别(帧) 选项组 类型 选项 roomtype 位 design
牌局(帧1) 局数 单选 6 局 / 12 局 位 0 §10.1
牌局(帧1) 扣卡 单选 房主扣卡 / AA 每人扣卡 + 附注房卡数 位 1 §10.1
模式(帧2) 查牌 单选 可查牌 / 不查牌 位 4 §9 / §10.2
规则(帧3) 附加规则 多选 傍王、爬坡(可同时勾选,互不冲突) 位 2、位 3 §8.3 / §7.3 / §10.3

(加粗为缺省值,即 roomtype = "00000"。三个类别正好对应 design §10.1 / §10.2 / §10.3 三个小节。)

二七王当前用不到「单选(可不选)」——四个选项组里三个是单选、一个是多选。该类型仍须在控件层实现,供后续玩法与模板克隆使用。

没有「人数」行——二七王固定 3 人(design §2),不给玩家选。参考图里的「人数」「霸王」两行不要照抄。

房卡消耗联动(协议 §0.5,随「局数 + 扣卡」两行实时变化):

扣卡方式 6 局 12 局
房主扣卡 房主 2 张 房主 4 张
AA 每人扣卡 每人 1 张 每人 2 张

职责边界(D-1 已定)

子游戏只管「类别标签 + 选项」这一块内容区。弹窗背景、标题、关闭按钮、确认按钮都由平台提供——所以 §5.8 只列内容区的精灵,不要重复建弹窗外壳。

实现要点

  • 交互:点击平台约定的 25 号精灵 → 拼 roomtype 串 → Net.Send_create_room({agentid, playerid, gameid, roomtype})。
  • 精灵:群组 250,号段 2050–2099,预置 20 个(见 §5.8);挂在平台创建房间界面所在图层(T-3)。
  • 资源:选择框(4 帧)、类别标题(3 帧)。
  • 整个界面由一份「类别 → 选项组 → 选项」的配置数据驱动渲染,不为每个选项写死代码。加一个选项 = 配置里加一条,不改渲染逻辑(工程总则 §5 OCP、§6 配置优先)。
  • roomtype 的拼串必须只在一处实现——与服务端 class.config.js parse() 对称的 SSOT 要求,不得在多处按下标硬拼。每个选项在配置里自带 bit 与 value,拼串就是遍历配置,无需按下标硬编码。
  • 房卡数不要硬编码在 UI 代码里,做成「局数 × 扣卡方式 → 房卡数」的配置表(工程总则 §6)。

配置数据形态(示意,落地位置见 §6.10):

EQW_RoomOptions = {
    categories: [
        { titleFrame: 1, /* 牌局 */ groups: [
            { key: 'aset',  type: 'radio',    bit: 0,
              items: [ {label:'6局',    value:'0'}, {label:'12局',      value:'1'} ] },
            { key: 'card',  type: 'radio',    bit: 1, note: 'cardCost',
              items: [ {label:'房主扣卡', value:'0'}, {label:'AA每人扣卡', value:'1'} ] }
        ]},
        { titleFrame: 2, /* 模式 */ groups: [
            { key: 'peek',  type: 'radio',    bit: 4,
              items: [ {label:'可查牌',  value:'0'}, {label:'不查牌',    value:'1'} ] }
        ]},
        { titleFrame: 3, /* 规则 */ groups: [
            { key: 'rules', type: 'checkbox',
              items: [ {label:'傍王', bit:2}, {label:'爬坡', bit:3} ] }   // 多选:bit 落在每一项上
        ]}
    ]
};

type 取 'radio' / 'checkbox' / 'radioOptional'(单选可不选)。选择框帧号由 type 推出,见上文公式——渲染代码不认识「傍王」「爬坡」这些具体玩法,只认识三种控件类型,这样框架侧保持游戏中立、子游戏只提供配置。

1.2 发牌 fapai 【图:等待叫分.png】

收包字段:asetidx(当前局数)、asetcount(总局数)、cards(自己 28 张)、seat(当前等待叫分者)、countdown。

渲染:

要做的事 涉及 UI
底栏局数显示 1/4 局 §2.6 底栏 · 局数文字
自己手牌 28 张,按主牌顺序排序后铺开 §2.7 手牌区(群组 210)
桌面中央 8 张底牌背面 底牌区(群组 211,帧 = 牌背 55)
顶部信息条清零:主 = 无、叫分 = 0、抓分 = 0 §2.1 顶部信息条
三家玩家位状态文字清空,主N/对N 角标隐藏 §2.2 玩家位附加标记
倒计时显示在 seat 对应的位置 §2.4 倒计时
  • 发牌动画(需要做):从右往左铺开。须遵守 client 02 §3「数据优先、表现延后」——先 setHandCards() 把 28 张写进 this.data,再播铺开动画;动画的开始/结束/出错回调里只刷界面、不写核心数据。动画缺失或卡住时,数据与界面仍须正确。动画时长、每张延迟进配置(§6.7)。
  • 排序:手牌排序规则(主牌在左还是在右、副牌花色顺序)由前端自行决定,但选主前后主牌集合会变,选主后必须重排。见 §7 T-5。

1.3 叫分坐庄 jiaofen 【图:等待叫分.png / 自己叫分.png / 自己已经叫分轮到下家叫分.png】

收包字段:seat(叫分者)、call(0 = 不叫)、currcall(当前叫到的分)、multiple(该叫分对应基础子数)、nextseat、countdown。

三种界面状态:

状态 参考图 表现
等待他家叫分 等待叫分.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)。
  • 每档 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

按钮配色:按档位位置固定,不随状态或数据变 【图:叫分按钮面板.png】

位置 档位 按钮底 角标底
1–4 70 / 65 / 60 / 55 浅黄 蓝
5–7 50 / 45 / 40 金黄 绿
8–14 35 / 30 / 25 / 20 / 15 / 10 / 5 橙 深橙

⚠️ 参考图里角标写的 1子/2子/4子 是填充假数据(§0.5),恰好与三组配色一一对应,不要据此以为「颜色随子数变」——颜色按档位位置写死,角标数值才随爬坡开关变。叫分越低(承诺越苛刻、子数越高)颜色越热。

反证:常规算子下 50/45/40 与 35…5 的 multiple 同为 6 子,但参考图里它们是两种颜色。

灰色 = 已经叫过的分数(不可再叫)。颜色只因「不可叫」变灰,不随子数档位变化。

按钮底与右上角角标(不含文字)画在同一张图上,即一个精灵一帧就同时包含按钮底色和角标底色。共 4 帧:

帧 内容
1 浅黄按钮底 + 蓝角标底(高分档 70/65/60/55)
2 金黄按钮底 + 绿角标底(中分档 50/45/40)
3 橙按钮底 + 深橙角标底(低分档 35…5)
4 灰按钮底 + 灰角标底(已叫过 / 不可选)

两种数字,两种精灵:

元素 精灵类型 说明
叫分的分数(70/65/…/5) 多帧图数字精灵(资源 NUM_CALL_SCORE,SpriteManager.setNumberImage) 带描边、需与图一致的美术字;一个精灵显示整串(两位数不拆精灵)
角标的子数(2子/7子…) 文字精灵(SpriteManager.setText) 随爬坡开关动态变,值域 2–15,用文字精灵最省

故每档 3 个精灵:按钮底(含角标底)+ 分数数字精灵 + 角标文字精灵。

2026-08-26 补充(档位分数的实现方式,务必照做):14 档里 13 档是两位数(70…10),而每档只有一个分数精灵——这是对的,不要拆成十位/个位两个精灵。 显示走平台既有接口 SpriteManager.setNumberImage(spriteId, '70', charWidth):整串文本交给一个多帧图片精灵,引擎按字符逐帧渲染,精灵宽度按字符数 × charWidth 自动调整。 不要用 setFrame 逐位切——setFrame 是"整个精灵显示第 N 帧",一次只能显示一位,用它做多位数必然要拆精灵。 资源 NUM_CALL_SCORE 须按 §3.6 的 16 帧固定帧序出图;charWidth 取 EQW_Layout.NUM_STYLE.CALL_SCORE.charWidth(§6.8,业务代码不写裸值)。

  • 可选性规则(design §4.2,由服务端权威 currcall 决定,前端只据其置灰、不自行推导规则):
    • 暂定庄家首叫:5–70 全部可选,无 不叫;
    • 其后:只有严格低于 currcall 的档位可选,不叫 可选。
  • 交互:点击某档 → 发 jiaofen { seat, call };点 不叫 → 发 jiaofen { seat, call: 0 }。
  • 悲观 UI:点击后只发包,面板的收起与状态文字的出现一律等 jiaofen 推送包到达再做(前端 05 §6)。唯一允许的乐观处理是按钮本身的防连点禁用。

上方提示条 70分坐庄才可投降:静态文字条,仅在叫分面板展开时显示。

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 秒后庄家摸入手牌、闲家侧收起
  • 开底(D-2 已定):复用「庄家摸底时翻开底牌」那套 UI(见 叫分确定庄.png——中央 8 张牌由背面翻正面),不要倒计时。 两种情形用的是同一套界面,唯一差别是谁能看到:

    情形 谁能看到这 3 秒
    非 70 分坐庄(只有摸底) 只有庄家自己(闲家侧那 8 张保持背面 / 直接收起)
    70 分坐庄(开底 → 摸底) 全场三人都能看到 3 秒

    因此不需要单独的「公示」面板,只是同一套翻牌表现的可见范围不同——精灵复用 §5.3 群组 211(底牌区),无需新增。

    【图:等待庄家选主.png】即闲家视角下的开底:中央 8 张底牌翻正面摊开,下方一条 等待庄家选主 状态提示条(见 §2.8)。

    该图把「开底摊牌」与「等待庄家选主」两个状态画在了一起,属叠画示意(见 §0.5「怎么读参考图」)。实际先后仍按 design §4:开底 3 秒 → 庄家摸底入手 → 选主,摸底后底牌区即收起。

  • 上庄后统一更新:顶部信息条 叫分 列 = grade、角标 = multiple;banker 对应玩家位显示 庄 印章(含底栏自己位)。

  • 三处 庄 印章是三个独立精灵(左上 / 右上 / 底栏),按 banker 显隐其一。

  • 重连不重放:协议明确 70 分的 3 秒亮牌是上庄时的一次性事件,deskinfo 重连不重放——前端不得在重连时补播。

1.5 选主 / 投降 xuanzhu · touxiang 【图:亮主.png】

同一决策点、二选一、互斥(design §4.4)。

选主面板规格(群组 221,号段 1650–1699):

2026-08-26 修订(其一):美术侧实际出图方式与原规格不符——花色按钮改为一张图 5 帧(帧1–4=四花色按钮,每帧已含按钮底+花色图标+右上角蓝色角标底;帧5=投降按钮,已含按钮底+「投降」字),花色图标、角标底、投降文字不再单独出精灵。按此改写以下条目,代码同步见 ImageResources.js/Sprites_Action.js/Layout_Action.js。

2026-08-26 修订(其二):张数数字用平台既有的 SpriteManager.setNumberImage(§3.6)——一个精灵就能显示整串 26张,故每花色一个数字精灵(MAIN_SUIT_COUNT_1..4 = 1674–1677);当日早前定的「十位/个位各一个精灵」(8 个)作废,空出的 1678–1681 不复用。

  • 标题斜角条:亮主 金色字 + 倒计时数字。
  • 4 个花色按钮:每个按钮由一个精灵呈现,帧 = 花色序号 1–4(服务端 flower 编号),该帧已含「按钮底 + 花色图标 + 右上角蓝色角标底」;角标底之上叠加一个对数文字精灵(N对)。
    • 按钮下方叠加张数数字精灵:该花色在庄家手中的总张数——两副牌单花色最多 26 张(两位数),用 SpriteManager.setNumberImage(spriteId, '26张', charWidth) 在一个精灵上显示整串(无需拆十位/个位),资源见 §3.6 的 NUM_MAIN_SUIT_COUNT(第16帧=张)、charWidth 见 §6.8 的 NUM_STYLE.MAIN_SUIT_COUNT
    • 右上角标文字 = 该花色的对子数(design §4/§11 明确要求)
    • 张数与对子数都由前端据 MyCards/cards 自行统计,协议 §「ChooseMain」明确「服务端不额外下发」。
  • 投降按钮:仅 touxiang === 1(即叫分 70)时显示,与 4 个花色按钮并列;按钮为一个精灵(BTN_SUIT_CHOOSE 帧5,已含底与「投降」字),不再单独出文字精灵。
  • 交互:点花色 → xuanzhu { seat, flower }(flower:1方块 2梅花 3红心 4黑桃);点投降 → touxiang { seat }。
  • 投降的后果:直接跳到结算(§1.8),不选主、不埋牌、不出牌。

收到 xuanzhu 推送后(字段 banker、flower、countdown、cards):

  • 顶部信息条 主 列显示 flower 对应的花色图标;
  • 手牌必须按新的主牌集合重排(正2/正7 升格为主牌,见 design §3);
  • 选主面板收起,进入埋牌。

1.6 埋牌 maipai 【图:庄家埋牌.png】

仅庄家,闲家此阶段等待。

界面变化:

  • 手牌从单排 36 张改为双排(上排 17 + 下排 19,实测估值)。

  • 操作条(群组 222):提示 按钮 + 倒计时 + 埋牌 (N/8) 按钮,N 为已选张数,N < 8 时按钮置灰不可提交。

  • 选中的牌上浮表示待埋。

  • 牌面上的三种标记(资源 MARK_CARD_GROUP 3 帧):

    • 拖 红色圆标 = 该牌属于一组拖拉机
    • 橙色五角星 = 正 2 / 正 7(选定花色的 2 和 7,design §3 里大小仅次于双王)
    • 蓝色五角星 = 除正2正7外的其他主牌(双王、副2、副7、主花色普通牌)

    三种标记互斥、每张牌至多一个;由前端据 flower(主牌花色)在本地标注,不需要服务端下发。

收到 maipai 推送后(字段 cards、bottomcards、seat、countdown、liangpai):

  • 庄家手牌回到单排 28 张;
  • 闲家若收到 liangpai(仅可查牌模式 + 庄家达标),弹出下方「亮牌」遮罩面板(群组 242,精灵 HIST_*,见 §5.7b / §6.9c)——不是 §2.5 那条主牌统计条(原表述「渲染 §2.5 亮牌信息条」是同名异实造成的笔误,2026-08-27 订正);
  • 进入出牌,seat = 首出者(必为庄家)。

亮牌(design §8.2,协议 liangpai):

庄家埋牌后、出牌开始前,若手中固定主牌达门槛,就向两个闲家亮出自己全部固定主牌的具体牌面。

项 说明
触发门槛(任一) 固定主牌总数 ≥10 / 王 ≥3 / 7 ≥6 / 2 ≥6
固定主牌 双王 + 全部花色的 2 + 全部花色的 7;不含主花色普通牌 A/K/Q/J/10/9/8/6/5
亮出内容 liangpai.cards,已按主牌序排好。固定的一份,不随被哪条门槛触发而增减
叫分限制 无,任何叫分档位都适用
查牌模式 仅可查牌模式下发;不查牌时闲家收不到该字段
谁能看 只有两个闲家收到(庄家自己的牌自己本来就看得见)

展示形式:与明牌同一套版式(半透黑遮罩 + 一排牌,照 冲关牌型显示.png),只是这里只有一排(庄家的)。可与 §5.7b 的明牌面板复用同一套精灵与渲染,仅数据源不同。

三个遮罩面板的关闭方式各不相同,别写混:

面板 关闭方式 遮罩是否可点
亮牌(本节) 仅自动时长,到点自动收起 ❌ 不注册点击
冲关牌型(§1.8) 点遮罩关闭 ✅ 是关闭热区
明牌 / 出牌历史(§1.7) 点遮罩关闭;明牌另可再点按钮切换 ✅ 是关闭热区

数量前端自己数——协议不再下发 zhu/zhupair/wang/qi/er 等统计,需要显示「x 张王」之类就从 cards 里算。

展示时机(T-34 已定):埋牌后、出牌前——庄家埋牌完成、服务端下发 maipai 包(其中带 liangpai)时弹出,出牌开始前收起。

  • 与 design §8.2「庄家埋牌后……出牌开始前」的规则时点一致。
  • 这是一次性弹出,不是常驻入口。关闭方式:只按自动时长关闭,不做点击关闭——遮罩不注册点击事件。时长进配置(liangpaiAutoClose,默认值待定)。
  • 只有闲家会收到 liangpai 并弹出;庄家自己不弹(自己的牌自己看得见)。
  • 不阻塞出牌:面板关闭与否不影响服务端推进,出牌包照常到达;若面板还开着就收到了出牌推送,直接收起面板即可。

1.7 出牌对局 chupai1 / chupai2 / chupai3 【图:出牌.png / 出牌2.png】

这是最复杂的阶段。

出牌操作条(群组 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 拒绝。
  • 只发意图,不发结论:不回传牌型、不回传「我最大」之类判定。
  • 前端可用 shared/ 做本地预校验与提示,结果不回传。

收 chupai1(首家出牌),字段最丰富:

字段 渲染用途
seat / cards 在该家已出牌区摆牌(资源 CARD_FACE_M)
cardtype 牌型标签(>100 单张 / >200 对子 / >300 拖拉机)
shuai 甩牌分量构成 {tractors:[], pairs, singles}——甩牌的真实结构只能读它,不得据 cardtype 反推(协议 §11 明确警告)
shuaicuo 甩错标志(= 1):整套甩牌收回,本轮只强制打出最小一张(design §5.4.5)。表现见下方「甩错提示」
flower / count 本轮首出花色与张数,供本地跟牌提示
nextseat / countdown 倒计时移到下一家
seatlist 仅可查牌模式:三家牌况,用于 §2.2 的 主N / 对N 角标
baozhu 是否已有任一玩家报无主:= 1 时触发余主公示(各家主牌数/对数),并让三家的底栏 明牌 按钮可用
cardsinhand 仅出牌者本人有:出牌后剩余手牌,据此重画手牌区

收 chupai2 / chupai3:字段类似,chupai3 额外带 maxseat(本轮谁最大)与 grade(本轮闲家得分,仅闲家有得分时才有)。

一轮结束的表现:

  • maxseat 高亮,随后三家出牌区收牌;
  • 若有 grade,播捡分飘字(+20分 金色,参考图 出牌2.png 中央 20分)→ 同时更新顶部信息条 抓分 列累计值;
  • 下一轮由 maxseat 先出。

牌型标签(参考图 出牌2.png 左下角橙色 拖拉机):需要一套标签资源,至少含 单张 / 对子 / 拖拉机 / 甩牌 / 毙 / 垫【待确认 T-11:标签种类以美术稿为准;「毙/垫/混合出牌」是否也要标】。

闲家提示 tishi 【图:自己是闲家时,底下的踩有分没分按钮.png】(design §11):

  • 闲家在出牌阶段可向对家(另一闲家)发三种提示:1 = 踩(我能大过庄家)、2 = 没分、3 = 有分。

  • 发送方收不到成功回执(协议 §13.7),只有失败才回包。

  • 接收方(对家)收到 tishi { seat, tip } → 在发送者的玩家位弹出气泡。

  • 庄家无对家,不提供此功能。

  • 自己发的提示需要本地回显:服务端只把提示转发给对家、不回执给发送者,所以发送者自己的气泡由前端在点击时本地弹出。

    这是「悲观 UI」红线的一处受控例外,成立的理由是:提示不含任何对局状态,服务端明确「不校验提示真实性」(协议 §13.7、design §11),它既不改阶段、不改控制权、不改分数,纯属玩家间的主观喊话。因此本地回显不会造成与服务端状态不一致。仍须遵守:失败回包(RULE/STEP/PARAM)到达时要把本地回显撤掉。

发起入口:底栏三个按钮 踩 有分 没分,位置就是庄标的位置——自己是闲家时没有 庄 印章,这块区域正好空出来给这三个按钮。

自己的身份 底栏该区域显示
庄家 庄 印章(1 个精灵)
闲家 踩 有分 没分(3 个按钮)

两者互斥,同一块区域二选一。注意按钮顺序是 踩 → 有分 → 没分,与协议 tip 编号(1踩 / 2没分 / 3有分)不同,映射不要按位置下标推。

气泡资源:3 × 2 = 6 帧。

箭头向左 箭头向右
踩 帧 1 帧 4
没分 帧 2 帧 5
有分 帧 3 帧 6

箭头朝向按头像相对气泡的位置选:头像在气泡左侧 → 用箭头向左的帧;头像在气泡右侧 → 用箭头向右的帧。三个座位的取用见 §6.5。

甩错提示(D-3 已定) 【图:强甩失败.png】:

  • 收到 shuaicuo === 1 时,用通用状态提示条(§2.8)显示 强甩失败,取「即时反馈类」位置预设。
  • 不做收回动画——甩出的牌不演"飞回手里",直接按服务端下发的 cards(那张被强制打出的最小主牌单张)落牌即可。
  • 提示条自动淡出,时长进配置。

报无主 → 余主公示(D-4 已定):

  • 不做全场提示。报无主本身没有独立的提示表现。
  • 唯一的界面变化是余主公示生效:他家的 主N / 对N 角标出现(服务端 baozhu=1 并整表刷新 seatlist,仅可查牌模式)。详见 §2.5。
  • 自己的主牌统计条本来就一直显示,不因报无主而变化。

明牌(design §9.3):

  • 按钮显示条件(D-6 已定,按 design 手册):可查牌模式 + 出牌阶段 + 已有任一玩家报无主(baozhu == 1)→ 三家都显示 明牌 按钮,且可随时查看、不限次数。

    判定的是「场上有人报无主」,不是「自己报无主」——报无主的那位自己也能看。与 design §9.3「一旦有玩家的主牌全部打空……为全体三人(含刚刚报无主的这位玩家自己)显示……同时界面上会出现一个『明牌』按钮」一致,也与服务端 mingpai 的受理条件 have_baofu() 一致。

  • 点击 → 发 mingpai { seat } → 收 mingpai { seat, others: [{seat, zhucards}] } → 弹出面板展示另两家全部未出主牌的具体牌面。
  • 再点一次取消是纯前端开关,不再请求服务端(协议 §13.6)。
  • 展示形式(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(遮罩 + 三家各一排牌)。

    前端自行摊平 + 排序即可,不需要改服务端:pushlist 已含全部轮次数据,且各轮内部已按本局主牌花色排好。

  • 上一轮 按钮则只取最近一轮的三家出牌(pushlist 末尾一项),版式同上。
  • 面板:图层 304,群组 242;牌用精灵复制(张数不定)。
  • 不可查牌模式下这两个按钮整体不出现(design §9)。

失败回包(协议 §0.2):任何请求被拒都会回同名 rpc 的 { success: false, errcode }。前端一律 if (!data.success) 判断,据 errcode 提示:

errcode 含义 建议提示
1 PLAYER 玩家/房间/座位校验不过 「身份校验失败」
2 NODESK 牌桌或牌局不存在 「牌局不存在」
3 STEP 当前阶段不允许 「当前阶段不能这样操作」
4 SEAT 位置不符 / 还没轮到 「还没轮到你」
5 PARAM 参数非法 「出牌数据有误」
6 RULE 规则不允许 「这样出不符合规则」

复用框架 UIManager.showMessage,无需专门资源。

1.8 末轮扣底 + 小局结算 jiesuan 【图:小局结算.png】

结算包三种来源(协议 §14):正常出牌结算(chupai + bottom + aset)、投降结算(只 aset)、解散结算(见 §1.10,投递方式完全不同)。

扣底表现(bottom 分组,design §6.3):

  • 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。

三家结算数字(aset.seatlist,每家两行):

行 内容 字段 样式
大字 本局总分 grade +20 橙色(赢)/ -10 蓝色(输),底带光晕
小字左 牌局分 N grade_jf(捡分子数得分) 白标签 + 数值
小字右 冲关分 N grade_cg(算奖得分里的冲关分量,S-6 新增;开傍王时不含傍王那部分) 白标签 + 数值

两个标签的文案已由更新后的 小局结算.png 确定(原图两个都写「牌局分」是 mock 重复,现已修正为 牌局分 / 冲关分)。

两个按钮:

按钮 位置 作用
冲关牌型(蓝色) 中央偏左 打开冲关牌型叠加层(见下)
下一局(金黄) 中央偏右 发 zhunbei { seat } 进入下一局(§1.12)

「冲关」是什么(chongguan 字段的准确定义)

服务端 class.arith.js:1277 get_chongguan(mainflower, cards)。chongguan 即 design §8.1 冲关的奖数(该规则旧称「常规算奖」,现统一叫冲关)。函数返回三项:

返回字段 含义 去向
count 关数 = 冲关奖数 aset.seatlist[i].chongguan
wang 手牌中的王数 aset.seatlist[i].wang(傍王按此计奖)
cards 王牌 + 所有参与冲关的牌,已按主牌序从大到小排好 aset.seatlist[i].cards → 冲关牌型叠加层要显示的就是它

计数规则(与 design §8.1 逐条对应):

  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 的亮牌与这里的冲关是两回事。

前端不重算冲关,chongguan / wang / naward / cards 一律直接取服务端下发值(服务端权威,红线)。上面的规则只用于理解要显示什么。

冲关牌型叠加层 【图:冲关牌型显示.png】:

点 冲关牌型 后,在结算面板之上盖一层半透黑遮罩,三家各展示自己的 aset.seatlist[i].cards,资源用 CARD_FACE_L、重叠排列。下一局 按钮在遮罩层上继续可见可点,冲关牌型 按钮本身被遮住。

关闭方式:整块全屏半透明黑遮罩本身就是关闭热区,点击遮罩即关闭。 不另设关闭按钮。因此 CG_MASK 必须注册点击事件,且 下一局 的层级要高于它、点它不被遮罩吃掉。

  • 三家牌位:左上家、右上家在各自头像内侧;自己在中央偏下。
  • 布局配置见 §6.7。

牌用精灵复制生成,不预置固定数量(见 §5.6a):cards 的张数没有小上限——四王 + 一条长连对链 + 八个 7 + 八个 2 叠加时可达 20 余张。预置精灵既会不够用,又在绝大多数局里白占 ID。

aset 其余字段的用途:

字段 用途
banker / call / flower 顶部信息条最终态
multiple 基础子数
grade 闲家最终捡分(含扣底)→ 顶部 抓分 列
upgrade 判定倍率(带符号):3 大光 / 2 小光 / 1 过庄 / -N 升 N 级(倒庄)/ -99 投降 / 0 解散。结算面板不显示判定文字——判定结果由动画呈现,见 §1.8「判定结果动画」
bangwang / climb 本局规则开关,用于结算面板上标注
cards 冲关牌型叠加层的牌(见上)
chongguan / wang / naward 冲关奖数 / 王数 / 总奖数。叠加层需要并列显示奖数——以 naward(该家总奖数 N,8.4 节的支付基数)为主;chongguan / wang 作为明细可选展示

判定结果动画(D-8)

结算面板上不做判定文字。大光 / 小光 / 过庄 / 升N级 / 投降这几个判定,由动画在两个时机呈现:

时机 数据来源 说明
对局过程中 curmultiple(随 chupai1/2/3 下发,S-1) 捡分变化导致判定档位跳变时提示,例如从「大光」掉到「小光」、或闲家捡够分数「过庄→升级」
结算前 aset.upgrade(结算包,带符号) 末轮打完、结算面板出现之前播一次最终判定

动画播放遵守「数据优先、表现延后」(client 02 §3):先 setXxx 把结算数据写进 this.data,再播动画;动画的开始/结束/出错回调里只刷界面、不写核心数据。动画缺失或卡住时,结算面板与数据仍须正确。

curmultiple 是带符号的(S-8 已改):3/2/1 = 庄家大光/小光/过庄,-N = 闲家升 N 级,0 = 叫分未定。判定动画按符号 + 绝对值两维映射即可,与结算包 aset.upgrade 同一套逻辑。

投降结算:只有 aset,无 chupai、无 bottom → 结算面板必须容忍底牌区缺失,不能因为读不到 bottom.cards 就崩或显示空框。

1.9 大局总结算 account 【图:大局结算.png】

  • 仅当打到最后一局(idx >= asetcount)时,jiesuan 包才带 account 分组。
  • 界面:图层 303,群组 241。三条玩家栏用精灵复制生成(见 §5.7a)。

版式(弹窗面板,圆角):

区 内容
标题栏(青绿底) 二七王-3人 房号{roomcode} 共{asetcount}局 {开战时间} + 右上角关闭钮
玩家栏 ×3(按名次排序,行间分隔线) 名次徽章 → 头像 → 昵称 / ID:{playerid}(两行)→ 基础分{n} / 总得分{n}(两行)→ 冲关分{n} → 傍王分{n} → 右侧大字总分
规则栏(浅绿底) 规则:可查牌、傍王、爬坡算子 —— 据 roomtype 位串拼出已启用项
面板外底部 再来一局(黄) 分享好友(蓝) 复制战绩(蓝) 退出房间(红)
  • 名次徽章:3 帧(1 金 / 2 橙 / 3 蓝,花瓣形),按总分排名取帧。
  • 总分大字:正分橙色带 +、负分蓝色带 -,复用 §3.6 的 NUM_RESULT_WIN / NUM_RESULT_LOSE。

四项分数已由 S-6 补齐:account 改为对象数组,含 grade_jf_total(基础分)/ grade_cg_total(冲关分)/ grade_bw_total(傍王分)/ score(总分),三项之和恒等于 score。

1.10 解散结算 free_room 【待设计】

投递方式与 §1.8 完全不同(协议 §14.1),前端必须单独处理:

{ app:"youle", route:"room", rpc:"free_room",
  data:{ seats:[], deskfree:{ rpc:"jiesuan", data:{ success, aset, account } } } }
  • rpc 是平台的 free_room、route 是 room,不是 erqiwang/jiesuan;
  • 真实取值路径是 data.deskfree.data.aset 与 data.deskfree.data.account(多一层 data 包装);
  • 外层 data.success 由平台填,子游戏的 success 在 data.deskfree.data.success;
  • 解散局 aset.multiple = 0、upgrade = 0、各家 grade = 0,account 恒有;
  • data.deskfree 可能缺失(开战后、首局发牌前解散时 get_disbandRoom 返回 null)→ 前端必须容忍。

界面复用 §1.9 的大局总结算面板。

解散的申请/投票/同意拒绝界面由平台全包(Layer 420 CheckFree_Layer + GameUI.openCheck + Desk.self_apply_free_room / other_apply_free_room / self_agree_free_room / self_refuse_free_room / agreefree),子游戏不做投票界面,只处理上面这个结算包。

1.11 断线重连 deskinfo

不新增任何界面。重连的本质是「恢复数据 → 调各 UI 组件 set-refresh 恢复界面」,复用与正常流程完全相同的一条重画路径(前端 04 §3.3 / 05 §6)。

平台把 deskinfo 挂在 pack.data.deskinfo 下,按当前 step 只带对应分组:

step 分组 恢复到 §1.x
1 CallRun(seat / countdown / nowcall / multiple / call[3]) §1.3 叫分
2 ChooseMain(banker / call / multiple / countdown / bottomcards 仅庄家 / touxiang) §1.5 选主
3 BuryCards(+ flower) §1.6 埋牌
5 PushCards(playproc / seatlist / liangpai / pushlist / grade / gradecards / bottomcards 仅庄家) §1.7 出牌
6 Balance(readystate / aset) §1.8 结算

另有 count / idx / PlayerInfo[3] / MyCards 全阶段通用。

关键点:

  • playproc.cards(当前轮桌面上的牌)两种查牌模式下都有 —— 否则后出的人无从跟牌;
  • pushlist(往轮历史)与 seatlist 仅可查牌模式有 —— 不查牌模式下前端不得渲染出牌历史;
  • 70 分的 3 秒亮底牌不重放;
  • 验收判据(前端 05 §6.2):任意时刻丢弃 this.data、仅凭最近一次服务端快照重画,界面必须完全一致。做不到即「前端私存了状态」或「服务端漏发了字段」,两者都要修。

1.12 准备 zhunbei

小局结算后各家点 下一局 进入下一局(§1.8),发 zhunbei { seat }。收 zhunbei { seat } → 该家玩家位显示「已准备」标记——用平台的准备标识(§0.2),子游戏不另做资源。


2. 常驻 UI

跨阶段常驻的部件,图层 101。

2.1 顶部信息条 【图:全部】

位置 x≈486–762, y≈4–72。三列表格式。

列 表头 数据 数据来源
1 主 花色图标 xuanzhu.flower / aset.flower(1方块 2梅花 3红心 4黑桃);选主前显示占位
2 叫分(绿字) 分数 + 蓝色角标 shangzhuang.grade + multiple
3 抓分(橙字) 分数 + 橙色角标 分数 = 闲家累计捡分(逐轮 chupai3.grade 累加,结算时以 aset.grade 为准);角标 = Math.abs(curmultiple)(该字段带符号,角标只取大小,见 S-8)

【待确认 T-16】:抓分 列的角标在 等待叫分.png 里是 1子、在 小局结算.png 里是 1倍,两图不一致。推定为 aset.upgrade 判定倍率(仅结算后有意义),需确认。

  • 精灵:群组 201,号段 1001–1029。
  • 资源:表格底图、花色小图标(4 帧)、角标底(2 种配色)。

2.2 玩家位附加标记 【图:全部】

平台负责头像/昵称/分数(§0.2),子游戏在其旁叠加:

元素 数据来源 显隐规则
庄 印章 shangzhuang.banker / aset.banker 三家各一个精灵,按 banker 显隐其一(含底栏自己位)
主N 角标(黄底黑字) seatlist[seat][4][0] 剩余主牌数 仅可查牌模式 + 已报无主;初始 [-1,-1] 时隐藏
对N 角标(白底黑字) seatlist[seat][4][1] 剩余主对数 同上
状态文字区 叫分阶段:60分 金色 / 不叫 白色 叫分阶段显示,进入选主后清空
  • 精灵:群组 202(左上)/ 203(右上)/ 204(自己),号段 1100–1149。

2.3 已出牌区 【图:出牌2.png】

三家各一个区域,展示本轮打出的牌(资源 CARD_FACE_M)。

  • 自己:中央偏下
  • 右上家(下家):右上,头像内侧
  • 左上家(上家):与右上家左右镜像——排列方式、牌尺寸、标签位置全部参照右上家,只是 x 方向对称、牌的堆叠朝向相反。已确认无需单独设计稿。
  • 每张牌可叠加角标:庄(橙色斜标)、大(大王圆标)等
  • 区域左下角:牌型标签(拖拉机 等,§1.7)
  • 三家的布局参数走同一份配置的 bySeat 三个变体,见 §6.5
  • 每家预置 28 个牌精灵(= 单次出牌张数上限,甩牌最多可甩满手牌)。号段每家 100 个,容量充裕,因此不使用动态复制精灵,避免 SpriteCopyUtils 的清理负担。
  • 精灵:群组 212 / 213 / 214,号段 1300–1599。

2.4 倒计时 【图:多张】

参考图里倒计时数字(12 / 15 / 20)出现在当前操作者的位置旁:

  • 轮到左上家 → 左上家头像右侧(x≈195–270, y≈165–235)
  • 轮到自己 → 自己操作区左侧(x≈445–520, y≈345–400)
  • 轮到右上家 → 对称位置

因此建 3 个倒计时精灵,按当前操作者显隐其一。

  • 数据来源:各包的 countdown。
  • 只做展示,不触发任何操作(design §11 / 协议 §0.3):倒计时归零后不自动叫分/选主/埋牌/出牌,也不判负、不跳过。前端不得在归零时做任何乐观界面推进(不跳阶段、不清控制权),一切仍等服务端推送。
  • 归零后停在 0 继续显示,不隐藏:协议 §0.3 明确归零不触发任何动作、牌局原地等待该玩家;隐藏会被误读为「已超时/已跳过」。
  • 精灵:群组 224,号段 1150–1159。
  • 精灵类型(2026-08-27 订正):3 个倒计时精灵均为多帧图数字精灵(非文字精灵)——玩家视线焦点、视觉权重最高的数字,参考图是带描边/渐变的美术字,文字精灵做不出这个效果。显示走 SpriteManager.setNumberImage,资源 NUM_COUNTDOWN(§3.6),纯秒数无后缀。见 §5.4 / §6.8。

2.5 自己的主牌统计 + 余主公示(他家)【图:多张】

这是两套不同的东西,别混为一谈:

谁的 显示在 何时显示 数据来源
自己的主牌统计 手牌上方偏左(x≈35 y≈400 那条) 有手牌时始终显示,与报无主无关 前端据 flower 本地统计自己手牌
他家的主牌数 / 对数(余主公示) 左上、右上家头像下方的 主N 对N 角标 仅可查牌模式 + 已报无主(design §9) seatlist[seat][4] = [剩余主牌数, 剩余主对数]

自己的主牌统计条(群组 206 ZHU_STAT_BAR,精灵 ZHU_STAT_BG / ZHU_STAT_TEXT):

  • 文案 x对 x主(暂定,见 §7.2 T-9),例如 3对 12主。
  • 始终显示、本地计算——自己的手牌自己完全可见,不需要服务端下发,也不受查牌模式与报无主影响。
  • 参考图里的 主牌对子: 1对 即此条。
  • 2026-08-27 改名:本条原名「亮牌条 / LIANGPAI_*」,与下方「亮牌」同名异实,已统一改为 ZHU_STAT_*(详见 §0.3 群组表下的修订说明)。

余主公示:他家的 主N / 对N 角标(群组 202 / 203,结构见 §2.2):

  • 一个图片底 + 一个文字精灵,两家各一组。
  • 初始 [-1,-1] 时隐藏;一旦全场有人报无主,服务端整表刷新 seatlist 并下发,两家的角标同时出现。
  • 不可查牌模式下永不出现。

「亮牌」(liangpai)与上面两者都不是一回事:它是 design §8.2 的规则——庄家达门槛时向闲家亮出自己全部固定主牌的具体牌面,用遮罩面板展示(§1.6,群组 242,复用 HIST_* 精灵),不是这里的统计条。 正因两者曾经同名,本条统计条在 2026-08-27 改名为 ZHU_STAT_*;代码里凡 LIANGPAI 字样自此只属于亮牌那一侧(协议字段 liangpai、EQW_Anim.LIANGPAI_AUTO_CLOSE)。

2.6 底栏 【图:全部】

y≈648–720 深色条。左侧头像/昵称/分数由平台渲染(§0.2),子游戏负责:

元素 位置(实测估值) 显隐规则
庄 印章 x≈338–370 自己是庄时显示
踩 / 有分 / 没分 按钮 x≈335–573(占用同一区域) 自己是闲家 + 出牌阶段时显示,与 庄 印章互斥(§1.7)
局数 1/4 局 居中 x≈635–700 常驻,asetidx / asetcount
右侧功能按钮共 5 个,按情况显隐(不是全部常驻):
按钮 看什么 显示条件
上一轮 上一轮所有人出的牌 可查牌 + 出牌阶段 + 已打过至少一轮
出牌历史 所有人出过的全部牌 可查牌 + 出牌阶段
明牌 另两家手中全部未出主牌的具体牌面 可查牌 + 出牌阶段 + 场上已有人报无主(baozhu==1)→ 三家都显示
扣底 埋牌底牌:庄家埋下的 8 张 仅庄家 + 已埋牌之后
底牌(查底牌) 底牌:发牌时没发给玩家、留在桌面的 8 张 庄家全程;闲家仅开底过的局(70 分坐庄)(S-3)

术语已统一:按钮名 = 术语名

本项目采用修订后的术语(2026-08-25 定,取代 design.md 原表述):

新术语 指哪 8 张 design.md 原称
底牌 发牌时没有发给玩家、留在桌面的 8 张 暗牌
埋牌底牌 庄家埋牌时从手里扣下的 8 张 底牌

改后底栏按钮名实相符:底牌 按钮看底牌、扣底 按钮看埋牌底牌,不再有命名倒挂。

协议字段也已拆开(S-4 已完成),前端按字段名取值即可,不必再按所在包判断语义:

按钮 展示 协议字段
底牌 底牌(发牌留桌 8 张) bottomcards —— shangzhuang(庄家恒有,闲家仅 70 分时有)、ChooseMain/BuryCards(仅庄家)
扣底 埋牌底牌(庄家埋的 8 张) burycards —— maipai、PushCards(仅庄家);结算包为 bottom.cards

实现要求:前端内部变量仍建议用 bottomCards / buryCards 区分,与字段名一一对应。已列入验收清单(§7.3)。

  • 精灵:群组 205,号段 1040–1069(5 个功能按钮 × 2 精灵 = 10,扣底 为 1056/1057,2026-08-27 补齐;另有 3 个提示按钮 × 2 精灵)。

2.7 手牌区 【图:全部】

形态 张数 位置(实测估值)
单排(叫分 / 出牌) 最多 36 y≈455–645,x≈35–1250,重叠排列
双排(庄家埋牌) 36(17 + 19) 上排 y≈285–455,下排 y≈455–645
  • 建 36 个手牌精灵(庄家摸底牌后的上限),资源 CARD_FACE_L。
  • 张数少于 36 时隐藏多余精灵并重算间距。
  • 选中态:牌上浮(Y 偏移),另可叠加选中标记。
  • 牌上标记(拖 圆标、⭐、🔵)见 T-8。
  • 精灵:群组 210,号段 1200–1249。

2.8 状态提示条(通用)【图:等待庄家选主.png / 强甩失败提示.png】

一条深色半透圆角条 + 居中白字,用于显示当前在等谁、或一次性的即时反馈。整个牌局复用同一个精灵,只换文字与位置。

用途 文案示例 位置(实测估值)
等待类(常驻到状态结束) 等待庄家选主、等待庄家埋牌、等待XX叫分 桌面中央 x≈500 y≈373 w≈320 h≈47
即时反馈类(自动淡出) 强甩失败 桌面中央偏上 x≈462 y≈172 w≈363 h≈50
  • 两类共用一套精灵(BAR_TOAST + 文字精灵),位置由布局配置的两个预设切换。
  • 文案表进配置,不在代码里写死字符串。
  • 精灵:图层 105 群组 230,1760 条底 + 1761 文字。

文案清单(T-33 已定)

全部 3 条。

# 文案 类型 谁看到 显示区间
1 等待庄家选主 状态类 两个闲家 收 shangzhuang 后 → 收 xuanzhu 前(§1.5)
2 等待庄家埋牌 状态类 两个闲家 收 xuanzhu 后 → 收 maipai 前(§1.6)
3 强甩失败 即时反馈 全场 收到 chupai1.shuaicuo == 1,自动淡出(§1.7)

前 2 条是「状态类」——常驻到该状态结束、由收包驱动收起;第 3 条是「即时反馈类」——自动淡出。 两类共用同一套精灵(BAR_TOAST + 文字),只切位置预设与文案。

明确不做的(已确认):

不做 理由
叫分等待 倒计时已经指明在等谁——它就显示在当前叫分者的位置旁(§2.4)
出牌等待 同上;且一局约 84 次切换,弹条只会吵
准备等待 平台自带已准备 / 未准备标识(§0.2),不重复造
玩家掉线 / 重连提示 平台已覆盖(Layer 615 Reconnect_Layer 等),子游戏不实现
开底提示 画面本身已经说清楚了——闲家看到底牌由背面翻成正面,就是开底;再加一行字是多余的

文案表进配置,不在代码里写死字符串。

原 §5.5 的 BAR_SHUAICUO(1754/1759)并入本部件——甩错只是这条通用提示条的一种文案,不必单独出图。


3. 图片资源总表

给美术清点用。按钮一律只出 1 帧普通态——点击的缩放/透明反馈由框架统一处理(client 02 §2)。 尺寸列为参考图实测估值,出图前请与最终设计稿核对。

3.1 牌面(3 套,见 §0.4)

ID 键名 用途 帧数 帧说明 单帧尺寸 整图
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

3.2 花色图标

ID 键名 用途 帧数 帧说明 尺寸
511 SUIT_ICON_S 顶部信息条 主 列 4 帧1=方块♦ 帧2=梅花♣ 帧3=红心♥ 帧4=黑桃♠(按服务端 flower 编号 1–4 排序) 30 × 30
512 SUIT_ICON_L 不需要:选主面板花色图标已并入 BTN_SUIT_CHOOSE 帧1–4(2026-08-26,美术改一张图 5 帧出图) —— —— ——

⚠️ 花色图标的帧序按服务端 flower 编号(1方块 2梅花 3红心 4黑桃),与牌面资源的花色顺序不同。两者互不换算,各自独立。

3.3 按钮

ID 键名 用途 帧数 帧说明 尺寸
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 选主 / 投降面板按钮(花色按钮 + 投降按钮,一张图 5 帧) 5 帧1–4=四花色按钮,每帧已含「按钮底 + 花色图标 + 右上角蓝色角标底」,花色序按服务端 flower 编号(帧1=方块♦ 帧2=梅花♣ 帧3=红心♥ 帧4=黑桃♠);帧5=投降按钮,已含「按钮底 + 投降二字」(2026-08-26 修订:原为按钮底单帧,花色图标/角标底/投降文字各自单独出精灵;美术侧实际按一张图 5 帧出图,改按此表) 128 × 55
534 BTN_SURRENDER 不需要:投降按钮已并入 BTN_SUIT_CHOOSE 帧5(2026-08-26) —— —— ——
535 BTN_TIP 提示 1 蓝色渐变 180 × 63
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 不需要:准备标识用平台的(§0.2) —— ——
540 BTN_TISHI 底栏 踩 / 有分 / 没分 按钮底(三者共用) 1 深色圆角,同 BTN_BOTTOM_FUNC 风格但更窄 52 × 30
541 BTN_NEXT_ASET 结算 下一局 1 金黄渐变 180 × 65
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
546 BTN_ACCOUNT_EXIT 大局结算 退出房间 1 红色渐变 190 × 60
547 BTN_ACC_CLOSE 大局结算标题栏右上角关闭 1 —— 36 × 36

3.4 标记类

ID 键名 用途 帧数 帧说明 尺寸
571 MARK_BANKER 庄 红色印章 1 —— 40 × 40
572 MARK_BANKER_CORNER 牌角 庄 橙色斜标 1 —— 28 × 28
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 牌型标签 1 只做「毙」一种(前端只展示这一个标签)。数据层仍保留 毙 / 垫 / 混合出牌 三种标识以备扩展,但当前不出图、不显示 76 × 24
577 MARK_CARD_GROUP 手牌牌型标记 3 帧1=拖(拖拉机)帧2=橙色五角星(正2 / 正7)帧3=蓝色五角星(除正2正7外的其他主牌) 26 × 26
578 MARK_SELECTED 手牌选中标记 1 待定(也可只用上浮,不出图) 待定
579 BADGE_RANK 大局结算名次徽章(花瓣形) 3 帧1=第1名(金) 帧2=第2名(橙) 帧3=第3名(蓝) 44 × 44

3.5 面板底图

ID 键名 用途 帧数 尺寸
601 PANEL_TOP_INFO 顶部三列信息条底 1 276 × 68
602 PANEL_CALL_SCORE 叫分面板底 1 575 × 170
603 BAR_HINT_TOP 70分坐庄才可投降 提示条底 1 345 × 33
604 BAR_CHOOSE_MAIN 亮主 斜角标题条 1 425 × 50
605 BAR_ZHU_STAT 主牌统计条底(半透圆角,§2.5;2026-08-27 由 BAR_LIANGPAI 改名,ID 不变) 1 210 × 35
606 PANEL_BOTTOM_CARDS 结算底牌区面板底 1 420 × 148
607 GLOW_RESULT 结算分数光晕背景 2 帧1=赢(橙) 帧2=输(蓝)
608 BAR_FOOTER 底栏深色条 1 1280 × 72
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
613 LINE_DIVIDER 玩家栏之间的分隔线 1 1060 × 2

3.6 数字与符号

2026-08-26 修订(重要,出图规范订正):数字类资源 631/632/633/635/636 一律出成 16 帧、固定帧序 0123456789.+-x/p 的多帧图片资源。 缘由:平台的 SpriteManager.setNumberImage(spriteId, text, charWidth) 就是为多位美术字数字准备的现成接口——把整串文本设给一个多帧图片精灵,引擎按字符逐帧渲染,并按字符数 × charWidth 自动调整精灵宽度。所以一个精灵就能显示一整串数字:既不用拆十位/个位,也不用 setFrame 逐位切(setFrame 是"整个精灵显示第 N 帧",只适合状态/花色/牌面这类"选其一")。 帧号由字符直接换算('0'–'9' → 帧1–10,后缀字 → 帧16),因此帧序不可重排、不可省略占位;用不到的帧位也要按顺序留出来,否则帧号对不上、画面串位。 三种显示机制的选用判据见前端文档 02-渲染与UI组件体系.md;charWidth/charHeight 等数值在 EQW_Layout.NUM_STYLE.*(LayoutConstants.js)集中配置,本表只记出图规格。

固定帧序(所有 NUM_* 通用):

帧 1–10 11 12 13 14 15 16
内容 0–9 . + - x / 可变后缀(该套资源自己的后缀字:分/倍/张)
ID 键名 用途 帧数 第 16 帧(后缀) 单字符尺寸 整图尺寸
631 NUM_COUNTDOWN 倒计时数字 16 无后缀(出空白占位) 44 × 60 704 × 60(16 × 44)
635 NUM_CALL_SCORE 叫分档位的分数数字(深棕描边美术字) 16 【待美术与规则确认】档位只显示分数数字;若日后要显示 70分 则此帧出 分 30 × 40 480 × 40(16 × 30)
632 NUM_RESULT_WIN 结算得分数字(赢,橙)——用到帧12 +、帧13 - 16 【待美术与规则确认】结算大字目前只显示数字,也可能是 分 46 × 62 736 × 62(16 × 46)
633 NUM_RESULT_LOSE 结算得分数字(输,蓝) 16 同 632(含待确认项),仅配色不同 46 × 62 736 × 62(16 × 46)
634 ANI_JUDGE 判定结果动画(大光 / 小光 / 过庄 / 升N级 / 投降)——帧动画资源,播放参数进 AnimationConfigs【待设计 D-8】。注意:这是帧动画,不适用本节的 16 帧数字规范 待定 —— 待定 待定
636 NUM_MAIN_SUIT_COUNT 选主面板花色张数数字(美术单独出图,字号配色与以上几套不同;一个花色一个精灵) 16 张(显示形如 26张) 24 × 32(估值) 384 × 32(16 × 24)

出图要求:16 帧等宽(后缀字与数字同宽,因为宽度按"字符数 × 单字宽"算);帧序严格照上表,用不到的帧位(如某些套的 . x /)仍要占位。 带描边/渐变的美术字用多帧图数字精灵 + setNumberImage(倒计时、结算得分、叫分分数、选主张数),文字精灵做不出这种效果——631–636 都要出图。 纯数据型小字用文字精灵(SpriteManager.setText / setTextWithWidth):叫分角标的子数(值域 2–15,随爬坡开关变)、主N/对N 角标、局数、主牌统计条文案等。 2026-08-26 新增 636:选主张数原计划走文字精灵,但美术侧单独出了一套数字图(字号配色不同于既有几套);同日一度定为「十位/个位各一个精灵」,现已撤销——setNumberImage 一个精灵就能显示 26张。

3.7 浮层与气泡

ID 键名 用途 帧数 帧说明 尺寸
651 BUBBLE_TISHI 踩 / 没分 / 有分 提示气泡 6(3×2) 帧1=踩·箭头向左 帧2=没分·箭头向左 帧3=有分·箭头向左 帧4=踩·箭头向右 帧5=没分·箭头向右 帧6=有分·箭头向右。帧序内层是 tip(1踩/2没分/3有分)、外层是箭头朝向 → frame = (arrowRight ? 3 : 0) + tip。箭头向左 = 头像在气泡左侧、箭头向右 = 头像在气泡右侧 待定
652 TXT_BAOZHU 不需要:报无主不做全场提示(D-4),只让他家 主N/对N 角标出现 —— —— ——
653 BAR_TOAST 通用状态提示条底(深色半透圆角,白字居中)——等待庄家选主 / 强甩失败 等共用(§2.8) 1 可九宫拉伸,按文案长度变宽 363 × 50
654 TXT_GRADE_FLOAT 捡分飘字底(20分 金色) 1 待定 待定
655 PANEL_BOTTOM_3S 不需要:底牌 3 秒展示复用庄家翻底牌那套 UI(D-2),仅可见范围不同 —— —— ——

3.8 建房选项

ID 键名 用途 帧数 帧说明 尺寸
681 ROOM_OPT_BOX 建房选择框(单选钮 + 复选框合一) 4(2×2) 帧1=单选·未选中(灰空心环) 帧2=单选·已选中(橙实心环) 帧3=复选·未选中(浅绿空方块) 帧4=复选·已选中。帧号 = (useCheckbox ? 3 : 1) + (selected ? 1 : 0);「单选(可不选)」用复选帧 3/4 22 × 22
682 ROOM_CAT_TITLE 建房类别标题(一张图多帧) 3 帧1=牌局 帧2=模式 帧3=规则 60 × 24
683 ROW_ROOM_OPT 选项行底(可选,参考图为无底透明) 1 —— 待定

4. 声音资源总表 【整节待确认 T-20】

design 与协议均未定义任何音效。以下是按牌类游戏常规推导的候选清单,未经确认,不得直接作为出音依据:

ID 键名 触发时机
101 SND_DEAL 发牌
102 SND_CALL_SCORE 叫分
103 SND_NO_CALL 不叫
104 SND_BE_BANKER 上庄
105 SND_CHOOSE_MAIN 选主
106 SND_SURRENDER 投降
107 SND_BURY 埋牌
108 SND_PLAY_CARD 出牌
109 SND_SHUAI 甩牌
110 SND_SHUAICUO 甩错
111 SND_BI 毙牌
112 SND_WIN_ROUND 赢下一轮 / 捡分
113 SND_BAOZHU 报无主
114 SND_TISHI_1/2/3 踩 / 没分 / 有分
115 SND_KOUDI 扣底
116 SND_RESULT_WIN 小局结算 · 赢
117 SND_RESULT_LOSE 小局结算 · 输
118 SND_COUNTDOWN_TICK 倒计时最后 N 秒
119 SND_BTN_CLICK 通用按钮点击

要确认的:是否需要男/女声区分、是否需要方言语音包、SND_TISHI 是否用真人语音、倒计时提示音从第几秒开始。


5. 精灵结构表

格式遵循 gameabc-framework/templates/GameView_Sprites.template.js。 ID 为规划建议值,编辑器建成后须逐个回填校准(§0 前言)。 每条注明:类型(图片/文字/容器/热区)· 用途 · 资源键 · 帧说明。

5.1 Layer 101 · 牌桌常驻

群组 精灵 ID 键名 类型 用途 资源 / 帧
201 顶部信息条 1001 TOP_INFO_BG 图片 三列表格底 PANEL_TOP_INFO
1002 TOP_SUIT_ICON 图片 主 列花色 SUIT_ICON_S 帧 = flower
1003 TOP_CALL_TEXT 文字 叫分数值 ——
1004 TOP_CALL_BADGE_BG 图片 叫分角标底 BADGE_MULTIPLE 帧1
1005 TOP_CALL_BADGE_TEXT 文字 N子 ——
1006 TOP_GRADE_TEXT 文字 抓分数值 ——
1007 TOP_GRADE_BADGE_BG 图片 抓分角标底 BADGE_MULTIPLE 帧2
1008 TOP_GRADE_BADGE_TEXT 文字 N倍【T-16】 ——
206 主牌统计条 1030 ZHU_STAT_BG 图片 半透圆角条 BAR_ZHU_STAT
1031 ZHU_STAT_TEXT 文字 自己主牌统计文案 x对 x主 ——
205 底栏 1040 FOOTER_BG 图片 底栏深色条 BAR_FOOTER
1041 FOOTER_ASET_TEXT 文字 1/4 局 ——
1042 BTN_MINGPAI 图片 明牌 BTN_BOTTOM_FUNC
1043 BTN_MINGPAI_TEXT 文字 按钮文案 ——
1044 BTN_HISTORY 图片 已出牌 BTN_BOTTOM_FUNC
1045 BTN_HISTORY_TEXT 文字 —— ——
1046 BTN_LAST_ROUND 图片 上一轮 BTN_BOTTOM_FUNC
1047 BTN_LAST_ROUND_TEXT 文字 —— ——
1048 BTN_BOTTOM_CARDS 图片 底牌 BTN_BOTTOM_FUNC
1049 BTN_BOTTOM_CARDS_TEXT 文字 —— ——
1050 BTN_TISHI_CAI 图片 踩(闲家,占庄标区) BTN_TISHI
1051 BTN_TISHI_CAI_TEXT 文字 踩 ——
1052 BTN_TISHI_HAS 图片 有分 BTN_TISHI
1053 BTN_TISHI_HAS_TEXT 文字 有分 ——
1054 BTN_TISHI_NONE 图片 没分 BTN_TISHI
1055 BTN_TISHI_NONE_TEXT 文字 没分 ——
1056 BTN_BURY_CARDS 图片 扣底(看埋牌底牌,2026-08-27 补齐) BTN_BOTTOM_FUNC
1057 BTN_BURY_CARDS_TEXT 文字 按钮文案 扣底 ——
202 左上家标记 1100 P_LEFT_BANKER 图片 庄 印章 MARK_BANKER
1101 P_LEFT_ZHU_BG 图片 主N 角标底 BADGE_ZHU_PAIR 帧1
1102 P_LEFT_ZHU_TEXT 文字 剩余主牌数 ——
1103 P_LEFT_PAIR_BG 图片 对N 角标底 BADGE_ZHU_PAIR 帧2
1104 P_LEFT_PAIR_TEXT 文字 剩余主对数 ——
1105 P_LEFT_STATUS_TEXT 文字 60分 / 不叫 ——
203 右上家标记 1110–1115 P_RIGHT_* 结构同 202
204 自己标记 1120 P_SELF_BANKER 图片 底栏 庄 印章 MARK_BANKER
1121 P_SELF_STATUS_TEXT 文字 50分 / 不叫 ——

5.2 Layer 102 · 手牌区(群组 210)

精灵 ID 键名 类型 用途 资源 / 帧
1200–1235 HAND_CARD_1 … HAND_CARD_36 图片 ×36 自己手牌 CARD_FACE_L,帧 = cardIdToFrame(id)
2100–2135 HAND_MARK_1 … HAND_MARK_36 图片 ×36 手牌牌面标记【T-8】,与 HAND_CARD_1..36 一一对应(HAND_MARK_i 属于 HAND_CARD_i) MARK_CARD_GROUP

2026-08-26 修订:原表写「牌型分组标记 ×8,1236–1243」,与本文 §1.6 的「三种标记互斥、每张牌至多一个」相矛盾——按分组理解只需 ≤8 个(一手至多 8 组拖拉机),按每张牌理解则需与手牌等量。 裁决按「每张牌」:§1.6 是行为规格、比本表的措辞更权威,且标记的三种取值(拖 / 正2正7 / 其他主牌)本就是逐张判定的属性,而非只标在拖拉机组上。实测一手 28 张牌通常带 13 个以上标记、36 张埋牌手更多,8 个远远不够。 号段改为 2100–2135(1236–1243 段太窄容不下 36 个,且其后 1250 起已被底牌区占用);1236–1243 作废、不再分配。前端 config/Sprites_Cards.js 已按此落地,core/CardMark.js 亦按每张牌返回标记。

5.3 Layer 103 · 桌面牌

群组 精灵 ID 键名 类型 用途 资源 / 帧
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 文字 标签文案 ——
213 左上家出牌 1400–1429 PLAY_LEFT_* 结构同 212
214 右上家出牌 1500–1529 PLAY_RIGHT_* 结构同 212

5.4 Layer 104 · 阶段操作区

群组 精灵 ID 键名 类型 用途 资源 / 帧
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–3 按档位位置固定 / 帧4 灰
1617–1630 CALL_BTN_NUM_1..14 多帧图数字精灵 ×14 档位分数(70…5),一个精灵显示整串(setNumberImage,两位数不拆精灵;2026-08-26,见 §1.3/§3.6) NUM_CALL_SCORE(16 帧)+ NUM_STYLE.CALL_SCORE.charWidth
1631–1644 CALL_BTN_BADGE_1..14 文字 ×14 该档 multiple 子数(2子…15子),随爬坡开关变 ——
1645 CALL_BTN_NONE 图片 不叫 BTN_NO_CALL
1646 CALL_BTN_NONE_TEXT 文字 —— ——
221 选主面板(2026-08-26 修订:美术改一张图 5 帧出图,花色图标/角标底/投降文字并入按钮帧,见 §1.5/§3.3) 1650 MAIN_TITLE_BG 图片 亮主 斜角条 BAR_CHOOSE_MAIN
1651 MAIN_TITLE_TEXT 文字 亮主 ——
1652–1655 MAIN_SUIT_BTN_1..4 图片 ×4 花色按钮(已含按钮底+花色图标+角标底),帧=花色序1–4 BTN_SUIT_CHOOSE 帧1–4
1668–1671 MAIN_SUIT_PAIR_TEXT_1..4 文字 ×4 N对,叠在对应按钮角标底之上 ——
1674–1677 MAIN_SUIT_COUNT_1..4 多帧图数字精灵 ×4 该花色在庄家手中的张数,显示 26张(一个花色一个精灵,setNumberImage;2026-08-26 由十位/个位 8 个精灵改回 4 个,见 §3.6) NUM_MAIN_SUIT_COUNT(16 帧,第16帧=张)+ NUM_STYLE.MAIN_SUIT_COUNT.charWidth
1672 MAIN_BTN_SURRENDER 图片 投降(已含按钮底+文字) BTN_SUIT_CHOOSE 帧5
1656–1659 / 1660–1663 / 1664–1667 / 1673 MAIN_SUIT_ICON_1..4 / 原 MAIN_SUIT_COUNT_1..4(文字精灵)/ MAIN_SUIT_PAIR_BG_1..4 / MAIN_BTN_SURRENDER_TEXT —— 不需要:分别并入按钮帧、或改为上方 1674–1677 的数字精灵,空出的 ID 不复用 ——
1678–1681 MAIN_SUIT_COUNT_3/4_TENS/ONES —— 不需要(2026-08-26):setNumberImage 一个精灵就能显示整串,十位/个位拆分作废,空出的 4 个 ID 不复用 ——
222 埋牌操作条 1700 BURY_BTN_TIP 图片 提示 BTN_TIP
1701 BURY_BTN_TIP_TEXT 文字 —— ——
1702 BURY_BTN_SUBMIT 图片 埋牌 BTN_BURY 帧1可提交/帧2灰
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 图片 提示(出牌阶段必备) BTN_TIP
1713 PLAY_BTN_TIP_TEXT 文字 按钮文案 ——
224 倒计时(2026-08-27 订正:由文字精灵改为多帧图数字精灵,见 §2.4/§6.8) 1150 CD_LEFT 多帧图数字精灵 左上家位倒计时 NUM_COUNTDOWN(16 帧)+ NUM_STYLE.COUNTDOWN.charWidth
1151 CD_RIGHT 多帧图数字精灵 右上家位倒计时 NUM_COUNTDOWN(16 帧)+ NUM_STYLE.COUNTDOWN.charWidth
1152 CD_SELF 多帧图数字精灵 自己操作区倒计时 NUM_COUNTDOWN(16 帧)+ NUM_STYLE.COUNTDOWN.charWidth

5.5 Layer 105 · 桌面浮层(群组 230)

精灵 ID 键名 类型 用途 资源 / 帧
1750–1752 BUBBLE_TISHI_LEFT/RIGHT/SELF 图片 ×3 踩/没分/有分 气泡(按发送者位置) BUBBLE_TISHI 帧 = tip
1753 TXT_BAOZHU —— 不需要(D-4) ——
1754 / 1759 BAR_SHUAICUO —— 并入下方通用状态提示条 ——
1760 BAR_TOAST 图片 通用状态提示条底(§2.8) BAR_TOAST
1761 TXT_TOAST 文字 提示文案(等待类 / 即时反馈类共用) ——
1755 GRADE_FLOAT_BG 图片 捡分飘字底 TXT_GRADE_FLOAT
1756 GRADE_FLOAT_TEXT 文字 20分 ——
1757 / 1758 BOTTOM_3S_* —— 不需要(D-2:底牌 3 秒展示复用底牌区翻牌,仅可见范围不同) ——

5.6 Layer 302 · 小局结算(群组 240)

精灵 ID 键名 类型 用途 资源 / 帧
1800 RESULT_BOTTOM_PANEL 图片 底牌区面板底 PANEL_BOTTOM_CARDS
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(2026-08-27 由文字精灵改,见 §1.9/§6.9) 三家总分(aset.seatlist[i].grade),正分橙带 +/负分蓝带 -,与 ACC_TPL_SCORE_NUM(1914)同一套资源与用法 NUM_RESULT_WIN(赢)/ NUM_RESULT_LOSE(输)+ NUM_STYLE.RESULT_WIN/RESULT_LOSE.charWidth
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 —— 不需要:结算面板不显示判定文字,改由动画呈现(§1.8) ——
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,精灵复制)

本层的牌用 SpriteCopyUtils 运行时复制,不预置固定张数。 aset.seatlist[i].cards 的长度不定(四王 + 长连对链 + 八个 7 + 八个 2 可达 20 余张),预置既可能不够、又在多数局里白占 ID。

只需在编辑器里建 5 个精灵(3 个容器 + 1 个牌模板 + 1 个遮罩):

精灵 ID 键名 类型 用途 资源 / 帧
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 明细见下) ——

生成方式:

// 每个座位一个容器,tag 用牌在 cards 里的下标(父精灵内唯一即可)
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.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)在遮罩之上仍需可见可点 —— 其图层内层级须高于 CG_MASK。

预置 vs 精灵复制的选用判据

判据 预置固定精灵 精灵复制
数量 有明确且不大的上限 上限不定或很大
常态占用率 多数时候都在用 多数时候只用极少几个
逐个控制 需要独立 z 序 / 动画 / 命名引用 只需批量摆位 + 设帧
清理成本 无 必须显式 remove,忘了就残留

据此,本清单的选用——全项目只有「冲关牌型」一处用复制,其余一律预置:

区域 方式 理由
冲关牌型 复制 张数不定、无小上限,多数局用不满
自己手牌(36) 预置 上限确定;需逐张选中上浮、独立动画与点击
已出牌区(28 × 3) 预置 需叠压 z 序与出牌动画,逐张独立控制
底牌(8)/ 埋牌底牌(8) 预置 固定 8 张
建房规则选项 预置 选项集固定(4 组 8 项),数量小

精灵段 1001–2999 有近 2000 个空位(§0.3),预置的 ID 开销不构成压力;复制只用在「数量真的不定」的地方,避免给每处都背上显式清理的负担。

5.7a Layer 303 · 大局总结算(群组 241,玩家栏用精灵复制)

三条玩家栏结构完全相同、仅数据不同,用 SpriteCopyUtils 复制生成;面板外壳与按钮预置。

精灵 ID 键名 类型 用途 资源 / 帧
1900 ACC_PANEL_BG 图片 面板底(圆角浅灰绿) PANEL_ACCOUNT
1901 ACC_TITLE_BAR 图片 标题栏(青绿底) BAR_ACCOUNT_TITLE
1902 ACC_TITLE_TEXT 文字 二七王-3人 房号… 共…局 … ——
1903 ACC_BTN_CLOSE 图片 右上角关闭 BTN_ACC_CLOSE
1904 ACC_RULE_BAR 图片 底部规则栏(浅绿底) BAR_ACCOUNT_RULE
1905 ACC_RULE_TEXT 文字 规则:可查牌、傍王、爬坡算子 ——
1910 ACC_ROW_CONTAINER 容器 玩家栏的复制父精灵 ——
1911 ACC_TPL_RANK 模板 名次徽章 BADGE_RANK,帧 = 名次 1–3
1912 ACC_TPL_AVATAR 模板 头像 运行时贴玩家头像
1913 ACC_TPL_TEXT 模板 通用文字(昵称/ID/各项分数,一行一个) ——
1914 ACC_TPL_SCORE_NUM 模板 右侧总分大字(数字精灵) NUM_RESULT_WIN / NUM_RESULT_LOSE
1915 ACC_TPL_DIVIDER 模板 行间分隔线 LINE_DIVIDER
1920–1927 ACC_BTN_* 图片×4 + 文字×4 再来一局 / 分享好友 / 复制战绩 / 退出房间 BTN_ACCOUNT_*

tag 分段(SpriteCopyUtils.createTagManager):rank 1–20 / avatar 21–40 / text 41–140(每行 6 条文字)/ score 141–160 / divider 161–180。 清理:关闭面板时 removeRange 清掉各段。

解散结算复用本面板(协议 §14.1,解散包也带 account),只是 aset 各项为 0。

布局配置见 §6.9a(2026-08-27 补齐;此前本 View 没有任何布局节点)。

5.7b Layer 304 / 305 · 出牌历史与明牌(群组 242 / 243,牌用精灵复制)

两者版式相同(遮罩 + 每家一排牌,照 冲关牌型显示.png),差别只在数据源与家数,共用同一套渲染:

精灵 ID 键名 类型 用途 资源 / 帧
1950 HIST_MASK 图片 半透黑遮罩(兼关闭热区) MASK_DIM
1951–1953 HIST_BOX_LEFT/RIGHT/SELF 容器 ×3 每家一个牌容器 ——
1954 HIST_CARD_TPL 模板 牌模板 CARD_FACE_L
1955–1957 HIST_LABEL_LEFT/RIGHT/SELF 文字 ×3 座位标签(昵称 / 张数) ——
2000 MING_MASK 图片 明牌遮罩 MASK_DIM
2001–2002 MING_BOX_A/B 容器 ×2 另两家各一个容器(明牌只看他家) ——
2003 MING_CARD_TPL 模板 牌模板 CARD_FACE_L
2004–2005 MING_LABEL_A/B 文字 ×2 座位标签 ——
  • 出牌历史:三家都显示,数据 = pushlist 摊平聚合到各家、按主牌序排序(§1.7 D-7)。
  • 上一轮:同一套精灵,数据只取 pushlist 末尾一项。
  • 明牌:只显示另两家,数据 = mingpai.others[].zhucards(§1.7 D-6)。
  • 亮牌:只显示一排(庄家的固定主牌),数据 = liangpai.cards(§1.6)。复用同一套遮罩 + 容器 + 牌模板,仅数据源与排数不同。 ⚠ 这里的「亮牌」是 design §8.2 那件事,与 §2.5 手牌上方的主牌统计条(群组 206 ZHU_STAT_*)无关——后者 2026-08-27 前也叫「亮牌条」,已改名以消歧义。

布局配置见 §6.9c(2026-08-27 补齐;此前 HIST_* / MING_* 都没有布局节点)。

解散投票由平台提供(Layer 420),子游戏无需精灵。

5.8 建房规则选项(群组 250,2050–2099,预置)

3 个类别、4 个选项组、8 个选项(§1.1)。选项集固定,全部预置。

精灵 ID 键名 类型 用途 资源 / 帧
2050–2052 ROOM_CAT_TITLE_1..3 图片 ×3 类别标题(牌局 / 模式 / 规则) ROOM_CAT_TITLE,帧 = 1 / 2 / 3
2053–2054 ROOM_BOX_ASET_1..2 图片 ×2 局数选择框(6局 / 12局) ROOM_OPT_BOX,单选帧 1–2
2055–2056 ROOM_TEXT_ASET_1..2 文字 ×2 局数选项文字 ——
2057–2058 ROOM_BOX_CARD_1..2 图片 ×2 扣卡选择框(房主 / AA) ROOM_OPT_BOX,单选帧 1–2
2059–2060 ROOM_TEXT_CARD_1..2 文字 ×2 扣卡选项文字 ——
2061 ROOM_TEXT_CARD_COST 文字 房卡消耗附注(灰色小字,随局数 × 扣卡联动) ——
2062–2063 ROOM_BOX_PEEK_1..2 图片 ×2 查牌选择框(可查 / 不查) ROOM_OPT_BOX,单选帧 1–2
2064–2065 ROOM_TEXT_PEEK_1..2 文字 ×2 查牌选项文字 ——
2066–2067 ROOM_BOX_RULE_1..2 图片 ×2 附加规则选择框(傍王 / 爬坡) ROOM_OPT_BOX,复选帧 3–4
2068–2069 ROOM_TEXT_RULE_1..2 文字 ×2 附加规则选项文字 ——

共 20 个精灵。挂在平台创建房间界面所在图层(T-3)。布局配置见 §6.9b。

精灵虽预置,渲染仍由 §1.1 的配置数据驱动:配置里每个选项声明自己用哪个精灵键、type(决定选择框帧号)、bit/value(决定 roomtype 拼串)。渲染代码不认识「傍王」「爬坡」这些具体玩法名。


6. 布局配置规范与配置清单

硬要求:所有布局参数一律外提为配置,业务代码零裸值。 位置、大小、排列方式、间距、对齐、朝向、缩放、文字样式——凡是「摆在哪、多大、怎么排」的参数, 全部写进布局配置文件,代码只读配置。这既是工程总则 §6「配置优先于硬编码」,也是 client 02 §2 「布局文件是纯数据:无函数、无副作用」的要求。

⚠️ 本节所有数值均为参考图(1280×720)目视实测估值,误差约 ±5px,是给美术和编辑器的起点、不是最终值。 设计稿到位后必须整体复核。但布局器类型(kind)与参数结构是设计决定,不随数值变动。

6.0 与框架 AlignmentUtils 的对齐

参数命名直接采用框架 gameabc-framework/ui/AlignmentUtils.js 的入参名,配置对象可原样喂进框架方法,中间零转换:

配置的 kind 落到框架的方法
line AlignmentUtils.distribute({direction, anchorX, anchorY, count, itemWidth, itemHeight, spacing, anchor})
fan 先算出 spacing,再走同一个 AlignmentUtils.distribute
attach(corner 为空) AlignmentUtils.alignSpriteToSprite(targetId, spriteId, hAlign, vAlign, offset)
attach(corner 有值) AlignmentUtils.alignSpriteCornerTopLeft/TopRight/BottomLeft/BottomRight(targetId, spriteId, offset)
grid 逐行调 distributeHorizontally
point 直接 SpriteManager.setPosition

对齐常量沿用框架的 AlignmentUtils.ALIGN:水平 left/center/right、垂直 top/middle/bottom。

精灵锚点恒在左上角、不可更改(AlignmentUtils 文件头注释),所有对齐都是基于锚点的换算。配置里写的 anchorX/anchorY 是对齐基准点,不是精灵左上角坐标。

6.1 五种布局器(kind)

每个部件的配置必须声明 kind,kind 决定它合法的参数集。

point — 定点

单个元素放在固定位置。

{ kind: 'point', x: 486, y: 4, w: 276, h: 68 }
// 可选:scale(倍数,业务单位)、opacity(0.0–1.0)

line — 等距排列

数量可变但间距固定的一排(底牌 8 张、埋牌底牌 8 张)。

{ kind: 'line', direction: 'horizontal',
  anchorX: 655, anchorY: 110,          // 对齐基准点
  itemWidth: 110, itemHeight: 190,
  spacing: -36,                         // 负值 = 重叠
  anchor: 'center' }                    // left | center | right

count 由运行时数据给出,不进配置。

逐项不等宽:给出可选的 items 时逐项取宽,itemWidth 失效——用于底栏功能钮组(74/87/93/78)与埋牌操作条(180/60/180)这类宽度不一的排:

{ kind: 'line', direction: 'horizontal',
  anchorX: 1250, anchorY: 672, itemHeight: 30, spacing: 15, anchor: 'right',
  items: [ {key:'BTN_MINGPAI', width:74}, {key:'BTN_HISTORY', width:87},
           {key:'BTN_LAST_ROUND', width:93}, {key:'BTN_BOTTOM_CARDS', width:78} ] }

fan — 自适应压缩排

张数可变、总宽受限、需要动态压缩间距的牌排(手牌、出牌区、冲关牌)。

{ kind: 'fan', direction: 'horizontal',
  anchorX: 640, anchorY: 455,
  maxWidth: 1215,                       // 可用总宽上限
  itemWidth: 110, itemHeight: 190,
  spacingMax: 0,                        // 张数少时的最大间距(0 = 紧贴不重叠)
  spacingMin: -84,                      // 张数多时的最大重叠量(负值)
  anchor: 'center',
  overlapFrom: 'left' }                 // left = 右边的牌压在左边的牌之上

间距算法(唯一实现,不散落):

count <= 1            → spacing 不参与,直接按 anchor 摆一张
otherwise             → raw     = (maxWidth - itemWidth) / (count - 1) - itemWidth
                        spacing = clamp(raw, spacingMin, spacingMax)

overlapFrom 决定 z 序方向:'left' 时后面的牌盖住前面的(自己手牌、右上家);'right' 时反过来(左上家镜像用)。

grid — 网格

固定行列的按钮阵(叫分 14 档 = 7×2)。

{ kind: 'grid',
  anchorX: 640, anchorY: 160,
  cols: 7, rows: 2,
  itemWidth: 74, itemHeight: 56,
  spacingX: 7, spacingY: 24,
  anchor: 'center',
  fillOrder: 'row' }                    // row = 先填满一行再换行

attach — 相对贴附

贴在另一个精灵上的从属元素(角标贴按钮、庄标贴头像、气泡贴头像)。

{ kind: 'attach',
  target: 'P_LEFT_AVATAR',              // 目标精灵的键名,不写 ID
  hAlign: 'right', vAlign: 'top',
  offsetX: 8, offsetY: -4,
  corner: 'topRight' }                  // 可选;有值 = 贴到目标【外侧】角,无值 = 在目标【内部】对齐

target 一律写键名而非数字 ID——ID 回填时只改一处映射表,配置文件不用动。

6.2 座位变体 bySeat

三个显示位上的同名部件共用一份配置,差异写在 bySeat 里;未列出的字段继承外层 base。

PLAY_AREA: {
    kind: 'fan', direction: 'horizontal',            // ← base:三家共同的部分
    itemWidth: 90, itemHeight: 155,                  //   (牌尺寸、压缩规则三家一致)
    maxWidth: 170, spacingMax: -35, spacingMin: -62,
    bySeat: {
        SELF:  { anchorX: 650, anchorY: 265, anchor: 'center', overlapFrom: 'left'  },
        RIGHT: { anchorX: 1022, anchorY: 120, anchor: 'center', overlapFrom: 'left'  },
        LEFT:  { anchorX: 258,  anchorY: 120, anchor: 'center', overlapFrom: 'right' }   // 与 RIGHT 左右镜像
    }
}

座位键固定为 SELF / LEFT / RIGHT(显示位,不是服务端座位号)。服务端座位 → 显示位的换算见 §0.1,只在一处实现。

6.3 文字样式 textStyle

文字精灵的样式也进配置,不在代码里写字号颜色。

{ fontSize: 24, color: '#FFFFFF', align: 'center', maxWidth: 130, bold: false }

6.4 牌尺寸档

三套牌面尺寸集中定义,各区域引用档名,不重复写数字。

CARD_SIZE: {
    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' }    // 结算埋牌底牌
}

改牌面尺寸只动这一处,所有引用它的区域自动跟随。


6.5 常驻区配置

部件 kind 关键参数(实测估值)
顶部信息条底 point x:486 y:4 w:276 h:68
顶部 · 花色图标 attach target:TOP_INFO_BG, hAlign:left, vAlign:bottom, offsetX:20, offsetY:-8
顶部 · 叫分角标 attach target:TOP_CALL_TEXT, corner:topRight, offsetX:4, offsetY:6
顶部 · 抓分角标 attach target:TOP_GRADE_TEXT, corner:topRight, offsetX:4, offsetY:6
主牌统计条(节点 ZHU_STAT_BG) point x:35 y:400 w:210 h:35
底栏条 point x:0 y:648 w:1280 h:72
底栏 · 局数文字 point x:635 y:672 w:65 h:26,textStyle{fontSize:20, align:center}
底栏 · 功能钮组(明牌/已出牌/上一轮/扣底/底牌) line + items direction:horizontal, anchorX:1250, anchorY:672, itemHeight:30, spacing:15, anchor:right,items:[74,87,93,78†,78](逐项不等宽,见 §6.1)。†扣底 的 78 是估值(2026-08-27 补项,本表原只列 4 项)——参考图(等待叫分.png)底栏当时也只画出 底牌 一项;依据取自 底牌 实测的 78,不能笼统说「两字按钮 = 78」:同为两字的 明牌 实测只有 74,两者不同,待设计稿复核
底栏 · 庄标 point x:338 y:668 w:32 h:34
底栏 · 提示按钮组(踩/有分/没分) line direction:horizontal, anchorX:335, anchorY:672, itemWidth:52, itemHeight:30, spacing:26, anchor:left
右侧语音钮(平台) point x:1210 y:310 w:56 h:56
右侧聊天钮(平台) point x:1210 y:385 w:56 h:56

6.6 玩家位配置(含气泡朝向)

平台负责头像/昵称/分数,子游戏的附加标记全部 attach 到平台头像框上——这样平台布局一调,标记自动跟随。

部件 kind 参数
头像框(平台) point bySeat{ LEFT:{x:22,y:122}, RIGHT:{x:1160,y:122}, SELF:{x:22,y:645} },w:91 h:118(SELF 为 84×53)。需同步写进 Game_Modify.PLAYER_INFO_LAYOUT(§6.11)
庄 印章 attach bySeat{ LEFT:{corner:'topRight',offsetX:7,offsetY:8}, RIGHT:{corner:'topLeft',offsetX:-40,offsetY:8}, SELF:{point x:338 y:668} }
主N 角标 attach target:头像框, corner:bottomLeft, offsetX:0, offsetY:6, w:40 h:19
对N 角标 attach target:主N角标, hAlign:right, vAlign:middle, offsetX:44, offsetY:0
状态文字(60分/不叫) point bySeat{ LEFT:{x:170,y:165}, RIGHT:{x:980,y:165} },w:130 h:70,textStyle{fontSize:46, align:center}
倒计时(多帧图数字精灵,2026-08-27 订正) point bySeat{ LEFT:{x:195,y:165}, RIGHT:{x:1010,y:165}, SELF:{x:445,y:345} },h:NUM_STYLE.COUNTDOWN.charHeight(60);w 运行时注入(1–2 位数字,setNumberImage 按字符数 × charWidth 自动改宽)

提示气泡的朝向与位置(资源 BUBBLE_TISHI 6 帧,§3.7):

气泡属于 头像在气泡的 用帧 贴附方式
左上家 左侧 箭头向左(帧 1–3) attach{ target:LEFT头像框, hAlign:right, vAlign:middle, offsetX:+10 }
右上家 右侧 箭头向右(帧 4–6) attach{ target:RIGHT头像框, hAlign:left, vAlign:middle, offsetX:-10 }(气泡向左展开)
自己 左侧 箭头向左(帧 1–3) attach{ target:SELF头像, hAlign:right, vAlign:top, offsetX:+10, offsetY:-70 }

帧号计算:frame = (arrowRight ? 3 : 0) + tip(tip:1踩 / 2没分 / 3有分)。 朝向本身也应是配置项(arrowRight: true|false)而非代码里按座位硬判。

自己发的提示,本人看不到自己的气泡(协议 §13.7 不回执,且只转发给对家)。表格里列出 SELF 的气泡配置,是为了「另一闲家看到我的气泡」时——那时在对方屏幕上我处于 LEFT 或 RIGHT 位。SELF 位的气泡实际不会出现【待确认 T-26:是否需要给自己一个本地回显】。

6.7 牌区配置

区域 kind 参数(实测估值)
自己手牌 · 单排 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 属填充画法、不作依据(§0.5)
手牌 · 选中上浮 —— 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 张)
已出牌区 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+ 张的极端情况

6.8 阶段操作区配置

2026-08-26 修订(其一):选主面板花色图标、对数角标底已并入按钮帧(见 §1.5/§3.3),对应布局节点删除。 2026-08-26 修订(其二):数字统一走 SpriteManager.setNumberImage(§3.6)后,一个多位数只占一个精灵——花色张数的「十位 / 个位」两个节点合并为一个 MAIN_SUIT_COUNT。 两个数字节点的 h 恒为单字高,直接引用 EQW_Layout.NUM_STYLE.*.charHeight(SSOT:数值只在 LayoutConstants.js 定义一处,布局文件不再手抄);w 则留到运行时注入——setNumberImage 会按「字符数 × charWidth」自动改精灵宽,位数变宽度就变。

部件 kind 参数(实测估值)
叫分 · 面板底 point x:355 y:140 w:575 h:170
叫分 · 提示条 point x:470 y:100 w:345 h:33
叫分 · 14 档按钮 grid anchorX:640 anchorY:160 cols:7 rows:2 itemWidth:74 itemHeight:56 spacingX:7 spacingY:24 anchor:center fillOrder:row
叫分 · 档位分数数字 attach target:对应档位按钮, hAlign:center, vAlign:middle, offsetY:4, h:NUM_STYLE.CALL_SCORE.charHeight(40);w 运行时注入(= 字符数 × 30,由 setNumberImage 自动设)
叫分 · 档位子数角标 attach target:对应档位按钮, corner:topRight, offsetX:-30, offsetY:2
叫分 · 不叫 按钮 point x:553 y:345 w:184 h:57
叫分 · 自己叫分大字 point x:570 y:320 w:140 h:70,textStyle{fontSize:52, align:center}
选主 · 标题斜角条 point x:330 y:315 w:425 h:50
选主 · 4 花色 + 投降 line direction:horizontal anchorX:330 anchorY:373 itemWidth:128 itemHeight:55 spacing:9 anchor:left(共 5 项;投降不显示时只排 4 项,anchor:left 保证前 4 个位置不变)
选主 · 张数 attach target:对应花色按钮, hAlign:center, vAlign:bottom, offsetY:-6, h:NUM_STYLE.MAIN_SUIT_COUNT.charHeight(32);w 运行时注入(9张=2 字符、26张=3 字符,宽度随之变)。一个花色一个精灵
选主 · 对数角标文字 attach target:对应花色按钮, corner:topRight, offsetX:-36, offsetY:2(按钮帧内已含角标底,本节点只定位叠加文字)
埋牌 · 操作条 line + items direction:horizontal anchorX:640 anchorY:165 itemHeight:63 spacing:45 anchor:center,items:[180,60,180](提示 / 倒计时 / 埋牌)
出牌 · 操作条 line + items direction:horizontal anchorX:446 anchorY:345 itemHeight:55 spacing:35 anchor:left,items:[75,157,180‡](倒计时 / 出牌 / 提示)。‡提示 的 180 是估值(2026-08-27 补项,本表原漏了 §1.7 明确要求的 提示 按钮)——与埋牌条的 提示 同资源 BTN_TIP(§3.3 实测 180×63),埋牌条 items 首项亦取 180,故沿用;顺序照 §1.7 行文。⚠ 本条 itemHeight:55 对齐的是 BTN_PLAY(157×55),而 BTN_TIP 原生高 63,高度差待设计稿裁定。2026-08-27 再订正:补「提示」项后若沿用 anchor:center,整排重新居中会把已有的倒计时/出牌两项相对原先(仅 2 项时)左移 107.5px,导致「出牌」按钮偏离参考图 出牌.png 的实测位置(556–711)。改为 anchor:left, anchorX:446(= 参考图出牌按钮实测起点 556 − 倒计时宽 75 − 间距 35),求解结果:倒计时 x=446、出牌 x=556(与实测吻合)、提示 x=748
捡分飘字 point x:570 y:180 w:170 h:55;另配 floatRise:-60、floatDuration:800(动画参数也进配置)
状态提示条 · 等待类 point x:500 y:373 w:320 h:47(§2.8)
状态提示条 · 即时反馈类 point x:462 y:172 w:363 h:50;另配 toastDuration:1500

多帧图数字样式配置 EQW_Layout.NUM_STYLE(2026-08-26 新增,在 LayoutConstants.js,与 CARD_SIZE/TEXT_STYLE 并列)——setNumberImage 所需数值的唯一出处,业务代码不许内联:

键 res(资源键名) charWidth charHeight suffix(第16帧后缀) 典型显示
COUNTDOWN NUM_COUNTDOWN 44 60 ''(无) 15
RESULT_WIN NUM_RESULT_WIN 46 62 ''(第16帧待确认) +120
RESULT_LOSE NUM_RESULT_LOSE 46 62 ''(同上) -120
CALL_SCORE NUM_CALL_SCORE 30 40 ''(第16帧待确认) 70
MAIN_SUIT_COUNT NUM_MAIN_SUIT_COUNT 24 32 张 26张
  • charWidth 是 setNumberImage 的入参,精灵宽度 = 字符数 × charWidth(该接口自动设),所以布局节点的 w 是运行时值、不写死在配置里。
  • charHeight 供布局节点定 h(setNumberImage 不改高度)。
  • suffix 只能是 '' / 分 / 倍 / 张——接口内部把这三个字统一编码到第 16 帧,写别的字不会被识别。
  • res 存的是资源键名而非 ID(与 CARD_SIZE.res 同一约定):布局文件是纯数据、不引用其他模块,调用方用 EQW_Images[style.res] 取真实 ID。

6.9 结算区配置

部件 kind 参数(实测估值)
底牌面板底 point x:430 y:140 w:420 h:148
底牌说明文字 attach target:底牌面板底, hAlign:center, vAlign:bottom, offsetY:-14
三家分数光晕 point bySeat{ LEFT:{x:175,y:150}, RIGHT:{x:865,y:150}, SELF:{x:490,y:340} },w:225 h:100
三家总分大字(多帧图数字精灵,2026-08-27 由文字精灵改,见 §1.9/§5.6) attach target:对应光晕, hAlign:center, vAlign:middle,h:NUM_STYLE.RESULT_WIN.charHeight(62)(与 RESULT_LOSE 相同);w 运行时注入
三家 牌局分 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
下一局 按钮 point x:835 y:518 w:180 h:65
冲关遮罩 point x:0 y:0 w:1280 h:720,opacity:0.72(透明度也是配置项)

6.9a 大局总结算配置(§1.9 / §5.7a,2026-08-27 补齐)

本表原先整块缺失——Layout_Result.js 里一个 ACC_* 节点都没有,实现时极易在渲染代码里就地硬编码坐标(违反 §6 零裸值)。 坐标全部是 uiref/大局结算.png 的目视实测估值(±5px),w/h 取 §3.5 / §3.3 的资源尺寸(那是权威值)。待设计稿复核。 玩家栏是精灵复制(§5.7a),故不逐行写死,而是给「容器 + 行节点(行高即 itemHeight)+ 行内模板贴附到行矩形」;行数由数据给出(ctx.count),不进配置。 ⚠ ACC_ROW 及贴附其上的节点求出的坐标都是相对 ACC_ROW_CONTAINER 的——复制精灵是容器的子精灵,x/y 本就相对容器,求解结果可直接喂 SpriteCopyUtils.create(与 §5.6a 冲关牌同一用法)。

部件 节点名 kind 参数(目视实测估值)
面板底 ACC_PANEL_BG point x:80 y:88 w:1100 h:540
标题栏 ACC_TITLE_BAR attach target:ACC_PANEL_BG, corner:topLeft, offset(0,0), w:1100 h:56
标题文字 ACC_TITLE_TEXT attach target:ACC_TITLE_BAR, hAlign:left, vAlign:middle, offsetX:30;w/h 运行时注入(文案长度不定)
关闭按钮 ACC_BTN_CLOSE attach target:ACC_TITLE_BAR, corner:topRight, offset(-20,10), w:36 h:36
规则栏 ACC_RULE_BAR attach target:ACC_PANEL_BG, corner:bottomLeft, offset(0,0), w:1100 h:62
规则文字 ACC_RULE_TEXT attach target:ACC_RULE_BAR, hAlign:left, vAlign:middle, offsetX:30;w/h 运行时注入
玩家栏容器 ACC_ROW_CONTAINER point x:80 y:144 w:1100 h:422(标题栏下沿 → 规则栏上沿)
玩家栏行 ACC_ROW line direction:vertical, anchorX:0, anchorY:14, itemWidth:1100, **itemHeight:132(行高)**, spacing:0, anchor:top(相对容器;行数 = ctx.count)
行内 · 名次徽章 ACC_TPL_RANK attach target:ACC_ROW, hAlign:left, vAlign:middle, offsetX:28, w:44 h:44
行内 · 头像 ACC_TPL_AVATAR attach target:ACC_ROW, hAlign:left, vAlign:middle, offsetX:92, w:80 h:80
行内 · 文字栅格(6 条文字的槽位) ACC_ROW_TEXT_GRID grid anchorX:192, cols:4, rows:2, itemWidth:176, itemHeight:34, spacingX:0, spacingY:10, anchor:left, fillOrder:row;anchorY 运行时注入(随所在行浮动)。列序:昵称/ID: · 基础分/总得分 · 冲关分 · 傍王分(第 2 行仅前两列有文字)。估值精度:本节点是等距列模型(相对容器 192/368/544/720),参考图目视实测列 x 约 272/455/634/800(列距 183/179/166,并不等距),偏差约 10px,比本节头部通用的「±5px」更大,待设计稿复核
行内 · 右侧总分大字 ACC_TPL_SCORE_NUM attach target:ACC_ROW, hAlign:right, vAlign:middle, offsetX:-25, h:NUM_STYLE.RESULT_WIN.charHeight(62);w 运行时注入
行内 · 分隔线 ACC_TPL_DIVIDER attach target:ACC_ROW, hAlign:center, vAlign:bottom, offset(0,0), w:1060 h:2(vAlign:bottom 的语义是"目标底边之下",见 §6.0)
面板外底部 4 按钮 ACC_FUNC_BUTTONS line direction:horizontal, anchorX:345, anchorY:640, itemWidth:190, itemHeight:60, spacing:25, anchor:left(参考图里这排不居中于屏幕、整体偏右,故用 anchor:left 定起点)

6.9b 建房规则选项配置(§1.1)

布局是两层嵌套:类别竖排,类别内的选项组横排。

部件 kind 参数(按参考图比例估,实际以平台建房界面尺寸为准)
类别(竖排) line direction:vertical, anchorX:0, anchorY:0, itemHeight:32, spacing:8, anchor:left;itemHeight 为单行类别高,折行类别按实际行数累加
类别标题 attach target:所在类别行, hAlign:left, vAlign:middle, offsetX:0;ROOM_CAT_TITLE 帧 = 类别序号
类别内选项槽(横排) line direction:horizontal, anchorX:70, itemWidth:150, spacing:0, anchor:left(itemWidth = 一个「选择框 + 文字」的槽宽)
选项组之间的额外间隔 —— groupGap: 40(同类别下两个选项组之间比组内选项多留的间距,配置项)
选择框 attach target:所在选项槽, hAlign:left, vAlign:middle
选项文字 attach target:同槽的选择框, hAlign:right, vAlign:middle, offsetX:8
房卡附注 attach target:扣卡组最后一个选项, hAlign:right, vAlign:middle, offsetX:20,textStyle{fontSize:16, color:'#999999'}
折行 grid 选项数超过 maxPerRow 时改用 grid{cols:maxPerRow, spacingX:0, spacingY:8, fillOrder:'row'};maxPerRow: 4(配置项,参考图「玩法」行即 4 列折 2 行)。二七王每组最多 2 项,不会触发

文字选中态也是配置(单选选中时文字变橙):

ROOM_OPT_TEXT: {
    normal:   { fontSize: 18, color: '#DDDDDD' },
    selected: { fontSize: 18, color: '#E8873A' }
},
ROOM_CAT_TITLE_STYLE: { fontSize: 18, color: '#7FBFB0', bold: true, align: 'right', maxWidth: 60 }

不要在代码里写死 '#E8873A'。

6.9c 出牌历史 / 亮牌 · 明牌配置(§5.7b,2026-08-27 补齐)

本表同样原先整块缺失(HIST_* / MING_* 一个节点都没有)。 两者与冲关牌型叠加层是同一种版式(半透黑遮罩 + 每家一排重叠大牌,参考图同为 uiref/冲关牌型显示.png),故照 §6.7 的 CHONGGUAN_FAN 同构给出,三家锚点沿用冲关牌的 LEFT 260,120 / RIGHT 1035,120 / SELF 640,400。 与冲关牌的唯一差别是张数上限:出牌历史摊平后可达 28 张以上,maxWidth:420 装不下。 2026-08-27 订正:原估值 maxWidth:500 的推导算错了——fan 的间距公式是 spacing = max(spacingMin, min(spacingMax, (maxWidth-itemWidth)/(count-1) - itemWidth)),代入 maxWidth 500 / itemWidth 110 / count 28 得 (500-110)/27-110 ≈ -95.56,没有触到 spacingMin:-96 的下限;而 fan 的总宽恒等于 maxWidth(只要 spacing 未被下限截断),并不是旧注释算的「488」。RIGHT 座位锚点 anchorX:1035 配合总宽 500、anchor:center,整排右边缘落在 1035+250=1285,超出 1280 设计画布 5px(LEFT/SELF 因锚点更靠左未暴露)。 2026-08-27 再订正(裁定 maxWidth:480):曾先收窄到 maxWidth:490 让 RIGHT 恰好贴住 1280,但零余量太脆弱(这些锚点本身是参考图目视实测、±5px 误差),且 490 时 spacingMin:-96 永远不触底、是个死参数,与「每张最窄只露 14px」这条约束名存实亡;旧注释原写的「每张露 14px、总宽 488」正是 spacingMin 触底后的结果,说明 488 才是当初想要的值,maxWidth:500 是与注释不符的笔误。改为 maxWidth:480:代入公式 (480-110)/27-110 ≈ -96.30,触及 spacingMin:-96 下限,实际 spacing 截断为 -96(不再等于 raw),总宽 = 28×110 + 27×(-96) = 488(不再等于 maxWidth,因为 spacing 已被下限截断)。spacingMin:-96 就此真正生效、不再是死参数;每张露 110-96=14px,与旧注释精确一致。求解验证(count=28):LEFT 首尾 x = 16 → 504,RIGHT 首尾 x = 791 → 1279,SELF 首尾 x = 396 → 884,均落在 0–1280 内且有余量(RIGHT 距边界 1px、LEFT/SELF 余量更大)。maxWidth:480 与 spacingMin:-96 仍是估值,待设计稿复核。 已知限制:每张仅露 14px、视觉偏窄,待设计稿复核是否改为分两排显示,或改用 CARD_SIZE.M——这是估值阶段接受的限制,留给后续复核。 牌用精灵复制:三个容器精灵摆在原点、尺寸铺满屏,故 fan 求出的屏幕坐标可直接当容器内坐标用。

部件 节点名 kind 参数
出牌历史 · 遮罩 HIST_MASK point x:0 y:0 w:1280 h:720, opacity:0.72(【亮牌】用途下不注册点击,见 §1.6)
出牌历史 · 三个牌容器 HIST_BOX point x:0 y:0 w:1280 h:720(同摆原点、铺满屏)
出牌历史 · 每家一排牌 HIST_FAN fan size:L, anchor:center, maxWidth:480, spacingMax:-40, spacingMin:-96;bySeat{ LEFT:{260,120}, RIGHT:{1035,120}, SELF:{640,400} }。求解验证(count=28,spacing 触底 -96、总宽 488):LEFT 首尾 x = 16 → 504,RIGHT 首尾 x = 791 → 1279,SELF 首尾 x = 396 → 884,均落在 0–1280 内且有余量
出牌历史 · 座位标签 HIST_LABEL point bySeat{ LEFT:{200,318}, RIGHT:{975,318}, SELF:{580,598} };w/h 运行时注入
明牌 · 遮罩 MING_MASK point 同 HIST_MASK
明牌 · 两个牌容器 MING_BOX point 同 HIST_BOX
明牌 · 每家一排牌 MING_FAN fan 同 HIST_FAN,但 bySeat 只有 LEFT / RIGHT(明牌只看他家,没有自己那排;精灵 MING_BOX_A 落 LEFT 位、MING_BOX_B 落 RIGHT 位)
明牌 · 座位标签 MING_LABEL point bySeat{ LEFT:{200,318}, RIGHT:{975,318} };w/h 运行时注入

6.10 配置文件组织

按 client 02 §2 的三件套拆分,布局部分建议再按界面拆文件,用保护性声明合并:

codes/config/
    LayoutConstants.js            // var EQW_Layout = EQW_Layout || {};  —— 总则:CARD_SIZE、textStyle 预设、座位键
    Layout_Table.js               //   常驻区(§6.5)+ 玩家位(§6.6)
    Layout_Cards.js               //   牌区(§6.7)
    Layout_Action.js              //   阶段操作区(§6.8)
    Layout_Result.js              //   结算区(§6.9)
    Layout_CreateRoom.js          //   建房规则选项(§6.9b)
    ImageResources.js             // 图片资源 ID(§3)
    SoundResources.js             // 声音资源 ID(§4)
    Sprites_*.js                  // 精灵结构(§5)

每个文件顶部 var EQW_Layout = EQW_Layout || {};,加载后合并为一份(client 02 §2「多文件用保护性声明」)。

布局文件是纯数据:不得出现函数、不得引用其他模块、不得有副作用。fan 的间距算法、bySeat 的合并、attach 的换算都属于布局求解器的职责,放在 codes/ui/LayoutSolver.js(或直接调 AlignmentUtils),不写进配置文件。

6.11 与平台布局配置的衔接

平台的玩家信息与气泡布局在 01_SubGame_modify.js 的配置区(该文件只允许在配置区填值):

  • Game_Modify.PLAYER_INFO_LAYOUT.POSITIONS —— 平台默认 ind0 南 (6,592)、ind1 东 (1186,85)、ind3 西 (7,59),与 §6.6 实测值不一致,须改为 §6.6 的值。
  • Game_Modify.BUBBLE_LAYOUT.POSITIONS —— 平台聊天/语音气泡锚点,同样按三人局位置调整。

这两处是平台契约配置,与子游戏自己的 EQW_Layout 是两份东西,但坐标必须一致(否则平台画的头像和子游戏贴的庄标会错位)。建议:EQW_Layout 里的头像框坐标为权威,01_SubGame_modify.js 配置区手工抄写并在注释里注明「与 EQW_Layout.PLAYER.AVATAR 保持一致」【T-28:转发壳配置区不能引用 codes,只能手工同步,需在验收清单里加一条一致性检查】。


7. 待补充清单

状态汇总(2026-08-26):待确认规格 34 项只剩 T-20 音效(已明确后补);设计稿只剩 D-8(判定结果动画)。 §7.5 服务端待补项 8 条全部处理完毕。服务端侧无遗留——D-8 只差动画设计稿与触发细节。

7.1 待出设计稿的界面

只剩 D-8 一项(已定稿的保留在表内备查)。

编号 界面 状态
D-8 判定结果动画(大光 / 小光 / 过庄 / 升N级 / 投降) ⬜ 已定形态:不做结算面板上的静态文字,改为动画,在对局过程中与结算前播放(§1.8)。缺动画设计稿与触发细节
D-1 建房规则选项区 ✅ 定稿:版式照 创建房间选项…png,内容按 §1.1 的 3 类别 / 4 选项组。子游戏只做「类别标签 + 选项」内容区,弹窗背景 / 标题 / 关闭 / 确认按钮均由平台提供
D-2 底牌 3 秒展示 ✅ 定稿:复用庄家翻开底牌那套 UI(叫分确定庄.png),不要倒计时。非 70 分只有庄家能看、70 分全场能看——同一套界面,只差可见范围
D-3 甩错提示 ✅ 定稿:桌面中央深色半透条 强甩失败(强甩失败提示.png),不做收回动画,直接落下那张被强制打出的最小主牌
D-4 报无主 ✅ 定稿:不做全场提示。只让他家 主N/对N 角标出现;自己的主牌统计条本来就常显(§2.5)
D-5 踩 / 没分 / 有分 ✅ 定稿:底栏三按钮(占庄标区)+ 3×2 六帧气泡
D-6 明牌面板 ✅ 定稿:版式照 冲关牌型显示.png(遮罩 + 每家一排牌)。按钮条件按 design 手册:可查牌 + 已有任一玩家报无主 → 三家都显示、可随时查看
D-7 出牌历史面板 ✅ 定稿:版式同上。不按轮次,按玩家聚合、用主牌序排序。前端摊平 pushlist 即可,无需改服务端
D-9 大局总结算 ✅ 定稿:大局结算.png,玩家栏用精灵复制(§5.7a)。四项分数协议缺 → 见 S-6
D-10 解散结算 ✅ 复用 D-9 面板;投票界面平台全包(Layer 420)
D-11 准备标识 ✅ 用平台的
D-12 左上家已出牌区 ✅ 与右上家左右镜像
D-13 扣底 查看面板 ✅ 与 底牌 按钮复用同一个「8 张牌」展示面板,仅数据源不同

7.2 待确认的规格问题

仍未决(1 项)

编号 问题 影响
T-20 整套音效:清单、是否需要语音包、是否分男女声、倒计时提示音从第几秒起 §4 全节;已明确「等待后续补充」

已定论(33 项)

编号 结论
T-9 主牌统计条文案(原称"亮牌条")
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 出牌阶段必有 提示 按钮;服务端已下发 mustcard 供自动选中(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 抓分 角标 = 当前捡分对应判定倍率的实时预览;服务端已下发 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-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-30 亮牌没有界面位置
T-31 大局结算「基础分」与「总得分」两行的对应
T-32 等待庄家选主.png 里底牌仍摊着与 design §4 顺序不符
T-34 亮牌的展示时机
T-33 等待提示条文案

T-5 手牌排序(已定)

前端排序对齐服务端主牌序(design §3),不另造一套——服务端 class.arith.js 的 order_cards(mainflower, cards) 即权威顺序(从大到小),下发的 pushlist 等字段也已按此排好。

  • 选主前(叫分阶段):flower 未定,只有固定主牌(双王 + 全部 2、7)是主牌,其余按花色分组。
  • 选主后:flower 确定,正 2 / 正 7 升格、主花色普通牌并入主牌段,必须整体重排。重排动画暂不做(先直接重画),后续可加。
  • 主牌段落在左侧——排序从大到小、主牌最大,自然靠左。

7.3 验收检查清单

编码完成后必须逐条核对(每条都对应一处已知易错点):

# 检查项 依据
1 cardIdToFrame 通过 §0.4 的 10 条校验样例 花色段与 id 段序相反,最易静默画错牌
2 三家显示位映射正确:下家 (mySeat+1)%3 在右上 §0.1
3 提示按钮顺序(踩/有分/没分)与 tip 编号(1踩/2没分/3有分)的映射未按下标硬推 §1.7
4 气泡帧号 = (箭头向右?3:0)+tip,朝向按头像相对位置取 §1.7 / §6.6
5 不可查牌模式下:明牌/已出牌/上一轮 按钮不出现、亮牌面板不弹出(design §8.2 那个遮罩面板,群组 242)、主N/对N 角标不出现。⚠ §2.5 自己的主牌统计条(群组 206)不在此列——它任何模式下都常显 design §9 / §2.5
6 投降结算(无 bottom)与解散结算(无 deskfree 的情形)都不崩、不显示空框 §1.8 / §1.10
7 解散包从 data.deskfree.data.aset 取值,不是 data.aset §1.10
8 倒计时归零不做任何界面推进 协议 §0.3
9 冲关牌型叠加层关闭时 SpriteCopyUtils.removeRange 已清理 §5.6a
10 EQW_Layout 与 Game_Modify.PLAYER_INFO_LAYOUT 的头像框坐标一致 §6.11
11 丢弃 this.data、仅凭最近一次服务端快照重画,界面完全一致 前端 05 §6.2
12 所有布局参数都在配置文件里,业务代码无裸值 §6
13 底牌 / 埋牌底牌未写反:底牌 按钮读 bottomcards、扣底 按钮读 burycards;内部变量 bottomCards/buryCards 一一对应 §2.6
14 叫分按钮配色按档位位置取(非按子数),已叫过的档位置灰 §1.3
15 自己发的提示本地回显后,收到失败回包时能撤掉 §1.7
16 自己的主牌统计条有手牌时常显、不受查牌模式与报无主影响;他家 主N/对N 角标只在「可查牌 + 已报无主」时出现 §2.5
17 出牌历史按玩家聚合 + 主牌序排序,不是按轮次分组 §1.7 D-7
18 明牌 按钮在「场上有人报无主」时三家都显示(含报无主那家自己),不是只给自己无主的那家 §1.7 D-6

7.4 开发前置条件

在本清单的资源补齐前,前端不具备开发条件的部分:

  1. 美术出图 → §3 全部资源(尤其 3 套牌面 × 60 帧)
  2. 编辑器建资源与精灵 → §5 全部 ID 回填本文
  3. D-1 建房界面 → 影响 roomtype 拼串与进入牌局的第一步

不受阻、可先行的部分:

  • client/js/01_SubGame/codes/ 目录结构与 SubGameHooks.js 骨架
  • cardIdToFrame 转换与其单元测试(§0.4 的 10 条校验样例可直接作为用例)
  • 收包分发骨架(一 rpc 一处理器)与 data.success 判定
  • 布局配置骨架与布局求解器(§6)——kind 五型的参数结构与求解逻辑是设计决定、不依赖具体数值,可先写好并用占位坐标跑通,等设计稿到位只改配置值
  • shared/ 同步机制

7.5 服务端待补项(需改服务端才能实现的前端需求)

以下 3 条来自本轮确认的需求,当前协议/服务端不支持,需在服务端补齐后前端才能实现。三条都要同步更新 packet_protocol.md。

S-1 · 「当前抓分的倍数」字段 curmultiple —— ✅ 已完成(2026-08-25)

语义:当前捡分对应判定倍率的实时预览——「若此刻结束是几倍」,取绝对值。

当前捡分 grade 相对叫分 call 判定 curmultiple
grade == 0 庄家:大光 3
0 < grade < Q 庄家:小光 2
Q ≤ grade < call 庄家:过庄 1
grade ≥ call 闲家:升 N 级 N

(Q = 小光/过庄分界兼升级级距,常规算子固定 40、爬坡按叫分分段,design §7.2.0 / §7.3.2。)

下发位置(随现有包,不另开推送):shangzhuang、chupai1、chupai2、chupai3、deskinfo.PushCards。

要点:

  • 三家同值,整表下发不涉及泄露(grade 本就公开)。
  • 与结算包 aset.upgrade 同源同算法(get_qvalue + get_upgrade),差别只在这里不含扣底——扣底要到末轮打完才产生。
  • 叫分未定时为 0,前端不显示角标。
  • 前端不得自算(服务端权威)。

实现:class.paiju.js 新增 get_curmultiple();mod.js / class.export.js 组包处下发。

S-2 · 下发「应当选中的牌」mustcard —— ✅ 已完成(2026-08-25)

语义:下一个出牌者本轮跟牌的必出牌(design §5.2),前端收到后自动选中(上浮),玩家确认后点 出牌。

下发位置:chupai1 / chupai2(给 nextseat)、deskinfo.PushCards(给轮到的那一家)。

可见性(关键):只发给 nextseat 一家。它是该玩家自己手牌的子集,发给他本人不泄露;整表下发会把另两家的手牌结构透露出去(server 红线:发全 ≠ 发多,按可见性下发)。已纳入 test_leak.js 的 CARD_FIELDS 审计白名单。

不下发的情形:

  1. 非出牌阶段;
  2. 该座位是本轮首家(自由出牌,无必出);
  3. 首家是甩牌——甩牌跟牌走 flush_follow_ok 的逐分量匹配(design §5.4.4),与 get_followcard 不是同一条路径,给建议会给错,宁可不发;
  4. 算出的必出牌为空(玩家可自由选)。

实现:class.paiju.js 新增 get_mustcard(seat),内部复用与出牌校验完全相同的 get_followcard,故建议与校验结果天然一致。

不违反「请求包只带意图」:方向是服务端 → 前端的建议,前端仍只回传 cards,合法性最终由服务端校验。

S-3 · 底牌的可见性:按手册办(对应 T-18)—— 已定

结论:按 design 手册,即前述方案 (a)。底栏 底牌 按钮只在能合法看到底牌时可用:

谁 何时可用
庄家 全程可用(他本来就摸过这 8 张)
闲家 仅 70 分坐庄局可用(这 8 张已向全场公示过 3 秒);其余局按钮不显示

依据 design §4:非 70 分坐庄时这 8 张只有庄家可见;协议也一致(shangzhuang.bottomcards 闲家仅 70 分时才有,重连包的同名字段标注「只有庄家有此属性」)。

服务端无需改动——现有下发面正好支持这条规则:闲家在非 70 分局本来就收不到数据,按钮不显示即可,不存在「拿到了但不渲染」的泄露风险(服务端红线:下发即泄露)。

S-4 · 拆分 bottomcards 字段名 —— ✅ 已完成(2026-08-25)

两批牌原先共用 bottomcards、只靠所在包区分语义,现已拆分:

字段名 含义 出现在
bottomcards 底牌(发牌留桌 8 张) shangzhuang、deskinfo.ChooseMain、deskinfo.BuryCards
burycards 埋牌底牌(庄家埋下 8 张) maipai、deskinfo.PushCards
bottom.cards 埋牌底牌 结算包 bottom 分组(分组名已表明是抠底相关,未改名)

服务端改动:mod.js(maipai 组包)、class.export.js(deskinfo.PushCards),另同步了两处的注释术语。 测试:test/test_leak.js 的 CARD_FIELDS 白名单加入 burycards(否则新字段会静默脱离下发面审计);test/test_rpc.js 新增 11 条正反用例锁死拆分结果。 协议文档:packet_protocol.md §0.0 与相关字段表已更新。

前端取值:直接按字段名区分即可,不再需要「按所在包判断语义」:

// 底牌(发牌留桌 8 张)——底栏「底牌」按钮
data.bottomcards      // shangzhuang / ChooseMain / BuryCards
// 埋牌底牌(庄家埋下 8 张)——底栏「扣底」按钮
data.burycards        // maipai / PushCards
data.bottom.cards     // 结算包

S-5 · 同步 design.md 与 packet_protocol.md 的术语 —— ✅ 已完成(2026-08-25)

术语变更(暗牌→底牌、底牌→埋牌底牌)已在各处生效:

文档 / 代码 状态
docs_dev/二七王-UI资源与精灵清单.md(本文) ✅ 全文新术语
server/games/erqiwang/docs/design/design.md ✅ 全文 38 处替换;术语表后补「术语变更记录」说明改名缘由
server/games/erqiwang/docs/protocol/packet_protocol.md ✅ 新增 §0.0 术语小节;字段说明同步;字段名随 S-4 拆分
mod.js / class.export.js / test/test_leak.js 注释 ✅ 随 S-4 一并更新
docs/compliance/*.md(3 份,24 处) ⬜ 有意不改——这三份是历次核对的历史记录,反映当时的 design 表述;下轮核对按新 design 重做即可,不追溯修改
test/*.js 其余注释(约 14 处) ⬜ 仅注释、不影响行为,后续顺手清理

S-6 · 大局结算的三项分解 —— ✅ 已完成(2026-08-26)

问题:大局结算面板要显示 基础分 / 冲关分 / 傍王分,而原 account 只有「累积得分 + 每局得分数组」。其中傍王分尤其拆不出来——N = 冲关奖数 + 傍王王数 两个来源在求和之后才代入 grade_aw = X×(2Ni−Nj−Nk),事后无法反推各自占比。

解法:在算钱时就拆。把 N 分成 N_冲关(只计庄家)与 N_傍王(勾选后庄闲都算),分别代入同一公式各算一次。公式对 N 线性,故恒有 grade_cg + grade_bw == grade_aw——这条恒等式正好当回归断言。

小局包 aset.seatlist[i] 新增:

字段 说明
grade_cg 算奖得分里的冲关分量(不含傍王)
grade_bw 算奖得分里的傍王分量(未勾傍王时恒 0)

大局包 account 结构改了(原为二元数组,现为对象数组):

[{ "score": 0, "grades": [], "grade_jf_total": 0, "grade_cg_total": 0, "grade_bw_total": 0 }, …]
面板栏位 取值
基础分 grade_jf_total
冲关分 grade_cg_total
傍王分 grade_bw_total
右侧总分大字 score

恒等式:grade_jf_total + grade_cg_total + grade_bw_total == score。

顺带解决了小局结算「冲关分」标签的不严谨(见 §0.0):该标签现在应改取 grade_cg 而非 grade_aw,开傍王时也名副其实了。

面板上「基础分」取 grade_jf_total、「总得分」取 score。参考图里这两行数值相同、且与右侧大字对不上,是填充假数据所致,不作依据(§0.5)。

S-7 · 明牌按钮的显示条件 —— ✅ 已定论:按手册,服务端无需改动(2026-08-26)

结论:按 design §9.3 手册办——任一玩家报无主后,三家都显示 明牌 按钮,且可随时查看。

项 取值
显示条件 可查牌模式 + 出牌阶段 + baozhu == 1(任一玩家主牌出空)
谁能看 全体三人,包括刚刚报无主的那位自己
次数 不限,随时可点开、可关闭

服务端无需改动——mingpai 现有的受理条件 have_baofu()(任一玩家报无主)正好就是这条规则,与 design §9.3 一致。此前我把前端条件收紧成「自己是无主玩家」,比手册严格,反而与服务端校验对不上;现已改回。

之前记录的「有主牌的玩家伪造请求也能拿到明牌数据」这一泄露担忧不成立:按手册他本来就有权查看,服务端受理是正确行为,不是校验缺失。

S-8 · curmultiple 改为带符号 —— ✅ 已完成(2026-08-26)

问题:S-1 实现时取了绝对值,而判定的正负号恰恰是「谁赢」的区分——3 大光与 -3 升3级、2 小光与 -2 升2级、1 过庄与 -1 升1级,取绝对值后三对完全撞在一起,D-8 的过程中动画无从分辨该播哪个。

改法:get_curmultiple 直接返回 get_upgrade 的原值,与结算包 aset.upgrade 完全同口径:

值 含义
3 / 2 / 1 庄家 大光 / 小光 / 过庄
-N 闲家升 N 级
0 叫分未定

前端用法:

  • 顶部「抓分」角标只关心倍数大小 → Math.abs(curmultiple)(§2.1)。
  • 判定动画靠符号分辨该播哪个(§1.8 D-8),一套映射通吃「过程中」与「结算前」两条路径。

测试(hint 33 → 46 checks):新增两组——一组直接钉住三对「绝对值相同、判定相反」的组合可区分;另一组直接调 get_curmultiple 本身覆盖负数分支。

后一组是补上的测试盲点:原有断言里,算法层的 cm() 走的是 A.get_upgrade、绕过了 get_curmultiple,而端到端那局恰好是大光(正数),取不取绝对值结果一样。第一次反向验证(把实现退回取绝对值)竟然全绿,正是因为这个盲点。补齐后再验,4 条断言立刻失败。


附:本文与其他文档的关系

文档 关系
server/games/erqiwang/docs/design/design.md 玩法规则权威源。本文引用其条款,不重新定义规则;术语「底牌 / 埋牌底牌」已同步(见 §0.0)
server/games/erqiwang/docs/protocol/packet_protocol.md 协议字段权威源。本文的「渲染什么」全部溯源到具体字段
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/templates/*.template.js 常量文件写法蓝本。本清单落地为常量文件时按其格式