From 4235bf62375d5c624f1412eda859248f1080b12b Mon Sep 17 00:00:00 2001 From: Nyutanislavsky Date: Mon, 10 Jun 2024 14:58:48 +0800 Subject: [PATCH] enhance processPrompt (#355) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 改进processPrompt,支持双将和暗将 2. 副将长名旋转 3. 国战体力上限优化,包括一览和选将框 4. 空格添加结束出牌阶段,Escape键呼出菜单 5. 武将一览左栏文本换行 6. 同名替换影响已选择的武将 7. 再次排序手牌时按照点数排序 8. Logic.js翻译 9. 进入房间翻译删去句号,跟房间内其他toast风格统一 10. 常见疑问最后一张“下一条”改为“OK!” 11. 录像回放“从文件打开”翻译 12. interaction自动弹出和关闭,comboBox补技能名 13. 卡牌音效添加装备效果音效和使用音效,小小重构 14. activeSkill的prompt的selected_targets实装 15. 禁用扩展包文本ui限制长度 16. 右键技能呼出气泡 Qsgs-Fans/freekill-core#3 --- Fk/Cheat/GeneralDetail.qml | 9 +++- Fk/Cheat/SameConvert.qml | 10 ++++ Fk/LobbyElement/BanGeneralSetting.qml | 6 +++ Fk/Pages/CardsOverview.qml | 69 ++++++++++++++++++--------- Fk/Pages/GeneralsOverview.qml | 3 ++ Fk/Pages/Logic.js | 6 +-- Fk/Pages/Replay.qml | 2 +- Fk/Pages/Room.qml | 19 ++++++-- Fk/Pages/RoomLogic.js | 59 ++++++++++++++++++++++- Fk/RoomElement/ChooseGeneralBox.qml | 20 +++++++- Fk/RoomElement/GeneralCardItem.qml | 10 +++- Fk/RoomElement/Photo.qml | 33 ++++++++++++- Fk/RoomElement/SkillButton.qml | 38 ++++++++++++++- Fk/SkillInteraction/SkillCombo.qml | 1 + Fk/Tutorial.qml | 12 +++-- Fk/util.js | 18 ++++++- 16 files changed, 272 insertions(+), 43 deletions(-) diff --git a/Fk/Cheat/GeneralDetail.qml b/Fk/Cheat/GeneralDetail.qml index 707f7068..5514a161 100644 --- a/Fk/Cheat/GeneralDetail.qml +++ b/Fk/Cheat/GeneralDetail.qml @@ -40,8 +40,13 @@ Flickable { extra_data.generals.forEach((g) => { const data = lcall("GetGeneralDetail", g); - skillDesc.append(luatr(data.kingdom) + " " + luatr(g) + " " + data.hp + - "/" + data.maxHp); + skillDesc.append(luatr(data.kingdom) + " " + luatr(g) + " " + (data.hp === data.maxHp + ? ((g.startsWith('hs__') || g.startsWith('ld__') || g.includes('heg__')) + ? ((data.mainMaxHp != 0 || data.deputyMaxHp != 0) + ? ((data.hp + data.mainMaxHp) / 2 + '/' + (data.hp + data.deputyMaxHp) / 2) + : data.hp / 2) + : data.hp) + : data.hp + "/" + data.maxHp)); if (data.companions.length > 0){ let ret = ''; ret +="" + luatr("Companions") + ": "; diff --git a/Fk/Cheat/SameConvert.qml b/Fk/Cheat/SameConvert.qml index 31ccf4ca..4fbb3fdd 100644 --- a/Fk/Cheat/SameConvert.qml +++ b/Fk/Cheat/SameConvert.qml @@ -50,6 +50,16 @@ Item { if (idx < extra_data.cards.count) { extra_data.cards.set(idx, { name: modelData }); } + + idx = 0; + extra_data.choices.forEach( s => { + if (s === gname) { + extra_data.choices[idx] = modelData; + return; + } + idx++; + }); + root.finish(); } } diff --git a/Fk/LobbyElement/BanGeneralSetting.qml b/Fk/LobbyElement/BanGeneralSetting.qml index 59ef8439..935292a6 100644 --- a/Fk/LobbyElement/BanGeneralSetting.qml +++ b/Fk/LobbyElement/BanGeneralSetting.qml @@ -184,6 +184,12 @@ Item { return ret; } delegate: Text { + width: parent.width / 2 + wrapMode: Text.WordWrap + fontSizeMode: Text.HorizontalFit + minimumPixelSize: 14 + elide: Text.ElideRight + height: 24 text: luatr(modelData) font.pixelSize: 16 } diff --git a/Fk/Pages/CardsOverview.qml b/Fk/Pages/CardsOverview.qml index 8a2fb3ab..8b8de045 100644 --- a/Fk/Pages/CardsOverview.qml +++ b/Fk/Pages/CardsOverview.qml @@ -289,18 +289,29 @@ Item { horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: { - if (gender === "male") { + if (audioType === "male") { return luatr("Male Audio"); - } else { + } else if (audioType === "female") { return luatr("Female Audio"); + } else if (audioType === "equip_effect") { + return luatr("Equip Effect Audio"); + } { + return luatr("Equip Use Audio"); } } font.pixelSize: 14 } onClicked: { const data = lcall("GetCardData", cardDetail.cid); - Backend.playSound("./packages/" + extension + "/audio/card/" - + gender + "/" + data.name); + if (audioType === "male" || audioType === "female") { + Backend.playSound("./packages/" + extension + "/audio/card/" + + audioType + "/" + data.name); + } else if (audioType === "equip_effect") { + Backend.playSound("./packages/" + extension + "/audio/card/" + + "/" + data.name); + } else { + Backend.playSound("./audio/card/common/" + extension); + } } } } @@ -317,27 +328,41 @@ Item { } } + function loadAudio(cardName, type, extension, orig_extension) { + const prefix = AppPath + "/packages/"; + const suffix = cardName + ".mp3"; + let midfix = type + "/"; + if (type === "equip_effect") { + midfix = ""; + } + let fname = prefix + extension + "/audio/card/" + midfix + suffix; + if (Backend.exists(fname)) { + audioRow.append( { audioType: type, extension: extension } ); + } else { + fname = prefix + orig_extension + "/audio/card/" + midfix + suffix; + if (Backend.exists(fname)) { + audioRow.append( { audioType: type, extension: orig_extension} ); + } + } + } + function addCardAudio(card) { const extension = card.extension; const orig_extension = lcall("GetCardExtensionByName", card.name); - const prefix = AppPath + "/packages/"; - const suffix = card.name + ".mp3"; - let fname = prefix + extension + "/audio/card/male/" + suffix; - if (Backend.exists(fname)) { - audioRow.append( { gender: "male", extension: extension } ); - } else { - fname = prefix + orig_extension + "/audio/card/male/" + suffix; - if (Backend.exists(fname)) { - audioRow.append( {gender: "male", extension: orig_extension} ); - } - } - fname = prefix + extension + "/audio/card/female/" + suffix; - if (Backend.exists(fname)) { - audioRow.append( { gender: "female", extension: extension } ); - }else { - fname = prefix + orig_extension + "/audio/card/female/" + suffix; - if (Backend.exists(fname)) { - audioRow.append( { gender: "female", extension: orig_extension } ); + loadAudio(card.name, "male", extension, orig_extension); + loadAudio(card.name, "female", extension, orig_extension); + if (audioRow.count === 0 && card.type === 3) { + loadAudio(card.name, "equip_effect", extension, orig_extension); + if (audioRow.count === 0) { + let subType = ""; + if (card.subtype === "defensive_horse" || card.subtype === "offensive_horse") { + subType = "horse"; + } else if (card.subtype === "weapon") { + subType = "weapon"; + } else { + subType = "armor"; + } + audioRow.append( { audioType: "equip_use", extension: subType } ); } } } diff --git a/Fk/Pages/GeneralsOverview.qml b/Fk/Pages/GeneralsOverview.qml index 5f512f8f..88a190a4 100644 --- a/Fk/Pages/GeneralsOverview.qml +++ b/Fk/Pages/GeneralsOverview.qml @@ -503,6 +503,8 @@ Item { Item { id: generalInfo + x: 5 + y: 10 width: 150 ColumnLayout { width: parent.width @@ -516,6 +518,7 @@ Item { Text { Layout.fillWidth: true + wrapMode: Text.WordWrap textFormat: TextEdit.RichText font.pixelSize: 16 function trans(str) { diff --git a/Fk/Pages/Logic.js b/Fk/Pages/Logic.js index da8288f7..e9d1e987 100644 --- a/Fk/Pages/Logic.js +++ b/Fk/Pages/Logic.js @@ -3,13 +3,13 @@ callbacks["UpdateAvatar"] = (jsonData) => { mainWindow.busy = false; Self.avatar = jsonData; - toast.show("Update avatar done."); + toast.show(luatr("Update avatar done.")); } callbacks["UpdatePassword"] = (jsonData) => { mainWindow.busy = false; if (jsonData === "1") - toast.show("Update password done."); + toast.show(luatr("Update password done.")); else - toast.show("Old password wrong!", 5000); + toast.show(luatr("Old password wrong!"), 5000); } diff --git a/Fk/Pages/Replay.qml b/Fk/Pages/Replay.qml index daa26b89..1a15ef7b 100644 --- a/Fk/Pages/Replay.qml +++ b/Fk/Pages/Replay.qml @@ -32,7 +32,7 @@ Item { id: menu y: bar.height MenuItem { - text: qsTr("Replay from file") + text: luatr("Replay from File") onTriggered: { fdialog.open(); } diff --git a/Fk/Pages/Room.qml b/Fk/Pages/Room.qml index 4c1de231..9928829a 100644 --- a/Fk/Pages/Room.qml +++ b/Fk/Pages/Room.qml @@ -810,7 +810,7 @@ Item { skillInteraction.item.choices = data.choices; skillInteraction.item.detailed = data.detailed; skillInteraction.item.all_choices = data.all_choices; - // skillInteraction.item.clicked(); + skillInteraction.item.clicked(); break; case "spin": skillInteraction.sourceComponent = @@ -818,12 +818,14 @@ Item { skillInteraction.item.skill = skill_name; skillInteraction.item.from = data.from; skillInteraction.item.to = data.to; + skillInteraction.item.clicked(); break; case "custom": skillInteraction.sourceComponent = Qt.createComponent(AppPath + "/" + data.qml_path + ".qml"); skillInteraction.item.skill = skill_name; skillInteraction.item.extra_data = data; + skillInteraction.item.clicked(); break; default: skillInteraction.sourceComponent = undefined; @@ -837,6 +839,8 @@ Item { cancelButton.enabled = true; } else { skillInteraction.sourceComponent = undefined; + if (roomScene.popupBox.item) + roomScene.popupBox.item.close(); Logic.doCancelButton(); } } @@ -1060,8 +1064,17 @@ Item { Shortcut { sequence: "Space" - enabled: cancelButton.enabled - onActivated: Logic.doCancelButton(); + enabled: cancelButton.enabled || endPhaseButton.visible; + onActivated: if (cancelButton.enabled) { + Logic.doCancelButton(); + } else { + Logic.replyToServer(""); + } + } + + Shortcut { + sequence: "Escape" + onActivated: menuContainer.open(); } function getCurrentCardUseMethod() { diff --git a/Fk/Pages/RoomLogic.js b/Fk/Pages/RoomLogic.js index e7cf92aa..e4fff394 100644 --- a/Fk/Pages/RoomLogic.js +++ b/Fk/Pages/RoomLogic.js @@ -314,6 +314,10 @@ function resortHandcards() { ["treasure"]: Card.SubtypeTreasure, } + const hand = dashboard.handcardArea.cards.map(c => { + return c.cid; + }) + dashboard.handcardArea.cards.sort((prev, next) => { if (prev.footnote === next.footnote) { if (prev.type === next.type) { @@ -341,6 +345,34 @@ function resortHandcards() { } }); + let i = 0; + let resort = true; + dashboard.handcardArea.cards.forEach(c => { + if (hand[i] !== c.cid) { + resort = false; + return; + } + i++; + }) + + if (resort) { + dashboard.handcardArea.cards.sort((prev, next) => { + if (prev.footnote === next.footnote) { + if (prev.number === next.number) { // 按点数排 + if (prev.suit === next.suit) { + return prev.cid - next.cid; + } else { + return prev.suit - next.suit; + } + } else { + return prev.number - next.number; + } + } else { + return prev.footnote > next.footnote ? 1 : -1; + } + }); + } + dashboard.handcardArea.updateCardPosition(true); } @@ -488,15 +520,29 @@ function doIndicate(from, tos) { line.running = true; } +function getPlayerStr(playerid) { + const photo = getPhoto(playerid); + if (photo.general === "anjiang" && (photo.deputyGeneral === "anjiang" || !p.deputyGeneral)) { + return luatr("seat#" + photo.seatNumber); + } + + let ret = photo.general; + ret = luatr(ret); + if (photo.deputyGeneral && photo.deputyGeneral !== "") { + ret = ret + "/" + luatr(photo.deputyGeneral); + } + return ret; +} + 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)); + raw = raw.replace(/%src/g, getPlayerStr(src)); if (raw.match("%dest")) - raw = raw.replace(/%dest/g, luatr(getPhoto(dest).general)); + raw = raw.replace(/%dest/g, getPlayerStr(dest)); if (raw.match("%arg2")) raw = raw.replace(/%arg2/g, luatr(data[4])); if (raw.match("%arg")) @@ -672,6 +718,15 @@ function updateSelectedTargets(playerid, selected) { } if (candidate) { + roomScene.resetPrompt(); // update prompt due to selected_targets + const prompt = lcall("ActiveSkillPrompt", + dashboard.pending_skill !== "" ? dashboard.pending_skill: lcall("GetCardSkill", card), + dashboard.pending_skill !== "" ? dashboard.pendings : [card], + selected_targets); + if (prompt !== "") { + roomScene.setPrompt(Util.processPrompt(prompt)); + } + all_photos.forEach(photo => { if (photo.selected) return; const id = photo.playerid; diff --git a/Fk/RoomElement/ChooseGeneralBox.qml b/Fk/RoomElement/ChooseGeneralBox.qml index 1278a28c..e1734728 100644 --- a/Fk/RoomElement/ChooseGeneralBox.qml +++ b/Fk/RoomElement/ChooseGeneralBox.qml @@ -112,7 +112,7 @@ GraphicsBox { visible: !convertDisabled text: luatr("Same General Convert") onClicked: { - roomScene.startCheat("SameConvert", { cards: generalList }); + roomScene.startCheat("SameConvert", { cards: generalList, choices: choices }); } } @@ -263,6 +263,7 @@ GraphicsBox { item.selectable = hegemony ? isHegPair(selectedItem[0], item) : true; if (hegemony) { + item.inPosition = 0; if (selectedItem[0]) { if (selectedItem[1]) { if (selectedItem[0] === item) { @@ -299,6 +300,23 @@ GraphicsBox { } } + if (hegemony) { + if (selectedItem[0]) { + if (selectedItem[0].mainMaxHp < 0) { + selectedItem[0].inPosition = 1; + } else if (selectedItem[0].deputyMaxHp < 0) { + selectedItem[0].inPosition = -1; + } + if (selectedItem[1]) { + if (selectedItem[1].mainMaxHp < 0) { + selectedItem[1].inPosition = -1; + } else if (selectedItem[1].deputyMaxHp < 0) { + selectedItem[1].inPosition = 1; + } + } + } + } + for (let i = 0; i < generalList.count; i++) { if (lcall("GetSameGenerals", generalList.get(i).name).length > 0) { convertBtn.enabled = true; diff --git a/Fk/RoomElement/GeneralCardItem.qml b/Fk/RoomElement/GeneralCardItem.qml index f7a39de5..9a82ff46 100644 --- a/Fk/RoomElement/GeneralCardItem.qml +++ b/Fk/RoomElement/GeneralCardItem.qml @@ -22,6 +22,9 @@ CardItem { property int hp property int maxHp property int shieldNum + property int mainMaxHp + property int deputyMaxHp + property int inPosition: 0 property string pkgName: "" property bool detailed: true property alias hasCompanions: companions.visible @@ -119,12 +122,15 @@ CardItem { width: childrenRect.width height: childrenRect.height Image { + opacity: ((mainMaxHp < 0 || deputyMaxHp < 0) && (index * 2 + 1 === hp) && inPosition !== -1) + ? (inPosition === 0 ? 0.5 : 0) :1 height: 12; fillMode: Image.PreserveAspectFit source: SkinBank.getGeneralCardDir(kingdom) + kingdom + "-magatama-l" } Image { x: 4.4 - opacity: (index + 1) * 2 <= hp ? 1 : 0 + opacity: (index + 1) * 2 <= hp ? (((mainMaxHp < 0 || deputyMaxHp < 0) && inPosition !== -1 && ((index + 1) * 2 === hp)) + ? (inPosition === 0 ? 0.5 : 0) : 1) : 0 height: 12; fillMode: Image.PreserveAspectFit source: { const k = subkingdom ? subkingdom : kingdom; @@ -227,6 +233,8 @@ CardItem { hp = data.hp; maxHp = data.maxHp; shieldNum = data.shield; + mainMaxHp = data.mainMaxHpAdjustedValue; + deputyMaxHp = data.deputyMaxHpAdjustedValue; const splited = name.split("__"); if (splited.length > 1) { diff --git a/Fk/RoomElement/Photo.qml b/Fk/RoomElement/Photo.qml index 40bc5c58..9d7ebee4 100644 --- a/Fk/RoomElement/Photo.qml +++ b/Fk/RoomElement/Photo.qml @@ -234,7 +234,26 @@ Item { color: "white" width: 24 wrapMode: Text.WrapAnywhere - text: luatr(deputyGeneral) + text: "" + style: Text.Outline + } + + Text { + id: longDeputyGeneralName + anchors.left: generalImage.right + anchors.leftMargin: -14 + y: 23 + font.family: fontLibian.name + font.pixelSize: 22 + rotation: 90 + transformOrigin: Item.BottomLeft + opacity: 0.9 + horizontalAlignment: Text.AlignHCenter + lineHeight: 18 + lineHeightMode: Text.FixedHeight + color: "white" + width: 24 + text: "" style: Text.Outline } } @@ -740,6 +759,18 @@ Item { } } + onDeputyGeneralChanged: { + if (!roomScene.isStarted) return; + const text = luatr(deputyGeneral); + if (text.length > 6) { + deputyGeneralName.text = ""; + longDeputyGeneralName.text = text; + } else { + deputyGeneralName.text = text; + longDeputyGeneralName.text = ""; + } + } + function chat(msg) { chat.text = msg; chat.visible = true; diff --git a/Fk/RoomElement/SkillButton.qml b/Fk/RoomElement/SkillButton.qml index d7c9c7f7..09316bfe 100644 --- a/Fk/RoomElement/SkillButton.qml +++ b/Fk/RoomElement/SkillButton.qml @@ -2,6 +2,7 @@ import QtQuick import Qt5Compat.GraphicalEffects +import QtQuick.Controls Item { id: root @@ -86,7 +87,40 @@ Item { } TapHandler { - enabled: root.type !== "notactive" && root.enabled - onTapped: parent.pressed = !parent.pressed; + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.NoButton + onTapped: (p, btn) => { + if ((btn === Qt.LeftButton || btn === Qt.NoButton) && root.type !== "notactive" && root.enabled) { + parent.pressed = !parent.pressed; + } else if (btn === Qt.RightButton) { + skillDetail.open(); + } + } + } + + Popup { + id: skillDetail + x: Math.round((parent.width - width) / 2) + y: Math.round((parent.height - height) / 2) + property string text: "" + width: Math.min(contentWidth, realMainWin.width * 0.4) + height: Math.min(contentHeight + 24, realMainWin.height * 0.9) + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + padding: 12 + background: Rectangle { + color: "#EEEEEEEE" + radius: 5 + border.color: "#A6967A" + border.width: 1 + } + contentItem: Text { + text: "" + luatr(orig) + ": " + luatr(":" + orig) + font.pixelSize: 20 + wrapMode: Text.WordWrap + textFormat: TextEdit.RichText + + TapHandler { + onTapped: skillDetail.close(); + } + } } } diff --git a/Fk/SkillInteraction/SkillCombo.qml b/Fk/SkillInteraction/SkillCombo.qml index ccf15719..23b8d441 100644 --- a/Fk/SkillInteraction/SkillCombo.qml +++ b/Fk/SkillInteraction/SkillCombo.qml @@ -32,6 +32,7 @@ MetroButton { const box = roomScene.popupBox.item; box.options = choices; box.all_options = all_choices; + box.skill_name = skill; box.accepted.connect(() => { answer = all_choices[box.result]; }); diff --git a/Fk/Tutorial.qml b/Fk/Tutorial.qml index fa017706..58576507 100644 --- a/Fk/Tutorial.qml +++ b/Fk/Tutorial.qml @@ -64,9 +64,15 @@ Rectangle { } Button { - text: qsTr("Next") - enabled: view.currentIndex + 1 < total - onClicked: view.currentIndex++ + text: view.currentIndex + 1 == total ? qsTr("OK!") : qsTr("Next") + enabled: view.currentIndex + 1 <= total + onClicked: { + if (view.currentIndex + 1 == total) { + mainStack.pop(); + } else { + view.currentIndex++ + } + } } } } diff --git a/Fk/util.js b/Fk/util.js index e7f53fa1..40273a7d 100644 --- a/Fk/util.js +++ b/Fk/util.js @@ -12,15 +12,29 @@ function convertNumber(number) { return ""; } +function getPlayerStr(playerid) { + const photo = getPhoto(playerid); + if (photo.general === "anjiang" && (photo.deputyGeneral === "anjiang" || !p.deputyGeneral)) { + return luatr("seat#" + photo.seatNumber); + } + + let ret = photo.general; + ret = luatr(ret); + if (photo.deputyGeneral && photo.deputyGeneral !== "") { + ret = ret + "/" + luatr(photo.deputyGeneral); + } + return ret; +} + 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)); + raw = raw.replace(/%src/g, getPlayerStr(src)); if (raw.match("%dest")) - raw = raw.replace(/%dest/g, luatr(getPhoto(dest).general)); + raw = raw.replace(/%dest/g, getPlayerStr(dest)); if (raw.match("%arg2")) raw = raw.replace(/%arg2/g, luatr(data[4])); if (raw.match("%arg"))