From 3031131e1b73528041d8560f328204a37fe47d8e Mon Sep 17 00:00:00 2001 From: notify Date: Fri, 26 Jan 2024 14:02:55 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A6=81=E5=B0=86=E5=8A=9F=E8=83=BD=E6=94=B9?= =?UTF-8?q?=E8=BF=9B=20(#309)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RT 不影响Lua API --- Fk/Config.qml | 44 +- Fk/LobbyElement/BanGeneralSetting.qml | 246 +++++++--- Fk/LobbyElement/RoomGeneralSettings.qml | 49 +- Fk/LobbyElement/RoomPackageSettings.qml | 27 +- Fk/Pages/GeneralsOverview.qml | 627 +++++++++++++++--------- Fk/Pages/Lobby.qml | 12 +- Fk/Pages/RoomLogic.js | 34 +- image/button/skill/locked.png | Bin 0 -> 2239 bytes lua/client/client_util.lua | 5 + lua/client/i18n/zh_CN.lua | 7 + lua/core/engine.lua | 3 + 11 files changed, 707 insertions(+), 347 deletions(-) create mode 100644 image/button/skill/locked.png diff --git a/Fk/Config.qml b/Fk/Config.qml index 1d5c079c..c488af08 100644 --- a/Fk/Config.qml +++ b/Fk/Config.qml @@ -15,7 +15,7 @@ QtObject { property string roomBg property string bgmFile property string language - property list disabledPack: [] + // property list disabledPack: [] property string preferedMode property int preferedPlayerNum property int preferredGeneralNum @@ -23,9 +23,12 @@ QtObject { property real bgmVolume property bool disableMsgAudio property bool hideUseless - property list disabledGenerals: [] - property list disableGeneralSchemes: [] - property int disableSchemeIdx: 0 + // property list disabledGenerals: [] + // property list disableGeneralSchemes: [] + // property int disableSchemeIdx: 0 + property list disableSchemes: [] + property int currentDisableIdx: 0 + property var curScheme property int preferredTimeout property int preferredLuckTime @@ -52,9 +55,9 @@ QtObject { property list blockedUsers: [] property int totalTime: 0 // FIXME: only for notifying - onDisabledGeneralsChanged: { - disableGeneralSchemes[disableSchemeIdx] = disabledGenerals; - } + // onDisabledGeneralsChanged: { + // disableGeneralSchemes[disableSchemeIdx] = disabledGenerals; + // } function loadConf() { conf = JSON.parse(Backend.loadConf()); @@ -75,7 +78,7 @@ QtObject { return 'en_US'; } })(); - disabledPack = conf.disabledPack ?? [ "test_p_0" ]; + // disabledPack = conf.disabledPack ?? [ "test_p_0" ]; preferedMode = conf.preferedMode ?? "aaa_role_mode"; preferedPlayerNum = conf.preferedPlayerNum ?? 2; preferredGeneralNum = conf.preferredGeneralNum ?? 3; @@ -87,9 +90,17 @@ QtObject { preferredTimeout = conf.preferredTimeout ?? 15; preferredLuckTime = conf.preferredLuckTime ?? 0; firstRun = conf.firstRun ?? true; - disabledGenerals = conf.disabledGenerals ?? []; - disableGeneralSchemes = conf.disableGeneralSchemes ?? [ disabledGenerals ]; - disableSchemeIdx = conf.disableSchemeIdx ?? 0; + // disabledGenerals = conf.disabledGenerals ?? []; + // disableGeneralSchemes = conf.disableGeneralSchemes ?? [ disabledGenerals ]; + // disableSchemeIdx = conf.disableSchemeIdx ?? 0; + disableSchemes = conf.disableSchemes ?? [{ + name: "", + banPkg: {}, // 被禁用的包,内部数据为 包名: 白名单武将名数组 + normalPkg: {}, // 未被禁用的包,内部数据为 包名: 黑名单武将名数组 + banCardPkg: [], // 被禁用的卡包 + }]; + currentDisableIdx = conf.currentDisableIdx ?? 0; + curScheme = disableSchemes[currentDisableIdx]; blockedUsers = conf.blockedUsers ?? []; } @@ -104,7 +115,7 @@ QtObject { conf.roomBg = roomBg; conf.bgmFile = bgmFile; conf.language = language; - conf.disabledPack = disabledPack; + // conf.disabledPack = disabledPack; conf.preferedMode = preferedMode; conf.preferedPlayerNum = preferedPlayerNum; conf.ladyImg = ladyImg; @@ -116,9 +127,12 @@ QtObject { conf.preferredTimeout = preferredTimeout; conf.preferredLuckTime = preferredLuckTime; conf.firstRun = firstRun; - conf.disabledGenerals = disabledGenerals; - conf.disableGeneralSchemes = disableGeneralSchemes; - conf.disableSchemeIdx = disableSchemeIdx; + // conf.disabledGenerals = disabledGenerals; + // conf.disableGeneralSchemes = disableGeneralSchemes; + // conf.disableSchemeIdx = disableSchemeIdx; + disableSchemes[currentDisableIdx] = curScheme; + conf.disableSchemes = disableSchemes; + conf.currentDisableIdx = currentDisableIdx; conf.blockedUsers = blockedUsers; Backend.saveConf(JSON.stringify(conf, undefined, 2)); diff --git a/Fk/LobbyElement/BanGeneralSetting.qml b/Fk/LobbyElement/BanGeneralSetting.qml index 63e6711d..59ef8439 100644 --- a/Fk/LobbyElement/BanGeneralSetting.qml +++ b/Fk/LobbyElement/BanGeneralSetting.qml @@ -11,6 +11,7 @@ Item { ColumnLayout { anchors.fill: parent RowLayout { + Layout.fillWidth: true anchors.rightMargin: 8 spacing: 16 Text { @@ -19,65 +20,94 @@ Item { ComboBox { id: banCombo textRole: "name" + Layout.fillWidth: true model: ListModel { id: banComboList } onCurrentIndexChanged: { - config.disableSchemeIdx = currentIndex; - config.disabledGenerals = config.disableGeneralSchemes[currentIndex]; + word.text = ""; + config.disableSchemes[config.currentDisableIdx] = config.curScheme; + config.currentDisableIdx = currentIndex; + config.curScheme = config.disableSchemes[currentIndex]; } } - Button { - text: luatr("New") - onClicked: { - const i = config.disableGeneralSchemes.length; - banComboList.append({ - name: luatr("List") + (i + 1), - }); - config.disableGeneralSchemes.push([]); - } - } + GridLayout { + columns: 2 - Button { - text: luatr("Clear") - onClicked: { - config.disabledGenerals = []; - } - } - - Button { - text: luatr("Export") - onClicked: { - Backend.copyToClipboard(JSON.stringify(config.disabledGenerals)); - toast.show(luatr("Export Success")); - } - } - - Button { - text: luatr("Import") - onClicked: { - const str = Backend.readClipboard(); - let data; - try { - data = JSON.parse(str); - } catch (e) { - toast.show(luatr("Not Legal")); - return; + Button { + text: luatr("New") + onClicked: { + const i = config.disableSchemes.length; + banComboList.append({ + name: luatr("List") + (i + 1), + }); + config.disableSchemes.push({ + name: "", + banPkg: {}, + normalPkg: {}, + banCardPkg: [], + }); } - if (!data instanceof Array) { - toast.show(luatr("Not JSON")); - return; + } + + Button { + text: luatr("Clear") + onClicked: { + config.curScheme.banPkg = {}; + config.curScheme.normalPkg = {}; + config.curScheme.banCardPkg = []; + config.curSchemeChanged(); } - let d = []; - for (let e of data) { - if (typeof e === "string" && luatr(e) !== e) { - d.push(e); + } + + Button { + text: luatr("Export") + onClicked: { + Backend.copyToClipboard(JSON.stringify(config.curScheme)); + toast.show(luatr("Export Success")); + } + } + + Button { + text: luatr("Import") + onClicked: { + const str = Backend.readClipboard(); + let data; + try { + data = JSON.parse(str); + } catch (e) { + toast.show(luatr("Not Legal")); + return; + } + if (!data instanceof Object || !data.banPkg || !data.normalPkg + || !data.banCardPkg) { + toast.show(luatr("Not JSON")); + return; + } + config.curScheme = data; + if (data.name) { + banComboList.get(banCombo.currentIndex).name = data.name; } } - config.disabledGenerals = d; - toast.show(luatr("Import Success")); + } + } + + TextField { + id: word + clip: true + leftPadding: 5 + rightPadding: 5 + } + + Button { + text: luatr("Rename") + enabled: word.text !== "" + onClicked: { + banComboList.get(banCombo.currentIndex).name = word.text; + config.curScheme.name = word.text; + word.text = ""; } } } @@ -89,35 +119,119 @@ Item { text: luatr("Help_Ban_List") } - GridView { - id: listView + GridLayout { + id: grid + flow: GridLayout.TopToBottom + rows: 2 Layout.fillWidth: true Layout.fillHeight: true - clip: true - cellWidth: width / 4 - cellHeight: 24 - model: config.disabledGenerals - delegate: Text { - width: listView.width - text: { - const prefix = modelData.split("__")[0]; - let name = luatr(modelData); - if (prefix !== modelData) { - name += (" (" + luatr(prefix) + ")"); - } - return name; - } - font.pixelSize: 16 + + Text { + wrapMode: Text.WrapAnywhere + text: luatr("Ban_Generals") + font.pixelSize: 18 + font.bold: true } + + GridView { + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + cellWidth: width / 2 + cellHeight: 24 + model: { + let ret = [], k; + const s = config.curScheme; + for (k in s.normalPkg) { + ret.push(...s.normalPkg[k]); + } + return ret; + } + delegate: Text { + //width: banChara.width + text: { + const prefix = modelData.split("__")[0]; + let name = luatr(modelData); + if (prefix !== modelData) { + name += (" (" + luatr(prefix) + ")"); + } + return name; + } + font.pixelSize: 16 + } + } + + Text { + wrapMode: Text.WrapAnywhere + text: luatr("Ban_Packages") + font.pixelSize: 18 + font.bold: true + } + + GridView { + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + cellWidth: width / 2 + cellHeight: 24 + model: { + let ret = [], k; + const s = config.curScheme; + for (k in s.banPkg) { + ret.push(k); + } + ret.push(...s.banCardPkg) + return ret; + } + delegate: Text { + text: luatr(modelData) + font.pixelSize: 16 + } + } + + Text { + wrapMode: Text.WrapAnywhere + text: luatr("Whitelist_Generals") + font.pixelSize: 18 + font.bold: true + } + + GridView { + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + cellWidth: width / 2 + cellHeight: 24 + model: { + let ret = [], k; + const s = config.curScheme; + for (k in s.banPkg) { + ret.push(...s.banPkg[k]); + } + return ret; + } + delegate: Text { + text: { + const prefix = modelData.split("__")[0]; + let name = luatr(modelData); + if (prefix !== modelData) { + name += (" (" + luatr(prefix) + ")"); + } + return name; + } + font.pixelSize: 16 + } + } + } } Component.onCompleted: { - for (let i = 0; i < config.disableGeneralSchemes.length; i++) { + for (let i = 0; i < config.disableSchemes.length; i++) { banComboList.append({ - name: luatr("List") + (i + 1), + name: config.disableSchemes[i]?.name || (luatr("List") + (i + 1)), }); } - banCombo.currentIndex = config.disableSchemeIdx; + banCombo.currentIndex = config.currentDisableIdx; } } diff --git a/Fk/LobbyElement/RoomGeneralSettings.qml b/Fk/LobbyElement/RoomGeneralSettings.qml index ed7cca5b..1889a42a 100644 --- a/Fk/LobbyElement/RoomGeneralSettings.qml +++ b/Fk/LobbyElement/RoomGeneralSettings.qml @@ -113,7 +113,6 @@ Flickable { id: warning anchors.rightMargin: 8 visible: { - //config.disabledPack; // 没什么用,只是为了禁包刷新时刷新visible罢了 const avail = lcall("GetAvailableGeneralsNum"); const ret = avail < config.preferredGeneralNum * config.preferedPlayerNum; @@ -164,36 +163,32 @@ Flickable { config.saveConf(); root.finished(); mainWindow.busy = true; + let k, arr; - let disabledGenerals = config.disabledGenerals.slice(); - if (disabledGenerals.length) { - const availablePack = lcall("GetAllGeneralPack"). - filter((pack) => !config.disabledPack.includes(pack)); - disabledGenerals = disabledGenerals.filter((general) => { - return availablePack.find(pack => - lcall("GetGenerals", pack).includes(general)); - }); - - disabledGenerals = Array.from(new Set(disabledGenerals)); + let disabledGenerals = []; + for (k in config.curScheme.banPkg) { + arr = config.curScheme.banPkg[k]; + if (arr.length !== 0) { + const generals = lcall("GetGenerals", k); + disabledGenerals.push(...generals.filter(g => !arr.includes(g))); + } + } + for (k in config.curScheme.normalPkg) { + arr = config.curScheme.normalPkg[k] ?? []; + if (arr.length !== 0) + disabledGenerals.push(...arr); } - let disabledPack = config.disabledPack.slice(); + let disabledPack = config.curScheme.banCardPkg.slice(); + for (k in config.curScheme.banPkg) { + if (config.curScheme.banPkg[k].length === 0) + disabledPack.push(k); + } config.serverHiddenPacks.forEach(p => { if (!disabledPack.includes(p)) { disabledPack.push(p); } }); - const generalPacks = lcall("GetAllGeneralPack"); - for (let pk of generalPacks) { - if (disabledPack.includes(pk)) continue; - let generals = lcall("GetGenerals", pk); - let t = generals.filter(g => !disabledGenerals.includes(g)); - if (t.length === 0) { - disabledPack.push(pk); - disabledGenerals = disabledGenerals - .filter(g1 => !generals.includes(g1)); - } - } ClientInstance.notifyServer( "CreateRoom", @@ -232,8 +227,12 @@ Flickable { playerNum.value = config.preferedPlayerNum; - config.disabledPack.forEach(p => lcall("UpdatePackageEnable", p, false)); - config.disabledPackChanged(); + for (let k in config.curScheme.banPkg) { + lcall("UpdatePackageEnable", k, false); + } + config.curScheme.banCardPkg.forEach(p => + lcall("UpdatePackageEnable", p, false)); + config.curSchemeChanged(); } } } diff --git a/Fk/LobbyElement/RoomPackageSettings.qml b/Fk/LobbyElement/RoomPackageSettings.qml index fff8328f..cbd2a405 100644 --- a/Fk/LobbyElement/RoomPackageSettings.qml +++ b/Fk/LobbyElement/RoomPackageSettings.qml @@ -113,7 +113,15 @@ Flickable { checked: pkg_enabled onCheckedChanged: { - checkPackage(orig_name, checked); + const packs = config.curScheme.banCardPkg; + if (checked) { + const idx = packs.indexOf(orig_name); + if (idx !== -1) packs.splice(idx, 1); + } else { + packs.push(orig_name); + } + lcall("UpdatePackageEnable", orig_name, checked); + config.curSchemeChanged(); } } } @@ -121,15 +129,16 @@ Flickable { } function checkPackage(orig_name, checked) { - const packs = config.disabledPack; - if (checked) { - const idx = packs.indexOf(orig_name); - if (idx !== -1) packs.splice(idx, 1); + const s = config.curScheme; + if (!checked) { + s.banPkg[orig_name] = []; + s.normalPkg[orig_name] = undefined; } else { - packs.push(orig_name); + s.normalPkg[orig_name] = undefined; + s.banPkg[orig_name] = undefined; } lcall("UpdatePackageEnable", orig_name, checked); - config.disabledPackChanged(); + config.curSchemeChanged(); } Component.onCompleted: { @@ -143,7 +152,7 @@ Flickable { gpacklist.append({ name: luatr(orig), orig_name: orig, - pkg_enabled: !config.disabledPack.includes(orig), + pkg_enabled: !config.curScheme.banPkg[orig], }); } @@ -155,7 +164,7 @@ Flickable { cpacklist.append({ name: luatr(orig), orig_name: orig, - pkg_enabled: !config.disabledPack.includes(orig), + pkg_enabled: !config.curScheme.banCardPkg.includes(orig), }); } loading = false; diff --git a/Fk/Pages/GeneralsOverview.qml b/Fk/Pages/GeneralsOverview.qml index d1fae2fd..840b515e 100644 --- a/Fk/Pages/GeneralsOverview.qml +++ b/Fk/Pages/GeneralsOverview.qml @@ -11,39 +11,97 @@ Item { id: root property bool loaded: false + property int stat: 0 // 0=normal 1=banPkg 2=banChara Rectangle { - anchors.fill: listView - color: "#88EEEEEE" + id: listBg + width: 260; height: parent.height + color: "snow" radius: 6 } ListView { - id: listView + id: modList + width: 130; height: parent.height + anchors.top: listBg.top; anchors.left: listBg.left clip: true - width: 130 - height: parent.height - 20 - y: 10 - ScrollBar.vertical: ScrollBar {} model: ListModel { - id: packages + id: mods } - highlight: Rectangle { color: "#E91E63"; radius: 5 } + Rectangle { + anchors.fill: parent + color: "#A48959" + z: -1 + } + + highlight: Rectangle { color: "snow" } highlightMoveDuration: 500 delegate: Item { - width: listView.width + width: modList.width height: 40 Text { text: luatr(name) + color: modList.currentIndex === index ? "black" : "white" anchors.centerIn: parent } TapHandler { onTapped: { - listView.currentIndex = index; + modList.currentIndex = index; + } + } + } + } + + ListView { + id: pkgList + width: 130; height: parent.height + anchors.top: listBg.top; anchors.left: modList.right + + clip: true + model: JSON.parse(mods.get(modList.currentIndex)?.pkgs ?? "[]") + + highlight: Rectangle { color: "#FFCC3F"; radius: 5; scale: 0.8 } + highlightMoveDuration: 500 + + delegate: Item { + width: pkgList.width + height: 40 + + Text { + text: luatr(modelData) + color: !config.curScheme.banPkg[modelData] ? "black" : "grey" + Behavior on color { ColorAnimation { duration: 200 } } + anchors.centerIn: parent + } + + Image { + source: AppPath + "/image/button/skill/locked.png" + opacity: !config.curScheme.banPkg[modelData] ? 0 : 1 + Behavior on opacity { NumberAnimation { duration: 200 } } + anchors.centerIn: parent + scale: 0.8 + } + + TapHandler { + onTapped: { + if (stat === 1) { + const name = modelData; + let s = config.curScheme; + if (s.banPkg[name]) { + s.banPkg[name] = undefined; + s.normalPkg[name] = undefined; + } else { + s.normalPkg[name] = undefined; + s.banPkg[name] = []; + } + config.curSchemeChanged(); + } else { + pkgList.currentIndex = index; + } } } } @@ -51,13 +109,102 @@ Item { onCurrentIndexChanged: { vanishAnim.start(); } } + ToolBar { + id: bar + width: root.width - listBg.width - 16 + anchors.left: listBg.right + anchors.leftMargin: 8 + y: 8 + + background: Rectangle { + color: stat === 0 ? "#5cb3cc" : "#869d9d" + Behavior on color { ColorAnimation { duration: 200 } } + } + + RowLayout { + anchors.fill: parent + Item { Layout.preferredWidth: 20 } + + Label { + text: { + switch (stat) { + case 0: return luatr("Generals Overview"); + case 1: return luatr("$BanPkgHelp"); + case 2: return luatr("$BanCharaHelp"); + } + } + elide: Label.ElideLeft + verticalAlignment: Qt.AlignVCenter + font.pixelSize: 24 + } + + Item { Layout.fillWidth: true } + + TextField { + id: word + clip: true + leftPadding: 5 + rightPadding: 5 + } + + ToolButton { + text: luatr("Search") + enabled: word.text !== "" + onClicked: { + pkgList.currentIndex = 0; + vanishAnim.start(); + } + } + + ToolButton { + id: banButton + text: { + if (stat === 2) return luatr("OK"); + return luatr("BanGeneral"); + } + enabled: stat !== 1 + onClicked: { + if (stat === 0) { + stat = 2; + } else { + stat = 0; + } + } + } + + ToolButton { + id: banPkgButton + text: { + if (stat === 1) return luatr("OK"); + return luatr("BanPackage"); + } + enabled: stat !== 2 + onClicked: { + if (stat === 0) { + stat = 1; + } else { + stat = 0; + } + } + } + + ToolButton { + text: luatr("Quit") + onClicked: { + mainStack.pop(); + config.saveConf(); + } + } + } + } + GridView { id: gridView clip: true - width: root.width - listView.width - generalDetail.width - 16 - height: parent.height - 20 - y: 10 - anchors.left: listView.right + width: root.width - listBg.width - 16 + height: parent.height - bar.height - 24 + y: 16 + bar.height + anchors.left: listBg.right anchors.leftMargin: 8 + (width % 100) / 2 cellHeight: 140 cellWidth: 100 @@ -66,24 +213,77 @@ Item { autoBack: false name: modelData onClicked: { - generalText.clear(); - generalDetail.general = modelData; - generalDetail.updateGeneral(); - // generalDetail.open(); + if (stat === 2) { + const s = config.curScheme; + const gdata = lcall("GetGeneralData", modelData); + const pack = gdata.package; + let arr; + if (s.banPkg[pack]) { + arr = s.banPkg[pack]; + } else { + if (!s.normalPkg[pack]) { + s.normalPkg[pack] = []; + } + arr = s.normalPkg[pack]; + } + // TODO: 根据手动全禁/全白名单自动改为禁包 + const idx = arr.indexOf(modelData); + if (idx !== -1) { + arr.splice(idx, 1); + } else { + arr.push(modelData); + } + config.curSchemeChanged(); + } else { + generalText.clear(); + generalDetail.general = modelData; + generalDetail.updateGeneral(); + generalDetail.open(); + } } Rectangle { anchors.fill: parent color: "black" - opacity: config.disabledGenerals.includes(modelData) ? 0.7 : 0 + opacity: { + const s = config.curScheme; + const gdata = lcall("GetGeneralData", modelData); + const pack = gdata.package; + if (s.banPkg[pack]) { + if (!s.banPkg[pack].includes(modelData)) return 0.7; + } else { + if (!!s.normalPkg[pack]?.includes(modelData)) return 0.7; + } + return 0; + } Behavior on opacity { NumberAnimation {} } } GlowText { - visible: config.disabledGenerals.includes(modelData) - text: '禁' + id: banText + visible: { + const s = config.curScheme; + const gdata = lcall("GetGeneralData", modelData); + const pack = gdata.package; + if (s.banPkg[pack]) { + return s.banPkg[pack].includes(modelData); + } else { + return !!s.normalPkg[pack]?.includes(modelData); + } + } + text: { + if (!visible) return ''; + const s = config.curScheme; + const gdata = lcall("GetGeneralData", modelData); + const pack = gdata.package; + if (s.banPkg[pack]) { + if (s.banPkg[pack].includes(modelData)) return '启用'; + } else { + if (!!s.normalPkg[pack]?.includes(modelData)) return '禁'; + } + } anchors.centerIn: parent font.family: fontLi2.name color: "#E4D5A0" @@ -108,7 +308,7 @@ Item { PropertyAnimation { target: gridView property: "y" - to: 30 + to: 36 + bar.height duration: 150 easing.type: Easing.InOutQuad } @@ -117,7 +317,7 @@ Item { gridView.model = lcall("SearchAllGenerals", word.text); } else { gridView.model = lcall("SearchGenerals", - listView.model.get(listView.currentIndex).name, word.text); + pkgList.model[pkgList.currentIndex], word.text); } word.text = ""; appearAnim.start(); @@ -138,23 +338,78 @@ Item { PropertyAnimation { target: gridView property: "y" - from: 20 - to: 10 + from: 36 + bar.height + to: 16 + bar.height duration: 150 easing.type: Easing.InOutQuad } } } - Rectangle { + Component { + id: skillAudioBtn + Button { + Layout.fillWidth: true + contentItem: ColumnLayout { + Text { + Layout.fillWidth: true + text: { + if (name.endsWith("_win_audio")) { + return "胜利语音"; + } + return luatr(name) + (idx ? " (" + idx.toString() + ")" + : ""); + } + font.bold: true + font.pixelSize: 14 + } + Text { + Layout.fillWidth: true + text: { + const orig = '$' + name + (idx ? idx.toString() : ""); + const orig_trans = luatr(orig); + + // try general specific + const orig_g = '$' + name + '_' + detailGeneralCard.name + + (idx ? idx.toString() : ""); + const orig_g_trans = luatr(orig_g); + + if (orig_g_trans !== orig_g) { + return orig_g_trans; + } + + if (orig_trans !== orig) { + return orig_trans; + } + + return ""; + } + wrapMode: Text.WordWrap + } + } + + onClicked: { + callbacks["LogEvent"](JSON.stringify({ + type: "PlaySkillSound", + name: name, + general: detailGeneralCard.name, + i: idx, + })); + } + } + } + + Popup { id: generalDetail - width: 310 - height: parent.height - searcher.height - 20 - y: 10 - anchors.right: parent.right - anchors.rightMargin: 10 - color: "#88EEEEEE" - radius: 8 + width: realMainWin.width * 0.6 + height: realMainWin.height * 0.8 + anchors.centerIn: parent + background: Rectangle { + color: "#EEEEEEEE" + radius: 5 + border.color: "#A6967A" + border.width: 1 + } property string general: "caocao" @@ -196,7 +451,7 @@ Item { function findDeathAudio(general) { const extension = lcall("GetGeneralData", general).extension; const fname = AppPath + "/packages/" + extension + "/audio/death/" - + general + ".mp3"; + + general + ".mp3"; if (Backend.exists(fname)) { audioDeath.visible = true; } else { @@ -212,7 +467,7 @@ Item { if (data.companions.length > 0){ let ret = "" + luatr("Companions") - + ": "; + + ": "; data.companions.forEach(t => { ret += luatr(t) + ' ' }); @@ -236,223 +491,153 @@ Item { addSkillAudio(general + "_win_audio"); } - Flickable { - flickableDirection: Flickable.VerticalFlick - contentHeight: detailLayout.height - width: parent.width - 40 - height: parent.height - 40 - clip: true + Item { anchors.centerIn: parent - ScrollBar.vertical: ScrollBar {} + width: parent.width / mainWindow.scale + height: parent.height / mainWindow.scale + scale: mainWindow.scale - ColumnLayout { - id: detailLayout - width: parent.width - - GeneralCardItem { - id: detailGeneralCard - Layout.alignment: Qt.AlignHCenter - name: "caocao" - } - - TextEdit { - id: generalText - - Layout.fillWidth: true - readOnly: true - selectByKeyboard: true - selectByMouse: false - wrapMode: TextEdit.WordWrap - textFormat: TextEdit.RichText - font.pixelSize: 16 - } - - Repeater { - model: ListModel { - id: audioModel + Item { + id: generalInfo + width: 150 + ColumnLayout { + width: parent.width + GeneralCardItem { + id: detailGeneralCard + name: "caocao" + scale: 1.5; transformOrigin: Item.TopLeft } + + Item { Layout.preferredHeight: 130 * 0.5 } + + Text { + Layout.fillWidth: true + textFormat: TextEdit.RichText + font.pixelSize: 16 + function trans(str) { + const ret = luatr(str); + if (ret === str) { + return "官方"; + } + return ret; + } + text: { + const general = generalDetail.general; + return [ + luatr(lcall("GetGeneralData", general).package), + "称号:" + trans("#" + general), + "设计:" + trans("designer:" + general), + "配音:" + trans("cv:" + general), + "画师:" + trans("illustrator:" + general), + ].join("
"); + } + } + + Timer { + id: opTimer + interval: 4000 + } + Button { + text: luatr("Set as Avatar") + enabled: detailGeneralCard.name !== "" && !opTimer.running + && Self.avatar !== detailGeneralCard.name + onClicked: { + mainWindow.busy = true; + opTimer.start(); + ClientInstance.notifyServer( + "UpdateAvatar", + JSON.stringify([detailGeneralCard.name]) + ); + } + } + } + } + + Flickable { + flickableDirection: Flickable.VerticalFlick + contentHeight: detailLayout.height + width: parent.width - 40 - generalInfo.width + height: parent.height - 40 + clip: true + anchors.left: generalInfo.right + anchors.leftMargin: 20 + y: 20 + + ColumnLayout { + id: detailLayout + width: parent.width + + TextEdit { + id: generalText + + Layout.fillWidth: true + readOnly: true + selectByKeyboard: true + selectByMouse: false + wrapMode: TextEdit.WordWrap + textFormat: TextEdit.RichText + font.pixelSize: 18 + } + + GridLayout { + Layout.fillWidth: true + columns: 2 + Repeater { + model: ListModel { + id: audioModel + } + delegate: skillAudioBtn + } + } + + Button { + id: audioDeath Layout.fillWidth: true contentItem: ColumnLayout { Text { Layout.fillWidth: true - text: { - if (name.endsWith("_win_audio")) { - return "胜利语音"; - } - return luatr(name) + (idx ? " (" + idx.toString() + ")" - : ""); - } + text: luatr("Death audio") font.bold: true font.pixelSize: 14 } Text { Layout.fillWidth: true text: { - const orig = '$' + name + (idx ? idx.toString() : ""); - const orig_trans = luatr(orig); - - // try general specific - const orig_g = '$' + name + '_' + detailGeneralCard.name - + (idx ? idx.toString() : ""); - const orig_g_trans = luatr(orig_g); - - if (orig_g_trans !== orig_g) { - return orig_g_trans; + const orig = "~" + generalDetail.general; + const tr = luatr(orig); + if (tr === orig) { + return ""; } - - if (orig_trans !== orig) { - return orig_trans; - } - - return ""; + return tr; } wrapMode: Text.WordWrap } } onClicked: { - callbacks["LogEvent"](JSON.stringify({ - type: "PlaySkillSound", - name: name, - general: detailGeneralCard.name, - i: idx, - })); + const general = generalDetail.general + const extension = lcall("GetGeneralData", general).extension; + Backend.playSound("./packages/" + extension + "/audio/death/" + + general); } } } - - Button { - id: audioDeath - Layout.fillWidth: true - contentItem: ColumnLayout { - Text { - Layout.fillWidth: true - text: luatr("Death audio") - font.bold: true - font.pixelSize: 14 - } - Text { - Layout.fillWidth: true - text: { - const orig = "~" + generalDetail.general; - const tr = luatr(orig); - if (tr === orig) { - return ""; - } - return tr; - } - wrapMode: Text.WordWrap - } - } - - onClicked: { - const general = generalDetail.general - const extension = lcall("GetGeneralData", general).extension; - Backend.playSound("./packages/" + extension + "/audio/death/" - + general); - } - } - } - } - Rectangle { - id: searcher - width: parent.width - height: childrenRect.height - color: "snow" - opacity: 0.75 - anchors.top: parent.bottom - radius: 8 - - RowLayout { - width: parent.width - TextField { - id: word - Layout.fillWidth: true - clip: true - leftPadding: 5 - rightPadding: 5 - } - - Button { - text: luatr("Search") - enabled: word.text !== "" - onClicked: { - listView.currentIndex = 0; - vanishAnim.start(); - } - } - } - } - } - - ColumnLayout { - anchors.right: parent.right - Button { - text: luatr("Quit") - onClicked: { - mainStack.pop(); - config.saveConf(); - } - } - - Button { - id: banButton - text: luatr(config.disabledGenerals.includes(detailGeneralCard.name) ? - 'ResumeGeneral' : 'BanGeneral') - visible: detailGeneralCard.name - onClicked: { - const { disabledGenerals } = config; - const { name } = detailGeneralCard; - - if (banButton.text === luatr('ResumeGeneral')) { - const deleteIndex = disabledGenerals.findIndex( - (general) => general === name); - if (deleteIndex === -1) { - return; - } - - disabledGenerals.splice(deleteIndex, 1); - } else { - if (disabledGenerals.includes(name)) { - return; - } - - disabledGenerals.push(name); - } - config.disabledGeneralsChanged(); - } - } - - Timer { - id: opTimer - interval: 4000 - } - - Button { - text: luatr("Set as Avatar") - enabled: detailGeneralCard.name !== "" && !opTimer.running - && Self.avatar !== detailGeneralCard.name - onClicked: { - mainWindow.busy = true; - opTimer.start(); - ClientInstance.notifyServer( - "UpdateAvatar", - JSON.stringify([detailGeneralCard.name]) - ); } } } function loadPackages() { if (loaded) return; + const _mods = lcall("GetAllModNames") + const modData = lcall("GetAllMods") const packs = lcall("GetAllGeneralPack"); - packs.forEach(name => { - if (!config.serverHiddenPacks.includes(name)) { - packages.append({ name: name }); - } + _mods.forEach(name => { + const pkgs = modData[name].filter(p => packs.includes(p) + && !config.serverHiddenPacks.includes(p)); + if (pkgs.length > 0) + mods.append({ name: name, pkgs: JSON.stringify(pkgs) }); }); - generalDetail.updateGeneral(); loaded = true; } } diff --git a/Fk/Pages/Lobby.qml b/Fk/Pages/Lobby.qml index 6971e25a..8da9162c 100644 --- a/Fk/Pages/Lobby.qml +++ b/Fk/Pages/Lobby.qml @@ -64,11 +64,21 @@ Item { Text { horizontalAlignment: Text.AlignLeft Layout.fillWidth: true - text: (hasPassword ? luatr("Has Password") : "") + roomName + text: roomName font.pixelSize: 20 elide: Label.ElideRight } + Item { + Layout.preferredWidth: 16 + Image { + source: AppPath + "/image/button/skill/locked.png" + visible: hasPassword + anchors.centerIn: parent + scale: 0.8 + } + } + Text { text: luatr(gameMode) } diff --git a/Fk/Pages/RoomLogic.js b/Fk/Pages/RoomLogic.js index 8d3eca11..025960fe 100644 --- a/Fk/Pages/RoomLogic.js +++ b/Fk/Pages/RoomLogic.js @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -.import Fk.Util as Util - const Card = { Unknown : 0, PlayerHand : 1, @@ -479,6 +477,22 @@ function doIndicate(from, tos) { line.running = true; } +function processPrompt(prompt) { + const data = prompt.split(":"); + let raw = luatr(data[0]); + const src = parseInt(data[1]); + const dest = parseInt(data[2]); + if (raw.match("%src")) + raw = raw.replace(/%src/g, luatr(getPhoto(src).general)); + if (raw.match("%dest")) + raw = raw.replace(/%dest/g, luatr(getPhoto(dest).general)); + if (raw.match("%arg2")) + raw = raw.replace(/%arg2/g, luatr(data[4])); + if (raw.match("%arg")) + raw = raw.replace(/%arg/g, luatr(data[3])); + return raw; +} + callbacks["MaxCard"] = (jsonData) => { const data = JSON.parse(jsonData); const id = data.id; @@ -936,7 +950,7 @@ callbacks["AskForSkillInvoke"] = (jsonData) => { const data = JSON.parse(jsonData); const skill = data[0]; const prompt = data[1]; - roomScene.promptText = prompt ? Util.processPrompt(prompt) + roomScene.promptText = prompt ? processPrompt(prompt) : luatr("#AskForSkillInvoke").arg(luatr(skill)); roomScene.state = "replying"; roomScene.okCancel.visible = true; @@ -1025,7 +1039,7 @@ callbacks["AskForChoice"] = (jsonData) => { roomScene.promptText = luatr("#AskForChoice") .arg(luatr(skill_name)); } else { - roomScene.setPrompt(Util.processPrompt(prompt), true); + roomScene.setPrompt(processPrompt(prompt), true); } roomScene.state = "replying"; let qmlSrc; @@ -1060,7 +1074,7 @@ callbacks["AskForChoices"] = (jsonData) => { roomScene.promptText = luatr("#AskForChoices") .arg(luatr(skill_name)); } else { - roomScene.setPrompt(Util.processPrompt(prompt), true); + roomScene.setPrompt(processPrompt(prompt), true); } roomScene.state = "replying"; let qmlSrc; @@ -1096,7 +1110,7 @@ callbacks["AskForCardChosen"] = (jsonData) => { roomScene.promptText = luatr("#AskForChooseCard") .arg(luatr(reason)); } else { - roomScene.setPrompt(Util.processPrompt(prompt), true); + roomScene.setPrompt(processPrompt(prompt), true); } roomScene.state = "replying"; roomScene.popupBox.sourceComponent = @@ -1128,7 +1142,7 @@ callbacks["AskForCardsChosen"] = (jsonData) => { roomScene.promptText = luatr("#AskForChooseCards") .arg(luatr(reason)).arg(min).arg(max); } else { - roomScene.setPrompt(Util.processPrompt(prompt), true); + roomScene.setPrompt(processPrompt(prompt), true); } roomScene.state = "replying"; @@ -1268,7 +1282,7 @@ callbacks["AskForUseActiveSkill"] = (jsonData) => { roomScene.promptText = luatr("#AskForUseActiveSkill") .arg(luatr(skill_name)); } else { - roomScene.setPrompt(Util.processPrompt(prompt), true); + roomScene.setPrompt(processPrompt(prompt), true); } roomScene.respond_play = false; @@ -1315,7 +1329,7 @@ callbacks["AskForUseCard"] = (jsonData) => { roomScene.promptText = luatr("#AskForUseCard") .arg(luatr(cardname)); } else { - roomScene.setPrompt(Util.processPrompt(prompt), true); + roomScene.setPrompt(processPrompt(prompt), true); } roomScene.responding_card = pattern; roomScene.respond_play = false; @@ -1337,7 +1351,7 @@ callbacks["AskForResponseCard"] = (jsonData) => { roomScene.promptText = luatr("#AskForResponseCard") .arg(luatr(cardname)); } else { - roomScene.setPrompt(Util.processPrompt(prompt), true); + roomScene.setPrompt(processPrompt(prompt), true); } roomScene.responding_card = pattern; roomScene.respond_play = true; diff --git a/image/button/skill/locked.png b/image/button/skill/locked.png new file mode 100644 index 0000000000000000000000000000000000000000..ce89fb8ba3edfccf10cdb76d8e3c8b5c33a8f771 GIT binary patch literal 2239 zcmV;w2tfCVP)760jDSJGsZxs<+>7_t(|PQ~QB3~^$JaJg;%lzmU7 zypxg#=3q`HA__?}%iF6`nUd14tdbm#=ueiMtlBd;jmmL?^P*#w3;?d{rcD-=4?3OB?#|B6-&y}O-U#8X0f@GE zKH}C;7J*r&1z$#B&2#`~0iaT;Q~==R%a_03*x2}qI&hq1;pFpqzh1A`n>=~)iYiBfAzQ?xg0zMr*HY9hMoCBBGzlsIJbU)+!TS38Pai&f@CyosLLx&83kv{% zZnulY#l`IA=H_nzU~6mZkD>}mYQUPQ2&*2^JK>o)aOr@hxmC-zTCGN_)oS#5J*cYc z2h%iR20*vlrC@fuU6T*g@Am-!?RI-ZQItghi_$nc0)v#~ZiNc7F%^k1ZoYL^XHD+( z)vH%;pFe;8GygUi3`!zt0>GU+cdD&c>vz|#T>}8Teft&wpzHe5U@+*hrnGiP>>C*c z(raHzQ7T8fGD)N$;-ct$LDX9WfR&XMOHmYMI2=OLG`xB9<{u9qKK!$7+hfMG1<6x* z|Ni|yzkU0rZf_P1EG% zzS$cL2C*|N!1teD#F%7}N!6lUBcFKL?^0Rd4C+!G3)3{M)z#Ir#bOZvKyk0v0|4vb z;9#cBXf%Rh_`J$v{lco|5i^;xH2Cp4CqfC{j42|N02~9j0N_KlT2-sns@?DRmEmxR z8#iuTv2FWAQ55~+#fwz{SX)~|xm;HE_xItt?jZp6;NZYKckY~;%jGZ_3{a_5aOKLC zY9^BzRVo!6A0OKY)~^bn0?(in;7N-gG4hm`RZc$Ra9!0QNv7FsHtO|yqtoex_MOL% zAGf%=H5!do*LBALaOu*eLjbsY_wKoNyS*VK=A+eWHMY06cNIl}ZQBr&NefgL3=k7D zQX;+No&hc5f{4oimf?8@daYK=x7+RZ{rmSX16Xuj?^HlWLDMwox(@mt2dXcK_B{tp z)A04{*W+5PR($m6(I0kpc6LRR6L?+(dF9649l>>7Wqo}etE;P* z0sIxSp37L!JrN-XV8$a>F}rp`Fbu=ibv^Ay$H(sOF822JVB0ntjRw}%*5+-B&!0a> zeWtY|$9`cFVwp=@BY@|4?(OXX0LtYuUc7h#(=<`9*ZC$oFLWe$2n4={PIF-b$8iz^ zFgwHbdL8@w`v3q{Ra4u?AZmjBZ)uk#bm}BOuIM-p#^W)v*<`P2JRU<)6ny#e1prX1 z)zItpP_0&R=FFMYJ{-sKEuX*?;mb?fCqp=uR5;{CEu&N_`4Z`LIskyBr6t_Db!)En z5;Jq-yBSJ@X?jPVX0r*?H1X-vC)~b$`&33jc6jGOnzv2U$gh|FSFofw5=jzrSg-(? z)9JJ@9*^f)xHBq~%jJ;CWH1~K0eJgU62{{(&YwSz;c)06uyDr+_8p6*ePZ~i{Pxm< z=lXE;5aS)BpNdeP{zbkwGmM_^$TAblU=MJ|_vVHmJ1 z3#zKlwU5Oh@{A>Tn8c}^15ZNyi9@k0s}EqH>v}cKN<~4_G-#UVj-@eFDwX6<2Etdw zkp#qf+vLBg@Xqr74e8CBH-FV?wOZG&UvJEI7eX=VJ%7|h#FVu+3r{7ygza0md3qWn6A;7UsQaZ;hTd(Y#|-$^*gPqaplm z!|TvPl}t?Pdydo>Z4n$JDduC6>Gr|zw)uMypJ`ePB}6}PsjQr1W>rft6Y_jwh|wb{ z&jTUR$^qfG8S0Fe^Vc{2oT4ISjUaF=sZUqRM@fv27l|}af!86?o*?`_!|%r^Ezf=w zqMj%T7Qzg2#^l#>!UTx^+k-#Xb3*02JNcD6?ruB|X$;9%RXpa*P&$?&f_&B>PeGOH zQhtK(_ud`WpZtFU{}#nasBYAQ7j+!>?@ruX(Y*KMagg6j{}*Q3CcWUrflCDV z@n N002ovPDHLkV1jV8OpE{k literal 0 HcmV?d00001 diff --git a/lua/client/client_util.lua b/lua/client/client_util.lua index 2baa02b6..bf6827e0 100644 --- a/lua/client/client_util.lua +++ b/lua/client/client_util.lua @@ -131,6 +131,10 @@ function GetAllMods() return json.encode(Fk.extensions) end +function GetAllModNames() + return json.encode(Fk.extension_names) +end + function GetAllGeneralPack() local ret = {} for _, name in ipairs(Fk.package_names) do @@ -142,6 +146,7 @@ function GetAllGeneralPack() end function GetGenerals(pack_name) + if not Fk.packages[pack_name] then return "{}" end local ret = {} for _, g in ipairs(Fk.packages[pack_name].generals) do if not g.total_hidden then diff --git a/lua/client/i18n/zh_CN.lua b/lua/client/i18n/zh_CN.lua index 9ae9ca97..e6b485f2 100644 --- a/lua/client/i18n/zh_CN.lua +++ b/lua/client/i18n/zh_CN.lua @@ -79,12 +79,16 @@ Fk:loadTranslationTable{ ["Clear"] = "清空", ["Help_Ban_List"] = "导出键会将这个方案的内容复制到剪贴板中;" .. "导入键会自动读取剪贴板,若可以导入则导入,不能导入则报错。", + ["Ban_Generals"] = "已禁用武将", + ["Ban_Packages"] = "禁用拓展包", + ["Whitelist_Generals"] = "白名单武将", ["Export"] = "导出", ["Export Success"] = "禁将方案已经复制到剪贴板。", ["Import"] = "导入", ["Not Legal"] = "导入失败:不是合法的JSON字符串。", ["Not JSON"] = "导入失败:数据格式不对。", ["Import Success"] = "从剪贴板导入禁将方案成功。", + ["Rename"] = "重命名", ["$OnlineInfo"] = "大厅人数:%1,总在线人数:%2", @@ -184,6 +188,9 @@ FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下 -- ["Quit"] = "退出", ["BanGeneral"] = "禁将", ["ResumeGeneral"] = "解禁", + ["BanPackage"] = "禁拓展包", + ["$BanPkgHelp"] = "正在禁用拓展包", + ["$BanCharaHelp"] = "正在禁用武将", ["Companions"] = "珠联璧合", ["Death audio"] = "阵亡", diff --git a/lua/core/engine.lua b/lua/core/engine.lua index 9b21d705..596af613 100644 --- a/lua/core/engine.lua +++ b/lua/core/engine.lua @@ -8,6 +8,7 @@ --- ---@class Engine : Object ---@field public extensions table @ 所有mod列表及其包含的拓展包 +---@field public extension_names string[] @ Mod名字的数组,为了方便排序 ---@field public packages table @ 所有拓展包的列表 ---@field public package_names string[] @ 含所有拓展包名字的数组,为了方便排序 ---@field public skills table @ 所有的技能 @@ -50,6 +51,7 @@ function Engine:initialize() ["standard_cards"] = { "standard_cards" }, ["maneuvering"] = { "maneuvering" }, } + self.extension_names = { "standard", "standard_cards", "maneuvering" } self.packages = {} -- name --> Package self.package_names = {} self.skills = {} -- name --> Skill @@ -147,6 +149,7 @@ function Engine:loadPackages() -- Note that instance of Package is a table too -- so dont use type(pack) == "table" here if type(pack) == "table" then + table.insert(self.extension_names, dir) if pack[1] ~= nil then self.extensions[dir] = {} for _, p in ipairs(pack) do