diff --git a/client/js/01_SubGame/codes/config/AnimConstants.js b/client/js/01_SubGame/codes/config/AnimConstants.js new file mode 100644 index 0000000..5266e18 --- /dev/null +++ b/client/js/01_SubGame/codes/config/AnimConstants.js @@ -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级)。 + //缺动画设计稿与触发细节,定案后在此补参数。 +}; diff --git a/client/js/01_SubGame/codes/config/LayoutConstants.js b/client/js/01_SubGame/codes/config/LayoutConstants.js new file mode 100644 index 0000000..f15f3e3 --- /dev/null +++ b/client/js/01_SubGame/codes/config/LayoutConstants.js @@ -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) +}; diff --git a/client/js/01_SubGame/codes/config/Layout_Action.js b/client/js/01_SubGame/codes/config/Layout_Action.js new file mode 100644 index 0000000..71576ea --- /dev/null +++ b/client/js/01_SubGame/codes/config/Layout_Action.js @@ -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 }; diff --git a/client/js/01_SubGame/codes/config/Layout_Cards.js b/client/js/01_SubGame/codes/config/Layout_Cards.js new file mode 100644 index 0000000..8a35f02 --- /dev/null +++ b/client/js/01_SubGame/codes/config/Layout_Cards.js @@ -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 } + } +}; diff --git a/client/js/01_SubGame/codes/config/Layout_CreateRoom.js b/client/js/01_SubGame/codes/config/Layout_CreateRoom.js new file mode 100644 index 0000000..8ab6553 --- /dev/null +++ b/client/js/01_SubGame/codes/config/Layout_CreateRoom.js @@ -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局 + } +}; diff --git a/client/js/01_SubGame/codes/config/Layout_Result.js b/client/js/01_SubGame/codes/config/Layout_Result.js new file mode 100644 index 0000000..563a50d --- /dev/null +++ b/client/js/01_SubGame/codes/config/Layout_Result.js @@ -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 }; diff --git a/client/js/01_SubGame/codes/config/Layout_Table.js b/client/js/01_SubGame/codes/config/Layout_Table.js new file mode 100644 index 0000000..eb7e116 --- /dev/null +++ b/client/js/01_SubGame/codes/config/Layout_Table.js @@ -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 } + } +};