This commit is contained in:
gechangfu 2025-08-21 17:06:13 +08:00
parent e13d346923
commit ed086039a1
29 changed files with 1503 additions and 28 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,7 @@
local ServerSignalEnum = {}
ServerSignalEnum = {
SHOW_ABILITY = "SHOW_ABILITY",
}
return ServerSignalEnum

View File

@ -1,18 +1,18 @@
[ [
{"id":40000,"type":1,"name":40000,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"MCSword","specialType":2,"specialRequire":20001,"specialActive":[14,25],"recycle":100}, {"id":40000,"type":1,"subType":1,"name":40000,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"MCSword","specialType":2,"specialRequire":20001,"specialActive":[14,25],"recycle":100},
{"id":40001,"type":1,"name":40001,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":7,"specialActive":[14,25],"recycle":100}, {"id":40001,"type":1,"subType":2,"name":40001,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":7,"specialActive":[14,25],"recycle":100},
{"id":40002,"type":1,"name":40002,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":8,"specialActive":[14,25],"recycle":100}, {"id":40002,"type":1,"subType":3,"name":40002,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":8,"specialActive":[14,25],"recycle":100},
{"id":40003,"type":1,"name":40003,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":9,"specialActive":[14,25],"recycle":100}, {"id":40003,"type":1,"subType":4,"name":40003,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":9,"specialActive":[14,25],"recycle":100},
{"id":40004,"type":1,"name":40004,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":10,"specialActive":[14,25],"recycle":100}, {"id":40004,"type":1,"subType":1,"name":40004,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":10,"specialActive":[14,25],"recycle":100},
{"id":40005,"type":1,"name":40005,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":11,"specialActive":[14,25],"recycle":100}, {"id":40005,"type":1,"subType":2,"name":40005,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":11,"specialActive":[14,25],"recycle":100},
{"id":40006,"type":1,"name":40006,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":12,"specialActive":[14,25],"recycle":100}, {"id":40006,"type":1,"subType":3,"name":40006,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":12,"specialActive":[14,25],"recycle":100},
{"id":40007,"type":1,"name":40007,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":13,"specialActive":[14,25],"recycle":100}, {"id":40007,"type":1,"subType":4,"name":40007,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":13,"specialActive":[14,25],"recycle":100},
{"id":40008,"type":1,"name":40008,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":6,"specialActive":[14,25],"recycle":100}, {"id":40008,"type":1,"subType":1,"name":40008,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":6,"specialActive":[14,25],"recycle":100},
{"id":40009,"type":1,"name":40009,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":7,"specialActive":[14,25],"recycle":100}, {"id":40009,"type":1,"subType":2,"name":40009,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":7,"specialActive":[14,25],"recycle":100},
{"id":40010,"type":1,"name":40010,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":8,"specialActive":[14,25],"recycle":100}, {"id":40010,"type":1,"subType":3,"name":40010,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":8,"specialActive":[14,25],"recycle":100},
{"id":40011,"type":1,"name":40011,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":9,"specialActive":[14,25],"recycle":100}, {"id":40011,"type":1,"subType":4,"name":40011,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":9,"specialActive":[14,25],"recycle":100},
{"id":40012,"type":1,"name":40012,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":10,"specialActive":[14,25],"recycle":100}, {"id":40012,"type":1,"subType":1,"name":40012,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":10,"specialActive":[14,25],"recycle":100},
{"id":40013,"type":1,"name":40013,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":11,"specialActive":[14,25],"recycle":100}, {"id":40013,"type":1,"subType":2,"name":40013,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":11,"specialActive":[14,25],"recycle":100},
{"id":40014,"type":1,"name":40014,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":12,"specialActive":[14,25],"recycle":100}, {"id":40014,"type":1,"subType":3,"name":40014,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":12,"specialActive":[14,25],"recycle":100},
{"id":40015,"type":1,"name":40015,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":13,"specialActive":[14,25],"recycle":100} {"id":40015,"type":1,"subType":4,"name":40015,"attributes":[14,100,0,15,100,0,16,100,0],"modelName":"Zeus","specialType":1,"specialRequire":13,"specialActive":[14,25],"recycle":100}
] ]

View File

@ -1,5 +1,56 @@
[ [
{"id":60000,"quality":1,"type":1,"icon":1,"nameId":60000,"runeName":"RuneFireDamage","behaviorName":null,"recycle":[],"isInPool":1}, {"id":60000,"quality":1,"type":1,"icon":1,"nameId":60000,"runeName":"RuneFireDamage","behaviorName":null,"recycle":[],"isInPool":1},
{"id":60001,"quality":1,"type":2,"icon":1,"nameId":60001,"runeName":"RuneIceDamage","behaviorName":null,"recycle":[],"isInPool":1},
{"id":60002,"quality":1,"type":3,"icon":1,"nameId":60002,"runeName":"RuneLightDamage","behaviorName":null,"recycle":[],"isInPool":1},
{"id":60003,"quality":1,"type":4,"icon":1,"nameId":60003,"runeName":"RuneShadowDamage","behaviorName":null,"recycle":[],"isInPool":1},
{"id":60004,"quality":1,"type":null,"icon":1,"nameId":60004,"runeName":"RuneBookQualityPurple","behaviorName":null,"recycle":[],"isInPool":1},
{"id":60005,"quality":1,"type":null,"icon":1,"nameId":60005,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60006,"quality":1,"type":null,"icon":1,"nameId":60006,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60007,"quality":1,"type":null,"icon":1,"nameId":60007,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60008,"quality":1,"type":null,"icon":1,"nameId":60008,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60009,"quality":1,"type":null,"icon":1,"nameId":60009,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60010,"quality":1,"type":null,"icon":1,"nameId":60010,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60011,"quality":1,"type":null,"icon":1,"nameId":60011,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60012,"quality":1,"type":null,"icon":1,"nameId":60012,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60013,"quality":1,"type":null,"icon":1,"nameId":60013,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60014,"quality":1,"type":null,"icon":1,"nameId":60014,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60015,"quality":1,"type":null,"icon":1,"nameId":60015,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60016,"quality":1,"type":null,"icon":1,"nameId":60016,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60017,"quality":1,"type":null,"icon":1,"nameId":60017,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60018,"quality":1,"type":null,"icon":1,"nameId":60018,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60019,"quality":1,"type":null,"icon":1,"nameId":60019,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60020,"quality":1,"type":null,"icon":1,"nameId":60020,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60021,"quality":1,"type":null,"icon":1,"nameId":60021,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60022,"quality":1,"type":null,"icon":1,"nameId":60022,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60023,"quality":1,"type":null,"icon":1,"nameId":60023,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":60024,"quality":1,"type":null,"icon":1,"nameId":60024,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61000,"quality":2,"type":1,"icon":1,"nameId":61000,"runeName":"RuneIceCoffin","behaviorName":"IceCoffine","recycle":[],"isInPool":1}, {"id":61000,"quality":2,"type":1,"icon":1,"nameId":61000,"runeName":"RuneIceCoffin","behaviorName":"IceCoffine","recycle":[],"isInPool":1},
{"id":61001,"quality":2,"type":null,"icon":1,"nameId":61001,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61002,"quality":2,"type":null,"icon":1,"nameId":61002,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61003,"quality":2,"type":null,"icon":1,"nameId":61003,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61004,"quality":2,"type":null,"icon":1,"nameId":61004,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61005,"quality":2,"type":null,"icon":1,"nameId":61005,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61006,"quality":2,"type":null,"icon":1,"nameId":61006,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61007,"quality":2,"type":null,"icon":1,"nameId":61007,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61008,"quality":2,"type":null,"icon":1,"nameId":61008,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61009,"quality":2,"type":null,"icon":1,"nameId":61009,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61010,"quality":2,"type":null,"icon":1,"nameId":61010,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61011,"quality":2,"type":null,"icon":1,"nameId":61011,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61012,"quality":2,"type":null,"icon":1,"nameId":61012,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61013,"quality":2,"type":null,"icon":1,"nameId":61013,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61014,"quality":2,"type":null,"icon":1,"nameId":61014,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61015,"quality":2,"type":null,"icon":1,"nameId":61015,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61016,"quality":2,"type":null,"icon":1,"nameId":61016,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61017,"quality":2,"type":null,"icon":1,"nameId":61017,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61018,"quality":2,"type":null,"icon":1,"nameId":61018,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61019,"quality":2,"type":null,"icon":1,"nameId":61019,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61020,"quality":2,"type":null,"icon":1,"nameId":61020,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61021,"quality":2,"type":null,"icon":1,"nameId":61021,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61022,"quality":2,"type":null,"icon":1,"nameId":61022,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61023,"quality":2,"type":null,"icon":1,"nameId":61023,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61024,"quality":2,"type":null,"icon":1,"nameId":61024,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61025,"quality":2,"type":null,"icon":1,"nameId":61025,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61026,"quality":2,"type":null,"icon":1,"nameId":61026,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":61027,"quality":2,"type":null,"icon":1,"nameId":61027,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1},
{"id":62000,"quality":3,"type":1,"icon":1,"nameId":62000,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1} {"id":62000,"quality":3,"type":1,"icon":1,"nameId":62000,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1}
] ]

View File

@ -0,0 +1,184 @@
--[[
EventFilter System - 自动回收版本
结合Signal和Filter实现事件数据过滤系统
支持事件触发时的数据修改和回调处理
自动回收机制,无需手动管理生命周期
]]
local Signal = require(script.Parent.Signal)
local Filter = require(script.Parent.Filter)
-- 事件Filter处理器类型
export type EventFilterHandler = {
handlerFunction: (eventData: any) -> any,
priority: number,
id: string,
eventName: string
}
-- EventFilter系统类
local EventFilter = {}
EventFilter.__index = EventFilter
EventFilter.ClassName = "EventFilter"
export type EventFilter = typeof(EventFilter)
-- 全局EventFilter实例使用弱表自动回收
local GlobalEventFilters = setmetatable({}, {__mode = "k"})
function EventFilter.new(name: string?): EventFilter
local eventFilter = setmetatable({
Name = name or "GlobalEventFilter",
_signals = {}, -- 存储事件信号
_filters = {}, -- 存储每个事件的Filter
_nextHandlerId = 1,
_weakRefs = setmetatable({}, {__mode = "k"}) -- 弱引用表
}, EventFilter)
if name then
GlobalEventFilters[eventFilter] = true
end
return eventFilter
end
-- 注册事件创建Signal和对应的Filter
function EventFilter:RegisterEvent(eventName: string): Signal
if not self._signals[eventName] then
self._signals[eventName] = Signal.new(eventName)
self._filters[eventName] = Filter.new(eventName .. "_Filter")
end
return self._signals[eventName]
end
-- 订阅事件Filter自动回收版本
function EventFilter:SubscribeFilter(eventName: string, filterFunction: (eventData: any) -> any, priority: number?, owner: any?): string
-- 确保事件已注册
self:RegisterEvent(eventName)
local handlerId = tostring(self._nextHandlerId)
self._nextHandlerId = self._nextHandlerId + 1
-- 添加到Filter带所有者引用
local filterId = self._filters[eventName]:AddHandler(filterFunction, priority, owner)
-- 如果提供了所有者,创建弱引用
if owner then
self._weakRefs[owner] = {eventName = eventName, handlerId = handlerId}
end
return handlerId
end
-- 取消订阅事件Filter
function EventFilter:UnsubscribeFilter(eventName: string, handlerId: string): boolean
if self._filters[eventName] then
return self._filters[eventName]:RemoveHandler(handlerId)
end
return false
end
-- 清理无效的处理器(自动回收)
function EventFilter:CleanupFilters()
for eventName, filter in pairs(self._filters) do
filter:CleanupHandlers()
end
end
-- 发送事件带Filter处理自动清理
function EventFilter:FireWithFilter(eventName: string, eventData: any, callback: (processedData: any) -> ())
-- 确保事件已注册
self:RegisterEvent(eventName)
-- 自动清理无效处理器
self:CleanupFilters()
-- 通过Filter处理数据
self._filters[eventName]:ProcessDataWithCallback(eventData, function(processedData)
-- 触发Signal事件
self._signals[eventName]:Fire(processedData)
-- 执行回调
if callback then
callback(processedData)
end
end)
end
-- 发送事件不带Filter直接触发
function EventFilter:Fire(eventName: string, eventData: any)
-- 确保事件已注册
self:RegisterEvent(eventName)
-- 自动清理无效处理器
self:CleanupFilters()
-- 直接触发Signal事件
self._signals[eventName]:Fire(eventData)
end
-- 订阅事件(监听处理后的数据)
function EventFilter:Subscribe(eventName: string, callback: (processedData: any) -> ()): any
-- 确保事件已注册
self:RegisterEvent(eventName)
-- 订阅Signal事件
return self._signals[eventName]:Connect(callback)
end
-- 获取事件Signal
function EventFilter:GetSignal(eventName: string): Signal?
return self._signals[eventName]
end
-- 获取事件Filter
function EventFilter:GetFilter(eventName: string): Filter?
return self._filters[eventName]
end
-- 获取所有已注册的事件名称
function EventFilter:GetRegisteredEvents(): {string}
local events = {}
for eventName, _ in pairs(self._signals) do
table.insert(events, eventName)
end
return events
end
-- 便捷方法获取全局EventFilter实例
function EventFilter.GetGlobal(): EventFilter
for eventFilter, _ in pairs(GlobalEventFilters) do
if eventFilter.Name == "GlobalEventFilter" then
return eventFilter
end
end
return EventFilter.new("GlobalEventFilter")
end
-- 便捷方法全局订阅Filter带所有者
function EventFilter.SubscribeGlobalFilter(eventName: string, filterFunction: (eventData: any) -> any, priority: number?, owner: any?): string
return EventFilter.GetGlobal():SubscribeFilter(eventName, filterFunction, priority, owner)
end
-- 便捷方法全局取消订阅Filter
function EventFilter.UnsubscribeGlobalFilter(eventName: string, handlerId: string): boolean
return EventFilter.GetGlobal():UnsubscribeFilter(eventName, handlerId)
end
-- 便捷方法全局发送事件带Filter
function EventFilter.FireGlobalWithFilter(eventName: string, eventData: any, callback: (processedData: any) -> ())
EventFilter.GetGlobal():FireWithFilter(eventName, eventData, callback)
end
-- 便捷方法全局发送事件不带Filter
function EventFilter.FireGlobal(eventName: string, eventData: any)
EventFilter.GetGlobal():Fire(eventName, eventData)
end
-- 便捷方法:全局订阅事件
function EventFilter.SubscribeGlobal(eventName: string, callback: (processedData: any) -> ()): any
return EventFilter.GetGlobal():Subscribe(eventName, callback)
end
return EventFilter

View File

@ -0,0 +1,230 @@
--[[
EventFilter使用例子
演示如何使用事件过滤系统
]]
local EventFilter = require(script.Parent.EventFilter)
-- ===== 基础使用示例 =====
-- 1. 创建符文对象(作为所有者)
local function createRunes()
local fireRune = {
name = "火焰符文",
level = 5,
element = "fire"
}
local iceRune = {
name = "冰霜符文",
level = 3,
element = "ice"
}
local criticalRune = {
name = "暴击符文",
level = 4,
criticalChance = 0.3
}
-- 添加Destroy方法用于自动回收
function fireRune:Destroy()
print("销毁火焰符文")
for k, v in pairs(self) do self[k] = nil end
self = nil
end
function iceRune:Destroy()
print("销毁冰霜符文")
for k, v in pairs(self) do self[k] = nil end
self = nil
end
function criticalRune:Destroy()
print("销毁暴击符文")
for k, v in pairs(self) do self[k] = nil end
self = nil
end
return fireRune, iceRune, criticalRune
end
-- 2. 设置符文效果
local function setupRuneEffects(fireRune, iceRune, criticalRune)
-- 火焰符文增加50%伤害
EventFilter.SubscribeGlobalFilter("OnAttack", function(eventData)
print("🔥 火焰符文生效:伤害 +50%")
eventData.damage = eventData.damage * 1.5
eventData.element = "fire"
return eventData
end, 10, fireRune) -- 优先级10所有者是fireRune
-- 冰霜符文增加30%伤害,有概率冰冻
EventFilter.SubscribeGlobalFilter("OnAttack", function(eventData)
print("❄️ 冰霜符文生效:伤害 +30%")
eventData.damage = eventData.damage * 1.3
eventData.element = "ice"
-- 20%概率冰冻
if math.random() < 0.2 then
eventData.freeze = true
print(" 💎 触发冰冻效果!")
end
return eventData
end, 8, iceRune) -- 优先级8所有者是iceRune
-- 暴击符文30%概率暴击
EventFilter.SubscribeGlobalFilter("OnAttack", function(eventData)
if math.random() < 0.3 then
print("⚡ 暴击符文生效:暴击!")
eventData.damage = eventData.damage * 2
eventData.isCritical = true
end
return eventData
end, 5, criticalRune) -- 优先级5所有者是criticalRune
end
-- 3. 监听最终结果
local function setupResultListener()
EventFilter.SubscribeGlobal("OnAttack", function(finalData)
print("=== 最终攻击结果 ===")
print("伤害:", finalData.damage)
print("元素:", finalData.element or "无")
print("暴击:", finalData.isCritical and "是" or "否")
print("冰冻:", finalData.freeze and "是" or "否")
print("==================")
end)
end
-- 4. 发送攻击事件
local function sendAttackEvent()
local attackData = {
damage = 100,
attacker = "玩家",
target = "敌人"
}
print("🗡️ 发送攻击事件,基础伤害:", attackData.damage)
EventFilter.FireGlobalWithFilter("OnAttack", attackData, function(processedData)
print("✅ 攻击事件处理完成!")
-- 这里可以执行实际的攻击逻辑
-- 比如DealDamage(processedData.damage, processedData.target)
end)
end
-- ===== 演示自动回收 =====
local function demonstrateAutoCleanup()
print("\n=== 演示自动回收 ===")
-- 第一次攻击:所有符文生效
print("\n第一次攻击所有符文生效")
sendAttackEvent()
-- 销毁火焰符文
print("\n销毁火焰符文...")
fireRune:Destroy()
-- 第二次攻击:只有冰霜和暴击符文生效
print("\n第二次攻击冰霜+暴击符文生效):")
sendAttackEvent()
-- 销毁冰霜符文
print("\n销毁冰霜符文...")
iceRune:Destroy()
-- 第三次攻击:只有暴击符文生效
print("\n第三次攻击只有暴击符文生效")
sendAttackEvent()
-- 销毁暴击符文
print("\n销毁暴击符文...")
criticalRune:Destroy()
-- 第四次攻击:没有符文生效
print("\n第四次攻击没有符文生效")
sendAttackEvent()
end
-- ===== 实际游戏场景示例 =====
local function gameSceneExample()
print("\n=== 实际游戏场景示例 ===")
-- 模拟玩家攻击
local function playerAttack()
local attackData = {
damage = 80,
attackType = "melee",
attacker = game.Players.LocalPlayer,
target = nil, -- 目标敌人
weaponType = "sword"
}
print("玩家发起攻击...")
-- 发送攻击事件,让符文系统处理
EventFilter.FireGlobalWithFilter("OnAttack", attackData, function(finalData)
print("执行攻击:", finalData.damage, "点伤害")
-- 应用元素效果
if finalData.element == "fire" then
print("🔥 造成燃烧效果")
elseif finalData.element == "ice" then
print("❄️ 造成冰冻效果")
end
-- 应用暴击效果
if finalData.isCritical then
print("⚡ 暴击!")
end
-- 应用冰冻效果
if finalData.freeze then
print("💎 目标被冰冻!")
end
end)
end
-- 执行攻击
playerAttack()
end
-- ===== 主函数:完整演示 =====
local function runCompleteExample()
print("=== EventFilter使用示例 ===")
-- 1. 创建符文
local fireRune, iceRune, criticalRune = createRunes()
print("创建了三个符文")
-- 2. 设置符文效果
setupRuneEffects(fireRune, iceRune, criticalRune)
print("设置了符文效果")
-- 3. 设置结果监听
setupResultListener()
print("设置了结果监听")
-- 4. 演示自动回收
demonstrateAutoCleanup()
-- 5. 实际游戏场景
gameSceneExample()
print("\n=== 示例完成 ===")
end
-- ===== 导出函数 =====
return {
runCompleteExample = runCompleteExample,
createRunes = createRunes,
setupRuneEffects = setupRuneEffects,
sendAttackEvent = sendAttackEvent,
demonstrateAutoCleanup = demonstrateAutoCleanup,
gameSceneExample = gameSceneExample
}

View File

@ -0,0 +1,86 @@
--[[
EventFilter快速入门指南
最简单的使用方式
]]
local EventFilter = require(script.Parent.EventFilter)
-- ===== 最简单的使用方式 =====
-- 1. 创建符文对象
local myRune = {
name = "我的符文",
level = 1
}
-- 2. 添加Destroy方法用于自动回收
function myRune:Destroy()
print("销毁符文:", self.name)
for k, v in pairs(self) do self[k] = nil end
self = nil
end
-- 3. 让符文订阅事件
EventFilter.SubscribeGlobalFilter("OnAttack", function(eventData)
print("符文生效:伤害 +50%")
eventData.damage = eventData.damage * 1.5
return eventData
end, 10, myRune) -- 事件名, 处理函数, 优先级, 所有者
-- 4. 发送事件
local attackData = {damage = 100}
EventFilter.FireGlobalWithFilter("OnAttack", attackData, function(processedData)
print("最终伤害:", processedData.damage) -- 输出150
end)
-- 5. 销毁符文(自动回收)
myRune:Destroy() -- Filter自动失效不需要手动取消订阅
-- ===== 实际游戏中的使用 =====
-- 在攻击脚本中:
local function playerAttack()
local attackData = {
damage = 100,
attackType = "melee",
target = enemy
}
-- 发送攻击事件,让符文系统处理
EventFilter.FireGlobalWithFilter("OnAttack", attackData, function(finalData)
-- 使用处理后的数据执行实际攻击
DealDamage(finalData.damage, finalData.target)
end)
end
-- 在符文脚本中:
local function setupRune(runeInstance)
-- 符文订阅攻击事件
EventFilter.SubscribeGlobalFilter("OnAttack", function(data)
-- 符文效果:增加伤害
data.damage = data.damage * 1.2
return data
end, 5, runeInstance)
end
-- ===== 常用事件类型 =====
-- "OnAttack" - 攻击事件
-- "OnMove" - 移动事件
-- "OnSkill" - 技能事件
-- "OnDamage" - 受伤事件
-- "OnHeal" - 治疗事件
-- ===== 优先级说明 =====
-- 数字越大,优先级越高,越先执行
-- 10: 最高优先级(比如基础属性修改)
-- 5: 中等优先级(比如元素转换)
-- 1: 最低优先级(比如暴击判定)
-- ===== 自动回收的好处 =====
-- 1. 不需要手动管理符文销毁时Filter自动失效
-- 2. 内存安全:不会造成内存泄露
-- 3. 代码简洁:不需要写清理代码
return {
-- 这里可以添加一些辅助函数
}

View File

@ -0,0 +1,178 @@
--[[
Filter System - 自动回收版本
用于实现事件数据的过滤和处理功能
支持多个Filter的链式处理、优先级排序和数据回调
自动回收机制,无需手动管理生命周期
]]
-- Filter处理器类型
export type FilterHandler = {
handlerFunction: (data: any) -> any,
priority: number,
id: string,
weakRef: any -- 弱引用,用于自动回收
}
-- Filter系统类
local Filter = {}
Filter.__index = Filter
Filter.ClassName = "Filter"
export type Filter = typeof(Filter)
-- 全局Filter实例使用弱表自动回收
local GlobalFilters = setmetatable({}, {__mode = "k"})
function Filter.new(name: string?): Filter
local filter = setmetatable({
Name = name or "GlobalFilter",
_handlers = {}, -- 存储所有Filter处理器
_nextHandlerId = 1,
_weakRefs = setmetatable({}, {__mode = "k"}) -- 弱引用表
}, Filter)
if name then
GlobalFilters[filter] = true
end
return filter
end
-- 添加Filter处理器自动回收版本
function Filter:AddHandler(handlerFunction: (data: any) -> any, priority: number?, owner: any?): string
local handlerId = tostring(self._nextHandlerId)
self._nextHandlerId = self._nextHandlerId + 1
local handler: FilterHandler = {
handlerFunction = handlerFunction,
priority = priority or 0,
id = handlerId,
weakRef = owner -- 存储所有者引用
}
table.insert(self._handlers, handler)
-- 如果提供了所有者,创建弱引用
if owner then
self._weakRefs[owner] = handlerId
end
-- 按优先级排序(优先级高的先执行)
table.sort(self._handlers, function(a, b)
return a.priority > b.priority
end)
return handlerId
end
-- 移除Filter处理器
function Filter:RemoveHandler(handlerId: string): boolean
for i, handler in ipairs(self._handlers) do
if handler.id == handlerId then
table.remove(self._handlers, i)
return true
end
end
return false
end
-- 清理无效的处理器(自动回收)
function Filter:CleanupHandlers()
local validHandlers = {}
for _, handler in ipairs(self._handlers) do
local isValid = true
if handler.weakRef then
-- 检查Instance类型
if typeof(handler.weakRef) == "Instance" then
-- Instance被销毁时Parent为nil
if handler.weakRef.Parent == nil then
isValid = false
end
else
-- 对于table类型如Rune类检查是否有Destroy方法且是否已被销毁
if type(handler.weakRef) == "table" then
-- 检查是否还在弱引用表中(如果不在,说明已被垃圾回收)
if not self._weakRefs[handler.weakRef] then
isValid = false
end
end
end
end
if isValid then
table.insert(validHandlers, handler)
end
end
self._handlers = validHandlers
end
-- 处理数据链式Filter自动清理
function Filter:ProcessData(data: any): any
-- 自动清理无效处理器
self:CleanupHandlers()
local processedData = data
for _, handler in ipairs(self._handlers) do
local success, result = pcall(handler.handlerFunction, processedData)
if success and result ~= nil then
processedData = result
end
end
return processedData
end
-- 带回调的数据处理(用于事件系统)
function Filter:ProcessDataWithCallback(data: any, callback: (processedData: any) -> ())
local processedData = self:ProcessData(data)
callback(processedData)
end
-- 获取处理器数量
function Filter:GetHandlerCount(): number
self:CleanupHandlers()
return #self._handlers
end
-- 获取所有处理器信息
function Filter:GetHandlers(): {FilterHandler}
self:CleanupHandlers()
return self._handlers
end
-- 便捷方法创建全局Filter实例
function Filter.GetGlobal(): Filter
for filter, _ in pairs(GlobalFilters) do
if filter.Name == "GlobalFilter" then
return filter
end
end
return Filter.new("GlobalFilter")
end
-- 便捷方法:快速添加处理器(带所有者)
function Filter.AddGlobalHandler(handlerFunction: (data: any) -> any, priority: number?, owner: any?): string
return Filter.GetGlobal():AddHandler(handlerFunction, priority, owner)
end
-- 便捷方法:快速移除处理器
function Filter.RemoveGlobalHandler(handlerId: string): boolean
return Filter.GetGlobal():RemoveHandler(handlerId)
end
-- 便捷方法:快速处理数据
function Filter.ProcessGlobalData(data: any): any
return Filter.GetGlobal():ProcessData(data)
end
-- 便捷方法:快速处理数据带回调
function Filter.ProcessGlobalDataWithCallback(data: any, callback: (processedData: any) -> ())
Filter.GetGlobal():ProcessDataWithCallback(data, callback)
end
return Filter

View File

@ -154,6 +154,12 @@ function Random:GetRandomInt(min: number, max: number)
return math.random(min, max) return math.random(min, max)
end end
-- 百分比概率随机
function Random:RandomPercent(percent: number)
-- 随机1-100如果随机值小于等于百分比则返回true否则返回false
local randomValue = self:GetRandomInt(1, 100)
return randomValue <= percent
end
-- 初始化随机种子 -- 初始化随机种子

View File

@ -10,6 +10,7 @@ local Behaviour = require(ServerStorage.Base.Behaviour)
local MobsProxy = require(ServerStorage.Proxy.MobsProxy) local MobsProxy = require(ServerStorage.Proxy.MobsProxy)
local DamageProxy = require(ServerStorage.Proxy.DamageProxy) local DamageProxy = require(ServerStorage.Proxy.DamageProxy)
local Utils = require(ReplicatedStorage.Tools.Utils) local Utils = require(ReplicatedStorage.Tools.Utils)
local Rng = require(ReplicatedStorage.Tools.Rng)
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -20,11 +21,11 @@ setmetatable(Attack, {__index = Behaviour})
local CAST_DISTANCE = 8 local CAST_DISTANCE = 8
local COOLDOWN = 1 local COOLDOWN = 1
local ATTRIBUTE_LIST = { local ATTRIBUTE_LIST = {
{Name = "attack", ElementType = DamageProxy.ElementType.NONE}, {Name = "attack", ElementType = DamageProxy.ElementType.NONE, CritCheckRateName = "critRate", CritDamageRateName = "critDamageRate"},
{Name = "fireAtk", ElementType = DamageProxy.ElementType.FIRE}, {Name = "fireAtk", ElementType = DamageProxy.ElementType.FIRE, CritCheckRateName = "critRateFire", CritDamageRateName = "critDamageRateFire"},
{Name = "iceAtk", ElementType = DamageProxy.ElementType.ICE}, {Name = "iceAtk", ElementType = DamageProxy.ElementType.ICE, CritCheckRateName = "critRateIce", CritDamageRateName = "critDamageRateIce"},
{Name = "lightAtk", ElementType = DamageProxy.ElementType.LIGHT}, {Name = "lightAtk", ElementType = DamageProxy.ElementType.LIGHT, CritCheckRateName = "critRateLight", CritDamageRateName = "critDamageRateLight"},
{Name = "shadowAtk", ElementType = DamageProxy.ElementType.SHADOW}, {Name = "shadowAtk", ElementType = DamageProxy.ElementType.SHADOW, CritCheckRateName = "critRateShadow", CritDamageRateName = "critDamageRateShadow"},
} }
@ -96,16 +97,27 @@ function Attack:Execute()
-- 攻击前摇 -- 攻击前摇
task.wait(atkSpeed) task.wait(atkSpeed)
-- TODO: 之后这里可以提前做暴击判定
-- 伤害逻辑计算部分 -- 伤害逻辑计算部分
local damageData = {} local damageData = {}
for _, attribute in ATTRIBUTE_LIST do for _, attribute in ATTRIBUTE_LIST do
local attributeValue = self:GetAttributeValue(attribute.Name) local attributeValue = self:GetAttributeValue(attribute.Name)
if attributeValue then if attributeValue then
-- 暴击判定
local DamageType = DamageProxy.DamageType.NORMAL
local critCheckRate = self:GetAttributeValue(attribute.CritCheckRateName) or 0
local critDamageRate = self:GetAttributeValue(attribute.CritDamageRateName) or 0
if critCheckRate then
if Rng:RandomPercent(critCheckRate) then
attributeValue = attributeValue * (1 + (200 + critDamageRate) / 100)
DamageType = DamageProxy.DamageType.CRIT
end
end
-- 记录伤害数据
table.insert(damageData, { table.insert(damageData, {
Damage = attributeValue, Damage = attributeValue,
Type = DamageProxy.DamageType.NORMAL, Type = DamageType,
Tag = DamageProxy.DamageTag.NORMAL, Tag = DamageProxy.DamageTag.NORMAL,
ElementType = attribute.ElementType, ElementType = attribute.ElementType,
}) })

View File

@ -0,0 +1,51 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneBookQualityPurple = {}
RuneBookQualityPurple.__index = RuneBookQualityPurple
setmetatable(RuneBookQualityPurple, {__index = Rune})
function RuneBookQualityPurple:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneBookQualityPurple)
return self
end
function RuneBookQualityPurple:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneBookQualityPurple:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local pDataFolder = ReplicatedStorage:FindFirstChild("PlayerData")
if not pDataFolder then return nil end
local pData = pDataFolder:FindFirstChild(self.PlayerAI.Player.UserId)
if not pData then return nil end
local bookFolder = pData:FindFirstChild("Book")
if not bookFolder then return nil end
local bookList = bookFolder:GetChildren()
if #bookList == 0 then return nil end
local qualityNumber = 0
for _, book in bookList do
local bookQuality = book:GetAttribute("quality")
if bookQuality >= 3 then
qualityNumber = qualityNumber + 1
end
end
local attackRate = math.floor(qualityNumber * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil
end
return RuneBookQualityPurple

View File

@ -0,0 +1,34 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneCritDamageRateFire = {}
RuneCritDamageRateFire.__index = RuneCritDamageRateFire
setmetatable(RuneCritDamageRateFire, {__index = Rune})
function RuneCritDamageRateFire:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneCritDamageRateFire)
return self
end
function RuneCritDamageRateFire:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneCritDamageRateFire:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local nowAttribute = AttributesData.critDamageRateFire or 200
local addAttribute = math.floor(nowAttribute * 50 / 100)
Utils:TableSafeAddValue(AttributesData, "critDamageRateFire", addAttribute)
return nil
end
return RuneCritDamageRateFire

View File

@ -0,0 +1,34 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneCritDamageRateIce = {}
RuneCritDamageRateIce.__index = RuneCritDamageRateIce
setmetatable(RuneCritDamageRateIce, {__index = Rune})
function RuneCritDamageRateIce:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneCritDamageRateIce)
return self
end
function RuneCritDamageRateIce:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneCritDamageRateIce:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local nowAttribute = AttributesData.critDamageRateIce or 200
local addAttribute = math.floor(nowAttribute * 50 / 100)
Utils:TableSafeAddValue(AttributesData, "critDamageRateIce", addAttribute)
return nil
end
return RuneCritDamageRateIce

View File

@ -0,0 +1,34 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneCritDamageRateLight = {}
RuneCritDamageRateLight.__index = RuneCritDamageRateLight
setmetatable(RuneCritDamageRateLight, {__index = Rune})
function RuneCritDamageRateLight:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneCritDamageRateLight)
return self
end
function RuneCritDamageRateLight:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneCritDamageRateLight:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local nowAttribute = AttributesData.critDamageRateLight or 200
local addAttribute = math.floor(nowAttribute * 50 / 100)
Utils:TableSafeAddValue(AttributesData, "critDamageRateLight", addAttribute)
return nil
end
return RuneCritDamageRateLight

