mirror of
https://github.com/Qsgs-Fans/FreeKill.git
synced 2024-11-16 03:32:34 +08:00
禅与bugfix (#312)
- 将Utility如canUseCardTo的一些函数搬运到了本体 - 为技能添加hooked_piles属性,当失去技能时自动弃置hooked_piles内的所有私人牌堆 - 修复了添加技能没写source_skill的bug - 修复了ActiveSkill的interaction不传入Skill本身而是metatable的bug - 修复了主动询问canUse时没有传入extra_data的bug - 修复了多选时按钮选项变回空白的bug - 修复了判定阶段被中途拿走判定牌后报错的bug
This commit is contained in:
parent
ea65a3dd4b
commit
d4bb4e21bb
|
@ -39,6 +39,7 @@ GraphicsBox {
|
||||||
id: choicetitle
|
id: choicetitle
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: luatr(modelData)
|
text: luatr(modelData)
|
||||||
|
triggered: root.result.includes(index)
|
||||||
enabled: options.indexOf(modelData) !== -1
|
enabled: options.indexOf(modelData) !== -1
|
||||||
&& (root.result.length < max_num || triggered)
|
&& (root.result.length < max_num || triggered)
|
||||||
textFont.pixelSize: 24
|
textFont.pixelSize: 24
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
---@field public special_skills? string[] @ 衍生技能,如重铸
|
---@field public special_skills? string[] @ 衍生技能,如重铸
|
||||||
---@field public is_damage_card boolean @ 是否为会造成伤害的牌
|
---@field public is_damage_card boolean @ 是否为会造成伤害的牌
|
||||||
---@field public multiple_targets boolean @ 是否为指定多个目标的牌
|
---@field public multiple_targets boolean @ 是否为指定多个目标的牌
|
||||||
|
---@field public is_passive? boolean @ 是否只能在响应时使用或打出
|
||||||
---@field public is_derived? boolean @ 判断是否为衍生牌
|
---@field public is_derived? boolean @ 判断是否为衍生牌
|
||||||
local Card = class("Card")
|
local Card = class("Card")
|
||||||
|
|
||||||
|
@ -145,11 +146,12 @@ function Card:clone(suit, number)
|
||||||
newCard.special_skills = self.special_skills
|
newCard.special_skills = self.special_skills
|
||||||
newCard.is_damage_card = self.is_damage_card
|
newCard.is_damage_card = self.is_damage_card
|
||||||
newCard.multiple_targets = self.multiple_targets
|
newCard.multiple_targets = self.multiple_targets
|
||||||
|
newCard.is_passive = self.is_passive
|
||||||
newCard.is_derived = self.is_derived
|
newCard.is_derived = self.is_derived
|
||||||
return newCard
|
return newCard
|
||||||
end
|
end
|
||||||
|
|
||||||
--- 检测是否为虚拟卡牌,如果其ID为0及以下,则为虚拟卡牌。
|
--- 检测是否为虚拟卡牌,如果其ID为0,则为虚拟卡牌。
|
||||||
function Card:isVirtual()
|
function Card:isVirtual()
|
||||||
return self.id == 0
|
return self.id == 0
|
||||||
end
|
end
|
||||||
|
|
|
@ -872,9 +872,20 @@ end
|
||||||
|
|
||||||
--- 确认玩家是否可以使用特定牌。
|
--- 确认玩家是否可以使用特定牌。
|
||||||
---@param card Card @ 特定牌
|
---@param card Card @ 特定牌
|
||||||
function Player:canUse(card)
|
---@param extra_data? UseExtraData @ 额外数据
|
||||||
assert(card, "Error: No Card")
|
function Player:canUse(card, extra_data)
|
||||||
return card.skill:canUse(self, card)
|
return card.skill:canUse(self, card, extra_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- 确认玩家是否可以对特定玩家使用特定牌。
|
||||||
|
---@param card Card @ 特定牌
|
||||||
|
---@param to Player @ 特定玩家
|
||||||
|
---@param extra_data? UseExtraData @ 额外数据
|
||||||
|
function Player:canUseTo(card, to, extra_data)
|
||||||
|
if self:prohibitUse(card) or self:isProhibited(to, card) then return false end
|
||||||
|
local distance_limited = not (extra_data and extra_data.bypass_distances)
|
||||||
|
local can_use = self:canUse(card, extra_data)
|
||||||
|
return can_use and card.skill:modTargetFilter(to.id, {}, self.id, card, distance_limited)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- 确认玩家是否被禁止对特定玩家使用特定牌。
|
--- 确认玩家是否被禁止对特定玩家使用特定牌。
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
---@field public main_skill UsableSkill
|
---@field public main_skill UsableSkill
|
||||||
---@field public max_use_time integer[]
|
---@field public max_use_time integer[]
|
||||||
---@field public expand_pile? string | integer[] | fun(self: UsableSkill): integer[]|string?
|
---@field public expand_pile? string | integer[] | fun(self: UsableSkill): integer[]|string?
|
||||||
|
---@field public derived_piles? string | string[]
|
||||||
local UsableSkill = Skill:subclass("UsableSkill")
|
local UsableSkill = Skill:subclass("UsableSkill")
|
||||||
|
|
||||||
function UsableSkill:initialize(name, frequency)
|
function UsableSkill:initialize(name, frequency)
|
||||||
|
|
|
@ -48,6 +48,11 @@ end
|
||||||
local function readUsableSpecToSkill(skill, spec)
|
local function readUsableSpecToSkill(skill, spec)
|
||||||
readCommonSpecToSkill(skill, spec)
|
readCommonSpecToSkill(skill, spec)
|
||||||
assert(spec.main_skill == nil or spec.main_skill:isInstanceOf(UsableSkill))
|
assert(spec.main_skill == nil or spec.main_skill:isInstanceOf(UsableSkill))
|
||||||
|
if type(spec.derived_piles) == "string" then
|
||||||
|
skill.derived_piles = {spec.derived_piles}
|
||||||
|
else
|
||||||
|
skill.derived_piles = spec.derived_piles or {}
|
||||||
|
end
|
||||||
skill.main_skill = spec.main_skill
|
skill.main_skill = spec.main_skill
|
||||||
skill.target_num = spec.target_num or skill.target_num
|
skill.target_num = spec.target_num or skill.target_num
|
||||||
skill.min_target_num = spec.min_target_num or skill.min_target_num
|
skill.min_target_num = spec.min_target_num or skill.min_target_num
|
||||||
|
@ -191,8 +196,8 @@ function fk.CreateActiveSkill(spec)
|
||||||
readUsableSpecToSkill(skill, spec)
|
readUsableSpecToSkill(skill, spec)
|
||||||
|
|
||||||
if spec.can_use then
|
if spec.can_use then
|
||||||
skill.canUse = function(curSkill, player, card)
|
skill.canUse = function(curSkill, player, card, extra_data)
|
||||||
return spec.can_use(curSkill, player, card) and curSkill:isEffectable(player)
|
return spec.can_use(curSkill, player, card, extra_data) and curSkill:isEffectable(player)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if spec.card_filter then skill.cardFilter = spec.card_filter end
|
if spec.card_filter then skill.cardFilter = spec.card_filter end
|
||||||
|
@ -211,9 +216,9 @@ function fk.CreateActiveSkill(spec)
|
||||||
|
|
||||||
if spec.interaction then
|
if spec.interaction then
|
||||||
skill.interaction = setmetatable({}, {
|
skill.interaction = setmetatable({}, {
|
||||||
__call = function(self)
|
__call = function()
|
||||||
if type(spec.interaction) == "function" then
|
if type(spec.interaction) == "function" then
|
||||||
return spec.interaction(self)
|
return spec.interaction(skill)
|
||||||
else
|
else
|
||||||
return spec.interaction
|
return spec.interaction
|
||||||
end
|
end
|
||||||
|
@ -445,6 +450,7 @@ end
|
||||||
---@field public special_skills? string[]
|
---@field public special_skills? string[]
|
||||||
---@field public is_damage_card? boolean
|
---@field public is_damage_card? boolean
|
||||||
---@field public multiple_targets? boolean
|
---@field public multiple_targets? boolean
|
||||||
|
---@field public is_passive? boolean
|
||||||
|
|
||||||
local defaultCardSkill = fk.CreateActiveSkill{
|
local defaultCardSkill = fk.CreateActiveSkill{
|
||||||
name = "default_card_skill",
|
name = "default_card_skill",
|
||||||
|
@ -487,6 +493,7 @@ local function readCardSpecToCard(card, spec)
|
||||||
card.special_skills = spec.special_skills
|
card.special_skills = spec.special_skills
|
||||||
card.is_damage_card = spec.is_damage_card
|
card.is_damage_card = spec.is_damage_card
|
||||||
card.multiple_targets = spec.multiple_targets
|
card.multiple_targets = spec.multiple_targets
|
||||||
|
card.is_passive = spec.is_passive
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param spec CardSpec
|
---@param spec CardSpec
|
||||||
|
|
|
@ -268,7 +268,7 @@ GameEvent.functions[GameEvent.Phase] = function(self)
|
||||||
local room = self.room
|
local room = self.room
|
||||||
local logic = room.logic
|
local logic = room.logic
|
||||||
|
|
||||||
local player = self.data[1]
|
local player = self.data[1] ---@type Player
|
||||||
if not logic:trigger(fk.EventPhaseStart, player) then
|
if not logic:trigger(fk.EventPhaseStart, player) then
|
||||||
if player.phase ~= Player.NotActive then
|
if player.phase ~= Player.NotActive then
|
||||||
logic:trigger(fk.EventPhaseProceeding, player)
|
logic:trigger(fk.EventPhaseProceeding, player)
|
||||||
|
@ -285,12 +285,14 @@ GameEvent.functions[GameEvent.Phase] = function(self)
|
||||||
end,
|
end,
|
||||||
[Player.Judge] = function()
|
[Player.Judge] = function()
|
||||||
local cards = player:getCardIds(Player.Judge)
|
local cards = player:getCardIds(Player.Judge)
|
||||||
for i = #cards, 1, -1 do
|
while #cards > 0 do
|
||||||
local card
|
local cid = table.remove(cards)
|
||||||
card = player:removeVirtualEquip(cards[i])
|
if not cid then return end
|
||||||
|
local card = player:removeVirtualEquip(cid)
|
||||||
if not card then
|
if not card then
|
||||||
card = Fk:getCardById(cards[i])
|
card = Fk:getCardById(cid)
|
||||||
end
|
end
|
||||||
|
if table.contains(player:getCardIds(Player.Judge), cid) then
|
||||||
room:moveCardTo(card, Card.Processing, nil, fk.ReasonPut, self.name)
|
room:moveCardTo(card, Card.Processing, nil, fk.ReasonPut, self.name)
|
||||||
|
|
||||||
---@type CardEffectEvent
|
---@type CardEffectEvent
|
||||||
|
@ -304,6 +306,7 @@ GameEvent.functions[GameEvent.Phase] = function(self)
|
||||||
card.skill:onNullified(room, effect_data)
|
card.skill:onNullified(room, effect_data)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
[Player.Draw] = function()
|
[Player.Draw] = function()
|
||||||
local data = {
|
local data = {
|
||||||
|
|
|
@ -599,6 +599,151 @@ function GameLogic:getEventsOfScope(eventType, n, func, scope)
|
||||||
return start_event:searchEvents(eventType, n, func)
|
return start_event:searchEvents(eventType, n, func)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- 在指定历史范围中找符合条件的事件(逆序)
|
||||||
|
---@param eventType integer @ 要查找的事件类型
|
||||||
|
---@param func fun(e: GameEvent): boolean @ 过滤用的函数
|
||||||
|
---@param n integer @ 最多找多少个
|
||||||
|
---@param end_id integer @ 查询历史范围:从最后的事件开始逆序查找直到id为end_id的事件(不含)
|
||||||
|
---@return GameEvent[] @ 找到的符合条件的所有事件,最多n个但不保证有n个
|
||||||
|
function GameLogic:getEventsByRule(eventType, n, func, end_id)
|
||||||
|
local ret = {}
|
||||||
|
local events = self.event_recorder[eventType] or Util.DummyTable
|
||||||
|
for i = #events, 1, -1 do
|
||||||
|
local e = events[i]
|
||||||
|
if e.id <= end_id then break end
|
||||||
|
if func(e) then
|
||||||
|
table.insert(ret, e)
|
||||||
|
if #ret >= n then break end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- 获取实际的伤害事件
|
||||||
|
---@param n integer @ 最多找多少个
|
||||||
|
---@param func fun(e: GameEvent): boolean @ 过滤用的函数
|
||||||
|
---@param scope? integer @ 查询历史范围,只能是当前阶段/回合/轮次
|
||||||
|
---@param end_id? integer @ 查询历史范围:从最后的事件开始逆序查找直到id为end_id的事件(不含)
|
||||||
|
---@return GameEvent[] @ 找到的符合条件的所有事件,最多n个但不保证有n个
|
||||||
|
function GameLogic:getActualDamageEvents(n, func, scope, end_id)
|
||||||
|
if not end_id then
|
||||||
|
scope = scope or Player.HistoryTurn
|
||||||
|
end
|
||||||
|
|
||||||
|
n = n or 1
|
||||||
|
func = func or Util.TrueFunc
|
||||||
|
|
||||||
|
local eventType = GameEvent.Damage
|
||||||
|
local ret = {}
|
||||||
|
local endIdRecorded
|
||||||
|
local tempEvents = {}
|
||||||
|
|
||||||
|
local addTempEvents = function(reverse)
|
||||||
|
if #tempEvents > 0 and #ret < n then
|
||||||
|
table.sort(tempEvents, function(a, b)
|
||||||
|
if reverse then
|
||||||
|
return a.data[1].dealtRecorderId > b.data[1].dealtRecorderId
|
||||||
|
else
|
||||||
|
return a.data[1].dealtRecorderId < b.data[1].dealtRecorderId
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
for _, e in ipairs(tempEvents) do
|
||||||
|
table.insert(ret, e)
|
||||||
|
if #ret >= n then return true end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endIdRecorded = nil
|
||||||
|
tempEvents = {}
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if scope then
|
||||||
|
local event = self:getCurrentEvent()
|
||||||
|
local start_event ---@type GameEvent
|
||||||
|
if scope == Player.HistoryGame then
|
||||||
|
start_event = self.all_game_events[1]
|
||||||
|
elseif scope == Player.HistoryRound then
|
||||||
|
start_event = event:findParent(GameEvent.Round, true)
|
||||||
|
elseif scope == Player.HistoryTurn then
|
||||||
|
start_event = event:findParent(GameEvent.Turn, true)
|
||||||
|
elseif scope == Player.HistoryPhase then
|
||||||
|
start_event = event:findParent(GameEvent.Phase, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not start_event then return {} end
|
||||||
|
|
||||||
|
local events = self.event_recorder[eventType] or Util.DummyTable
|
||||||
|
local from = start_event.id
|
||||||
|
local to = start_event.end_id
|
||||||
|
if math.abs(to) == 1 then to = #self.all_game_events end
|
||||||
|
|
||||||
|
for _, v in ipairs(events) do
|
||||||
|
local damageStruct = v.data[1]
|
||||||
|
if damageStruct.dealtRecorderId then
|
||||||
|
if endIdRecorded and v.id > endIdRecorded then
|
||||||
|
local result = addTempEvents()
|
||||||
|
if result then
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if v.id >= from and v.id <= to then
|
||||||
|
if not endIdRecorded and v.end_id > -1 and v.end_id > v.id then
|
||||||
|
endIdRecorded = v.end_id
|
||||||
|
end
|
||||||
|
|
||||||
|
if func(v) then
|
||||||
|
if endIdRecorded then
|
||||||
|
table.insert(tempEvents, v)
|
||||||
|
else
|
||||||
|
table.insert(ret, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #ret >= n then break end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
addTempEvents()
|
||||||
|
else
|
||||||
|
local events = self.event_recorder[eventType] or Util.DummyTable
|
||||||
|
|
||||||
|
for i = #events, 1, -1 do
|
||||||
|
local e = events[i]
|
||||||
|
if e.id <= end_id then break end
|
||||||
|
|
||||||
|
local damageStruct = e.data[1]
|
||||||
|
if damageStruct.dealtRecorderId then
|
||||||
|
if e.end_id == -1 or (endIdRecorded and endIdRecorded > e.end_id) then
|
||||||
|
local result = addTempEvents(true)
|
||||||
|
if result then
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
if func(e) then
|
||||||
|
table.insert(ret, e)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
endIdRecorded = e.end_id
|
||||||
|
if func(e) then
|
||||||
|
table.insert(tempEvents, e)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #ret >= n then break end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
addTempEvents(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
function GameLogic:dumpEventStack(detailed)
|
function GameLogic:dumpEventStack(detailed)
|
||||||
local top = self:getCurrentEvent()
|
local top = self:getCurrentEvent()
|
||||||
local i = self.game_event_stack.p
|
local i = self.game_event_stack.p
|
||||||
|
|
|
@ -19,23 +19,38 @@ MarkEnum.MinusMaxCards = "MinusMaxCards"
|
||||||
---于本回合内减少标记值数量的手牌上限
|
---于本回合内减少标记值数量的手牌上限
|
||||||
MarkEnum.MinusMaxCardsInTurn = "MinusMaxCards-turn"
|
MarkEnum.MinusMaxCardsInTurn = "MinusMaxCards-turn"
|
||||||
|
|
||||||
---使用牌无次数限制,可带清除标记后缀(-tmp为请求专用)
|
---使用牌无次数限制
|
||||||
MarkEnum.BypassTimesLimit = "BypassTimesLimit"
|
MarkEnum.BypassTimesLimit = "BypassTimesLimit"
|
||||||
---使用牌无距离限制,可带清除标记后缀(-tmp为请求专用)
|
---使用牌无距离限制
|
||||||
MarkEnum.BypassDistancesLimit = "BypassDistancesLimit"
|
MarkEnum.BypassDistancesLimit = "BypassDistancesLimit"
|
||||||
---对其使用牌无次数限制,可带清除标记后缀
|
---对其使用牌无次数限制
|
||||||
MarkEnum.BypassTimesLimitTo = "BypassTimesLimitTo"
|
MarkEnum.BypassTimesLimitTo = "BypassTimesLimitTo"
|
||||||
---对其使用牌无距离限制,可带清除标记后缀
|
---对其使用牌无距离限制
|
||||||
MarkEnum.BypassDistancesLimitTo = "BypassDistancesLimitTo"
|
MarkEnum.BypassDistancesLimitTo = "BypassDistancesLimitTo"
|
||||||
---非锁定技失效,可带清除标记后缀
|
---非锁定技失效
|
||||||
MarkEnum.UncompulsoryInvalidity = "UncompulsoryInvalidity"
|
MarkEnum.UncompulsoryInvalidity = "UncompulsoryInvalidity"
|
||||||
---不可明置,可带清除标记后缀(值为表,m - 主将, d - 副将)
|
---不可明置(值为表,m - 主将, d - 副将)
|
||||||
MarkEnum.RevealProhibited = "RevealProhibited"
|
MarkEnum.RevealProhibited = "RevealProhibited"
|
||||||
---不计入距离、座次后缀,可带清除标记后缀
|
---不计入距离、座次后缀
|
||||||
MarkEnum.PlayerRemoved = "PlayerRemoved"
|
MarkEnum.PlayerRemoved = "PlayerRemoved"
|
||||||
|
|
||||||
---各种清除标记后缀
|
---各种清除标记后缀
|
||||||
|
---
|
||||||
|
---phase:阶段结束后
|
||||||
|
---
|
||||||
|
---turn:回合结束后
|
||||||
|
---
|
||||||
|
---round:轮次结束后
|
||||||
MarkEnum.TempMarkSuffix = { "-phase", "-turn", "-round" }
|
MarkEnum.TempMarkSuffix = { "-phase", "-turn", "-round" }
|
||||||
|
|
||||||
---卡牌标记版本的清除标记后缀
|
---卡牌标记版本的清除标记后缀
|
||||||
MarkEnum.CardTempMarkSuffix = { "-phase", "-turn", "-round", "-inhand" }
|
---
|
||||||
|
---phase:阶段结束后
|
||||||
|
---
|
||||||
|
---turn:回合结束后
|
||||||
|
---
|
||||||
|
---round:轮次结束后
|
||||||
|
---
|
||||||
|
---inhand:离开手牌区后
|
||||||
|
MarkEnum.CardTempMarkSuffix = { "-phase", "-turn", "-round",
|
||||||
|
"-inhand" }
|
||||||
|
|
|
@ -1726,6 +1726,26 @@ function Room:askForSkillInvoke(player, skill_name, data, prompt)
|
||||||
return invoked
|
return invoked
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- 获取使用牌的合法额外目标(【借刀杀人】等带副目标的卡牌除外)
|
||||||
|
---@param data CardUseStruct @ 使用事件的data
|
||||||
|
---@param bypass_distances boolean? @ 是否无距离关系的限制
|
||||||
|
---@param use_AimGroup boolean? @ 某些场合需要使用AimGroup,by smart Ho-spair
|
||||||
|
---@return integer[] @ 返回满足条件的player的id列表
|
||||||
|
function Room:getUseExtraTargets(data, bypass_distances, use_AimGroup)
|
||||||
|
if not (data.card.type == Card.TypeBasic or data.card:isCommonTrick()) then return {} end
|
||||||
|
if data.card.skill:getMinTargetNum() > 1 then return {} end --stupid collateral
|
||||||
|
local tos = {}
|
||||||
|
local current_targets = use_AimGroup and AimGroup:getAllTargets(data.tos) or TargetGroup:getRealTargets(data.tos)
|
||||||
|
for _, p in ipairs(self.alive_players) do
|
||||||
|
if not table.contains(current_targets, p.id) and not self:getPlayerById(data.from):isProhibited(p, data.card) then
|
||||||
|
if data.card.skill:modTargetFilter(p.id, {}, data.from, data.card, not bypass_distances) then
|
||||||
|
table.insert(tos, p.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return tos
|
||||||
|
end
|
||||||
|
|
||||||
--为使用牌增减目标
|
--为使用牌增减目标
|
||||||
---@param player ServerPlayer @ 执行的玩家
|
---@param player ServerPlayer @ 执行的玩家
|
||||||
---@param targets ServerPlayer[] @ 可选的目标范围
|
---@param targets ServerPlayer[] @ 可选的目标范围
|
||||||
|
@ -2913,7 +2933,7 @@ end
|
||||||
|
|
||||||
--- 让一名玩家获得一张牌
|
--- 让一名玩家获得一张牌
|
||||||
---@param player integer|ServerPlayer @ 要拿牌的玩家
|
---@param player integer|ServerPlayer @ 要拿牌的玩家
|
||||||
---@param cid integer|Card @ 要拿到的卡牌
|
---@param cid integer|Card|integer[] @ 要拿到的卡牌
|
||||||
---@param unhide? boolean @ 是否明着拿
|
---@param unhide? boolean @ 是否明着拿
|
||||||
---@param reason? CardMoveReason @ 卡牌移动的原因
|
---@param reason? CardMoveReason @ 卡牌移动的原因
|
||||||
---@param proposer? integer @ 移动操作者的id
|
---@param proposer? integer @ 移动操作者的id
|
||||||
|
@ -3114,6 +3134,7 @@ function Room:handleAddLoseSkills(player, skill_names, source_skill, sendlog, no
|
||||||
if #skill_names == 0 then return end
|
if #skill_names == 0 then return end
|
||||||
local losts = {} ---@type boolean[]
|
local losts = {} ---@type boolean[]
|
||||||
local triggers = {} ---@type Skill[]
|
local triggers = {} ---@type Skill[]
|
||||||
|
local lost_piles = {} ---@type integer[]
|
||||||
for _, skill in ipairs(skill_names) do
|
for _, skill in ipairs(skill_names) do
|
||||||
if string.sub(skill, 1, 1) == "-" then
|
if string.sub(skill, 1, 1) == "-" then
|
||||||
local actual_skill = string.sub(skill, 2, #skill)
|
local actual_skill = string.sub(skill, 2, #skill)
|
||||||
|
@ -3135,12 +3156,17 @@ function Room:handleAddLoseSkills(player, skill_names, source_skill, sendlog, no
|
||||||
|
|
||||||
table.insert(losts, true)
|
table.insert(losts, true)
|
||||||
table.insert(triggers, s)
|
table.insert(triggers, s)
|
||||||
|
if s.derived_piles then
|
||||||
|
for _, pile_name in ipairs(s.derived_piles) do
|
||||||
|
table.insertTableIfNeed(lost_piles, player:getPile(pile_name))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local sk = Fk.skills[skill]
|
local sk = Fk.skills[skill]
|
||||||
if sk and not player:hasSkill(sk, true, true) then
|
if sk and not player:hasSkill(sk, true, true) then
|
||||||
local got_skills = player:addSkill(sk)
|
local got_skills = player:addSkill(sk, source_skill)
|
||||||
|
|
||||||
for _, s in ipairs(got_skills) do
|
for _, s in ipairs(got_skills) do
|
||||||
-- TODO: limit skill mark
|
-- TODO: limit skill mark
|
||||||
|
@ -3171,6 +3197,15 @@ function Room:handleAddLoseSkills(player, skill_names, source_skill, sendlog, no
|
||||||
self.logic:trigger(event, player, triggers[i])
|
self.logic:trigger(event, player, triggers[i])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if #lost_piles > 0 then
|
||||||
|
self:moveCards({
|
||||||
|
ids = lost_piles,
|
||||||
|
from = player.id,
|
||||||
|
toArea = Card.DiscardPile,
|
||||||
|
moveReason = fk.ReasonPutIntoDiscardPile,
|
||||||
|
})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- 判定
|
-- 判定
|
||||||
|
@ -3236,7 +3271,7 @@ function Room:retrial(card, player, judge, skillName, exchange)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- 弃置一名角色的牌。
|
--- 弃置一名角色的牌。
|
||||||
---@param card_ids integer[] @ 被弃掉的牌
|
---@param card_ids integer[]|integer @ 被弃掉的牌
|
||||||
---@param skillName? string @ 技能名
|
---@param skillName? string @ 技能名
|
||||||
---@param who ServerPlayer @ 被弃牌的人
|
---@param who ServerPlayer @ 被弃牌的人
|
||||||
---@param thrower? ServerPlayer @ 弃别人牌的人
|
---@param thrower? ServerPlayer @ 弃别人牌的人
|
||||||
|
|
|
@ -134,7 +134,7 @@ fk.IceDamage = 4
|
||||||
---@field public additionalEffect? integer
|
---@field public additionalEffect? integer
|
||||||
|
|
||||||
---@class CardEffectEvent
|
---@class CardEffectEvent
|
||||||
---@field public from integer
|
---@field public from? integer
|
||||||
---@field public to integer
|
---@field public to integer
|
||||||
---@field public subTargets? integer[]
|
---@field public subTargets? integer[]
|
||||||
---@field public tos TargetGroup
|
---@field public tos TargetGroup
|
||||||
|
|
|
@ -112,6 +112,7 @@ local jink = fk.CreateBasicCard{
|
||||||
suit = Card.Heart,
|
suit = Card.Heart,
|
||||||
number = 2,
|
number = 2,
|
||||||
skill = jinkSkill,
|
skill = jinkSkill,
|
||||||
|
is_passive = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
extension:addCards({
|
extension:addCards({
|
||||||
|
@ -468,6 +469,7 @@ local nullification = fk.CreateTrickCard{
|
||||||
suit = Card.Spade,
|
suit = Card.Spade,
|
||||||
number = 11,
|
number = 11,
|
||||||
skill = nullificationSkill,
|
skill = nullificationSkill,
|
||||||
|
is_passive = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
extension:addCards({
|
extension:addCards({
|
||||||
|
|
Loading…
Reference in New Issue
Block a user