diff --git a/Fk/Pages/Room.qml b/Fk/Pages/Room.qml index cde31e6b..2e88a42b 100644 --- a/Fk/Pages/Room.qml +++ b/Fk/Pages/Room.qml @@ -82,6 +82,87 @@ Item { ClientInstance.notifyServer("QuitRoom", "[]"); } } + + Menu { + id: menuContainer + x: parent.width - menuButton.width - menuContainer.width - 17 + width: menuRow.width + height: menuRow.height + verticalPadding: 0 + spacing: 7 + z: 2 + + Row { + id: menuRow + spacing: 7 + + Button { + id: surrenderButton + text: Backend.translate("Surrender") + onClicked: { + if (isStarted) { + const surrenderCheck = JSON.parse(Backend.callLuaFunction('CheckSurrenderAvailable', [miscStatus.playedTime])); + if (!surrenderCheck.length) { + surrenderDialog.informativeText = Backend.translate('Surrender is disabled in this mode'); + } else { + surrenderDialog.informativeText = surrenderCheck.map(str => `${Backend.translate(str.text)}(${str.passed ? '√' : '×'})`).join('
'); + } + surrenderDialog.open(); + } + } + } + + MessageDialog { + id: surrenderDialog + title: Backend.translate("Surrender") + informativeText: '' + buttons: MessageDialog.Ok | MessageDialog.Cancel + onButtonClicked: function (button, role) { + switch (button) { + case MessageDialog.Ok: { + const surrenderCheck = JSON.parse(Backend.callLuaFunction('CheckSurrenderAvailable', [miscStatus.playedTime])); + if (surrenderCheck.length && !surrenderCheck.find(check => !check.passed)) { + ClientInstance.notifyServer("PushRequest", [ + "surrender", true + ]); + } + break; + } + case MessageDialog.Cancel: { + surrenderDialog.close(); + } + } + } + } + + Button { + id: quitButton + text: Backend.translate("Quit") + onClicked: { + quitDialog.open(); + } + } + + MessageDialog { + id: quitDialog + title: Backend.translate("Quit") + informativeText: Backend.translate("Are you sure to quit?") + buttons: MessageDialog.Ok | MessageDialog.Cancel + onButtonClicked: function (button, role) { + switch (button) { + case MessageDialog.Ok: { + ClientInstance.notifyServer("QuitRoom", "[]"); + break; + } + case MessageDialog.Cancel: { + quitDialog.close(); + } + } + } + } + } + } + Button { text: Backend.translate("Add Robot") visible: isOwner && !isStarted && !isFull diff --git a/lua/client/i18n/zh_CN.lua b/lua/client/i18n/zh_CN.lua index a34d3575..fe2354c4 100644 --- a/lua/client/i18n/zh_CN.lua +++ b/lua/client/i18n/zh_CN.lua @@ -215,6 +215,12 @@ FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下 ["seat#8"] = "八号位", ["@ControledBy"] = "控制者", + ["Menu"] = "菜单", + ["Surrender"] = "投降", + ["Surrender is disabled in this mode"] = "投降在该模式不可用", + ["Quit"] = "退出", + ["Are you sure to quit?"] = "是否确认退出对局(若对局开始则将计入逃跑次数)?", + ["Trust"] = "托管", ["Sort Cards"] = "牌序", ["Chat"] = "聊天", diff --git a/lua/core/game_mode.lua b/lua/core/game_mode.lua index 695848a2..a613f0ce 100644 --- a/lua/core/game_mode.lua +++ b/lua/core/game_mode.lua @@ -22,4 +22,41 @@ function GameMode:initialize(name, min, max) self.maxPlayer = math.min(max, 8) end +---@param victim ServerPlayer @ 死者 +---@return string @ 胜者阵营 +function GameMode:getWinner(victim) + local room = victim.room + local winner = "" + local alive = table.filter(room.alive_players, function(p) + return not p.surrendered + end) + + if victim.role == "lord" then + if #alive == 1 and alive[1].role == "renegade" then + winner = "renegade" + else + winner = "rebel" + end + elseif victim.role ~= "loyalist" then + local lord_win = true + for _, p in ipairs(alive) do + if p.role == "rebel" or p.role == "renegade" then + lord_win = false + break + end + end + if lord_win then + winner = "lord+loyalist" + end + end + + return winner +end + +---@param playedTime number @ 游戏时长(单位:秒) +---@return table +function GameMode:surrenderFunc(playedTime) + return {} +end + return GameMode diff --git a/packages/standard/init.lua b/packages/standard/init.lua index c57e97af..c02715af 100644 --- a/packages/standard/init.lua +++ b/packages/standard/init.lua @@ -1114,8 +1114,98 @@ local role_mode = fk.CreateGameMode{ name = "aaa_role_mode", -- just to let it at the top of list minPlayer = 2, maxPlayer = 8, + surrender_func = function(self, playedTime) + local roleCheck = false + local roleText = "" + local roleTable = { + { "lord" }, + { "lord", "rebel" }, + { "lord", "rebel", "renegade" }, + { "lord", "loyalist", "rebel", "renegade" }, + { "lord", "loyalist", "rebel", "rebel", "renegade" }, + { "lord", "loyalist", "rebel", "rebel", "rebel", "renegade" }, + { "lord", "loyalist", "loyalist", "rebel", "rebel", "rebel", "renegade" }, + { "lord", "loyalist", "loyalist", "rebel", "rebel", "rebel", "rebel", "renegade" }, + } + + roleTable = roleTable[#Fk:currentRoom().players] + + if Self.role == "renegade" then + roleCheck = #Fk:currentRoom().alive_players == 2 + roleText = "only you and me" + elseif Self.role == "rebel" then + local rebelNum = #table.filter(roleTable, function(role) + return role == "rebel" + end) + + local renegadeDead = not table.find(roleTable, function(role) + return role == "renegade" + end) + for _, p in ipairs(Fk:currentRoom().players) do + if p.role == "renegade" and p.dead then + renegadeDead = true + end + + if p ~= Self and p.role == "rebel" then + if p:isAlive() then + break + else + rebelNum = rebelNum - 1 + end + end + end + + roleCheck = renegadeDead and rebelNum == 1 + roleText = "left one rebel alive" + else + if Self.role == "loyalist" then + return { { text = "loyalist never surrender", passed = false } } + else + if #Fk:currentRoom().alive_players == 2 then + roleCheck = true + else + local lordNum = #table.filter(roleTable, function(role) + return role == "lord" or role == "loyalist" + end) + + local renegadeDead = not table.find(roleTable, function(role) + return role == "renegade" + end) + for _, p in ipairs(Fk:currentRoom().players) do + if p.role == "renegade" and p.dead then + renegadeDead = true + end + + if p ~= Self and (p.role == "lord" or p.role == "loyalist") then + if p:isAlive() then + break + else + lordNum = lordNum - 1 + end + end + end + + roleCheck = renegadeDead and lordNum == 1 + end + end + + roleText = "left you alive" + end + + return { + { text = "time limitation: 5 sec", passed = playedTime >= 5 }, + { text = roleText, passed = roleCheck }, + } + end, } extension:addGameMode(role_mode) +Fk:loadTranslationTable{ + ["time limitation: 5 sec"] = "游戏时长达到5秒(测试用)", + ["only you and me"] = "仅剩你和主公存活", + ["left one rebel alive"] = "反贼仅剩你存活且不存在存活内奸", + ["left you alive"] = "主忠方仅剩你存活且其他阵营仅剩一方", + ["loyalist never surrender"] = "忠臣永不投降!", +} local anjiang = General(extension, "anjiang", "unknown", 5) anjiang.gender = General.Agender