View File

@ -0,0 +1,34 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneCritDamageRateShadow = {}
RuneCritDamageRateShadow.__index = RuneCritDamageRateShadow
setmetatable(RuneCritDamageRateShadow, {__index = Rune})
function RuneCritDamageRateShadow:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneCritDamageRateShadow)
return self
end
function RuneCritDamageRateShadow:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneCritDamageRateShadow:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local nowAttribute = AttributesData.critDamageRateShadow or 200
local addAttribute = math.floor(nowAttribute * 50 / 100)
Utils:TableSafeAddValue(AttributesData, "critDamageRateShadow", addAttribute)
return nil
end
return RuneCritDamageRateShadow

View File

@ -24,8 +24,9 @@ function RuneFireDamage:Check(index: number, AttributesData: table, BehaviorName
end end
function RuneFireDamage:OnExecute(index: number, AttributesData: table, BehaviorNameList: table) function RuneFireDamage:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
print("RuneFireDamage:OnExecute", index, AttributesData, BehaviorNameList) local baseAttribute = AttributesData.fireAtk or 100
Utils:TableSafeAddValue(AttributesData, "fireAtk", 100) local addAttribute = math.floor(baseAttribute * 50 / 100)
Utils:TableSafeAddValue(AttributesData, "fireAtk", addAttribute)
return nil return nil
end end

View File

@ -24,7 +24,6 @@ function RuneIceCoffin:Check(index: number, AttributesData: table, BehaviorNameL
end end
function RuneIceCoffin:OnExecute(index: number, AttributesData: table, BehaviorNameList: table) function RuneIceCoffin:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
print("RuneIceCoffin:OnExecute", index, AttributesData, BehaviorNameList)
local maxRecover = self.PlayerAI:GetSharedData("IceCoffin_MaxRecover") local maxRecover = self.PlayerAI:GetSharedData("IceCoffin_MaxRecover")
if maxRecover then if maxRecover then
self.PlayerAI:SetSharedData("IceCoffin_MaxRecover", maxRecover + 60) self.PlayerAI:SetSharedData("IceCoffin_MaxRecover", maxRecover + 60)

View File

@ -0,0 +1,34 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneIceDamage = {}
RuneIceDamage.__index = RuneIceDamage
setmetatable(RuneIceDamage, {__index = Rune})
function RuneIceDamage:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneIceDamage)
return self
end
function RuneIceDamage:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneIceDamage:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local baseAttribute = AttributesData.iceAtk or 100
local addAttribute = math.floor(baseAttribute * 50 / 100)
Utils:TableSafeAddValue(AttributesData, "iceAtk", addAttribute)
return nil
end
return RuneIceDamage

View File

@ -0,0 +1,34 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneLightDamage = {}
RuneLightDamage.__index = RuneLightDamage
setmetatable(RuneLightDamage, {__index = Rune})
function RuneLightDamage:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneLightDamage)
return self
end
function RuneLightDamage:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneLightDamage:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local baseAttribute = AttributesData.lightAtk or 100
local addAttribute = math.floor(baseAttribute * 50 / 100)
Utils:TableSafeAddValue(AttributesData, "lightAtk", addAttribute)
return nil
end
return RuneLightDamage

