From e448cb18de7439aebac017baf734e0108c7a0113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E5=A6=96=E6=A2=A6=E5=8E=A8?= <12796194+youmuKon-supreme@user.noreply.gitee.com> Date: Sun, 24 Aug 2025 04:01:05 +0800 Subject: [PATCH 01/13] =?UTF-8?q?derived=5Fpiles=E5=92=8C=E6=AC=A1?= =?UTF-8?q?=E6=95=B0=E5=AE=A1=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lua/core/skill_skeleton.lua | 68 ++++++++++++++++++++++++++-- lua/core/skill_type/usable_skill.lua | 11 +++-- 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/lua/core/skill_skeleton.lua b/lua/core/skill_skeleton.lua index e6b746d..4af3526 100644 --- a/lua/core/skill_skeleton.lua +++ b/lua/core/skill_skeleton.lua @@ -7,7 +7,11 @@ ---@field public anim_type? string|AnimationType @ 技能类型定义 ---@field public global? boolean @ 决定是否是全局技能 ---@field public dynamic_desc? fun(self: Skill, player: Player, lang: string): string? @ 动态描述函数 ----@field public derived_piles? string|string[] @ 与某效果联系起来的私人牌堆名,失去该效果时将之置入弃牌堆(@deprecated) +---@field public derived_piles? string|string[] @deprecated @ 与某效果联系起来的私人牌堆名,失去该效果时将之置入弃牌堆 +---@field public max_phase_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能效果的最大使用次数——阶段 +---@field public max_turn_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能效果的最大使用次数——回合 +---@field public max_round_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能效果的最大使用次数——轮次 +---@field public max_game_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能效果的最大使用次数——本局游戏 ---@field public audio_index? table|integer @ 此技能效果播放的语音序号,可为int或int表 ---@field public extra? table @ 塞进技能里的各种数据 @@ -19,7 +23,11 @@ ---@field public attached_skill_name? string @ 向其他角色分发的技能名(如黄天) ---@field public dynamic_name? fun(self: SkillSkeleton, player: Player, lang?: string): string @ 动态名称函数 ---@field public dynamic_desc? fun(self: SkillSkeleton, player: Player, lang?: string): string? @ 动态描述函数 ----@field public derived_piles? string | string[] @ 与该技能联系起来的私人牌堆名,失去该技能时将之置入弃牌堆 +---@field public derived_piles? string|string[] @ 与该技能联系起来的私人牌堆名,失去该技能时将之置入弃牌堆 +---@field public max_phase_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能的最大使用次数——阶段 +---@field public max_turn_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能的最大使用次数——回合 +---@field public max_round_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能的最大使用次数——轮次 +---@field public max_game_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能的最大使用次数——本局游戏 ---@field public mode_skill? boolean @ 是否为模式技能(诸如斗地主的“飞扬”和“跋扈”) ---@field public extra? table @ 塞进技能里的各种数据 @@ -32,9 +40,10 @@ ---@field public dynamicName fun(self: SkillSkeleton, player: Player, lang?: string): string @ 动态名称函数 ---@field public dynamicDesc fun(self: SkillSkeleton, player: Player, lang?: string): string @ 动态描述函数 ---@field public derived_piles? string[] @ 与一个技能同在的私有牌堆名,失去时弃置其中的所有牌 +---@field public max_use_time table @ 一个技能在各时机内最大的使用次数 ---@field public addTest fun(self: SkillSkeleton, fn: fun(room: Room, me: ServerPlayer)) @ 测试函数 ----@field public onAcquire fun(self: SkillSkeleton, player: ServerPlayer, is_start: boolean) ----@field public onLose fun(self: SkillSkeleton, player: ServerPlayer, is_death: boolean) +---@field public onAcquire fun(self: SkillSkeleton, player: ServerPlayer, is_start: boolean) @ 获得技能时执行的函数 +---@field public onLose fun(self: SkillSkeleton, player: ServerPlayer, is_death: boolean) @ 失去技能时执行的函数 ---@field public addEffect fun(self: SkillSkeleton, key: "distance", data: DistanceSpec, attribute: nil): SkillSkeleton ---@field public addEffect fun(self: SkillSkeleton, key: "prohibit", data: ProhibitSpec, attribute: nil): SkillSkeleton ---@field public addEffect fun(self: SkillSkeleton, key: "atkrange", data: AttackRangeSpec, attribute: nil): SkillSkeleton @@ -87,6 +96,13 @@ function SkillSkeleton:initialize(spec) self.extra = spec.extra or {} + self.max_use_time = { + spec.max_phase_use_time, + spec.max_turn_use_time, + spec.max_round_use_time, + spec.max_game_use_time, + } + --Notify智慧,当不存在main_skill时,用于创建main_skill。看上去毫无用处 fk.readCommonSpecToSkill(self, spec) end @@ -672,6 +688,50 @@ function SkillSkeleton:getDynamicDescription(player, lang) return self.dynamicDesc and self:dynamicDesc(player, lang) end +-- 获得技能的最大使用次数 +---@param player Player @ 使用者 +---@param scope integer @ 查询历史范围(默认为回合) +---@param to? Player @ 目标 +---@return number? @ 最大使用次数,nil就是无限 +function SkillSkeleton:getMaxUseTime(player, scope, to) + scope = scope or Player.HistoryTurn + local time = self.max_use_time[scope] + local ret = time + if type(time) == "function" then + ret = time(self, player, to) + end + if ret == nil then return nil end + return ret +end + +-- 获得技能的剩余使用次数 +---@param player Player @ 使用者 +---@param scope integer @ 查询历史范围(默认为回合) +---@param to? Player @ 目标 +---@return number? @ 剩余使用次数,nil就是无限 +function SkillSkeleton:getRemainUseTime(player, scope, to) + scope = scope or Player.HistoryTurn + + local limit = self:getMaxUseTime(player, scope, to) + if limit == nil then return nil end + + return math.max(0, limit - player:usedSkillTimes(self.name, scope)) +end + +-- 判断一个角色是否在技能的次数限制内 +---@param player Player @ 使用者 +---@param scope integer @ 查询历史范围(默认为回合) +---@param to? Player @ 目标 +---@return boolean? +function SkillSkeleton:withinTimesLimit(player, scope, to) + scope = scope or Player.HistoryTurn + + local limit = self:getMaxUseTime(player, scope, to) + if limit == nil then return true end + + return self:getRemainUseTime(player, scope, to) > 0 +end + ---@param spec SkillSkeletonSpec ---@return SkillSkeleton function fk.CreateSkill(spec) diff --git a/lua/core/skill_type/usable_skill.lua b/lua/core/skill_type/usable_skill.lua index 924ce1a..8c5839f 100644 --- a/lua/core/skill_type/usable_skill.lua +++ b/lua/core/skill_type/usable_skill.lua @@ -7,9 +7,9 @@ --]] ---@class UsableSkill : Skill ----@field public max_use_time integer[] +---@field public max_use_time (integer?)[] @ 一个效果的最大可用次数 ---@field public expand_pile? string | integer[] | fun(self: UsableSkill, player: Player): integer[]|string? @ 额外牌堆,牌堆名称或卡牌id表 ----@field public derived_piles? string | string[] @ 与某效果联系起来的私人牌堆名,失去该效果时将之置入弃牌堆(@deprecated) +---@field public derived_piles? string | string[] @deprecated @ 与某效果联系起来的私人牌堆名,失去该效果时将之置入弃牌堆 ---@field public times? fun(self: UsableSkill, player: Player): integer local UsableSkill = Skill:subclass("UsableSkill") @@ -67,9 +67,6 @@ function UsableSkill:withinTimesLimit(player, scope, card, card_name, to) local limit = self:getMaxUseTime(player, scope, card, to) if not limit then return true end - for _, skill in ipairs(status_skills) do - if skill:bypassTimesCheck(player, self, scope, card, to) then return true end - end if not card_name then if card then @@ -79,6 +76,10 @@ function UsableSkill:withinTimesLimit(player, scope, card, card_name, to) end end + for _, skill in ipairs(status_skills) do + if skill:bypassTimesCheck(player, self, scope, card, to) then return true end + end + return player:usedCardTimes(card_name, scope) < limit or (card and not not card:hasMark(MarkEnum.BypassTimesLimit)) or not not player:hasMark(MarkEnum.BypassTimesLimit) or -- Gitee From a796e88b3cee64b35cad6548fa0b00ffe39b46a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E5=A6=96=E6=A2=A6=E5=8E=A8?= <12796194+youmuKon-supreme@user.noreply.gitee.com> Date: Sun, 24 Aug 2025 04:01:05 +0800 Subject: [PATCH 02/13] =?UTF-8?q?skel=E5=88=A4=E5=AE=9A=E6=89=A9=E5=B1=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lua/core/skill_type/usable_skill.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lua/core/skill_type/usable_skill.lua b/lua/core/skill_type/usable_skill.lua index 8c5839f..4a17d67 100644 --- a/lua/core/skill_type/usable_skill.lua +++ b/lua/core/skill_type/usable_skill.lua @@ -72,7 +72,14 @@ function UsableSkill:withinTimesLimit(player, scope, card, card_name, to) if card then card_name = card.trueName else ---坏了,不是卡的技能 - return player:usedEffectTimes(self.name, scope) < limit + if player:usedEffectTimes(self.name, scope) < limit then + if self:getSkeleton() then + return self:getSkeleton():withinTimesLimit(player, scope, to) + else + return true + end + end + return false end end -- Gitee From e5988a90286f66e4f24619fe564e0c4c8590fbbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E5=A6=96=E6=A2=A6=E5=8E=A8?= <12796194+youmuKon-supreme@user.noreply.gitee.com> Date: Sun, 24 Aug 2025 04:01:05 +0800 Subject: [PATCH 03/13] SkillAttribute --- lua/core/skill_skeleton.lua | 102 +++++++++++++++++++++++---- lua/core/skill_type/usable_skill.lua | 2 +- 2 files changed, 88 insertions(+), 16 deletions(-) diff --git a/lua/core/skill_skeleton.lua b/lua/core/skill_skeleton.lua index 4af3526..ea890b2 100644 --- a/lua/core/skill_skeleton.lua +++ b/lua/core/skill_skeleton.lua @@ -52,9 +52,9 @@ ---@field public addEffect fun(self: SkillSkeleton, key: "filter", data: FilterSpec, attribute: nil): SkillSkeleton ---@field public addEffect fun(self: SkillSkeleton, key: "invalidity", data: InvaliditySpec, attribute: nil): SkillSkeleton ---@field public addEffect fun(self: SkillSkeleton, key: "visibility", data: VisibilitySpec, attribute: nil): SkillSkeleton ----@field public addEffect fun(self: SkillSkeleton, key: "active", data: ActiveSkillSpec, attribute: nil): SkillSkeleton +---@field public addEffect fun(self: SkillSkeleton, key: "active", data: ActiveSkillSpec, attribute: SkillAttribute?): SkillSkeleton ---@field public addEffect fun(self: SkillSkeleton, key: "cardskill", data: CardSkillSpec, attribute: nil): SkillSkeleton ----@field public addEffect fun(self: SkillSkeleton, key: "viewas", data: ViewAsSkillSpec, attribute: nil): SkillSkeleton +---@field public addEffect fun(self: SkillSkeleton, key: "viewas", data: ViewAsSkillSpec, attribute: SkillAttribute?): SkillSkeleton local SkillSkeleton = class("SkillSkeleton") @@ -205,9 +205,12 @@ function SkillSkeleton:createSkill() return main_skill end ----@class TrigSkelAttribute ----@field public is_delay_effect? boolean ---- 若为true,则不贴main_skill +---@class SkillAttribute +---@field public check_effect_limit? boolean @ 若为true,则自带判断效果次数(若不填can_use,则默认带限定“本阶段”的次数判定) +---@field public check_skill_limit? boolean @ 若为true,则自带判断技能次数 + +---@class TrigSkelAttribute: SkillAttribute +---@field public is_delay_effect? boolean @ 若为true,则不贴main_skill ---@alias TrigFunc fun(self: TriggerSkill, event: TriggerEvent, target: ServerPlayer?, player: ServerPlayer, data: any): any ---@class TrigSkelSpec: { @@ -245,16 +248,34 @@ function SkillSkeleton:createTriggerSkill(_skill, idx, key, attr, spec) sk.global = spec.global end if spec.can_trigger then + local tmp_func if table.contains(_skill.tags, Skill.Wake) then - sk.triggerable = function(_self, event, target, player, data) + if spec.can_wake then + sk.canWake = spec.can_wake + end + tmp_func = function(_self, event, target, player, data) return spec.can_trigger(_self, event, target, player, data) and sk:enableToWake(event, target, player, data) end else - sk.triggerable = spec.can_trigger + tmp_func = spec.can_trigger end - if table.contains(_skill.tags, Skill.Wake) and spec.can_wake then - sk.canWake = spec.can_wake + sk.triggerable = function(_self, event, target, player, data) + if attr.check_effect_limit then + for scope, _ in pairs(_self.max_use_time) do + if not _self:withinTimesLimit(player, scope) then + return false + end + end + end + if attr.check_skill_limit then + for scope, _ in pairs(_skill.max_use_time) do + if not _skill:withinTimesLimit(player, scope) then + return false + end + end + end + return tmp_func(_self, event, target, player, data) end end if spec.on_trigger then sk.trigger = spec.on_trigger end @@ -472,10 +493,28 @@ function SkillSkeleton:createActiveSkill(_skill, idx, key, attr, spec) local skill = ActiveSkill:new(new_name, #_skill.tags > 0 and _skill.tags[1] or Skill.NotFrequent) fk.readUsableSpecToSkill(skill, spec) - if spec.can_use then - skill.canUse = function(curSkill, player) - return spec.can_use(curSkill, player) and curSkill:isEffectable(player) + local spec_can_use = spec.can_use + if not spec_can_use then + spec_can_use = ActiveSkill.canUse + end + + skill.canUse = function(curSkill, player, _, extra_data) + if not curSkill:isEffectable(player) then return end + if attr.check_effect_limit then + for scope, _ in pairs(curSkill.max_use_time) do + if not curSkill:withinTimesLimit(player, scope) then + return false + end + end + end + if attr.check_skill_limit then + for scope, _ in pairs(_skill.max_use_time) do + if not _skill:withinTimesLimit(player, scope) then + return false + end + end end + return spec_can_use(curSkill, player, _, extra_data) end if spec.card_filter then skill.cardFilter = spec.card_filter end if spec.target_filter then skill.targetFilter = spec.target_filter end @@ -546,14 +585,41 @@ function SkillSkeleton:createViewAsSkill(_skill, idx, key, attr, spec) if type(spec.pattern) == "string" then skill.pattern = spec.pattern end + + local timeCheck = function(curSkill, player) + if attr.check_effect_limit then + for scope, _ in pairs(curSkill.max_use_time) do + if not curSkill:withinTimesLimit(player, scope) then + return false + end + end + end + if attr.check_skill_limit then + for scope, _ in pairs(_skill.max_use_time) do + if not _skill:withinTimesLimit(player, scope) then + return false + end + end + end + return true + end + if type(spec.enabled_at_play) == "function" then skill.enabledAtPlay = function(curSkill, player) - return spec.enabled_at_play(curSkill, player) and curSkill:isEffectable(player) + return timeCheck(curSkill, player) and spec.enabled_at_play(curSkill, player) and curSkill:isEffectable(player) + end + else + skill.enabledAtPlay = function(curSkill, player) + return timeCheck(curSkill, player) and ViewAsSkill.enabledAtPlay(curSkill, player) end end if type(spec.enabled_at_response) == "function" then skill.enabledAtResponse = function(curSkill, player, cardResponsing) - return spec.enabled_at_response(curSkill, player, cardResponsing) and curSkill:isEffectable(player) + return timeCheck(curSkill, player) and spec.enabled_at_response(curSkill, player, cardResponsing) and curSkill:isEffectable(player) + end + else + skill.enabledAtResponse = function(curSkill, player, cardResponsing) + return timeCheck(curSkill, player) and ViewAsSkill.enabledAtResponse(curSkill, player, cardResponsing) end end if spec.prompt then skill.prompt = spec.prompt end @@ -572,7 +638,13 @@ function SkillSkeleton:createViewAsSkill(_skill, idx, key, attr, spec) if spec.click_count then skill.click_count = spec.click_count end if type(spec.enabled_at_nullification) == "function" then - skill.enabledAtNullification = spec.enabled_at_nullification + skill.enabledAtNullification = function(curSkill, player, cardData) + return timeCheck(curSkill, player) and spec.enabled_at_nullification(curSkill, player, cardData) and curSkill:isEffectable(player) + end + else + skill.enabledAtNullification = function(curSkill, player, cardData) + return timeCheck(curSkill, player) and ViewAsSkill.enabledAtNullification(curSkill, player, cardData) + end end skill.handly_pile = spec.handly_pile diff --git a/lua/core/skill_type/usable_skill.lua b/lua/core/skill_type/usable_skill.lua index 4a17d67..c9cb499 100644 --- a/lua/core/skill_type/usable_skill.lua +++ b/lua/core/skill_type/usable_skill.lua @@ -7,7 +7,7 @@ --]] ---@class UsableSkill : Skill ----@field public max_use_time (integer?)[] @ 一个效果的最大可用次数 +---@field public max_use_time table @ 一个效果的最大可用次数 ---@field public expand_pile? string | integer[] | fun(self: UsableSkill, player: Player): integer[]|string? @ 额外牌堆,牌堆名称或卡牌id表 ---@field public derived_piles? string | string[] @deprecated @ 与某效果联系起来的私人牌堆名,失去该效果时将之置入弃牌堆 ---@field public times? fun(self: UsableSkill, player: Player): integer -- Gitee From cff3855df89cfa4b38c2d825774f1cec99098101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E5=A6=96=E6=A2=A6=E5=8E=A8?= <12796194+youmuKon-supreme@user.noreply.gitee.com> Date: Sun, 24 Aug 2025 04:01:05 +0800 Subject: [PATCH 04/13] =?UTF-8?q?=E5=9B=9E=E6=BB=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lua/core/skill_type/usable_skill.lua | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lua/core/skill_type/usable_skill.lua b/lua/core/skill_type/usable_skill.lua index c9cb499..fb2d6df 100644 --- a/lua/core/skill_type/usable_skill.lua +++ b/lua/core/skill_type/usable_skill.lua @@ -72,14 +72,7 @@ function UsableSkill:withinTimesLimit(player, scope, card, card_name, to) if card then card_name = card.trueName else ---坏了,不是卡的技能 - if player:usedEffectTimes(self.name, scope) < limit then - if self:getSkeleton() then - return self:getSkeleton():withinTimesLimit(player, scope, to) - else - return true - end - end - return false + return player:usedEffectTimes(self.name, scope) < limit end end -- Gitee From 86a5a70e49668cc5a74f495bd6690291f8af34dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E5=A6=96=E6=A2=A6=E5=8E=A8?= <12796194+youmuKon-supreme@user.noreply.gitee.com> Date: Sun, 24 Aug 2025 04:24:05 +0800 Subject: [PATCH 05/13] =?UTF-8?q?=E8=A7=A6=E5=8F=91=E5=99=A8=E7=9A=84?= =?UTF-8?q?=E5=88=86=E6=94=AF=E6=AC=A1=E6=95=B0=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lua/client/client.lua | 23 ++++++ lua/core/events/skill.lua | 3 +- lua/core/player.lua | 81 ++++++++++++++++++- lua/core/skill_skeleton.lua | 115 ++++++++++++++++++++++++--- lua/core/skill_type/usable_skill.lua | 4 +- lua/fk_ex.lua | 14 ++-- lua/server/events/skill.lua | 7 ++ lua/server/room.lua | 1 + lua/server/serverplayer.lua | 12 +++ 9 files changed, 235 insertions(+), 25 deletions(-) diff --git a/lua/client/client.lua b/lua/client/client.lua index f091edb..36de236 100644 --- a/lua/client/client.lua +++ b/lua/client/client.lua @@ -1116,6 +1116,17 @@ fk.client_callback["AddSkillUseHistory"] = function(self, data) updateLimitSkill(playerid, Fk.skills[skill_name]) end +fk.client_callback["AddSkillBranchUseHistory"] = function(self, data) + local playerid, skill_name, branch, time = data[1], data[2], data[3], data[4] + local player = self:getPlayerById(playerid) + player:addSkillBranchUseHistory(skill_name, branch, time) + + -- 真的有分支会改变状态吗……? + -- local skill = Fk.skills[skill_name] + -- if not skill then return end + -- updateLimitSkill(playerid, Fk.skills[skill_name]) +end + fk.client_callback["SetSkillUseHistory"] = function(self, data) local id, skill_name, time, scope = data[1], data[2], data[3], data[4] local player = self:getPlayerById(id) @@ -1126,6 +1137,18 @@ fk.client_callback["SetSkillUseHistory"] = function(self, data) updateLimitSkill(id, Fk.skills[skill_name]) end +fk.client_callback["SetSkillBranchUseHistory"] = function(self, data) + local id, skill_name, branch, time, scope = + data[1], data[2], data[3], data[4], data[5] + local player = self:getPlayerById(id) + player:setSkillBranchUseHistory(skill_name, branch, time, scope) + + -- 真的有分支会改变状态吗……? + -- local skill = Fk.skills[skill_name] + -- if not skill then return end + -- updateLimitSkill(id, Fk.skills[skill_name]) +end + fk.client_callback["AddVirtualEquip"] = function(self, data) local cname = data.name local player = self:getPlayerById(data.player) diff --git a/lua/core/events/skill.lua b/lua/core/events/skill.lua index 9a4df10..8379346 100644 --- a/lua/core/events/skill.lua +++ b/lua/core/events/skill.lua @@ -13,6 +13,7 @@ ---@field public no_indicate? boolean @ 发动时是否不显示指示线 ---@field public audio_index? number @ 发动时是否播放特定编号台词 ---@field public anim_type? AnimationType|string @ 发动时是否播放特定动画 +---@field public history_branch? string @ 发动时是否播放特定动画 --- 技能使用的数据 ---@class SkillUseData: SkillUseDataSpec, TriggerData @@ -21,7 +22,7 @@ SkillUseData = TriggerData:subclass("SkillUseData") ---@class SkillEffectDataSpec ---@field public skill_cb fun():any @ 实际技能函数 ---@field public who ServerPlayer @ 技能发动者 ----@field public skill Skill @ 发动的技能 +---@field public skill UsableSkill @ 发动的技能 ---@field public skill_data SkillUseData @ 技能数据 ---@field public prevented? boolean @ 防止执行技能效果(仅用于触发技、主动技、转化技) ---@field public trigger_break? boolean @ 停止继续触发此时机(仅用于触发技) diff --git a/lua/core/player.lua b/lua/core/player.lua index acb7676..aa3029a 100644 --- a/lua/core/player.lua +++ b/lua/core/player.lua @@ -35,6 +35,7 @@ ---@field public special_cards table @ 类似“屯田”的“田”的私人牌堆 ---@field public cardUsedHistory table @ 用牌次数历史记录 ---@field public skillUsedHistory table @ 发动技能次数的历史记录 +---@field public skillBranchUsedHistory table> @ 发动技能某分支次数的历史记录 ---@field public buddy_list integer[] @ 队友列表,或者说自己可以观看别人手牌的那些玩家的列表 ---@field public equipSlots string[] @ 装备栏列表 ---@field public sealedSlots string[] @ 被废除的装备栏列表 @@ -123,6 +124,7 @@ function Player:initialize() self.cardUsedHistory = {} self.skillUsedHistory = {} + self.skillBranchUsedHistory = {} self.buddy_list = {} end @@ -838,22 +840,42 @@ function Player:addSkillUseHistory(skill_name, num) end end +--- 增加玩家使用特定技能分支的历史次数。 +---@param skill_name string @ 技能名 +---@param branch string @ 技能分支名,不写则默认改变某技能**所有分支**的历史次数 +---@param num? integer @ 次数 默认1 +function Player:addSkillBranchUseHistory(skill_name, branch, num) + num = num or 1 + assert(type(num) == "number" and num ~= 0) + + self.skillBranchUsedHistory[skill_name] = self.skillBranchUsedHistory[skill_name] or {} + self.skillBranchUsedHistory[skill_name][branch] = self.skillBranchUsedHistory[skill_name][branch] or {0, 0, 0, 0} + local t = self.skillBranchUsedHistory[skill_name][branch] + for i, _ in ipairs(t) do + t[i] = t[i] + num + end +end + --- 设定玩家使用特定技能的历史次数。 +--- `num`和`scope`均不写则为清空特定区域的历史次数 ---@param skill_name? string @ 技能名,不写则默认改变所有技能的历史次数 ---@param num? integer @ 次数 默认0 ----@param scope? integer @ 查询历史范围 +---@param scope? integer @ 查询历史范围,若你填了num则必须填具体时机 function Player:setSkillUseHistory(skill_name, num, scope) skill_name = skill_name or "" if num == nil and scope == nil then if skill_name ~= "" then self.skillUsedHistory[skill_name] = {0, 0, 0, 0} + self:setSkillBranchUseHistory(skill_name) else self.skillUsedHistory = {} + self:setSkillBranchUseHistory() end return end num = num or 0 + assert(scope) if skill_name == "" then for _, v in pairs(self.skillUsedHistory) do v[scope] = num @@ -865,6 +887,52 @@ function Player:setSkillUseHistory(skill_name, num, scope) self.skillUsedHistory[skill_name][scope] = num end +--- 设定玩家使用特定技能分支的历史次数。 +--- `num`和`scope`均不写则为清空特定区域的历史次数 +---@param skill_name? string @ 技能名,不写则默认改变**所有技能**之所有分支的历史次数 +---@param branch? string @ 技能分支名,不写则默认改变某技能**所有分支**的历史次数 +---@param num? integer @ 次数 默认0 +---@param scope? integer @ 查询历史范围 +function Player:setSkillBranchUseHistory(skill_name, branch, num, scope) + skill_name = skill_name or "" + if num == nil and scope == nil then + if skill_name ~= "" then + if branch then + self.skillBranchUsedHistory[skill_name][branch] = {0, 0, 0, 0} + else + self.skillBranchUsedHistory[skill_name] = {} + end + else + self.skillBranchUsedHistory = {} + end + return + end + + num = num or 0 + assert(scope) + if skill_name == "" then + for _, v in pairs(self.skillBranchUsedHistory) do + if branch then + v[branch][scope] = num + else + for _, history in pairs(v) do + history[scope] = num + end + end + end + else + self.skillBranchUsedHistory[skill_name] = self.skillBranchUsedHistory[skill_name] or {} + if branch then + self.skillBranchUsedHistory[skill_name][branch] = self.skillBranchUsedHistory[skill_name][branch] or {0, 0, 0, 0} + self.skillBranchUsedHistory[skill_name][branch][scope] = num + else + for _, history in pairs(self.skillBranchUsedHistory[skill_name]) do + history[scope] = num + end + end + end +end + --- 获取玩家使用特定牌的历史次数(只算计入次数的部分)。 ---@param cardName string @ 牌名 ---@param scope? integer @ 查询历史范围,默认Turn @@ -879,11 +947,20 @@ end --- 获取玩家使用特定技能的历史次数。 ---@param skill_name string @ 技能(skill skeleton)名 ---@param scope? integer @ 查询历史范围,默认Turn -function Player:usedSkillTimes(skill_name, scope) +---@param branch? string @ 不查询主技能使用次数,改为查询分支所属的次数限制 +function Player:usedSkillTimes(skill_name, scope, branch) if not self.skillUsedHistory[skill_name] then return 0 end scope = scope or Player.HistoryTurn + + if branch then + if not self.skillBranchUsedHistory[skill_name] or not self.skillBranchUsedHistory[skill_name][branch] then + return 0 + end + + return self.skillBranchUsedHistory[skill_name][branch][scope] + end return self.skillUsedHistory[skill_name][scope] end diff --git a/lua/core/skill_skeleton.lua b/lua/core/skill_skeleton.lua index ea890b2..a45ccc8 100644 --- a/lua/core/skill_skeleton.lua +++ b/lua/core/skill_skeleton.lua @@ -2,16 +2,12 @@ ---@class SkillSpec ---@field public name? string @ 技能名 ----@field public mute? boolean @ 决定是否关闭技能配音 +---@field public mute? boolean @ 决定是否关闭技能配音,若为true,同时也不添加技能发动历史 ---@field public no_indicate? boolean @ 决定是否关闭技能指示线 ---@field public anim_type? string|AnimationType @ 技能类型定义 ---@field public global? boolean @ 决定是否是全局技能 ---@field public dynamic_desc? fun(self: Skill, player: Player, lang: string): string? @ 动态描述函数 ---@field public derived_piles? string|string[] @deprecated @ 与某效果联系起来的私人牌堆名,失去该效果时将之置入弃牌堆 ----@field public max_phase_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能效果的最大使用次数——阶段 ----@field public max_turn_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能效果的最大使用次数——回合 ----@field public max_round_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能效果的最大使用次数——轮次 ----@field public max_game_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能效果的最大使用次数——本局游戏 ---@field public audio_index? table|integer @ 此技能效果播放的语音序号,可为int或int表 ---@field public extra? table @ 塞进技能里的各种数据 @@ -28,19 +24,21 @@ ---@field public max_turn_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能的最大使用次数——回合 ---@field public max_round_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能的最大使用次数——轮次 ---@field public max_game_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能的最大使用次数——本局游戏 +---@field public max_branches_use_time? table?>|fun(self: SkillSkeleton, player: Player): table?>? @ 该技能的最大使用次数——任意标签(内部有独立的时段细分) ---@field public mode_skill? boolean @ 是否为模式技能(诸如斗地主的“飞扬”和“跋扈”) ---@field public extra? table @ 塞进技能里的各种数据 ---@class SkillSkeleton : Object, SkillSkeletonSpec ----@field public effects Skill[] 技能对应的所有效果 ----@field public effect_names string[] 技能对应的效果名 ----@field public effect_spec_list ([any, any, any])[] 技能对应的效果信息 +---@field public effects Skill[] @ 该技能对应的所有效果 +---@field public effect_names string[] @ 该技能对应的效果名 +---@field public effect_spec_list ([any, any, any])[] @ 该技能对应的效果信息 ---@field public ai_list ([string, any, string, boolean?])[] ---@field public tests fun(room: Room, me: ServerPlayer)[] ---@field public dynamicName fun(self: SkillSkeleton, player: Player, lang?: string): string @ 动态名称函数 ---@field public dynamicDesc fun(self: SkillSkeleton, player: Player, lang?: string): string @ 动态描述函数 ----@field public derived_piles? string[] @ 与一个技能同在的私有牌堆名,失去时弃置其中的所有牌 ----@field public max_use_time table @ 一个技能在各时机内最大的使用次数 +---@field public derived_piles? string[] @ 与该技能同在的私有牌堆名,失去时弃置其中的所有牌 +---@field public max_use_time table @ 该技能在各时机内最大的使用次数 +---@field public max_branches_use_time? table?>|fun(self: SkillSkeleton, player: Player): table?>? @ 该技能的最大使用次数——任意标签(内部有独立的时段细分) ---@field public addTest fun(self: SkillSkeleton, fn: fun(room: Room, me: ServerPlayer)) @ 测试函数 ---@field public onAcquire fun(self: SkillSkeleton, player: ServerPlayer, is_start: boolean) @ 获得技能时执行的函数 ---@field public onLose fun(self: SkillSkeleton, player: ServerPlayer, is_death: boolean) @ 失去技能时执行的函数 @@ -102,6 +100,7 @@ function SkillSkeleton:initialize(spec) spec.max_round_use_time, spec.max_game_use_time, } + self.max_branches_use_time = spec.max_branches_use_time --Notify智慧,当不存在main_skill时,用于创建main_skill。看上去毫无用处 fk.readCommonSpecToSkill(self, spec) @@ -269,6 +268,14 @@ function SkillSkeleton:createTriggerSkill(_skill, idx, key, attr, spec) end end if attr.check_skill_limit then + if #_skill.max_use_time == 0 and _skill.max_branches_use_time then + -- 写死的时机table,考虑到历史记录也是写死在这的,姑且先这样吧 + for _, scope in ipairs({Player.HistoryGame, Player.HistoryRound, Player.HistoryTurn, Player.HistoryPhase}) do + if not _skill:withinBranchTimesLimit(player, nil, scope) then + return false + end + end + end for scope, _ in pairs(_skill.max_use_time) do if not _skill:withinTimesLimit(player, scope) then return false @@ -484,6 +491,9 @@ function fk.readInteractionToSkill(skill, spec) end end +---@param _skill SkillSkeleton +---@param idx integer +---@param attr SkillAttribute ---@param spec ActiveSkillSpec ---@return ActiveSkill function SkillSkeleton:createActiveSkill(_skill, idx, key, attr, spec) @@ -498,7 +508,9 @@ function SkillSkeleton:createActiveSkill(_skill, idx, key, attr, spec) spec_can_use = ActiveSkill.canUse end - skill.canUse = function(curSkill, player, _, extra_data) + ---@param curSkill ViewAsSkill + ---@param player Player + skill.canUse = function(curSkill, player, card, extra_data) if not curSkill:isEffectable(player) then return end if attr.check_effect_limit then for scope, _ in pairs(curSkill.max_use_time) do @@ -508,13 +520,21 @@ function SkillSkeleton:createActiveSkill(_skill, idx, key, attr, spec) end end if attr.check_skill_limit then + if #_skill.max_use_time == 0 and _skill.max_branches_use_time then + -- 写死的时机table,考虑到历史记录也是写死在这的,姑且先这样吧 + for _, scope in ipairs({Player.HistoryGame, Player.HistoryRound, Player.HistoryTurn, Player.HistoryPhase}) do + if not _skill:withinBranchTimesLimit(player, nil, scope) then + return false + end + end + end for scope, _ in pairs(_skill.max_use_time) do if not _skill:withinTimesLimit(player, scope) then return false end end end - return spec_can_use(curSkill, player, _, extra_data) + return spec_can_use(curSkill, player, card, extra_data) end if spec.card_filter then skill.cardFilter = spec.card_filter end if spec.target_filter then skill.targetFilter = spec.target_filter end @@ -556,6 +576,9 @@ function SkillSkeleton:createCardSkill(_skill, idx, key, attr, spec) return skill end +---@param _skill SkillSkeleton +---@param idx integer +---@param attr SkillAttribute ---@param spec ViewAsSkillSpec ---@return ViewAsSkill function SkillSkeleton:createViewAsSkill(_skill, idx, key, attr, spec) @@ -586,6 +609,8 @@ function SkillSkeleton:createViewAsSkill(_skill, idx, key, attr, spec) skill.pattern = spec.pattern end + ---@param curSkill ViewAsSkill + ---@param player Player local timeCheck = function(curSkill, player) if attr.check_effect_limit then for scope, _ in pairs(curSkill.max_use_time) do @@ -595,6 +620,14 @@ function SkillSkeleton:createViewAsSkill(_skill, idx, key, attr, spec) end end if attr.check_skill_limit then + if #_skill.max_use_time == 0 and _skill.max_branches_use_time then + -- 写死的时机table,考虑到历史记录也是写死在这的,姑且先这样吧 + for _, scope in ipairs({Player.HistoryGame, Player.HistoryRound, Player.HistoryTurn, Player.HistoryPhase}) do + if not _skill:withinBranchTimesLimit(player, nil, scope) then + return false + end + end + end for scope, _ in pairs(_skill.max_use_time) do if not _skill:withinTimesLimit(player, scope) then return false @@ -776,6 +809,27 @@ function SkillSkeleton:getMaxUseTime(player, scope, to) return ret end +-- 获得技能的最大使用次数(基于某个分支) +---@param player Player @ 使用者 +---@param branch string @ 分支名(没有后缀) +---@param scope integer @ 查询历史范围(默认为回合) +---@param to? Player @ 目标 +---@return number? @ 最大使用次数,nil就是无限 +function SkillSkeleton:getBranchMaxUseTime(player, branch, scope, to) + scope = scope or Player.HistoryTurn + local times_table + if type(self.max_branches_use_time) == "function" then + times_table = self:max_branches_use_time(player) + else + times_table = self.max_branches_use_time + end + if not times_table then return nil end + + local ret = times_table[branch][scope] + if ret == nil then return nil end + return ret +end + -- 获得技能的剩余使用次数 ---@param player Player @ 使用者 ---@param scope integer @ 查询历史范围(默认为回合) @@ -792,11 +846,12 @@ end -- 判断一个角色是否在技能的次数限制内 ---@param player Player @ 使用者 ----@param scope integer @ 查询历史范围(默认为回合) +---@param scope? integer @ 查询历史范围(默认为回合) ---@param to? Player @ 目标 ---@return boolean? function SkillSkeleton:withinTimesLimit(player, scope, to) scope = scope or Player.HistoryTurn + if not self:withinBranchTimesLimit(player, nil, scope) then return false end local limit = self:getMaxUseTime(player, scope, to) if limit == nil then return true end @@ -804,6 +859,40 @@ function SkillSkeleton:withinTimesLimit(player, scope, to) return self:getRemainUseTime(player, scope, to) > 0 end +-- 判断一个角色是否在技能的**所有分支**次数限制内 +---@param player Player @ 使用者 +---@param branch? string @ 查询分支范围(无则检查所有分支) +---@param scope? integer @ 查询历史范围(默认为回合) +---@param to? Player @ 目标 +---@return boolean? +function SkillSkeleton:withinBranchTimesLimit(player, branch, scope, to) + scope = scope or Player.HistoryTurn + local times_table + if type(self.max_branches_use_time) == "function" then + times_table = self:max_branches_use_time(player) + else + times_table = self.max_branches_use_time + end + if not times_table then return true end + + if branch then + local limit = (times_table[branch] or {})[scope] + return not (limit and player:usedSkillTimes(self.name, scope, branch) >= limit) + end + + local has_limit = false + for target_branch, limits in pairs(times_table) do + local ret = (limits or {})[scope] + if ret ~= nil then + has_limit = true + if player:usedSkillTimes(self.name, scope, target_branch) < ret then + return true + end + end + end + return not has_limit +end + ---@param spec SkillSkeletonSpec ---@return SkillSkeleton function fk.CreateSkill(spec) diff --git a/lua/core/skill_type/usable_skill.lua b/lua/core/skill_type/usable_skill.lua index fb2d6df..7e8dbb4 100644 --- a/lua/core/skill_type/usable_skill.lua +++ b/lua/core/skill_type/usable_skill.lua @@ -22,7 +22,7 @@ end -- 获得技能的最大使用次数 ---@param player Player @ 使用者 ----@param scope integer @ 查询历史范围(默认为回合) +---@param scope? integer @ 查询历史范围(默认为回合) ---@param card? Card @ 卡牌 ---@param to? Player @ 目标 ---@return number? @ 最大使用次数,nil就是无限 @@ -48,7 +48,7 @@ end -- 判断一个角色是否在技能的次数限制内 ---@param player Player @ 使用者 ----@param scope integer @ 查询历史范围(默认为回合) +---@param scope? integer @ 查询历史范围(默认为回合) ---@param card? Card @ 牌,若没有牌,则尝试制造一张虚拟牌 ---@param card_name? string @ 牌名 ---@param to? Player @ 目标 diff --git a/lua/fk_ex.lua b/lua/fk_ex.lua index b21e37d..99afb5a 100644 --- a/lua/fk_ex.lua +++ b/lua/fk_ex.lua @@ -90,15 +90,15 @@ function fk.readStatusSpecToSkill(skill, spec) end ---@class UsableSkillSpec: SkillSpec ----@field public main_skill? UsableSkill ----@field public max_use_time? integer[] +---@field public main_skill? UsableSkill @ 该技能是否为某技能的主框架 +---@field public max_phase_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能效果的最大使用次数——阶段 +---@field public max_turn_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能效果的最大使用次数——回合 +---@field public max_round_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能效果的最大使用次数——轮次 +---@field public max_game_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能效果的最大使用次数——本局游戏 +---@field public history_branch? string @ 裁定本技能发动时(on_cost->on_use)将技能历史额外添加到某处分支下(内部有独立的时段细分),这也将超前地接管自动次数判断 ---@field public expand_pile? string | integer[] | fun(self: UsableSkill, player: ServerPlayer): integer[]|string? @ 额外牌堆,牌堆名称或卡牌id表 ---@field public derived_piles? string | string[] @ 与某效果联系起来的私人牌堆名,失去该效果时将之置入弃牌堆(@deprecated) ----@field public max_phase_use_time? integer @ 每阶段使用次数上限 ----@field public max_turn_use_time? integer @ 每回合使用次数上限 ----@field public max_round_use_time? integer @ 每回合使用次数上限 ----@field public max_game_use_time? integer @ 整场游戏使用次数上限 ----@field public times? integer | fun(self: UsableSkill, player: Player): integer +---@field public times? integer | fun(self: UsableSkill, player: Player): integer @ 显示在主动技按钮上的发动次数数字 ---@field public min_target_num? integer ---@field public max_target_num? integer ---@field public target_num? integer diff --git a/lua/server/events/skill.lua b/lua/server/events/skill.lua index f7448cb..9b9c24c 100644 --- a/lua/server/events/skill.lua +++ b/lua/server/events/skill.lua @@ -98,6 +98,13 @@ function SkillEffect:main() player:addSkillUseHistory(skill.name) if skill.name ~= skill:getSkeleton().name and not skill.is_delay_effect then player:addSkillUseHistory(skill:getSkeleton().name) + if cost_data.history_branch then + player:addSkillBranchUseHistory(skill:getSkeleton().name, cost_data.history_branch) + end + else --想必没人给自己的主effect上is_delay_effect吧 + if cost_data.history_branch then + player:addSkillBranchUseHistory(skill.name, cost_data.history_branch) + end end end diff --git a/lua/server/room.lua b/lua/server/room.lua index e04184f..8ba3810 100644 --- a/lua/server/room.lua +++ b/lua/server/room.lua @@ -3983,6 +3983,7 @@ function Room:clearHistory (scope) for _, p in ipairs(self.players) do p:setCardUseHistory("", 0, scope) p:setSkillUseHistory("", 0, scope) + p:setSkillBranchUseHistory("", nil, 0, scope) for name, _ in pairs(p.mark) do if name:find(suffix, 1, true) then self:setPlayerMark(p, name, 0) diff --git a/lua/server/serverplayer.lua b/lua/server/serverplayer.lua index a4fe669..0f9cc9d 100644 --- a/lua/server/serverplayer.lua +++ b/lua/server/serverplayer.lua @@ -454,12 +454,24 @@ function ServerPlayer:addSkillUseHistory(skillName, num) self.room:doBroadcastNotify("AddSkillUseHistory", {self.id, skillName, num}) end +-- 增加技能分支发动次数 +function ServerPlayer:addSkillBranchUseHistory(skillName, branch, num) + Player.addSkillBranchUseHistory(self, skillName, branch, num) + self.room:doBroadcastNotify("AddSkillBranchUseHistory", {self.id, skillName, branch, num}) +end + -- 设置技能已发动次数 function ServerPlayer:setSkillUseHistory(skillName, num, scope) Player.setSkillUseHistory(self, skillName, num, scope) self.room:doBroadcastNotify("SetSkillUseHistory", {self.id, skillName, num, scope}) end +-- 设置技能分支已发动次数 +function ServerPlayer:setSkillBranchUseHistory(skillName, branch, num, scope) + Player.setSkillBranchUseHistory(self, skillName, branch, num, scope) + self.room:doBroadcastNotify("SetSkillBranchUseHistory", {self.id, skillName, branch, num, scope}) +end + --- 设置连环状态 ---@param chained boolean @ true为横置,false为重置 ---@param data any? @ 额外数据 -- Gitee From e3adae2a9347d39667395782a9f28bd7940b69d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E5=A6=96=E6=A2=A6=E5=8E=A8?= <12796194+youmuKon-supreme@user.noreply.gitee.com> Date: Sun, 24 Aug 2025 06:00:52 +0800 Subject: [PATCH 06/13] =?UTF-8?q?=E4=B8=BB=E5=8A=A8=E6=8A=80/=E8=A7=86?= =?UTF-8?q?=E4=B8=BA=E6=8A=80=E7=9A=84=E6=8A=80=E8=83=BD=E5=88=86=E6=94=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lua/core/events/skill.lua | 2 +- lua/core/skill_type/usable_skill.lua | 1 + lua/fk_ex.lua | 3 ++- lua/server/events/skill.lua | 19 ++++++++++++------- lua/server/room.lua | 26 ++++++++++++++------------ 5 files changed, 30 insertions(+), 21 deletions(-) diff --git a/lua/core/events/skill.lua b/lua/core/events/skill.lua index 8379346..b3b644d 100644 --- a/lua/core/events/skill.lua +++ b/lua/core/events/skill.lua @@ -13,7 +13,7 @@ ---@field public no_indicate? boolean @ 发动时是否不显示指示线 ---@field public audio_index? number @ 发动时是否播放特定编号台词 ---@field public anim_type? AnimationType|string @ 发动时是否播放特定动画 ----@field public history_branch? string @ 发动时是否播放特定动画 +---@field public history_branch? string @ 发动时是否将技能发动历史归类到某个分支 --- 技能使用的数据 ---@class SkillUseData: SkillUseDataSpec, TriggerData diff --git a/lua/core/skill_type/usable_skill.lua b/lua/core/skill_type/usable_skill.lua index 7e8dbb4..cc94500 100644 --- a/lua/core/skill_type/usable_skill.lua +++ b/lua/core/skill_type/usable_skill.lua @@ -8,6 +8,7 @@ ---@class UsableSkill : Skill ---@field public max_use_time table @ 一个效果的最大可用次数 +---@field public history_branch? string|fun(self: UsableSkill, player: ServerPlayer, data: SkillUseData):string? @ 发动时是否将技能发动历史归类到某个分支 ---@field public expand_pile? string | integer[] | fun(self: UsableSkill, player: Player): integer[]|string? @ 额外牌堆,牌堆名称或卡牌id表 ---@field public derived_piles? string | string[] @deprecated @ 与某效果联系起来的私人牌堆名,失去该效果时将之置入弃牌堆 ---@field public times? fun(self: UsableSkill, player: Player): integer diff --git a/lua/fk_ex.lua b/lua/fk_ex.lua index 99afb5a..709d18c 100644 --- a/lua/fk_ex.lua +++ b/lua/fk_ex.lua @@ -80,6 +80,7 @@ function fk.readUsableSpecToSkill(skill, spec) skill.is_delay_effect = not not spec.is_delay_effect skill.late_refresh = not not spec.late_refresh skill.click_count = not not spec.click_count + skill.history_branch = spec.history_branch end function fk.readStatusSpecToSkill(skill, spec) @@ -95,7 +96,7 @@ end ---@field public max_turn_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能效果的最大使用次数——回合 ---@field public max_round_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能效果的最大使用次数——轮次 ---@field public max_game_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能效果的最大使用次数——本局游戏 ----@field public history_branch? string @ 裁定本技能发动时(on_cost->on_use)将技能历史额外添加到某处分支下(内部有独立的时段细分),这也将超前地接管自动次数判断 +---@field public history_branch? string|fun(self: UsableSkill, player: ServerPlayer, data: SkillUseData):string? @ 裁定本技能发动时(on_cost->on_use)将技能历史额外添加到某处分支下(内部有独立的时段细分),无法约束本技能是否可用 ---@field public expand_pile? string | integer[] | fun(self: UsableSkill, player: ServerPlayer): integer[]|string? @ 额外牌堆,牌堆名称或卡牌id表 ---@field public derived_piles? string | string[] @ 与某效果联系起来的私人牌堆名,失去该效果时将之置入弃牌堆(@deprecated) ---@field public times? integer | fun(self: UsableSkill, player: Player): integer @ 显示在主动技按钮上的发动次数数字 diff --git a/lua/server/events/skill.lua b/lua/server/events/skill.lua index 9b9c24c..d4a1d6e 100644 --- a/lua/server/events/skill.lua +++ b/lua/server/events/skill.lua @@ -96,14 +96,19 @@ function SkillEffect:main() end player:addSkillUseHistory(skill.name) - if skill.name ~= skill:getSkeleton().name and not skill.is_delay_effect then + if not (skill.name ~= skill:getSkeleton().name and skill.is_delay_effect) then player:addSkillUseHistory(skill:getSkeleton().name) - if cost_data.history_branch then - player:addSkillBranchUseHistory(skill:getSkeleton().name, cost_data.history_branch) + local branch = cost_data.history_branch + if not branch then + if type(skill.history_branch) == "function" then + branch = skill:history_branch(player, skill_data) + else + branch = skill.history_branch + end end - else --想必没人给自己的主effect上is_delay_effect吧 - if cost_data.history_branch then - player:addSkillBranchUseHistory(skill.name, cost_data.history_branch) + + if branch then + player:addSkillBranchUseHistory(skill:getSkeleton().name, branch) end end end @@ -141,7 +146,7 @@ end ---@param player ServerPlayer @ 发动技能的玩家 ---@param skill Skill @ 发动的技能 ---@param effect_cb fun() @ 实际要调用的函数 ----@param skill_data? table @ 技能的信息 +---@param skill_data? SkillUseDataSpec @ 技能的信息 ---@return SkillEffectData function SkillEventWrappers:useSkill(player, skill, effect_cb, skill_data) ---@cast self Room diff --git a/lua/server/room.lua b/lua/server/room.lua index 8ba3810..565256a 100644 --- a/lua/server/room.lua +++ b/lua/server/room.lua @@ -2205,26 +2205,28 @@ function Room:handleUseCardReply(player, data, params) local selected_cards = card_data.subcards if skill.interaction then skill.interaction.data = data.interaction_data end if skill:isInstanceOf(ActiveSkill) then + local use_data = { + from = player, + cards = selected_cards, + tos = table.map(targets, Util.Id2PlayerMapper), + } ---@cast skill ActiveSkill self:useSkill(player, skill, function() - skill:onUse(self, SkillUseData:new { - from = player, - cards = selected_cards, - tos = table.map(targets, Util.Id2PlayerMapper), - }) - end, {tos = table.map(targets, Util.Id2PlayerMapper), cards = selected_cards, cost_data = {}}) + skill:onUse(self, SkillUseData:new(use_data)) + end, use_data) return nil elseif skill:isInstanceOf(ViewAsSkill) then ---@cast skill ViewAsSkill --Self = player local useResult local c = skill:viewAs(player, selected_cards) + local use_data = { + from = player, + cards = selected_cards, + tos = table.map(targets, Util.Id2PlayerMapper), + } self:useSkill(player, skill, function() - useResult = skill:onUse(self, SkillUseData:new { - from = player, - cards = selected_cards, - tos = table.map(targets, Util.Id2PlayerMapper), - }, c, params) or "" + useResult = skill:onUse(self, SkillUseData:new(use_data), c, params) or "" if type(useResult) == "table" then if params == nil then player.room:useCard(useResult) @@ -2234,7 +2236,7 @@ function Room:handleUseCardReply(player, data, params) useResult.attachedSkillAndUser = { skillName = skill.name, user = player.id, muteCard = skill.mute_card } end end - end, {tos = table.map(targets, Util.Id2PlayerMapper), cards = selected_cards, cost_data = {}}) + end, use_data) return useResult end else -- Gitee From eb95cfed0f168819941eee7e2d1388c83edd685d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E5=A6=96=E6=A2=A6=E5=8E=A8?= <12796194+youmuKon-supreme@user.noreply.gitee.com> Date: Sun, 24 Aug 2025 06:08:33 +0800 Subject: [PATCH 07/13] fix --- lua/server/events/skill.lua | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/lua/server/events/skill.lua b/lua/server/events/skill.lua index d4a1d6e..6024100 100644 --- a/lua/server/events/skill.lua +++ b/lua/server/events/skill.lua @@ -95,21 +95,26 @@ function SkillEffect:main() ) end + local branch = cost_data.history_branch + if not branch then + if type(skill.history_branch) == "function" then + branch = skill:history_branch(player, skill_data) + else + branch = skill.history_branch + end + end + player:addSkillUseHistory(skill.name) - if not (skill.name ~= skill:getSkeleton().name and skill.is_delay_effect) then + if skill.name ~= skill:getSkeleton().name and not skill.is_delay_effect then player:addSkillUseHistory(skill:getSkeleton().name) - local branch = cost_data.history_branch - if not branch then - if type(skill.history_branch) == "function" then - branch = skill:history_branch(player, skill_data) - else - branch = skill.history_branch - end - end if branch then player:addSkillBranchUseHistory(skill:getSkeleton().name, branch) end + else + if branch then + player:addSkillBranchUseHistory(skill.name, branch) + end end end -- Gitee From d36b7d9f23100768a65b7be6fe8f9b01d66ca818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E5=A6=96=E6=A2=A6=E5=8E=A8?= <12796194+youmuKon-supreme@user.noreply.gitee.com> Date: Sun, 24 Aug 2025 21:45:49 +0800 Subject: [PATCH 08/13] fix --- lua/core/skill_skeleton.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/core/skill_skeleton.lua b/lua/core/skill_skeleton.lua index a45ccc8..3008c96 100644 --- a/lua/core/skill_skeleton.lua +++ b/lua/core/skill_skeleton.lua @@ -2,7 +2,7 @@ ---@class SkillSpec ---@field public name? string @ 技能名 ----@field public mute? boolean @ 决定是否关闭技能配音,若为true,同时也不添加技能发动历史 +---@field public mute? boolean @ 决定是否关闭技能配音 ---@field public no_indicate? boolean @ 决定是否关闭技能指示线 ---@field public anim_type? string|AnimationType @ 技能类型定义 ---@field public global? boolean @ 决定是否是全局技能 -- Gitee From 2d469277b3e58113264a267af39ec4b4b7dc01ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E5=A6=96=E6=A2=A6=E5=8E=A8?= <12796194+youmuKon-supreme@user.noreply.gitee.com> Date: Sun, 24 Aug 2025 22:19:48 +0800 Subject: [PATCH 09/13] =?UTF-8?q?=E6=B8=85=E7=A9=BA=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lua/core/player.lua | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/lua/core/player.lua b/lua/core/player.lua index aa3029a..6ca061b 100644 --- a/lua/core/player.lua +++ b/lua/core/player.lua @@ -933,6 +933,37 @@ function Player:setSkillBranchUseHistory(skill_name, branch, num, scope) end end +--- 清空玩家使用特定技能的历史次数 +---@param skill_name string @ 技能名,若为主技能则同时清空所有技能效果和分支的历史次数 +---@param scope? integer @ 清空的历史范围,不填则全部清空 +function Player:clearSkillHistory(skill_name, scope) + local skill = Fk.skills[skill_name] + local skel = skill:getSkeleton() + if skel and skel.name == skill_name then + if scope then + for _, effect in ipairs(skel.effect_names) do + self:setSkillUseHistory(effect, 0, scope) + end + else + for _, effect in ipairs(skel.effect_names) do + self:setSkillUseHistory(effect) + end + end + self:setSkillBranchUseHistory(skill_name) + return + end + + if scope then + for _, effect in ipairs(skill_name) do + self:setSkillUseHistory(effect, 0, scope) + end + else + for _, effect in ipairs(skill_name) do + self:setSkillUseHistory(effect) + end + end +end + --- 获取玩家使用特定牌的历史次数(只算计入次数的部分)。 ---@param cardName string @ 牌名 ---@param scope? integer @ 查询历史范围,默认Turn -- Gitee From df3fc5c7d734d346862522dad0cd25b64abd92e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E5=A6=96=E6=A2=A6=E5=8E=A8?= <12796194+youmuKon-supreme@user.noreply.gitee.com> Date: Sun, 24 Aug 2025 22:40:11 +0800 Subject: [PATCH 10/13] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=BB=E5=8A=A8?= =?UTF-8?q?=E6=8A=80/=E8=A7=86=E4=B8=BA=E6=8A=80=E7=9A=84=E8=8E=B7?= =?UTF-8?q?=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lua/server/room.lua | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/lua/server/room.lua b/lua/server/room.lua index 565256a..f39ce3a 100644 --- a/lua/server/room.lua +++ b/lua/server/room.lua @@ -2205,28 +2205,48 @@ function Room:handleUseCardReply(player, data, params) local selected_cards = card_data.subcards if skill.interaction then skill.interaction.data = data.interaction_data end if skill:isInstanceOf(ActiveSkill) then - local use_data = { + ---@cast skill ActiveSkill + + local use_spec = { from = player, cards = selected_cards, tos = table.map(targets, Util.Id2PlayerMapper), + cost_data = {} } - ---@cast skill ActiveSkill + local use_data = SkillUseData:new(use_spec) + if type(skill.history_branch) == "function" then + use_data.cost_data.history_branch = skill:history_branch(player, use_data) + else + use_data.cost_data.history_branch = skill.history_branch + end + use_spec.cost_data = table.simpleClone(use_data.cost_data) + self:useSkill(player, skill, function() - skill:onUse(self, SkillUseData:new(use_data)) - end, use_data) + skill:onUse(self, use_data) + end, use_spec) return nil elseif skill:isInstanceOf(ViewAsSkill) then ---@cast skill ViewAsSkill --Self = player local useResult local c = skill:viewAs(player, selected_cards) - local use_data = { + + local use_spec = { from = player, cards = selected_cards, tos = table.map(targets, Util.Id2PlayerMapper), + cost_data = {} } + local use_data = SkillUseData:new(use_spec) + if type(skill.history_branch) == "function" then + use_data.cost_data.history_branch = skill:history_branch(player, use_data) + else + use_data.cost_data.history_branch = skill.history_branch + end + use_spec.cost_data = table.simpleClone(use_data.cost_data) + self:useSkill(player, skill, function() - useResult = skill:onUse(self, SkillUseData:new(use_data), c, params) or "" + useResult = skill:onUse(self, use_data, c, params) or "" if type(useResult) == "table" then if params == nil then player.room:useCard(useResult) @@ -2236,7 +2256,7 @@ function Room:handleUseCardReply(player, data, params) useResult.attachedSkillAndUser = { skillName = skill.name, user = player.id, muteCard = skill.mute_card } end end - end, use_data) + end, use_spec) return useResult end else -- Gitee From 1fb08264735a76a879657b27afa5241699b04f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E5=A6=96=E6=A2=A6=E5=8E=A8?= <12796194+youmuKon-supreme@user.noreply.gitee.com> Date: Sun, 24 Aug 2025 22:46:12 +0800 Subject: [PATCH 11/13] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lua/core/skill_skeleton.lua | 14 +++++++------- lua/core/skill_type/usable_skill.lua | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lua/core/skill_skeleton.lua b/lua/core/skill_skeleton.lua index 3008c96..f8ae22a 100644 --- a/lua/core/skill_skeleton.lua +++ b/lua/core/skill_skeleton.lua @@ -19,12 +19,12 @@ ---@field public attached_skill_name? string @ 向其他角色分发的技能名(如黄天) ---@field public dynamic_name? fun(self: SkillSkeleton, player: Player, lang?: string): string @ 动态名称函数 ---@field public dynamic_desc? fun(self: SkillSkeleton, player: Player, lang?: string): string? @ 动态描述函数 ----@field public derived_piles? string|string[] @ 与该技能联系起来的私人牌堆名,失去该技能时将之置入弃牌堆 ----@field public max_phase_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能的最大使用次数——阶段 ----@field public max_turn_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能的最大使用次数——回合 ----@field public max_round_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能的最大使用次数——轮次 ----@field public max_game_use_time? integer|fun(self: SkillSkeleton, player: Player): integer? @ 该技能的最大使用次数——本局游戏 ----@field public max_branches_use_time? table?>|fun(self: SkillSkeleton, player: Player): table?>? @ 该技能的最大使用次数——任意标签(内部有独立的时段细分) +---@field public derived_piles? string | string[] @ 与该技能联系起来的私人牌堆名,失去该技能时将之置入弃牌堆 +---@field public max_phase_use_time? integer | fun(self: SkillSkeleton, player: Player): integer? @ 该技能的最大使用次数——阶段 +---@field public max_turn_use_time? integer | fun(self: SkillSkeleton, player: Player): integer? @ 该技能的最大使用次数——回合 +---@field public max_round_use_time? integer | fun(self: SkillSkeleton, player: Player): integer? @ 该技能的最大使用次数——轮次 +---@field public max_game_use_time? integer | fun(self: SkillSkeleton, player: Player): integer? @ 该技能的最大使用次数——本局游戏 +---@field public max_branches_use_time? table?> | fun(self: SkillSkeleton, player: Player): table?>? @ 该技能的最大使用次数——任意标签(内部有独立的时段细分) ---@field public mode_skill? boolean @ 是否为模式技能(诸如斗地主的“飞扬”和“跋扈”) ---@field public extra? table @ 塞进技能里的各种数据 @@ -38,7 +38,7 @@ ---@field public dynamicDesc fun(self: SkillSkeleton, player: Player, lang?: string): string @ 动态描述函数 ---@field public derived_piles? string[] @ 与该技能同在的私有牌堆名,失去时弃置其中的所有牌 ---@field public max_use_time table @ 该技能在各时机内最大的使用次数 ----@field public max_branches_use_time? table?>|fun(self: SkillSkeleton, player: Player): table?>? @ 该技能的最大使用次数——任意标签(内部有独立的时段细分) +---@field public max_branches_use_time? table?> | fun(self: SkillSkeleton, player: Player): table?>? @ 该技能的最大使用次数——任意标签(内部有独立的时段细分) ---@field public addTest fun(self: SkillSkeleton, fn: fun(room: Room, me: ServerPlayer)) @ 测试函数 ---@field public onAcquire fun(self: SkillSkeleton, player: ServerPlayer, is_start: boolean) @ 获得技能时执行的函数 ---@field public onLose fun(self: SkillSkeleton, player: ServerPlayer, is_death: boolean) @ 失去技能时执行的函数 diff --git a/lua/core/skill_type/usable_skill.lua b/lua/core/skill_type/usable_skill.lua index cc94500..772a6c4 100644 --- a/lua/core/skill_type/usable_skill.lua +++ b/lua/core/skill_type/usable_skill.lua @@ -8,7 +8,7 @@ ---@class UsableSkill : Skill ---@field public max_use_time table @ 一个效果的最大可用次数 ----@field public history_branch? string|fun(self: UsableSkill, player: ServerPlayer, data: SkillUseData):string? @ 发动时是否将技能发动历史归类到某个分支 +---@field public history_branch? string | fun(self: UsableSkill, player: ServerPlayer, data: SkillUseData):string? @ 发动时是否将技能发动历史归类到某个分支 ---@field public expand_pile? string | integer[] | fun(self: UsableSkill, player: Player): integer[]|string? @ 额外牌堆,牌堆名称或卡牌id表 ---@field public derived_piles? string | string[] @deprecated @ 与某效果联系起来的私人牌堆名,失去该效果时将之置入弃牌堆 ---@field public times? fun(self: UsableSkill, player: Player): integer -- Gitee From 5f82d9b8e5ef810edd967d0a7cd9d3b7c9b0d27b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E5=A6=96=E6=A2=A6=E5=8E=A8?= <12796194+youmuKon-supreme@user.noreply.gitee.com> Date: Mon, 25 Aug 2025 16:27:51 +0800 Subject: [PATCH 12/13] on_cost --- lua/core/skill_skeleton.lua | 3 +++ lua/core/skill_type/active.lua | 6 ++++++ lua/core/skill_type/view_as.lua | 6 ++++++ lua/fk_ex.lua | 4 +++- lua/server/room.lua | 24 ++++++++++++++---------- 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/lua/core/skill_skeleton.lua b/lua/core/skill_skeleton.lua index f8ae22a..5b8cf2e 100644 --- a/lua/core/skill_skeleton.lua +++ b/lua/core/skill_skeleton.lua @@ -539,6 +539,7 @@ function SkillSkeleton:createActiveSkill(_skill, idx, key, attr, spec) if spec.card_filter then skill.cardFilter = spec.card_filter end if spec.target_filter then skill.targetFilter = spec.target_filter end if spec.feasible then skill.feasible = spec.feasible end + if spec.on_cost then skill.onCost = spec.on_cost end if spec.on_use then skill.onUse = spec.on_use end if spec.prompt then skill.prompt = spec.prompt end if spec.target_tip then skill.targetTip = spec.target_tip end @@ -688,6 +689,8 @@ function SkillSkeleton:createViewAsSkill(_skill, idx, key, attr, spec) skill.mute_card = not (string.find(skill.pattern, "|") or skill.pattern == "." or string.find(skill.pattern, ",")) end + if spec.on_cost then skill.onCost = spec.on_cost end + return skill end diff --git a/lua/core/skill_type/active.lua b/lua/core/skill_type/active.lua index b417474..d7e092f 100644 --- a/lua/core/skill_type/active.lua +++ b/lua/core/skill_type/active.lua @@ -196,6 +196,12 @@ function ActiveSkill:prompt(player, selected_cards, selected_targets, extra_data ------- } +---@param player ServerPlayer +---@param skillData SkillUseData +function ActiveSkill:onCost(player, skillData) + return {} +end + ---@param room Room ---@param cardUseEvent SkillUseData function ActiveSkill:onUse(room, cardUseEvent) end diff --git a/lua/core/skill_type/view_as.lua b/lua/core/skill_type/view_as.lua index f000a07..266e1fb 100644 --- a/lua/core/skill_type/view_as.lua +++ b/lua/core/skill_type/view_as.lua @@ -116,6 +116,12 @@ function ViewAsSkill:feasible(player, targets, selected_cards, card) return false end +---@param player ServerPlayer +---@param skillData SkillUseData +function ViewAsSkill:onCost(player, skillData) + return {} +end + ---@param room Room ---@param cardUseEvent SkillUseData ---@param params? handleUseCardParams diff --git a/lua/fk_ex.lua b/lua/fk_ex.lua index 709d18c..20db6ec 100644 --- a/lua/fk_ex.lua +++ b/lua/fk_ex.lua @@ -115,6 +115,7 @@ end ---@field public card_filter? fun(self: ActiveSkill, player: Player, to_select: integer, selected: integer[], selected_targets: Player[]): any @ 判断卡牌能否选择 ---@field public target_filter? fun(self: ActiveSkill, player: Player?, to_select: Player, selected: Player[], selected_cards: integer[], card: Card?, extra_data: UseExtraData|table?): any @ 判定目标能否选择 ---@field public feasible? fun(self: ActiveSkill, player: Player, selected: Player[], selected_cards: integer[], card: Card): any @ 判断卡牌和目标是否符合技能限制 +---@field public on_cost? fun(self: UsableSkill, player: ServerPlayer, data: SkillUseData):CostData|table @ 自定义技能的消耗信息 ---@field public on_use? fun(self: ActiveSkill, room: Room, skillUseEvent: SkillUseData): any ---@field public prompt? string|fun(self: ActiveSkill, player: Player, selected_cards: integer[], selected_targets: Player[]): string @ 提示信息 ---@field public interaction? fun(self: ActiveSkill, player: Player): table? @ 选项框 @@ -143,8 +144,9 @@ end ---@field public card_filter? fun(self: ViewAsSkill, player: Player, to_select: integer, selected: integer[], selected_targets: Player[]): any @ 判断卡牌能否选择 ---@field public target_filter? fun(self: ViewAsSkill, player: Player?, to_select: Player, selected: Player[], selected_cards: integer[], card: Card?, extra_data: UseExtraData|table?): any @ 判定目标能否选择 ---@field public feasible? fun(self: ViewAsSkill, player: Player, selected: Player[], selected_cards: integer[], card: Card): any @ 判断卡牌和目标是否符合技能限制 ----@field public on_use? fun(self: ActiveSkill, room: Room, skillUseEvent: SkillUseData, card: Card, params: handleUseCardParams?): UseCardDataSpec|string? +---@field public on_use? fun(self: ViewAsSkill, room: Room, skillUseEvent: SkillUseData, card: Card, params: handleUseCardParams?): UseCardDataSpec|string? ---@field public view_as fun(self: ViewAsSkill, player: Player, cards: integer[]): Card? @ 判断转化为什么牌 +---@field public on_cost? fun(self: ViewAsSkill, player: ServerPlayer, data: SkillUseData):CostData|table @ 自定义技能的消耗信息 ---@field public pattern? string ---@field public enabled_at_play? fun(self: ViewAsSkill, player: Player): any ---@field public enabled_at_response? fun(self: ViewAsSkill, player: Player, response: boolean): any diff --git a/lua/server/room.lua b/lua/server/room.lua index f39ce3a..de8c973 100644 --- a/lua/server/room.lua +++ b/lua/server/room.lua @@ -2211,13 +2211,15 @@ function Room:handleUseCardReply(player, data, params) from = player, cards = selected_cards, tos = table.map(targets, Util.Id2PlayerMapper), - cost_data = {} } local use_data = SkillUseData:new(use_spec) - if type(skill.history_branch) == "function" then - use_data.cost_data.history_branch = skill:history_branch(player, use_data) - else - use_data.cost_data.history_branch = skill.history_branch + use_data.cost_data = skill:onCost(player, use_data) + if not use_data.cost_data.history_branch then + if type(skill.history_branch) == "function" then + use_data.cost_data.history_branch = skill:history_branch(player, use_data) + else + use_data.cost_data.history_branch = skill.history_branch + end end use_spec.cost_data = table.simpleClone(use_data.cost_data) @@ -2235,13 +2237,15 @@ function Room:handleUseCardReply(player, data, params) from = player, cards = selected_cards, tos = table.map(targets, Util.Id2PlayerMapper), - cost_data = {} } local use_data = SkillUseData:new(use_spec) - if type(skill.history_branch) == "function" then - use_data.cost_data.history_branch = skill:history_branch(player, use_data) - else - use_data.cost_data.history_branch = skill.history_branch + use_data.cost_data = skill:onCost(player, use_data) + if not use_data.cost_data.history_branch then + if type(skill.history_branch) == "function" then + use_data.cost_data.history_branch = skill:history_branch(player, use_data) + else + use_data.cost_data.history_branch = skill.history_branch + end end use_spec.cost_data = table.simpleClone(use_data.cost_data) -- Gitee From a59e393b5dffb560f2f254eda14b9c7e11ce1385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E5=A6=96=E6=A2=A6=E5=8E=A8?= <12796194+youmuKon-supreme@user.noreply.gitee.com> Date: Mon, 25 Aug 2025 20:40:41 +0800 Subject: [PATCH 13/13] =?UTF-8?q?=E5=A6=A5=E5=8D=8F=E4=B8=80=E4=B8=8B?= =?UTF-8?q?=EF=BC=8C=E4=BC=A0data=E5=90=A7=E2=80=A6=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lua/server/room.lua | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lua/server/room.lua b/lua/server/room.lua index de8c973..fbef33b 100644 --- a/lua/server/room.lua +++ b/lua/server/room.lua @@ -2221,11 +2221,10 @@ function Room:handleUseCardReply(player, data, params) use_data.cost_data.history_branch = skill.history_branch end end - use_spec.cost_data = table.simpleClone(use_data.cost_data) self:useSkill(player, skill, function() skill:onUse(self, use_data) - end, use_spec) + end, use_data) return nil elseif skill:isInstanceOf(ViewAsSkill) then ---@cast skill ViewAsSkill @@ -2247,7 +2246,6 @@ function Room:handleUseCardReply(player, data, params) use_data.cost_data.history_branch = skill.history_branch end end - use_spec.cost_data = table.simpleClone(use_data.cost_data) self:useSkill(player, skill, function() useResult = skill:onUse(self, use_data, c, params) or "" @@ -2260,7 +2258,7 @@ function Room:handleUseCardReply(player, data, params) useResult.attachedSkillAndUser = { skillName = skill.name, user = player.id, muteCard = skill.mute_card } end end - end, use_spec) + end, use_data) return useResult end else -- Gitee