Files
2026-08-19 08:14:48 +08:00

507 lines
23 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================================================
// 02_SubGame_Input.js —— 平台输入/回调接口「转发壳」(框架维护,子游戏不碰)
// 平台按全局名调用 gameHallImport.* / Game_Modify.*;本文件统一转发到 SubGameHooks 同名 hook。
// 子游戏只需在 codes/ 的 SubGameHooks 里实现需要的接口(见 codes/SubGameHooks.js)。
// 严格 ES5。接口清单与默认值依据 spec §9。
// ============================================================================
var gameHallImport = gameHallImport || {};
var Game_Modify = Game_Modify || {};
// ============================================================================
// gameHallImport.* — 大厅接口(9 个)
// ============================================================================
// A 类:纯子游戏行为,无 hook 即 no-op
// 注:与 Game_Modify.appStart 同名但语义不同(大厅启动 vs 游戏启动),故 hook 名加 hall 前缀区分
gameHallImport.appStart = function () {
if (window.SubGameHooks && SubGameHooks.hallAppStart) return SubGameHooks.hallAppStart();
};
// A 类:纯子游戏行为,无 hook 即 no-op
gameHallImport.jumpMenuScene = function () {
if (window.SubGameHooks && SubGameHooks.jumpMenuScene) return SubGameHooks.jumpMenuScene();
};
// A 类:纯子游戏行为,无 hook 即 no-op
gameHallImport.gameStart = function () {
if (window.SubGameHooks && SubGameHooks.gameStart) return SubGameHooks.gameStart();
};
// A 类:纯子游戏行为,无 hook 即 no-op
gameHallImport.setGameList = function () {
if (window.SubGameHooks && SubGameHooks.setGameList) return SubGameHooks.setGameList();
};
// A 类:纯子游戏行为,无 hook 即 no-op
gameHallImport.clearGameinfo = function () {
if (window.SubGameHooks && SubGameHooks.clearGameinfo) return SubGameHooks.clearGameinfo();
};
// A 类:纯子游戏行为,无 hook 即 no-op
gameHallImport.getWebdata = function (data) {
if (window.SubGameHooks && SubGameHooks.getWebdata) return SubGameHooks.getWebdata(data);
};
// B 类:有平台默认返回值,无 hook 即返回默认
gameHallImport.isInstalled = function (data) {
if (window.SubGameHooks && SubGameHooks.isInstalled) return SubGameHooks.isInstalled(data);
return 1;
};
// A 类:纯子游戏行为,无 hook 即 no-op
gameHallImport.up_imgurl = function (recid, photo) {
if (window.SubGameHooks && SubGameHooks.up_imgurl) return SubGameHooks.up_imgurl(recid, photo);
};
// A 类:纯子游戏行为,无 hook 即 no-op
gameHallImport.getphoto = function (recid, photo) {
if (window.SubGameHooks && SubGameHooks.getphoto) return SubGameHooks.getphoto(recid, photo);
};
// ============================================================================
// Game_Modify.* — 生命周期/回调接口(来自 02,45 个)
// ============================================================================
// A 类:纯子游戏行为,无 hook 即 no-op
Game_Modify.appStart = function () {
if (window.SubGameHooks && SubGameHooks.appStart) return SubGameHooks.appStart();
};
// A 类:开战回调,无 hook 即 no-op
Game_Modify.StartWar = function (_msg) {
if (window.SubGameHooks && SubGameHooks.StartWar) return SubGameHooks.StartWar(_msg);
};
// A 类:接收数据包,无 hook 即 no-op
Game_Modify._ReceiveData = function (_msg) {
if (window.SubGameHooks && SubGameHooks._ReceiveData) return SubGameHooks._ReceiveData(_msg);
};
// A 类:创建房间,无 hook 即 no-op
Game_Modify.createRoom = function (_roomtype, _infinite) {
if (window.SubGameHooks && SubGameHooks.createRoom) return SubGameHooks.createRoom(_roomtype, _infinite);
};
// A 类:自己进入房间,无 hook 即 no-op
Game_Modify.myJoinRoom = function (_msg) {
if (window.SubGameHooks && SubGameHooks.myJoinRoom) return SubGameHooks.myJoinRoom(_msg);
};
// A 类:重连,无 hook 即 no-op
Game_Modify.Reconnect = function (_deskinfo) {
if (window.SubGameHooks && SubGameHooks.Reconnect) return SubGameHooks.Reconnect(_deskinfo);
};
// A 类:未开战重连,无 hook 即 no-op
Game_Modify.ReconnectNoMakewar = function () {
if (window.SubGameHooks && SubGameHooks.ReconnectNoMakewar) return SubGameHooks.ReconnectNoMakewar();
};
// A 类:关闭所有声音,无 hook 即 no-op
Game_Modify.stopAllSounds = function () {
if (window.SubGameHooks && SubGameHooks.stopAllSounds) return SubGameHooks.stopAllSounds();
};
// A 类:投票解散确认,无 hook 即 no-op
Game_Modify.Free = function (_msg) {
if (window.SubGameHooks && SubGameHooks.Free) return SubGameHooks.Free(_msg);
};
// A 类:未开战状态加入牌桌数据,无 hook 即 no-op
Game_Modify.DeskInfo = function (_msg) {
if (window.SubGameHooks && SubGameHooks.DeskInfo) return SubGameHooks.DeskInfo(_msg);
};
// A 类:开局后自己退出房间,无 hook 即 no-op
Game_Modify.breakRoom = function () {
if (window.SubGameHooks && SubGameHooks.breakRoom) return SubGameHooks.breakRoom();
};
// A 类:其他玩家加入房间,无 hook 即 no-op
Game_Modify.playerJoinRoom = function (seat) {
if (window.SubGameHooks && SubGameHooks.playerJoinRoom) return SubGameHooks.playerJoinRoom(seat);
};
// A 类:其他玩家离开房间,无 hook 即 no-op
Game_Modify.playerLeaveRoom = function (seat) {
if (window.SubGameHooks && SubGameHooks.playerLeaveRoom) return SubGameHooks.playerLeaveRoom(seat);
};
// A 类:更新游戏界面,无 hook 即 no-op
Game_Modify.updateScene = function () {
if (window.SubGameHooks && SubGameHooks.updateScene) return SubGameHooks.updateScene();
};
// A 类:关闭游戏界面,无 hook 即 no-op
Game_Modify.closeGameScene = function () {
if (window.SubGameHooks && SubGameHooks.closeGameScene) return SubGameHooks.closeGameScene();
};
// A 类:玩家离线,无 hook 即 no-op
Game_Modify.playerOffline = function (seat) {
if (window.SubGameHooks && SubGameHooks.playerOffline) return SubGameHooks.playerOffline(seat);
};
// A 类:玩家上线,无 hook 即 no-op
Game_Modify.playerOnline = function (seat) {
if (window.SubGameHooks && SubGameHooks.playerOnline) return SubGameHooks.playerOnline(seat);
};
// A 类:玩家电话状态,无 hook 即 no-op
Game_Modify.playerphonestate = function (seat, type) {
if (window.SubGameHooks && SubGameHooks.playerphonestate) return SubGameHooks.playerphonestate(seat, type);
};
// A 类:摇一摇事件,无 hook 即 no-op
Game_Modify.shakeEvent = function () {
if (window.SubGameHooks && SubGameHooks.shakeEvent) return SubGameHooks.shakeEvent();
};
// A 类:计算结果,无 hook 即 no-op
Game_Modify.calResult = function (inputArr) {
if (window.SubGameHooks && SubGameHooks.calResult) return SubGameHooks.calResult(inputArr);
};
// A 类:进入游戏主场景,无 hook 即 no-op
Game_Modify.onEnterMainScene = function (roomtype) {
if (window.SubGameHooks && SubGameHooks.onEnterMainScene) return SubGameHooks.onEnterMainScene(roomtype);
};
// A 类:退出游戏主场景,无 hook 即 no-op
Game_Modify.onExitMainScene = function () {
if (window.SubGameHooks && SubGameHooks.onExitMainScene) return SubGameHooks.onExitMainScene();
};
// A 类:获取游戏配置时调用,无 hook 即 no-op
Game_Modify.onGameConfig = function (_gameConfig) {
if (window.SubGameHooks && SubGameHooks.onGameConfig) return SubGameHooks.onGameConfig(_gameConfig);
};
// A 类:进入牌局回放,无 hook 即 no-op
Game_Modify.onEnterVideo = function () {
if (window.SubGameHooks && SubGameHooks.onEnterVideo) return SubGameHooks.onEnterVideo();
};
// A 类:收到投降回包,无 hook 即 no-op
Game_Modify.onSurrender = function (_msg) {
if (window.SubGameHooks && SubGameHooks.onSurrender) return SubGameHooks.onSurrender(_msg);
};
// A 类:玩家准备触发,无 hook 即 no-op
Game_Modify.onReady = function (seat) {
if (window.SubGameHooks && SubGameHooks.onReady) return SubGameHooks.onReady(seat);
};
// B 类:获取房间描述,无 hook 返回默认文案
Game_Modify.getRoomInfo = function (roomtype, type, tea) {
if (window.SubGameHooks && SubGameHooks.getRoomInfo) return SubGameHooks.getRoomInfo(roomtype, type, tea);
return "房间描述" + roomtype;
};
// B 类:获取房间星星场下限,无 hook 返回默认值
Game_Modify.getStarLimit = function (roomtype) {
if (window.SubGameHooks && SubGameHooks.getStarLimit) return SubGameHooks.getStarLimit(roomtype);
return 2001000;
};
// B 类:获取房间星星场倍数,无 hook 返回默认值
Game_Modify.getMult = function (roomtype, type) {
if (window.SubGameHooks && SubGameHooks.getMult) return SubGameHooks.getMult(roomtype, type);
return 10000;
};
// B 类:获取房间全部信息描述,无 hook 返回默认文案
Game_Modify.getFullRoomInfo = function (roomtype) {
if (window.SubGameHooks && SubGameHooks.getFullRoomInfo) return SubGameHooks.getFullRoomInfo(roomtype);
return "房间描述" + roomtype;
};
// A 类:打开帮助页面,无 hook 即 no-op
Game_Modify.onOpenHelp = function (spid) {
if (window.SubGameHooks && SubGameHooks.onOpenHelp) return SubGameHooks.onOpenHelp(spid);
};
// A 类:显示大厅界面,无 hook 即 no-op
Game_Modify.onMainMenuScene = function () {
if (window.SubGameHooks && SubGameHooks.onMainMenuScene) return SubGameHooks.onMainMenuScene();
};
// A 类:数字输入框确认回调,无 hook 即 no-op
Game_Modify.onCheckInput = function (_result) {
if (window.SubGameHooks && SubGameHooks.onCheckInput) return SubGameHooks.onCheckInput(_result);
};
// A 类:创建房间成功后触发,无 hook 即 no-op
Game_Modify.onCreateRoom = function (_data) {
if (window.SubGameHooks && SubGameHooks.onCreateRoom) return SubGameHooks.onCreateRoom(_data);
};
// B 类:获取离场限制,无 hook 返回默认值
Game_Modify.getLeaveLimit = function (roomtype) {
if (window.SubGameHooks && SubGameHooks.getLeaveLimit) return SubGameHooks.getLeaveLimit(roomtype);
return 10;
};
// A 类:成功获取定位信息,无 hook 即 no-op
Game_Modify.onLocationInfo = function (_locationInfo) {
if (window.SubGameHooks && SubGameHooks.onLocationInfo) return SubGameHooks.onLocationInfo(_locationInfo);
};
// A 类:进入游戏界面创建牌桌之前,无 hook 即 no-op
Game_Modify.onCreateDesk = function (roomtype) {
if (window.SubGameHooks && SubGameHooks.onCreateDesk) return SubGameHooks.onCreateDesk(roomtype);
};
// B 类:获取是否开启视频功能,无 hook 返回默认值
Game_Modify.getVideoByRoomType = function (roomtype) {
if (window.SubGameHooks && SubGameHooks.getVideoByRoomType) return SubGameHooks.getVideoByRoomType(roomtype);
return 1;
};
// B 类:获取房间顶部描述数组,无 hook 返回默认文案数组
Game_Modify.getRoomTopDescAry = function (roomtype) {
if (window.SubGameHooks && SubGameHooks.getRoomTopDescAry) return SubGameHooks.getRoomTopDescAry(roomtype);
return ["" + roomtype];
};
// A 类:星星场房间列表,无 hook 即 no-op
Game_Modify.getShareRoom = function (_msg) {
if (window.SubGameHooks && SubGameHooks.getShareRoom) return SubGameHooks.getShareRoom(_msg);
};
// A 类:玩家自己退出房间,无 hook 即 no-op
Game_Modify.myExitRoom = function (seat) {
if (window.SubGameHooks && SubGameHooks.myExitRoom) return SubGameHooks.myExitRoom(seat);
};
// A 类:接收到换座包触发,无 hook 即 no-op
Game_Modify.changeSeat = function (seat1, seat2) {
if (window.SubGameHooks && SubGameHooks.changeSeat) return SubGameHooks.changeSeat(seat1, seat2);
};
// A 类:关闭 vip 选项时调用,无 hook 即 no-op
Game_Modify.onCloseVip = function () {
if (window.SubGameHooks && SubGameHooks.onCloseVip) return SubGameHooks.onCloseVip();
};
// B 类:判断房间是否为金币场,无 hook 返回默认值(0=非金币场)
Game_Modify.getRoomMode = function (roomtype) {
if (window.SubGameHooks && SubGameHooks.getRoomMode) return SubGameHooks.getRoomMode(roomtype);
return 0;
};
// B 类:获取房间最大玩家数量,无 hook 返回默认值
Game_Modify.getMaxPlayerCount = function (roomtype) {
if (window.SubGameHooks && SubGameHooks.getMaxPlayerCount) return SubGameHooks.getMaxPlayerCount(roomtype);
// 默认值依赖全局 Game_Config(须在本模板之前加载);无则回退 4
return (Game_Config.Max && Game_Config.Max.PlayerCnt) || 4;
};
// 内部辅助(非平台接口):把相对显示位序 relPos 映射为 { ind:精灵槽, configIndex:物理布局位 }。
// 2/3 人时 ind≠configIndex;无效返回 null。updatePlayerInfoUI 与桌面气泡默认实现共用此映射,
// 保证头像面板与聊天/语音气泡落在同一玩家位。
Game_Modify._resolveDisplaySlot = function (relPos, playerCount) {
var ind = -1, configIndex = -1;
if (playerCount === 2) {
if (relPos === 0) { ind = 0; configIndex = 0; }
else if (relPos === 1) { ind = 1; configIndex = 2; }
} else if (playerCount === 3) {
if (relPos === 0) { ind = 0; configIndex = 0; }
else if (relPos === 1) { ind = 1; configIndex = 1; }
else if (relPos === 2) { ind = 2; configIndex = 3; }
} else {
if (relPos === 0) { ind = 0; configIndex = 0; }
else if (relPos === 1) { ind = 1; configIndex = 1; }
else if (relPos === 2) { ind = 2; configIndex = 2; }
else if (relPos === 3) { ind = 3; configIndex = 3; }
}
if (ind === -1) return null;
return { ind: ind, configIndex: configIndex };
};
// B 类:更新指定座位的玩家信息 UI(昵称/分数/头像)。
// 有 hook 则委托子游戏;无 hook 时由本模板提供默认头像等 UI 的显示逻辑,其逻辑与子游戏
// codes 内 GameView.updatePlayerInfoUI 保持一致,布局取自 Game_Modify.PLAYER_INFO_LAYOUT(见 01)。
// 精灵操作一律经框架 SpriteManager(setPosition/setSize/setText/show|hideGroup),不直接调
// set_self/set_group 等引擎原语;头像加载走平台 Func.up_imgurl(非精灵原语,SpriteManager 无对应能力)。
// 不引用任何 codes 模块。平台 GameUI.updatePlayerInfoUI 会对每个座位逐一调用本接口,故按单座位渲染。
Game_Modify.updatePlayerInfoUI = function (targetSeat) {
if (window.SubGameHooks && SubGameHooks.updatePlayerInfoUI) return SubGameHooks.updatePlayerInfoUI(targetSeat);
// ---- 模板默认:与 GameView.updatePlayerInfoUI 一致的单座位渲染 ----
if (typeof Desk === 'undefined' || typeof C_Player === 'undefined' || typeof SpriteManager === 'undefined') return false;
var layout = Game_Modify.PLAYER_INFO_LAYOUT;
if (!layout || !layout.POSITIONS) return false;
if (!Desk.PlayerList || targetSeat < 0 || targetSeat >= Desk.PlayerList.length) return false;
var selfSeat = (typeof C_Player.seat === 'number') ? C_Player.seat : 0;
var playerCount = (Game_Config.Max && Game_Config.Max.PlayerCnt) || 4;
var relPos = (targetSeat - selfSeat + playerCount) % playerCount;
// 显示槽 ind 与布局位 configIndex(2/3 人时两者不同)
var slot = Game_Modify._resolveDisplaySlot(relPos, playerCount);
if (!slot) return false;
var ind = slot.ind, configIndex = slot.configIndex;
var player = Desk.PlayerList[targetSeat];
// 空座位:隐藏该位玩家信息群组
if (!player || !player.playerid || player.playerid === -1) {
SpriteManager.hideGroup(43 + ind);
return true;
}
var posConfig = layout.POSITIONS[configIndex];
if (!posConfig) return false;
// 底框(346+ind)
if (posConfig.FRAME_X !== undefined) {
SpriteManager.setPosition(346 + ind, posConfig.FRAME_X, posConfig.FRAME_Y);
SpriteManager.setSize(346 + ind, posConfig.FRAME_WIDTH, posConfig.FRAME_HEIGHT);
}
// 头像框(376+ind):基于底框 + 相对偏移
var avatarX = posConfig.FRAME_X + posConfig.AVATAR.OFFSET_X;
var avatarY = posConfig.FRAME_Y + posConfig.AVATAR.OFFSET_Y;
var avatarWidth = posConfig.AVATAR.WIDTH;
var avatarHeight = posConfig.AVATAR.HEIGHT;
var nameOffsetX = posConfig.AVATAR.NAME_OFFSET_X || 0;
var nameOffsetY = posConfig.AVATAR.NAME_OFFSET_Y || 0;
var scoreOffsetX = posConfig.AVATAR.SCORE_OFFSET_X || 0;
var scoreOffsetY = posConfig.AVATAR.SCORE_OFFSET_Y || 0;
SpriteManager.setPosition(376 + ind, avatarX, avatarY);
SpriteManager.setSize(376 + ind, avatarWidth, avatarHeight);
var textStyle = layout.TEXT_STYLE || {};
var maxLen = textStyle.NAME_MAX_LENGTH || 8;
var charWidth = textStyle.CHAR_WIDTH || 7;
// 昵称(406+ind)
var nickname = Func.subString(player.nickname || '', maxLen, true);
SpriteManager.setText(406 + ind, nickname);
var nameX = avatarX + nameOffsetX;
if (posConfig.NAME_CENTER_ALIGN) {
var textWidth = (typeof nickname.gblen === 'function') ? nickname.gblen() * charWidth : nickname.length * charWidth;
nameX = avatarX + avatarWidth / 2 - textWidth / 2;
}
SpriteManager.setPosition(406 + ind, nameX, avatarY + nameOffsetY);
// 分数(436+ind)
var score = (typeof player.score === 'number') ? player.score : 0;
SpriteManager.setText(436 + ind, score);
var scoreX = avatarX + scoreOffsetX;
if (posConfig.NAME_CENTER_ALIGN) {
var scoreWidth = String(score).length * charWidth;
scoreX = avatarX + avatarWidth / 2 - scoreWidth / 2;
}
SpriteManager.setPosition(436 + ind, scoreX, avatarY + scoreOffsetY);
// 头像图(116+ind):Func.up_imgurl 为平台头像加载接口(非引擎精灵原语)
if (player.avatar && typeof Func !== 'undefined' && typeof Func.up_imgurl === 'function') {
Func.up_imgurl(116 + ind, player.avatar);
}
// 显示该座位玩家信息群组
SpriteManager.showGroup(43 + ind);
return true;
};
// 桌面文字聊天气泡:有 hook 委托子游戏;无 hook 时按【可变人数】默认渲染,使气泡贴合各玩家。
// seat 为绝对座位;经 SpriteManager 操作精灵(背景552+ind/文字582+ind),位置取自 Game_Modify.BUBBLE_LAYOUT
// 的物理位配置,尺寸(内边距/字宽/显示时长)复用 Game_Config.Chat/Max;不直接调引擎原语、不引用 codes。
Game_Modify.ShowChat = function (seat, text) {
if (window.SubGameHooks && SubGameHooks.ShowChat) return SubGameHooks.ShowChat(seat, text);
GameUI.CloseChat();
if (typeof Desk === 'undefined' || typeof C_Player === 'undefined' || typeof SpriteManager === 'undefined') return;
var layout = Game_Modify.BUBBLE_LAYOUT;
if (!layout || !layout.POSITIONS) return;
var playerCount = (Game_Config.Max && Game_Config.Max.PlayerCnt) || 4;
var relPos = (seat - C_Player.seat + playerCount) % playerCount;
var slot = Game_Modify._resolveDisplaySlot(relPos, playerCount);
if (!slot) return;
var pos = layout.POSITIONS[slot.configIndex];
if (!pos) return;
var ind = slot.ind;
text = String(text);
var chat = Game_Config.Chat || {};
var dis_x = (chat.ChatDis && chat.ChatDis[0]) || 0;
var dis_y = (chat.ChatDis && chat.ChatDis[1]) || 0;
var text_w = chat.textwidth || 14;
var text_len = (typeof text.gblen === 'function') ? text.gblen() : text.length;
var bgW = text_len * text_w + dis_x * 2;
SpriteManager.setText(582 + ind, text);
if (pos.IS_LEFT) {
SpriteManager.setPosition(552 + ind, pos.X, pos.Y);
SpriteManager.setPosition(582 + ind, pos.X + dis_x, pos.Y + dis_y);
SpriteManager.setImage(552 + ind, layout.IMG_LEFT);
} else {
SpriteManager.setPosition(552 + ind, pos.X - bgW, pos.Y);
SpriteManager.setPosition(582 + ind, pos.X - text_len * text_w - dis_x, pos.Y + dis_y);
SpriteManager.setImage(552 + ind, layout.IMG_RIGHT);
}
SpriteManager.setWidth(552 + ind, bgW);
SpriteManager.show(552 + ind);
SpriteManager.show(582 + ind);
// 自动隐藏:复用平台配置的显示时长(观感与固定人数版一致),按槽位去重定时器
var dur = (Game_Config.Max && Game_Config.Max.ShowChat) || 3000;
Game_Modify._chatHideTimers = Game_Modify._chatHideTimers || {};
if (Game_Modify._chatHideTimers[ind]) { clearTimeout(Game_Modify._chatHideTimers[ind]); }
Game_Modify._chatHideTimers[ind] = setTimeout(function () {
SpriteManager.hide(552 + ind);
SpriteManager.hide(582 + ind);
Game_Modify._chatHideTimers[ind] = null;
}, dur);
};
// 桌面语音气泡(播放):有 hook 委托子游戏;无 hook 时按【可变人数】默认渲染。
// uiIndex 已是相对显示位序(relPos);经 SpriteManager 操作精灵(背景612+ind/内容642+ind),
// 位置取自 Game_Modify.BUBBLE_LAYOUT,气泡宽度依据内容精灵当前宽度;尺寸复用 Game_Config.Voice。
Game_Modify.gameui_play_voice = function (uiIndex) {
if (window.SubGameHooks && SubGameHooks.gameui_play_voice) return SubGameHooks.gameui_play_voice(uiIndex);
if (typeof SpriteManager === 'undefined') return;
var layout = Game_Modify.BUBBLE_LAYOUT;
if (!layout || !layout.POSITIONS) return;
var playerCount = (Game_Config.Max && Game_Config.Max.PlayerCnt) || 4;
var relPos = ((Number(uiIndex) % playerCount) + playerCount) % playerCount;
var slot = Game_Modify._resolveDisplaySlot(relPos, playerCount);
if (!slot) return;
var pos = layout.POSITIONS[slot.configIndex];
if (!pos) return;
var ind = slot.ind;
var voice = Game_Config.Voice || {};
var dis_x = (voice.VoiceDis && voice.VoiceDis[0]) || 0;
var dis_y = (voice.VoiceDis && voice.VoiceDis[1]) || 0;
var contentSize = SpriteManager.getSize(642 + ind);
var text_len = (contentSize && typeof contentSize.width === 'number') ? contentSize.width : 0;
var bgW = text_len + dis_x * 2;
if (pos.IS_LEFT) {
SpriteManager.setPosition(612 + ind, pos.X, pos.Y);
SpriteManager.setPosition(642 + ind, pos.X + dis_x, pos.Y + dis_y);
SpriteManager.setImage(612 + ind, layout.IMG_LEFT);
} else {
SpriteManager.setPosition(612 + ind, pos.X - bgW, pos.Y);
SpriteManager.setPosition(642 + ind, pos.X - text_len - dis_x, pos.Y + dis_y);
SpriteManager.setImage(612 + ind, layout.IMG_RIGHT);
}
SpriteManager.setWidth(612 + ind, bgW);
SpriteManager.show(612 + ind);
SpriteManager.show(642 + ind);
play_ani(1, 642 + ind, 43, 1, 3, 0, Game_Config.Voice.VoiceTime, 0, 0, 0, 0, 0, 0);
};
// 桌面语音气泡(停止):有 hook 委托子游戏;无 hook 时隐藏对应槽位的语音气泡。
Game_Modify.gameui_stop_voice = function (uiIndex) {
if (window.SubGameHooks && SubGameHooks.gameui_stop_voice) return SubGameHooks.gameui_stop_voice(uiIndex);
if (typeof SpriteManager === 'undefined') return;
var playerCount = (Game_Config.Max && Game_Config.Max.PlayerCnt) || 4;
var relPos = ((Number(uiIndex) % playerCount) + playerCount) % playerCount;
var slot = Game_Modify._resolveDisplaySlot(relPos, playerCount);
if (!slot) return;
var ind = slot.ind;
SpriteManager.hide(612 + ind);
SpriteManager.hide(642 + ind);
};