View File

@ -0,0 +1,34 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneShadowDamage = {}
RuneShadowDamage.__index = RuneShadowDamage
setmetatable(RuneShadowDamage, {__index = Rune})
function RuneShadowDamage:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneShadowDamage)
return self
end
function RuneShadowDamage:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneShadowDamage:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local baseAttribute = AttributesData.shadowAtk or 100
local addAttribute = math.floor(baseAttribute * 50 / 100)
Utils:TableSafeAddValue(AttributesData, "shadowAtk", addAttribute)
return nil
end
return RuneShadowDamage

View File

@ -0,0 +1,52 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneWearElementAttack = {}
RuneWearElementAttack.__index = RuneWearElementAttack
setmetatable(RuneWearElementAttack, {__index = Rune})
function RuneWearElementAttack:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneWearElementAttack)
return self
end
function RuneWearElementAttack:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneWearElementAttack:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local pDataFolder = ReplicatedStorage:FindFirstChild("PlayerData")
if not pDataFolder then return nil end
local pData = pDataFolder:FindFirstChild(self.PlayerAI.Player.UserId)
if not pData then return nil end
local equipmentFolder = pData:FindFirstChild("Equipment")
if not equipmentFolder then return nil end
local equipmentList = equipmentFolder:GetChildren()
if #equipmentList == 0 then return nil end
local elementNumber = 0
for _, equipment in equipmentList do
local equipmentWearing = equipment:GetAttribute("wearing")
if equipmentWearing > 0 then
elementNumber = elementNumber + #equipment:FindFirstChild("Element"):GetAttributes()
end
end
local attackRate = math.floor(elementNumber * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil
end
return RuneWearElementAttack

View File

@ -0,0 +1,70 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneWearEmptySlot = {}
RuneWearEmptySlot.__index = RuneWearEmptySlot
setmetatable(RuneWearEmptySlot, {__index = Rune})
function RuneWearEmptySlot:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneWearEmptySlot)
return self
end
function RuneWearEmptySlot:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneWearEmptySlot:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local pDataFolder = ReplicatedStorage:FindFirstChild("PlayerData")
if not pDataFolder then return nil end
local pData = pDataFolder:FindFirstChild(self.PlayerAI.Player.UserId)
if not pData then return nil end
local equipmentFolder = pData:FindFirstChild("Equipment")
if not equipmentFolder then return nil end
local equipmentList = equipmentFolder:GetChildren()
if #equipmentList == 0 then return nil end
local runeFolder = pData:FindFirstChild("Rune")
if not runeFolder then return nil end
local runeList = runeFolder:GetChildren()
if #runeList == 0 then return nil end
local maxRuneNumber = 0
local hasSlotNumber = 0
local wearWeaponList = {}
for _, equipment in equipmentList do
local equipmentWearing = equipment:GetAttribute("wearing")
if equipmentWearing > 0 then
maxRuneNumber = maxRuneNumber + 1
table.insert(wearWeaponList, equipment.Name)
end
end
for _, rune in runeList do
local runeWearing = rune:GetAttribute("wearing")
if runeWearing then
if table.find(wearWeaponList, tostring(runeWearing)) then
hasSlotNumber = hasSlotNumber + 1
end
end
end
local attackRate = math.floor((maxRuneNumber - hasSlotNumber) * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil
end
return RuneWearEmptySlot

View File

@ -0,0 +1,70 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneWearFillSlot = {}
RuneWearFillSlot.__index = RuneWearFillSlot
setmetatable(RuneWearFillSlot, {__index = Rune})
function RuneWearFillSlot:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneWearFillSlot)
return self
end
function RuneWearFillSlot:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneWearFillSlot:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local pDataFolder = ReplicatedStorage:FindFirstChild("PlayerData")
if not pDataFolder then return nil end
local pData = pDataFolder:FindFirstChild(self.PlayerAI.Player.UserId)
if not pData then return nil end
local equipmentFolder = pData:FindFirstChild("Equipment")
if not equipmentFolder then return nil end
local equipmentList = equipmentFolder:GetChildren()
if #equipmentList == 0 then return nil end
local runeFolder = pData:FindFirstChild("Rune")
if not runeFolder then return nil end
local runeList = runeFolder:GetChildren()
if #runeList == 0 then return nil end
local maxRuneNumber = 0
local hasSlotNumber = 0
local wearWeaponList = {}
for _, equipment in equipmentList do
local equipmentWearing = equipment:GetAttribute("wearing")
if equipmentWearing > 0 then
maxRuneNumber = maxRuneNumber + 1
table.insert(wearWeaponList, equipment.Name)
end
end
for _, rune in runeList do
local runeWearing = rune:GetAttribute("wearing")
if runeWearing then
if table.find(wearWeaponList, tostring(runeWearing)) then
hasSlotNumber = hasSlotNumber + 1
end
end
end
local attackRate = math.floor(hasSlotNumber * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil
end
return RuneWearFillSlot

View File

@ -0,0 +1,60 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneWearHeavySword = {}
RuneWearHeavySword.__index = RuneWearHeavySword
setmetatable(RuneWearHeavySword, {__index = Rune})
function RuneWearHeavySword:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneWearHeavySword)
return self
end
function RuneWearHeavySword:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneWearHeavySword:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local pDataFolder = ReplicatedStorage:FindFirstChild("PlayerData")
if not pDataFolder then return nil end
local pData = pDataFolder:FindFirstChild(self.PlayerAI.Player.UserId)
if not pData then return nil end
local equipmentFolder = pData:FindFirstChild("Equipment")
if not equipmentFolder then return nil end
local equipmentList = equipmentFolder:GetChildren()
if #equipmentList == 0 then return nil end
local CheckSubType = 4
local subTypeNumber = 0
for _, equipment in equipmentList do
local equipmentSubType = equipment:GetAttribute("subType")
local equipmentWearing = equipment:GetAttribute("wearing")
if equipmentSubType == CheckSubType and equipmentWearing > 0 then
subTypeNumber = subTypeNumber + 1
end
end
local CheckShareName = "RuneTagHeavySword"
if self.PlayerAI:GetSharedData(CheckShareName) then
subTypeNumber = subTypeNumber + self.PlayerAI:GetSharedData(CheckShareName)
end
local attackRate = math.floor(subTypeNumber * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil
end
return RuneWearHeavySword

View File

@ -0,0 +1,60 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneWearKnife = {}
RuneWearKnife.__index = RuneWearKnife
setmetatable(RuneWearKnife, {__index = Rune})
function RuneWearKnife:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneWearKnife)
return self
end
function RuneWearKnife:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneWearKnife:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local pDataFolder = ReplicatedStorage:FindFirstChild("PlayerData")
if not pDataFolder then return nil end
local pData = pDataFolder:FindFirstChild(self.PlayerAI.Player.UserId)
if not pData then return nil end
local equipmentFolder = pData:FindFirstChild("Equipment")
if not equipmentFolder then return nil end
local equipmentList = equipmentFolder:GetChildren()
if #equipmentList == 0 then return nil end
local CheckSubType = 1
local subTypeNumber = 0
for _, equipment in equipmentList do
local equipmentSubType = equipment:GetAttribute("subType")
local equipmentWearing = equipment:GetAttribute("wearing")
if equipmentSubType == CheckSubType and equipmentWearing > 0 then
subTypeNumber = subTypeNumber + 1
end
end
local CheckShareName = "RuneTagKnife"
if self.PlayerAI:GetSharedData(CheckShareName) then
subTypeNumber = subTypeNumber + self.PlayerAI:GetSharedData(CheckShareName)
end
local attackRate = math.floor(subTypeNumber * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil
end
return RuneWearKnife

View File

@ -0,0 +1,60 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneWearStick = {}
RuneWearStick.__index = RuneWearStick
setmetatable(RuneWearStick, {__index = Rune})
function RuneWearStick:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneWearStick)
return self
end
function RuneWearStick:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneWearStick:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local pDataFolder = ReplicatedStorage:FindFirstChild("PlayerData")
if not pDataFolder then return nil end
local pData = pDataFolder:FindFirstChild(self.PlayerAI.Player.UserId)
if not pData then return nil end
local equipmentFolder = pData:FindFirstChild("Equipment")
if not equipmentFolder then return nil end
local equipmentList = equipmentFolder:GetChildren()
if #equipmentList == 0 then return nil end
local CheckSubType = 3
local subTypeNumber = 0
for _, equipment in equipmentList do
local equipmentSubType = equipment:GetAttribute("subType")
local equipmentWearing = equipment:GetAttribute("wearing")
if equipmentSubType == CheckSubType and equipmentWearing > 0 then
subTypeNumber = subTypeNumber + 1
end
end
local CheckShareName = "RuneTagStick"
if self.PlayerAI:GetSharedData(CheckShareName) then
subTypeNumber = subTypeNumber + self.PlayerAI:GetSharedData(CheckShareName)
end
local attackRate = math.floor(subTypeNumber * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil
end
return RuneWearStick

View File

@ -0,0 +1,60 @@
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Utils = require(ReplicatedStorage.Tools.Utils)
local TypeList = require(ServerStorage.Base.TypeList)
local Rune = require(ServerStorage.Base.Rune)
local RuneWearSword = {}
RuneWearSword.__index = RuneWearSword
setmetatable(RuneWearSword, {__index = Rune})
function RuneWearSword:Init(PlayerAI, Character: TypeList.Character)
local self = Rune:Init(PlayerAI, Character, script.Name)
setmetatable(self, RuneWearSword)
return self
end
function RuneWearSword:Check(index: number, AttributesData: table, BehaviorNameList: table)
return true
end
function RuneWearSword:OnExecute(index: number, AttributesData: table, BehaviorNameList: table)
local pDataFolder = ReplicatedStorage:FindFirstChild("PlayerData")
if not pDataFolder then return nil end
local pData = pDataFolder:FindFirstChild(self.PlayerAI.Player.UserId)
if not pData then return nil end
local equipmentFolder = pData:FindFirstChild("Equipment")
if not equipmentFolder then return nil end
local equipmentList = equipmentFolder:GetChildren()
if #equipmentList == 0 then return nil end
local CheckSubType = 2
local subTypeNumber = 0
for _, equipment in equipmentList do
local equipmentSubType = equipment:GetAttribute("subType")
local equipmentWearing = equipment:GetAttribute("wearing")
if equipmentSubType == CheckSubType and equipmentWearing > 0 then
subTypeNumber = subTypeNumber + 1
end
end
local CheckShareName = "RuneTagSword"
if self.PlayerAI:GetSharedData(CheckShareName) then
subTypeNumber = subTypeNumber + self.PlayerAI:GetSharedData(CheckShareName)
end
local attackRate = math.floor(subTypeNumber * 25 / 100)
Utils:TableSafeAddValue(AttributesData, "attackRate", attackRate)
return nil
end
return RuneWearSword