diff --git a/lua/core/skill_type/trigger.lua b/lua/core/skill_type/trigger.lua index 71a4d388..6dd76167 100644 --- a/lua/core/skill_type/trigger.lua +++ b/lua/core/skill_type/trigger.lua @@ -49,10 +49,9 @@ end ---@param data any # useful data of the event ---@return boolean # returns true if trigger is broken function TriggerSkill:trigger(event, target, player, data) - print(string.format("%s triggered: event=%d", self.name, event)) - --if player.room:askForSkillInvoke(self.name) then - -- return self:use(event, target, player, data) - --end + if player.room:askForSkillInvoke(player, self.name) then + return self:use(event, target, player, data) + end return false end diff --git a/lua/server/gamelogic.lua b/lua/server/gamelogic.lua index b6c5c83f..2986e0b9 100644 --- a/lua/server/gamelogic.lua +++ b/lua/server/gamelogic.lua @@ -249,7 +249,7 @@ function GameLogic:trigger(event, target, data) end while #skill_names > 0 do - local skill_name = room:askForChoice(player, skill_names) + local skill_name = room:askForChoice(player, skill_names, "trigger") local skill = triggerables[table.indexOf(skill_names, skill_name)] broken = skill:trigger(event, target, player, data) if broken then break end diff --git a/lua/server/room.lua b/lua/server/room.lua index e124b417..4bb24f4d 100644 --- a/lua/server/room.lua +++ b/lua/server/room.lua @@ -220,8 +220,28 @@ end ---@param player ServerPlayer ---@param choices string[] -function Room:askForChoice(player, choices) - return choices[1] +---@param skill_name string +function Room:askForChoice(player, choices, skill_name, data) + if #choices == 1 then return choices[1] end + local command = "AskForChoice" + self:notifyMoveFocus(player, skill_name) + local result = self:doRequest(player, command, json.encode{ + choices, skill_name + }) + if result == "" then result = choices[1] end + return result +end + +---@param player ServerPlayer +---@param skill_name string +---@return boolean +function Room:askForSkillInvoke(player, skill_name, data) + local command = "AskForSkillInvoke" + self:notifyMoveFocus(player, skill_name) + local invoked = false + local result = self:doRequest(player, command, skill_name) + if result ~= "" then invoked = true end + return invoked end fk.room_callback["QuitRoom"] = function(jsonData) diff --git a/packages/standard/game_rule.lua b/packages/standard/game_rule.lua index a1e55575..8b398599 100644 --- a/packages/standard/game_rule.lua +++ b/packages/standard/game_rule.lua @@ -10,4 +10,13 @@ GameRule = fk.CreateTriggerSkill{ return (target == player) or (target == nil) end, + on_trigger = function(self, event, target, player, data) + if player == nil then return false end + local room = player.room + if player.room:askForSkillInvoke(player, self.name) then + -- do something + end + return false + end, + } diff --git a/qml/Pages/Room.qml b/qml/Pages/Room.qml index 3bc290eb..38836f5a 100644 --- a/qml/Pages/Room.qml +++ b/qml/Pages/Room.qml @@ -14,11 +14,13 @@ Item { property bool isStarted: false property alias popupBox: popupBox + property alias promptText: prompt.text // tmp Button { text: "quit" - anchors.bottom: parent.bottom + anchors.top: parent.top + anchors.right: parent.right onClicked: { ClientInstance.clearPlayers(); ClientInstance.notifyServer("QuitRoom", "[]"); @@ -30,22 +32,60 @@ Item { anchors.centerIn: parent } - // For debugging - RowLayout { - visible: Debugging ? true : false - width: parent.width - TextField { - id: lua - Layout.fillWidth: true - text: "print \"Hello world.\"" - } - Button { - text: "DoLuaScript" - onClicked: { - ClientInstance.notifyServer("DoLuaScript", JSON.stringify([lua.text])); + states: [ + State { name: "notactive" }, // Normal status + State { name: "playing" }, // Playing cards in playing phase + State { name: "responding" }, // all requests need to operate dashboard + State { name: "replying" } // requests only operate a popup window + ] + state: "notactive" + transitions: [ + Transition { + from: "*"; to: "notactive" + ScriptAction { + script: { + promptText = ""; + progress.visible = false; + okCancel.visible = false; + endPhaseButton.visible = false; + + if (popupBox.item != null) { + popupBox.item.finished(); + } + } + } + }, + + Transition { + from: "*"; to: "playing" + ScriptAction { + script: { + progress.visible = true; + okCancel.visible = true; + endPhaseButton.visible = true; + } + } + }, + + Transition { + from: "*"; to: "responding" + ScriptAction { + script: { + progress.visible = true; + okCancel.visible = true; + } + } + }, + + Transition { + from: "*"; to: "replying" + ScriptAction { + script: { + progress.visible = true; + } } } - } + ] /* Layout: * +---------------------+ @@ -127,6 +167,74 @@ Item { self.isOwner: dashboardModel.isOwner } + Item { + id: controls + anchors.bottom: dashboard.top + anchors.bottomMargin: -40 + width: roomScene.width + + Text { + id: prompt + visible: progress.visible + anchors.bottom: progress.top + anchors.bottomMargin: 8 + anchors.horizontalCenter: progress.horizontalCenter + } + + ProgressBar { + id: progress + width: parent.width * 0.6 + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: okCancel.top + anchors.bottomMargin: 8 + from: 0.0 + to: 100.0 + + visible: false + NumberAnimation on value { + running: progress.visible + from: 100.0 + to: 0.0 + duration: config.roomTimeout * 1000 + + onFinished: { + roomScene.state = "notactive" + } + } + } + + Row { + id: okCancel + anchors.bottom: parent.bottom + anchors.horizontalCenter: progress.horizontalCenter + spacing: 20 + visible: false + + Button { + id: okButton + text: "OK" + onClicked: Logic.doOkButton(); + } + + Button { + id: cancelButton + text: "Cancel" + onClicked: Logic.doCancelButton(); + } + } + + Button { + id: endPhaseButton + text: "End" + anchors.bottom: parent.bottom + anchors.bottomMargin: 40 + anchors.right: parent.right + anchors.rightMargin: 30 + visible: false; + onClicked: Logic.doCancelButton(); + } + } + Loader { id: popupBox onSourceChanged: { diff --git a/qml/Pages/RoomElement/ChoiceBox.qml b/qml/Pages/RoomElement/ChoiceBox.qml new file mode 100644 index 00000000..ead7e80d --- /dev/null +++ b/qml/Pages/RoomElement/ChoiceBox.qml @@ -0,0 +1,34 @@ +import QtQuick 2.15 +import ".." + +GraphicsBox { + property var options: [] + property string skill_name: "" + property int result + + id: root + title.text: skill_name + ": Please choose" + width: Math.max(140, body.width + 20) + height: body.height + title.height + 20 + + Column { + id: body + x: 10 + y: title.height + 5 + spacing: 10 + + Repeater { + model: options + + MetroButton { + text: modelData + anchors.horizontalCenter: parent.horizontalCenter + + onClicked: { + result = index; + root.close(); + } + } + } + } +} diff --git a/qml/Pages/RoomLogic.js b/qml/Pages/RoomLogic.js index 587f08cd..680e7d9e 100644 --- a/qml/Pages/RoomLogic.js +++ b/qml/Pages/RoomLogic.js @@ -48,6 +48,19 @@ function arrangePhotos() { } } +function doOkButton() { + replyToServer("1"); +} + +function doCancelButton() { + replyToServer(""); +} + +function replyToServer(jsonData) { + roomScene.state = "notactive"; + ClientInstance.replyToServer("", jsonData); +} + callbacks["AddPlayer"] = function(jsonData) { // jsonData: int id, string screenName, string avatar for (let i = 0; i < photoModel.count; i++) { @@ -178,13 +191,38 @@ callbacks["AskForGeneral"] = function(jsonData) { // jsonData: string[] Generals // TODO: choose multiple generals let data = JSON.parse(jsonData); + roomScene.promptText = "Please choose 1 general"; + roomScene.state = "replying"; roomScene.popupBox.source = "RoomElement/ChooseGeneralBox.qml"; let box = roomScene.popupBox.item; box.choiceNum = 1; box.accepted.connect(() => { - ClientInstance.replyToServer("AskForGeneral", JSON.stringify([box.choices[0]])); + replyToServer(JSON.stringify([box.choices[0]])); }); for (let i = 0; i < data.length; i++) box.generalList.append({ "name": data[i] }); box.updatePosition(); } + +callbacks["AskForSkillInvoke"] = function(jsonData) { + // jsonData: string name + roomScene.promptText = "Do you want to invoke '" + jsonData + "' ?"; + roomScene.state = "responding"; +} + +callbacks["AskForChoice"] = function(jsonData) { + // jsonData: [ string[] choices, string skill ] + // TODO: multiple choices, e.g. benxi_ol + let data = JSON.parse(jsonData); + let choices = data[0]; + let skill_name = data[1]; + roomScene.promptText = skill_name + ": Please make choice"; + roomScene.state = "replying"; + roomScene.popupBox.source = "RoomElement/ChoiceBox.qml"; + let box = roomScene.popupBox.item; + box.options = choices; + box.skill_name = skill_name; + box.accepted.connect(() => { + replyToServer(choices[box.result]); + }); +}