Initial kingdom choosing (#143)
- 实现副势力概念,用于应对双势力机制; - 完善神将及拥有副势力的武将开局选择势力的机制; - 完成势力技概念; - 实现ViewAsSkill在响应时对使用和打出的区分。 --------- Co-authored-by: notify <notify-ctrl@qq.com>
This commit is contained in:
parent
34ce4c9859
commit
19a2cc5ed7
|
@ -13,6 +13,7 @@ function GetGeneralData(name)
|
|||
package = general.package.name,
|
||||
extension = general.package.extensionName,
|
||||
kingdom = general.kingdom,
|
||||
subkingdom = general.subkingdom,
|
||||
hp = general.hp,
|
||||
maxHp = general.maxHp,
|
||||
shield = general.shield,
|
||||
|
@ -323,7 +324,7 @@ function ActiveTargetFilter(skill_name, to_select, selected, selected_cards)
|
|||
elseif skill:isInstanceOf(ViewAsSkill) then
|
||||
local card = skill:viewAs(selected_cards)
|
||||
if card then
|
||||
ret = card.skill:targetFilter(to_select, selected, selected_cards)
|
||||
ret = card.skill:targetFilter(to_select, selected, selected_cards, card)
|
||||
ret = ret and not Self:isProhibited(Fk:currentRoom():getPlayerById(to_select), card)
|
||||
end
|
||||
end
|
||||
|
@ -402,11 +403,11 @@ function CardProhibitedResponse(cid)
|
|||
return json.encode(ret)
|
||||
end
|
||||
|
||||
function SkillCanResponse(skill_name)
|
||||
function SkillCanResponse(skill_name, cardResponsing)
|
||||
local skill = Fk.skills[skill_name]
|
||||
local ret = false
|
||||
if skill and skill:isInstanceOf(ViewAsSkill) then
|
||||
ret = skill:enabledAtResponse(Self)
|
||||
ret = skill:enabledAtResponse(Self, cardResponsing)
|
||||
end
|
||||
return json.encode(ret)
|
||||
end
|
||||
|
|
|
@ -139,6 +139,7 @@ FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下
|
|||
["AskForGeneral"] = "选择武将",
|
||||
["AskForGuanxing"] = "观星",
|
||||
["AskForChoice"] = "选择",
|
||||
["AskForKingdom"] = "选择势力",
|
||||
["AskForPindian"] = "拼点",
|
||||
["PlayCard"] = "出牌",
|
||||
|
||||
|
@ -164,6 +165,8 @@ FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下
|
|||
["pindianwin"] = "赢",
|
||||
["pindiannotwin"] = "没赢",
|
||||
|
||||
["#ChooseInitialKingdom"] = "请选择初始势力(不可变更)",
|
||||
|
||||
["#RevealGeneral"] = "%from 亮出 %arg %arg2",
|
||||
["mainGeneral"] = "主将",
|
||||
["deputyGeneral"] = "副将",
|
||||
|
|
|
@ -50,6 +50,7 @@ function Engine:initialize()
|
|||
self.translations = {} -- srcText --> translated
|
||||
self.game_modes = {}
|
||||
self.disabled_packs = {}
|
||||
self.kingdoms = {}
|
||||
|
||||
self:loadPackages()
|
||||
self:addSkills(AuxSkills)
|
||||
|
@ -182,6 +183,10 @@ function Engine:addGeneral(general)
|
|||
end
|
||||
self.generals[general.name] = general
|
||||
|
||||
if general.kingdom ~= "unknown" then
|
||||
table.insertIfNeed(self.kingdoms, general.kingdom)
|
||||
end
|
||||
|
||||
if general.name ~= general.trueName then
|
||||
local tName = general.trueName
|
||||
self.same_generals[tName] = self.same_generals[tName] or { tName }
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
---@field public name string @ 武将名字
|
||||
---@field public trueName string @ 武将真名,也许可以分辨标界?
|
||||
---@field public kingdom string @ 武将所属势力
|
||||
---@field public subkingdom string @ 武将副势力
|
||||
---@field public hp integer @ 武将初始体力
|
||||
---@field public maxHp integer @ 武将初始最大体力
|
||||
---@field public shield integer @ 初始护甲
|
||||
|
@ -48,6 +49,7 @@ function General:initialize(package, name, kingdom, hp, maxHp, gender)
|
|||
self.maxHp = maxHp or hp
|
||||
self.gender = gender or General.Male
|
||||
self.shield = 0
|
||||
self.subkingdom = nil
|
||||
|
||||
self.skills = {} -- skills first added to this general
|
||||
self.other_skills = {} -- skill belongs other general, e.g. "mashu" of pangde
|
||||
|
|
|
@ -38,6 +38,7 @@ function Skill:initialize(name, frequency)
|
|||
self.mute = false
|
||||
self.anim_type = ""
|
||||
self.related_skills = {}
|
||||
self.attachedKingdom = {}
|
||||
|
||||
local name_splited = name:split("__")
|
||||
self.trueName = name_splited[#name_splited]
|
||||
|
@ -85,4 +86,8 @@ function Skill:isEffectable(player)
|
|||
return true
|
||||
end
|
||||
|
||||
function Skill:addAttachedKingdom(kingdom)
|
||||
table.insertIfNeed(self.attachedKingdom, kingdom)
|
||||
end
|
||||
|
||||
return Skill
|
||||
|
|
|
@ -31,8 +31,12 @@ function ViewAsSkill:enabledAtPlay(player)
|
|||
end
|
||||
|
||||
---@param player Player
|
||||
function ViewAsSkill:enabledAtResponse(player)
|
||||
function ViewAsSkill:enabledAtResponse(player, cardResponsing)
|
||||
return player:hasSkill(self)
|
||||
end
|
||||
|
||||
---@param player Player
|
||||
---@param cardUseStruct CardUseStruct
|
||||
function ViewAsSkill:beforeUse(player, cardUseStruct) end
|
||||
|
||||
return ViewAsSkill
|
||||
|
|
|
@ -161,7 +161,11 @@ function fk.CreateActiveSkill(spec)
|
|||
local skill = ActiveSkill:new(spec.name, spec.frequency or Skill.NotFrequent)
|
||||
readUsableSpecToSkill(skill, spec)
|
||||
|
||||
if spec.can_use then skill.canUse = spec.can_use end
|
||||
if spec.can_use then
|
||||
skill.canUse = function(curSkill, player)
|
||||
return spec.can_use(curSkill, player) and curSkill:isEffectable(player)
|
||||
end
|
||||
end
|
||||
if spec.card_filter then skill.cardFilter = spec.card_filter end
|
||||
if spec.target_filter then skill.targetFilter = spec.target_filter end
|
||||
if spec.feasible then
|
||||
|
@ -193,6 +197,7 @@ end
|
|||
---@field public pattern string
|
||||
---@field public enabled_at_play fun(self: ViewAsSkill, player: Player): boolean
|
||||
---@field public enabled_at_response fun(self: ViewAsSkill, player: Player): boolean
|
||||
---@field public before_use fun(self: ViewAsSkill, player: Player)
|
||||
|
||||
---@param spec ViewAsSkillSpec
|
||||
---@return ViewAsSkill
|
||||
|
@ -211,10 +216,14 @@ function fk.CreateViewAsSkill(spec)
|
|||
skill.pattern = spec.pattern
|
||||
end
|
||||
if type(spec.enabled_at_play) == "function" then
|
||||
skill.enabledAtPlay = spec.enabled_at_play
|
||||
skill.enabledAtPlay = function(curSkill, player)
|
||||
return spec.enabled_at_play(curSkill, player) and curSkill:isEffectable(player)
|
||||
end
|
||||
end
|
||||
if type(spec.enabled_at_response) == "function" then
|
||||
skill.enabledAtResponse = spec.enabled_at_response
|
||||
skill.enabledAtResponse = function(curSkill, player, cardResponsing)
|
||||
return spec.enabled_at_response(curSkill, player, cardResponsing) and curSkill:isEffectable(player)
|
||||
end
|
||||
end
|
||||
|
||||
if spec.interaction then
|
||||
|
@ -229,6 +238,10 @@ function fk.CreateViewAsSkill(spec)
|
|||
})
|
||||
end
|
||||
|
||||
if spec.before_use and type(spec.before_use) == "function" then
|
||||
skill.beforeUse = spec.before_use
|
||||
end
|
||||
|
||||
return skill
|
||||
end
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
fk.NonTrigger = 1
|
||||
fk.GameStart = 2
|
||||
fk.TurnStart = 3
|
||||
fk.TurnEnd = 72
|
||||
fk.TurnEnd = 73
|
||||
fk.EventPhaseStart = 4
|
||||
fk.EventPhaseProceeding = 5
|
||||
fk.EventPhaseEnd = 6
|
||||
|
@ -81,18 +81,19 @@ fk.AskForPeaches = 59
|
|||
fk.AskForPeachesDone = 60
|
||||
fk.Death = 61
|
||||
fk.BuryVictim = 62
|
||||
fk.BeforeGameOverJudge = 63
|
||||
fk.GameOverJudge = 64
|
||||
fk.GameFinished = 65
|
||||
fk.Deathed = 63
|
||||
fk.BeforeGameOverJudge = 64
|
||||
fk.GameOverJudge = 65
|
||||
fk.GameFinished = 66
|
||||
|
||||
fk.AskForCardUse = 66
|
||||
fk.AskForCardResponse = 67
|
||||
fk.AskForCardUse = 67
|
||||
fk.AskForCardResponse = 68
|
||||
|
||||
fk.StartPindian = 68
|
||||
fk.PindianCardsDisplayed = 69
|
||||
fk.PindianResultConfirmed = 70
|
||||
fk.PindianFinished = 71
|
||||
fk.StartPindian = 69
|
||||
fk.PindianCardsDisplayed = 70
|
||||
fk.PindianResultConfirmed = 71
|
||||
fk.PindianFinished = 72
|
||||
|
||||
-- 72 = TurnEnd
|
||||
-- 73 = TurnEnd
|
||||
|
||||
fk.NumOfEvents = 72
|
||||
fk.NumOfEvents = 74
|
||||
|
|
|
@ -66,4 +66,6 @@ GameEvent.functions[GameEvent.Death] = function(self)
|
|||
logic:trigger(fk.GameOverJudge, victim, deathStruct)
|
||||
logic:trigger(fk.Death, victim, deathStruct)
|
||||
logic:trigger(fk.BuryVictim, victim, deathStruct)
|
||||
|
||||
logic:trigger(fk.Deathed, victim, deathStruct)
|
||||
end
|
||||
|
|
|
@ -83,6 +83,7 @@ function GameLogic:chooseGenerals()
|
|||
local n = room.settings.enableDeputy and 2 or 1
|
||||
local lord = room:getLord()
|
||||
local lord_general = nil
|
||||
|
||||
if lord ~= nil then
|
||||
room.current = lord
|
||||
local generals = Fk:getGeneralsRandomly(generalNum)
|
||||
|
@ -97,6 +98,23 @@ function GameLogic:chooseGenerals()
|
|||
end
|
||||
|
||||
room:setPlayerGeneral(lord, lord_general, true)
|
||||
if lord.kingdom == "god" or Fk.generals[lord_general].subkingdom then
|
||||
local allKingdoms = {}
|
||||
if lord.kingdom == "god" then
|
||||
allKingdoms = table.simpleClone(Fk.kingdoms)
|
||||
|
||||
local exceptedKingdoms = { "god" }
|
||||
for _, kingdom in ipairs(exceptedKingdoms) do
|
||||
table.removeOne(allKingdoms, kingdom)
|
||||
end
|
||||
else
|
||||
local curGeneral = Fk.generals[lord_general]
|
||||
allKingdoms = { curGeneral.kingdom, curGeneral.subkingdom }
|
||||
end
|
||||
|
||||
lord.kingdom = room:askForChoice(lord, allKingdoms, "AskForKingdom", "#ChooseInitialKingdom")
|
||||
room:broadcastProperty(lord, "kingdom")
|
||||
end
|
||||
room:broadcastProperty(lord, "general")
|
||||
room:setDeputyGeneral(lord, deputy)
|
||||
room:broadcastProperty(lord, "deputyGeneral")
|
||||
|
@ -116,19 +134,62 @@ function GameLogic:chooseGenerals()
|
|||
|
||||
room:notifyMoveFocus(nonlord, "AskForGeneral")
|
||||
room:doBroadcastRequest("AskForGeneral", nonlord)
|
||||
|
||||
for _, p in ipairs(nonlord) do
|
||||
if p.general == "" and p.reply_ready then
|
||||
local generals = json.decode(p.client_reply)
|
||||
local general = generals[1]
|
||||
local deputy = generals[2]
|
||||
room:setPlayerGeneral(p, general, true)
|
||||
room:setPlayerGeneral(p, general, true, true)
|
||||
room:setDeputyGeneral(p, deputy)
|
||||
else
|
||||
room:setPlayerGeneral(p, p.default_reply[1], true)
|
||||
room:setPlayerGeneral(p, p.default_reply[1], true, true)
|
||||
room:setDeputyGeneral(p, p.default_reply[2])
|
||||
end
|
||||
p.default_reply = ""
|
||||
end
|
||||
|
||||
local specialKingdomPlayers = table.filter(nonlord, function(p)
|
||||
return p.kingdom == "god" or Fk.generals[p.general].subkingdom
|
||||
end)
|
||||
|
||||
if #specialKingdomPlayers > 0 then
|
||||
local choiceMap = {}
|
||||
for _, p in ipairs(specialKingdomPlayers) do
|
||||
local allKingdoms = {}
|
||||
if p.kingdom == "god" then
|
||||
allKingdoms = table.simpleClone(Fk.kingdoms)
|
||||
|
||||
local exceptedKingdoms = { "god" }
|
||||
for _, kingdom in ipairs(exceptedKingdoms) do
|
||||
table.removeOne(allKingdoms, kingdom)
|
||||
end
|
||||
else
|
||||
local curGeneral = Fk.generals[p.general]
|
||||
allKingdoms = { curGeneral.kingdom, curGeneral.subkingdom }
|
||||
end
|
||||
|
||||
choiceMap[p.id] = allKingdoms
|
||||
|
||||
local data = json.encode({ allKingdoms, "AskForKingdom", "#ChooseInitialKingdom" })
|
||||
p.request_data = data
|
||||
end
|
||||
|
||||
room:notifyMoveFocus(nonlord, "AskForKingdom")
|
||||
room:doBroadcastRequest("AskForChoice", specialKingdomPlayers)
|
||||
|
||||
for _, p in ipairs(specialKingdomPlayers) do
|
||||
local kingdomChosen
|
||||
if p.reply_ready then
|
||||
kingdomChosen = p.client_reply
|
||||
else
|
||||
kingdomChosen = choiceMap[p.id][1]
|
||||
end
|
||||
|
||||
p.kingdom = kingdomChosen
|
||||
room:notifyProperty(p, p, "kingdom")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function GameLogic:buildPlayerCircle()
|
||||
|
@ -157,6 +218,7 @@ function GameLogic:broadcastGeneral()
|
|||
|
||||
if p.role ~= "lord" then
|
||||
room:broadcastProperty(p, "general")
|
||||
room:broadcastProperty(p, "kingdom")
|
||||
room:broadcastProperty(p, "deputyGeneral")
|
||||
elseif #players >= 5 then
|
||||
p.maxHp = p.maxHp + 1
|
||||
|
@ -188,6 +250,10 @@ function GameLogic:attachSkillToPlayers()
|
|||
return
|
||||
end
|
||||
|
||||
if #skill.attachedKingdom > 0 and not table.contains(skill.attachedKingdom, player.kingdom) then
|
||||
return
|
||||
end
|
||||
|
||||
room:handleAddLoseSkills(player, skillName, nil, false)
|
||||
end
|
||||
for _, p in ipairs(room.alive_players) do
|
||||
|
|
|
@ -427,7 +427,8 @@ end
|
|||
---@param player ServerPlayer
|
||||
---@param general string
|
||||
---@param changeKingdom boolean
|
||||
function Room:setPlayerGeneral(player, general, changeKingdom)
|
||||
---@param noBroadcast boolean|null
|
||||
function Room:setPlayerGeneral(player, general, changeKingdom, noBroadcast)
|
||||
if Fk.generals[general] == nil then return end
|
||||
player.general = general
|
||||
player.gender = Fk.generals[general].gender
|
||||
|
@ -436,8 +437,12 @@ function Room:setPlayerGeneral(player, general, changeKingdom)
|
|||
|
||||
if changeKingdom then
|
||||
player.kingdom = Fk.generals[general].kingdom
|
||||
if noBroadcast then
|
||||
self:notifyProperty(player, player, "kingdom")
|
||||
else
|
||||
self:broadcastProperty(player, "kingdom")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param player ServerPlayer
|
||||
|
@ -1303,6 +1308,7 @@ function Room:handleUseCardReply(player, data)
|
|||
local c = skill:viewAs(selected_cards)
|
||||
if c then
|
||||
self:useSkill(player, skill)
|
||||
|
||||
local use = {} ---@type CardUseStruct
|
||||
use.from = player.id
|
||||
use.tos = {}
|
||||
|
@ -1313,6 +1319,8 @@ function Room:handleUseCardReply(player, data)
|
|||
use.tos = nil
|
||||
end
|
||||
use.card = c
|
||||
|
||||
skill:beforeUse(player, use)
|
||||
return use
|
||||
end
|
||||
end
|
||||
|
@ -2399,6 +2407,7 @@ function Room:useSkill(player, skill, effect_cb)
|
|||
end
|
||||
end
|
||||
player:addSkillUseHistory(skill.name)
|
||||
|
||||
if effect_cb then
|
||||
return execGameEvent(GameEvent.SkillEffect, effect_cb)
|
||||
end
|
||||
|
|
|
@ -601,7 +601,7 @@ end
|
|||
---@param initialCard Card
|
||||
---@return PindianStruct
|
||||
function ServerPlayer:pindian(tos, skillName, initialCard)
|
||||
local pindianData = { from = self, tos = tos, reson = skillName, fromCard = initialCard, results = {} }
|
||||
local pindianData = { from = self, tos = tos, reason = skillName, fromCard = initialCard, results = {} }
|
||||
self.room:pindian(pindianData)
|
||||
return pindianData
|
||||
end
|
||||
|
|
|
@ -145,7 +145,7 @@ Item {
|
|||
script: {
|
||||
skillInteraction.source = "";
|
||||
dashboard.enableCards(responding_card);
|
||||
dashboard.enableSkills(responding_card);
|
||||
dashboard.enableSkills(responding_card, respond_play);
|
||||
autoPending = false;
|
||||
progress.visible = true;
|
||||
okCancel.visible = true;
|
||||
|
|
|
@ -346,13 +346,13 @@ RowLayout {
|
|||
}
|
||||
}
|
||||
|
||||
function enableSkills(cname) {
|
||||
function enableSkills(cname, cardResponsing) {
|
||||
if (cname) {
|
||||
// if cname is presented, we are responding use or play.
|
||||
for (let i = 0; i < skillButtons.count; i++) {
|
||||
let item = skillButtons.itemAt(i);
|
||||
let fitpattern = JSON.parse(Backend.callLuaFunction("SkillFitPattern", [item.orig, cname]));
|
||||
let canresp = JSON.parse(Backend.callLuaFunction("SkillCanResponse", [item.orig]));
|
||||
let canresp = JSON.parse(Backend.callLuaFunction("SkillCanResponse", [item.orig, cardResponsing]));
|
||||
item.enabled = fitpattern && canresp;
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import QtQuick
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import "PhotoElement"
|
||||
import "../skin-bank.js" as SkinBank
|
||||
|
||||
|
@ -17,6 +18,7 @@ import "../skin-bank.js" as SkinBank
|
|||
|
||||
CardItem {
|
||||
property string kingdom
|
||||
property string subkingdom: "wei"
|
||||
property int hp
|
||||
property int maxHp
|
||||
property int shieldNum
|
||||
|
@ -34,9 +36,17 @@ CardItem {
|
|||
}
|
||||
|
||||
Image {
|
||||
scale: subkingdom ? 0.6 : 1
|
||||
transformOrigin: Item.TopLeft
|
||||
source: SkinBank.getGeneralCardDir(kingdom) + kingdom
|
||||
}
|
||||
|
||||
Image {
|
||||
scale: 0.6; x: 9; y: 12
|
||||
transformOrigin: Item.TopLeft
|
||||
source: subkingdom ? SkinBank.getGeneralCardDir(subkingdom) + subkingdom : ""
|
||||
}
|
||||
|
||||
Row {
|
||||
x: 34
|
||||
y: 4
|
||||
|
@ -44,9 +54,33 @@ CardItem {
|
|||
Repeater {
|
||||
id: hpRepeater
|
||||
model: (hp > 5 || hp !== maxHp) ? 1 : hp
|
||||
Item {
|
||||
width: childrenRect.width
|
||||
height: childrenRect.height
|
||||
Image {
|
||||
source: SkinBank.getGeneralCardDir(kingdom) + kingdom + "-magatama"
|
||||
}
|
||||
Image {
|
||||
id: subkingdomMagatama
|
||||
visible: false
|
||||
source: subkingdom ? SkinBank.getGeneralCardDir(subkingdom) + subkingdom + "-magatama" : ""
|
||||
}
|
||||
LinearGradient {
|
||||
id: subkingdomMask
|
||||
visible: false
|
||||
anchors.fill: subkingdomMagatama
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0.35; color: "transparent" }
|
||||
GradientStop { position: 0.50; color: "white" }
|
||||
}
|
||||
}
|
||||
OpacityMask {
|
||||
anchors.fill: subkingdomMagatama
|
||||
source: subkingdomMagatama
|
||||
maskSource: subkingdomMask
|
||||
visible: subkingdom
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
|
@ -123,6 +157,7 @@ CardItem {
|
|||
onNameChanged: {
|
||||
let data = JSON.parse(Backend.callLuaFunction("GetGeneralData", [name]));
|
||||
kingdom = data.kingdom;
|
||||
subkingdom = (data.subkingdom !== kingdom && data.subkingdom) || "";
|
||||
hp = data.hp;
|
||||
maxHp = data.maxHp;
|
||||
shieldNum = data.shield;
|
||||
|
|
Loading…
Reference in New Issue