多后缀与bugFix (#321)

- 正式添加对多后缀标记的支持
- 添加了一点注释
- 搬运了moveCardIntoEquip和canMoveCardIntoEquip
- 为选牌的默认prompt添加了目标
- 完善了朱雀羽扇的判定
- 修复了抽选武将牌堆时未删除已选武将的bug
- 修复了maxCard标记不识别“-turn”以外标记的bug
- 修复了obtaincard实际不能接受id数组的bug
This commit is contained in:
YoumuKon 2024-02-27 02:27:59 +08:00 committed by GitHub
parent 6fbaf9d055
commit 380ca120e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 307 additions and 131 deletions

View File

@ -1107,7 +1107,7 @@ callbacks["AskForCardChosen"] = (jsonData) => {
const reason = data._reason; const reason = data._reason;
const prompt = data._prompt; const prompt = data._prompt;
if (prompt === "") { if (prompt === "") {
roomScene.promptText = luatr("#AskForChooseCard") roomScene.promptText = luatr(processPrompt("#AskForChooseCard:" + data._id))
.arg(luatr(reason)); .arg(luatr(reason));
} else { } else {
roomScene.setPrompt(processPrompt(prompt), true); roomScene.setPrompt(processPrompt(prompt), true);
@ -1139,7 +1139,7 @@ callbacks["AskForCardsChosen"] = (jsonData) => {
const reason = data._reason; const reason = data._reason;
const prompt = data._prompt; const prompt = data._prompt;
if (prompt === "") { if (prompt === "") {
roomScene.promptText = luatr("#AskForChooseCards") roomScene.promptText = luatr(processPrompt("#AskForChooseCards:" + data._id))
.arg(luatr(reason)).arg(min).arg(max); .arg(luatr(reason)).arg(min).arg(max);
} else { } else {
roomScene.setPrompt(processPrompt(prompt), true); roomScene.setPrompt(processPrompt(prompt), true);

View File

@ -378,6 +378,7 @@ fk.client_callback["AskForCardChosen"] = function(jsonData)
judge = {} judge = {}
end end
ui_data = { ui_data = {
_id = id,
_reason = reason, _reason = reason,
card_data = {}, card_data = {},
_prompt = prompt, _prompt = prompt,
@ -413,6 +414,7 @@ fk.client_callback["AskForCardsChosen"] = function(jsonData)
judge = {} judge = {}
end end
ui_data = { ui_data = {
_id = id,
_min = min, _min = min,
_max = max, _max = max,
_reason = reason, _reason = reason,

View File

@ -185,12 +185,13 @@ Fk:loadTranslationTable({
["AskForKingdom"] = "Choosing kingdom", ["AskForKingdom"] = "Choosing kingdom",
["AskForPindian"] = "Point fight", ["AskForPindian"] = "Point fight",
["AskForMoveCardInBoard"] = "Moving cards", ["AskForMoveCardInBoard"] = "Moving cards",
["replaceEquip"] = "Replacing Equip",
["PlayCard"] = "Playing card", ["PlayCard"] = "Playing card",
["AskForCardChosen"] = "Choosing card", ["AskForCardChosen"] = "Choosing card",
["AskForCardsChosen"] = "Choosing card", ["AskForCardsChosen"] = "Choosing card",
["#AskForChooseCard"] = "%1: please choose a card", ["#AskForChooseCard"] = "%1: please choose a card from %src",
["#AskForChooseCards"] = "%1: please choose %2~%3 cards", ["#AskForChooseCards"] = "%1: please choose %2~%3 cards from %src",
["$ChooseCard"] = "Choose a card", ["$ChooseCard"] = "Choose a card",
["$ChooseCards"] = "Choose %1~%2 cards", ["$ChooseCards"] = "Choose %1~%2 cards",
["$Hand"] = "Hand", ["$Hand"] = "Hand",
@ -209,6 +210,7 @@ Fk:loadTranslationTable({
["#AskForCard"] = "Please choose %arg cards (%arg2 at least)", ["#AskForCard"] = "Please choose %arg cards (%arg2 at least)",
["#AskForDistribution"] = "Please distribute cards (%arg at least , %arg2 total)", ["#AskForDistribution"] = "Please distribute cards (%arg at least , %arg2 total)",
["@DistributionTo"] = "", ["@DistributionTo"] = "",
["#replaceEquip"] = "Please Choose a Equip Card to be replaced",
["#askForPindian"] = "%arg: please choose a hand card for point fight", ["#askForPindian"] = "%arg: please choose a hand card for point fight",
["#StartPindianReason"] = "%from started point fight (%arg)", ["#StartPindianReason"] = "%from started point fight (%arg)",
["#ShowPindianCard"] = "The point fight card of %from is %card", ["#ShowPindianCard"] = "The point fight card of %from is %card",

View File

@ -239,12 +239,13 @@ FreeKill使用的是libgit2的C API与此同时使用Git完成拓展包的下
["AskForKingdom"] = "选择势力", ["AskForKingdom"] = "选择势力",
["AskForPindian"] = "拼点", ["AskForPindian"] = "拼点",
["AskForMoveCardInBoard"] = "移动卡牌", ["AskForMoveCardInBoard"] = "移动卡牌",
["replaceEquip"] = "替换装备",
["PlayCard"] = "出牌", ["PlayCard"] = "出牌",
["AskForCardChosen"] = "选牌", ["AskForCardChosen"] = "选牌",
["AskForCardsChosen"] = "选牌", ["AskForCardsChosen"] = "选牌",
["#AskForChooseCard"] = "%1请选择一张卡牌", ["#AskForChooseCard"] = "%1请选择%src的一张卡牌",
["#AskForChooseCards"] = "%1请选择%2至%3张卡牌", ["#AskForChooseCards"] = "%1请选择%src的%2至%3张卡牌",
["$ChooseCard"] = "请选择一张卡牌", ["$ChooseCard"] = "请选择一张卡牌",
["$ChooseCards"] = "请选择%1至%2张卡牌", ["$ChooseCards"] = "请选择%1至%2张卡牌",
["$Hand"] = "手牌区", ["$Hand"] = "手牌区",
@ -263,6 +264,7 @@ FreeKill使用的是libgit2的C API与此同时使用Git完成拓展包的下
["#AskForCard"] = "请选择 %arg 张牌,最少 %arg2 张", ["#AskForCard"] = "请选择 %arg 张牌,最少 %arg2 张",
["#AskForDistribution"] = "请分配这些牌,至少 %arg 张,至多 %arg2 张", ["#AskForDistribution"] = "请分配这些牌,至少 %arg 张,至多 %arg2 张",
["@DistributionTo"] = "", ["@DistributionTo"] = "",
["#replaceEquip"] = "选择一张装备牌替换之",
["#askForPindian"] = "%arg请选择一张手牌作为拼点牌", ["#askForPindian"] = "%arg请选择一张手牌作为拼点牌",
["#StartPindianReason"] = "%from 由于 %arg 而发起拼点", ["#StartPindianReason"] = "%from 由于 %arg 而发起拼点",
["#ShowPindianCard"] = "%from 的拼点牌是 %card", ["#ShowPindianCard"] = "%from 的拼点牌是 %card",

View File

@ -71,7 +71,7 @@ function General:__tostring()
end end
--- 为武将增加技能,需要注意增加其他武将技能时的处理方式。 --- 为武将增加技能,需要注意增加其他武将技能时的处理方式。
---@param skill Skill @ (单个)武将技能 ---@param skill Skill|string @ (单个)武将技能
function General:addSkill(skill) function General:addSkill(skill)
if (type(skill) == "string") then if (type(skill) == "string") then
table.insert(self.other_skills, skill) table.insert(self.other_skills, skill)
@ -82,7 +82,7 @@ function General:addSkill(skill)
end end
--- 为武将增加相关技能,需要注意增加其他武将技能时的处理方式。 --- 为武将增加相关技能,需要注意增加其他武将技能时的处理方式。
---@param skill Skill @ (单个)武将技能 ---@param skill Skill|string @ (单个)武将技能
function General:addRelatedSkill(skill) function General:addRelatedSkill(skill)
if (type(skill) == "string") then if (type(skill) == "string") then
table.insert(self.related_other_skills, skill) table.insert(self.related_other_skills, skill)

View File

@ -475,9 +475,17 @@ end
--- 获取角色是否被移除。 --- 获取角色是否被移除。
function Player:isRemoved() function Player:isRemoved()
return self:getMark(MarkEnum.PlayerRemoved) ~= 0 or table.find(MarkEnum.TempMarkSuffix, function(s) for mark, _ in pairs(self.mark) do
return self:getMark(MarkEnum.PlayerRemoved .. s) ~= 0 if mark == MarkEnum.PlayerRemoved then return true end
end) if mark:startsWith(MarkEnum.PlayerRemoved .. "-") then
for _, suffix in ipairs(MarkEnum.TempMarkSuffix) do
if mark:find(suffix, 1, true) then return true end
end
end
end
-- return self:getMark(MarkEnum.PlayerRemoved) ~= 0 or table.find(MarkEnum.TempMarkSuffix, function(s)
-- return self:getMark(MarkEnum.PlayerRemoved .. s) ~= 0
-- end)
end end
--- 修改玩家与其他角色的固定距离。 --- 修改玩家与其他角色的固定距离。
@ -950,13 +958,21 @@ function Player:prohibitReveal(isDeputy)
if type(self:getMark(MarkEnum.RevealProhibited)) == "table" and table.contains(self:getMark(MarkEnum.RevealProhibited), place) then if type(self:getMark(MarkEnum.RevealProhibited)) == "table" and table.contains(self:getMark(MarkEnum.RevealProhibited), place) then
return true return true
end end
for _, m in ipairs(table.map(MarkEnum.TempMarkSuffix, function(s)
return self:getMark(MarkEnum.RevealProhibited .. s) for mark, value in pairs(self.mark) do
end)) do if mark:startsWith(MarkEnum.RevealProhibited .. "-") and type(value) == "table" then
if type(m) == "table" and table.contains(m, place) then for _, suffix in ipairs(MarkEnum.TempMarkSuffix) do
return true if mark:find(suffix, 1, true) then return true end
end end
end end
end
-- for _, m in ipairs(table.map(MarkEnum.TempMarkSuffix, function(s)
-- return self:getMark(MarkEnum.RevealProhibited .. s)
-- end)) do
-- if type(m) == "table" and table.contains(m, place) then
-- return true
-- end
-- end
return false return false
end end
@ -981,6 +997,21 @@ function Player:canPindian(to, ignoreFromKong, ignoreToKong)
return true return true
end end
--- 判断一张牌能否移动至某角色的装备区
---@param cardId integer @ 移动的牌
---@param convert? boolean @ 是否可以替换装备(默认可以)
---@return boolean
function Player:canMoveCardIntoEquip(cardId, convert)
convert = (convert == nil) and true or convert
local card = Fk:getCardById(cardId)
if not (card.sub_type >= 3 and card.sub_type <= 7) then return false end
if self.dead or table.contains(self:getCardIds("e"), cardId) then return false end
if self:hasEmptyEquipSlot(card.sub_type) or (#self:getEquipments(card.sub_type) > 0 and convert) then
return true
end
return false
end
--转换技状态阳 --转换技状态阳
fk.SwitchYang = 0 fk.SwitchYang = 0
--转换技状态阴 --转换技状态阴

View File

@ -155,21 +155,38 @@ function ActiveSkill:withinDistanceLimit(player, isattack, card, to)
local temp_suf = table.simpleClone(MarkEnum.TempMarkSuffix) local temp_suf = table.simpleClone(MarkEnum.TempMarkSuffix)
local card_temp_suf = table.simpleClone(MarkEnum.CardTempMarkSuffix) local card_temp_suf = table.simpleClone(MarkEnum.CardTempMarkSuffix)
table.insert(temp_suf, 1, "")
table.insert(temp_suf, "-tmp") ---@param object Card|Player
table.insert(card_temp_suf, 1, "") ---@param markname string
---@param suffixes string[]
---@return boolean
local function hasMark(object, markname, suffixes)
if not object then return false end
for mark, _ in pairs(object.mark) do
if mark == markname then return true end
if mark:startsWith(markname .. "-") then
for _, suffix in ipairs(suffixes) do
if mark:find(suffix, 1, true) then return true end
end
end
end
return false
end
return (isattack and player:inMyAttackRange(to)) or return (isattack and player:inMyAttackRange(to)) or
(player:distanceTo(to) > 0 and player:distanceTo(to) <= self:getDistanceLimit(player, card, to)) or (player:distanceTo(to) > 0 and player:distanceTo(to) <= self:getDistanceLimit(player, card, to)) or
(card and table.find(card_temp_suf, function(s) hasMark(card, MarkEnum.BypassDistancesLimit, card_temp_suf) or
return card:getMark(MarkEnum.BypassDistancesLimit .. s) ~= 0 hasMark(player, MarkEnum.BypassDistancesLimit, temp_suf) or
end)) or hasMark(to, MarkEnum.BypassDistancesLimitTo, temp_suf)
(table.find(temp_suf, function(s) -- (card and table.find(card_temp_suf, function(s)
return player:getMark(MarkEnum.BypassDistancesLimit .. s) ~= 0 -- return card:getMark(MarkEnum.BypassDistancesLimit .. s) ~= 0
end)) or -- end)) or
(to and (table.find(temp_suf, function(s) -- (table.find(temp_suf, function(s)
return to:getMark(MarkEnum.BypassDistancesLimitTo .. s) ~= 0 -- return player:getMark(MarkEnum.BypassDistancesLimit .. s) ~= 0
end))) -- end)) or
-- (to and (table.find(temp_suf, function(s)
-- return to:getMark(MarkEnum.BypassDistancesLimitTo .. s) ~= 0
-- end)))
end end
--- Determine if selected cards and targets are valid for this skill --- Determine if selected cards and targets are valid for this skill

View File

@ -40,20 +40,37 @@ function UsableSkill:withinTimesLimit(player, scope, card, card_name, to)
card_name = card_name or card.trueName card_name = card_name or card.trueName
local temp_suf = table.simpleClone(MarkEnum.TempMarkSuffix) local temp_suf = table.simpleClone(MarkEnum.TempMarkSuffix)
local card_temp_suf = table.simpleClone(MarkEnum.CardTempMarkSuffix) local card_temp_suf = table.simpleClone(MarkEnum.CardTempMarkSuffix)
table.insert(temp_suf, 1, "")
table.insert(temp_suf, "-tmp") ---@param object Card|Player
table.insert(card_temp_suf, 1, "") ---@param markname string
---@param suffixes string[]
---@return boolean
local function hasMark(object, markname, suffixes)
if not object then return false end
for mark, _ in pairs(object.mark) do
if mark == markname then return true end
if mark:startsWith(markname .. "-") then
for _, suffix in ipairs(suffixes) do
if mark:find(suffix, 1, true) then return true end
end
end
end
return false
end
return player:usedCardTimes(card_name, scope) < self:getMaxUseTime(player, scope, card, to) or return player:usedCardTimes(card_name, scope) < self:getMaxUseTime(player, scope, card, to) or
(card and table.find(card_temp_suf, function(s) hasMark(card, MarkEnum.BypassTimesLimit, card_temp_suf) or
return card:getMark(MarkEnum.BypassTimesLimit .. s) ~= 0 hasMark(player, MarkEnum.BypassTimesLimit, temp_suf) or
end)) or hasMark(to, MarkEnum.BypassTimesLimitTo, temp_suf)
(table.find(temp_suf, function(s) -- (card and table.find(card_temp_suf, function(s)
return player:getMark(MarkEnum.BypassTimesLimit .. s) ~= 0 -- return card:getMark(MarkEnum.BypassTimesLimit .. s) ~= 0
end)) or -- end)) or
(to and (table.find(temp_suf, function(s) -- (table.find(temp_suf, function(s)
return to:getMark(MarkEnum.BypassTimesLimitTo .. s) ~= 0 -- return player:getMark(MarkEnum.BypassTimesLimit .. s) ~= 0
end))) -- end)) or
-- (to and (table.find(temp_suf, function(s)
-- return to:getMark(MarkEnum.BypassTimesLimitTo .. s) ~= 0
-- end)))
end end
return UsableSkill return UsableSkill

View File

@ -114,6 +114,73 @@ function fk.sorted_pairs(t, val_func, reverse)
return iter, nil, 1 return iter, nil, 1
end end
-- frequenly used filter & map functions
--- 返回ID
Util.IdMapper = function(e) return e.id end
--- 根据卡牌ID返回卡牌
Util.Id2CardMapper = function(id) return Fk:getCardById(id) end
--- 根据玩家ID返回玩家
Util.Id2PlayerMapper = function(id)
return Fk:currentRoom():getPlayerById(id)
end
--- 返回武将名
Util.NameMapper = function(e) return e.name end
--- 根据武将名返回武将
Util.Name2GeneralMapper = function(e) return Fk.generals[e] end
--- 根据技能名返回技能
Util.Name2SkillMapper = function(e) return Fk.skills[e] end
--- 返回译文
Util.TranslateMapper = function(str) return Fk:translate(str) end
-- for card preset
--- 全局卡牌(包括自己)的canUse
Util.GlobalCanUse = function(self, player, card)
local room = Fk:currentRoom()
for _, p in ipairs(room.alive_players) do
if not (card and player:isProhibited(p, card)) then
return true
end
end
end
--- AOE卡牌(不包括自己)的canUse
Util.AoeCanUse = function(self, player, card)
local room = Fk:currentRoom()
for _, p in ipairs(room.alive_players) do
if p ~= player and not (card and player:isProhibited(p, card)) then
return true
end
end
end
--- 全局卡牌(包括自己)的onUse
Util.GlobalOnUse = function(self, room, cardUseEvent)
if not cardUseEvent.tos or #TargetGroup:getRealTargets(cardUseEvent.tos) == 0 then
cardUseEvent.tos = {}
for _, player in ipairs(room:getAlivePlayers()) do
if not room:getPlayerById(cardUseEvent.from):isProhibited(player, cardUseEvent.card) then
TargetGroup:pushTargets(cardUseEvent.tos, player.id)
end
end
end
end
--- AOE卡牌(不包括自己)的onUse
Util.AoeOnUse = function(self, room, cardUseEvent)
if not cardUseEvent.tos or #TargetGroup:getRealTargets(cardUseEvent.tos) == 0 then
cardUseEvent.tos = {}
for _, player in ipairs(room:getOtherPlayers(room:getPlayerById(cardUseEvent.from))) do
if not room:getPlayerById(cardUseEvent.from):isProhibited(player, cardUseEvent.card) then
TargetGroup:pushTargets(cardUseEvent.tos, player.id)
end
end
end
end
-- Table
---@param func fun(element, index, array) ---@param func fun(element, index, array)
function table:forEach(func) function table:forEach(func)
for i, v in ipairs(self) do for i, v in ipairs(self) do
@ -164,66 +231,6 @@ function table:map(func)
return ret return ret
end end
-- frequenly used filter & map functions
--- 返回ID
Util.IdMapper = function(e) return e.id end
--- 根据卡牌ID返回卡牌
Util.Id2CardMapper = function(id) return Fk:getCardById(id) end
--- 根据玩家ID返回玩家
Util.Id2PlayerMapper = function(id)
return Fk:currentRoom():getPlayerById(id)
end
--- 返回武将名
Util.NameMapper = function(e) return e.name end
--- 根据武将名返回武将
Util.Name2GeneralMapper = function(e) return Fk.generals[e] end
--- 根据技能名返回技能
Util.Name2SkillMapper = function(e) return Fk.skills[e] end
--- 返回译文
Util.TranslateMapper = function(str) return Fk:translate(str) end
-- for card preset
Util.GlobalCanUse = function(self, player, card)
local room = Fk:currentRoom()
for _, p in ipairs(room.alive_players) do
if not (card and player:isProhibited(p, card)) then
return true
end
end
end
Util.AoeCanUse = function(self, player, card)
local room = Fk:currentRoom()
for _, p in ipairs(room.alive_players) do
if p ~= player and not (card and player:isProhibited(p, card)) then
return true
end
end
end
Util.GlobalOnUse = function(self, room, cardUseEvent)
if not cardUseEvent.tos or #TargetGroup:getRealTargets(cardUseEvent.tos) == 0 then
cardUseEvent.tos = {}
for _, player in ipairs(room:getAlivePlayers()) do
if not room:getPlayerById(cardUseEvent.from):isProhibited(player, cardUseEvent.card) then
TargetGroup:pushTargets(cardUseEvent.tos, player.id)
end
end
end
end
Util.AoeOnUse = function(self, room, cardUseEvent)
if not cardUseEvent.tos or #TargetGroup:getRealTargets(cardUseEvent.tos) == 0 then
cardUseEvent.tos = {}
for _, player in ipairs(room:getOtherPlayers(room:getPlayerById(cardUseEvent.from))) do
if not room:getPlayerById(cardUseEvent.from):isProhibited(player, cardUseEvent.card) then
TargetGroup:pushTargets(cardUseEvent.tos, player.id)
end
end
end
end
---@generic T ---@generic T
---@param self T[] ---@param self T[]
---@return T[] ---@return T[]

View File

@ -174,7 +174,7 @@ GameEvent.cleaners[GameEvent.Round] = function(self)
p:setCardUseHistory("", 0, Player.HistoryRound) p:setCardUseHistory("", 0, Player.HistoryRound)
p:setSkillUseHistory("", 0, Player.HistoryRound) p:setSkillUseHistory("", 0, Player.HistoryRound)
for name, _ in pairs(p.mark) do for name, _ in pairs(p.mark) do
if name:endsWith("-round") then if name:find("-round", 1, true) then
room:setPlayerMark(p, name, 0) room:setPlayerMark(p, name, 0)
end end
end end
@ -182,7 +182,7 @@ GameEvent.cleaners[GameEvent.Round] = function(self)
for cid, cmark in pairs(room.card_marks) do for cid, cmark in pairs(room.card_marks) do
for name, _ in pairs(cmark) do for name, _ in pairs(cmark) do
if name:endsWith("-round") then if name:find("-round", 1, true) then
room:setCardMark(Fk:getCardById(cid), name, 0) room:setCardMark(Fk:getCardById(cid), name, 0)
end end
end end
@ -249,7 +249,7 @@ GameEvent.cleaners[GameEvent.Turn] = function(self)
p:setCardUseHistory("", 0, Player.HistoryTurn) p:setCardUseHistory("", 0, Player.HistoryTurn)
p:setSkillUseHistory("", 0, Player.HistoryTurn) p:setSkillUseHistory("", 0, Player.HistoryTurn)
for name, _ in pairs(p.mark) do for name, _ in pairs(p.mark) do
if name:endsWith("-turn") then if name:find("-turn", 1, true) then
room:setPlayerMark(p, name, 0) room:setPlayerMark(p, name, 0)
end end
end end
@ -257,7 +257,7 @@ GameEvent.cleaners[GameEvent.Turn] = function(self)
for cid, cmark in pairs(room.card_marks) do for cid, cmark in pairs(room.card_marks) do
for name, _ in pairs(cmark) do for name, _ in pairs(cmark) do
if name:endsWith("-turn") then if name:find("-turn", 1, true) then
room:setCardMark(Fk:getCardById(cid), name, 0) room:setCardMark(Fk:getCardById(cid), name, 0)
end end
end end
@ -372,7 +372,7 @@ GameEvent.cleaners[GameEvent.Phase] = function(self)
p:setCardUseHistory("", 0, Player.HistoryPhase) p:setCardUseHistory("", 0, Player.HistoryPhase)
p:setSkillUseHistory("", 0, Player.HistoryPhase) p:setSkillUseHistory("", 0, Player.HistoryPhase)
for name, _ in pairs(p.mark) do for name, _ in pairs(p.mark) do
if name:endsWith("-phase") then if name:find("-phase", 1, true) then
room:setPlayerMark(p, name, 0) room:setPlayerMark(p, name, 0)
end end
end end
@ -380,7 +380,7 @@ GameEvent.cleaners[GameEvent.Phase] = function(self)
for cid, cmark in pairs(room.card_marks) do for cid, cmark in pairs(room.card_marks) do
for name, _ in pairs(cmark) do for name, _ in pairs(cmark) do
if name:endsWith("-phase") then if name:find("-phase", 1, true) then
room:setCardMark(Fk:getCardById(cid), name, 0) room:setCardMark(Fk:getCardById(cid), name, 0)
end end
end end

View File

@ -166,7 +166,7 @@ GameEvent.functions[GameEvent.MoveCards] = function(self)
local currentCard = Fk:getCardById(info.cardId) local currentCard = Fk:getCardById(info.cardId)
for name, _ in pairs(currentCard.mark) do for name, _ in pairs(currentCard.mark) do
if name:endsWith("-inhand") and if name:find("-inhand", 1, true) and
realFromArea == Player.Hand and realFromArea == Player.Hand and
data.from data.from
then then

View File

@ -1501,6 +1501,7 @@ end
---@param name string @ 武将name如找不到则查找truename再找不到则返回nil ---@param name string @ 武将name如找不到则查找truename再找不到则返回nil
---@return string? @ 抽出的武将名 ---@return string? @ 抽出的武将名
function Room:findGeneral(name) function Room:findGeneral(name)
if not Fk.generals[name] then return nil end
for i, g in ipairs(self.general_pile) do for i, g in ipairs(self.general_pile) do
if g == name or Fk.generals[g].trueName == Fk.generals[name].trueName then if g == name or Fk.generals[g].trueName == Fk.generals[name].trueName then
return table.remove(self.general_pile, i) return table.remove(self.general_pile, i)
@ -1517,13 +1518,13 @@ function Room:findGenerals(func, n)
n = n or 1 n = n or 1
local ret = {} local ret = {}
local index = 1 local index = 1
repeat while #ret < n and index <= #self.general_pile do
if func(self.general_pile[index]) then if func(self.general_pile[index]) then
table.insert(ret, table.remove(self.general_pile, index)) table.insert(ret, table.remove(self.general_pile, index))
else else
index = index + 1 index = index + 1
end end
until index >= #self.general_pile or #ret >= n end
return ret return ret
end end
@ -2993,8 +2994,10 @@ end
---@param proposer? integer @ 移动操作者的id ---@param proposer? integer @ 移动操作者的id
function Room:obtainCard(player, cid, unhide, reason, proposer) function Room:obtainCard(player, cid, unhide, reason, proposer)
if type(cid) ~= "number" then if type(cid) ~= "number" then
assert(cid and cid:isInstanceOf(Card)) assert(cid and type(cid) == "table")
if cid:isInstanceOf(Card) then
cid = cid:isVirtual() and cid.subcards or {cid.id} cid = cid:isVirtual() and cid.subcards or {cid.id}
end
else else
cid = {cid} cid = {cid}
end end
@ -3156,6 +3159,37 @@ function Room:doYiji(room, list, proposer, skillName)
return move_ids return move_ids
end end
--- 将一张牌移动至某角色的装备区,若不合法则置入弃牌堆。目前没做相同副类别装备同时置入的适配(甘露神典韦)
---@param target ServerPlayer @ 接受牌的角色
---@param cards integer|integer[] @ 移动的牌
---@param skillName? string @ 技能名
---@param convert? boolean @ 是否可以替换装备(默认可以)
---@param proposer? ServerPlayer @ 操作者
function Room:moveCardIntoEquip(target, cards, skillName, convert, proposer)
convert = (convert == nil) and true or convert
skillName = skillName or ""
cards = type(cards) == "table" and cards or {cards}
local moves = {}
for _, cardId in ipairs(cards) do
local card = Fk:getCardById(cardId)
local fromId = self.owner_map[cardId]
local proposerId = proposer and proposer.id or nil
if target:canMoveCardIntoEquip(cardId, convert) then
if target:hasEmptyEquipSlot(card.sub_type) then
table.insert(moves,{ids = {cardId}, from = fromId, to = target.id, toArea = Card.PlayerEquip, moveReason = fk.ReasonPut,skillName = skillName,proposer = proposerId})
else
local existingEquip = target:getEquipments(card.sub_type)
local throw = #existingEquip == 1 and existingEquip[1] or
self:askForCardChosen(proposer or target, target, {card_data = { {Util.convertSubtypeAndEquipSlot(card.sub_type),existingEquip} } }, "replaceEquip","#replaceEquip")
table.insert(moves,{ids = {throw}, from = target.id, toArea = Card.DiscardPile, moveReason = fk.ReasonPutIntoDiscardPile, skillName = skillName,proposer = proposerId})
table.insert(moves,{ids = {cardId}, from = fromId, to = target.id, toArea = Card.PlayerEquip, moveReason = fk.ReasonPut,skillName = skillName,proposer = proposerId})
end
else
table.insert(moves,{ids = {cardId}, from = fromId, toArea = Card.DiscardPile, moveReason = fk.ReasonPutIntoDiscardPile,skillName = skillName})
end
end
self:moveCards(table.unpack(moves))
end
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- 其他游戏事件 -- 其他游戏事件
------------------------------------------------------------------------ ------------------------------------------------------------------------

View File

@ -366,9 +366,12 @@ local fanSkill = fk.CreateTriggerSkill{
card[k] = v card[k] = v
end end
end end
if not data.card:isVirtual() then if data.card:isVirtual() then
card.subcards = data.card.subcards
else
card.id = data.card.id card.id = data.card.id
end end
card.skillNames = data.card.skillNames
card.skillName = "fan" card.skillName = "fan"
data.card = card data.card = card
end, end,

View File

@ -129,11 +129,25 @@ local maxCardsSkill = fk.CreateMaxCardsSkill{
name = "max_cards_skill", name = "max_cards_skill",
global = true, global = true,
correct_func = function(self, player) correct_func = function(self, player)
local function getMark(markname)
local v = 0
for mark, value in pairs(player.mark) do
if mark == markname then
v = v + value
elseif mark:startsWith(markname .. "-") then
for _, suffix in ipairs(MarkEnum.TempMarkSuffix) do
if mark:find(suffix, 1, true) then
v = v + value
break
end
end
end
end
return v
end
return return
player:getMark(MarkEnum.AddMaxCards) + getMark(MarkEnum.AddMaxCards) -
player:getMark(MarkEnum.AddMaxCardsInTurn) - getMark(MarkEnum.MinusMaxCards)
player:getMark(MarkEnum.MinusMaxCards) -
player:getMark(MarkEnum.MinusMaxCardsInTurn)
end, end,
} }
@ -181,15 +195,32 @@ local uncompulsoryInvalidity = fk.CreateInvaliditySkill {
name = "uncompulsory_invalidity", name = "uncompulsory_invalidity",
global = true, global = true,
invalidity_func = function(self, from, skill) invalidity_func = function(self, from, skill)
---@param object Card|Player
---@param markname string
---@param suffixes string[]
---@return boolean
local function hasMark(object, markname, suffixes)
if not object then return false end
for mark, _ in pairs(object.mark) do
if mark == markname then return true end
if mark:startsWith(markname .. "-") then
for _, suffix in ipairs(suffixes) do
if mark:find(suffix, 1, true) then return true end
end
end
end
return false
end
return return
(skill.frequency ~= Skill.Compulsory and skill.frequency ~= Skill.Wake) and (skill.frequency ~= Skill.Compulsory and skill.frequency ~= Skill.Wake) and
not (skill:isEquipmentSkill() or skill.name:endsWith("&")) and not (skill:isEquipmentSkill() or skill.name:endsWith("&")) and
( hasMark(from, MarkEnum.UncompulsoryInvalidity, MarkEnum.TempMarkSuffix)
from:getMark(MarkEnum.UncompulsoryInvalidity) ~= 0 or -- (
table.find(MarkEnum.TempMarkSuffix, function(s) -- from:getMark(MarkEnum.UncompulsoryInvalidity) ~= 0 or
return from:getMark(MarkEnum.UncompulsoryInvalidity .. s) ~= 0 -- table.find(MarkEnum.TempMarkSuffix, function(s)
end) -- return from:getMark(MarkEnum.UncompulsoryInvalidity .. s) ~= 0
) -- end)
-- )
end end
} }
@ -201,15 +232,27 @@ local revealProhibited = fk.CreateInvaliditySkill {
if type(from:getMark(MarkEnum.RevealProhibited)) == "table" then if type(from:getMark(MarkEnum.RevealProhibited)) == "table" then
generals = from:getMark(MarkEnum.RevealProhibited) generals = from:getMark(MarkEnum.RevealProhibited)
end end
for _, m in ipairs(table.map(MarkEnum.TempMarkSuffix, function(s)
return from:getMark(MarkEnum.RevealProhibited .. s) for mark, value in pairs(from.mark) do
end)) do if mark:startsWith(MarkEnum.RevealProhibited .. "-") and type(value) == "table" then
if type(m) == "table" then for _, suffix in ipairs(MarkEnum.TempMarkSuffix) do
for _, g in ipairs(m) do if mark:find(suffix, 1, true) then
for _, g in ipairs(value) do
table.insertIfNeed(generals, g) table.insertIfNeed(generals, g)
end end
end end
end end
end
end
-- for _, m in ipairs(table.map(MarkEnum.TempMarkSuffix, function(s)
-- return from:getMark(MarkEnum.RevealProhibited .. s)
-- end)) do
-- if type(m) == "table" then
-- for _, g in ipairs(m) do
-- table.insertIfNeed(generals, g)
-- end
-- end
-- end
if #generals == 0 then return false end if #generals == 0 then return false end
local sname = skill.name local sname = skill.name

View File

@ -1132,9 +1132,17 @@ local role_getlogic = function()
lord_general = lord_generals lord_general = lord_generals
lord_generals = {lord_general} lord_generals = {lord_general}
end end
generals = table.filter(generals, function(g) return not table.contains(lord_generals, g) end)
room:returnToGeneralPile(generals) room:returnToGeneralPile(generals)
local index = 1
while index <= #room.general_pile do
local ret = {}
for _, gname in ipairs(lord_generals) do
if room.general_pile[index] == gname or Fk.generals[room.general_pile[index]].trueName == Fk.generals[gname].trueName then
table.insert(ret, table.remove(room.general_pile, index))
end
end
if #ret == 0 then index = index + 1 end
end
room:setPlayerGeneral(lord, lord_general, true) room:setPlayerGeneral(lord, lord_general, true)
room:askForChooseKingdom({lord}) room:askForChooseKingdom({lord})
@ -1216,14 +1224,24 @@ local role_getlogic = function()
room:setPlayerGeneral(p, general, true, true) room:setPlayerGeneral(p, general, true, true)
room:setDeputyGeneral(p, deputy) room:setDeputyGeneral(p, deputy)
else else
table.insertTableIfNeed(selected, p.default_reply)
room:setPlayerGeneral(p, p.default_reply[1], true, true) room:setPlayerGeneral(p, p.default_reply[1], true, true)
room:setDeputyGeneral(p, p.default_reply[2]) room:setDeputyGeneral(p, p.default_reply[2])
end end
p.default_reply = "" p.default_reply = ""
end end
generals = table.filter(generals, function(g) return not table.contains(selected, g) end)
room:returnToGeneralPile(generals) room:returnToGeneralPile(generals)
local index = 1
while index <= #room.general_pile do
local ret = {}
for _, gname in ipairs(selected) do
if room.general_pile[index] == gname or Fk.generals[room.general_pile[index]].trueName == Fk.generals[gname].trueName then
table.insert(ret, table.remove(room.general_pile, index))
end
end
if #ret == 0 then index = index + 1 end
end
room:askForChooseKingdom(nonlord) room:askForChooseKingdom(nonlord)
end end