From 9a9fc9c105075b4035d6d068e60d41fb80234492 Mon Sep 17 00:00:00 2001 From: notify Date: Wed, 6 Dec 2023 21:07:35 +0800 Subject: [PATCH] UI (#290) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 杀光侧栏 只留战报一个 Qml标记,以及一个割圆demo 自由选将增加搜索功能 room:setBanner,相当于公共标记了,客户端可以Fk:currentRoom():getBanner拿(当然服务端也可) 改掉两个很蠢的命名 --- Fk/Cheat/CardDetail.qml | 43 ++++++--- Fk/Cheat/FreeAssign.qml | 29 +++++- Fk/Cheat/PlayerDetail.qml | 68 +++++++++----- Fk/Cheat/SameConvert.qml | 2 +- Fk/LobbyElement/BanGeneralSetting.qml | 18 ++-- Fk/LobbyElement/CreateRoom.qml | 1 + Fk/LobbyElement/EditProfile.qml | 1 + Fk/LobbyElement/RoomGeneralSettings.qml | 119 +++++++++++------------- Fk/LobbyElement/RoomPackageSettings.qml | 4 +- Fk/Pages/Lobby.qml | 24 +++-- Fk/Pages/MetroButton.qml | 3 + Fk/Pages/Room.qml | 85 ++++++++++------- Fk/Pages/RoomLogic.js | 20 +++- Fk/PhotoElement/MarkArea.qml | 26 +++++- Fk/RoomElement/BigGlowText.qml | 39 ++++++++ Fk/RoomElement/ChooseHandcard.qml | 63 ++++++------- Fk/RoomElement/GeneralCardItem.qml | 2 +- Fk/RoomElement/ViewGeneralPile.qml | 89 ++++-------------- Fk/RoomElement/ViewPile.qml | 113 ++++++---------------- Fk/RoomElement/qmldir | 1 + lang/zh_CN.ts | 4 + lua/client/client.lua | 23 +++++ lua/client/client_util.lua | 10 ++ lua/client/i18n/en_US.lua | 4 +- lua/client/i18n/zh_CN.lua | 4 +- lua/core/engine.lua | 13 +++ lua/fk_ex.lua | 5 + lua/server/request.lua | 5 + lua/server/room.lua | 22 ++++- lua/server/serverplayer.lua | 5 + packages/test/init.lua | 25 +++++ packages/test/qml/TestDialog.qml | 75 +++++++++------ src/network/router.cpp | 8 +- src/server/room.cpp | 19 ++++ src/server/room.h | 3 + src/server/server.cpp | 2 +- 36 files changed, 584 insertions(+), 393 deletions(-) create mode 100644 Fk/RoomElement/BigGlowText.qml diff --git a/Fk/Cheat/CardDetail.qml b/Fk/Cheat/CardDetail.qml index 7f5c33d4..cd069808 100644 --- a/Fk/Cheat/CardDetail.qml +++ b/Fk/Cheat/CardDetail.qml @@ -3,6 +3,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts +import Fk.RoomElement Flickable { id: root @@ -14,35 +15,47 @@ Flickable { contentHeight: details.height ScrollBar.vertical: ScrollBar {} - ColumnLayout { + RowLayout { id: details width: parent.width - 40 x: 20 + spacing: 20 - // TODO: player details - Text { - id: screenName - Layout.fillWidth: true - font.pixelSize: 18 + CardItem { + id: cardPic + Layout.alignment: Qt.AlignTop + Layout.topMargin: 10 + cid: 0 } - TextEdit { - id: skillDesc + ColumnLayout { + Text { + id: screenName + Layout.fillWidth: true + font.pixelSize: 18 + color: "#E4D5A0" + } - Layout.fillWidth: true - font.pixelSize: 18 + TextEdit { + id: skillDesc - readOnly: true - selectByKeyboard: true - selectByMouse: false - wrapMode: TextEdit.WordWrap - textFormat: TextEdit.RichText + Layout.fillWidth: true + font.pixelSize: 18 + color: "#E4D5A0" + + readOnly: true + selectByKeyboard: true + selectByMouse: false + wrapMode: TextEdit.WordWrap + textFormat: TextEdit.RichText + } } } onExtra_dataChanged: { const card = extra_data.card; if (!card) return; + cardPic.setData(card.toData()); const name = card.virt_name ? card.virt_name : card.name; screenName.text = Backend.translate(name); skillDesc.text = Backend.translate(":" + name); diff --git a/Fk/Cheat/FreeAssign.qml b/Fk/Cheat/FreeAssign.qml index 12fd18e3..6a610f42 100644 --- a/Fk/Cheat/FreeAssign.qml +++ b/Fk/Cheat/FreeAssign.qml @@ -24,6 +24,7 @@ Item { text: Backend.translate("Back") onClicked: stack.pop() } + Label { text: Backend.translate("Enable free assign") elide: Label.ElideRight @@ -31,8 +32,29 @@ Item { verticalAlignment: Qt.AlignVCenter Layout.fillWidth: true } + + TextField { + id: word + placeholderText: "Search..." + clip: true + verticalAlignment: Qt.AlignVCenter + background: Rectangle { + implicitHeight: 16 + implicitWidth: 120 + color: "transparent" + } + } + ToolButton { - opacity: 0 + text: Backend.translate("Search") + enabled: word.text !== "" + onClicked: { + if (stack.depth > 1) stack.pop(); + generalModel = JSON.parse(Backend.callLuaFunction("SearchAllGenerals", + [word.text])); + stack.push(generalList); + word.text = ""; + } } } } @@ -58,15 +80,16 @@ Item { ScrollBar.vertical: ScrollBar {} model: packages clip: true - cellWidth: width / 3 + cellWidth: width / 5 cellHeight: 40 delegate: ItemDelegate { - width: listView.width / 3 + width: listView.width / 5 height: 40 Text { text: Backend.translate(name) + color: "#E4D5A0" anchors.centerIn: parent } diff --git a/Fk/Cheat/PlayerDetail.qml b/Fk/Cheat/PlayerDetail.qml index b76a426c..f600fe3c 100644 --- a/Fk/Cheat/PlayerDetail.qml +++ b/Fk/Cheat/PlayerDetail.qml @@ -3,6 +3,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts +import Fk.Pages +import Fk.RoomElement Flickable { id: root @@ -24,29 +26,18 @@ Flickable { Text { id: screenName font.pixelSize: 18 + color: "#E4D5A0" } Text { id: playerGameData Layout.fillWidth: true font.pixelSize: 18 - } - - TextEdit { - id: skillDesc - - Layout.fillWidth: true - font.pixelSize: 18 - - readOnly: true - selectByKeyboard: true - selectByMouse: false - wrapMode: TextEdit.WordWrap - textFormat: TextEdit.RichText + color: "#E4D5A0" } RowLayout { - Button { + MetroButton { text: Backend.translate("Give Flower") onClicked: { enabled = false; @@ -55,7 +46,7 @@ Flickable { } } - Button { + MetroButton { text: Backend.translate("Give Egg") onClicked: { enabled = false; @@ -68,7 +59,7 @@ Flickable { } } - Button { + MetroButton { text: Backend.translate("Give Wine") enabled: Math.random() < 0.3 onClicked: { @@ -78,7 +69,7 @@ Flickable { } } - Button { + MetroButton { text: Backend.translate("Give Shoe") enabled: Math.random() < 0.3 onClicked: { @@ -87,10 +78,8 @@ Flickable { root.finish(); } } - } - RowLayout { - Button { + MetroButton { text: config.blockedUsers.indexOf(screenName.text) === -1 ? Backend.translate("Block Chatter") : Backend.translate("Unblock Chatter") enabled: pid !== Self.id && pid > 0 onClicked: { @@ -103,7 +92,7 @@ Flickable { config.blockedUsersChanged(); } } - Button { + MetroButton { text: Backend.translate("Kick From Room") visible: !roomScene.isStarted && roomScene.isOwner enabled: pid !== Self.id @@ -113,6 +102,41 @@ Flickable { } } } + + RowLayout { + spacing: 20 + ColumnLayout { + Layout.alignment: Qt.AlignTop + Layout.topMargin: 16 + + GeneralCardItem { + id: mainChara + name: "caocao" + visible: name !== "" + } + GeneralCardItem { + id: deputyChara + name: "caocao" + visible: name !== "" + } + } + + TextEdit { + id: skillDesc + + Layout.fillWidth: true + Layout.alignment: Qt.AlignTop + Layout.topMargin: 10 + font.pixelSize: 18 + color: "#E4D5A0" + + readOnly: true + selectByKeyboard: true + selectByMouse: false + wrapMode: TextEdit.WordWrap + textFormat: TextEdit.RichText + } + } } function givePresent(p) { @@ -136,6 +160,8 @@ Flickable { root.pid = id; screenName.text = extra_data.photo.screenName; + mainChara.name = extra_data.photo.general; + deputyChara.name = extra_data.photo.deputyGeneral; if (!config.observing) { const gamedata = JSON.parse(Backend.callLuaFunction("GetPlayerGameData", [id])); diff --git a/Fk/Cheat/SameConvert.qml b/Fk/Cheat/SameConvert.qml index ae0fd80a..b4be5da6 100644 --- a/Fk/Cheat/SameConvert.qml +++ b/Fk/Cheat/SameConvert.qml @@ -28,7 +28,7 @@ Item { ColumnLayout { Text { text: Backend.translate(gname) } GridLayout { - columns: 3 + columns: 6 Repeater { model: JSON.parse(Backend.callLuaFunction("GetSameGenerals", [gname])) diff --git a/Fk/LobbyElement/BanGeneralSetting.qml b/Fk/LobbyElement/BanGeneralSetting.qml index 31e5cd21..7eac2671 100644 --- a/Fk/LobbyElement/BanGeneralSetting.qml +++ b/Fk/LobbyElement/BanGeneralSetting.qml @@ -46,16 +46,7 @@ Item { config.disabledGenerals = []; } } - } - Text { - Layout.fillWidth: true - Layout.margins: 8 - wrapMode: Text.WrapAnywhere - text: Backend.translate("Help_Ban_List") - } - - RowLayout { Button { text: Backend.translate("Export") onClicked: { @@ -91,12 +82,19 @@ Item { } } + Text { + Layout.fillWidth: true + Layout.margins: 8 + wrapMode: Text.WrapAnywhere + text: Backend.translate("Help_Ban_List") + } + GridView { id: listView Layout.fillWidth: true Layout.fillHeight: true clip: true - cellWidth: width / 2 + cellWidth: width / 4 cellHeight: 24 model: config.disabledGenerals delegate: Text { diff --git a/Fk/LobbyElement/CreateRoom.qml b/Fk/LobbyElement/CreateRoom.qml index 071edff5..2449f536 100644 --- a/Fk/LobbyElement/CreateRoom.qml +++ b/Fk/LobbyElement/CreateRoom.qml @@ -16,6 +16,7 @@ Item { transformOrigin: Item.BottomLeft rotation: 90 width: root.height + background: Rectangle { color: "#EEEEEEEE" } TabButton { text: Backend.translate("General Settings") } diff --git a/Fk/LobbyElement/EditProfile.qml b/Fk/LobbyElement/EditProfile.qml index 2fb36e18..c64651e2 100644 --- a/Fk/LobbyElement/EditProfile.qml +++ b/Fk/LobbyElement/EditProfile.qml @@ -15,6 +15,7 @@ Item { transformOrigin: Item.BottomLeft rotation: 90 width: root.height + background: Rectangle { color: "#EEEEEEEE" } TabButton { text: Backend.translate("Userinfo Settings") } diff --git a/Fk/LobbyElement/RoomGeneralSettings.qml b/Fk/LobbyElement/RoomGeneralSettings.qml index 839a3376..3e418f3b 100644 --- a/Fk/LobbyElement/RoomGeneralSettings.qml +++ b/Fk/LobbyElement/RoomGeneralSettings.qml @@ -28,24 +28,6 @@ Flickable { } } - RowLayout { - anchors.rightMargin: 8 - spacing: 16 - Text { - text: Backend.translate("Player num") - } - SpinBox { - id: playerNum - from: 2 - to: 12 - value: config.preferedPlayerNum - - onValueChanged: { - config.preferedPlayerNum = value; - } - } - } - RowLayout { anchors.rightMargin: 8 spacing: 16 @@ -69,12 +51,33 @@ Flickable { } } - RowLayout { + GridLayout { anchors.rightMargin: 8 - spacing: 16 + rowSpacing: 20 + columnSpacing: 20 + columns: 4 + Text { + text: Backend.translate("Player num") + } Text { text: Backend.translate("Select generals num") } + Text { + text: Backend.translate("Operation timeout") + } + Text { + text: Backend.translate("Luck Card Times") + } + SpinBox { + id: playerNum + from: 2 + to: 12 + value: config.preferedPlayerNum + + onValueChanged: { + config.preferedPlayerNum = value; + } + } SpinBox { id: generalNum from: 3 @@ -85,6 +88,25 @@ Flickable { config.preferredGeneralNum = value; } } + SpinBox { + from: 10 + to: 60 + editable: true + value: config.preferredTimeout + + onValueChanged: { + config.preferredTimeout = value; + } + } + SpinBox { + from: 0 + to: 8 + value: config.preferredLuckTime + + onValueChanged: { + config.preferredLuckTime = value; + } + } } Text { @@ -100,41 +122,6 @@ Flickable { color: "red" } - RowLayout { - anchors.rightMargin: 8 - spacing: 16 - Text { - text: Backend.translate("Operation timeout") - } - SpinBox { - from: 10 - to: 60 - editable: true - value: config.preferredTimeout - - onValueChanged: { - config.preferredTimeout = value; - } - } - } - - RowLayout { - anchors.rightMargin: 8 - spacing: 16 - Text { - text: Backend.translate("Luck Card Times") - } - SpinBox { - from: 0 - to: 8 - value: config.preferredLuckTime - - onValueChanged: { - config.preferredLuckTime = value; - } - } - } - RowLayout { anchors.rightMargin: 8 spacing: 16 @@ -150,16 +137,20 @@ Flickable { } } - Switch { - id: freeAssignCheck - checked: Debugging ? true : false - text: Backend.translate("Enable free assign") - } + RowLayout { + anchors.rightMargin: 8 + spacing: 16 + Switch { + id: freeAssignCheck + checked: Debugging ? true : false + text: Backend.translate("Enable free assign") + } - Switch { - id: deputyCheck - checked: Debugging ? true : false - text: Backend.translate("Enable deputy general") + Switch { + id: deputyCheck + checked: Debugging ? true : false + text: Backend.translate("Enable deputy general") + } } RowLayout { diff --git a/Fk/LobbyElement/RoomPackageSettings.qml b/Fk/LobbyElement/RoomPackageSettings.qml index ec2ca43f..7b7edb13 100644 --- a/Fk/LobbyElement/RoomPackageSettings.qml +++ b/Fk/LobbyElement/RoomPackageSettings.qml @@ -52,7 +52,7 @@ Flickable { } GridLayout { - columns: 2 + columns: 4 Repeater { id: gpacks @@ -100,7 +100,7 @@ Flickable { } GridLayout { - columns: 2 + columns: 4 Repeater { id: cpacks diff --git a/Fk/Pages/Lobby.qml b/Fk/Pages/Lobby.qml index f313152f..3140d411 100644 --- a/Fk/Pages/Lobby.qml +++ b/Fk/Pages/Lobby.qml @@ -224,19 +224,25 @@ Item { } } - Drawer { + Popup { id: lobby_drawer - width: parent.width * 0.4 / mainWindow.scale - height: parent.height / mainWindow.scale - dim: false - clip: true - dragMargin: 0 - scale: mainWindow.scale - transformOrigin: Item.TopLeft + width: realMainWin.width * 0.8 + height: realMainWin.height * 0.8 + anchors.centerIn: parent + background: Rectangle { + color: "#EEEEEEEE" + radius: 5 + border.color: "#A6967A" + border.width: 1 + } Loader { id: lobby_dialog - anchors.fill: parent + anchors.centerIn: parent + width: parent.width / mainWindow.scale + height: parent.height / mainWindow.scale + scale: mainWindow.scale + clip: true onSourceChanged: { if (item === null) return; diff --git a/Fk/Pages/MetroButton.qml b/Fk/Pages/MetroButton.qml index aab1b980..b602ce26 100644 --- a/Fk/Pages/MetroButton.qml +++ b/Fk/Pages/MetroButton.qml @@ -41,6 +41,9 @@ Item { TapHandler { id: mouse + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.NoButton + gesturePolicy: TapHandler.WithinBounds + onTapped: if (parent.enabled) parent.clicked() } diff --git a/Fk/Pages/Room.qml b/Fk/Pages/Room.qml index a5178680..292e252d 100644 --- a/Fk/Pages/Room.qml +++ b/Fk/Pages/Room.qml @@ -8,6 +8,7 @@ import QtMultimedia import Fk import Fk.Common import Fk.RoomElement +import Fk.PhotoElement as PhotoElement import "RoomLogic.js" as Logic Item { @@ -37,6 +38,7 @@ Item { property alias drawPile: drawPile property alias skillInteraction: skillInteraction property alias miscStatus: miscStatus + property alias banner: banner property var selected_targets: [] property string responding_card @@ -55,7 +57,6 @@ Item { fillMode: Image.PreserveAspectCrop } - /* MediaPlayer { id: bgm source: config.bgmFile @@ -69,15 +70,14 @@ Item { volume: config.bgmVolume / 100 } } - */ onIsStartedChanged: { if (isStarted) { - // bgm.play(); + bgm.play(); canKickOwner = false; kickOwnerTimer.stop(); } else { - // bgm.stop(); + bgm.stop(); } } @@ -533,14 +533,6 @@ Item { } } - GlowText { - text: Backend.translate("Observing ...") - visible: config.observing && !config.replaying - color: "#4B83CD" - font.family: fontLi2.name - font.pixelSize: 48 - } - Rectangle { id: replayControls visible: config.replaying @@ -855,7 +847,7 @@ Item { Drawer { id: roomDrawer - width: parent.width * 0.3 / mainWindow.scale + width: parent.width * 0.36 / mainWindow.scale height: parent.height / mainWindow.scale dim: false clip: true @@ -901,20 +893,25 @@ Item { } } - Drawer { + Popup { id: cheatDrawer - edge: Qt.RightEdge - width: parent.width * 0.4 / mainWindow.scale - height: parent.height / mainWindow.scale - dim: false - clip: true - dragMargin: 0 - scale: mainWindow.scale - transformOrigin: Item.TopRight + width: realMainWin.width * 0.60 + height: realMainWin.height * 0.8 + anchors.centerIn: parent + background: Rectangle { + color: "#CC2E2C27" + radius: 5 + border.color: "#A6967A" + border.width: 1 + } Loader { id: cheatLoader - anchors.fill: parent + anchors.centerIn: parent + width: parent.width / mainWindow.scale + height: parent.height / mainWindow.scale + scale: mainWindow.scale + clip: true onSourceChanged: { if (item === null) return; @@ -931,6 +928,20 @@ Item { anchors.fill: parent } + Rectangle { + anchors.fill: dashboard + visible: config.observing && !config.replaying + color: "transparent" + GlowText { + anchors.centerIn: parent + text: Backend.translate("Observing ...") + color: "#4B83CD" + font.family: fontLi2.name + font.pixelSize: 48 + } + } + + /* 这东西似乎一直不好使啊 Rectangle { id: easyChat width: parent.width @@ -967,6 +978,16 @@ Item { } } + Shortcut { + sequence: "T" + onActivated: { + easyChat.visible = true; + easyChatEdit.enabled = true; + easyChatEdit.forceActiveFocus(); + } + } + */ + MiscStatus { id: miscStatus anchors.right: menuButton.left @@ -975,20 +996,20 @@ Item { anchors.topMargin: 8 } + PhotoElement.MarkArea { + id: banner + x: 12; y: 12 + width: (roomScene.width - 175 * 0.75 * 7) / 4 + 175 - 16 + transformOrigin: Item.TopLeft + scale: 0.75 + bgColor: "#BB838AEA" + } + Danmaku { id: danmaku width: parent.width } - Shortcut { - sequence: "T" - onActivated: { - easyChat.visible = true; - easyChatEdit.enabled = true; - easyChatEdit.forceActiveFocus(); - } - } - Shortcut { sequence: "D" property bool show_distance: false diff --git a/Fk/Pages/RoomLogic.js b/Fk/Pages/RoomLogic.js index 8936a9dd..c1677e75 100644 --- a/Fk/Pages/RoomLogic.js +++ b/Fk/Pages/RoomLogic.js @@ -1012,7 +1012,7 @@ callbacks["AskForChoice"] = (jsonData) => { }); } -callbacks["AskForCheck"] = (jsonData) => { +callbacks["AskForChoices"] = (jsonData) => { // jsonData: [ string[] choices, string skill ] // TODO: multiple choices, e.g. benxi_ol const data = JSON.parse(jsonData); @@ -1025,7 +1025,7 @@ callbacks["AskForCheck"] = (jsonData) => { const prompt = data[5]; const detailed = data[6]; if (prompt === "") { - roomScene.promptText = Backend.translate("#AskForCheck") + roomScene.promptText = Backend.translate("#AskForChoices") .arg(Backend.translate(skill_name)); } else { roomScene.setPrompt(processPrompt(prompt), true); @@ -1335,7 +1335,7 @@ callbacks["SetPlayerMark"] = (jsonData) => { const data = JSON.parse(jsonData); const player = getPhoto(data[0]); const mark = data[1]; - const value = data[2] instanceof Array ? data[2] : data[2].toString(); + const value = data[2] instanceof Object ? data[2] : data[2].toString(); let area = mark.startsWith("@!") ? player.picMarkArea : player.markArea; if (data[2] === 0) { area.removeMark(mark); @@ -1344,6 +1344,18 @@ callbacks["SetPlayerMark"] = (jsonData) => { } } +callbacks["SetBanner"] = (jsonData) => { + const data = JSON.parse(jsonData); + const mark = data[0]; + const value = data[1] instanceof Object ? data[1] : data[1].toString(); + let area = roomScene.banner; + if (data[1] === 0) { + area.removeMark(mark); + } else { + area.setMark(mark, mark.startsWith("@@") ? "" : value); + } +} + callbacks["Animate"] = (jsonData) => { // jsonData: [Object object] const data = JSON.parse(jsonData); @@ -1581,7 +1593,7 @@ callbacks["ChangeSelf"] = (j) => { callbacks["AskForLuckCard"] = (j) => { // jsonData: int time - if (config.replaying) return; + if (config.observing || config.replaying) return; const time = parseInt(j); roomScene.setPrompt(Backend.translate("#AskForLuckCard").arg(time), true); roomScene.state = "replying"; diff --git a/Fk/PhotoElement/MarkArea.qml b/Fk/PhotoElement/MarkArea.qml index adda007c..f4e5ed0c 100644 --- a/Fk/PhotoElement/MarkArea.qml +++ b/Fk/PhotoElement/MarkArea.qml @@ -6,6 +6,7 @@ import QtQuick.Layouts Item { id: root width: 138 + property var bgColor: "#3C3229" ListModel { id: markList @@ -15,7 +16,7 @@ Item { anchors.bottom: parent.bottom width: parent.width height: parent.height - color: "#3C3229" + color: bgColor opacity: 0.8 radius: 4 border.color: "white" @@ -68,7 +69,21 @@ Item { } else { params.cardNames = data; } + } else if (mark_name.startsWith('@[')) { + // @[xxx]yyy 怀疑是不是qml标记 + const close_br = mark_name.indexOf(']'); + if (close_br === -1) return; + + const mark_type = mark_name.slice(2, close_br); + const _data = (mark_extra); + let data = JSON.parse(Backend.callLuaFunction("GetQmlMark", [mark_type, mark_name, JSON.stringify(_data)])); + if (data && data.qml_path) { + params.data = _data; + roomScene.startCheat("../../" + data.qml_path, params); + } + return; } else { + if (!root.parent.playerid) return; let data = JSON.parse(Backend.callLuaFunction("GetPile", [root.parent.playerid, mark_name])); data = data.filter((e) => e !== -1); if (data.length === 0) @@ -103,6 +118,15 @@ Item { if (mark.startsWith('@$') || mark.startsWith('@&')) { special_value += data.length; data = data.join(','); + } else if (mark.startsWith('@[')) { + const close_br = mark.indexOf(']'); + if (close_br !== -1) { + const mark_type = mark.slice(2, close_br); + const _data = JSON.parse(Backend.callLuaFunction("GetQmlMark", [mark_type, mark, JSON.stringify(data)])); + if (_data && _data.text) { + special_value = _data.text; + } + } } else { data = data instanceof Array ? data.map((markText) => Backend.translate(markText)).join(' ') : Backend.translate(data); } diff --git a/Fk/RoomElement/BigGlowText.qml b/Fk/RoomElement/BigGlowText.qml new file mode 100644 index 00000000..fb375d1c --- /dev/null +++ b/Fk/RoomElement/BigGlowText.qml @@ -0,0 +1,39 @@ +import QtQuick +import Qt5Compat.GraphicalEffects + +Item { + property alias text: pileName.text + GlowText { + id: pileName + horizontalAlignment: Text.AlignHCenter + width: parent.width + font.family: fontLibian.name + color: "#E4D5A0" + font.pixelSize: 30 + font.weight: Font.Medium + glow.color: "black" + glow.spread: 0.3 + glow.radius: 5 + } + + LinearGradient { + anchors.fill: pileName + source: pileName + gradient: Gradient { + GradientStop { + position: 0 + color: "#FEF7C2" + } + + GradientStop { + position: 0.5 + color: "#D2AD4A" + } + + GradientStop { + position: 1 + color: "#BE9878" + } + } + } +} diff --git a/Fk/RoomElement/ChooseHandcard.qml b/Fk/RoomElement/ChooseHandcard.qml index 94747891..45281e18 100644 --- a/Fk/RoomElement/ChooseHandcard.qml +++ b/Fk/RoomElement/ChooseHandcard.qml @@ -5,7 +5,7 @@ import QtQuick.Layouts import QtQuick.Controls import Qt5Compat.GraphicalEffects -Item { +ColumnLayout { id: root anchors.fill: parent property var extra_data: ({}) // unused @@ -14,51 +14,40 @@ Item { Text { text: Backend.translate("Handcard selector") - width: parent.width - anchors.topMargin: 6 + Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter - font.pixelSize: 16 + font.pixelSize: 18 + color: "#E4D5A0" } - Flickable { - id: flickableContainer - ScrollBar.vertical: ScrollBar {} - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: 40 - flickableDirection: Flickable.VerticalFlick - width: parent.width - 20 - height: parent.height - 40 - contentWidth: cardsList.width - contentHeight: cardsList.height + GridView { + id: cardsList + cellWidth: 93 * 0.9 + 4 + cellHeight: 130 * 0.9 + 4 + Layout.preferredWidth: root.width - root.width % 88 + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter clip: true - GridLayout { - id: cardsList - columns: Math.floor(flickableContainer.width / 90) + model: cards - Repeater { - model: cards - - CardItem { - width: 93 * 0.9 - height: 130 * 0.9 - chosenInBox: modelData.chosen - onClicked: { - const clist = roomScene.dashboard.handcardArea.cards; - for (let cd of clist) { - if (cd.cid == cid) { - cd.selected = !cd.selected; - cd.clicked(); - finish(); - } - } - } - Component.onCompleted: { - setData(JSON.parse(Backend.callLuaFunction("GetCardData", [modelData.cid]))); + delegate: CardItem { + width: 93 * 0.9 + height: 130 * 0.9 + chosenInBox: modelData.chosen + onClicked: { + const clist = roomScene.dashboard.handcardArea.cards; + for (let cd of clist) { + if (cd.cid == cid) { + cd.selected = !cd.selected; + cd.clicked(); + finish(); } } } + Component.onCompleted: { + setData(JSON.parse(Backend.callLuaFunction("GetCardData", [modelData.cid]))); + } } } diff --git a/Fk/RoomElement/GeneralCardItem.qml b/Fk/RoomElement/GeneralCardItem.qml index 123a05fd..290882c0 100644 --- a/Fk/RoomElement/GeneralCardItem.qml +++ b/Fk/RoomElement/GeneralCardItem.qml @@ -153,7 +153,7 @@ CardItem { height: 80 x: 2 y: lineCount > 6 ? 30 : 34 - text: Backend.translate(name) + text: name !== "" ? Backend.translate(name) : "nil" visible: Backend.translate(name).length <= 6 && detailed color: "white" font.family: fontLibian.name diff --git a/Fk/RoomElement/ViewGeneralPile.qml b/Fk/RoomElement/ViewGeneralPile.qml index aead17bd..46645f41 100644 --- a/Fk/RoomElement/ViewGeneralPile.qml +++ b/Fk/RoomElement/ViewGeneralPile.qml @@ -2,87 +2,34 @@ import QtQuick import QtQuick.Layouts -import QtQuick.Controls -import Qt5Compat.GraphicalEffects -Item { +ColumnLayout { id: root anchors.fill: parent property var extra_data: ({}) signal finish() - Rectangle { - anchors.fill: parent - color: "black" + BigGlowText { + Layout.fillWidth: true + Layout.preferredHeight: childrenRect.height + 4 - GlowText { - id: pileName - text: Backend.translate(extra_data.name) - width: parent.width - anchors.topMargin: 10 - horizontalAlignment: Text.AlignHCenter - font.family: fontLibian.name - color: "#E4D5A0" - font.pixelSize: 30 - font.weight: Font.Medium - glow.color: "black" - glow.spread: 0.3 - glow.radius: 5 - } + text: Backend.translate(extra_data.name) + } - LinearGradient { - anchors.fill: pileName - source: pileName - gradient: Gradient { - GradientStop { - position: 0 - color: "#FEF7C2" - } + GridView { + cellWidth: 93 + 4 + cellHeight: 130 + 4 + Layout.preferredWidth: root.width - root.width % 97 + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter + clip: true - GradientStop { - position: 0.5 - color: "#D2AD4A" - } + model: extra_data.ids || extra_data.cardNames - GradientStop { - position: 1 - color: "#BE9878" - } - } - } - - Flickable { - id: flickableContainer - ScrollBar.vertical: ScrollBar {} - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: 40 - flickableDirection: Flickable.VerticalFlick - width: parent.width - 20 - height: parent.height - 40 - contentWidth: cardsList.width - contentHeight: cardsList.height - clip: true - - ColumnLayout { - id: cardsList - - GridLayout { - columns: Math.floor(flickableContainer.width / 100) - - Repeater { - model: extra_data.ids || extra_data.cardNames - - GeneralCardItem { - id: cardItem - // width: (flickableContainer.width - 15) / 4 - // height: cardItem.width * 1.4 - autoBack: false - name: modelData - } - } - } - } + delegate: GeneralCardItem { + id: cardItem + autoBack: false + name: modelData } } } diff --git a/Fk/RoomElement/ViewPile.qml b/Fk/RoomElement/ViewPile.qml index 860f4e6a..4b0bb269 100644 --- a/Fk/RoomElement/ViewPile.qml +++ b/Fk/RoomElement/ViewPile.qml @@ -2,98 +2,45 @@ import QtQuick import QtQuick.Layouts -import QtQuick.Controls -import Qt5Compat.GraphicalEffects -Item { +ColumnLayout { id: root anchors.fill: parent property var extra_data: ({}) signal finish() - Rectangle { - anchors.fill: parent - color: "black" + BigGlowText { + Layout.fillWidth: true + Layout.preferredHeight: childrenRect.height + 4 - GlowText { - id: pileName - text: Backend.translate(extra_data.name) - width: parent.width - anchors.topMargin: 10 - horizontalAlignment: Text.AlignHCenter - font.family: fontLibian.name - color: "#E4D5A0" - font.pixelSize: 30 - font.weight: Font.Medium - glow.color: "black" - glow.spread: 0.3 - glow.radius: 5 - } + text: Backend.translate(extra_data.name) + } - LinearGradient { - anchors.fill: pileName - source: pileName - gradient: Gradient { - GradientStop { - position: 0 - color: "#FEF7C2" - } - - GradientStop { - position: 0.5 - color: "#D2AD4A" - } - - GradientStop { - position: 1 - color: "#BE9878" - } - } - } - - Flickable { - id: flickableContainer - ScrollBar.vertical: ScrollBar {} - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: 40 - flickableDirection: Flickable.VerticalFlick - width: parent.width - 20 - height: parent.height - 40 - contentWidth: cardsList.width - contentHeight: cardsList.height - clip: true - - ColumnLayout { - id: cardsList - - GridLayout { - columns: 4 - - Repeater { - model: extra_data.ids || extra_data.cardNames - - CardItem { - id: cardItem - width: (flickableContainer.width - 15) / 4 - height: cardItem.width * 1.4 - autoBack: false - Component.onCompleted: { - let data = {} - if (extra_data.ids) { - data = JSON.parse(Backend.callLuaFunction("GetCardData", [modelData])); - } else { - data.cid = 0; - data.name = modelData; - data.suit = ''; - data.number = 0; - data.color = ''; - } - setData(data); - } - } - } + GridView { + cellWidth: 93 + 4 + cellHeight: 130 + 4 + Layout.preferredWidth: root.width - root.width % 97 + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter + clip: true + + model: extra_data.ids || extra_data.cardNames + + delegate: CardItem { + id: cardItem + autoBack: false + Component.onCompleted: { + let data = {} + if (extra_data.ids) { + data = JSON.parse(Backend.callLuaFunction("GetCardData", [modelData])); + } else { + data.cid = 0; + data.name = modelData; + data.suit = ''; + data.number = 0; + data.color = ''; } + setData(data); } } } diff --git a/Fk/RoomElement/qmldir b/Fk/RoomElement/qmldir index ac94eb75..13c69b78 100644 --- a/Fk/RoomElement/qmldir +++ b/Fk/RoomElement/qmldir @@ -8,6 +8,7 @@ Dashboard 1.0 Dashboard.qml GameOverBox 1.0 GameOverBox.qml GeneralCardItem 1.0 GeneralCardItem.qml GlowText 1.0 GlowText.qml +BigGlowText 1.0 BigGlowText.qml GraphicsBox 1.0 GraphicsBox.qml GuanxingBox 1.0 GuanxingBox.qml HandcardArea 1.0 HandcardArea.qml diff --git a/lang/zh_CN.ts b/lang/zh_CN.ts index 72bba804..e5dbf625 100644 --- a/lang/zh_CN.ts +++ b/lang/zh_CN.ts @@ -334,6 +334,10 @@ Room is full or already started! 房间已满! + + rejected your demand of joining room + 房主拒绝你加入。 + server is full! 服务器已满! diff --git a/lua/client/client.lua b/lua/client/client.lua index 12bfa646..3b79f51a 100644 --- a/lua/client/client.lua +++ b/lua/client/client.lua @@ -8,6 +8,7 @@ ---@field public current ClientPlayer @ 当前回合玩家 ---@field public discard_pile integer[] @ 弃牌堆 ---@field public status_skills Skill[] @ 状态技总和 +---@field public banners table @ 左上角显示的东西 ---@field public observing boolean Client = class('Client') @@ -57,6 +58,8 @@ function Client:initialize() self.status_skills[class] = {table.unpack(skills)} end + self.banners = {} + self.skill_costs = {} self.card_marks = {} self.filtered_cards = {} @@ -234,6 +237,15 @@ function Client:setCardNote(ids, msg) end end +function Client:setBanner(name, value) + if value == 0 then value = nil end + self.banners[name] = value +end + +function Client:getBanner(name) + return self.banners[name] +end + fk.client_callback["SetCardFootnote"] = function(jsonData) local data = json.decode(jsonData) ClientInstance:setCardNote(data[1], data[2]); @@ -769,6 +781,17 @@ fk.client_callback["SetPlayerMark"] = function(jsonData) end end +fk.client_callback["SetBanner"] = function(jsonData) + -- jsonData: [ int id, string mark, int value ] + local data = json.decode(jsonData) + local mark, value = data[1], data[2] + ClientInstance:setBanner(mark, value) + + if string.sub(mark, 1, 1) == "@" then + ClientInstance:notifyUI("SetBanner", jsonData) + end +end + fk.client_callback["SetCardMark"] = function(jsonData) -- jsonData: [ int id, string mark, int value ] local data = json.decode(jsonData) diff --git a/lua/client/client_util.lua b/lua/client/client_util.lua index adc00859..83aaa849 100644 --- a/lua/client/client_util.lua +++ b/lua/client/client_util.lua @@ -734,4 +734,14 @@ function PoxiFeasible(poxi_type, selected, data, extra_data) return json.encode(poxi.feasible(selected, data, extra_data)) end +function GetQmlMark(mtype, name, value) + local spec = Fk.qml_marks[mtype] + if not spec then return "{}" end + value = json.decode(value) + return json.encode { + qml_path = spec.qml_path, + text = spec.how_to_show(name, value) + } +end + dofile "lua/client/i18n/init.lua" diff --git a/lua/client/i18n/en_US.lua b/lua/client/i18n/en_US.lua index cc3ccbed..5f34c0f1 100644 --- a/lua/client/i18n/en_US.lua +++ b/lua/client/i18n/en_US.lua @@ -159,7 +159,7 @@ Fk:loadTranslationTable({ ["#AskForLuckCard"] = "Do you want to use luck card (%1 times left)?", ["AskForLuckCard"] = "Luck card", ["#AskForChoice"] = "%1: Please choose", - ["#AskForCheck"] = "%1: Please choose", + ["#AskForChoices"] = "%1: Please choose", ["#choose-trigger"] = "Please choose the skill to use", ["trigger"] = "Trigger skill", -- ["Please arrange cards"] = "请拖拽移动卡牌", @@ -170,7 +170,7 @@ Fk:loadTranslationTable({ ["AskForGuanxing"] = "Stargazing", ["AskForExchange"] = "Exchaging", ["AskForChoice"] = "Making choice", - ["AskForCheck"] = "Making choice", + ["AskForChoices"] = "Making choice", ["AskForKingdom"] = "Choosing kingdom", ["AskForPindian"] = "Point fight", ["AskForMoveCardInBoard"] = "Moving cards", diff --git a/lua/client/i18n/zh_CN.lua b/lua/client/i18n/zh_CN.lua index 71bb9901..31aa502f 100644 --- a/lua/client/i18n/zh_CN.lua +++ b/lua/client/i18n/zh_CN.lua @@ -206,7 +206,7 @@ FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下 ["#AskForLuckCard"] = "你想使用手气卡吗?还可以使用 %1 次,剩余手气卡∞张", ["AskForLuckCard"] = "手气卡", ["#AskForChoice"] = "%1:请选择", - ["#AskForCheck"] = "%1:请选择", + ["#AskForChoices"] = "%1:请选择", ["#choose-trigger"] = "请选择一项技能发动", ["trigger"] = "选择技能", ["Please arrange cards"] = "请拖拽移动卡牌", @@ -217,7 +217,7 @@ FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下 ["AskForGuanxing"] = "观星", ["AskForExchange"] = "换牌", ["AskForChoice"] = "选择", - ["AskForCheck"] = "选择", + ["AskForChoices"] = "选择", ["AskForKingdom"] = "选择势力", ["AskForPindian"] = "拼点", ["AskForMoveCardInBoard"] = "移动卡牌", diff --git a/lua/core/engine.lua b/lua/core/engine.lua index cf4a568a..309c6b9b 100644 --- a/lua/core/engine.lua +++ b/lua/core/engine.lua @@ -27,6 +27,7 @@ ---@field public printed_cards table @ 被某些房间现场打印的卡牌,id都是负数且从-2开始 ---@field private _custom_events any[] @ 自定义事件列表 ---@field public poxi_methods table @ “魄袭”框操作方法表 +---@field public qml_marks table @ 自定义Qml标记的表 local Engine = class("Engine") --- Engine的构造函数。 @@ -59,6 +60,7 @@ function Engine:initialize() self.kingdoms = {} self._custom_events = {} self.poxi_methods = {} + self.qml_marks = {} self:loadPackages() self:loadDisabled() @@ -345,11 +347,22 @@ function Engine:addPoxiMethod(spec) assert(type(spec.name) == "string") assert(type(spec.card_filter) == "function") assert(type(spec.feasible) == "function") + if self.poxi_methods[spec.name] then + fk.qCritical("Warning: duplicated poxi_method " .. spec.name) + end self.poxi_methods[spec.name] = spec spec.default_choice = spec.default_choice or function() return {} end spec.post_select = spec.post_select or function(s) return s end end +function Engine:addQmlMark(spec) + assert(type(spec.name) == "string") + if self.qml_marks[spec.name] then + fk.qCritical("Warning: duplicated qml mark type " .. spec.name) + end + self.qml_marks[spec.name] = spec +end + --- 从已经开启的拓展包中,随机选出若干名武将。 --- --- 对于同名武将不会重复选取。 diff --git a/lua/fk_ex.lua b/lua/fk_ex.lua index 449ec452..d6f329c4 100644 --- a/lua/fk_ex.lua +++ b/lua/fk_ex.lua @@ -598,3 +598,8 @@ end ---@field post_select? fun(selected: int[], data: any, extra_data: any): int[] ---@field default_choice? fun(data: any, extra_data: any): int[] ---@field prompt? string | fun(data: any, extra_data: any): string + +---@class QmlMarkSpec +---@field name string +---@field qml_path string +---@field how_to_show function(name: string, value?: any): string? diff --git a/lua/server/request.lua b/lua/server/request.lua index 8469fe95..7c87d1cf 100644 --- a/lua/server/request.lua +++ b/lua/server/request.lua @@ -41,6 +41,11 @@ local function tellRoomToObserver(self, player) end end + -- send banners + for k, v in pairs(self.banners) do + player:doNotify("SetBanner", json.encode{ k, v }) + end + for _, p in ipairs(self.players) do self:notifyProperty(player, p, "general") self:notifyProperty(player, p, "deputyGeneral") diff --git a/lua/server/room.lua b/lua/server/room.lua index 3e442976..b329375c 100644 --- a/lua/server/room.lua +++ b/lua/server/room.lua @@ -15,6 +15,7 @@ ---@field public game_finished boolean @ 游戏是否已经结束 ---@field public timeout integer @ 出牌时长上限 ---@field public tag table @ Tag清单,其实跟Player的标记是差不多的东西 +---@field public banners table @ 左上角显示点啥好呢? ---@field public general_pile string[] @ 武将牌堆,这是可用武将名的数组 ---@field public draw_pile integer[] @ 摸牌堆,这是卡牌id的数组 ---@field public discard_pile integer[] @ 弃牌堆,也是卡牌id的数组 @@ -77,6 +78,7 @@ function Room:initialize(_room) self.game_finished = false self.timeout = _room:getTimeout() self.tag = {} + self.banners = {} self.general_pile = {} self.draw_pile = {} self.discard_pile = {} @@ -563,6 +565,16 @@ function Room:removeTag(tag_name) self.tag[tag_name] = nil end +function Room:setBanner(name, value) + if value == 0 then value = nil end + self.banners[name] = value + self:doBroadcastNotify("SetBanner", json.encode{ name, value }) +end + +function Room:getBanner(name) + return self.banners[name] +end + ---@return boolean local function execGameEvent(type, ...) local event = GameEvent:new(type, ...) @@ -1338,9 +1350,9 @@ end ---@param cancelable? boolean @ 能否点取消 ---@param no_indicate? boolean @ 是否不显示指示线 ---@return integer[], integer[] -function Room:askForChooseBoth(player, minCardNum, maxCardNum, targets, minTargetNum, maxTargetNum, pattern, prompt, skillName, cancelable, no_indicate) +function Room:askForChooseCardsAndPlayers(player, minCardNum, maxCardNum, targets, minTargetNum, maxTargetNum, pattern, prompt, skillName, cancelable, no_indicate) if minCardNum < 1 or minTargetNum < 1 then - return table.unpack({}, {}) + return {}, {} end cancelable = (cancelable == nil) and true or cancelable no_indicate = no_indicate or false @@ -1366,7 +1378,7 @@ function Room:askForChooseBoth(player, minCardNum, maxCardNum, targets, minTarge return ret.targets, ret.cards else if cancelable then - return table.unpack({}, {}) + return {}, {} else return table.random(targets, minTargetNum), table.random(pcards, minCardNum) end @@ -1675,12 +1687,12 @@ end ---@param detailed? boolean @ 选项详细描述 ---@param all_choices? string[] @ 所有选项(不可选变灰) ---@return string[] @ 选择的选项 -function Room:askForCheck(player, choices, minNum, maxNum, skill_name, prompt, cancelable, detailed, all_choices) +function Room:askForChoices(player, choices, minNum, maxNum, skill_name, prompt, cancelable, detailed, all_choices) cancelable = (cancelable == nil) and true or cancelable if #choices <= minNum and not all_choices then return choices end assert(minNum <= maxNum) assert(not all_choices or table.every(choices, function(c) return table.contains(all_choices, c) end)) - local command = "AskForCheck" + local command = "AskForChoices" skill_name = skill_name or "" prompt = prompt or "" all_choices = all_choices or choices diff --git a/lua/server/serverplayer.lua b/lua/server/serverplayer.lua index 11b53b38..677ad4b9 100644 --- a/lua/server/serverplayer.lua +++ b/lua/server/serverplayer.lua @@ -362,6 +362,11 @@ function ServerPlayer:reconnect() end end + -- send banners + for k, v in pairs(room.banners) do + self:doNotify("SetBanner", json.encode{ k, v }) + end + for _, p in ipairs(room.players) do room:notifyProperty(self, p, "general") room:notifyProperty(self, p, "deputyGeneral") diff --git a/packages/test/init.lua b/packages/test/init.lua index 5f599725..f1e81e1a 100644 --- a/packages/test/init.lua +++ b/packages/test/init.lua @@ -87,6 +87,10 @@ local control = fk.CreateActiveSkill{ on_use = function(self, room, effect) --room:doSuperLightBox("packages/test/qml/Test.qml") local from = room:getPlayerById(effect.from) + -- room:setPlayerMark(from, "@[test]test", { + -- all = {3, 1, 6, 9, 5, 11, 10, 2, 8, 7, 12, 4, 13}, + -- ok = {10, 2}, + -- }) -- room:swapSeat(from, to) for _, pid in ipairs(effect.tos) do local to = room:getPlayerById(pid) @@ -145,6 +149,27 @@ Fk:addPoxiMethod{ end, prompt = "魄袭:选你们俩手牌总共四个花色,或者不选直接按确定按钮" } +Fk:loadTranslationTable{['@[test]test']='割圆'} +Fk:addQmlMark{ + name = "test", + how_to_show = function(name, value) + local all_points = value.all + local ok_points = value.ok + -- 若没有点亮的就不显示 + if #ok_points == 0 then return "" end + -- 否则,显示相邻的,逻辑上要构成循环 + local start_idx = table.indexOf(all_points, ok_points[1]) - 1 + local end_idx = table.indexOf(all_points, ok_points[#ok_points]) + 1 + if start_idx == 0 then start_idx = #all_points end + if end_idx == #all_points + 1 then end_idx = 1 end + if start_idx == end_idx then + return Card:getNumberStr(all_points[start_idx]) + else + return Card:getNumberStr(all_points[start_idx]) .. Card:getNumberStr(all_points[end_idx]) + end + end, + qml_path = "packages/test/qml/TestDialog" +} --]] local test_vs = fk.CreateViewAsSkill{ name = "test_vs", diff --git a/packages/test/qml/TestDialog.qml b/packages/test/qml/TestDialog.qml index a663bc53..be4ad3e6 100644 --- a/packages/test/qml/TestDialog.qml +++ b/packages/test/qml/TestDialog.qml @@ -1,38 +1,57 @@ +// 割圆的例子 import QtQuick -import "../../../qml/Pages/RoomElement" -import "../../../qml/Pages" - -GraphicsBox { - property string custom_string: "" +import QtQuick.Layouts +import Fk.RoomElement +ColumnLayout { id: root - title.text: Backend.translate("Test") - width: Math.max(140, body.width + 20) - height: body.height + title.height + 20 + anchors.fill: parent + property var extra_data: ({ name: "", data: { + all: [1, 2, 4, 6], + ok: [1, 4], + } }) + signal finish() - Column { - id: body - x: 10 - y: title.height + 5 - spacing: 10 + BigGlowText { + Layout.fillWidth: true + Layout.preferredHeight: childrenRect.height + 4 - Text { - text: root.custom_string - color: "#E4D5A0" + text: Backend.translate(extra_data.name) + } + + PathView { + id: pathView + Layout.fillWidth: true + Layout.fillHeight: true + model: extra_data.data.all + delegate: Rectangle{ + width: 42; height: 42 + color: extra_data.data.ok.includes(modelData) ? "yellow" : "#CCEEEEEE" + radius: 2 + Text { + anchors.centerIn: parent + text: modelData + font.pixelSize: 24 + } } - - MetroButton { - text: Backend.translate("OKOK") - anchors.horizontalCenter: parent.horizontalCenter - - onClicked: { - close(); - ClientInstance.replyToServer("", "Hello from test dialog"); + path: Path { + // 默认横屏了,应该没人用竖屏玩这游戏 + startX: pathView.width / 2 + startY: 40 + PathArc { + x: pathView.width / 2 + y: pathView.height - 40 + radiusX: (pathView.height - 80) / 2 + radiusY: (pathView.height - 80) / 2 + direction: PathArc.Clockwise + } + PathArc { + x: pathView.width / 2 + y: 40 + radiusX: (pathView.height - 80) / 2 + radiusY: (pathView.height - 80) / 2 + direction: PathArc.Clockwise } } } - - function loadData(data) { - custom_string = data; - } } diff --git a/src/network/router.cpp b/src/network/router.cpp index be73a555..38c96437 100644 --- a/src/network/router.cpp +++ b/src/network/router.cpp @@ -284,7 +284,13 @@ void Router::handlePacket(const QByteArray &rawPacket) { } else if (command == "KickPlayer") { int i = jsonData.toInt(); auto p = room->findPlayer(i); - if (p && !room->isStarted()) room->removePlayer(p); + if (p && !room->isStarted()) { + room->removePlayer(p); + room->addRejectId(i); + QTimer::singleShot(30000, this, [=]() { + room->removeRejectId(i); + }); + } } else if (command == "Ready") { player->setReady(!player->isReady()); room->doBroadcastNotify(room->getPlayers(), "ReadyChanged", diff --git a/src/server/room.cpp b/src/server/room.cpp index 3241336e..4e96f636 100644 --- a/src/server/room.cpp +++ b/src/server/room.cpp @@ -125,6 +125,11 @@ void Room::addPlayer(ServerPlayer *player) { if (!player) return; + if (rejected_players.contains(player->getId())) { + player->doNotify("ErrorMsg", "rejected your demand of joining room"); + return; + } + // 如果要加入的房间满员了,或者已经开战了,就不能再加入 if (isFull() || gameStarted) { player->doNotify("ErrorMsg", "Room is full or already started!"); @@ -322,6 +327,11 @@ void Room::addObserver(ServerPlayer *player) { return; } + if (rejected_players.contains(player->getId())) { + player->doNotify("ErrorMsg", "rejected your demand of joining room"); + return; + } + // 向observers中追加player,并从大厅移除player,然后将player的room设为this observers.append(player); player->setRoom(this); @@ -573,3 +583,12 @@ void Room::pushRequest(const QString &req) { m_thread->pushRequest(QString("%1,%2").arg(QString::number(id), req)); } } + +void Room::addRejectId(int id) { + if (isLobby()) return; + rejected_players << id; +} + +void Room::removeRejectId(int id) { + rejected_players.removeOne(id); +} diff --git a/src/server/room.h b/src/server/room.h index ad7a4b90..2cf9a13a 100644 --- a/src/server/room.h +++ b/src/server/room.h @@ -63,6 +63,8 @@ class Room : public QObject { void manuallyStart(); void pushRequest(const QString &req); + void addRejectId(int id); + void removeRejectId(int id); signals: void abandoned(); @@ -82,6 +84,7 @@ class Room : public QObject { QList players; QList observers; QList runned_players; + QList rejected_players; int robot_id; bool gameStarted; bool m_ready; diff --git a/src/server/server.cpp b/src/server/server.cpp index e8eada4b..30c5d98a 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -60,7 +60,7 @@ Server::Server(QObject *parent) : QObject(parent) { } } - for (int i = 0; i < 20; i++) { + for (int i = 0; i < 30; i++) { if (!this->isListening) { return; }