2023-04-09 13:35:35 +08:00
|
|
|
-- SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
2022-09-15 11:17:13 +08:00
|
|
|
local discardSkill = fk.CreateActiveSkill{
|
|
|
|
name = "discard_skill",
|
|
|
|
card_filter = function(self, to_select, selected)
|
|
|
|
if #selected >= self.num then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2023-08-03 20:34:43 +08:00
|
|
|
if Fk:currentRoom():getCardArea(to_select) == Card.PlayerSpecial then
|
|
|
|
local pile = ""
|
|
|
|
for p, t in pairs(Self.special_cards) do
|
|
|
|
if table.contains(t, to_select) then
|
|
|
|
pile = p
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if not string.find(self.pattern or "", pile) then return false end
|
2023-08-02 21:50:47 +08:00
|
|
|
end
|
|
|
|
|
2023-03-20 20:15:24 +08:00
|
|
|
local checkpoint = true
|
2023-04-10 15:55:06 +08:00
|
|
|
local card = Fk:getCardById(to_select)
|
|
|
|
|
2023-06-11 16:22:11 +08:00
|
|
|
local status_skills = Fk:currentRoom().status_skills[ProhibitSkill] or Util.DummyTable
|
2023-04-10 15:55:06 +08:00
|
|
|
for _, skill in ipairs(status_skills) do
|
|
|
|
if skill:prohibitDiscard(Self, card) then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
end
|
2023-06-04 19:39:20 +08:00
|
|
|
if Fk.currentResponseReason == "game_rule" then
|
2023-06-11 16:22:11 +08:00
|
|
|
status_skills = Fk:currentRoom().status_skills[MaxCardsSkill] or Util.DummyTable
|
2023-06-04 19:39:20 +08:00
|
|
|
for _, skill in ipairs(status_skills) do
|
|
|
|
if skill:excludeFrom(Self, card) then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2023-04-10 15:55:06 +08:00
|
|
|
|
2023-01-29 18:11:41 +08:00
|
|
|
if not self.include_equip then
|
2023-03-20 20:15:24 +08:00
|
|
|
checkpoint = checkpoint and (Fk:currentRoom():getCardArea(to_select) ~= Player.Equip)
|
2023-01-29 18:11:41 +08:00
|
|
|
end
|
|
|
|
|
2023-04-12 22:28:19 +08:00
|
|
|
if self.pattern and self.pattern ~= "" then
|
2023-04-10 15:55:06 +08:00
|
|
|
checkpoint = checkpoint and (Exppattern:Parse(self.pattern):match(card))
|
2023-03-20 20:15:24 +08:00
|
|
|
end
|
|
|
|
return checkpoint
|
2022-09-15 11:17:13 +08:00
|
|
|
end,
|
2023-02-26 15:01:14 +08:00
|
|
|
min_card_num = function(self) return self.min_num end,
|
|
|
|
max_card_num = function(self) return self.num end,
|
2022-09-15 11:17:13 +08:00
|
|
|
}
|
|
|
|
|
2023-03-14 20:48:08 +08:00
|
|
|
local chooseCardsSkill = fk.CreateActiveSkill{
|
|
|
|
name = "choose_cards_skill",
|
2023-04-12 22:28:19 +08:00
|
|
|
card_filter = function(self, to_select, selected)
|
|
|
|
if #selected >= self.num then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2023-08-03 20:34:43 +08:00
|
|
|
if Fk:currentRoom():getCardArea(to_select) == Card.PlayerSpecial then
|
|
|
|
if not string.find(self.pattern or "", self.expand_pile or "") then return false end
|
2023-08-02 21:50:47 +08:00
|
|
|
end
|
|
|
|
|
2023-04-12 22:28:19 +08:00
|
|
|
local checkpoint = true
|
|
|
|
local card = Fk:getCardById(to_select)
|
|
|
|
|
|
|
|
if not self.include_equip then
|
|
|
|
checkpoint = checkpoint and (Fk:currentRoom():getCardArea(to_select) ~= Player.Equip)
|
|
|
|
end
|
|
|
|
|
|
|
|
if self.pattern and self.pattern ~= "" then
|
|
|
|
checkpoint = checkpoint and (Exppattern:Parse(self.pattern):match(card))
|
|
|
|
end
|
|
|
|
return checkpoint
|
|
|
|
end,
|
2023-03-14 20:48:08 +08:00
|
|
|
min_card_num = function(self) return self.min_num end,
|
|
|
|
max_card_num = function(self) return self.num end,
|
|
|
|
}
|
|
|
|
|
2022-09-15 11:17:13 +08:00
|
|
|
local choosePlayersSkill = fk.CreateActiveSkill{
|
|
|
|
name = "choose_players_skill",
|
2024-02-17 09:48:42 +08:00
|
|
|
card_filter = function(self, to_select, selected)
|
|
|
|
return self.pattern ~= "" and Exppattern:Parse(self.pattern):match(Fk:getCardById(to_select)) and #selected == 0
|
2022-09-15 11:17:13 +08:00
|
|
|
end,
|
2023-02-26 15:01:14 +08:00
|
|
|
target_filter = function(self, to_select, selected, cards)
|
|
|
|
if self.pattern ~= "" and #cards == 0 then return end
|
2022-09-15 11:17:13 +08:00
|
|
|
if #selected < self.num then
|
2023-01-29 18:11:41 +08:00
|
|
|
return table.contains(self.targets, to_select)
|
2022-09-15 11:17:13 +08:00
|
|
|
end
|
|
|
|
end,
|
2024-10-22 00:10:53 +08:00
|
|
|
target_tip = function(self, to_select, selected, selected_cards, card, selectable, extra_data)
|
|
|
|
if self.targetTipName then
|
|
|
|
local targetTip = Fk.target_tips[self.targetTipName]
|
|
|
|
assert(targetTip)
|
|
|
|
return targetTip.target_tip(self, to_select, selected, selected_cards, card, selectable, extra_data)
|
|
|
|
end
|
|
|
|
end,
|
2023-02-26 15:01:14 +08:00
|
|
|
card_num = function(self) return self.pattern ~= "" and 1 or 0 end,
|
|
|
|
min_target_num = function(self) return self.min_num end,
|
|
|
|
max_target_num = function(self) return self.num end,
|
2022-09-15 11:17:13 +08:00
|
|
|
}
|
|
|
|
|
2023-11-07 12:57:00 +08:00
|
|
|
local exChooseSkill = fk.CreateActiveSkill{
|
|
|
|
name = "ex__choose_skill",
|
|
|
|
card_filter = function(self, to_select, selected)
|
2024-04-02 00:56:04 +08:00
|
|
|
if #selected >= self.max_c_num then return false end
|
2023-12-06 21:08:56 +08:00
|
|
|
|
|
|
|
if Fk:currentRoom():getCardArea(to_select) == Card.PlayerSpecial then
|
|
|
|
if not string.find(self.pattern or "", self.expand_pile or "") then return false end
|
|
|
|
end
|
|
|
|
|
|
|
|
local checkpoint = true
|
|
|
|
local card = Fk:getCardById(to_select)
|
|
|
|
|
|
|
|
|
|
|
|
if self.pattern and self.pattern ~= "" then
|
|
|
|
checkpoint = checkpoint and (Exppattern:Parse(self.pattern):match(card))
|
|
|
|
end
|
|
|
|
return checkpoint
|
2023-11-07 12:57:00 +08:00
|
|
|
end,
|
|
|
|
target_filter = function(self, to_select, selected, cards)
|
2024-04-02 00:56:04 +08:00
|
|
|
if #cards < self.min_c_num then return end
|
|
|
|
if #selected < self.max_t_num then
|
2023-11-07 12:57:00 +08:00
|
|
|
return table.contains(self.targets, to_select)
|
|
|
|
end
|
|
|
|
end,
|
2024-10-22 00:10:53 +08:00
|
|
|
target_tip = function(self, to_select, selected, selected_cards, card, selectable, extra_data)
|
|
|
|
if self.targetTipName then
|
|
|
|
local targetTip = Fk.target_tips[self.targetTipName]
|
|
|
|
assert(targetTip)
|
|
|
|
return targetTip.target_tip(self, to_select, selected, selected_cards, card, selectable, extra_data)
|
|
|
|
end
|
|
|
|
end,
|
2024-04-02 00:56:04 +08:00
|
|
|
min_target_num = function(self) return self.min_t_num end,
|
|
|
|
max_target_num = function(self) return self.max_t_num end,
|
|
|
|
min_card_num = function(self) return self.min_c_num end,
|
|
|
|
max_card_num = function(self) return self.max_c_num end,
|
2023-11-07 12:57:00 +08:00
|
|
|
}
|
|
|
|
|
2023-05-13 14:16:09 +08:00
|
|
|
local maxCardsSkill = fk.CreateMaxCardsSkill{
|
|
|
|
name = "max_cards_skill",
|
|
|
|
global = true,
|
|
|
|
correct_func = function(self, player)
|
2024-02-27 02:27:59 +08:00
|
|
|
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
|
2023-05-28 18:45:54 +08:00
|
|
|
return
|
2024-02-27 02:27:59 +08:00
|
|
|
getMark(MarkEnum.AddMaxCards) -
|
|
|
|
getMark(MarkEnum.MinusMaxCards)
|
2023-05-28 18:45:54 +08:00
|
|
|
end,
|
|
|
|
}
|
|
|
|
|
2024-02-17 09:48:42 +08:00
|
|
|
local distributionSelectSkill = fk.CreateActiveSkill{
|
|
|
|
name = "distribution_select_skill",
|
|
|
|
mute = true,
|
|
|
|
min_card_num = 1,
|
|
|
|
card_filter = function(self, to_select, selected)
|
|
|
|
return #selected < self.max_num and table.contains(self.cards, to_select)
|
|
|
|
end,
|
|
|
|
target_num = 1,
|
|
|
|
target_filter = function(self, to_select, selected, selected_cards)
|
|
|
|
return #selected == 0 and #selected_cards > 0 and table.contains(self.targets, to_select)
|
|
|
|
and #selected_cards <= (self.residued_list[string.format("%d", to_select)] or 0)
|
|
|
|
end,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-05-28 18:45:54 +08:00
|
|
|
local choosePlayersToMoveCardInBoardSkill = fk.CreateActiveSkill{
|
|
|
|
name = "choose_players_to_move_card_in_board",
|
|
|
|
target_num = 2,
|
|
|
|
card_filter = function(self, to_select)
|
|
|
|
return false
|
|
|
|
end,
|
|
|
|
target_filter = function(self, to_select, selected, cards)
|
|
|
|
local target = Fk:currentRoom():getPlayerById(to_select)
|
|
|
|
if #selected > 0 then
|
2023-07-16 19:18:43 +08:00
|
|
|
return Fk:currentRoom():getPlayerById(selected[1]):canMoveCardsInBoardTo(target, self.flag, self.excludeIds)
|
2023-05-28 18:45:54 +08:00
|
|
|
end
|
|
|
|
|
2023-07-16 19:18:43 +08:00
|
|
|
local fromAreas = { Player.Equip, Player.Judge }
|
|
|
|
if self.flag == "e" then
|
|
|
|
fromAreas = { Player.Equip }
|
|
|
|
elseif self.flag == "j" then
|
|
|
|
fromAreas = { Player.Judge }
|
|
|
|
end
|
|
|
|
|
|
|
|
return #table.filter(target:getCardIds(fromAreas), function(id)
|
|
|
|
return not table.contains((type(self.excludeIds) == "table" and self.excludeIds or {}), id)
|
|
|
|
end) > 0
|
2023-05-13 14:16:09 +08:00
|
|
|
end,
|
|
|
|
}
|
|
|
|
|
2023-06-11 12:45:12 +08:00
|
|
|
local uncompulsoryInvalidity = fk.CreateInvaliditySkill {
|
|
|
|
name = "uncompulsory_invalidity",
|
|
|
|
global = true,
|
|
|
|
invalidity_func = function(self, from, skill)
|
2024-02-27 02:27:59 +08:00
|
|
|
---@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
|
2023-06-11 12:45:12 +08:00
|
|
|
return
|
|
|
|
(skill.frequency ~= Skill.Compulsory and skill.frequency ~= Skill.Wake) and
|
2024-06-10 15:19:47 +08:00
|
|
|
skill:isPlayerSkill(from) and
|
2024-02-27 02:27:59 +08:00
|
|
|
hasMark(from, MarkEnum.UncompulsoryInvalidity, MarkEnum.TempMarkSuffix)
|
|
|
|
-- (
|
|
|
|
-- from:getMark(MarkEnum.UncompulsoryInvalidity) ~= 0 or
|
|
|
|
-- table.find(MarkEnum.TempMarkSuffix, function(s)
|
|
|
|
-- return from:getMark(MarkEnum.UncompulsoryInvalidity .. s) ~= 0
|
|
|
|
-- end)
|
|
|
|
-- )
|
2023-06-11 12:45:12 +08:00
|
|
|
end
|
|
|
|
}
|
|
|
|
|
2023-08-24 21:37:06 +08:00
|
|
|
local revealProhibited = fk.CreateInvaliditySkill {
|
|
|
|
name = "reveal_prohibited",
|
|
|
|
global = true,
|
|
|
|
invalidity_func = function(self, from, skill)
|
|
|
|
local generals = {}
|
|
|
|
if type(from:getMark(MarkEnum.RevealProhibited)) == "table" then
|
|
|
|
generals = from:getMark(MarkEnum.RevealProhibited)
|
|
|
|
end
|
2024-02-27 02:27:59 +08:00
|
|
|
|
|
|
|
for mark, value in pairs(from.mark) do
|
|
|
|
if mark:startsWith(MarkEnum.RevealProhibited .. "-") and type(value) == "table" then
|
|
|
|
for _, suffix in ipairs(MarkEnum.TempMarkSuffix) do
|
|
|
|
if mark:find(suffix, 1, true) then
|
|
|
|
for _, g in ipairs(value) do
|
|
|
|
table.insertIfNeed(generals, g)
|
|
|
|
end
|
|
|
|
end
|
2023-08-24 21:37:06 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2024-02-27 02:27:59 +08:00
|
|
|
-- 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
|
2023-08-24 21:37:06 +08:00
|
|
|
|
|
|
|
if #generals == 0 then return false end
|
|
|
|
local sname = skill.name
|
|
|
|
for _, g in ipairs(generals) do
|
2024-02-04 15:30:27 +08:00
|
|
|
if (g == "m" and from.general == "anjiang") or (g == "d" and from.deputyGeneral == "anjiang") then
|
|
|
|
local generalName = g == "m" and from:getMark("__heg_general") or from:getMark("__heg_deputy")
|
|
|
|
local general = Fk.generals[generalName]
|
|
|
|
if table.contains(general:getSkillNameList(true), sname) then
|
|
|
|
return true
|
|
|
|
end
|
2023-08-24 21:37:06 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
-- 亮将
|
|
|
|
local revealSkill = fk.CreateActiveSkill{
|
2024-04-07 00:45:55 +08:00
|
|
|
name = "reveal_skill&",
|
|
|
|
prompt = "#reveal_skill&",
|
2023-08-24 21:37:06 +08:00
|
|
|
interaction = function(self)
|
|
|
|
local choiceList = {}
|
|
|
|
if (Self.general == "anjiang" and not Self:prohibitReveal()) then
|
|
|
|
local general = Fk.generals[Self:getMark("__heg_general")]
|
2024-01-25 03:13:57 +08:00
|
|
|
for _, sname in ipairs(general:getSkillNameList(true)) do
|
2023-08-24 21:37:06 +08:00
|
|
|
local s = Fk.skills[sname]
|
|
|
|
if s.frequency == Skill.Compulsory and s.relate_to_place ~= "m" then
|
2024-04-07 00:45:55 +08:00
|
|
|
table.insert(choiceList, "revealMain:::" .. general.name)
|
2023-08-24 21:37:06 +08:00
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if (Self.deputyGeneral == "anjiang" and not Self:prohibitReveal(true)) then
|
|
|
|
local general = Fk.generals[Self:getMark("__heg_deputy")]
|
2024-01-25 03:13:57 +08:00
|
|
|
for _, sname in ipairs(general:getSkillNameList(true)) do
|
2023-08-24 21:37:06 +08:00
|
|
|
local s = Fk.skills[sname]
|
|
|
|
if s.frequency == Skill.Compulsory and s.relate_to_place ~= "d" then
|
2024-04-07 00:45:55 +08:00
|
|
|
table.insert(choiceList, "revealDeputy:::" .. general.name)
|
2023-08-24 21:37:06 +08:00
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if #choiceList == 0 then return false end
|
2024-04-07 00:45:55 +08:00
|
|
|
return UI.ComboBox { choices = choiceList }
|
2023-08-24 21:37:06 +08:00
|
|
|
end,
|
|
|
|
target_num = 0,
|
|
|
|
card_num = 0,
|
|
|
|
card_filter = Util.FalseFunc,
|
|
|
|
on_use = function(self, room, effect)
|
|
|
|
local player = room:getPlayerById(effect.from)
|
|
|
|
local choice = self.interaction.data
|
|
|
|
if not choice then return false
|
2024-04-07 00:45:55 +08:00
|
|
|
elseif choice:startsWith("revealMain") then player:revealGeneral(false)
|
|
|
|
elseif choice:startsWith("revealDeputy") then player:revealGeneral(true) end
|
2023-08-24 21:37:06 +08:00
|
|
|
end,
|
2024-02-04 15:30:27 +08:00
|
|
|
can_use = function(self, player)
|
|
|
|
if (player.general == "anjiang" and not player:prohibitReveal()) then
|
|
|
|
local general = Fk.generals[player:getMark("__heg_general")]
|
|
|
|
for _, sname in ipairs(general:getSkillNameList(true)) do
|
|
|
|
local s = Fk.skills[sname]
|
|
|
|
if s.frequency == Skill.Compulsory and s.relate_to_place ~= "m" then
|
2024-04-07 00:45:55 +08:00
|
|
|
return true
|
2024-02-04 15:30:27 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if (player.deputyGeneral == "anjiang" and not player:prohibitReveal(true)) then
|
|
|
|
local general = Fk.generals[player:getMark("__heg_deputy")]
|
|
|
|
for _, sname in ipairs(general:getSkillNameList(true)) do
|
|
|
|
local s = Fk.skills[sname]
|
|
|
|
if s.frequency == Skill.Compulsory and s.relate_to_place ~= "d" then
|
2024-04-07 00:45:55 +08:00
|
|
|
return true
|
2024-02-04 15:30:27 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2024-04-07 00:45:55 +08:00
|
|
|
return false
|
2024-02-04 15:30:27 +08:00
|
|
|
end
|
2023-08-24 21:37:06 +08:00
|
|
|
}
|
|
|
|
|
2022-09-15 11:17:13 +08:00
|
|
|
AuxSkills = {
|
|
|
|
discardSkill,
|
2023-03-14 20:48:08 +08:00
|
|
|
chooseCardsSkill,
|
2022-09-15 11:17:13 +08:00
|
|
|
choosePlayersSkill,
|
2023-11-07 12:57:00 +08:00
|
|
|
exChooseSkill,
|
2024-02-17 09:48:42 +08:00
|
|
|
distributionSelectSkill,
|
2023-05-13 14:16:09 +08:00
|
|
|
maxCardsSkill,
|
2023-05-28 18:45:54 +08:00
|
|
|
choosePlayersToMoveCardInBoardSkill,
|
2023-06-11 12:45:12 +08:00
|
|
|
uncompulsoryInvalidity,
|
2023-08-24 21:37:06 +08:00
|
|
|
revealProhibited,
|
|
|
|
revealSkill
|
2022-09-15 11:17:13 +08:00
|
|
|
}
|