二七王:前端布局与动画常量

照清单 §6 各表逐条录入,字段名与 LayoutSolver 的 node 一一对应、可原样喂入。
布局文件保持纯数据:无函数、无副作用;分行策略等写成数据标记而非函数。
建房选项配置自带 bit 与 value,roomtype 拼串遍历配置即可,不按下标硬拼。
动画参数含 D-8 判定动画的待补说明。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-26 21:26:16 +08:00
co-authored by Claude Opus 5
parent 1976edf9bd
commit 6c92920df8
7 changed files with 526 additions and 0 deletions
@@ -0,0 +1,32 @@
///////////////////////////////////////////////////////////////
////////// EQW_Anim: 动画与时长参数(纯数据)//////////////////
///////////////////////////////////////////////////////////////
// client 02 §3「数据优先、表现延后」:动画只是体验层,
// 其开始/结束/出错回调里只刷界面、绝不写核心数据。
// 动画缺失或卡住时,数据与界面仍须正确。
var EQW_Anim = EQW_Anim || {
//发牌铺开:从右往左(清单 §1.2 T-4)
DEAL: { totalDuration: 800, perCardDelay: 20, direction: 'rightToLeft' },
//手牌选中上浮(清单 §6.7)
HAND_SELECT_OFFSET_Y: -40,
//捡分飘字(清单 §6.8)
SCORE_FLOAT: { rise: -60, duration: 800 },
//即时反馈提示条自动消失(清单 §6.8)
TOAST_DURATION: 1500,
//亮牌面板自动关闭(清单 §1.6 T-34:只按时长关闭,不做点击关闭)。
//清单原文时长「默认值待定」,此处沿用与开底展示同数量级的 3 秒作为起始估值,设计定稿后回填
LIANGPAI_AUTO_CLOSE: 3000,
//开底:70 分坐庄时 8 张底牌向全场翻开 3 秒(design §4 / 清单 §1.4 D-2,不要倒计时)
ANCARD_REVEAL_DURATION: 3000
//【D-8 待补】判定结果动画(大光/小光/过庄/升N级/投降)——
//已定形态:不做结算面板上的静态文字,改为动画,在对局过程中与结算前播放;
//靠 curmultiple 的【符号】分辨该播哪个(3/2/1 庄家大光/小光/过庄,-N 闲家升N级)。
//缺动画设计稿与触发细节,定案后在此补参数。
};
@@ -0,0 +1,33 @@
///////////////////////////////////////////////////////////////
////////// EQW_Layout: 布局配置总则(清单 §6)/////////////////
///////////////////////////////////////////////////////////////
// 设计基准 1280×720,ScreenFitMode 1,30fps(清单 §0.1)。
// 【纯数据文件】无函数、无副作用、不引用其他模块——
// fan 的间距算法、bySeat 合并、attach 换算都在 codes/ui/LayoutSolver.js。
// 数值为参考图目视实测估值(±5px),设计稿到位后只改本层。
//
// 本文件须最先加载(其余 5 个 Layout_*.js 会引用本文件的 CARD_SIZE / TEXT_STYLE,
// 这是 EQW_Layout 内部的自引用,不是跨模块引用)。
var EQW_Layout = EQW_Layout || {};
//座位键(显示位,非服务端座位号;换算见 core/SeatMap.js)
EQW_Layout.SEAT = { SELF: 'SELF', LEFT: 'LEFT', RIGHT: 'RIGHT' };
//三套牌面尺寸档(清单 §6.4)。改牌面尺寸只动这一处,引用它的区域自动跟随
EQW_Layout.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.3,逐条对应 §6.5–§6.9b 各表出现的 textStyle{...})
EQW_Layout.TEXT_STYLE = {
STATUS_BIG: { fontSize: 46, color: '#FFFFFF', align: 'center' }, //玩家位「60分」「不叫」(§6.6)
CALL_BIG: { fontSize: 52, color: '#FFD24A', align: 'center' }, //自己叫分大字(§6.8)
SCORE_BIG: { fontSize: 56, color: '#FFFFFF', align: 'center' }, //结算总分大字(§6.9)
ASET_COUNT: { fontSize: 20, color: '#FFFFFF', align: 'center' }, //底栏「1/4 局」(§6.5)
ROOM_OPT: { normal: { fontSize: 18, color: '#DDDDDD' }, //建房选项文字(§6.9b)
selected: { fontSize: 18, color: '#E8873A' } },
ROOM_CAT: { fontSize: 18, color: '#7FBFB0', bold: true, align: 'right', maxWidth: 60 },
ROOM_CARD_COST_NOTE: { fontSize: 16, color: '#999999' } //建房房卡消耗附注(§6.9b)
};
@@ -0,0 +1,89 @@
///////////////////////////////////////////////////////////////
////////// EQW_Layout: 阶段操作区配置(清单 §6.8)//////////////
///////////////////////////////////////////////////////////////
// 【纯数据文件】无函数、无副作用;依赖 LayoutConstants.js 先加载
// (引用其 EQW_Layout.TEXT_STYLE.*,属 EQW_Layout 内部自引用)。
var EQW_Layout = EQW_Layout || {};
//===== 叫分面板 =====
EQW_Layout.CALL_PANEL_BG = { kind: 'point', x: 355, y: 140, w: 575, h: 170 };
EQW_Layout.CALL_HINT_BG = { kind: 'point', x: 470, y: 100, w: 345, h: 33 };
//14 档位按钮:grid 布局(清单 §6.1 示例,7×2)
EQW_Layout.CALL_BTN_GRID = {
kind: 'grid', anchorX: 640, anchorY: 160, cols: 7, rows: 2,
itemWidth: 74, itemHeight: 56, spacingX: 7, spacingY: 24,
anchor: 'center', fillOrder: 'row'
};
//档位分数文字:贴对应档位按钮居中。CALL_BTN_1..14 是 14 个固定精灵,但本节点是共用模板,
//target 由调用方按第几档注入(不预置单一 target)。宽高随数字位数变化,清单未给固定值,
//资源 NUM_CALL_SCORE 单字位 30×40 仅供参考,不作为本节点的 w/h
EQW_Layout.CALL_BTN_SCORE_TEXT = { kind: 'attach', hAlign: 'center', vAlign: 'middle', offsetY: 4 };
//档位子数角标:贴对应档位按钮右上角,纯文字无底图,清单未给宽高(同上,调用方注入 target)
EQW_Layout.CALL_BTN_MULTIPLE_BADGE = { kind: 'attach', corner: 'topRight', offsetX: -30, offsetY: 2 };
EQW_Layout.CALL_BTN_NONE = { kind: 'point', x: 553, y: 345, w: 184, h: 57 };
//自己叫分大字
EQW_Layout.CALL_SELF_SCORE_TEXT = {
kind: 'point', x: 570, y: 320, w: 140, h: 70, textStyle: EQW_Layout.TEXT_STYLE.CALL_BIG
};
//===== 选主 / 投降面板 =====
EQW_Layout.MAIN_TITLE_BG = { kind: 'point', x: 330, y: 315, w: 425, h: 50 };
//4 花色 + 投降:投降不显示时只排前 4 项,anchor:left 保证前 4 个位置不变
EQW_Layout.MAIN_SUIT_LINE = {
kind: 'line', direction: 'horizontal', anchorX: 330, anchorY: 373,
itemWidth: 128, itemHeight: 55, spacing: 9, anchor: 'left'
};
//花色图标:贴对应花色按钮左侧(资源 SUIT_ICON_L 46×46)。target 由调用方按花色序号注入
EQW_Layout.MAIN_SUIT_ICON = { kind: 'attach', hAlign: 'left', vAlign: 'middle', offsetX: 14, w: 46, h: 46 };
//张数大字:贴对应花色按钮居中,纯文字,清单未给宽高(调用方注入 target)
EQW_Layout.MAIN_SUIT_COUNT_TEXT = { kind: 'attach', hAlign: 'center', vAlign: 'middle', offsetX: 14 };
//对数角标底:贴对应花色按钮右上角(资源 BADGE_MULTIPLE 帧1 34×18)。
//角标文字复用同一矩形,不单独配置(调用方注入 target)
EQW_Layout.MAIN_SUIT_PAIR_BADGE = { kind: 'attach', corner: 'topRight', offsetX: -36, offsetY: 2, w: 34, h: 18 };
//===== 埋牌 / 出牌操作条 =====
//埋牌操作条:提示 / 倒计时(CD_SELF) / 埋牌,逐项不等宽(清单 §6.1)
EQW_Layout.BURY_OPERATION_BAR = {
kind: 'line', direction: 'horizontal', anchorX: 640, anchorY: 165,
itemHeight: 63, spacing: 45, anchor: 'center',
items: [
{ key: 'BURY_BTN_TIP', width: 180 },
{ key: 'CD_SELF', width: 60 },
{ key: 'BURY_BTN_SUBMIT', width: 180 }
]
};
//出牌操作条:倒计时(CD_SELF) / 出牌
EQW_Layout.PLAY_OPERATION_BAR = {
kind: 'line', direction: 'horizontal', anchorX: 640, anchorY: 345,
itemHeight: 55, spacing: 35, anchor: 'center',
items: [
{ key: 'CD_SELF', width: 75 },
{ key: 'PLAY_BTN_SUBMIT', width: 157 }
]
};
//===== 浮层 =====
//捡分飘字:起始位置在此。动画参数(floatRise / floatDuration)见 EQW_Anim.SCORE_FLOAT,不在此重复(SSOT)
EQW_Layout.GRADE_FLOAT = { kind: 'point', x: 570, y: 180, w: 170, h: 55 };
//状态提示条 · 等待类(如『等待庄家选主』)。与即时反馈类共用同一套精灵 BAR_TOAST/TXT_TOAST,
//仅位置预设不同,调用方按提示类型二选一应用(清单 §2.8:收敛为 3 条)
EQW_Layout.TOAST_WAIT = { kind: 'point', x: 500, y: 373, w: 320, h: 47 };
//状态提示条 · 即时反馈类(如『强甩失败』)。自动消失时长见 EQW_Anim.TOAST_DURATION,不在此重复(SSOT)
EQW_Layout.TOAST_INSTANT = { kind: 'point', x: 462, y: 172, w: 363, h: 50 };
@@ -0,0 +1,99 @@
///////////////////////////////////////////////////////////////
////////// EQW_Layout: 牌区配置(清单 §6.7)////////////////////
///////////////////////////////////////////////////////////////
// 【纯数据文件】无函数、无副作用;依赖 LayoutConstants.js 先加载
// (引用其 EQW_Layout.CARD_SIZE,属 EQW_Layout 内部自引用)。
var EQW_Layout = EQW_Layout || {};
//===== 自己手牌区(清单 §6.7)=====
//自己手牌 · 单排:36 张时 spacing ≈ -78(露 32px),与参考图实测 33px 吻合
EQW_Layout.HAND_FAN_SINGLE = {
kind: 'fan', direction: 'horizontal',
anchorX: 640, anchorY: 455, maxWidth: 1215,
itemWidth: EQW_Layout.CARD_SIZE.L.w, itemHeight: EQW_Layout.CARD_SIZE.L.h,
spacingMax: 0, spacingMin: -78, anchor: 'center', overlapFrom: 'left'
};
//自己手牌 · 双排(埋牌)。分行策略是数据标记 splitStrategy,由调用方据此分行,本文件不写函数:
//floorTop = 上排 floor(n/2)、下排 ceil(n/2)(36 张 = 18/18;参考图 17/19 属填充画法,不作依据,见清单 §0.5)。
//spacingMax / anchor / overlapFrom 清单双排行未重复给出,沿用单排同参数(同一批牌、同一压缩规则)
EQW_Layout.HAND_TWO_ROW = {
splitStrategy: 'floorTop',
ROW_TOP: {
kind: 'fan', direction: 'horizontal',
anchorX: 644, anchorY: 285, maxWidth: 928,
itemWidth: EQW_Layout.CARD_SIZE.L.w, itemHeight: EQW_Layout.CARD_SIZE.L.h,
spacingMax: 0, spacingMin: -65, anchor: 'center', overlapFrom: 'left'
},
ROW_BOTTOM: {
kind: 'fan', direction: 'horizontal',
anchorX: 644, anchorY: 455, maxWidth: 928,
itemWidth: EQW_Layout.CARD_SIZE.L.w, itemHeight: EQW_Layout.CARD_SIZE.L.h,
spacingMax: 0, spacingMin: -65, anchor: 'center', overlapFrom: 'left'
}
};
//手牌 · 选中上浮偏移量定义在 EQW_Anim.HAND_SELECT_OFFSET_Y(AnimConstants.js),此处不重复(SSOT)
//底牌区(8 张,未揭示为牌背、揭示后翻正面,同一批精灵)
EQW_Layout.BOTTOM_CARDS = {
kind: 'line', direction: 'horizontal',
anchorX: 655, anchorY: 110,
itemWidth: EQW_Layout.CARD_SIZE.L.w, itemHeight: EQW_Layout.CARD_SIZE.L.h,
spacing: -36, anchor: 'center'
};
//埋牌底牌区(结算,8 张,尺寸档 S)
EQW_Layout.BURY_CARDS = {
kind: 'line', direction: 'horizontal',
anchorX: 640, anchorY: 163,
itemWidth: EQW_Layout.CARD_SIZE.S.w, itemHeight: EQW_Layout.CARD_SIZE.S.h,
spacing: 2, anchor: 'center'
};
//===== 已出牌区(清单 §6.2 示例 / §6.7)=====
//三家已出牌区:三家共用 base,LEFT 与 RIGHT 左右镜像(overlapFrom 相反)
EQW_Layout.PLAY_AREA = {
kind: 'fan', direction: 'horizontal',
itemWidth: EQW_Layout.CARD_SIZE.M.w, itemHeight: EQW_Layout.CARD_SIZE.M.h,
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' }
}
};
//已出牌 · 牌型标签:贴该区第一张牌。首槽是固定精灵(PLAY_SELF_1 / PLAY_LEFT_1 / PLAY_RIGHT_1),非动态目标。
//资源 LABEL_CARDTYPE 76×24(清单 §3)
EQW_Layout.PLAY_TYPE_LABEL = {
kind: 'attach', corner: 'bottomLeft', offsetX: 0, offsetY: -24, w: 76, h: 24,
bySeat: {
SELF: { target: 'PLAY_SELF_1' },
LEFT: { target: 'PLAY_LEFT_1' },
RIGHT: { target: 'PLAY_RIGHT_1' }
}
};
//已出牌 · 牌角『庄』/『大』标:贴的是本轮打出的哪张具体牌,运行时才能确定,不是固定精灵键。
//本节点只是模板(corner/offset),调用方在确定具体是哪张牌之后,以此为基础补上 target 再喂给
//EQW_LayoutSolver.solve——这是有意的动态目标模式,不在配置里预置 target(清单未给尺寸;
//两种资源分别是 MARK_BANKER_CORNER 28×28 / MARK_JOKER_BIG 34×34,按实际显示的是哪个徽标取值)
EQW_Layout.PLAY_CARD_CORNER_MARK = {
kind: 'attach', corner: 'topRight', offsetX: -28, offsetY: 0
};
//冲关牌(叠加层):精灵复制场景(§5.6a),spacingMin 放宽到 -88 以容纳 20+ 张的极端情况。
//anchor / direction 清单未重复给出,沿用其余 fan 配置的通用约定(center / horizontal)
EQW_Layout.CHONGGUAN_FAN = {
kind: 'fan', direction: 'horizontal', anchor: 'center',
itemWidth: EQW_Layout.CARD_SIZE.L.w, itemHeight: EQW_Layout.CARD_SIZE.L.h,
maxWidth: 420, spacingMax: -40, spacingMin: -88,
bySeat: {
LEFT: { anchorX: 260, anchorY: 120 },
RIGHT: { anchorX: 1035, anchorY: 120 },
SELF: { anchorX: 640, anchorY: 400 }
}
};
@@ -0,0 +1,80 @@
///////////////////////////////////////////////////////////////
////////// EQW_Layout / EQW_RoomOptions: 建房规则选项(清单 §6.9b / §1.1)
///////////////////////////////////////////////////////////////
// 【纯数据文件】无函数、无副作用;依赖 LayoutConstants.js 先加载
// (引用其 EQW_Layout.TEXT_STYLE.*,属 EQW_Layout 内部自引用)。
var EQW_Layout = EQW_Layout || {};
//===== 建房规则选项区布局(清单 §6.9b)=====
//两层嵌套:类别竖排(ROOM_CATEGORY_COLUMN)+ 类别内选项槽横排(ROOM_OPTION_ROW)。
//本节数值按参考图比例估,实际以平台建房界面尺寸为准(清单 §6.9b 原文,不是本文件误差)。
//类别竖排。itemWidth 清单未给——类别行宽度等于平台内容区实际宽度,由调用方按实际面板尺寸处理
EQW_Layout.ROOM_CATEGORY_COLUMN = {
kind: 'line', direction: 'vertical', anchorX: 0, anchorY: 0,
itemHeight: 32, spacing: 8, anchor: 'left'
};
//类别标题:贴所在类别行。该行是 ROOM_CATEGORY_COLUMN 求解结果的第 N 项,不是固定精灵,
//target 由调用方按类别序号注入。资源 ROOM_CAT_TITLE 60×24(清单 §3)
EQW_Layout.ROOM_CATEGORY_TITLE = { kind: 'attach', hAlign: 'left', vAlign: 'middle', offsetX: 0, w: 60, h: 24 };
//类别内选项槽横排。anchorY 清单未给(随所在类别行的 y 浮动,由调用方按该行位置注入);
//itemHeight 清单未给,沿用 ROOM_CATEGORY_COLUMN.itemHeight(同一行内选择框与文字纵向居中)
EQW_Layout.ROOM_OPTION_ROW = {
kind: 'line', direction: 'horizontal', anchorX: 70,
itemWidth: 150, spacing: 0, anchor: 'left'
};
//选项组之间的额外间隔(同类别下两个选项组之间比组内选项多留的间距)
EQW_Layout.ROOM_OPTION_GROUP_GAP = 40;
//选择框:贴所在选项槽左侧(资源 ROOM_OPT_BOX 22×22)。target 由调用方按选项槽注入
EQW_Layout.ROOM_OPTION_BOX = { kind: 'attach', hAlign: 'left', vAlign: 'middle', w: 22, h: 22 };
//选项文字:贴同槽选择框右侧,纯文字,清单未给宽高。
//选中态变橙见 EQW_Layout.TEXT_STYLE.ROOM_OPT(normal / selected 两态,由调用方按选中状态二选一)
EQW_Layout.ROOM_OPTION_TEXT = { kind: 'attach', hAlign: 'right', vAlign: 'middle', offsetX: 8 };
//房卡附注:贴扣卡组最后一个选项(固定精灵 ROOM_BOX_CARD_2)右侧
EQW_Layout.ROOM_CARD_COST_NOTE = {
kind: 'attach', target: 'ROOM_BOX_CARD_2', hAlign: 'right', vAlign: 'middle', offsetX: 20,
textStyle: EQW_Layout.TEXT_STYLE.ROOM_CARD_COST_NOTE
};
//折行:选项数超过 maxPerRow 时改用 grid。二七王每组最多 2 项,不会触发(清单 §6.9b 原文);
//itemWidth / itemHeight / anchorX / anchorY 清单未给(该分支未被实际使用),仅记录已定的三个字段
EQW_Layout.ROOM_OPTION_MAX_PER_ROW = 4;
EQW_Layout.ROOM_OPTION_OVERFLOW_GRID = { kind: 'grid', spacingX: 0, spacingY: 8, fillOrder: 'row' };
///////////////////////////////////////////////////////////////
////////// EQW_RoomOptions: 建房规则选项配置(清单 §1.1)///////
///////////////////////////////////////////////////////////////
//整个界面由本配置驱动渲染,加一个选项 = 配置里加一条,不改渲染逻辑(工程总则 §5 OCP / §6 配置优先)。
//type: 'radio' 单选 / 'checkbox' 多选 / 'radioOptional' 单选可不选
//选择框帧号 = (useCheckbox ? 3 : 1) + (selected ? 1 : 0),useCheckbox = (checkbox 或 radioOptional)
//【roomtype 拼串只在一处实现】每个选项自带 bit 与 value,拼串就是遍历本配置,
//不得在别处按下标硬拼(与服务端 class.config.js parse() 对称的 SSOT 要求)
var 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 } ] }
] }
],
//房卡消耗联动(协议 §0.5):不硬编码在 UI 代码里
cardCost: {
'0': { '0': '房主2张', '1': '房主4张' }, //房主扣卡:6局 / 12局
'1': { '0': '每人1张', '1': '每人2张' } //AA 每人扣卡:6局 / 12局
}
};
@@ -0,0 +1,60 @@
///////////////////////////////////////////////////////////////
////////// EQW_Layout: 结算区配置(清单 §6.9)//////////////////
///////////////////////////////////////////////////////////////
// 【纯数据文件】无函数、无副作用;依赖 LayoutConstants.js 先加载
// (引用其 EQW_Layout.TEXT_STYLE.*,属 EQW_Layout 内部自引用)。
var EQW_Layout = EQW_Layout || {};
EQW_Layout.RESULT_BOTTOM_PANEL = { kind: 'point', x: 430, y: 140, w: 420, h: 148 };
//底牌说明文字:贴面板底部,纯文字,清单未给宽高
EQW_Layout.RESULT_BOTTOM_TEXT = {
kind: 'attach', target: 'RESULT_BOTTOM_PANEL', hAlign: 'center', vAlign: 'bottom', offsetY: -14
};
//三家分数光晕
EQW_Layout.RESULT_GLOW = {
kind: 'point', w: 225, h: 100,
bySeat: {
LEFT: { x: 175, y: 150 },
RIGHT: { x: 865, y: 150 },
SELF: { x: 490, y: 340 }
}
};
//三家总分大字:贴对应光晕居中。target 直接指向光晕精灵键(固定,非动态)
EQW_Layout.RESULT_SCORE_TEXT = {
kind: 'attach', hAlign: 'center', vAlign: 'middle', textStyle: EQW_Layout.TEXT_STYLE.SCORE_BIG,
bySeat: {
LEFT: { target: 'RESULT_GLOW_LEFT' },
RIGHT: { target: 'RESULT_GLOW_RIGHT' },
SELF: { target: 'RESULT_GLOW_SELF' }
}
};
//三家『牌局分』:贴对应光晕左下
EQW_Layout.RESULT_JF_TEXT = {
kind: 'attach', hAlign: 'left', vAlign: 'bottom', offsetX: -15, offsetY: 24,
bySeat: {
LEFT: { target: 'RESULT_GLOW_LEFT' },
RIGHT: { target: 'RESULT_GLOW_RIGHT' },
SELF: { target: 'RESULT_GLOW_SELF' }
}
};
//三家『冲关分』:贴对应光晕右下
EQW_Layout.RESULT_AW_TEXT = {
kind: 'attach', hAlign: 'right', vAlign: 'bottom', offsetX: 15, offsetY: 24,
bySeat: {
LEFT: { target: 'RESULT_GLOW_LEFT' },
RIGHT: { target: 'RESULT_GLOW_RIGHT' },
SELF: { target: 'RESULT_GLOW_SELF' }
}
};
EQW_Layout.RESULT_BTN_CG = { kind: 'point', x: 535, y: 515, w: 183, h: 63 };
EQW_Layout.RESULT_BTN_NEXT = { kind: 'point', x: 835, y: 518, w: 180, h: 65 };
//冲关遮罩:透明度也是配置项
EQW_Layout.CG_MASK = { kind: 'point', x: 0, y: 0, w: 1280, h: 720, opacity: 0.72 };
@@ -0,0 +1,133 @@
///////////////////////////////////////////////////////////////
////////// EQW_Layout: 常驻区 + 玩家位(清单 §6.5 / §6.6)//////
///////////////////////////////////////////////////////////////
// 【纯数据文件】无函数、无副作用;依赖 LayoutConstants.js 先加载
// (引用其 EQW_Layout.TEXT_STYLE.*,属 EQW_Layout 内部自引用)。
var EQW_Layout = EQW_Layout || {};
//===== 常驻区(清单 §6.5)=====
//顶部信息条底
EQW_Layout.TOP_INFO_BG = { kind: 'point', x: 486, y: 4, w: 276, h: 68 };
//顶部 · 花色图标:贴信息条内部左下角(资源 SUIT_ICON_S 30×30,清单 §3)
EQW_Layout.TOP_SUIT_ICON = {
kind: 'attach', target: 'TOP_INFO_BG',
hAlign: 'left', vAlign: 'bottom', offsetX: 20, offsetY: -8, w: 30, h: 30
};
//顶部 · 叫分角标底:贴叫分数值文字右上角(资源 BADGE_MULTIPLE 帧1 34×18)。
//角标数值文字复用同一矩形,不单独配置(清单未给独立位置,下同)
EQW_Layout.TOP_CALL_BADGE_BG = {
kind: 'attach', target: 'TOP_CALL_TEXT', corner: 'topRight', offsetX: 4, offsetY: 6, w: 34, h: 18
};
//顶部 · 抓分角标底:贴抓分数值文字右上角(资源 BADGE_MULTIPLE 帧2 34×18)
EQW_Layout.TOP_GRADE_BADGE_BG = {
kind: 'attach', target: 'TOP_GRADE_TEXT', corner: 'topRight', offsetX: 4, offsetY: 6, w: 34, h: 18
};
//亮牌信息条
EQW_Layout.LIANGPAI_BG = { kind: 'point', x: 35, y: 400, w: 210, h: 35 };
//底栏条
EQW_Layout.FOOTER_BG = { kind: 'point', x: 0, y: 648, w: 1280, h: 72 };
//底栏 · 局数文字「1/4 局」
EQW_Layout.FOOTER_ASET_TEXT = {
kind: 'point', x: 635, y: 672, w: 65, h: 26, textStyle: EQW_Layout.TEXT_STYLE.ASET_COUNT
};
//底栏 · 功能钮组(明牌/已出牌/上一轮/底牌):逐项不等宽(清单 §6.1 T-25)
EQW_Layout.FOOTER_FUNC_BUTTONS = {
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 }
]
};
//底栏 · 提示按钮组(踩/有分/没分):count 由运行时同时可见的按钮数给出,不进配置
EQW_Layout.FOOTER_TISHI_BUTTONS = {
kind: 'line', direction: 'horizontal', anchorX: 335, anchorY: 672,
itemWidth: 52, itemHeight: 30, spacing: 26, anchor: 'left'
};
//右侧语音钮(平台):坐标仅登记供 01_SubGame_modify.js 配置区人工同步核对(清单 §6.11 同类处理)
EQW_Layout.VOICE_BTN_REF = { kind: 'point', x: 1210, y: 310, w: 56, h: 56 };
//右侧聊天钮(平台):同上
EQW_Layout.CHAT_BTN_REF = { kind: 'point', x: 1210, y: 385, w: 56, h: 56 };
//===== 玩家位(清单 §6.6)=====
//头像框(平台提供):仅登记坐标供 attach 参考与 Game_Modify.PLAYER_INFO_LAYOUT 人工同步(清单 §6.11)。
//SELF 尺寸与 LEFT/RIGHT 不同(84×53 vs 91×118),bySeat 内单独覆盖 w/h
EQW_Layout.PLAYER_AVATAR_FRAME_REF = {
kind: 'point', w: 91, h: 118,
bySeat: {
LEFT: { x: 22, y: 122 },
RIGHT: { x: 1160, y: 122 },
SELF: { x: 22, y: 645, w: 84, h: 53 }
}
};
//『庄』印章:三家各一个精灵(P_LEFT_BANKER / P_RIGHT_BANKER / P_SELF_BANKER),按 bySeat 求位置。
//LEFT/RIGHT 贴平台头像框外角;SELF 为底栏固定点(与清单 §6.5「底栏·庄标」同一元素,此处合并,避免重复定义)
EQW_Layout.P_BANKER_MARK = {
kind: 'attach', w: 40, h: 40,
bySeat: {
LEFT: { target: 'P_LEFT_AVATAR', corner: 'topRight', offsetX: 7, offsetY: 8 },
RIGHT: { target: 'P_RIGHT_AVATAR', corner: 'topLeft', offsetX: -40, offsetY: 8 },
SELF: { kind: 'point', x: 338, y: 668, w: 32, h: 34 }
}
};
//『主N』角标底:仅左右两家(自己主/对数已在手牌区可见,无此角标)。w/h 为清单 §6.6 实测值
EQW_Layout.P_ZHU_BADGE = {
kind: 'attach', corner: 'bottomLeft', offsetX: 0, offsetY: 6, w: 40, h: 19,
bySeat: {
LEFT: { target: 'P_LEFT_AVATAR' },
RIGHT: { target: 'P_RIGHT_AVATAR' }
}
};
//『对N』角标底:贴主N角标右侧。w/h 清单未重复给出,沿用主N角标同尺寸
//(同资源 BADGE_ZHU_PAIR 的另一帧,帧1黄底=主N、帧2白底=对N,尺寸一致)
EQW_Layout.P_PAIR_BADGE = {
kind: 'attach', target: 'P_ZHU_BADGE', hAlign: 'right', vAlign: 'middle',
offsetX: 44, offsetY: 0, w: 40, h: 19
};
//状态文字「60分」/「不叫」:仅左右两家(自己此阶段无独立文字区,见清单 §6.6 表)
EQW_Layout.P_STATUS_TEXT = {
kind: 'point', w: 130, h: 70, textStyle: EQW_Layout.TEXT_STYLE.STATUS_BIG,
bySeat: {
LEFT: { x: 170, y: 165 },
RIGHT: { x: 980, y: 165 }
}
};
//倒计时:三家都有
EQW_Layout.P_COUNTDOWN = {
kind: 'point', w: 75, h: 70,
bySeat: {
LEFT: { x: 195, y: 165 },
RIGHT: { x: 1010, y: 165 },
SELF: { x: 445, y: 345 }
}
};
//提示气泡(踩/没分/有分):朝向 arrowRight 是配置项,不按座位硬判(清单 §6.6)。
//w/h 清单 §3 标『待定』,此处用示意尺寸占位,资源定稿后回填(不影响 kind/字段结构)
EQW_Layout.TISHI_BUBBLE = {
kind: 'attach', w: 96, h: 44,
bySeat: {
LEFT: { target: 'P_LEFT_AVATAR', hAlign: 'right', vAlign: 'middle', offsetX: 10, arrowRight: false },
RIGHT: { target: 'P_RIGHT_AVATAR', hAlign: 'left', vAlign: 'middle', offsetX: -10, arrowRight: true },
SELF: { target: 'P_SELF_AVATAR', hAlign: 'right', vAlign: 'top', offsetX: 10, offsetY: -70, arrowRight: false }
}
};