FreeKill/packages/standard_cards/init.lua

1251 lines
38 KiB
Lua
Raw Normal View History

-- SPDX-License-Identifier: GPL-3.0-or-later
local extension = Package:new("standard_cards", Package.CardPack)
extension.metadata = require "packages.standard_cards.metadata"
2023-09-21 15:21:28 +00:00
local slashSkill = fk.CreateActiveSkill {
name = "slash_skill",
max_phase_use_time = 1,
target_num = 1,
can_use = function(self, player, card)
2023-09-21 15:21:28 +00:00
return table.find(Fk:currentRoom().alive_players, function(p)
return self:withinTimesLimit(player, Player.HistoryPhase, card, "slash", p)
end)
end,
mod_target_filter = function(self, to_select, selected, user, card, distance_limited)
local player = Fk:currentRoom():getPlayerById(to_select)
local from = Fk:currentRoom():getPlayerById(user)
2023-09-21 15:21:28 +00:00
return
user ~= to_select and not (distance_limited and not self:withinDistanceLimit(from, true, card, player)) and
not (card and from:isProhibited(player, card))
end,
target_filter = function(self, to_select, selected, _, card)
if #selected < self:getMaxTargetNum(Self, card) then
local player = Fk:currentRoom():getPlayerById(to_select)
return self:modTargetFilter(to_select, selected, Self.id, card, true) and
2023-09-21 15:21:28 +00:00
(#selected > 0 or self:withinTimesLimit(Self, Player.HistoryPhase, card, "slash", player))
end
end,
on_effect = function(self, room, effect)
2023-07-11 13:15:38 +00:00
local from = room:getPlayerById(effect.from)
local to = room:getPlayerById(effect.to)
if not to.dead then
room:damage({
from = from,
to = to,
card = effect.card,
damage = 1,
damageType = fk.NormalDamage,
skillName = self.name
})
end
end
}
2023-09-21 15:21:28 +00:00
local slash = fk.CreateBasicCard {
name = "slash",
number = 7,
suit = Card.Spade,
is_damage_card = true,
2023-09-21 15:21:28 +00:00
skill = slashSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ slash, slash:clone(Card.Spade, 8), slash:clone(Card.Spade, 8), slash:clone(Card.Spade, 9),
slash:clone(Card.Spade, 9), slash:clone(Card.Spade, 10), slash:clone(Card.Spade, 10),
slash:clone(Card.Club, 2), slash:clone(Card.Club, 3), slash:clone(Card.Club, 4),
slash:clone(Card.Club, 5), slash:clone(Card.Club, 6), slash:clone(Card.Club, 7),
slash:clone(Card.Club, 8), slash:clone(Card.Club, 8), slash:clone(Card.Club, 9),
slash:clone(Card.Club, 9), slash:clone(Card.Club, 10), slash:clone(Card.Club, 10),
slash:clone(Card.Club, 11), slash:clone(Card.Club, 11), slash:clone(Card.Heart, 10),
slash:clone(Card.Heart, 10), slash:clone(Card.Heart, 11), slash:clone(Card.Diamond, 6),
slash:clone(Card.Diamond, 7), slash:clone(Card.Diamond, 8), slash:clone(Card.Diamond, 9),
slash:clone(Card.Diamond, 10), slash:clone(Card.Diamond, 13) })
local jinkSkill = fk.CreateActiveSkill {
name = "jink_skill",
can_use = function()
return false
end,
on_effect = function(self, room, effect)
if effect.responseToEvent then
effect.responseToEvent.isCancellOut = true
end
end
}
2023-09-21 15:21:28 +00:00
local jink = fk.CreateBasicCard {
name = "jink",
suit = Card.Heart,
number = 2,
2023-09-21 15:21:28 +00:00
skill = jinkSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ jink, jink:clone(Card.Heart, 2), jink:clone(Card.Heart, 13), jink:clone(Card.Diamond, 2),
jink:clone(Card.Diamond, 2), jink:clone(Card.Diamond, 3), jink:clone(Card.Diamond, 4),
jink:clone(Card.Diamond, 5), jink:clone(Card.Diamond, 6), jink:clone(Card.Diamond, 7),
jink:clone(Card.Diamond, 8), jink:clone(Card.Diamond, 9), jink:clone(Card.Diamond, 10),
jink:clone(Card.Diamond, 11), jink:clone(Card.Diamond, 11) })
local peachSkill = fk.CreateActiveSkill {
name = "peach_skill",
mod_target_filter = function(self, to_select)
return Fk:currentRoom():getPlayerById(to_select):isWounded() and
2023-09-21 15:21:28 +00:00
not table.find(Fk:currentRoom().alive_players, function(p)
return p.dying
end)
end,
can_use = function(self, player, card)
return player:isWounded() and not player:isProhibited(player, card)
end,
on_use = function(self, room, use)
if not use.tos or #TargetGroup:getRealTargets(use.tos) == 0 then
use.tos = { { use.from } }
end
end,
on_effect = function(self, room, effect)
2023-07-11 13:15:38 +00:00
local player = room:getPlayerById(effect.from)
local target = room:getPlayerById(effect.to)
if target:isWounded() and not target.dead then
room:recover({
who = target,
num = 1,
card = effect.card,
recoverBy = player,
skillName = self.name
})
end
end
}
2023-09-21 15:21:28 +00:00
local peach = fk.CreateBasicCard {
name = "peach",
suit = Card.Heart,
number = 3,
2023-09-21 15:21:28 +00:00
skill = peachSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ peach, peach:clone(Card.Heart, 4), peach:clone(Card.Heart, 6), peach:clone(Card.Heart, 7),
peach:clone(Card.Heart, 8), peach:clone(Card.Heart, 9), peach:clone(Card.Heart, 12),
peach:clone(Card.Heart, 12) })
local dismantlementSkill = fk.CreateActiveSkill {
name = "dismantlement_skill",
target_num = 1,
2023-09-21 15:21:28 +00:00
mod_target_filter = function(self, to_select, selected, user, card)
local player = Fk:currentRoom():getPlayerById(to_select)
2023-09-21 15:21:28 +00:00
local from = Fk:currentRoom():getPlayerById(user)
return user ~= to_select and not player:isAllNude() and not (card and from:isProhibited(player, card))
end,
2023-09-21 15:21:28 +00:00
target_filter = function(self, to_select, selected, _, card)
if #selected < self:getMaxTargetNum(Self, card) then
return self:modTargetFilter(to_select, selected, Self.id, card)
end
end,
on_effect = function(self, room, effect)
local from = room:getPlayerById(effect.from)
2023-07-11 13:15:38 +00:00
local to = room:getPlayerById(effect.to)
2023-09-21 15:21:28 +00:00
if to.dead or to:isAllNude() then
return
end
2023-07-11 13:15:38 +00:00
local cid = room:askForCardChosen(from, to, "hej", self.name)
2023-09-21 15:21:28 +00:00
room:throwCard({ cid }, self.name, to, from)
end
}
2023-09-21 15:21:28 +00:00
local dismantlement = fk.CreateTrickCard {
name = "dismantlement",
suit = Card.Spade,
number = 3,
2023-09-21 15:21:28 +00:00
skill = dismantlementSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ dismantlement, dismantlement:clone(Card.Spade, 4), dismantlement:clone(Card.Spade, 12),
dismantlement:clone(Card.Club, 3), dismantlement:clone(Card.Club, 4),
2023-09-21 15:21:28 +00:00
dismantlement:clone(Card.Heart, 12) })
2023-09-21 15:21:28 +00:00
local snatchSkill = fk.CreateActiveSkill {
name = "snatch_skill",
distance_limit = 1,
mod_target_filter = function(self, to_select, selected, user, card, distance_limited)
local player = Fk:currentRoom():getPlayerById(to_select)
local from = Fk:currentRoom():getPlayerById(user)
2023-09-21 15:21:28 +00:00
return user ~= to_select and
not (player:isAllNude() or
(distance_limited and not self:withinDistanceLimit(from, false, card, player))) and
not (card and from:isProhibited(player, card))
end,
target_filter = function(self, to_select, selected, _, card)
2023-09-21 15:21:28 +00:00
if #selected < self:getMaxTargetNum(Self, card) then
return self:modTargetFilter(to_select, selected, Self.id, card, true)
end
end,
target_num = 1,
on_effect = function(self, room, effect)
2023-07-11 13:15:38 +00:00
local from = room:getPlayerById(effect.from)
local to = room:getPlayerById(effect.to)
2023-09-21 15:21:28 +00:00
if to.dead or to:isAllNude() then
return
end
2023-07-11 13:15:38 +00:00
local cid = room:askForCardChosen(from, to, "hej", self.name)
room:obtainCard(from, cid, false, fk.ReasonPrey)
end
}
2023-09-21 15:21:28 +00:00
local snatch = fk.CreateTrickCard {
name = "snatch",
suit = Card.Spade,
number = 3,
2023-09-21 15:21:28 +00:00
skill = snatchSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ snatch, snatch:clone(Card.Spade, 4), snatch:clone(Card.Spade, 11), snatch:clone(Card.Diamond, 3),
snatch:clone(Card.Diamond, 4) })
2023-09-21 15:21:28 +00:00
local duelSkill = fk.CreateActiveSkill {
name = "duel_skill",
2023-09-21 15:21:28 +00:00
mod_target_filter = function(self, to_select, selected, user, card)
local player = Fk:currentRoom():getPlayerById(to_select)
local from = Fk:currentRoom():getPlayerById(user)
return user ~= to_select and not (card and from:isProhibited(player, card))
end,
2023-09-21 15:21:28 +00:00
target_filter = function(self, to_select, selected, _, card)
if #selected < self:getMaxTargetNum(Self, card) then
return self:modTargetFilter(to_select, selected, Self.id, card)
end
end,
target_num = 1,
on_effect = function(self, room, effect)
local to = room:getPlayerById(effect.to)
local from = room:getPlayerById(effect.from)
local responsers = { to, from }
local currentTurn = 1
local currentResponser = to
while currentResponser:isAlive() do
local loopTimes = 1
if effect.fixedResponseTimes then
local canFix = currentResponser == to
if effect.fixedAddTimesResponsors then
canFix = table.contains(effect.fixedAddTimesResponsors, currentResponser.id)
end
if canFix then
if type(effect.fixedResponseTimes) == 'table' then
loopTimes = effect.fixedResponseTimes["slash"] or 1
elseif type(effect.fixedResponseTimes) == 'number' then
loopTimes = effect.fixedResponseTimes
end
end
end
2023-09-21 15:21:28 +00:00
local can
for i = 1, loopTimes do
2023-09-21 15:21:28 +00:00
if room:askForResponse(currentResponser, 'slash', nil, nil, false, nil, effect) then
else
2023-09-21 15:21:28 +00:00
can = true
break
end
end
2023-09-21 15:21:28 +00:00
if can then
break
end
currentTurn = currentTurn % 2 + 1
currentResponser = responsers[currentTurn]
end
if currentResponser:isAlive() then
room:damage({
from = responsers[currentTurn % 2 + 1],
to = currentResponser,
card = effect.card,
2023-05-28 10:45:54 +00:00
damage = 1,
damageType = fk.NormalDamage,
2023-09-21 15:21:28 +00:00
skillName = self.name
})
end
end
}
2023-09-21 15:21:28 +00:00
local duel = fk.CreateTrickCard {
name = "duel",
suit = Card.Spade,
number = 1,
is_damage_card = true,
2023-09-21 15:21:28 +00:00
skill = duelSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ duel, duel:clone(Card.Club, 1), duel:clone(Card.Diamond, 1) })
2023-09-21 15:21:28 +00:00
local collateralSkill = fk.CreateActiveSkill {
name = "collateral_skill",
2023-09-21 15:21:28 +00:00
mod_target_filter = function(self, to_select, selected, user, card)
local player = Fk:currentRoom():getPlayerById(to_select)
2023-09-21 15:21:28 +00:00
local from = Fk:currentRoom():getPlayerById(user)
return user ~= to_select and player:getEquipment(Card.SubtypeWeapon) and
not (card and from:isProhibited(player, card))
end,
2023-09-21 15:21:28 +00:00
target_filter = function(self, to_select, selected, _, card)
if #selected >= (self:getMaxTargetNum(Self, card) - 1) * 2 then
return false
elseif #selected % 2 == 0 then
return self:modTargetFilter(to_select, selected, Self.id, card)
elseif #selected > 0 then
return Fk:currentRoom():getPlayerById(selected[#selected]):inMyAttackRange(
Fk:currentRoom():getPlayerById(to_select))
end
end,
target_num = 2,
on_use = function(self, room, cardUseEvent)
2023-09-21 15:21:28 +00:00
-- cardUseEvent.tos = {{cardUseEvent.tos[1][1], cardUseEvent.tos[2][1]}}
local tos = {}
local exclusive = {}
for i, pid in ipairs(TargetGroup:getRealTargets(cardUseEvent.tos)) do
if i % 2 == 1 then
exclusive = { pid }
else
table.insert(exclusive, pid)
table.insert(tos, exclusive)
end
end
cardUseEvent.tos = tos
end,
on_effect = function(self, room, effect)
local to = room:getPlayerById(effect.to)
2023-09-21 15:21:28 +00:00
if to.dead or not to:getEquipment(Card.SubtypeWeapon) then
return
end
local prompt = "#collateral-slash:" .. effect.from .. ":" .. effect.subTargets[1]
2023-07-11 13:15:38 +00:00
if #effect.subTargets > 1 then
prompt = nil
end
2023-09-21 15:21:28 +00:00
if room:askForUseCard(to, "slash", nil, prompt, nil, {
must_targets = effect.subTargets,
exclusive_targets = effect.subTargets,
bypass_distances = true,
bypass_times = true
}, effect) then
else
2023-09-21 15:21:28 +00:00
room:obtainCard(effect.from, room:getPlayerById(effect.to):getEquipment(Card.SubtypeWeapon), true,
fk.ReasonGive)
end
end
}
2023-09-21 15:21:28 +00:00
local collateral = fk.CreateTrickCard {
name = "collateral",
suit = Card.Club,
number = 12,
2023-09-21 15:21:28 +00:00
skill = collateralSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ collateral, collateral:clone(Card.Club, 13) })
2023-09-21 15:21:28 +00:00
local exNihiloSkill = fk.CreateActiveSkill {
name = "ex_nihilo_skill",
mod_target_filter = function(self, to_select, selected, user, card, distance_limited)
2023-09-21 15:21:28 +00:00
local player = Fk:currentRoom():getPlayerById(to_select)
local from = Fk:currentRoom():getPlayerById(user)
return not (card and from:isProhibited(player, card))
end,
can_use = function(self, player, card)
return not player:isProhibited(player, card)
end,
on_use = function(self, room, cardUseEvent)
if not cardUseEvent.tos or #TargetGroup:getRealTargets(cardUseEvent.tos) == 0 then
cardUseEvent.tos = { { cardUseEvent.from } }
end
end,
2023-07-11 13:15:38 +00:00
on_effect = function(self, room, effect)
local target = room:getPlayerById(effect.to)
2023-09-21 15:21:28 +00:00
if target.dead then
return
end
2023-07-11 13:15:38 +00:00
target:drawCards(2, "ex_nihilo")
end
}
2023-09-21 15:21:28 +00:00
local exNihilo = fk.CreateTrickCard {
name = "ex_nihilo",
suit = Card.Heart,
number = 7,
2023-09-21 15:21:28 +00:00
skill = exNihiloSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ exNihilo, exNihilo:clone(Card.Heart, 8), exNihilo:clone(Card.Heart, 9),
exNihilo:clone(Card.Heart, 11) })
2023-09-21 15:21:28 +00:00
local nullificationSkill = fk.CreateActiveSkill {
name = "nullification_skill",
can_use = function()
return false
end,
2023-09-21 15:21:28 +00:00
on_use = function()
RoomInstance:delay(1200)
end,
on_effect = function(self, room, effect)
if effect.responseToEvent then
effect.responseToEvent.isCancellOut = true
end
end
}
2023-09-21 15:21:28 +00:00
local nullification = fk.CreateTrickCard {
name = "nullification",
suit = Card.Spade,
number = 11,
2023-09-21 15:21:28 +00:00
skill = nullificationSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ nullification, nullification:clone(Card.Club, 12), nullification:clone(Card.Club, 13),
nullification:clone(Card.Diamond, 12) })
2023-09-21 15:21:28 +00:00
local savageAssaultSkill = fk.CreateActiveSkill {
name = "savage_assault_skill",
can_use = Util.AoeCanUse,
on_use = Util.AoeOnUse,
mod_target_filter = function(self, to_select, selected, user, card, distance_limited)
2023-09-21 15:21:28 +00:00
local player = Fk:currentRoom():getPlayerById(to_select)
local from = Fk:currentRoom():getPlayerById(user)
return user ~= to_select and not (card and from:isProhibited(player, card))
end,
on_effect = function(self, room, effect)
2023-09-21 15:21:28 +00:00
if room:askForResponse(room:getPlayerById(effect.to), 'slash', nil, nil, false, nil, effect) then
else
room:damage({
from = room:getPlayerById(effect.from),
to = room:getPlayerById(effect.to),
card = effect.card,
2023-05-28 10:45:54 +00:00
damage = 1,
damageType = fk.NormalDamage,
2023-09-21 15:21:28 +00:00
skillName = self.name
})
end
end
}
2023-09-21 15:21:28 +00:00
local savageAssault = fk.CreateTrickCard {
name = "savage_assault",
suit = Card.Spade,
number = 7,
is_damage_card = true,
multiple_targets = true,
2023-09-21 15:21:28 +00:00
skill = savageAssaultSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ savageAssault, savageAssault:clone(Card.Spade, 13), savageAssault:clone(Card.Club, 7) })
2023-09-21 15:21:28 +00:00
local archeryAttackSkill = fk.CreateActiveSkill {
name = "archery_attack_skill",
can_use = Util.AoeCanUse,
on_use = Util.AoeOnUse,
mod_target_filter = function(self, to_select, selected, user, card, distance_limited)
2023-09-21 15:21:28 +00:00
local player = Fk:currentRoom():getPlayerById(to_select)
local from = Fk:currentRoom():getPlayerById(user)
return user ~= to_select and not (card and from:isProhibited(player, card))
end,
on_effect = function(self, room, effect)
2023-09-21 15:21:28 +00:00
if room:askForResponse(room:getPlayerById(effect.to), 'jink', nil, nil, false, nil, effect) then
else
room:damage({
from = room:getPlayerById(effect.from),
to = room:getPlayerById(effect.to),
card = effect.card,
2023-05-28 10:45:54 +00:00
damage = 1,
damageType = fk.NormalDamage,
2023-09-21 15:21:28 +00:00
skillName = self.name
})
end
end
}
2023-09-21 15:21:28 +00:00
local archeryAttack = fk.CreateTrickCard {
name = "archery_attack",
suit = Card.Heart,
number = 1,
is_damage_card = true,
multiple_targets = true,
2023-09-21 15:21:28 +00:00
skill = archeryAttackSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ archeryAttack })
2023-09-21 15:21:28 +00:00
local godSalvationSkill = fk.CreateActiveSkill {
name = "god_salvation_skill",
can_use = Util.GlobalCanUse,
on_use = Util.GlobalOnUse,
mod_target_filter = function(self, to_select, selected, user, card, distance_limited)
2023-09-21 15:21:28 +00:00
local player = Fk:currentRoom():getPlayerById(to_select)
local from = Fk:currentRoom():getPlayerById(user)
return not (card and from:isProhibited(player, card))
end,
about_to_effect = function(self, room, effect)
if not room:getPlayerById(effect.to):isWounded() then
return true
end
end,
on_effect = function(self, room, effect)
2023-07-11 13:15:38 +00:00
local player = room:getPlayerById(effect.from)
local target = room:getPlayerById(effect.to)
if target:isWounded() and not target.dead then
room:recover({
who = target,
num = 1,
recoverBy = player,
card = effect.card,
2023-09-21 15:21:28 +00:00
skillName = self.name
2023-07-11 13:15:38 +00:00
})
end
end
}
2023-09-21 15:21:28 +00:00
local godSalvation = fk.CreateTrickCard {
name = "god_salvation",
suit = Card.Heart,
number = 1,
multiple_targets = true,
2023-09-21 15:21:28 +00:00
skill = godSalvationSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ godSalvation })
2023-09-21 15:21:28 +00:00
local amazingGraceSkill = fk.CreateActiveSkill {
name = "amazing_grace_skill",
can_use = Util.GlobalCanUse,
on_use = Util.GlobalOnUse,
mod_target_filter = function(self, to_select, selected, user, card, distance_limited)
2023-09-21 15:21:28 +00:00
local player = Fk:currentRoom():getPlayerById(to_select)
local from = Fk:currentRoom():getPlayerById(user)
return not (card and from:isProhibited(player, card))
end,
on_effect = function(self, room, effect)
local to = room:getPlayerById(effect.to)
if not (effect.extra_data and effect.extra_data.AGFilled) then
return
end
local chosen = room:askForAG(to, effect.extra_data.AGFilled, false, self.name)
room:takeAG(to, chosen, room.players)
room:obtainCard(effect.to, chosen, true, fk.ReasonPrey)
table.removeOne(effect.extra_data.AGFilled, chosen)
end
}
2023-09-21 15:21:28 +00:00
local amazingGraceAction = fk.CreateTriggerSkill {
name = "amazing_grace_action",
global = true,
2023-09-21 15:21:28 +00:00
priority = {
[fk.BeforeCardUseEffect] = 0,
[fk.CardUseFinished] = 10
}, -- game rule
events = { fk.BeforeCardUseEffect, fk.CardUseFinished },
can_trigger = function(self, event, target, player, data)
local frameFilled = data.extra_data and data.extra_data.AGFilled
if event == fk.BeforeCardUseEffect then
return data.card.trueName == 'amazing_grace' and not frameFilled
else
return frameFilled
end
end,
on_trigger = function(self, event, target, player, data)
local room = player.room
if event == fk.BeforeCardUseEffect then
local toDisplay = room:getNCards(#TargetGroup:getRealTargets(data.tos))
room:moveCards({
ids = toDisplay,
toArea = Card.Processing,
2023-09-21 15:21:28 +00:00
moveReason = fk.ReasonPut
})
table.forEach(room.players, function(p)
room:fillAG(p, toDisplay)
end)
data.extra_data = data.extra_data or {}
data.extra_data.AGFilled = toDisplay
else
table.forEach(room.players, function(p)
room:closeAG(p)
end)
if data.extra_data and data.extra_data.AGFilled then
local toDiscard = table.filter(data.extra_data.AGFilled, function(id)
return room:getCardArea(id) == Card.Processing
end)
if #toDiscard > 0 then
room:moveCards({
ids = toDiscard,
toArea = Card.DiscardPile,
2023-09-21 15:21:28 +00:00
moveReason = fk.ReasonPutIntoDiscardPile
})
end
end
data.extra_data.AGFilled = nil
end
2023-09-21 15:21:28 +00:00
end
}
Fk:addSkill(amazingGraceAction)
2023-09-21 15:21:28 +00:00
local amazingGrace = fk.CreateTrickCard {
name = "amazing_grace",
suit = Card.Heart,
number = 3,
multiple_targets = true,
2023-09-21 15:21:28 +00:00
skill = amazingGraceSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ amazingGrace, amazingGrace:clone(Card.Heart, 4) })
2023-09-21 15:21:28 +00:00
local lightningSkill = fk.CreateActiveSkill {
name = "lightning_skill",
mod_target_filter = function(self, to_select, selected, user, card, distance_limited)
2023-09-21 15:21:28 +00:00
local player = Fk:currentRoom():getPlayerById(to_select)
local from = Fk:currentRoom():getPlayerById(user)
return not (card and from:isProhibited(player, card))
end,
can_use = function(self, player, card)
return not player:isProhibited(player, card)
end,
on_use = function(self, room, use)
if not use.tos or #TargetGroup:getRealTargets(use.tos) == 0 then
use.tos = { { use.from } }
end
end,
on_effect = function(self, room, effect)
local to = room:getPlayerById(effect.to)
local judge = {
who = to,
reason = "lightning",
2023-09-21 15:21:28 +00:00
pattern = ".|.|^spade;.|1,10,11,12,13|spade"
}
room:judge(judge)
2023-09-21 15:21:28 +00:00
if judge.card.suit == Card.Spade and judge.card.number >= 2 and judge.card.number <= 9 then
room:damage {
to = to,
damage = 3,
card = effect.card,
damageType = fk.ThunderDamage,
2023-09-21 15:21:28 +00:00
skillName = self.name
}
2023-09-21 15:21:28 +00:00
room:moveCards {
ids = { effect.cardId },
toArea = Card.DiscardPile,
2023-06-04 11:40:14 +00:00
moveReason = fk.ReasonUse
}
else
self:onNullified(room, effect)
end
end,
on_nullified = function(self, room, effect)
local to = room:getPlayerById(effect.to)
local nextp = to
repeat
nextp = nextp:getNextAlive(true)
2023-09-21 15:21:28 +00:00
if nextp == to then
break
end
until not nextp:hasDelayedTrick("lightning") and not nextp:isProhibited(nextp, effect.card)
if effect.card:isVirtual() then
nextp:addVirtualEquip(effect.card)
end
2023-09-21 15:21:28 +00:00
room:moveCards {
ids = room:getSubcardsByRule(effect.card, { Card.Processing }),
to = nextp.id,
toArea = Card.PlayerJudge,
moveReason = fk.ReasonPut
}
2023-09-21 15:21:28 +00:00
end
}
2023-09-21 15:21:28 +00:00
local lightning = fk.CreateDelayedTrickCard {
name = "lightning",
suit = Card.Spade,
number = 1,
2023-09-21 15:21:28 +00:00
skill = lightningSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ lightning, lightning:clone(Card.Heart, 12) })
2023-09-21 15:21:28 +00:00
local indulgenceSkill = fk.CreateActiveSkill {
name = "indulgence_skill",
mod_target_filter = function(self, to_select, selected, user, card, distance_limited)
2023-09-21 15:21:28 +00:00
local player = Fk:currentRoom():getPlayerById(to_select)
local from = Fk:currentRoom():getPlayerById(user)
return user ~= to_select and not (card and from:isProhibited(player, card))
end,
target_filter = function(self, to_select, selected, _, card)
2023-09-21 15:21:28 +00:00
return #selected < 1 and self:modTargetFilter(to_select, selected, Self.id, card, true)
end,
target_num = 1,
on_effect = function(self, room, effect)
local to = room:getPlayerById(effect.to)
local judge = {
who = to,
reason = "indulgence",
2023-09-21 15:21:28 +00:00
pattern = ".|.|heart"
}
room:judge(judge)
2023-09-21 15:21:28 +00:00
if judge.card.suit ~= Card.Heart then
to:skip(Player.Play)
end
self:onNullified(room, effect)
end,
on_nullified = function(self, room, effect)
2023-09-21 15:21:28 +00:00
room:moveCards {
ids = room:getSubcardsByRule(effect.card, { Card.Processing }),
toArea = Card.DiscardPile,
2023-06-04 11:40:14 +00:00
moveReason = fk.ReasonUse
}
2023-09-21 15:21:28 +00:00
end
}
2023-09-21 15:21:28 +00:00
local indulgence = fk.CreateDelayedTrickCard {
name = "indulgence",
suit = Card.Spade,
number = 6,
2023-09-21 15:21:28 +00:00
skill = indulgenceSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ indulgence, indulgence:clone(Card.Club, 6), indulgence:clone(Card.Heart, 6) })
2023-09-21 15:21:28 +00:00
local crossbowAudio = fk.CreateTriggerSkill {
name = "#crossbowAudio",
2023-09-21 15:21:28 +00:00
refresh_events = { fk.CardUsing },
can_refresh = function(self, event, target, player, data)
2023-09-21 15:21:28 +00:00
return target == player and player:hasSkill(self.name) and player.phase == Player.Play and data.card.trueName ==
"slash" and player:usedCardTimes("slash", Player.HistoryPhase) > 1
end,
on_refresh = function(self, event, target, player, data)
local room = player.room
room:broadcastPlaySound("./packages/standard_cards/audio/card/crossbow")
room:setEmotion(player, "./packages/standard_cards/image/anim/crossbow")
2023-09-21 15:21:28 +00:00
end
}
2023-09-21 15:21:28 +00:00
local crossbowSkill = fk.CreateTargetModSkill {
name = "#crossbow_skill",
attached_equip = "crossbow",
bypass_times = function(self, player, skill, scope)
2023-09-21 15:21:28 +00:00
if player:hasSkill(self.name) and skill.trueName == "slash_skill" and scope == Player.HistoryPhase then
return true
end
2023-09-21 15:21:28 +00:00
end
}
crossbowSkill:addRelatedSkill(crossbowAudio)
Fk:addSkill(crossbowSkill)
2023-09-21 15:21:28 +00:00
local crossbow = fk.CreateWeapon {
name = "crossbow",
suit = Card.Club,
number = 1,
attack_range = 1,
2023-09-21 15:21:28 +00:00
equip_skill = crossbowSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ crossbow, crossbow:clone(Card.Diamond, 1) })
fk.MarkArmorNullified = "mark__armor_nullified"
local armorInvalidity = fk.CreateInvaliditySkill {
name = "armor_invalidity",
global = true,
invalidity_func = function(self, from, skill)
2023-07-11 13:15:38 +00:00
if from:getMark(fk.MarkArmorNullified) > 0 and skill.attached_equip then
for _, card in ipairs(Fk.cards) do
if card.sub_type == Card.SubtypeArmor and skill.attached_equip == card.name then
return true
end
end
end
end
}
Fk:addSkill(armorInvalidity)
2023-09-21 15:21:28 +00:00
local qingGangSkill = fk.CreateTriggerSkill {
name = "#qinggang_sword_skill",
attached_equip = "qinggang_sword",
frequency = Skill.Compulsory,
events = { fk.TargetSpecified },
can_trigger = function(self, event, target, player, data)
2023-09-21 15:21:28 +00:00
return target == player and player:hasSkill(self.name) and data.card and data.card.trueName == "slash"
end,
on_use = function(self, event, target, player, data)
local room = player.room
room:addPlayerMark(room:getPlayerById(data.to), fk.MarkArmorNullified)
data.extra_data = data.extra_data or {}
data.extra_data.qinggangNullified = data.extra_data.qinggangNullified or {}
2023-09-21 15:21:28 +00:00
data.extra_data.qinggangNullified[tostring(data.to)] =
(data.extra_data.qinggangNullified[tostring(data.to)] or 0) + 1
end,
refresh_events = { fk.CardUseFinished },
can_refresh = function(self, event, target, player, data)
return data.extra_data and data.extra_data.qinggangNullified
end,
on_refresh = function(self, event, target, player, data)
local room = player.room
for key, num in pairs(data.extra_data.qinggangNullified) do
local p = room:getPlayerById(tonumber(key))
if p:getMark(fk.MarkArmorNullified) > 0 then
room:removePlayerMark(p, fk.MarkArmorNullified, num)
end
end
data.qinggangNullified = nil
2023-09-21 15:21:28 +00:00
end
}
Fk:addSkill(qingGangSkill)
2023-09-21 15:21:28 +00:00
local qingGang = fk.CreateWeapon {
name = "qinggang_sword",
suit = Card.Spade,
number = 6,
attack_range = 2,
2023-09-21 15:21:28 +00:00
equip_skill = qingGangSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ qingGang })
2023-09-21 15:21:28 +00:00
local iceSwordSkill = fk.CreateTriggerSkill {
name = "#ice_sword_skill",
attached_equip = "ice_sword",
2023-09-21 15:21:28 +00:00
events = { fk.DamageCaused },
can_trigger = function(self, event, target, player, data)
2023-09-21 15:21:28 +00:00
return
target == player and player:hasSkill(self.name) and (not data.chain) and data.card and data.card.trueName ==
"slash" and not data.to:isNude()
end,
on_use = function(self, event, target, player, data)
local room = player.room
local to = data.to
for i = 1, 2 do
2023-09-21 15:21:28 +00:00
if player.dead or to.dead or to:isNude() then
break
end
local card = room:askForCardChosen(player, to, "he", self.name)
2023-09-21 15:21:28 +00:00
room:throwCard({ card }, self.name, to, player)
end
return true
end
}
Fk:addSkill(iceSwordSkill)
2023-09-21 15:21:28 +00:00
local iceSword = fk.CreateWeapon {
name = "ice_sword",
suit = Card.Spade,
number = 2,
attack_range = 2,
2023-09-21 15:21:28 +00:00
equip_skill = iceSwordSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ iceSword })
2023-09-21 15:21:28 +00:00
local doubleSwordsSkill = fk.CreateTriggerSkill {
name = "#double_swords_skill",
attached_equip = "double_swords",
2023-09-21 15:21:28 +00:00
events = { fk.TargetSpecified },
can_trigger = function(self, event, target, player, data)
2023-09-21 15:21:28 +00:00
if target == player and player:hasSkill(self.name) and data.card and data.card.trueName == "slash" then
local target = player.room:getPlayerById(data.to)
2023-09-21 15:21:28 +00:00
return target.gender ~= player.gender and target.gender ~= General.Agender and player.gender ~=
General.Agender
end
end,
on_use = function(self, event, target, player, data)
local room = player.room
local to = player.room:getPlayerById(data.to)
2023-07-11 13:15:38 +00:00
if to:isKongcheng() then
player:drawCards(1, self.name)
2023-07-11 13:15:38 +00:00
else
2023-09-21 15:21:28 +00:00
local result = room:askForDiscard(to, 1, 1, false, self.name, true, ".",
"#double_swords-invoke:" .. player.id)
2023-07-11 13:15:38 +00:00
if #result == 0 then
player:drawCards(1, self.name)
end
end
2023-09-21 15:21:28 +00:00
end
}
Fk:addSkill(doubleSwordsSkill)
2023-09-21 15:21:28 +00:00
local doubleSwords = fk.CreateWeapon {
name = "double_swords",
suit = Card.Spade,
number = 2,
attack_range = 2,
2023-09-21 15:21:28 +00:00
equip_skill = doubleSwordsSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ doubleSwords })
2023-09-21 15:21:28 +00:00
local bladeSkill = fk.CreateTriggerSkill {
name = "#blade_skill",
attached_equip = "blade",
2023-09-21 15:21:28 +00:00
events = { fk.CardEffectCancelledOut },
can_trigger = function(self, event, target, player, data)
2023-09-21 15:21:28 +00:00
return player:hasSkill(self.name) and data.from == player.id and data.card.trueName == "slash" and
not player.room:getPlayerById(data.to).dead
end,
on_cost = function(self, event, target, player, data)
2023-09-21 15:21:28 +00:00
local extra_data = {
must_targets = { data.to },
exclusive_targets = { data.to },
bypass_distances = true,
bypass_times = true
}
if extra_data then
if extra_data.bypass_distances then
player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit .. "", 1)
end
if extra_data.bypass_times ~= false then
player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit .. "-tmp", 1)
end
fk.useMustTargets = extra_data.must_targets
end
local command = "AskForUseCard"
player.room:notifyMoveFocus(player, "slash")
local pattern = "slash"
local prompt = "#blade_slash:" .. data.to
local useData = {
user = player,
cardName = "slash",
pattern = pattern,
extraData = extra_data
}
local use = nil
if self.cost_data == nil then
player.room.logic:trigger(fk.AskForCardUse, player, useData)
if type(useData.result) == "table" then
useData = useData.result
useData.extraUse = extra_data ~= nil
use = useData
end
end
local usedata = { "slash", pattern, prompt, true, extra_data }
if use == nil then
Fk.currentResponsePattern = pattern
local result = player.room:doRequest(player, command, json.encode(usedata))
Fk.currentResponsePattern = nil
if result ~= "" then
result = player.room:handleUseCardReply(player, result)
result.extraUse = extra_data ~= nil
use = result
end
end
fk.useMustTargets = nil
player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit .. "-tmp", 0)
player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit .. "-tmp", 0)
if use
then
self.cost_data = use
return true
end
end,
on_use = function(self, event, target, player, data)
2023-09-21 15:21:28 +00:00
while true do
local use = self.cost_data
player.room:useCard(use)
if use.breakEvent and self:onCost(event, target, player, data) then
else
break
end
end
self.cost_data = nil
end
}
Fk:addSkill(bladeSkill)
2023-09-21 15:21:28 +00:00
local blade = fk.CreateWeapon {
name = "blade",
suit = Card.Spade,
number = 5,
attack_range = 3,
2023-09-21 15:21:28 +00:00
equip_skill = bladeSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ blade })
2023-09-21 15:21:28 +00:00
local spearSkill = fk.CreateViewAsSkill {
name = "spear_skill",
attached_equip = "spear",
pattern = "slash",
card_filter = function(self, to_select, selected)
2023-09-21 15:21:28 +00:00
if #selected == 2 then
return false
end
return Fk:currentRoom():getCardArea(to_select) ~= Player.Equip
end,
view_as = function(self, cards)
if #cards ~= 2 then
return nil
end
local c = Fk:cloneCard("slash")
c.skillName = "spear"
c:addSubcards(cards)
return c
2023-09-21 15:21:28 +00:00
end
}
Fk:addSkill(spearSkill)
2023-09-21 15:21:28 +00:00
local spear = fk.CreateWeapon {
name = "spear",
suit = Card.Spade,
number = 12,
attack_range = 3,
2023-09-21 15:21:28 +00:00
equip_skill = spearSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ spear })
2023-09-21 15:21:28 +00:00
local axeSkill = fk.CreateTriggerSkill {
name = "#axe_skill",
attached_equip = "axe",
2023-09-21 15:21:28 +00:00
events = { fk.CardEffectCancelledOut },
can_trigger = function(self, event, target, player, data)
2023-09-21 15:21:28 +00:00
return player:hasSkill(self.name) and data.from == player.id and data.card.trueName == "slash" and
not player.room:getPlayerById(data.to).dead
end,
on_cost = function(self, event, target, player, data)
local room = player.room
2023-07-11 13:15:38 +00:00
local pattern
if player:getEquipment(Card.SubtypeWeapon) then
2023-09-21 15:21:28 +00:00
pattern = ".|.|.|.|.|.|^" .. tostring(player:getEquipment(Card.SubtypeWeapon))
2023-07-11 13:15:38 +00:00
else
pattern = "."
end
2023-09-21 15:21:28 +00:00
player.axe_to = data.to
local cards = room:askForDiscard(player, 2, 2, true, self.name, true, pattern, "#axe-invoke::" .. data.to, true)
2023-07-11 13:15:38 +00:00
if #cards > 0 then
self.cost_data = cards
return true
end
end,
on_use = function(self, event, target, player, data)
local room = player.room
room:throwCard(self.cost_data, "axe", player, player)
return true
2023-09-21 15:21:28 +00:00
end
}
Fk:addSkill(axeSkill)
2023-09-21 15:21:28 +00:00
local axe = fk.CreateWeapon {
name = "axe",
suit = Card.Diamond,
number = 5,
attack_range = 3,
2023-09-21 15:21:28 +00:00
equip_skill = axeSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ axe })
2023-09-21 15:21:28 +00:00
local halberdAudio = fk.CreateTriggerSkill {
name = "#halberdAudio",
2023-09-21 15:21:28 +00:00
refresh_events = { fk.CardUsing },
can_refresh = function(self, event, target, player, data)
2023-09-21 15:21:28 +00:00
return target == player and player:hasSkill(self.name) and data.card.trueName == "slash" and
#TargetGroup:getRealTargets(data.tos) > 1
end,
on_refresh = function(self, event, target, player, data)
local room = player.room
room:broadcastPlaySound("./packages/standard_cards/audio/card/halberd")
room:setEmotion(player, "./packages/standard_cards/image/anim/halberd")
2023-09-21 15:21:28 +00:00
end
}
2023-09-21 15:21:28 +00:00
local halberdSkill = fk.CreateTargetModSkill {
name = "#halberd_skill",
attached_equip = "halberd",
extra_target_func = function(self, player, skill, card)
2023-09-21 15:21:28 +00:00
if player:hasSkill(self.name) and skill.trueName == "slash_skill" and card then
local cards = card:isVirtual() and card.subcards or { card.id }
local handcards = player:getCardIds(Player.Hand)
2023-09-21 15:21:28 +00:00
if #cards == #handcards and table.every(cards, function(id)
return table.contains(handcards, id)
end) then
return 2
end
end
2023-09-21 15:21:28 +00:00
end
}
halberdSkill:addRelatedSkill(halberdAudio)
Fk:addSkill(halberdSkill)
2023-09-21 15:21:28 +00:00
local halberd = fk.CreateWeapon {
name = "halberd",
suit = Card.Diamond,
number = 12,
attack_range = 4,
2023-09-21 15:21:28 +00:00
equip_skill = halberdSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ halberd })
2023-09-21 15:21:28 +00:00
local kylinBowSkill = fk.CreateTriggerSkill {
name = "#kylin_bow_skill",
attached_equip = "kylin_bow",
2023-09-21 15:21:28 +00:00
events = { fk.DamageCaused },
can_trigger = function(self, event, target, player, data)
2023-09-21 15:21:28 +00:00
local ret = target == player and player:hasSkill(self.name) and data.card and data.card.trueName == "slash" and
(not data.chain)
if ret then
---@type ServerPlayer
local to = data.to
2023-09-21 15:21:28 +00:00
return to:getEquipment(Card.SubtypeDefensiveRide) or to:getEquipment(Card.SubtypeOffensiveRide)
end
end,
on_use = function(self, event, target, player, data)
local room = player.room
local to = data.to
local ride_tab = {}
if to:getEquipment(Card.SubtypeDefensiveRide) then
table.insert(ride_tab, "+1")
end
if to:getEquipment(Card.SubtypeOffensiveRide) then
table.insert(ride_tab, "-1")
end
2023-09-21 15:21:28 +00:00
if #ride_tab == 0 then
return
end
local choice = room:askForChoice(player, ride_tab, self.name)
if choice == "+1" then
room:throwCard(to:getEquipment(Card.SubtypeDefensiveRide), self.name, to, player)
else
room:throwCard(to:getEquipment(Card.SubtypeOffensiveRide), self.name, to, player)
end
end
}
Fk:addSkill(kylinBowSkill)
2023-09-21 15:21:28 +00:00
local kylinBow = fk.CreateWeapon {
name = "kylin_bow",
suit = Card.Heart,
number = 5,
attack_range = 5,
2023-09-21 15:21:28 +00:00
equip_skill = kylinBowSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ kylinBow })
2023-09-21 15:21:28 +00:00
local eightDiagramSkill = fk.CreateTriggerSkill {
name = "#eight_diagram_skill",
attached_equip = "eight_diagram",
2023-09-21 15:21:28 +00:00
events = { fk.AskForCardUse, fk.AskForCardResponse },
can_trigger = function(self, event, target, player, data)
return target == player and player:hasSkill(self.name) and
2023-09-21 15:21:28 +00:00
(data.cardName == "jink" or
(data.pattern and Exppattern:Parse(data.pattern):matchExp("jink|0|nosuit|none")))
end,
on_use = function(self, event, target, player, data)
local room = player.room
local judgeData = {
who = player,
reason = self.name,
2023-09-21 15:21:28 +00:00
pattern = ".|.|heart,diamond"
}
room:judge(judgeData)
if judgeData.card.color == Card.Red then
if event == fk.AskForCardUse then
data.result = {
from = player.id,
2023-09-21 15:21:28 +00:00
card = Fk:cloneCard('jink')
}
data.result.card.skillName = "eight_diagram"
if data.eventData then
data.result.toCard = data.eventData.toCard
data.result.responseToEvent = data.eventData.responseToEvent
end
else
data.result = Fk:cloneCard('jink')
data.result.skillName = "eight_diagram"
end
return true
end
end
}
Fk:addSkill(eightDiagramSkill)
2023-09-21 15:21:28 +00:00
local eightDiagram = fk.CreateArmor {
name = "eight_diagram",
suit = Card.Spade,
number = 2,
2023-09-21 15:21:28 +00:00
equip_skill = eightDiagramSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ eightDiagram, eightDiagram:clone(Card.Club, 2) })
2023-09-21 15:21:28 +00:00
local niohShieldSkill = fk.CreateTriggerSkill {
name = "#nioh_shield_skill",
attached_equip = "nioh_shield",
frequency = Skill.Compulsory,
2023-09-21 15:21:28 +00:00
events = { fk.PreCardEffect },
can_trigger = function(self, event, target, player, data)
2023-09-21 15:21:28 +00:00
return player.id == data.to and player:hasSkill(self.name) and data.card.trueName == "slash" and
data.card.color == Card.Black
end,
2023-09-21 15:21:28 +00:00
on_use = function()
return true
end
}
Fk:addSkill(niohShieldSkill)
2023-09-21 15:21:28 +00:00
local niohShield = fk.CreateArmor {
name = "nioh_shield",
suit = Card.Club,
number = 2,
2023-09-21 15:21:28 +00:00
equip_skill = niohShieldSkill
}
2023-09-21 15:21:28 +00:00
extension:addCards({ niohShield })
2023-09-21 15:21:28 +00:00
local horseSkill = fk.CreateDistanceSkill {
name = "horse_skill",
global = true,
correct_func = function(self, from, to)
local ret = 0
if from:getEquipment(Card.SubtypeOffensiveRide) then
ret = ret - 1
end
if to:getEquipment(Card.SubtypeDefensiveRide) then
ret = ret + 1
end
return ret
2023-09-21 15:21:28 +00:00
end
}
if not Fk.skills["horse_skill"] then
Fk:addSkill(horseSkill)
end
2023-09-21 15:21:28 +00:00
local diLu = fk.CreateDefensiveRide {
name = "dilu",
suit = Card.Club,
2023-09-21 15:21:28 +00:00
number = 5
}
2023-09-21 15:21:28 +00:00
extension:addCards({ diLu })
2023-09-21 15:21:28 +00:00
local jueYing = fk.CreateDefensiveRide {
name = "jueying",
suit = Card.Spade,
2023-09-21 15:21:28 +00:00
number = 5
}
2023-09-21 15:21:28 +00:00
extension:addCards({ jueYing })
2023-09-21 15:21:28 +00:00
local zhuaHuangFeiDian = fk.CreateDefensiveRide {
name = "zhuahuangfeidian",
suit = Card.Heart,
2023-09-21 15:21:28 +00:00
number = 13
}
2023-09-21 15:21:28 +00:00
extension:addCards({ zhuaHuangFeiDian })
2023-09-21 15:21:28 +00:00
local chiTu = fk.CreateOffensiveRide {
name = "chitu",
suit = Card.Heart,
2023-09-21 15:21:28 +00:00
number = 5
}
2023-09-21 15:21:28 +00:00
extension:addCards({ chiTu })
2023-09-21 15:21:28 +00:00
local daYuan = fk.CreateOffensiveRide {
name = "dayuan",
suit = Card.Spade,
2023-09-21 15:21:28 +00:00
number = 13
}
2023-09-21 15:21:28 +00:00
extension:addCards({ daYuan })
2023-09-21 15:21:28 +00:00
local ziXing = fk.CreateOffensiveRide {
name = "zixing",
suit = Card.Diamond,
2023-09-21 15:21:28 +00:00
number = 13
}
2023-09-21 15:21:28 +00:00
extension:addCards({ ziXing })
dofile "packages/standard_cards/i18n/init.lua"
return extension