diff --git a/luafight/BattleMain.lua b/luafight/BattleMain.lua new file mode 100644 index 000000000..89f33c1de --- /dev/null +++ b/luafight/BattleMain.lua @@ -0,0 +1,417 @@ +package.path = package.path ..';luafight\\?.lua'; + +require("Modules.Battle.Logic.Misc.BattleDefine") +require("Modules.Battle.Logic.Misc.BattleUtil") +require("Modules.Battle.Logic.Misc.BattleQueue") +require("Modules.Battle.Logic.Misc.BattleDictionary") + +require("Modules.Battle.Logic.Base.BattleEvent") +require("Modules.Battle.Logic.Base.Random") +require("Modules.Battle.Logic.Base.RoleData") +require("Modules.Battle.Logic.Base.Buff") +require("Modules.Battle.Logic.Base.Skill") +require("Modules.Battle.Logic.Base.Passivity") + +require("Modules.Battle.Logic.BattleLogic") +require("Modules.Battle.Logic.RoleLogic") + +--捕获异常,并输出错误日志 +local function error( err ) + local time = string.format("%d-%d-%d-%d-%d-%d", + os.date("%Y"), + os.date("%m"), + os.date("%d"), + os.date("%H"), + os.date("%M"), + os.date("%S")) + local file = io.open("LogError/"..time..".txt", "a") + file:write(debug.traceback(err)) + io.close(file) +end + +--测试战斗数据 +local test_fight_data={ + playerData = { + [1] = { + --角色id + roleId = 10001, + --职业id 0 无职业 1 秘法;2 天罚 3 武卫;4 玄策 5 生花 + professionId = 4, + --角色类型 1人形 2亡灵 3动物 4魔人 + type = 1, + --品质 1普通 2精英 3首领 4史诗 + quality = 1, + --camp 0我方, 1敌方 + camp = 0, + --skill = {cd, {目标id1, 效果时间, 效果1, 效果2, ...},{目标id2, 效果时间, 效果3, 效果4, ...}, ...} + --效果 = {效果类型id, 效果参数1, 效果参数2, ...} + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + --同skill + superSkill = { 0.5, {20011, 0.7, {1, 0.1, 1}} + }, + --passivity = {被动1, 被动2, ...} + --被动 = {被动类型id1, 被动参数1, 被动参数2, ...} + passivity = {}, + --属性 {等级,生命,最大生命,攻击力,护甲,魔抗,速度,伤害加成系数(%,伤害减免系数(%),命中率(%),闪避率(%),暴击率(%),暴击伤害系数(%),治疗加成系数(%) + -- ,火系伤害加成系数(%),火系伤害减免系数(%),冰系伤害加成系数(%),冰系伤害减免系数(%),雷系伤害加成系数(%),雷系伤害减免系数(%),风系伤害加成系数(%) + -- ,风系伤害减免系数(%),地系伤害加成系数(%),地系伤害减免系数(%),暗系伤害加成系数(%),暗系伤害减免系数(%)} + property = {1, 2390, 2390, 169, 271, 95, 176, 0, 0, 0.3, 0.15, 0.3, 1.5, 1, 0.05, 0, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0}, + }, + [2] = { + roleId = 10001, + professionId = 4, + type = 1, + quality = 1, + camp = 0, --阵营 0我方 1敌方 + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + passivity = { + --{201011, {30, 1, 0.2, 24, 0}}, + --passivity = {被动1, 被动2, ...} + --被动 = {被动id, 被动参数1, 被动参数2, ...} + }, + property = {1, 10000, 10000, 169, 271, 95, 176, 0, 0, 0.3, 0.15, 0.3, 1.5, 1, 0.05, 0, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0}, + }, + [3] = { + roleId = 10001, + professionId = 4, + type = 1, + quality = 1, + camp = 0, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + passivity = { + --{201011, {30, 1, 0.2, 24, 0}}, + }, + property = {1, 10000, 10000, 169, 271, 95, 176, 0, 0, 0.3, 0.15, 0.3, 1.5, 1, 0.05, 0, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0}, + }, + [4] = { + roleId = 10001, + professionId = 4, + type = 1, + quality = 1, + camp = 0, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { + 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + passivity = { + --{201011, {30, 1, 0.2, 24, 0}}, + }, + property = {1, 10000, 10000, 169, 271, 95, 176, 0, 0, 0.3, 0.15, 0.3, 1.5, 1, 0.05, 0, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0}, + }, + [5] = { + roleId = 10001, + professionId = 4, + type = 1, + quality = 1, + camp = 0, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = {0.5, {20011, 0.7,{1, 0.1, 1}} + }, + passivity = { + --{201011, {30, 1, 0.2, 24, 0}}, + }, + property = {1, 10000, 10000, 169, 271, 95, 176, 0, 0, 0.3, 0.15, 0.3, 1.5, 1, 0.05, 0, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0}, + }, + }, + enemyData = { + [1] = { + [1] = { + roleId = 1, + professionId = 2, + type = 1, + quality = 1, + camp = 1, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { + + }, + passivity = { + --{206021, {1,1}}, + }, + property = {1, 144, 144, 285, 152, 53, 154, 0, 0, 0.7, 0.35, 0.3, 1.5, 1, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0, 0.05, 0}, + }, + [2] = { + roleId = 1, + professionId = 2, + type = 1, + quality = 1, + camp = 1, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { + + }, + passivity = { + --{206021, {1,1}}, + }, + property = {9, 144, 144, 285, 152, 53, 154, 0, 0, 0.7, 0.35, 0.3, 1.5, 1, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0, 0.05, 0}, + }, + [3] = { + roleId = 1, + professionId = 2, + type = 1, + quality = 1, + camp = 1, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { + + }, + passivity = { + --{206021, {1,1}}, + }, + property = {7, 144, 144, 285, 152, 53, 154, 0, 0, 0.7, 0.35, 0.3, 1.5, 1, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0, 0.05, 0}, + }, + [4] = { + roleId = 1, + professionId = 2, + type = 1, + quality = 1, + camp = 1, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { + + }, + passivity = { + --{206021, {1,1}}, + }, + property = {5, 144, 144, 285, 152, 53, 154, 0, 0, 0.7, 0.35, 0.3, 1.5, 1, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0, 0.05, 0}, + }, + [5] = { + roleId = 1, + professionId = 2, + type = 1, + quality = 1, + camp = 1, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { + + }, + passivity = { + --{206021, {1,1}}, + }, + property = {3, 144, 144, 285, 152, 53, 154, 0, 0, 0.7, 0.35, 0.3, 1.5, 1, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0, 0.05, 0}, + }, + }, + [2] = { + [1] = { + roleId = 1, + professionId = 2, + type = 1, + quality = 1, + camp = 1, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { + + }, + passivity = { + --{206021, {1,1}}, + }, + property = {1, 144, 144, 285, 152, 53, 154, 0, 0, 0.7, 0.35, 0.3, 1.5, 1, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0, 0.05, 0}, + }, + [2] = { + roleId = 1, + professionId = 2, + type = 1, + quality = 1, + camp = 1, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { + + }, + passivity = { + --{206021, {1,1}}, + }, + property = {9, 144, 144, 285, 152, 53, 154, 0, 0, 0.7, 0.35, 0.3, 1.5, 1, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0, 0.05, 0}, + }, + [3] = { + roleId = 1, + professionId = 2, + type = 1, + quality = 1, + camp = 1, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { + + }, + passivity = { + --{206021, {1,1}}, + }, + property = {7, 144, 144, 285, 152, 53, 154, 0, 0, 0.7, 0.35, 0.3, 1.5, 1, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0, 0.05, 0}, + }, + [4] = { + roleId = 1, + professionId = 2, + type = 1, + quality = 1, + camp = 1, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { + + }, + passivity = { + --{206021, {1,1}}, + }, + property = {9, 144, 144, 285, 152, 53, 154, 0, 0, 0.7, 0.35, 0.3, 1.5, 1, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0, 0.05, 0}, + }, + [5] = { + roleId = 1, + professionId = 2, + type = 1, + quality = 1, + camp = 1, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { + + }, + passivity = { + --{206021, {1,1}}, + }, + property = {7, 144, 144, 285, 152, 53, 154, 0, 0, 0.7, 0.35, 0.3, 1.5, 1, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0, 0.05, 0}, + }, + }, + [3] = { + [1] = { + roleId = 1, + professionId = 2, + type = 1, + quality = 1, + camp = 1, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { + + }, + passivity = { + --{206021, {1,1}}, + }, + property = {1, 1044, 1044, 285, 152, 53, 154, 0, 0, 0.7, 0.35, 0.3, 1.5, 1, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0, 0.05, 0}, + }, + [2] = { + roleId = 1, + professionId = 2, + type = 1, + quality = 1, + camp = 1, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { + + }, + passivity = { + --{206021, {1,1}}, + }, + property = {9, 144, 144, 285, 152, 53, 154, 0, 0, 0.7, 0.35, 0.3, 1.5, 1, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0, 0.05, 0}, + }, + [3] = { + roleId = 1, + professionId = 2, + type = 1, + quality = 1, + camp = 1, + skill = { 0.5, {20011, 0.7,{1, 0.1, 1}} + }, + superSkill = { + + }, + passivity = { + --{206021, {1,1}}, + }, + property = {7, 144, 144, 285, 152, 53, 154, 0, 0, 0.7, 0.35, 0.3, 1.5, 1, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0, 0.05, 0}, + }, + } + } +} +local optionData = { + {14,1,0}, --{第几帧,操作类型,操作参数} + {132,2,3}, + {152,2,5}, + {178,3,2}, + {219,2,4}, + {260,3,1}, + {287,2,2}, + {312,3,5}, + {467,1,1}, +} + +local BattleMain = {} + +function BattleMain.Execute(seed, fightData, optionData) + --该开关用于输出战斗过程中的日志,用于验证前后端是否出现战斗不同步 + --BattleLogic.IsOpenBattleRecord = true + + Random.SetSeed(seed) + BattleLogic.Init(fightData, optionData) + BattleLogic.StartOrder() + + if xpcall(function () + while not BattleLogic.IsEnd do + BattleLogic.Update() + end + end, error) then + local resultList = {} + if BattleLogic.Result == 1 then --胜利记录我方剩余血量 + local arr = BattleLogic.Query(function (r) return r.camp == 0 end, true) + for i=1, #arr do + resultList[i] = arr[i]:GetRoleData(RoleDataName.Hp) + end + elseif BattleLogic.Result == 0 then --失败记录敌方剩余血量 + local arr = BattleLogic.Query(function (r) return r.camp == 1 end, true) + for i=1, #arr do + resultList[i] = arr[i]:GetRoleData(RoleDataName.Hp) + end + end + resultList.result = BattleLogic.Result + + -- print ----------------------------------------- + for i=1, #resultList do + print("hp:"..resultList[i]) + end + print("最终运行帧数:"..BattleLogic.CurFrame()) + print("result:"..BattleLogic.Result) + + + return resultList + --[[ --TODO:需要导入cjson库 + --local json = require("cjson") + --local time = string.format("%d-%d-%d-%d-%d-%d", + -- os.date("%Y"), + -- os.date("%m"), + -- os.date("%d"), + -- os.date("%H"), + -- os.date("%M"), + -- os.date("%S")) + --local file = io.open("BattleRecord/"..time..".txt", "a") + --file:write(json.encode(test_fight_data)) + --io.close(file) + ]] + end + return { result = -1 } +end +BattleMain.Execute(932590676, test_fight_data, optionData) + +return BattleMain +--> hp:2084 +--> hp:9934 +--> hp:9781 +--> hp:9868 +--> hp:9752 +--> 最终运行帧数:2735 +--> result:1 (1胜,0负,-1战斗异常) \ No newline at end of file diff --git a/luafight/Modules/Battle/Logic/Base/BattleEvent.lua b/luafight/Modules/Battle/Logic/Base/BattleEvent.lua new file mode 100644 index 000000000..1411c3218 --- /dev/null +++ b/luafight/Modules/Battle/Logic/Base/BattleEvent.lua @@ -0,0 +1,51 @@ +BattleEvent={} +BattleEvent.__index = BattleEvent + +function BattleEvent.New() + local instance = {} + setmetatable(instance, BattleEvent) + instance.m_listeners = {} + return instance +end + +function BattleEvent:AddEvent(sEventName, fListener, pObj, bOnce) + if self.m_listeners[sEventName] == nil then + self.m_listeners[sEventName] = {} + end + table.insert(self.m_listeners[sEventName],{ func = fListener, obj = pObj, once = bOnce } ) + +end +function BattleEvent:RemoveEvent(sEventName, fListener) + if self.m_listeners[sEventName] == nil then + return + end + local v + for i=1, #self.m_listeners[sEventName] do + v = self.m_listeners[sEventName][i] + if v.func == fListener then + table.remove(self.m_listeners[sEventName], i) + break + end + end +end + +function BattleEvent:DispatchEvent(sEventName,...) + if self.m_listeners[sEventName] == nil then + return + end + local v + for i=1, #self.m_listeners[sEventName] do + v = self.m_listeners[sEventName][i] + if nil == v.obj then + v.func(...) + else + v.func(v.obj, ...) + end + if v.once then + self:RemoveEvent(sEventName, v) + end + end +end +function BattleEvent:ClearEvent() + self.m_listeners={} +end \ No newline at end of file diff --git a/luafight/Modules/Battle/Logic/Base/Buff.lua b/luafight/Modules/Battle/Logic/Base/Buff.lua new file mode 100644 index 000000000..0d7451c23 --- /dev/null +++ b/luafight/Modules/Battle/Logic/Base/Buff.lua @@ -0,0 +1,195 @@ +Buff = {} + +local floor = math.floor +function Buff:New() + local o = {} + setmetatable(o, self) + self.__index = self + return o +end + +function Buff.Create(caster, type, duration, ...) + local instance = require("Modules/Battle/Logic/Buff/"..type):New() + + instance.type = type + instance.id = BattleLogic.GenerateBuffId() + instance.caster = caster + instance.disperse = false + instance.cover = false + + instance.duration = duration --持续时间为0时buff永久存在 + instance.interval = -1 --间隔帧为0时每帧触发,小于0不触发 默认不触发OnTrigger + instance.maxCount = 0 --限定效果最大数量 + instance.framePass = 0 + + instance:SetData(...) + return instance +end + +BuffManager = {} +BuffManager.__index = BuffManager + +function BuffManager.New(owner) + local instance = {} + instance.owner = owner + instance.buffQueue = BattleQueue.New() + instance.buffList = BattleDictionary.New() + + setmetatable(instance, BuffManager) + + return instance +end + +function BuffManager:AddBuff(buff) + self.buffQueue:Enqueue(buff) + if not buff.exCtrlTime then + buff.exCtrlTime = 0 + end + buff.frameDuration = floor(buff.duration * (1 + buff.exCtrlTime) * BattleLogic.GameFrameRate) + --if buff.isBuff then --TODO:增益buff持续时间加成 + -- local buffBocus = buff.caster:GetRoleData(RoleDataName.BuffBocus) + -- buff.frameDuration = floor(buff.duration * (1 + buffBocus + buff.exCtrlTime) * BattleLogic.GameFrameRate) + --end + -- + --if buff.isDeBuff then --TODO:减益buff持续时间减免 + -- local debuffReduce = self.owner:GetRoleData(RoleDataName.DebuffReduce) + -- buff.frameDuration = floor(buff.duration * (1 - debuffReduce - buff.exCtrlTime) * BattleLogic.GameFrameRate) + --end + + buff.frameInterval = floor(buff.interval * BattleLogic.GameFrameRate) +end + +function BuffManager:HasBuff(type, checkFunc) + local v + for i=1, self.buffList:Count() do + v = self.buffList.vList[i] + if #v > 0 then + if v[1].type == type and (not checkFunc or (checkFunc and checkFunc(v[1]))) then + return true + end + end + end + return false +end + +function BuffManager:ClearBuff(func) + for i = 1, self.buffList.size do + local k = self.buffList.kList[i] + local v = self.buffList.vList[i] + local count = #v + if count > 0 then + local removeCount = 0 + local idx = 1 + while idx <= count do + if func(v[idx]) then + table.remove(v, idx) + count = count - 1 + removeCount = removeCount + 1 + else + idx = idx + 1 + end + end + if removeCount > 0 then + self.owner.Event:DispatchEvent(BattleEventName.BuffCountChange, k, count) + end + end + end +end + +function BuffManager:GetBuffCount(id) + if self.buffList[id] then + return self.buffList[id]:Count() + end + return 0 +end + +function BuffManager:Update() + for i=1, self.buffQueue.size do + local buff = self.buffQueue:Dequeue() + if not buff.caster then + --logErrorTrace("buff's caster can't be nil!") + return + end + local buffList + if not self.buffList.kvList[buff.id] then + buffList = {} + self.buffList:Add(buff.id, buffList) + else + buffList = self.buffList.kvList[buff.id] + end + local count = #buffList + if buff.cover and count > 0 then + if buffList[1]:OnCover(buff) then --判定该效果能否被覆盖 + buffList[1]:OnEnd(self.owner) + self.owner.Event:DispatchEvent(BattleEventName.BuffEnd, buffList[1]) + buffList[1] = buff + buff.target = self.owner + buff:OnStart() + self.owner.Event:DispatchEvent(BattleEventName.BuffStart, buff) + self.owner.Event:DispatchEvent(BattleEventName.BuffCover, buff) + end + else + if buff.maxCount == 0 or count < buff.maxCount then --限制相同效果的数量,为0则不限制 + count = count + 1 + buffList[count] = buff + buff.target = self.owner + buff:OnStart() + self.owner.Event:DispatchEvent(BattleEventName.BuffStart, buff) + self.owner.Event:DispatchEvent(BattleEventName.BuffCountChange, buff.id, count) + end + end + end + for i = 1, self.buffList.size do + local k = self.buffList.kList[i] + local v = self.buffList.vList[i] + local count = #v + if count > 0 then + local removeCount = 0 + local idx = 1 + local buff + while idx <= count do + buff = v[idx] + --印记类型的buff不处理更新逻辑 + if buff.frameDuration == 0 and buff.frameInterval < 0 then + else + buff.framePass = buff.framePass + 1 + if buff.frameDuration == 0 then + if buff.frameInterval == 0 or buff.framePass % buff.frameInterval == 0 then + if not buff:OnTrigger() then + buff.disperse = true + end + buff.target.Event:DispatchEvent(BattleEventName.BuffTrigger, buff) + end + elseif buff.frameInterval < 0 then + if buff.framePass > buff.frameDuration then + buff.disperse = true + end + else + if buff.frameInterval == 0 or buff.framePass % buff.frameInterval == 0 then + if not buff:OnTrigger() then + buff.disperse = true + end + buff.target.Event:DispatchEvent(BattleEventName.BuffTrigger, buff) + end + + if buff.framePass > buff.frameDuration then + buff.disperse = true + end + end + end + if buff.disperse then + buff:OnEnd() + buff.target.Event:DispatchEvent(BattleEventName.BuffEnd, buff) + table.remove(v, idx) + count = count - 1 + removeCount = removeCount + 1 + else + idx = idx + 1 + end + end + if removeCount > 0 then + self.owner.Event:DispatchEvent(BattleEventName.BuffCountChange, k, count) + end + end + end +end diff --git a/luafight/Modules/Battle/Logic/Base/Effect.lua b/luafight/Modules/Battle/Logic/Base/Effect.lua new file mode 100644 index 000000000..ef8742793 --- /dev/null +++ b/luafight/Modules/Battle/Logic/Base/Effect.lua @@ -0,0 +1,431 @@ +local floor = math.floor +--local RoleDataName = RoleDataName +--local BattleLogic = BattleLogic +--local BattleUtil = BattleUtil + +--属性编号 +local propertyList = { + RoleDataName.Attack, + RoleDataName.PhysicalDefence, + RoleDataName.MagicDefence, + RoleDataName.Speed, + RoleDataName.DamageBocusFactor, + RoleDataName.DamageReduceFactor, + RoleDataName.Hit, + RoleDataName.Dodge, + RoleDataName.Crit, + RoleDataName.CritDamageFactor, + RoleDataName.TreatFacter, +} + +--效果表 +local effectList = { + --造成[a]%的[b]伤害 + --a[float],b[伤害类型] + [1] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + caster.Event:DispatchEvent(BattleEventName.RoleViewBullet, interval) + if caster.camp == 0 and target.camp == 1 then + BattleLogic.Event:DispatchEvent(BattleEventName.ZoomChange, target, interval) + end + BattleLogic.WaitForTrigger(interval, function () + BattleUtil.CalDamage(caster, target, dt, f1) + end) + end, + --造成[a]%的[b]伤害【AOE】 + --a[float],b[伤害类型] + [2] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + BattleLogic.WaitForTrigger(interval, function () + BattleUtil.CalDamage(caster, target, dt, f1) + end) + end, + --[a]%概率[b],持续[c]秒 + --a[float],b[控制状态],c[float] + [3] = function(caster, target, args, interval) + local f1 = args[1] * (1 + caster:GetRoleData(RoleDataName.Hit) / (1 + target:GetRoleData(RoleDataName.Dodge))) + local cb1 = args[2] + local f2 = args[3] + BattleLogic.WaitForTrigger(interval, function () + BattleUtil.RandomAction(f1, function () + target:AddBuff(Buff.Create(caster, BuffName.Control, f2, cb1)) + end) + end) + end, + --[d]改变[a]属性[b]%,持续[c]秒 + --a[属性],b[float],c[int],d[改变类型] + [4] = function(caster, target, args, interval) + local pro1 = args[1] + local f1 = args[2] + local f2 = args[3] + local ct = args[4] + BattleLogic.WaitForTrigger(interval, function () + target:AddBuff(Buff.Create(caster, BuffName.PropertyChange, f2, propertyList[pro1], f1, ct)) + end) + end, + --持续恢复[a]*[b]%生命,持续[c]秒 + --a[属性],b[float],c[int] + [5] = function(caster, target, args, interval) + local pro1 = args[1] + local f1 = args[2] + local f2 = args[3] + BattleLogic.WaitForTrigger(interval, function () + target:AddBuff(Buff.Create(caster, BuffName.HOT, f2, 1, floor(caster:GetRoleData(propertyList[pro1]) * f1))) + end) + end, + --造成[a]到[b]次[c]%的[d]伤害 + --a[int],b[int],c[float],d[伤害类型] + [6] = function(caster, target, args, interval) + local i1 = args[1] + local i2 = args[2] + local f1 = args[3] + local dt = args[4] + + local count = Random.RangeInt(i1, i2) + local d = interval / count + if caster.camp == 0 and target.camp == 1 then + BattleLogic.Event:DispatchEvent(BattleEventName.ZoomChange, target, d) + end + for i=1, count do + BattleLogic.WaitForTrigger(d * (i-1), function () + caster.Event:DispatchEvent(BattleEventName.RoleViewBullet, d) + BattleLogic.WaitForTrigger(d, function () + BattleUtil.CalDamage(caster, target, dt, f1) + end) + end) + end + end, + --造成[a]到[b]次[c]%的[d]伤害【AOE】 + --a[int],b[int],c[float],d[伤害类型] + [7] = function(caster, target, args, interval) + local i1 = args[1] + local i2 = args[2] + local f1 = args[3] + local dt = args[4] + + local count = Random.RangeInt(i1, i2) + local d = interval / count + for i=1, count do + BattleLogic.WaitForTrigger(d * (i-1), function () + BattleLogic.WaitForTrigger(d, function () + BattleUtil.CalDamage(caster, target, dt, f1) + end) + end) + end + end, + --[b]%改变[c]下次重击技能CD[a]秒 + --a[float],b[float] + [8] = function(caster, target, args, interval) + local f1 = args[1] + local f2 = args[2] * (1 + caster:GetRoleData(RoleDataName.Hit) / (1 + target:GetRoleData(RoleDataName.Dodge))) + local ct = args[3] + BattleLogic.WaitForTrigger(interval, function () + BattleUtil.RandomAction(f2, function () + if target.skill then + if f2 == 0 then --值为0时,直接清除CD + target.skill.sp = target.skill.spPass + else + if ct == 1 then --加算 + target.skill.sp = target.skill.sp - floor(f1 * BattleLogic.GameFrameRate) + elseif ct == 2 then --乘加算(百分比属性加算) + target.skill.sp = floor(target.skill.sp * (1 - f1)) + elseif ct == 3 then --减算 + target.skill.sp = target.skill.sp + floor(f1 * BattleLogic.GameFrameRate) + elseif ct == 4 then --乘减算(百分比属性减算) + target.skill.sp = floor(target.skill.sp * (1 + f1)) + end + end + end + end) + end) + end, + --添加[a]的[b]%护盾,持续[c]秒,盾消失的时候反射吸收伤害的[d]% + --a[属性],b[float],c[int],d[float] + [9] = function(caster, target, args, interval) + local pro1 = args[1] + local f1 = args[2] + local f2 = args[3] + local f3 = args[4] + BattleLogic.WaitForTrigger(interval, function () + target:AddBuff(Buff.Create(caster, BuffName.Shield, f2, floor(caster:GetRoleData(propertyList[pro1]) * f1), f3)) + end) + end, + --造成[a]%的[b]伤害,自身恢复造成伤害[c]%的生命 + --a[float],b[伤害类型],c[float] + [10] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + local f2 = args[3] + caster.Event:DispatchEvent(BattleEventName.RoleViewBullet, interval) + if caster.camp == 0 and target.camp == 1 then + BattleLogic.Event:DispatchEvent(BattleEventName.ZoomChange, target, interval) + end + BattleLogic.WaitForTrigger(interval, function () + local dmg = BattleUtil.CalDamage(caster, target, dt, f1) + BattleUtil.ApplyTreat(caster, caster, floor(dmg * f2)) + end) + end, + --造成[a]%的[b]伤害,对[c]造成额外[d]%伤害 + --a[float],b[伤害类型,]c[职业],d[float] + [11] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + local i1 = args[3] + local f2 = args[4] + caster.Event:DispatchEvent(BattleEventName.RoleViewBullet, interval) + if caster.camp == 0 and target.camp == 1 then + BattleLogic.Event:DispatchEvent(BattleEventName.ZoomChange, target, interval) + end + BattleLogic.WaitForTrigger(interval, function () + if target.professionId == i1 then + f1 = f1 + f2 + end + BattleUtil.CalDamage(caster, target, dt, f1) + end) + end, + --每秒造成[a]的[b]的伤害,持续[c]秒 + --a[float],b[伤害类型],c[int] + [12] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + local f2 = args[3] + BattleLogic.WaitForTrigger(interval, function () + target:AddBuff(Buff.Create(caster, BuffName.DOT, f2, 1, 0, dt, f1)) + end) + end, + --造成[c],每秒造成[d]的[e]的伤害,持续[f]秒 + --c[持续伤害状态].d[float],e[伤害类型],f[int] + [13] = function(caster, target, args, interval) + local d1 = args[1] + local f1 = args[2] + local dt = args[3] + local f2 = args[4] + BattleLogic.WaitForTrigger(interval, function () + target:AddBuff(Buff.Create(caster, BuffName.DOT, f2, 1, d1, dt, f1)) + end) + end, + --造成[a]%的[b]伤害,[c]%概率[d]专属伤害加深印记(如果有印记,无印记伤害*(1+印记数量*[e]) + --a[float],b[伤害类型],c[float],d[角色id],e[float] + [14] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + local f2 = args[3] * (1 + caster:GetRoleData(RoleDataName.Hit) / (1 + target:GetRoleData(RoleDataName.Dodge))) + local rid = args[4] + local f3 = args[5] + caster.Event:DispatchEvent(BattleEventName.RoleViewBullet, interval) + if caster.camp == 0 and target.camp == 1 then + BattleLogic.Event:DispatchEvent(BattleEventName.ZoomChange, target, interval) + end + BattleLogic.WaitForTrigger(interval, function () + local layer + if target.BuffMgr:HasBuff(BuffName.Brand, function (buff) + local b = buff.flag == rid + if b then + layer = buff.layer + end + return b + end) then + BattleUtil.CalDamage(caster, target, dt,f1 + layer * f3) + else + BattleUtil.CalDamage(caster, target, dt, f1) + end + BattleUtil.RandomAction(f2, function () + target:AddBuff(Buff.Create(caster, BuffName.Brand,0, rid)) + end) + end) + end, + --造成[a]%的[b]伤害,如果击杀,则其他人再受到此次伤害的[c]%的伤害 + --a[float],b[伤害类型],c[float] + [15] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + local f2 = args[3] + caster.Event:DispatchEvent(BattleEventName.RoleViewBullet, interval) + if caster.camp == 0 and target.camp == 1 then + BattleLogic.Event:DispatchEvent(BattleEventName.ZoomChange, target, interval) + end + BattleLogic.WaitForTrigger(interval, function () + local dmg = BattleUtil.CalDamage(caster, target, dt, f1) + if target.isDead then + local arr = BattleLogic.Query(function (r) return r.camp ~= caster.camp and r.uid ~= target.uid end) + for i=1, #arr do + BattleUtil.ApplyDamage(caster, arr[i], floor(dmg * f2)) + end + end + end) + end, + --吸取[a]%的[b],持续[c]秒 + --a[float],b[属性],c[float] + [16] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + local f2 = args[3] + local value = floor(target:GetRoleData(propertyList[dt]) * f1) + BattleLogic.WaitForTrigger(interval, function () + target:AddBuff(Buff.Create(caster, BuffName.PropertyChange, f2, value, f1, 3)) + caster:AddBuff(Buff.Create(caster, BuffName.PropertyChange, f2, value, f1, 1)) + end) + end, + --造成[a]%的[b]伤害,如果是[c],有[d]%必定暴击 + --a[float],b[伤害类型],c[职业],d[float] + [17] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + local i1 = args[3] + local f2 = args[4] * (1 + caster:GetRoleData(RoleDataName.Hit) / (1 + target:GetRoleData(RoleDataName.Dodge))) + caster.Event:DispatchEvent(BattleEventName.RoleViewBullet, interval) + if caster.camp == 0 and target.camp == 1 then + BattleLogic.Event:DispatchEvent(BattleEventName.ZoomChange, target, interval) + end + BattleLogic.WaitForTrigger(interval, function () + local dmg = floor(caster:GetRoleData(propertyList[dt]) * f1) + if target.professionId == i1 then + BattleUtil.RandomAction(f2, function () + target.isFlagCrit = true + BattleUtil.CalDamage(caster, target, dmg) + target.isFlagCrit = false + end) + else + BattleUtil.CalDamage(caster, target, dmg) + end + end) + end, + --造成[a]%的[b]伤害,若暴击,则减少下次发动技能CD[c]秒。 + --a[float],b[伤害类型],c[float] + [18] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + local f2 = args[3] + caster.Event:DispatchEvent(BattleEventName.RoleViewBullet, interval) + if caster.camp == 0 and target.camp == 1 then + BattleLogic.Event:DispatchEvent(BattleEventName.ZoomChange, target, interval) + end + BattleLogic.WaitForTrigger(interval, function () + local d, crit = BattleUtil.CalDamage(caster, target, dt, f1) + if crit then + if target.skill then + target.skill.sp = target.skill.sp + floor(f2 * BattleLogic.GameFrameRate) + end + end + end) + end, + --造成[a]%的[b]伤害,若暴击,则减少下次发动技能CD[c]秒。 + --a[float],b[伤害类型],c[float] + [18] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + local f2 = args[3] + caster.Event:DispatchEvent(BattleEventName.RoleViewBullet, interval) + if caster.camp == 0 and target.camp == 1 then + BattleLogic.Event:DispatchEvent(BattleEventName.ZoomChange, target, interval) + end + BattleLogic.WaitForTrigger(interval, function () + local d, crit = BattleUtil.CalDamage(caster, target, dt, f1) + if crit then + if target.skill then + target.skill.sp = target.skill.sp + floor(f2 * BattleLogic.GameFrameRate) + end + end + end) + end, + --造成[a]%的[b]伤害,有[c]%的概率追加伤害,最多可追加[d]次。(0无限追加) + --a[float],b[伤害类型],c[float],d[int] + [19] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + local f2 = args[3] + local i1 = args[4] + + if i1 == 0 then + i1 = floor(interval * BattleLogic.GameFrameRate) + end + local count = 1 + while Random.Range01() <= f2 and count <= i1 do + count = count + 1 + end + local d = interval / count + if caster.camp == 0 and target.camp == 1 then + BattleLogic.Event:DispatchEvent(BattleEventName.ZoomChange, target, d) + end + for i=1, count do + BattleLogic.WaitForTrigger(d * (i-1), function () + caster.Event:DispatchEvent(BattleEventName.RoleViewBullet, d) + BattleLogic.WaitForTrigger(d, function () + BattleUtil.CalDamage(caster, target, dt, f1) + end) + end) + end + end, + --造成[a]%的[b]伤害,对[c]造成额外[d]%伤害 + --a[float],b[伤害类型,]c[控制状态],d[float] + [20] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + local i1 = args[3] + local f2 = args[4] + caster.Event:DispatchEvent(BattleEventName.RoleViewBullet, interval) + if caster.camp == 0 and target.camp == 1 then + BattleLogic.Event:DispatchEvent(BattleEventName.ZoomChange, target, interval) + end + BattleLogic.WaitForTrigger(interval, function () + if target.BuffMgr:HasBuff(BuffName.Control, function (buff) return i1 == 0 or buff.ctrlType == i1 end) then + f1 = f1 + f2 + end + BattleUtil.CalDamage(caster, target, dt, f1) + end) + end, + --造成[a]%的[b]伤害,对[c]有[d]%造成[e],持续[f]秒【AOE】 + --a[float],b[伤害类型,]c[持续伤害状态],d[float],e[控制状态],f[int] + [21] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + local dot = args[3] + local f2 = args[4] * (1 + caster:GetRoleData(RoleDataName.Hit) / (1 + target:GetRoleData(RoleDataName.Dodge))) + local ct = args[5] + local f3 = args[6] + BattleLogic.WaitForTrigger(interval, function () + BattleUtil.CalDamage(caster, target, dt, f1) + if target.BuffMgr:HasBuff(BuffName.DOT, function (buff) return dot == 0 or buff.damageType == dot end) then + BattleUtil.RandomAction(f2, function () + target:AddBuff(Buff.Create(caster, BuffName.Control, f3, ct)) + end) + end + end) + end, + --造成[a]%的[b]伤害,对[c]造成额外[d]%伤害【AOE】 + --a[float],b[伤害类型,]c[持续伤害状态],d[float] + [22] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + local dot = args[3] + local f2 = args[4] + BattleLogic.WaitForTrigger(interval, function () + if target.BuffMgr:HasBuff(BuffName.DOT, function (buff) return dot == 0 or buff.damageType == dot end) then + f1 = f1 + f2 + end + BattleUtil.CalDamage(caster, target, dt, f1) + end) + end, + --造成[a]%的[b]伤害,对[c]造成额外[d]%伤害 + --a[float],b[伤害类型,]c[持续回复状态],d[float] + [23] = function(caster, target, args, interval) + local f1 = args[1] + local dt = args[2] + local ht = args[3] + local f2 = args[4] + caster.Event:DispatchEvent(BattleEventName.RoleViewBullet, interval) + if caster.camp == 0 and target.camp == 1 then + BattleLogic.Event:DispatchEvent(BattleEventName.ZoomChange, target, interval) + end + BattleLogic.WaitForTrigger(interval, function () + if target.BuffMgr:HasBuff(BuffName.HOT, function (buff) return true end) then + f1 = f1 + f2 + end + BattleUtil.CalDamage(caster, target, dt, f1) + end) + end, +} + +return effectList \ No newline at end of file diff --git a/luafight/Modules/Battle/Logic/Base/Passivity.lua b/luafight/Modules/Battle/Logic/Base/Passivity.lua new file mode 100644 index 000000000..099434f12 --- /dev/null +++ b/luafight/Modules/Battle/Logic/Base/Passivity.lua @@ -0,0 +1,283 @@ +local floor = math.floor +local max = math.max +--local RoleDataName = RoleDataName +--local BattleLogic = BattleLogic +--local BattleUtil = BattleUtil +--local BattleEventName = BattleEventName +--local BuffName = BuffName + +local function queryAllies(role) return function (r) return r.camp == role.camp end end +local function queryEnemy(role) return function (r) return r.camp ~= role.camp end end +--被动技能表 +local passivityList = { + --受到暴击伤害时,有(a%)的概率发动一次反击,对敌人造成【b*c+d】的【e】伤害 + [201011] = function(role, args) + local f1 = args[1]/100 + local pro1 = args[2] + local f2 = args[3] + local pro2 = args[4] + local dt = args[5] + + local OnCrit = function(atkRole) + BattleUtil.RandomAction(f1, function () + local value = role:GetRoleData(BattleUtil.GetPropertyName(pro1)) * f2 + role:GetRoleData(BattleUtil.GetPropertyName(pro2)) + BattleUtil.CalDamage(role, atkRole, value, 1, dt) + end) + end + role.Event:AddEvent(BattleEventName.RoleBeCrit, OnCrit) + end, + + --生命低于(a%)的时候,提升自身减伤率(b%),持续(c)秒。每场战斗只能触发一次。 + [201021] = function(role, args) + local f1 = args[1] + local f2 = args[2] + local f3 = args[3] + + local buffId1 = BattleUtil.CreateBuffId(role, 1) + + local triggerCount = 0 + local OnDamaged = function(atkRole) + if BattleUtil.GetHPPencent(role) < f1 then + if triggerCount < 1 then + local buff = Buff.Create(role, BuffName.PropertyChange, buffId1, f3, RoleDataName.DamageReduceFactor, f2, 1) + role:AddBuff(buff) + triggerCount = triggerCount + 1 + end + end + end + + role.Event:AddEvent(BattleEventName.RoleBeDamaged, OnDamaged) + end, + + --开场降低敌方全体(a%)的【c】,持续(bs)。 + [202011] = function(role, args) + local f1 = args[1]/100 + local f2 = args[2] + local pro1 = args[3] + + local buffId1 = BattleUtil.CreateBuffId(role, 1) + + local arr = BattleLogic.Query(queryEnemy(role)) + local v + for i=1, #arr do + v = arr[i] + local buff = Buff.Create(role, BuffName.PropertyChange, buffId1, f2, BattleUtil.GetPropertyName(pro1), f1, 2) + v:AddBuff(buff) + end + end, + + --开场增加增加全队暴击率(a%),持续(b)秒。 + [202021] = function(role, args) + local f1 = args[1]/100 + local f2 = args[2] + + local buffId1 = BattleUtil.CreateBuffId(role, 1) + + local arr = BattleLogic.Query(queryAllies(role)) + local v + for i=1, #arr do + v = arr[i] + local buff = Buff.Create(role, BuffName.PropertyChange, buffId1, f2, RoleDataName.Crit, f1, 2) + v:AddBuff(buff) + end + end, + + --场上每有1个流血目标,GCD降低(a)秒。最高降低(b)秒。 + [203011] = function(role, args) + local f1 = args[1] + local f2 = args[2] + + local buffId1 = BattleUtil.CreateBuffId(role, 1) + + local originGcd = role:GetRoleData(RoleDataName.GCD) + local aurabuff = Buff.Create(role, BuffName.Aura, buffId1, 0, function (role) + local arr = BattleLogic.Query(queryEnemy(role)) + local count = 0 + local v + for i=1, #arr do + v = arr[i] + if v.BuffMgr:HasBuff(BuffName.Bleed) then + count = count + 1 + end + end + role.data:SetValue(RoleDataName.GCD, max(originGcd - count * f1, f2)) + end) + aurabuff.interval = 0 + role:AddBuff(aurabuff) + end, + + --每次受到伤害,额外提升伤害(a%)(最多b%)。 + [203021] = function(role, args) + local f1 = args[1]/100 + local f2 = args[2]/100 + + local buffId1 = BattleUtil.CreateBuffId(role, 1) + local totalFactor = 0 + + local OnDamaged = function(atkRole) + if totalFactor <= f2 then + local buff = Buff.Create(role, BuffName.PropertyChange, buffId1, 0, RoleDataName.DamageBocusFactor, f2, 1) + role:AddBuff(buff) + totalFactor = totalFactor + f1 + end + end + role.Event:AddEvent(BattleEventName.RoleBeDamaged, OnDamaged) + end, + + --开场额外增加暴击率(a%)。 + [204011] = function(role, args) + local f1 = args[1]/100 + + local buffId1 = BattleUtil.CreateBuffId(role, 1) + local buff = Buff.Create(role, BuffName.PropertyChange, buffId1, 0, RoleDataName.Crit, f1, 1) + role:AddBuff(buff) + end, + + --受到攻击时,攻击者有(a%)的概率被附加1个印记。 + [204021] = function(role, args) + local f1 = args[1]/100 + + local buffId1 = BattleUtil.CreateBuffId(role, 1) + local OnDamaged = function(atkRole) + BattleUtil.RandomAction(f1, function () + local buff = Buff.Create(role, BuffName.Brand, buffId1, 0, "咒术师印记") + atkRole:AddBuff(buff) + end) + end + + role.Event:AddEvent(BattleEventName.RoleBeDamaged, OnDamaged) + end, + + --生命低于(a%),治疗量增加(b%),持续(c)秒。每场战斗只能触发一次。 + [205011] = function(role, args) + local f1 = args[1] + local f2 = args[2]/100 + local f3 = args[3] + + local buffId1 = BattleUtil.CreateBuffId(role, 1) + + local triggerCount = 0 + local OnDamaged = function(atkRole) + if BattleUtil.GetHPPencent(role) < f1 then + if triggerCount < 1 then + local buff = Buff.Create(role, BuffName.PropertyChange, buffId1, f3, RoleDataName.TreatFacter, f2, 1) + role:AddBuff(buff) + triggerCount = triggerCount + 1 + end + end + end + + role.Event:AddEvent(BattleEventName.RoleBeDamaged, OnDamaged) + end, + + --生命低于(a%),提升友军(b%)的【e】,并且(d%)概率眩晕对方全体(c)秒,每场战斗只能触发一次。 + [205021] = function(role, args) + local f1 = args[1] + local f2 = args[2]/100 + local f3 = args[3] + local f4 = args[4]/100 + local pro1 = args[5] + local f5 = args[6] + + local buffId1 = BattleUtil.CreateBuffId(role, 1) + local buffId2 = BattleUtil.CreateBuffId(role, 2) + + local triggerCount = 0 + local OnDamaged = function(atkRole) + if BattleUtil.GetHPPencent(role) < f1 then + if triggerCount < 1 then + local arr = BattleLogic.Query(queryAllies(role)) + local v + for i=1, #arr do + v = arr[i] + local buff = Buff.Create(role, BuffName.PropertyChange, buffId1, f5, BattleUtil.GetPropertyName(pro1), f2, 1) + v:AddBuff(buff) + end + + BattleUtil.RandomAction(f4, function () + local arr = BattleLogic.Query(queryEnemy(role)) + local v + for i=1, #arr do + v = arr[i] + local stun = Buff.Create(role, BuffName.Stun, buffId2, f3) + v:AddBuff(stun) + end + end) + triggerCount = triggerCount + 1 + end + end + end + role.Event:AddEvent(BattleEventName.RoleBeDamaged, OnDamaged) + end, + + --每(a)秒恢复(b)魂能 + [206021] = function(role, args) + local f1 = args[1] + local i1 = args[2] + + local buffId1 = BattleUtil.CreateBuffId(role, 1) + local aurabuff = Buff.Create(role, BuffName.Aura, buffId1, 0, function (role) + BattleLogic.AddMP(role.camp, i1) + end) + aurabuff.interval = f1 + role:AddBuff(aurabuff) + end, + + --自身生命高于(a%),暴击率提高(b%) + [207011] = function(role, args) + local f1 = args[1] + local f2 = args[2]/100 + + local buffId1 = BattleUtil.CreateBuffId(role, 1) + local buffId2 = BattleUtil.CreateBuffId(role, 2) + + local buff = Buff.Create(role, BuffName.PropertyChange, buffId2, 0, RoleDataName.Crit, f2, 1) + local active = BattleUtil.GetHPPencent(role) > f1 + if active then + role:AddBuff(buff) + end + + local aurabuff = Buff.Create(role, BuffName.Aura, buffId1, 0, function (role) + local curActive = BattleUtil.GetHPPencent(role) > f1 + if active ~= curActive then + active = curActive + if active then + buff.disperse = false + role:AddBuff(buff) + else + buff.disperse = true + end + end + end) + aurabuff.interval = 0 + role:AddBuff(aurabuff) + end, + + --召唤物存在期间,场上伙伴阵亡超过2名时,冰雪皇后会牺牲并复活所有已阵亡的队友,保留其(a%)的生命,全场只可触发1次 + [208011] = function(role, args) + local f1 = args[1]/100 + + local deadCount = 0 + local triggerCount = 0 + + local OnDead = function(role) + if role.camp == role.camp and role.roleType ~= 3 then + deadCount = deadCount + 1 + if deadCount > 2 and role.summon and triggerCount < 1 then + BattleLogic.RemoveSummon(role.summon) + local arr = BattleLogic.Query(function (r) return r.camp == role.camp and r.roleType ~= 3 end, true) + local v + for i=1, #arr do + v = arr[i] + local hp = v:GetRoleData(RoleDataName.MaxHp) + v.data:AddValue(RoleDataName.Hp, floor(hp*f1)) + v.Event:DispatchEvent(BattleEventName.RoleRevive) + end + triggerCount = triggerCount + 1 + end + end + end + BattleLogic.Event:AddEvent(BattleEventName.BattleRoleDead, OnDead) + end, +} +return passivityList \ No newline at end of file diff --git a/luafight/Modules/Battle/Logic/Base/Random.lua b/luafight/Modules/Battle/Logic/Base/Random.lua new file mode 100644 index 000000000..61eea900f --- /dev/null +++ b/luafight/Modules/Battle/Logic/Base/Random.lua @@ -0,0 +1,67 @@ +Random = {} + +local floor = math.floor +local seed = 0 + +local function random() + local r = seed + local m = 123459876 + if r < m then + r, m = m, r + end + local res = 0 + local shift = 1 + local b + while r ~= 0 do + b = (r % 2 + m % 2) == 1 and 1 or 0 + res = shift * b + res + shift = shift * 2 + r = floor( r * 0.5) + m = floor( m * 0.5) + end + local k = floor(res / 127773) + r = 16807 * (res - k * 127773) - 2836 * k + if r < 0 then + r = r + 2147483647 + end + seed = r + return r +end +function Random.SetSeed(sd) + seed = sd +end + +function Random.GetSeed() + return seed +end + +--随机0-1 +function Random.Range01() + local var = random() / 2147483647 + if BattleLogic.IsOpenBattleRecord then + BattleLogic.RecordSeed(seed) + end + return var +end + +--随机v1-v2 +function Random.Range(v1, v2) + if v2 > v1 then + return Random.Range01()*(v2-v1)+v1 + elseif v1 > v2 then + return Random.Range01()*(v1-v2)+v2 + else + return v1 + end +end + +--随机v1-v2 返回整数 +function Random.RangeInt(v1, v2) + if v2 > v1 then + return floor(Random.Range01()*(v2-v1) + 0.5)+v1 + elseif v1 > v2 then + return floor(Random.Range01()*(v1-v2) + 0.5)+v2 + else + return v1 + end +end \ No newline at end of file diff --git a/luafight/Modules/Battle/Logic/Base/RoleData.lua b/luafight/Modules/Battle/Logic/Base/RoleData.lua new file mode 100644 index 000000000..9a4079155 --- /dev/null +++ b/luafight/Modules/Battle/Logic/Base/RoleData.lua @@ -0,0 +1,90 @@ +RoleData = {} +RoleData.__index = RoleData +local max = math.max + +function RoleData.New(role, data) + local instance = {} + setmetatable(instance, RoleData) + instance.role = role + instance.data = data + return instance +end + +function RoleData:GetData(name) + if self.data[name] then + return self.data[name][1] + end +end + +function RoleData:SetValue(name, value) + if self.data[name][1] then + local delta = self.data[name][1] + self.data[name][1] = value + delta = value - delta + if delta ~= 0 then + self.role.Event:DispatchEvent(BattleEventName.RolePropertyChanged, name, value, delta) + if BattleLogic.IsOpenBattleRecord then + BattleLogic.RecordRoleProperty(self.role.uid, self.role.camp, name, value, delta) + end + end + end +end + +function RoleData:AddValue(name, delta) + if delta < 0 or not self.data[name] then --delta必须非负 + return 0 + end + if self.data[name][1] then + self:SetValue(name, self.data[name][1] + delta) + end + return delta +end + +function RoleData:AddPencentValue(name, pencent) + if self.data[name][1] and not self.data[name][2] then + return self:AddValue(name, self.data[name][1] * pencent) + else + return self:AddValue(name, pencent) + end +end + +function RoleData:SubDeltaValue(name, delta) + if delta < 0 or not self.data[name] then --delta必须非负 + return 0 + end + if self.data[name][1] then + self:SetValue(name, self.data[name][1] - delta) + end + return delta +end + +function RoleData:SubValue(name, delta) + if delta < 0 or not self.data[name] then --delta必须非负 + return 0 + end + local orVal = self.data[name][1] + if orVal then + if self.data[name][2] then + self:SetValue(name, self.data[name][1] * (1 - delta)) + else + self:SetValue(name, max(self.data[name][1] - delta, 0)) + end + orVal = orVal - self.data[name][1] + end + return orVal +end + +function RoleData:SubPencentValue(name, pencent) + if self.data[name][1] and not self.data[name][2] then + return self:SubValue(name, self.data[name][1] * pencent) + else + return self:SubValue(name, pencent) + end +end + +--Debug +function RoleData:Foreach(func) + for k,v in ipairs(self.data) do + func(k, v[1]) + end +end \ No newline at end of file diff --git a/luafight/Modules/Battle/Logic/Base/Skill.lua b/luafight/Modules/Battle/Logic/Base/Skill.lua new file mode 100644 index 000000000..7fc509f20 --- /dev/null +++ b/luafight/Modules/Battle/Logic/Base/Skill.lua @@ -0,0 +1,274 @@ +local effect = require("Modules/Battle/Logic/Base/Effect") +local floor = math.floor +local max = math.max +--local BattleConst = BattleConst +--local RoleDataName = RoleDataName +--local BattleEventName = BattleEventName +local function queryExceptList(r, exceptList) + if not exceptList then return true end + for i=1, #exceptList do + if r.uid == exceptList[i].uid then + return false + end + end + return true +end +local function queryAllies(role, exceptList) + return function (r) return r.camp == role.camp and queryExceptList(r, exceptList) end +end +local function queryAlliesExceptSelf(role, exceptList) + return function (r) return r.camp == role.camp and r.uid ~= role.uid and queryExceptList(r, exceptList) end +end +local function queryEnemy(role, exceptList) + return function (r) return r.camp ~= role.camp and queryExceptList(r, exceptList) end +end + +local function chooseTarget(role, chooseId, exceptList) + local chooseType = floor(chooseId / 10000) % 10 + local chooseWeight = floor(chooseId / 100) % 10 + local sort = floor(chooseId / 10) % 10 + local exceptNum = #exceptList + local num = chooseId % 10 + + local arr = {} + if chooseType == 1 then + arr = BattleLogic.Query(queryAllies(role, exceptList)) + elseif chooseType == 2 then + if role.lockTarget and num == 1 then + return {role.lockTarget} + end + arr = BattleLogic.Query(queryEnemy(role, exceptList)) + elseif chooseType == 3 then + return {role} + elseif chooseType == 4 then + return {BattleLogic.GetAggro(role.camp)} + end + + if chooseWeight == 0 then + BattleUtil.RandomList(arr) + elseif chooseWeight == 1 then + table.sort(arr, function(a, b) + local r1 = a:GetRoleData(RoleDataName.Hp) + local r2 = b:GetRoleData(RoleDataName.Hp) + return sort == 1 and r1 < r2 or r1 > r2 + end) + elseif chooseWeight == 2 then + table.sort(arr, function(a, b) + local r1 = a:GetRoleData(RoleDataName.Hp) / a:GetRoleData(RoleDataName.MaxHp) + local r2 = b:GetRoleData(RoleDataName.Hp) / b:GetRoleData(RoleDataName.MaxHp) + return sort == 1 and r1 < r2 or r1 > r2 + end) + elseif chooseWeight == 3 then + table.sort(arr, function(a, b) + local r1 = a:GetRoleData(RoleDataName.Attack) + local r2 = b:GetRoleData(RoleDataName.Attack) + return sort == 1 and r1 < r2 or r1 > r2 + end) + elseif chooseWeight == 4 then + table.sort(arr, function(a, b) + local r1 = a:GetRoleData(RoleDataName.PhysicalDefence) + local r2 = b:GetRoleData(RoleDataName.PhysicalDefence) + return sort == 1 and r1 < r2 or r1 > r2 + end) + elseif chooseWeight == 5 then + table.sort(arr, function(a, b) + local r1 = a:GetRoleData(RoleDataName.PhysicalDefence) + local r2 = b:GetRoleData(RoleDataName.PhysicalDefence) + return sort == 1 and r1 < r2 or r1 > r2 + end) + elseif chooseWeight == 6 then + table.sort(arr, function(a, b) + local r1 = a:GetRoleData(RoleDataName.MagicDefence) + local r2 = b:GetRoleData(RoleDataName.MagicDefence) + return sort == 1 and r1 < r2 or r1 > r2 + end) + elseif chooseWeight == 7 then + table.sort(arr, function(a, b) + local r1 = a:GetRoleData(RoleDataName.MagicDefence) + local r2 = b:GetRoleData(RoleDataName.MagicDefence) + return sort == 1 and r1 < r2 or r1 > r2 + end) + end + + local arr2 = {} + for i=1, exceptNum do + arr2[i] = exceptList[i] + end + if #arr >= num then + for i=1+exceptNum, num == 0 and #arr or num do + arr2[i] = arr[i] + end + end + arr = arr2 + return arr +end + +Skill = {} + +function Skill:New(role, effectData) + local o = {} + o.cd = effectData[1] + + --skill = {cd, {目标id1, 效果时间, 效果1, 效果2, ...},{目标id2, 效果时间, 效果3, 效果4, ...}, ...} + --效果 = {效果类型id, 效果参数1, 效果参数2, ...} + o.effectList = {} + + o.owner = role + o.sp = 0 + o.spPass = 0 + o.choosedList = {} + + local v + for i=2, #effectData do + v = effectData[i] + local effectGroup = { 0, 0, {}} -- chooseId, duration, {effect1, effect2, ...} + effectGroup[1] = v[1] --chooseId + effectGroup[2] = v[2] --duration + for j=3, #v do --effectList + local effect = {0, {}} -- type, {args, ...} + effect[1] = v[j][1] + for k=2, #v[j] do + effect[2][k-1] = v[j][k] + end + effectGroup[3][j-2] = effect + end + o.effectList[i-1] = effectGroup + end + setmetatable(o, self) + self.__index = self + + return o +end + +function Skill:ResetCD() + if self.owner.superSkill == self then + if BattleLogic.SkillUsable then + self.sp = 0 + self.spPass = floor(self.cd * BattleLogic.GameFrameRate) + self.owner.Event:DispatchEvent(BattleEventName.SkillCast, self) + BattleLogic.SkillUsable = false + BattleLogic.WaitForTrigger(self.cd, function() + BattleLogic.SkillUsable = true + end) + BattleLogic.AddMP(self.owner.camp, 8) + if self.owner.skill then + local skill = self.owner.skill + skill.sp = 0 + skill.spPass = floor(skill.cd * BattleLogic.GameFrameRate) + end + end + else + local time = max(6-self.owner:GetRoleData(RoleDataName.Speed)/(8*(self.owner:GetRoleData(RoleDataName.Level)+10)), 1.5) + self.sp = 0 + self.spPass = floor(time * BattleLogic.GameFrameRate) + BattleLogic.AddMP(self.owner.camp, 4) + self.owner.Event:DispatchEvent(BattleEventName.SkillCast, self) + end +end + +function Skill:Cast() + if self.owner.superSkill == self and not BattleLogic.SkillUsable then + return + end + for i=1, #self.effectList do + local effectGroup = self.effectList[i] + local chooseId = effectGroup[1] + local duration = effectGroup[2] + local arr = chooseTarget(self.owner, chooseId, self.choosedList) + if #arr > 0 then + --延迟1帧释放效果 + BattleLogic.WaitForTrigger(BattleLogic.GameDeltaTime, function () + local nn = floor(chooseId / 10000) % 10 + if self.owner.camp == 0 and nn == 2 then --我方释放效果开始切镜头 + BattleLogic.Event:DispatchEvent(BattleEventName.ZoomIn, 0.3) + BattleLogic.WaitForTrigger(duration, function() + BattleLogic.Event:DispatchEvent(BattleEventName.ZoomOut, 0.3) + end) + end + if chooseId == 10000 then --我方aoe + self.owner.Event:DispatchEvent(BattleEventName.AOE, 0) + for j=1, #arr do + for k=1, #effectGroup[3] do + local v = effectGroup[3][k] + effect[v[1]](self.owner, arr[j], v[2], duration) + end + end + elseif chooseId == 20000 then --敌方aoe + self.owner.Event:DispatchEvent(BattleEventName.AOE, 1) + for j=1, #arr do + for k=1, #effectGroup[3] do + local v = effectGroup[3][k] + effect[v[1]](self.owner, arr[j], v[2], duration) + end + end + elseif nn == 1 then + for j=1, #arr do + for k=1, #effectGroup[3] do + local v = effectGroup[3][k] + effect[v[1]](self.owner, arr[j], v[2], duration) + end + end + else + local d = duration / (#arr + 1) --分割多人目标施加效果的时间,按照(1+1+..+2)的时间权重占比分配 + for j=1, #arr do + local index = j + local cd = j == #arr and d * 2 or d + BattleLogic.WaitForTrigger(d * (j-1), function() + local r = arr[index] + if r.isDead then --当被选取的目标已经死亡,则重新选取,若重新选取的目标也死亡,则从之前的目标中选取第一个不死亡的 + arr = chooseTarget(self.owner, chooseId, self.choosedList) + r = arr[index] + if not r then --当没有新增的被选取目标时,可能为空 + for i=1, #arr do + if not arr[i].isDead then + r = arr[i] + for k=1, #effectGroup[3] do + local v = effectGroup[3][k] + effect[v[1]](self.owner, r, v[2], cd) + end + return + end + end + if not r then + return + end + end + end + table.insert(self.choosedList, r) + for k=1, #effectGroup[3] do + local v = effectGroup[3][k] + effect[v[1]](self.owner, r, v[2], cd) + end + end) + end + BattleLogic.WaitForTrigger(duration, function() + self.choosedList = {} + end) + end + end) + end + end + BattleLogic.SetAggro(self.owner, 0) + self:ResetCD() +end +--表现层调用 +function Skill:CanManualCast() + return not self.owner.IsDebug and self.owner.camp == 0 and not self.owner.Auto and self.sp >= self.spPass and BattleLogic.SkillUsable +end +--表现层调用 +function Skill:ManualCast() + --非调试模式下,只有我方阵营角色,且处在非自动状态下可手动释放技能 + local b = self:CanManualCast() + --调试模式下,可无条件手动释放技能 + local b2 = self.owner.IsDebug + if b or b2 then + if self.owner.skill == self then + BattleLogic.AddOption(2, self.owner.uid) + else + BattleLogic.AddOption(3, self.owner.uid) + end + end +end + + + diff --git a/luafight/Modules/Battle/Logic/BattleLogic.lua b/luafight/Modules/Battle/Logic/BattleLogic.lua new file mode 100644 index 000000000..8c9d35af6 --- /dev/null +++ b/luafight/Modules/Battle/Logic/BattleLogic.lua @@ -0,0 +1,400 @@ +BattleLogic = {} + +local floor = math.floor +local tbObjList +local tbActionList +local tbActionListCount = 0 +local curUid +local curBuffId +local curFrame + +local playerMP +local enemyMP + +local playerAggro +local enemyAggro +local playerAggroChangable +local enemyAggroChangable + +local fightData +local record +local optionRecord + +BattleLogic.IsEnd = false +BattleLogic.Result = -1 +BattleLogic.Event = BattleEvent:New() +--是否开启战斗日志 +BattleLogic.IsOpenBattleRecord = false +--逻辑帧频 +BattleLogic.GameFrameRate = 30 +BattleLogic.GameDeltaTime = 1 / BattleLogic.GameFrameRate +BattleLogic.SkillUsable = true +--总波次 +BattleLogic.TotalOrder = 0 +--当前波次 +BattleLogic.CurOrder = 0 + +function BattleLogic.Init(data, optionData) + if BattleLogic.IsOpenBattleRecord then + record = {} + end + + fightData = data + if optionData then + optionRecord = optionData + else + optionRecord = {} + end + + BattleLogic.CurOrder = 0 + BattleLogic.TotalOrder = #data.enemyData + + tbObjList = BattleDictionary.New() + tbActionList = {} + tbActionListCount = 0 + curUid = 0 + curBuffId = 0 + curFrame = 0 + playerMP = 0 + enemyMP = 0 + playerAggroChangable = true + enemyAggroChangable = true + BattleLogic.Event:ClearEvent() + BattleLogic.IsEnd = false + BattleLogic.Result = -1 + BattleLogic.SkillUsable = true +end + +function BattleLogic.StartOrder() + BattleLogic.CurOrder = BattleLogic.CurOrder + 1 + if BattleLogic.CurOrder == 1 then + for i=1, #fightData.playerData do + BattleLogic.AddRole(fightData.playerData[i]) + end + for i=1, #fightData.enemyData[BattleLogic.CurOrder] do + BattleLogic.AddRole(fightData.enemyData[BattleLogic.CurOrder][i]) + end + else + BattleLogic.ClearOrder() + for i=1, #fightData.enemyData[BattleLogic.CurOrder] do + BattleLogic.AddRole(fightData.enemyData[BattleLogic.CurOrder][i]) + end + end + BattleLogic.InitAggro() +end + +function BattleLogic.AddMP(camp, mp) + if camp == 0 then + playerMP = math.min(playerMP + mp, 100) + else + enemyMP = math.min(playerMP + mp, 100) + end +end + +function BattleLogic.GetMP(camp) + return camp == 0 and playerMP or enemyMP +end + +function BattleLogic.GenerateBuffId() + curBuffId = curBuffId + 1 + return curBuffId +end + +function BattleLogic.AddRole(roleData) + curUid = curUid + 1 + local data = RoleLogic.New(curUid, roleData) + tbObjList:Add(curUid, data) + BattleLogic.Event:DispatchEvent(BattleEventName.AddRole, data) +end + +function BattleLogic.InitAggro() + for i=1, tbObjList.size do + if tbObjList.vList[i].camp == 1 then + playerAggro = tbObjList.vList[i] + break + end + end + for i=1, tbObjList.size do + if tbObjList.vList[i].camp == 0 then + enemyAggro = tbObjList.vList[i] + break + end + end +end + +function BattleLogic.SetAggro(role, duration) + if role.camp == 1 then + if playerAggroChangable then + playerAggro = role + BattleLogic.Event:DispatchEvent(BattleEventName.ZoomChange, role, math.max(duration, 0.3)) + playerAggroChangable = false + BattleLogic.WaitForTrigger(duration-BattleLogic.GameDeltaTime, function () --减去一帧避免卡点 + playerAggroChangable = true + end) + end + else + if enemyAggroChangable then + enemyAggro = role + enemyAggroChangable = false + BattleLogic.WaitForTrigger(duration-BattleLogic.GameDeltaTime, function () --减去一帧避免卡点 + enemyAggroChangable = true + end) + end + end +end + +function BattleLogic.GetAggro(camp) + if camp == 0 then + if not playerAggro or playerAggro.isDead then + for i=1, tbObjList.size do + if tbObjList.vList[i].camp == 1 and not tbObjList.vList[i].isDead then + playerAggro = tbObjList.vList[i] + BattleLogic.SetAggro(playerAggro, 0) + break + end + end + end + return playerAggro + else + if not enemyAggro or enemyAggro.isDead then + for i=1, tbObjList.size do + if tbObjList.vList[i].camp == 0 and not tbObjList.vList[i].isDead then + enemyAggro = tbObjList.vList[i] + BattleLogic.SetAggro(enemyAggro, 0) + break + end + end + end + return enemyAggro + end +end + +function BattleLogic.WaitForTrigger(delayTime, action) + tbActionListCount = tbActionListCount + 1 + tbActionList[tbActionListCount] = { curFrame + floor(delayTime * BattleLogic.GameFrameRate + 0.5), action } +end + +function BattleLogic.AddOption(opType, opArg) + table.insert(optionRecord, {curFrame + 1, opType, opArg}) +end + +function BattleLogic.GetOption() + return optionRecord +end + +function BattleLogic.HasObj(obj) + return obj and tbObjList.kvList[obj.uid] +end + +function BattleLogic.RemoveObj(uid) + local role = tbObjList.kvList[uid] + if role then + BattleLogic.Event:DispatchEvent(BattleEventName.RemoveRole, role) + tbObjList:Remove(uid) + end +end + +function BattleLogic.CurFrame() + return curFrame +end + +function BattleLogic.Query(func, inCludeDeadRole) + local list = {} + local index = 1 + if func then + for i=1, tbObjList.size do + local v = tbObjList.vList[i] + if func(v) and (inCludeDeadRole or not v.isDead) then + list[index] = v + index = index + 1 + end + end + end + return list +end + +function BattleLogic.ClearOrder() + local index = 1 + local count = tbObjList.size + while index <= count do + if tbObjList.vList[index].camp == 1 then + BattleLogic.RemoveObj(tbObjList.vList[index].uid) + count = count - 1 + else + index = index + 1 + end + end +end + +local tmpObj, index, bMyAllDead, bEnemyAllDead + +function BattleLogic.Update() + curFrame = curFrame + 1 + + for i=1, #optionRecord do + if optionRecord[i][1] == curFrame then + local opType = optionRecord[i][2] + local opArg = optionRecord[i][3] + if opType == 1 then --自动手动 + for i=1, tbObjList.size do + tmpObj = tbObjList.vList[i] + if tmpObj.camp == 0 then + tmpObj.Auto = opArg == 1 + end + end + elseif opType == 2 then --释放skill + local role = tbObjList.kvList[opArg] + if role and role.skill then + role.skill:Cast() + end + elseif opType == 3 then --释放superSkill + local role = tbObjList.kvList[opArg] + if role and role.superSkill then + role.superSkill:Cast() + end + end + end + end + + index = 1 + while index <= tbActionListCount do + if tbActionList[index][1] <= curFrame then + if tbActionList[index][2] then + tbActionList[index][2]() + end + table.remove(tbActionList, index) + tbActionListCount = tbActionListCount - 1 + else + index = index + 1 + end + end + + if playerMP == 100 then + if Random.Range01() < 0.5 then + local roleArr = BattleLogic.Query(function (r) return r.camp == 0 end) + BattleLogic.Event:DispatchEvent(BattleEventName.AOE, 0) + --延迟1帧释放效果 + BattleLogic.WaitForTrigger(BattleLogic.GameDeltaTime, function () + for i = 1, #roleArr do + local role = roleArr[i] + BattleLogic.WaitForTrigger(0.3, function () + BattleUtil.ApplyTreat(role, role, 50) + end) + end + end) + else + local roleArr = BattleLogic.Query(function (r) return r.camp == 1 end) + BattleLogic.Event:DispatchEvent(BattleEventName.AOE, 1) + --延迟1帧释放效果 + BattleLogic.WaitForTrigger(BattleLogic.GameDeltaTime, function () + for i = 1, #roleArr do + local role = roleArr[i] + for j=1, 4 do + BattleLogic.WaitForTrigger(0.1 * (j-1), function () + BattleUtil.ApplyDamage(nil, role, 5) + end) + end + end + end) + end + playerMP = 0 + BattleLogic.SkillUsable = false + BattleLogic.WaitForTrigger(2, function () + BattleLogic.SkillUsable = true + end) + end + + bMyAllDead = true + bEnemyAllDead = true + for i=1, tbObjList.size do + tmpObj = tbObjList.vList[i] + if not tmpObj.isDead then + tmpObj:Update() + if tmpObj.camp == 0 then + bMyAllDead = false + else + bEnemyAllDead = false + end + end + end + if bMyAllDead then + BattleLogic.IsEnd = true + BattleLogic.Result = 0 + BattleLogic.Event:DispatchEvent(BattleEventName.BattleEnd, 0) + end + if bEnemyAllDead then + if BattleLogic.CurOrder == BattleLogic.TotalOrder then + BattleLogic.IsEnd = true + BattleLogic.Result = 1 + BattleLogic.Event:DispatchEvent(BattleEventName.BattleEnd, 1) + else + BattleLogic.CurOrder = BattleLogic.CurOrder + 1 + --for i=1, tbObjList.size do --切波次重置技能冷却时间 + -- tmpObj = tbObjList.vList[i] + -- if tmpObj.camp == 0 then + -- if tmpObj.skill then + -- tmpObj.skill.sp = 0 + -- end + -- if tmpObj.superSkill then + -- tmpObj.superSkill.sp = 0 + -- end + -- end + --end + --playerMP = 0 + --tbActionList = {} + --tbActionListCount = 0 + BattleLogic.SkillUsable = true + BattleLogic.Event:DispatchEvent(BattleEventName.BattleOrderChange, BattleLogic.CurOrder) + BattleLogic.StartOrder() + end + end +end + +--Debug专用 +function BattleLogic.SetDebug() + local v + for i=1, tbObjList.size do + v = tbObjList.vList[i] + v.IsDebug = not v.IsDebug + end +end + +--Debug专用 +function BattleLogic.SetRoleValue(uid, name, value) + if tbObjList.kvList[uid] then + tbObjList.kvList[uid].data:SetValue(name, value) + end +end + +--Debug专用 +function BattleLogic.SetRoleDebug(uid, isDebug) + if tbObjList.kvList[uid] then + tbObjList.kvList[uid].IsDebug = isDebug + end +end + +--Record专用 +function BattleLogic.RecordSeed(seed) + table.insert(record, string.format("frame:%d, seed:%d", curFrame, seed)) +end + +--Record专用 +function BattleLogic.RecordRoleProperty(uid, camp, name, value, delta) + table.insert(record, string.format("frame:%d, uid:%d, camp:%d, name:%s, value:%d, delta:%d", curFrame, uid, camp, name, value, delta)) +end + +--Record专用 +function BattleLogic.GenerateRecordFile() + local time = string.format("%d-%d-%d-%d-%d-%d", + os.date("%Y"), + os.date("%m"), + os.date("%d"), + os.date("%H"), + os.date("%M"), + os.date("%S")) + local file = io.open("BattleRecord/"..time..".txt", "a") + for i=1, #record do + file:write(record[i].."\n") + end + io.close(file) +end \ No newline at end of file diff --git a/luafight/Modules/Battle/Logic/Buff/Aura.lua b/luafight/Modules/Battle/Logic/Buff/Aura.lua new file mode 100644 index 000000000..7f86d2f16 --- /dev/null +++ b/luafight/Modules/Battle/Logic/Buff/Aura.lua @@ -0,0 +1,36 @@ +require("Modules/Battle/Logic/Base/Buff") +Aura = Buff:New() + +--初始化Buff,通过传入一些自定义参数控制成长相关的数值 +function Aura:SetData(...) + --log("Aura:SetData") + local args = {...} + self.action = args[1] +end + +--初始化后调用一次 +function Aura:OnStart() + --log("Aura:OnStart") +end + +--间隔N帧触发,返回true时表示继续触发,返回false立刻触发OnEnd +function Aura:OnTrigger() + --log("Aura:OnTrigger") + if self.action then + self.action(self.target) + end + return true +end + +--效果结束时调用一次 +function Aura:OnEnd() + --log("Aura:OnEnd") +end + +--只有当cover字段为true时触发,返回true则被新效果覆盖 +function Aura:OnCover(newBuff) + --log("Aura:OnCover") + return true +end + +return Aura \ No newline at end of file diff --git a/luafight/Modules/Battle/Logic/Buff/Brand.lua b/luafight/Modules/Battle/Logic/Buff/Brand.lua new file mode 100644 index 000000000..677866728 --- /dev/null +++ b/luafight/Modules/Battle/Logic/Buff/Brand.lua @@ -0,0 +1,36 @@ +require("Modules/Battle/Logic/Base/Buff") +Brand = Buff:New() + +--初始化Buff,通过传入一些自定义参数控制成长相关的数值 +function Brand:SetData(...) + --log("Brand:SetData") + local args = {...} + self.flag = args[1] + self.cover = true + self.layer = 1 +end + +--初始化后调用一次 +function Brand:OnStart() + --log("Brand:OnStart") +end + +--间隔N帧触发,返回true时表示继续触发,返回false立刻触发OnEnd +function Brand:OnTrigger() + --log("Brand:OnTrigger") + return true +end + +--效果结束时调用一次 +function Brand:OnEnd() + --log("Brand:OnEnd") +end + +--只有当cover字段为true时触发,返回true则被新效果覆盖 +function Brand:OnCover(newBuff) + --log("Brand:OnCover") + newBuff.layer = self.layer + 1 + return true +end + +return Brand \ No newline at end of file diff --git a/luafight/Modules/Battle/Logic/Buff/Control.lua b/luafight/Modules/Battle/Logic/Buff/Control.lua new file mode 100644 index 000000000..cb771d844 --- /dev/null +++ b/luafight/Modules/Battle/Logic/Buff/Control.lua @@ -0,0 +1,55 @@ +require("Modules/Battle/Logic/Base/Buff") +Control = Buff:New() + +--初始化Buff,通过传入一些自定义参数控制成长相关的数值 +function Control:SetData(...) + --log("Control:SetData") + local args = {...} + self.ctrlType = args[1] +end + +--初始化后调用一次 +function Control:OnStart() + --log("Control:OnStart") + if self.ctrlType == 1 then --眩晕 + self.target.enable = false + elseif self.ctrlType == 2 then --沉默 + + elseif self.ctrlType == 3 then --嘲讽 + self.target.lockTarget = self.caster + elseif self.ctrlType == 4 then --禁疗 + + elseif self.ctrlType == 5 then --致盲 + + end +end + +--间隔N帧触发,返回true时表示继续触发,返回false立刻触发OnEnd +function Control:OnTrigger() + --log("Control:OnTrigger") + return true +end + +--效果结束时调用一次 +function Control:OnEnd() + --log("Control:OnEnd") + if self.ctrlType == 1 then --眩晕 + self.target.enable = true + elseif self.ctrlType == 2 then --沉默 + + elseif self.ctrlType == 3 then --嘲讽 + self.target.lockTarget = nil + elseif self.ctrlType == 4 then --禁疗 + + elseif self.ctrlType == 5 then --致盲 + + end +end + +--只有当cover字段为true时触发,返回true则被新效果覆盖 +function Control:OnCover(newBuff) + --log("Control:OnCover") + return true +end + +return Control \ No newline at end of file diff --git a/luafight/Modules/Battle/Logic/Buff/DOT.lua b/luafight/Modules/Battle/Logic/Buff/DOT.lua new file mode 100644 index 000000000..9edb6d293 --- /dev/null +++ b/luafight/Modules/Battle/Logic/Buff/DOT.lua @@ -0,0 +1,38 @@ +require("Modules/Battle/Logic/Base/Buff") +DOT = Buff:New() + +--初始化Buff,通过传入一些自定义参数控制成长相关的数值 +function DOT:SetData(...) + --log("DOT:SetData") + local args = {...} + self.interval = args[1] + self.damageType = args[2] --1 燃烧 2 中毒 3 流血 + self.damagePro = args[3] --1 物理 2 魔法 + self.damageFactor = args[4] --伤害系数 + self.isDeBuff = true +end + +--初始化后调用一次 +function DOT:OnStart() + --log("DOT:OnStart") +end + +--间隔N帧触发,返回true时表示继续触发,返回false立刻触发OnEnd +function DOT:OnTrigger() + --log("DOT:OnTrigger") + BattleUtil.CalDamage(self.caster, self.target, self.damagePro, self.damageFactor) + return true +end + +--效果结束时调用一次 +function DOT:OnEnd() + --log("DOT:OnEnd") +end + +--只有当cover字段为true时触发,返回true则被新效果覆盖 +function DOT:OnCover(newBuff) + --log("DOT:OnCover") + return true +end + +return DOT \ No newline at end of file diff --git a/luafight/Modules/Battle/Logic/Buff/HOT.lua b/luafight/Modules/Battle/Logic/Buff/HOT.lua new file mode 100644 index 000000000..34a56b74e --- /dev/null +++ b/luafight/Modules/Battle/Logic/Buff/HOT.lua @@ -0,0 +1,36 @@ +require("Modules/Battle/Logic/Base/Buff") +HOT = Buff:New() + +--初始化Buff,通过传入一些自定义参数控制成长相关的数值 +function HOT:SetData(...) + --log("HOT:SetData") + local args = {...} + self.interval = args[1] + self.healValue = args[2] + self.isBuff = true +end + +--初始化后调用一次 +function HOT:OnStart() + --log("HOT:OnStart") +end + +--间隔N帧触发,返回true时表示继续触发,返回false立刻触发OnEnd +function HOT:OnTrigger() + --log("HOT:OnTrigger") + BattleUtil.ApplyTreat(self.caster, self.target, self.healValue) + return true +end + +--效果结束时调用一次 +function HOT:OnEnd() + --log("HOT:OnEnd") +end + +--只有当cover字段为true时触发,返回true则被新效果覆盖 +function HOT:OnCover(newBuff) + --log("HOT:OnCover") + return true +end + +return HOT \ No newline at end of file diff --git a/luafight/Modules/Battle/Logic/Buff/PropertyChange.lua b/luafight/Modules/Battle/Logic/Buff/PropertyChange.lua new file mode 100644 index 000000000..807f0d2c1 --- /dev/null +++ b/luafight/Modules/Battle/Logic/Buff/PropertyChange.lua @@ -0,0 +1,60 @@ +require("Modules/Battle/Logic/Base/Buff") +PropertyChange = Buff:New() + +--初始化Buff,通过传入一些自定义参数控制成长相关的数值 +function PropertyChange:SetData(...) + --log("PropertyChange:SetData") + local args = {...} + self.propertyName = args[1] + self.Value = args[2] + self.changeType = args[3] +end + +--初始化后调用一次 +function PropertyChange:OnStart() + --log("PropertyChange:OnStart") + if self.changeType == 1 then --加算 + self.delta = self.target.data:AddValue(self.propertyName, self.Value) + self.isBuff = true + elseif self.changeType == 2 then --乘加算(百分比属性加算) + self.delta = self.target.data:AddPencentValue(self.propertyName, self.Value) + self.isBuff = true + elseif self.changeType == 3 then --减算 + self.delta = self.target.data:SubValue(self.propertyName, self.Value) + self.isDeBuff = true + elseif self.changeType == 4 then --乘减算(百分比属性减算) + self.delta = self.target.data:SubPencentValue(self.propertyName, self.Value) + self.isDeBuff = true + end +end + +--间隔N帧触发,返回true时表示继续触发,返回false立刻触发OnEnd +function PropertyChange:OnTrigger() + --log("PropertyChange:OnTrigger") + return true +end + +--效果结束时调用一次 +function PropertyChange:OnEnd() + --log("PropertyChange:OnEnd") + if self.changeType == 3 or self.changeType == 4 then + self.target.data:AddValue(self.propertyName, self.delta) + else + self.target.data:SubDeltaValue(self.propertyName, self.delta) + end +end + +--只有当Cover字段为true时触发,返回true则被新效果覆盖 +function PropertyChange:OnCover(newBuff) + --log("PropertyChange:OnCover") + if self.layer then + if self.maxCount == 0 then + newBuff.layer = self.layer + 1 + else + newBuff.layer = math.min(self.layer + 1, self.maxCount) + end + end + return true +end + +return PropertyChange \ No newline at end of file diff --git a/luafight/Modules/Battle/Logic/Buff/Shield.lua b/luafight/Modules/Battle/Logic/Buff/Shield.lua new file mode 100644 index 000000000..6fea942bb --- /dev/null +++ b/luafight/Modules/Battle/Logic/Buff/Shield.lua @@ -0,0 +1,50 @@ +require("Modules/Battle/Logic/Base/Buff") +Shield = Buff:New() + +--初始化Buff,通过传入一些自定义参数控制成长相关的数值 +function Shield:SetData(...) + --log("Shield:SetData") + local args = {...} + self.shieldValue = args[1] --护盾值 + self.dmgReboundFactor = args[2] --伤害反弹系数 + self.damageSum = 0 --记录承受的伤害 +end + +--初始化后调用一次 +function Shield:OnStart() + --log("Shield:OnStart") + if not self.target.shield then + self.target.shield = {} + end + table.insert(self.target.shield, self) + self.target.Event:DispatchEvent(BattleEventName.ShieldAdd, self) +end + +--间隔N帧触发,返回true时表示继续触发,返回false立刻触发OnEnd +function Shield:OnTrigger() + --log("Shield:OnTrigger") + return true +end + +--效果结束时调用一次 +function Shield:OnEnd() + --log("Shield:OnEnd") + if self.target.shield then + for i = 1, #self.target.shield do + if self.target.shield[i] == self then + table.remove(self.target.shield, i) + BattleUtil.ApplyDamage(self.caster, self.target, math.floor(self.dmgReboundFactor * self.damageSum)) + self.target.Event:DispatchEvent(BattleEventName.ShieldEnd, self) + break + end + end + end +end + +--只有当cover字段为true时触发,返回true则被新效果覆盖 +function Shield:OnCover(newBuff) + --log("Shield:OnCover") + return true +end + +return Shield \ No newline at end of file diff --git a/luafight/Modules/Battle/Logic/Misc/BattleDefine.lua b/luafight/Modules/Battle/Logic/Misc/BattleDefine.lua new file mode 100644 index 000000000..f23070757 --- /dev/null +++ b/luafight/Modules/Battle/Logic/Misc/BattleDefine.lua @@ -0,0 +1,96 @@ +local index = 0 +local function indexAdd() + index = index + 1 + return index +end + +BattleEventName = { + BattleOrderChange = indexAdd(), + BattleEnd = indexAdd(), + AddRole = indexAdd(), + RemoveRole = indexAdd(), + MpChanged = indexAdd(), + MpAdd = indexAdd(), + MpSub = indexAdd(), + BattleRoleDead = indexAdd(), + + RoleBeDamaged = indexAdd(), + RoleDamage = indexAdd(), + RoleBeTreated = indexAdd(), + RoleTreat = indexAdd(), + RoleBeCrit = indexAdd(), + RoleCrit = indexAdd(), + RoleDodge = indexAdd(), + RoleBeDodge = indexAdd(), + RoleDead = indexAdd(), + RoleRevive = indexAdd(), + RolePropertyChanged = indexAdd(), + + SkillCast = indexAdd(), + + ZoomIn = indexAdd(), + ZoomChange = indexAdd(), + ZoomOut = indexAdd(), + + AOE = indexAdd(), + + RoleViewBullet = indexAdd(), --弹道飞行击中表现 + + BuffStart = indexAdd(), + BuffTrigger = indexAdd(), + BuffEnd = indexAdd(), + BuffCountChange = indexAdd(), + BuffCover = indexAdd(), + + ShieldAdd = indexAdd(), + ShieldEnd = indexAdd(), +} + +index = 0 +RoleDataName = { + Level = indexAdd(), --等级 + Hp = indexAdd(), --生命 + MaxHp = indexAdd(), --最大生命 + Attack = indexAdd(), --攻击力 + PhysicalDefence = indexAdd(),--护甲 + MagicDefence = indexAdd(),--魔抗 + Speed = indexAdd(),--速度 + DamageBocusFactor = indexAdd(), --伤害加成系数(%) + DamageReduceFactor = indexAdd(), --伤害减免系数(%) + Hit = indexAdd(), --命中率(%) + Dodge = indexAdd(), --闪避率(%) + Crit = indexAdd(), --暴击率(%) + CritDamageFactor = indexAdd(), --暴击伤害系数(%) + TreatFacter = indexAdd(),--治疗加成系数(%) + + FireDamageBocusFactor = indexAdd(), --火系伤害加成系数(%) + FireDamageReduceFactor = indexAdd(), --火系伤害减免系数(%) + WindDamageBocusFactor = indexAdd(), --风系伤害加成系数(%) + WindDamageReduceFactor = indexAdd(), --风系伤害减免系数(%) + IceDamageBocusFactor = indexAdd(), --冰系伤害加成系数(%) + IceDamageReduceFactor = indexAdd(), --冰系伤害减免系数(%) + LandDamageBocusFactor = indexAdd(), --地系伤害加成系数(%) + LandDamageReduceFactor = indexAdd(), --地系伤害减免系数(%) + LightDamageBocusFactor = indexAdd(), --光系伤害加成系数(%) + LightDamageReduceFactor = indexAdd(), --光系伤害减免系数(%) + DarkDamageBocusFactor = indexAdd(), --暗系伤害加成系数(%) + DarkDamageReduceFactor = indexAdd(), --暗系伤害减免系数(%) +} + +BuffName = { + Poison = "Poison", + PropertyChange = "PropertyChange", + Taunt = "Taunt", + Bleed = "Bleed", + Frozen = "Frozen", + Stun = "Stun", + HOT = "HOT", + DOT = "DOT", + Control = "Control", + Aura = "Aura", + Brand = "Brand", + Shield = "Shield", +} + + + diff --git a/luafight/Modules/Battle/Logic/Misc/BattleDictionary.lua b/luafight/Modules/Battle/Logic/Misc/BattleDictionary.lua new file mode 100644 index 000000000..ea8e38701 --- /dev/null +++ b/luafight/Modules/Battle/Logic/Misc/BattleDictionary.lua @@ -0,0 +1,58 @@ +BattleDictionary = {} +function BattleDictionary.New() + local o = {} + setmetatable(o, BattleDictionary) + BattleDictionary.__index = BattleDictionary + o.kList = {} + o.vList = {} + o.kvList = {} + o.size = 0 + return o +end + +function BattleDictionary:Add(k,v) + if not self.kvList[k] then + self.size = self.size + 1 + self.kvList[k] = v + self.kList[self.size] = k + self.vList[self.size] = v + end +end + +function BattleDictionary:Remove(k) + if self.kvList[k] then + for i=1, self.size do + if self.vList[i] == self.kvList[k] then + self.size = self.size - 1 + table.remove(self.kList, i) + table.remove(self.vList, i) + self.kvList[k] = nil + break + end + end + end +end + +function BattleDictionary:Set(k,v) + self:Remove(k) + self:Add(k,v) +end + +function BattleDictionary:Clear() + self.kList = {} + self.vList = {} + self.kvList = {} + self.size = 0 +end + +function BattleDictionary:Count() + return self.size +end + +function BattleDictionary:Foreach(func) + for i = 1, self.size do + if func then + func(self.kList[i], self.vList[i]) + end + end +end diff --git a/luafight/Modules/Battle/Logic/Misc/BattleQueue.lua b/luafight/Modules/Battle/Logic/Misc/BattleQueue.lua new file mode 100644 index 000000000..02703828f --- /dev/null +++ b/luafight/Modules/Battle/Logic/Misc/BattleQueue.lua @@ -0,0 +1,62 @@ +BattleQueue = {} +function BattleQueue.New() + local o = {} + setmetatable(o, BattleQueue) + BattleQueue.__index = BattleQueue + o.head = -1 + o.rear = -1 + o.list = {} + o.size = 0 + return o +end + +function BattleQueue:Enqueue(e) + if self.size == 0 then + self.head = 0 + self.rear = 1 + self.size = 1 + self.list[self.rear] = e + else + self.rear = self.rear + 1 + self.list[self.rear] = e + self.size = self.size + 1 + end +end + +function BattleQueue:Dequeue() + if self.size == 0 then + error("lua queue is isEmpty") + return nil + end + self.size = self.size - 1 + self.head = self.head + 1 + return self.list[self.head] +end + +function BattleQueue:Clear() + self.list = {} + self.size = 0 + self.head = -1 + self.rear = -1 +end + +function BattleQueue:Count() + return self.size +end + +function BattleQueue:Foreach(func) + for i = self.head + 1, self.rear do + if func then + func(self.list[i]) + end + end +end + +function BattleQueue:Contain(e) + for i = self.head + 1, self.rear do + if e == self.list[i] then + return true + end + end + return false +end diff --git a/luafight/Modules/Battle/Logic/Misc/BattleUtil.lua b/luafight/Modules/Battle/Logic/Misc/BattleUtil.lua new file mode 100644 index 000000000..49e04ea9a --- /dev/null +++ b/luafight/Modules/Battle/Logic/Misc/BattleUtil.lua @@ -0,0 +1,221 @@ +BattleUtil = {} +--local BattleUtil = BattleUtil +local floor = math.floor +local max = math.max +local min = math.min +--local Random = Random +--local RoleDataName = RoleDataName +--local BattleEventName = BattleEventName + +local function clamp(v, minValue, maxValue) + if v < minValue then + return minValue + end + if v > maxValue then + return maxValue + end + return v +end + +function BattleUtil.CreateBuffId(skill, index) + local id = 0 + if skill.preAI then --主动技能生成buff + id = skill.owner.uid * 10000 + index + else --被动技能生成buff + id = skill.owner.uid * 1000 + index + end + return id +end + +function BattleUtil.CalBaseDamage(atkRole, defRole, baseDamage, baseFactor) + local atkData, defData = atkRole.data, defRole.data + if not baseFactor then baseFactor = 1 end + + local elementDamage, elementReduce = 0 + if skillAttribute == 0 then --无属性 + elementDamage = 0 + elementReduce = 0 + elseif skillAttribute == 1 then --火系 + elementDamage = atkData:GetData(RoleDataName.FireDamageBocusFactor) + elementReduce = defData:GetData(RoleDataName.FireDamageReduceFactor) + elseif skillAttribute == 2 then --风系 + elementDamage = atkData:GetData(RoleDataName.WindDamageBocusFactor) + elementReduce = defData:GetData(RoleDataName.WindDamageReduceFactor) + elseif skillAttribute == 3 then --水系 + elementDamage = atkData:GetData(RoleDataName.IceDamageBocusFactor) + elementReduce = defData:GetData(RoleDataName.IceDamageReduceFactor) + elseif skillAttribute == 4 then --地系 + elementDamage = atkData:GetData(RoleDataName.LandDamageBocusFactor) + elementReduce = defData:GetData(RoleDataName.LandDamageReduceFactor) + elseif skillAttribute == 5 then --光系 + elementDamage = atkData:GetData(RoleDataName.LightDamageBocusFactor) + elementReduce = defData:GetData(RoleDataName.LightDamageReduceFactor) + elseif skillAttribute == 6 then --暗系 + elementDamage = atkData:GetData(RoleDataName.DarkDamageBocusFactor) + elementReduce = defData:GetData(RoleDataName.DarkDamageReduceFactor) + end + + + --伤害 =(基础伤害*(1+己伤害加成-目标伤害减免)*(1+己方属性伤害加成-目标属性伤害减免),10%*己攻) + local damage = baseDamage * baseFactor * + (1 + atkData:GetData(RoleDataName.DamageBocusFactor)) * (1 - defData:GetData(RoleDataName.DamageReduceFactor)) * + (1 + atkData:GetData(RoleDataName.FireDamageBocusFactor)) * (1 - defData:GetData(RoleDataName.FireDamageReduceFactor)) * --火系 + (1 + atkData:GetData(RoleDataName.WindDamageBocusFactor)) * (1 - defData:GetData(RoleDataName.WindDamageReduceFactor)) * --风系 + (1 + atkData:GetData(RoleDataName.IceDamageBocusFactor)) * (1 - defData:GetData(RoleDataName.IceDamageReduceFactor)) * --冰系 + (1 + atkData:GetData(RoleDataName.LandDamageBocusFactor)) * (1 - defData:GetData(RoleDataName.LandDamageReduceFactor)) * --地系 + (1 + atkData:GetData(RoleDataName.LightDamageBocusFactor)) * (1 - defData:GetData(RoleDataName.LightDamageReduceFactor)) * --光系 + (1 + atkData:GetData(RoleDataName.DarkDamageBocusFactor)) * (1 - defData:GetData(RoleDataName.DarkDamageReduceFactor)) --暗系 + return damage +end + +function BattleUtil.CalHit(atkRole, defRole) + --命中率 = clamp(自身命中率-敌方闪避率,0,1) + local hit = atkRole:GetRoleData(RoleDataName.Hit) + local dodge = defRole:GetRoleData(RoleDataName.Dodge) + + local bHit = Random.Range01() <= clamp(hit - dodge, 0, 1) + + if bHit then + else + atkRole.Event:DispatchEvent(BattleEventName.RoleDodge) + defRole.Event:DispatchEvent(BattleEventName.RoleBeDodge) + end + return bHit +end + +function BattleUtil.CalCrit(atkRole, defRole) + local bCrit = Random.Range01() <= clamp(atkRole:GetRoleData(RoleDataName.Crit), 0, 1) + + if bCrit then + atkRole.Event:DispatchEvent(BattleEventName.RoleCrit, defRole) + defRole.Event:DispatchEvent(BattleEventName.RoleBeCrit, atkRole) + end + return bCrit +end + +function BattleUtil.CalShield(atkRole, defRole, damage) + if defRole.shield then + local buff + for i=1, #defRole.shield do + buff = defRole.shield[i] + if damage < buff.shieldValue then + buff.shieldValue = buff.shieldValue - damage + buff.damageSum = buff.damageSum + damage + return 0 + else + buff.damageSum = buff.damageSum + buff.shieldValue + damage = damage - buff.shieldValue + buff.shieldValue = 0 + buff.disperse = true + end + end + end + return damage +end + +function BattleUtil.ApplyDamage(atkRole, defRole, damage, bCrit) + if not bCrit then bCrit = false end + damage = floor(damage + 0.5) + local finalDmg = defRole.data:SubValue(RoleDataName.Hp, damage) + if finalDmg > 0 then + if atkRole then + atkRole.Event:DispatchEvent(BattleEventName.RoleDamage, defRole, damage, bCrit) + end + defRole.Event:DispatchEvent(BattleEventName.RoleBeDamaged, atkRole, damage, bCrit) + + if defRole:GetRoleData(RoleDataName.Hp) <= 0 then + defRole.isDead = true + defRole.Event:DispatchEvent(BattleEventName.RoleDead) + BattleLogic.Event:DispatchEvent(BattleEventName.BattleRoleDead, defRole) + end + end + return finalDmg +end + +--执行完整的命中,伤害,暴击计算,返回命中,暴击 +function BattleUtil.CalDamage(atkRole, defRole, damageType, baseFactor) + local bCrit = false + local baseDamage + bCrit = BattleUtil.CalCrit(atkRole, defRole) + local defence = 0 + if damageType == 1 then --1 物理 2 魔法 + defence = defRole:GetRoleData(RoleDataName.PhysicalDefence) + else + defence = defRole:GetRoleData(RoleDataName.MagicDefence) + end + local attack = 0 + if atkRole.GetAttackFunc then + attack = atkRole.GetAttackFunc(bCrit) + else + attack = atkRole:GetRoleData(RoleDataName.Attack) + end + --计算暴击 + if bCrit or defRole.isFlagCrit then + local critDamageFactor = atkRole:GetRoleData(RoleDataName.CritDamageFactor) + baseDamage = attack * critDamageFactor - 0.5 * defence + else + baseDamage = attack - 0.5 * defence + end + baseDamage = BattleUtil.CalBaseDamage(atkRole, defRole, baseDamage, baseFactor) + baseDamage = max(baseDamage, 0.1 * attack) + baseDamage = BattleUtil.CalShield(atkRole, defRole, baseDamage) + local finalDmg = 0 --计算实际造成的扣血 + if not defRole.isDead then + finalDmg = BattleUtil.ApplyDamage(atkRole, defRole, baseDamage, bCrit) + end + return finalDmg, bCrit +end + +function BattleUtil.ApplyTreat(castRole, targetRole, value, baseFactor) + if not baseFactor then baseFactor = 1 end + local maxHp = targetRole:GetRoleData(RoleDataName.MaxHp) + local hp = targetRole:GetRoleData(RoleDataName.Hp) + local factor = castRole:GetRoleData(RoleDataName.TreatFacter) + local treat = min(floor(value * baseFactor * factor + 0.5), maxHp - hp) + targetRole.data:AddValue(RoleDataName.Hp, treat) + castRole.Event:DispatchEvent(BattleEventName.RoleTreat, targetRole, treat) + targetRole.Event:DispatchEvent(BattleEventName.RoleBeTreated, castRole, treat) +end + +function BattleUtil.RandomAction(rand, action) + if Random.Range01() <= rand and action then + action() + end +end + +function BattleUtil.RandomList(arr) + if #arr <= 1 then return end + local index + for i=#arr, 1, -1 do + index = Random.RangeInt(1, i) + arr[i], arr[index] = arr[index], arr[i] + end +end + +function BattleUtil.GetPropertyName(type) + if type == 1 then + return RoleDataName.Strength + elseif type == 2 then + return RoleDataName.Energy + elseif type == 3 then + return RoleDataName.Vitality + elseif type == 4 then + return RoleDataName.Dexterity + elseif type == 5 then + return RoleDataName.Speed + elseif type == 6 then + return RoleDataName.PhysicalAttack + elseif type == 7 then + return RoleDataName.MagicAttack + elseif type == 8 then + return RoleDataName.PhysicalDefence + elseif type == 9 then + return RoleDataName.MagicDefence + end +end + +function BattleUtil.GetHPPencent(role) + return role:GetRoleData(RoleDataName.Hp) / role:GetRoleData(RoleDataName.MaxHp) * 100 +end + + diff --git a/luafight/Modules/Battle/Logic/RoleLogic.lua b/luafight/Modules/Battle/Logic/RoleLogic.lua new file mode 100644 index 000000000..f501431d6 --- /dev/null +++ b/luafight/Modules/Battle/Logic/RoleLogic.lua @@ -0,0 +1,136 @@ +RoleLogic = {} +RoleLogic.__index = RoleLogic +--local RoleLogic = RoleLogic +--local RoleDataName = RoleDataName +--local BattleLogic = BattleLogic +local Random = Random +local floor = math.floor +local max = math.max +local Passivity = require("Modules/Battle/Logic/Base/Passivity") +local function InitData(property) + --初始化属性 + local index = 1 + local getData = function(property) + local p = property[index] + index = index + 1 + return p + end + return { + [RoleDataName.Level] = {getData(property), false}, + [RoleDataName.Hp] = {getData(property), false}, + [RoleDataName.MaxHp] = {getData(property), false}, + [RoleDataName.Attack] = {getData(property), false}, + [RoleDataName.PhysicalDefence] = {getData(property), false}, + [RoleDataName.MagicDefence] = {getData(property), false}, + [RoleDataName.Speed] = {getData(property), false}, + [RoleDataName.DamageBocusFactor] = {getData(property), true}, + [RoleDataName.DamageReduceFactor] = {getData(property), true}, + [RoleDataName.Hit] = {getData(property), true}, + [RoleDataName.Dodge] = {getData(property), true}, + [RoleDataName.Crit] = {getData(property), true}, + [RoleDataName.CritDamageFactor] = {getData(property), true}, + [RoleDataName.TreatFacter] = {getData(property), true}, + [RoleDataName.FireDamageBocusFactor] = {getData(property), true}, + [RoleDataName.IceDamageBocusFactor] = {getData(property), true}, + [RoleDataName.LightDamageBocusFactor] = { getData(property), true}, + [RoleDataName.WindDamageBocusFactor] = {getData(property), true}, + [RoleDataName.LandDamageBocusFactor] = {getData(property), true}, + [RoleDataName.DarkDamageBocusFactor] = {getData(property), true}, + [RoleDataName.FireDamageReduceFactor] = {getData(property), true}, + [RoleDataName.IceDamageReduceFactor] = {getData(property), true}, + [RoleDataName.LightDamageReduceFactor] = { getData(property), true}, + [RoleDataName.WindDamageReduceFactor] = {getData(property), true}, + [RoleDataName.LandDamageReduceFactor] = {getData(property), true}, + [RoleDataName.DarkDamageReduceFactor] = {getData(property), true}, + } +end + +function RoleLogic.New(uid, data) + local instance = {} + setmetatable(instance, RoleLogic) + + instance.uid = uid + instance.roleData = data + instance.data = RoleData.New(instance, InitData(data.property)) + + instance.camp = data.camp --阵营 0:我方 1:敌方 + instance.name = data.name + instance.roleType = 1 --阵营 1:普通 2:Boss 3:召唤物 + + instance.BuffMgr = BuffManager.New(instance) + instance.Event = BattleEvent:New() + + instance.passiveList = {} + if data.skill and #data.skill > 0 then + instance.skill = Skill:New(instance, data.skill) + instance.skill.sp = 0 + local time = max(6-instance:GetRoleData(RoleDataName.Speed)/(8*(instance:GetRoleData(RoleDataName.Level)+10)), 1.5) + instance.skill.spPass = floor( time * BattleLogic.GameFrameRate) + end + if data.superSkill and #data.superSkill > 0 then + instance.superSkill = Skill:New(instance, data.superSkill) + instance.superSkill.spPass = floor(instance.superSkill.cd * BattleLogic.GameFrameRate) + instance.superSkill.sp = instance.superSkill.spPass + end + for i = 1, #data.passivity do + local v = data.passivity[i] + local id = v[1] + local args = v[2] + Passivity[id](instance, args) + end + + instance.isDead = false + instance.Auto = true + instance.IsDebug = false + instance.enable = true + + return instance +end + +function RoleLogic:GetRoleData(property) + return self.data:GetData(property) +end + +function RoleLogic:AddBuff(buff) + self.BuffMgr:AddBuff(buff) +end + +function RoleLogic:Update() + self.BuffMgr:Update() + if not self.enable then + return + end + if self.superSkill then + if self.superSkill.sp >= self.superSkill.spPass then + if self.skill then + if self.skill.sp >= self.skill.spPass then + if self.Auto and not self.IsDebug then + if Random.Range01() <= 0.75 then + self.skill:Cast() + else + self.superSkill:Cast() + end + end + else + self.skill.sp = self.skill.sp + 1 + end + else + if self.Auto and not self.IsDebug then + self.superSkill:Cast() + end + end + else + self.superSkill.sp = self.superSkill.sp + 1 + end + else + if self.skill then + if self.skill.sp >= self.skill.spPass then + if self.Auto and not self.IsDebug then + self.skill:Cast() + end + else + self.skill.sp = self.skill.sp + 1 + end + end + end +end \ No newline at end of file