Deputy general (#127)

增加双将机制
This commit is contained in:
notify 2023-04-19 14:07:16 +08:00 committed by GitHub
parent 1ad352521f
commit 85923c8a71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 124 additions and 29 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -25,6 +25,7 @@ Fk:loadTranslationTable{
["Select general num"] = "选将数目",
["Game Mode"] = "游戏模式",
["Enable free assign"] = "自由选将",
["Enable deputy general"] = "启用副将机制",
["General Settings"] = "通常设置",
["Package Settings"] = "拓展包设置",
["General Packages"] = "武将拓展包",

View File

@ -14,6 +14,7 @@
---@field public kingdom string @ 势力
---@field public role string @ 身份
---@field public general string @ 武将
---@field public deputyGeneral string @ 副将
---@field public gender integer @ 性别
---@field public seat integer @ 座位号
---@field public next Player @ 下家
@ -67,6 +68,7 @@ function Player:initialize()
self.kingdom = "qun"
self.role = ""
self.general = ""
self.deputyGeneral = ""
self.gender = General.Male
self.seat = 0
self.next = nil

View File

@ -70,6 +70,7 @@ end
function GameLogic:chooseGenerals()
local room = self.room
local generalNum = room.settings.generalNum
local n = room.settings.enableDeputy and 2 or 1
local lord = room:getLord()
local lord_general = nil
if lord ~= nil then
@ -78,9 +79,17 @@ function GameLogic:chooseGenerals()
for i = 1, #generals do
generals[i] = generals[i].name
end
lord_general = room:askForGeneral(lord, generals)
lord_general = room:askForGeneral(lord, generals, n)
local deputy
if type(lord_general) == "table" then
deputy = lord_general[2]
lord_general = lord_general[1]
end
room:setPlayerGeneral(lord, lord_general, true)
room:broadcastProperty(lord, "general")
room:setDeputyGeneral(lord, deputy)
room:broadcastProperty(lord, "deputyGeneral")
end
local nonlord = room:getOtherPlayers(lord, true)
@ -91,18 +100,22 @@ function GameLogic:chooseGenerals()
for i = 1, generalNum do
table.insert(arg, table.remove(generals, 1).name)
end
p.request_data = json.encode(arg)
p.default_reply = arg[1]
p.request_data = json.encode{ arg, n }
p.default_reply = table.random(arg, n)
end
room:notifyMoveFocus(nonlord, "AskForGeneral")
room:doBroadcastRequest("AskForGeneral", nonlord)
for _, p in ipairs(nonlord) do
if p.general == "" and p.reply_ready then
local general = json.decode(p.client_reply)[1]
local generals = json.decode(p.client_reply)
local general = generals[1]
local deputy = generals[2]
room:setPlayerGeneral(p, general, true)
room:setDeputyGeneral(p, deputy)
else
room:setPlayerGeneral(p, p.default_reply, true)
room:setPlayerGeneral(p, p.default_reply[1], true)
room:setDeputyGeneral(p, p.default_reply[2])
end
p.default_reply = ""
end
@ -120,13 +133,16 @@ function GameLogic:prepareForStart()
for _, p in ipairs(players) do
assert(p.general ~= "")
local general = Fk.generals[p.general]
p.maxHp = general.maxHp
p.hp = general.hp
p.shield = general.shield
local deputy = Fk.generals[p.deputyGeneral]
p.maxHp = deputy and math.floor((deputy.maxHp + general.maxHp) / 2)
or general.maxHp
p.hp = deputy and math.floor((deputy.hp + general.hp) / 2) or general.hp
p.shield = math.min(general.shield + (deputy and deputy.shield or 0), 5)
-- TODO: setup AI here
if p.role ~= "lord" then
room:broadcastProperty(p, "general")
room:broadcastProperty(p, "deputyGeneral")
elseif #players >= 5 then
p.maxHp = p.maxHp + 1
p.hp = p.hp + 1
@ -159,6 +175,17 @@ function GameLogic:prepareForStart()
for _, sname in ipairs(Fk.generals[p.general].other_skills) do
addRoleModSkills(p, sname)
end
local deputy = Fk.generals[p.deputyGeneral]
if deputy then
skills = deputy.skills
for _, s in ipairs(skills) do
addRoleModSkills(p, s.name)
end
for _, sname in ipairs(deputy.other_skills) do
addRoleModSkills(p, sname)
end
end
end
self:addTriggerSkill(GameRule)

View File

@ -393,6 +393,14 @@ function Room:setPlayerGeneral(player, general, changeKingdom)
end
end
---@param player ServerPlayer
---@param general string
function Room:setDeputyGeneral(player, general)
if Fk.generals[general] == nil then return end
player.deputyGeneral = general
self:notifyProperty(player, player, "deputyGeneral")
end
------------------------------------------------------------------------
-- 网络通信有关
------------------------------------------------------------------------
@ -1048,22 +1056,24 @@ end
---@param player ServerPlayer @ 询问目标
---@param generals string[] @ 可选武将
---@return string @ 选择的武将
function Room:askForGeneral(player, generals)
function Room:askForGeneral(player, generals, n)
local command = "AskForGeneral"
self:notifyMoveFocus(player, command)
if #generals == 1 then return generals[1] end
local defaultChoice = generals[1]
n = n or 1
if #generals == n then return n == 1 and generals[1] or generals end
local defaultChoice = table.random(generals, n)
if (player.state == "online") then
local result = self:doRequest(player, command, json.encode(generals))
local result = self:doRequest(player, command, json.encode{ generals, n })
local choices
if result == "" then
return defaultChoice
choices = defaultChoice
else
-- TODO: result is a JSON array
-- update here when choose multiple generals
return json.decode(result)[1]
choices = json.decode(result)
end
if #choices == 1 then return choices[1] end
return choices
end
return defaultChoice

View File

@ -85,6 +85,12 @@ ColumnLayout {
text: Backend.translate("Enable free assign")
}
CheckBox {
id: deputyCheck
checked: Debugging ? true : false
text: Backend.translate("Enable deputy general")
}
RowLayout {
anchors.rightMargin: 8
spacing: 16
@ -97,6 +103,7 @@ ColumnLayout {
"CreateRoom",
JSON.stringify([roomName.text, playerNum.value, {
enableFreeAssign: freeAssignCheck.checked,
enableDeputy: deputyCheck.checked,
gameMode: config.preferedMode,
disabledPack: config.disabledPack,
generalNum: config.preferredGeneralNum,

View File

@ -186,6 +186,7 @@ Item {
Photo {
playerid: model.id
general: model.general
deputyGeneral: model.deputyGeneral
screenName: model.screenName
role: model.role
kingdom: model.kingdom
@ -253,6 +254,7 @@ Item {
self.playerid: dashboardModel.id
self.general: dashboardModel.general
self.screenName: dashboardModel.screenName
self.deputyGeneral: dashboardModel.deputyGeneral
self.role: dashboardModel.role
self.kingdom: dashboardModel.kingdom
self.netstate: dashboardModel.netstate
@ -798,6 +800,7 @@ Item {
dashboardModel = {
id: Self.id,
general: Self.avatar,
deputyGeneral: "",
screenName: Self.screenName,
role: "unknown",
kingdom: "qun",
@ -822,6 +825,7 @@ Item {
id: -1,
index: i - 1, // For animating seat swap
general: "",
deputyGeneral: "",
screenName: "",
role: "unknown",
kingdom: "qun",

View File

@ -13,6 +13,7 @@ Item {
scale: 0.75
property int playerid: 0
property string general: ""
property string deputyGeneral: ""
property string screenName: ""
property string role: "unknown"
property string kingdom: "qun"
@ -120,7 +121,7 @@ Item {
y: 28
font.family: fontLibian.name
font.pixelSize: 22
opacity: 0.7
opacity: 0.9
horizontalAlignment: Text.AlignHCenter
lineHeight: 18
lineHeightMode: Text.FixedHeight
@ -138,7 +139,7 @@ Item {
font.pixelSize: 22
rotation: 90
transformOrigin: Item.BottomLeft
opacity: 0.7
opacity: 0.9
horizontalAlignment: Text.AlignHCenter
lineHeight: 18
lineHeightMode: Text.FixedHeight
@ -156,15 +157,55 @@ Item {
anchors.bottomMargin: 36
}
Image {
id: generalImage
Item {
width: 138
height: 222
smooth: true
visible: false
fillMode: Image.PreserveAspectCrop
source: (general != "") ? SkinBank.getGeneralPicture(general) : ""
id: generalImgItem
Image {
id: generalImage
width: deputyGeneral ? parent.width / 2 : parent.width
height: parent.height
smooth: true
fillMode: Image.PreserveAspectCrop
source: (general != "") ? SkinBank.getGeneralPicture(general) : ""
}
Image {
id: deputyGeneralImage
anchors.left: generalImage.right
width: parent.width / 2
height: parent.height
smooth: true
fillMode: Image.PreserveAspectCrop
source: (deputyGeneral != "") ?
SkinBank.getGeneralPicture(deputyGeneral) : ""
}
Image {
id: deputySplit
source: SkinBank.PHOTO_DIR + "deputy-split"
opacity: deputyGeneral ? 1 : 0
}
Text {
id: deputyGeneralName
anchors.left: generalImage.right
anchors.leftMargin: -14
y: 23
font.family: fontLibian.name
font.pixelSize: 22
opacity: 0.9
horizontalAlignment: Text.AlignHCenter
lineHeight: 18
lineHeightMode: Text.FixedHeight
color: "white"
width: 24
wrapMode: Text.WordWrap
text: Backend.translate(deputyGeneral)
style: Text.Outline
}
}
Rectangle {
@ -179,13 +220,13 @@ Item {
OpacityMask {
anchors.fill: photoMask
source: generalImage
source: generalImgItem
maskSource: photoMask
}
Colorize {
anchors.fill: photoMask
source: generalImage
source: generalImgItem
saturation: 0
visible: root.dead
}

View File

@ -564,18 +564,20 @@ callbacks["PlayerRunned"] = function(jsonData) {
callbacks["AskForGeneral"] = function(jsonData) {
// jsonData: string[] Generals
// TODO: choose multiple generals
let data = JSON.parse(jsonData);
let generals = data[0];
let n = data[1];
roomScene.promptText = Backend.translate("#AskForGeneral");
roomScene.state = "replying";
roomScene.popupBox.source = "RoomElement/ChooseGeneralBox.qml";
let box = roomScene.popupBox.item;
box.choiceNum = 1;
box.accepted.connect(() => {
replyToServer(JSON.stringify([box.choices[0]]));
replyToServer(JSON.stringify(box.choices));
});
for (let i = 0; i < data.length; i++)
box.generalList.append({ "name": data[i] });
box.choiceNum = n;
for (let i = 0; i < generals.length; i++)
box.generalList.append({ "name": generals[i] });
box.updatePosition();
}

View File

@ -73,6 +73,7 @@ Server::Server(QObject *parent) : QObject(parent) {
}
Server::~Server() {
isListening = false;
ServerInstance = nullptr;
m_lobby->deleteLater();
sqlite3_close(db);