更新-主要符文后端内容
This commit is contained in:
parent
4ccf2a6709
commit
924b1dccad
BIN
excel/Rune.xlsx
BIN
excel/Rune.xlsx
Binary file not shown.
Binary file not shown.
31
src/ReplicatedStorage/Tools/ScriptModule.luau
Normal file
31
src/ReplicatedStorage/Tools/ScriptModule.luau
Normal file
@ -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
|
108
src/ServerStorage/Base/Rune.luau
Normal file
108
src/ServerStorage/Base/Rune.luau
Normal file
@ -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
|
71
src/ServerStorage/Modules/Behaviours/IceCoffine.luau
Normal file
71
src/ServerStorage/Modules/Behaviours/IceCoffine.luau
Normal file
@ -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
|
31
src/ServerStorage/Modules/Runes/RuneFireDamage.luau
Normal file
31
src/ServerStorage/Modules/Runes/RuneFireDamage.luau
Normal file
@ -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
|
36
src/ServerStorage/Modules/Runes/RuneIceCoffin.luau
Normal file
36
src/ServerStorage/Modules/Runes/RuneIceCoffin.luau
Normal file
@ -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
|
@ -42,6 +42,12 @@ export type DamageInfo = {
|
|||||||
ElementType: ElementType,
|
ElementType: ElementType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type HealInfo = {
|
||||||
|
Caster: TypeList.Character,
|
||||||
|
Victim: TypeList.Character,
|
||||||
|
Amount: number,
|
||||||
|
}
|
||||||
|
|
||||||
DamageProxy.DamageType = DamageType
|
DamageProxy.DamageType = DamageType
|
||||||
DamageProxy.DamageTag = DamageTag
|
DamageProxy.DamageTag = DamageTag
|
||||||
DamageProxy.ElementType = ElementType
|
DamageProxy.ElementType = ElementType
|
||||||
@ -275,4 +281,58 @@ function DamageProxy:TakeDamage(Caster: TypeList.Character, Victim: TypeList.Cha
|
|||||||
end
|
end
|
||||||
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
|
return DamageProxy
|
@ -10,6 +10,7 @@ local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|||||||
--> Dependencies
|
--> Dependencies
|
||||||
local TypeList = require(ServerStorage.Base.TypeList)
|
local TypeList = require(ServerStorage.Base.TypeList)
|
||||||
local Utils = require(ReplicatedStorage.Tools.Utils)
|
local Utils = require(ReplicatedStorage.Tools.Utils)
|
||||||
|
local ScriptModule = require(ReplicatedStorage.Tools.ScriptModule)
|
||||||
local Communicate = require(ServerStorage.Modules.Tools.Communicate)
|
local Communicate = require(ServerStorage.Modules.Tools.Communicate)
|
||||||
|
|
||||||
--> Events
|
--> Events
|
||||||
@ -21,21 +22,10 @@ local DamageProxy = require(ServerStorage.Proxy.DamageProxy)
|
|||||||
local ActivePlayers = {}
|
local ActivePlayers = {}
|
||||||
|
|
||||||
local Behaviours = {}
|
local Behaviours = {}
|
||||||
local BehaviourFolder = ServerStorage:FindFirstChild("Modules"):FindFirstChild("Behaviours")
|
ScriptModule:InjectFolderModules(Behaviours, ServerStorage:FindFirstChild("Modules"):FindFirstChild("Behaviours"))
|
||||||
if BehaviourFolder then
|
|
||||||
for _, behaviourModule in ipairs(BehaviourFolder:GetChildren()) do
|
local Runes = {}
|
||||||
if behaviourModule:IsA("ModuleScript") then
|
ScriptModule:InjectFolderModules(Runes, ServerStorage:FindFirstChild("Modules"):FindFirstChild("Runes"))
|
||||||
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
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -53,6 +43,8 @@ function PlayerAI.new(Player: Player, PlayerRole: TypeList.Character)
|
|||||||
self.Counter = 0
|
self.Counter = 0
|
||||||
|
|
||||||
self.BehaviourList = {}
|
self.BehaviourList = {}
|
||||||
|
self.RuneList = {}
|
||||||
|
self.SharedData = {} -- 符文和行为之间的共享数据
|
||||||
self.LoopTask = task.spawn(function()
|
self.LoopTask = task.spawn(function()
|
||||||
while task.wait(0.25) do
|
while task.wait(0.25) do
|
||||||
if self.Character.Stats.Died then continue end
|
if self.Character.Stats.Died then continue end
|
||||||
@ -109,11 +101,118 @@ function PlayerAI:AddBehaviour(BehaviourName: string, WearingSlot: number?)
|
|||||||
self.BehaviourList[BehaviourName] = newBehaviour
|
self.BehaviourList[BehaviourName] = newBehaviour
|
||||||
end
|
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
|
-- 获取并记录行为UniqueId
|
||||||
function PlayerAI:GetBehaviourUniqueId()
|
function PlayerAI:GetBehaviourUniqueId()
|
||||||
return Utils:GenUniqueIdPlayerAI(self.LastTime, self.Counter)
|
return Utils:GenUniqueIdPlayerAI(self.LastTime, self.Counter)
|
||||||
end
|
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()
|
function PlayerAI:GetClientBehaviourList()
|
||||||
local clientBehaviourList = {
|
local clientBehaviourList = {
|
||||||
@ -144,6 +243,24 @@ function PlayerAI:RemoveBehaviour(BehaviourName: string)
|
|||||||
end
|
end
|
||||||
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()
|
function PlayerAI:ClearAllBehaviour()
|
||||||
for _, behaviour in self.BehaviourList do behaviour:Destroy() end
|
for _, behaviour in self.BehaviourList do behaviour:Destroy() end
|
||||||
|
@ -192,13 +192,17 @@ function PlayerFightProxy:UpdatePlayerFightData(Player: Player)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- 根据技能添加玩家AI行为
|
-- 根据技能添加玩家AI行为
|
||||||
local abilityIdList, behaviourNameList = AbilityProxy:GetPlayerWearingAbilityData(Player)
|
local abilityIdList, behaviorNameList = AbilityProxy:GetPlayerWearingAbilityData(Player)
|
||||||
local playerAI = PlayerFightProxy:GetPlayerAI(Player)
|
local playerAI = PlayerFightProxy:GetPlayerAI(Player)
|
||||||
|
|
||||||
|
-- 玩家符文影响
|
||||||
|
local RuneProxy = require(ServerStorage.Proxy.RuneProxy)
|
||||||
|
RuneProxy:GetRuneAttributes(Player, playerAI, AttributesData, behaviorNameList)
|
||||||
|
|
||||||
-- TODO:设置AI行为(临时清除所有行为,添加新的玩家行为)
|
-- TODO:设置AI行为(临时清除所有行为,添加新的玩家行为)
|
||||||
playerAI:ClearAllBehaviour()
|
playerAI:ClearAllBehaviour()
|
||||||
for _, behaviourName in behaviourNameList do
|
for _, behaviorName in behaviorNameList do
|
||||||
playerAI:AddBehaviour(behaviourName)
|
playerAI:AddBehaviour(behaviorName)
|
||||||
end
|
end
|
||||||
playerAI:AddBehaviour("Move")
|
playerAI:AddBehaviour("Move")
|
||||||
-- playerAI:AddBehaviour("SwordWave")
|
-- playerAI:AddBehaviour("SwordWave")
|
||||||
|
79
src/ServerStorage/Proxy/RuneProxy/RuneCalculation.luau
Normal file
79
src/ServerStorage/Proxy/RuneProxy/RuneCalculation.luau
Normal file
@ -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
|
@ -9,6 +9,7 @@ local ServerStorage = game:GetService("ServerStorage")
|
|||||||
local Utils = require(ReplicatedStorage.Tools.Utils)
|
local Utils = require(ReplicatedStorage.Tools.Utils)
|
||||||
local ArchiveProxy = require(ServerStorage.Proxy.ArchiveProxy)
|
local ArchiveProxy = require(ServerStorage.Proxy.ArchiveProxy)
|
||||||
local Rng = require(ReplicatedStorage.Tools.Rng)
|
local Rng = require(ReplicatedStorage.Tools.Rng)
|
||||||
|
local ScriptModule = require(ReplicatedStorage.Tools.ScriptModule)
|
||||||
|
|
||||||
--> Json
|
--> Json
|
||||||
local JsonRune = require(ReplicatedStorage.Json.Rune)
|
local JsonRune = require(ReplicatedStorage.Json.Rune)
|
||||||
@ -16,6 +17,10 @@ local JsonRune = require(ReplicatedStorage.Json.Rune)
|
|||||||
--> Events
|
--> Events
|
||||||
local RE_PlayerTip = ReplicatedStorage.Events.RE_PlayerTip
|
local RE_PlayerTip = ReplicatedStorage.Events.RE_PlayerTip
|
||||||
|
|
||||||
|
--> SubFunctions
|
||||||
|
local RuneCalculation = require(script.RuneCalculation)
|
||||||
|
ScriptModule:InjectScriptFunctions(RuneProxy, RuneCalculation)
|
||||||
|
|
||||||
--> Constants
|
--> Constants
|
||||||
local STORE_NAME = "Rune"
|
local STORE_NAME = "Rune"
|
||||||
|
|
||||||
@ -225,7 +230,8 @@ end
|
|||||||
-- 获取穿戴中的符文
|
-- 获取穿戴中的符文
|
||||||
function RuneProxy:GetPlayerWearingRuneData(Player: Player)
|
function RuneProxy:GetPlayerWearingRuneData(Player: Player)
|
||||||
local wearingRuneUniqueId = {}
|
local wearingRuneUniqueId = {}
|
||||||
local behaviourNames = {}
|
local wearingRuneName = {}
|
||||||
|
local wearingRuneBehaviorName = {}
|
||||||
-- 穿戴中的填入
|
-- 穿戴中的填入
|
||||||
local EquipmentProxy = require(ServerStorage.Proxy.EquipmentProxy)
|
local EquipmentProxy = require(ServerStorage.Proxy.EquipmentProxy)
|
||||||
local wearingEquipments = EquipmentProxy:GetPlayerWearingEquipmentUniqueId(Player)
|
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
|
if RuneData.wearing > 0 and table.find(wearingEquipments, RuneData.wearing) then
|
||||||
table.insert(wearingRuneUniqueId, RuneData.id)
|
table.insert(wearingRuneUniqueId, RuneData.id)
|
||||||
local RuneData = Utils:GetIdDataFromJson(JsonRune, RuneData.orgId)
|
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
|
||||||
end
|
end
|
||||||
return wearingRuneUniqueId, behaviourNames
|
return wearingRuneUniqueId, wearingRuneName
|
||||||
end
|
end
|
||||||
|
|
||||||
-- 获取对应装备槽位上的技能
|
-- 获取对应装备槽位上的技能
|
Loading…
x
Reference in New Issue
Block a user