diff --git a/excel/Rune.xlsx b/excel/Rune.xlsx index d48bb19..73fe200 100644 Binary files a/excel/Rune.xlsx and b/excel/Rune.xlsx differ diff --git a/excel/attribute.xlsx b/excel/attribute.xlsx index 16f4933..1c5e8f9 100644 Binary files a/excel/attribute.xlsx and b/excel/attribute.xlsx differ diff --git a/src/ReplicatedStorage/Tools/ScriptModule.luau b/src/ReplicatedStorage/Tools/ScriptModule.luau new file mode 100644 index 0000000..f04f90c --- /dev/null +++ b/src/ReplicatedStorage/Tools/ScriptModule.luau @@ -0,0 +1,31 @@ +local ScriptModule = {} + +-- 将目标类的所有函数全部注入到指定表中 +function ScriptModule:InjectScriptFunctions(ParentTable: table, ScriptModule: table) + for key, value in ScriptModule do + if typeof(value) == "function" then + ParentTable[key] = value + end + end +end + +-- 注入文件夹下所有模块,到指定表中 +function ScriptModule:InjectFolderModules(ParentTable: table, Folder: Instance) + if Folder then + for _, module in ipairs(Folder:GetChildren()) do + if module:IsA("ModuleScript") then + local success, result = pcall(require, module) + if success then + -- 去掉文件名后缀 + local name = module.Name + ParentTable[name] = result + else + warn("加载代理模块失败: " .. module.Name, result) + end + end + end + end +end + + +return ScriptModule \ No newline at end of file diff --git a/src/ServerStorage/Base/Rune.luau b/src/ServerStorage/Base/Rune.luau new file mode 100644 index 0000000..53de154 --- /dev/null +++ b/src/ServerStorage/Base/Rune.luau @@ -0,0 +1,108 @@ +local Rune = {} +Rune.__index = Rune + +--> Services +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local ServerStorage = game:GetService("ServerStorage") + +--> Dependencies +local TypeList = require(ServerStorage.Base.TypeList) +local Communicate = require(ServerStorage.Modules.Tools.Communicate) +local Utils = require(ReplicatedStorage.Tools.Utils) + + + +function Rune:Init(PlayerAI: Player, Character: TypeList.Character, ScriptName: string) + local self = {} + setmetatable(self, Rune) + self.PlayerAI = PlayerAI + self.Character = Character + self.ScriptName = ScriptName + self.TriggerSlot = 0 + self.WearingSlot = 0 + self.TriggerTime = 0 +end + +-- 触发最开始事件 +function Rune:OnStartEvent(runeName: string, triggerSlot: number, AttributesData: table?, BehaviorNameList: table?) + -- runeName: 符文名称 + -- triggerSlot: 触发槽位 + -- AttributesData: 属性数据,符文可以修改 + -- BehaviorNameList: 行为名称列表,符文可以修改 + -- 返回值: 可以返回下一个index来控制流程,或者nil表示不干预 +end + +-- 卡牌触发前事件 +function Rune:OnTriggerBeginEvent(index: number, AttributesData: table?, BehaviorNameList: table?) + -- index: 当前符文在列表中的位置 + -- AttributesData: 属性数据,符文可以修改 + -- BehaviorNameList: 行为名称列表,符文可以修改 + -- 返回值: 可以返回下一个index来控制流程,或者nil表示不干预 +end + +-- 卡牌触发后事件 +function Rune:OnTriggerEndEvent(index: number, AttributesData: table?, BehaviorNameList: table?) + -- index: 当前符文在列表中的位置 + -- AttributesData: 属性数据,符文可以修改 + -- BehaviorNameList: 行为名称列表,符文可以修改 + -- 返回值: 可以返回下一个index来控制流程,或者nil表示不干预 +end + +-- 触发结束事件 +function Rune:OnEndEvent(runeName: string, triggerSlot: number, AttributesData: table?, BehaviorNameList: table?) + -- runeName: 符文名称 + -- triggerSlot: 触发槽位 + -- AttributesData: 属性数据,符文可以修改 + -- BehaviorNameList: 行为名称列表,符文可以修改 + -- 返回值: 可以返回下一个index来控制流程,或者nil表示不干预 +end + +-- 检查事件 +function Rune:Check(index: number, AttributesData: table?, BehaviorNameList: table?) + -- index: 当前符文在列表中的位置 + -- AttributesData: 属性数据,符文可以修改 + -- BehaviorNameList: 行为名称列表,符文可以修改 + return false -- 默认返回false,表示不可以执行 +end + +-- 执行事件 +function Rune:Execute(index: number, AttributesData: table?, BehaviorNameList: table?) + -- 使用PlayerAI的专用方法,性能更好 + local beginNextIndex = self.PlayerAI:TriggerAllRunesExcept(self, "OnTriggerBeginEvent", index, AttributesData, BehaviorNameList) + if type(beginNextIndex) == "number" then + return beginNextIndex + end + + -- 执行自己的逻辑 + local nextIndex = self:OnExecute(index, AttributesData, BehaviorNameList) + if type(nextIndex) == "number" then + self.PlayerAI:TriggerAllRunesExcept(self, "OnTriggerEndEvent", index, AttributesData, BehaviorNameList) + return nextIndex + end + + local endNextIndex = self.PlayerAI:TriggerAllRunesExcept(self, "OnTriggerEndEvent", index, AttributesData, BehaviorNameList) + if type(endNextIndex) == "number" then + return endNextIndex + end + self.TriggerTime = self.TriggerTime + 1 + return nextIndex -- 返回下一个要执行的index +end + +-- 子类可以重写这个方法 +function Rune:OnExecute(index: number, AttributesData: table?, BehaviorNameList: table?) + -- 默认实现,子类可以重写 + -- index: 当前符文在列表中的位置 + -- AttributesData: 属性数据,符文可以修改 + -- BehaviorNameList: 行为名称列表,符文可以修改 + -- 返回值: 下一个要执行的index,或者nil表示继续下一个 + return nil -- 默认继续下一个符文 +end + +-- 销毁 +function Rune:OnDestroy() + self = nil +end + + + +return Rune \ No newline at end of file diff --git a/src/ServerStorage/Modules/Behaviours/IceCoffine.luau b/src/ServerStorage/Modules/Behaviours/IceCoffine.luau new file mode 100644 index 0000000..d3911c3 --- /dev/null +++ b/src/ServerStorage/Modules/Behaviours/IceCoffine.luau @@ -0,0 +1,71 @@ +-- 冰棺技能:残血后立即回血 + +--> Services +local ServerStorage = game:GetService("ServerStorage") +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +--> Dependencies +local TypeList = require(ServerStorage.Base.TypeList) +local Behaviour = require(ServerStorage.Base.Behaviour) +local MobsProxy = require(ServerStorage.Proxy.MobsProxy) +local DamageProxy = require(ServerStorage.Proxy.DamageProxy) +local Utils = require(ReplicatedStorage.Tools.Utils) + +-------------------------------------------------------------------------------- + +local IceCoffine = {} +IceCoffine.__index = IceCoffine +setmetatable(IceCoffine, {__index = Behaviour}) + +local CAST_DISTANCE = 50 +local PROJECTILE_LENGTH = 50 +local PROJECTILE_DURATION = 3 +local COOLDOWN = 1000 + +function IceCoffine:Init(PlayerAI, Character: TypeList.Character, Player: Player) + local self = Behaviour:Init(PlayerAI, Character, script.Name) + self.Player = Player + self.Mobs = nil + setmetatable(self, IceCoffine) + self.OrgCooldown = COOLDOWN + self:StartCooldownTask() + + -- 客户端表现 + self:SendPerformanceEvent("Init", self.Player, script.Name, true, {}) + return self +end + +function IceCoffine:Check(CheckInfo: table) + if Behaviour.CheckStat(self) then return -1, self.CheckData end + self:CheckClean() + + -- 当前血量<=20%时触发技能 + local maxHp = self.Character.Stats.MaxHp + local currentHp = self.Character.Stats.Hp + local recoverHp = maxHp * 0.2 + if currentHp <= recoverHp then + self.CheckData = {} + return 300, self.CheckData + end + + -- 返回优先级,执行数据 + return -1, self.CheckData +end + +function IceCoffine:Execute() + self.ExeTask = task.spawn(function () + self:ChangeExecutingState(true) + -- cd放前面之后发送事件才能正常记录cd + self:StartCooldownTask() + + local maxHp = self.Character.Stats.MaxHp + local recoverHp = math.floor(maxHp * (self.PlayerAI:GetSharedData("IceCoffin_MaxRecover") / 100)) + DamageProxy:Heal(self.Character, self.Character, recoverHp) + task.wait(0.5) + + self:ChangeExecutingState(false) + end) +end + + +return IceCoffine \ No newline at end of file diff --git a/src/ServerStorage/Modules/Runes/RuneFireDamage.luau b/src/ServerStorage/Modules/Runes/RuneFireDamage.luau new file mode 100644 index 0000000..3e5d225 --- /dev/null +++ b/src/ServerStorage/Modules/Runes/RuneFireDamage.luau @@ -0,0 +1,31 @@ +--> Services +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +--> Dependencies +local Utils = require(ReplicatedStorage.Tools.Utils) + +local RuneFireDamage = {} +RuneFireDamage.__index = RuneFireDamage +setmetatable(RuneFireDamage, {__index = Rune}) + + +function RuneFireDamage:Init(PlayerAI, Character: TypeList.Character, Player: Player) + local self = Rune:Init(PlayerAI, Character, script.Name) + self.Player = Player + setmetatable(self, RuneFireDamage) + + return self +end + +function RuneFireDamage:Check(index: number, AttributesData: table, BehaviorNameList: table) + return true +end + +function RuneFireDamage:OnExecute(index: number, AttributesData: table, BehaviorNameList: table) + print("RuneFireDamage:OnExecute", index, AttributesData, BehaviorNameList) + Utils:TableSafeAddValue(AttributesData, "fireAtk", 100) + return nil +end + + +return RuneFireDamage \ No newline at end of file diff --git a/src/ServerStorage/Modules/Runes/RuneIceCoffin.luau b/src/ServerStorage/Modules/Runes/RuneIceCoffin.luau new file mode 100644 index 0000000..040e688 --- /dev/null +++ b/src/ServerStorage/Modules/Runes/RuneIceCoffin.luau @@ -0,0 +1,36 @@ +--> Services +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +--> Dependencies +local Utils = require(ReplicatedStorage.Tools.Utils) + +local RuneIceCoffin = {} +RuneIceCoffin.__index = RuneIceCoffin +setmetatable(RuneIceCoffin, {__index = Rune}) + + +function RuneIceCoffin:Init(PlayerAI, Character: TypeList.Character, Player: Player) + local self = Rune:Init(PlayerAI, Character, script.Name) + self.Player = Player + setmetatable(self, RuneIceCoffin) + + return self +end + +function RuneIceCoffin:Check(index: number, AttributesData: table, BehaviorNameList: table) + return true +end + +function RuneIceCoffin:OnExecute(index: number, AttributesData: table, BehaviorNameList: table) + print("RuneIceCoffin:OnExecute", index, AttributesData, BehaviorNameList) + local maxRecover = self.PlayerAI:GetSharedData("IceCoffin_MaxRecover") + if maxRecover then + self.PlayerAI:SetSharedData("IceCoffin_MaxRecover", maxRecover + 60) + else + self.PlayerAI:SetSharedData("IceCoffin_MaxRecover", 60) + end + return nil +end + + +return RuneIceCoffin \ No newline at end of file diff --git a/src/ServerStorage/Proxy/DamageProxy.luau b/src/ServerStorage/Proxy/DamageProxy.luau index 069887a..318ad07 100644 --- a/src/ServerStorage/Proxy/DamageProxy.luau +++ b/src/ServerStorage/Proxy/DamageProxy.luau @@ -42,6 +42,12 @@ export type DamageInfo = { ElementType: ElementType, } +export type HealInfo = { + Caster: TypeList.Character, + Victim: TypeList.Character, + Amount: number, +} + DamageProxy.DamageType = DamageType DamageProxy.DamageTag = DamageTag DamageProxy.ElementType = ElementType @@ -275,4 +281,58 @@ function DamageProxy:TakeDamage(Caster: TypeList.Character, Victim: TypeList.Cha end end +-- 治疗处理(简化版本) +function DamageProxy:Heal(Caster: TypeList.Character, Victim: TypeList.Character, Amount: number) + -- 基础参数验证 + if not Caster or not Victim or not Amount or Amount <= 0 then + warn("Heal: 基础参数无效") + return + end + + -- 注册对象到生命周期管理器 + globalLifecycleManager:RegisterObject(Caster) + globalLifecycleManager:RegisterObject(Victim) + + -- 检查对象是否仍然有效 + if not globalLifecycleManager:IsObjectValid(Caster) or not globalLifecycleManager:IsObjectValid(Victim) then + warn("Heal: 施法者或目标已被销毁") + return + end + + -- 治疗计算 + local VictimHealth = Victim:GetAttributeValue("hp") or 0 + local MaxHealth = Victim:GetAttributeValue("maxHp") or 0 + + -- 计算实际治疗量(不超过最大生命值) + local actualHeal = math.min(Amount, MaxHealth - VictimHealth) + local overheal = math.max(0, Amount - actualHeal) + + if actualHeal > 0 then + Victim:ChangeAttributeValue("hp", VictimHealth + actualHeal) + end + + -- 给前端发送治疗信息 + local clientHealInfo = { + Caster = Caster.Instance, + Victim = Victim.Instance, + ServerTime = os.time(), + HealPosition = Victim.Instance.PrimaryPart.Position, + HealAmount = actualHeal, + Overheal = overheal, + OriginalHealth = VictimHealth, + NewHealth = VictimHealth + actualHeal + } + + -- 发送数据到客户端 + local success, error = pcall(function() + Communicate:SendToClient(RE_DamagePerformance, "Heal", Caster.Player, clientHealInfo) + end) + + if not success then + warn("Heal: 发送治疗数据失败:", error) + end + + return actualHeal, overheal +end + return DamageProxy \ No newline at end of file diff --git a/src/ServerStorage/Proxy/PlayerFightProxy/PlayerAI.luau b/src/ServerStorage/Proxy/PlayerFightProxy/PlayerAI.luau index 4544910..685b939 100644 --- a/src/ServerStorage/Proxy/PlayerFightProxy/PlayerAI.luau +++ b/src/ServerStorage/Proxy/PlayerFightProxy/PlayerAI.luau @@ -10,6 +10,7 @@ local ReplicatedStorage = game:GetService("ReplicatedStorage") --> Dependencies local TypeList = require(ServerStorage.Base.TypeList) local Utils = require(ReplicatedStorage.Tools.Utils) +local ScriptModule = require(ReplicatedStorage.Tools.ScriptModule) local Communicate = require(ServerStorage.Modules.Tools.Communicate) --> Events @@ -21,21 +22,10 @@ local DamageProxy = require(ServerStorage.Proxy.DamageProxy) local ActivePlayers = {} local Behaviours = {} -local BehaviourFolder = ServerStorage:FindFirstChild("Modules"):FindFirstChild("Behaviours") -if BehaviourFolder then - for _, behaviourModule in ipairs(BehaviourFolder:GetChildren()) do - if behaviourModule:IsA("ModuleScript") then - local success, result = pcall(require, behaviourModule) - if success then - -- 去掉文件名后缀 - local name = behaviourModule.Name - Behaviours[name] = result - else - warn("加载代理模块失败: " .. behaviourModule.Name, result) - end - end - end -end +ScriptModule:InjectFolderModules(Behaviours, ServerStorage:FindFirstChild("Modules"):FindFirstChild("Behaviours")) + +local Runes = {} +ScriptModule:InjectFolderModules(Runes, ServerStorage:FindFirstChild("Modules"):FindFirstChild("Runes")) -------------------------------------------------------------------------------- @@ -53,6 +43,8 @@ function PlayerAI.new(Player: Player, PlayerRole: TypeList.Character) self.Counter = 0 self.BehaviourList = {} + self.RuneList = {} + self.SharedData = {} -- 符文和行为之间的共享数据 self.LoopTask = task.spawn(function() while task.wait(0.25) do if self.Character.Stats.Died then continue end @@ -109,11 +101,118 @@ function PlayerAI:AddBehaviour(BehaviourName: string, WearingSlot: number?) self.BehaviourList[BehaviourName] = newBehaviour end +-- 动态添加符文 +function PlayerAI:AddRune(RuneName: string, WearingSlot: number?) + if not Runes[RuneName] then warn("Rune not found") return end + local newRune = Runes[RuneName]:Init(self, self.Character, self.Player) + newRune.WearingSlot = WearingSlot or 4 + + self.RuneList[RuneName] = newRune + + -- 更新所有符文的TriggerSlot + self:UpdateRuneTriggerSlots() +end + +-- 更新所有符文的TriggerSlot +function PlayerAI:UpdateRuneTriggerSlots() + -- 收集所有符文并按WearingSlot排序 + local runeArray = {} + for runeName, rune in pairs(self.RuneList) do + table.insert(runeArray, { + name = runeName, + rune = rune, + slot = rune.WearingSlot + }) + end + + -- 按WearingSlot排序 + table.sort(runeArray, function(a, b) + return a.slot < b.slot + end) + + -- 分配TriggerSlot(从1开始,排除空槽位) + local currentTriggerSlot = 1 + for _, runeData in ipairs(runeArray) do + runeData.rune.TriggerSlot = currentTriggerSlot + currentTriggerSlot = currentTriggerSlot + 1 + end +end + -- 获取并记录行为UniqueId function PlayerAI:GetBehaviourUniqueId() return Utils:GenUniqueIdPlayerAI(self.LastTime, self.Counter) end +-- 获取当前符文列表 +function PlayerAI:GetRuneList() + local runeArray = {} + for runeName, rune in self.RuneList do + runeArray[rune.TriggerSlot] = runeName + end + return runeArray +end + + +-- 遍历符文并执行回调 +function PlayerAI:ForEachRune(callback: (runeName: string, triggerSlot: number, rune: table) -> ()) + for runeName, rune in pairs(self.RuneList) do + local result = callback(runeName, rune.TriggerSlot, rune) + -- 如果回调返回了数字,表示要控制流程 + if type(result) == "number" then + return result + end + end + return nil -- 没有符文要控制流程 +end + +-- 触发所有符文的指定事件(除了指定符文) +function PlayerAI:TriggerAllRunesExcept(excludeRune: table, eventName: string, ...) + for runeName, rune in pairs(self.RuneList) do + if rune ~= excludeRune and rune[eventName] and typeof(rune[eventName]) == "function" then + local result = rune[eventName](rune, ...) + if type(result) == "number" then + return result + end + end + end + return nil +end + +-- 触发所有符文的指定事件 +function PlayerAI:TriggerAllRunes(eventName: string, ...) + for runeName, rune in pairs(self.RuneList) do + if rune[eventName] and typeof(rune[eventName]) == "function" then + rune[eventName](rune, ...) + end + end +end + +-- 触发指定符文的指定事件 +function PlayerAI:TriggerRune(runeName: string, eventName: string, ...) + if self.RuneList[runeName] and self.RuneList[runeName][eventName] and typeof(self.RuneList[runeName][eventName]) == "function" then + return self.RuneList[runeName][eventName](self.RuneList[runeName], ...) + end +end + +-- 设置共享数据 +function PlayerAI:SetSharedData(key: string, value: any) + self.SharedData[key] = value +end + +-- 获取共享数据 +function PlayerAI:GetSharedData(key: string) + return self.SharedData[key] +end + +-- 清除共享数据 +function PlayerAI:ClearSharedData(key: string?) + if key then + self.SharedData[key] = nil + else + self.SharedData = {} + end +end + -- 获取客户端行为列表 function PlayerAI:GetClientBehaviourList() local clientBehaviourList = { @@ -144,6 +243,24 @@ function PlayerAI:RemoveBehaviour(BehaviourName: string) end end +-- 动态删除符文 +function PlayerAI:RemoveRune(RuneName: string) + if self.RuneList[RuneName] then + self.RuneList[RuneName]:Destroy() + self.RuneList[RuneName] = nil + + -- 更新所有符文的TriggerSlot + self:UpdateRuneTriggerSlots() + end +end + +-- 清除所有符文 +function PlayerAI:ClearAllRune() + for _, rune in self.RuneList do rune:Destroy() end + self.RuneList = {} + -- 清除后不需要更新TriggerSlot,因为已经没有符文了 +end + -- 清除所有行为 function PlayerAI:ClearAllBehaviour() for _, behaviour in self.BehaviourList do behaviour:Destroy() end diff --git a/src/ServerStorage/Proxy/PlayerFightProxy/init.luau b/src/ServerStorage/Proxy/PlayerFightProxy/init.luau index 95a1801..305a5a4 100644 --- a/src/ServerStorage/Proxy/PlayerFightProxy/init.luau +++ b/src/ServerStorage/Proxy/PlayerFightProxy/init.luau @@ -192,13 +192,17 @@ function PlayerFightProxy:UpdatePlayerFightData(Player: Player) end -- 根据技能添加玩家AI行为 - local abilityIdList, behaviourNameList = AbilityProxy:GetPlayerWearingAbilityData(Player) + local abilityIdList, behaviorNameList = AbilityProxy:GetPlayerWearingAbilityData(Player) local playerAI = PlayerFightProxy:GetPlayerAI(Player) + -- 玩家符文影响 + local RuneProxy = require(ServerStorage.Proxy.RuneProxy) + RuneProxy:GetRuneAttributes(Player, playerAI, AttributesData, behaviorNameList) + -- TODO:设置AI行为(临时清除所有行为,添加新的玩家行为) playerAI:ClearAllBehaviour() - for _, behaviourName in behaviourNameList do - playerAI:AddBehaviour(behaviourName) + for _, behaviorName in behaviorNameList do + playerAI:AddBehaviour(behaviorName) end playerAI:AddBehaviour("Move") -- playerAI:AddBehaviour("SwordWave") diff --git a/src/ServerStorage/Proxy/RuneProxy/RuneCalculation.luau b/src/ServerStorage/Proxy/RuneProxy/RuneCalculation.luau new file mode 100644 index 0000000..8ad3573 --- /dev/null +++ b/src/ServerStorage/Proxy/RuneProxy/RuneCalculation.luau @@ -0,0 +1,79 @@ +local RuneCalculation = {} + +-- 处理符文机制主函数 +function RuneCalculation:GetRuneAttributes(Player: Player, PlayerAI: table, AttributesData: table, BehaviorNameList: table) + if not Player and not PlayerAI then warn("Player or PlayerAI not found") return end + + -- 没穿戴符文,直接返回 + local wearingRuneUniqueId, wearingRuneName, wearingRuneBehaviorName = self:GetPlayerWearingRuneData(Player) + if #wearingRuneUniqueId == 0 then return AttributesData, BehaviorNameList end + + -- 行为名称列表处理 + for _, behaviorName in wearingRuneBehaviorName do + if not table.find(BehaviorNameList, behaviorName) then + table.insert(BehaviorNameList, behaviorName) + end + end + + -- 符文初始化 + PlayerAI:ClearSharedData() + PlayerAI:ClearAllRune() + for wearingSlot, runeName in wearingRuneName do PlayerAI:AddRune(runeName, wearingSlot) end + + -- 触发开始事件,并检查是否有符文要控制流程 + local startNextIndex = PlayerAI:ForEachRune(function(runeName, triggerSlot, rune) + local result = rune:OnStartEvent(runeName, triggerSlot, AttributesData, BehaviorNameList) + if type(result) == "number" then + return result -- 返回要跳转的index + end + end) + + local index = 1 + local maxSteps = 1000 -- 防止无限循环 + + -- 如果开始事件指定了起始位置,使用它 + if type(startNextIndex) == "number" then + index = startNextIndex + end + + -- 执行符文循环 + self:ExecuteRuneLoop(PlayerAI, wearingRuneName, wearingRuneUniqueId, index, maxSteps) +end + +-- 执行符文循环的辅助函数 +function RuneCalculation:ExecuteRuneLoop(PlayerAI: table, wearingRuneName: table, wearingRuneUniqueId: table, startIndex: number, maxSteps: number, AttributesData: table, BehaviorNameList: table) + local index = startIndex + + while index <= #wearingRuneUniqueId and maxSteps > 0 do + local result = PlayerAI:TriggerRune(wearingRuneName[index], "Check", index, AttributesData, BehaviorNameList) + if result then + local nextIndex = PlayerAI:TriggerRune(wearingRuneName[index], "Execute", index, AttributesData, BehaviorNameList) + + -- 根据返回值决定下一个index + if type(nextIndex) == "number" then + index = nextIndex -- 符文指定了下一个位置 + else + index += 1 -- 默认继续下一个 + end + else + index += 1 + end + maxSteps -= 1 -- 防止无限循环 + end + + -- 触发结束事件,并检查是否有符文要控制流程 + local endNextIndex = PlayerAI:ForEachRune(function(runeName, triggerSlot, rune) + local result = rune:OnEndEvent(runeName, triggerSlot, AttributesData, BehaviorNameList) + if type(result) == "number" then + return result -- 返回要跳转的index + end + end) + + -- 如果结束事件指定了要跳转的位置,重新开始循环 + if type(endNextIndex) == "number" and endNextIndex <= #wearingRuneUniqueId and maxSteps > 0 then + self:ExecuteRuneLoop(PlayerAI, wearingRuneName, wearingRuneUniqueId, endNextIndex, maxSteps, AttributesData, BehaviorNameList) + end +end + + +return RuneCalculation \ No newline at end of file diff --git a/src/ServerStorage/Proxy/RuneProxy.luau b/src/ServerStorage/Proxy/RuneProxy/init.luau similarity index 94% rename from src/ServerStorage/Proxy/RuneProxy.luau rename to src/ServerStorage/Proxy/RuneProxy/init.luau index 3d4096e..003ede8 100644 --- a/src/ServerStorage/Proxy/RuneProxy.luau +++ b/src/ServerStorage/Proxy/RuneProxy/init.luau @@ -9,6 +9,7 @@ local ServerStorage = game:GetService("ServerStorage") local Utils = require(ReplicatedStorage.Tools.Utils) local ArchiveProxy = require(ServerStorage.Proxy.ArchiveProxy) local Rng = require(ReplicatedStorage.Tools.Rng) +local ScriptModule = require(ReplicatedStorage.Tools.ScriptModule) --> Json local JsonRune = require(ReplicatedStorage.Json.Rune) @@ -16,6 +17,10 @@ local JsonRune = require(ReplicatedStorage.Json.Rune) --> Events local RE_PlayerTip = ReplicatedStorage.Events.RE_PlayerTip +--> SubFunctions +local RuneCalculation = require(script.RuneCalculation) +ScriptModule:InjectScriptFunctions(RuneProxy, RuneCalculation) + --> Constants local STORE_NAME = "Rune" @@ -225,7 +230,8 @@ end -- 获取穿戴中的符文 function RuneProxy:GetPlayerWearingRuneData(Player: Player) local wearingRuneUniqueId = {} - local behaviourNames = {} + local wearingRuneName = {} + local wearingRuneBehaviorName = {} -- 穿戴中的填入 local EquipmentProxy = require(ServerStorage.Proxy.EquipmentProxy) local wearingEquipments = EquipmentProxy:GetPlayerWearingEquipmentUniqueId(Player) @@ -233,10 +239,15 @@ function RuneProxy:GetPlayerWearingRuneData(Player: Player) if RuneData.wearing > 0 and table.find(wearingEquipments, RuneData.wearing) then table.insert(wearingRuneUniqueId, RuneData.id) local RuneData = Utils:GetIdDataFromJson(JsonRune, RuneData.orgId) - table.insert(behaviourNames, RuneData.behaviourName) + if RuneData.runeName then + wearingRuneName[RuneData.wearingSlot] = RuneData.runeName + end + if RuneData.behaviorName then + table.insert(wearingRuneBehaviorName, RuneData.behaviorName) + end end end - return wearingRuneUniqueId, behaviourNames + return wearingRuneUniqueId, wearingRuneName end -- 获取对应装备槽位上的技能