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 BattleUtil.Passivity = require("Modules/Battle/Logic/Base/Passivity") 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.ErrorCorrection(f) --进行精度处理,避免前后端计算不一致 return floor(f * 100000 + 0.5) / 100000 end function BattleUtil.FP_Mul(...) local f = 1 for i, v in ipairs{...} do f = floor(f * v * 100000 + 0.5) / 100000 end return f end -- 选择前排 function BattleUtil.ChooseFRow(arr) local tempArr = {} for _, r in ipairs(arr) do --不是放逐 if r.position <= 3 and not r:IsRealDead() and not r.isExile then table.insert(tempArr, r) end end table.sort(tempArr, function(a, b) return a.position < b.position end) return tempArr end -- 选择后排 function BattleUtil.ChooseBRow(arr) local tempArr = {} for _, r in ipairs(arr) do if r.position > 3 and not r:IsRealDead() and not r.isExile then table.insert(tempArr, r) end end table.sort(tempArr, function(a, b) return a.position < b.position end) return tempArr end -- 选择一列(col == 0 表示第三列哦) function BattleUtil.ChooseCol(arr, col) local tempArr = {} for _, role in ipairs(arr) do if role.position % 3 == col and not role.isExile then table.insert(tempArr, role) end end table.sort(tempArr, function(a, b) return a.position < b.position end) return tempArr end -- 选择两列 function BattleUtil.ChooseTowCol(arr) local teamArr={} --第一列 local oneArr = {} for _, role in ipairs(arr) do if role.position % 3 == 1 then table.insert(oneArr, role) end end local one=#oneArr --第二列 local twoArr = {} for _, role in ipairs(arr) do if role.position % 3 == 2 then table.insert(twoArr, role) end end local two=#twoArr --第三列 local threeArr = {} for _, role in ipairs(arr) do if role.position % 3 == 0 then table.insert(threeArr, role) end end local three=#threeArr --如果每列人数相同,就选前两列 if one==two and two==three then for key, value in pairs(oneArr) do table.insert(teamArr,value) end for key, value in pairs(twoArr) do table.insert(teamArr,value) end else --如果第一列数量>第二列数量就把第一列选入 if one>two then if one>0 then for key, value in pairs(oneArr) do table.insert(teamArr,value) end end --如果第二列数量>=第三列数量就把第二列选入 if two>=three then if two>0 then for key, value in pairs(twoArr) do table.insert(teamArr,value) end end else --如果第三列数量>第二列数量就把第三列选入 if three>0 then for key, value in pairs(threeArr) do table.insert(teamArr,value) end end end else --如果第二列数量>第一列数量就把第二列选入 if two>0 then for key, value in pairs(twoArr) do table.insert(teamArr,value) end end --如果第一列数量>第三列数量就把第一列选入 if one>=three then if one>0 then for key, value in pairs(oneArr) do table.insert(teamArr,value) end end else --如果第三列数量>第一列数量就把第三列选入 if three>0 then for key, value in pairs(threeArr) do table.insert(teamArr,value) end end end end end table.sort(teamArr, function(a, b) return a.position < b.position end) return teamArr end -- 根据属性排序 function BattleUtil.SortByProp(arr, prop, sort) BattleUtil.Sort(arr, function(a, b) local r1 = a:GetRoleData(prop) local r2 = b:GetRoleData(prop) if sort == 1 then return r1 > r2 else return r1 < r2 end end) return arr end -- 按百分比血量排序 function BattleUtil.SortByHpFactor(arr, sort) BattleUtil.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) if sort == 1 then return r1 > r2 else return r1 < r2 end end) return arr end -- 按百分比血量排序 function BattleUtil.SortByHpFactorAndHp(arr, sort) BattleUtil.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) if sort == 1 then if r1==r2 then return a:GetRoleData(RoleDataName.Hp) r2 end else if r1==r2 then return a:GetRoleData(RoleDataName.Hp)b.position else return r1 < r2 end else if r1==r2 then return a.position>b.position else return r1 > r2 end end end) return arr end -- 获取技能最大目标数 function BattleUtil.GetMaxTargetNum(chooseId) local chooseType = floor(chooseId / 100000) % 10 local chooseLimit = floor(chooseId / 10000) % 10 local chooseWeight = floor(chooseId / 100) % 100 local sort = floor(chooseId / 10) % 10 local num = chooseId % 10 -- if chooseType == 3 or chooseType == 4 then return 1 else if num == 0 then if chooseLimit == 0 then if chooseWeight == 7 then return 4 elseif chooseLimit == 8 then return 1 else return 6 end elseif chooseLimit == 1 or chooseLimit == 2 then return 3 elseif chooseLimit == 3 then return 2 end else return num end end end -- function BattleUtil.ChooseTarget(role, chooseId) local chooseType = floor(chooseId / 100000) % 10 local chooseLimit = floor(chooseId / 10000) % 10 local chooseWeight = floor(chooseId / 100) % 100 local sort = floor(chooseId / 10) % 10 local num = chooseId % 10 local arr -- 选择类型 if chooseType == 1 then arr = RoleManager.Query(function (r) return r.camp == role.camp end) elseif chooseType == 2 then if role.lockTarget and not role.lockTarget:IsRealDead() and not role.lockTarget.isExile and num == 1 then --嘲讽时对单个敌军生效 return {role.lockTarget} end arr = RoleManager.Query(function (r) return r.camp ~= role.camp end) elseif chooseType == 3 then if role.ctrl_blind then --致盲时自身变随机友军 arr = RoleManager.Query(function (r) return r.camp == role.camp end) BattleUtil.RandomList(arr) return {arr[1]} end return {role} elseif chooseType == 4 then if role.lockTarget and not role.lockTarget:IsRealDead() and not role.lockTarget.isExile then --嘲讽时对仇恨目标生效 return {role.lockTarget} end if role.ctrl_blind then --致盲时仇恨目标变随机 arr = RoleManager.Query(function (r) return r.camp ~= role.camp end) BattleUtil.RandomList(arr) return {arr[1]} end return {RoleManager.GetAggro(role)} else arr = RoleManager.Query() end --选择范围 if chooseLimit == 0 then --选择全体不做任何操作 elseif chooseLimit == 1 then-- 前排 local tempArr = BattleUtil.ChooseFRow(arr) if #tempArr == 0 then -- 没有选择后排 tempArr = BattleUtil.ChooseBRow(arr) end arr = tempArr elseif chooseLimit == 2 then-- 后排 local tempArr = BattleUtil.ChooseBRow(arr) if #tempArr == 0 then -- 没有选择前排 tempArr = BattleUtil.ChooseFRow(arr) end arr = tempArr elseif chooseLimit == 3 then-- 对列 local target=RoleManager.GetAggro(role) if target then local myCol = target.position % 3 local tempArr = BattleUtil.ChooseCol(arr, myCol) if #tempArr == 0 then -- 对列没有人,按顺序找到有人得列 for i = 1, 3 do local col = i % 3 -- 0 表示第三列嗷 tempArr = BattleUtil.ChooseCol(arr, col) if #tempArr ~= 0 then break end end end arr = tempArr end elseif chooseLimit == 4 then -- 处于灼烧状态 local tempArr = {} for i = 1, #arr do if BattleLogic.BuffMgr:HasBuff(arr[i], BuffName.DOT, function (buff) return buff.damageType == DotType.Burn end,role,1) then table.insert(tempArr, arr[i]) end end arr = tempArr elseif chooseLimit == 5 then -- 人阵营 local tempArr = {} for i = 1, #arr do if arr[i].element == BattleRoleElementType.REN then table.insert(tempArr, arr[i]) end end arr = tempArr elseif chooseLimit == 6 then --两纵排单位 local tempArr=BattleUtil.ChooseTowCol(arr) arr=tempArr end -- 选择条件 if chooseWeight == 0 or role.ctrl_blind then --致盲时排序无效 BattleUtil.RandomList(arr) elseif chooseWeight == 1 then -- 生命值 BattleUtil.SortByProp(arr, RoleDataName.Hp, sort) elseif chooseWeight == 2 then -- 血量百分比 BattleUtil.SortByHpFactor(arr, sort) --选血量百分比最低的 不选择有不灭的,如果伤害要选有不灭的 需处理 BattleUtil.RemoveNoDeadRole(arr) elseif chooseWeight == 3 then -- 攻击力 BattleUtil.SortByProp(arr, RoleDataName.Attack, sort) elseif chooseWeight == 4 then -- 防御 BattleUtil.SortByProp(arr, RoleDataName.PhysicalDefence, sort) elseif chooseWeight == 5 then -- 护甲 BattleUtil.SortByProp(arr, RoleDataName.PhysicalDefence, sort) elseif chooseWeight == 6 then -- 魔抗 BattleUtil.SortByProp(arr, RoleDataName.MagicDefence, sort) elseif chooseWeight == 7 then -- 对位及其相邻目标 arr = RoleManager.GetNeighbor(role, chooseType) elseif chooseWeight == 8 then -- 对位 if num==1 then arr=RoleManager.GetAggroHero(role,arr) else arr = RoleManager.GetArrAggroList(role, arr) end -- elseif chooseWeight == 9 then -- 展位距离 -- BattleUtil.Sort(arr, function(a, b) -- local r1 = math.abs(role.position - a.position) * 10 + a.position -- local r2 = math.abs(role.position - b.position) * 10 + b.position -- if sort == 1 then return r1 > r2 else return r1 < r2 end -- end) elseif chooseWeight ==9 then --攻击最高且没被放逐过 local list=role.exileTargets local tempArr = {} local team = RoleManager.Query(function (r) return r.camp ~= role.camp end) if list then for key, value in pairs(team) do if not value:IsRealDead() and not BattleUtil.ChecklistIsContainValue(role.exileTargets,value) then --return arr[i] table.insert(tempArr,value) end end end BattleUtil.SortByProp(tempArr,RoleDataName.Attack,sort) arr=tempArr elseif chooseWeight ==10 then --剩余血量百分比低于25%且生命绝对值最小 return BattleUtil.GetHpPctLessThanPctHero(arr,0.25) elseif chooseWeight ==11 then --剩余血量百分比低于32%且生命绝对值最小 return BattleUtil.GetHpPctLessThanPctHero(arr,0.32) elseif chooseWeight ==12 then --剩余血量百分比低于40%且生命绝对值最小 return BattleUtil.GetHpPctLessThanPctHero(arr,0.40) elseif chooseWeight ==13 then --剩余血量百分比低于50%且生命绝对值最小 return BattleUtil.GetHpPctLessThanPctHero(arr,0.50) end local finalArr = {} if num == 0 then finalArr = arr else for i = 1, num do if arr[i] then table.insert(finalArr, arr[i]) end end end -- table.sort(finalArr, function(a, b) -- return a.position < b.position -- end) return finalArr end --获取生命百分比少于指定百分比且生命置最少 function BattleUtil.GetHpPctLessThanPctHero(arr,pct) local hp=0 local hero=nil for i = 1, #arr[i] do local aaa=arr[i] local curHp=aaa:GetRoleData(RoleDataName.Hp) local r1 = curHp / aaa:GetRoleData(RoleDataName.MaxHp) if r1= 0 then if defRole:GetRoleData(RoleDataName.Hp) <= 0 and not defRole:IsDead() then defRole:SetDead(damage) defRole.Event:DispatchEvent(BattleEventName.RoleDead, atkRole,skill) atkRole.Event:DispatchEvent(BattleEventName.RoleKill, defRole,skill) BattleLogic.Event:DispatchEvent(BattleEventName.BattleRoleDead, defRole, atkRole) atkRole.Event:DispatchEvent(BattleEventName.Seckill, defRole,damage,nil,finalDmg) defRole.Event:DispatchEvent(BattleEventName.BeSeckill, atkRole) BattleLogic.Event:DispatchEvent(BattleEventName.Seckill, atkRole, defRole) end atkRole.Event:DispatchEvent(BattleEventName.RoleDamage, defRole, damage, false, finalDmg, 0, false, skill) defRole.Event:DispatchEvent(BattleEventName.RoleBeDamaged, atkRole, damage, false, finalDmg, 0, false, skill) BattleLogic.Event:DispatchEvent(BattleEventName.RoleDamage, atkRole, defRole, damage, false, finalDmg, 0, false, skill) BattleLogic.Event:DispatchEvent(BattleEventName.RoleBeDamaged, defRole, atkRole, damage, false, finalDmg, 0, false, skill) if skill then atkRole.Event:DispatchEvent(BattleEventName.RoleHit, defRole, damage, nil, finalDmg, nil, skill) defRole.Event:DispatchEvent(BattleEventName.RoleBeHit, atkRole, damage, nil, finalDmg, nil, skill) end end -- 用于记录统计 BattleLogic.Event:DispatchEvent(BattleEventName.RecordSecKill, atkRole, defRole) end -- 秒杀定额血量 function BattleUtil.SeckillHP(skill, atkRole, defRole, pro) -- 灵兽无效 if defRole.type == BattleUnitType.Monster then return end local damage = floor(BattleUtil.FP_Mul(defRole:GetRoleData(RoleDataName.MaxHp),pro)) local finalDmg = defRole.data:SubValue(RoleDataName.Hp, damage) if finalDmg >= 0 then if defRole:GetRoleData(RoleDataName.Hp) <= 0 and not defRole:IsDead() then defRole:SetDead(damage) defRole.Event:DispatchEvent(BattleEventName.RoleDead, atkRole) atkRole.Event:DispatchEvent(BattleEventName.RoleKill, defRole,skill) BattleLogic.Event:DispatchEvent(BattleEventName.BattleRoleDead, defRole, atkRole) atkRole.Event:DispatchEvent(BattleEventName.Seckill, defRole,damage,nil,finalDmg) defRole.Event:DispatchEvent(BattleEventName.BeSeckill, atkRole) BattleLogic.Event:DispatchEvent(BattleEventName.Seckill, atkRole, defRole) end atkRole.Event:DispatchEvent(BattleEventName.RoleDamage, defRole, damage, false, finalDmg, 0, false, skill) defRole.Event:DispatchEvent(BattleEventName.RoleBeDamaged, atkRole, damage, false, finalDmg, 0, false, skill) BattleLogic.Event:DispatchEvent(BattleEventName.RoleDamage, atkRole, defRole, damage, false, finalDmg, 0, false, skill) BattleLogic.Event:DispatchEvent(BattleEventName.RoleBeDamaged, defRole, atkRole, damage, false, finalDmg, 0, false, skill) if skill then atkRole.Event:DispatchEvent(BattleEventName.RoleHit, defRole, damage, nil, finalDmg, nil, skill) defRole.Event:DispatchEvent(BattleEventName.RoleBeHit, atkRole, damage, nil, finalDmg, nil, skill) end end -- 用于记录统计 BattleLogic.Event:DispatchEvent(BattleEventName.RecordSecKill, atkRole, defRole) end -- 计算真实伤害 function BattleUtil.ApplyDamage(skill, atkRole, defRole, damage, bCrit, damageType, dotType,isDirect) -- 灵兽无效 if defRole.type == BattleUnitType.Monster then return end bCrit = bCrit or false damageType = damageType or 0 -- if atkRole.isTeam then -- --max(技能基础伤害*(1+已方异妖伤害加成-目标异妖伤害减免),30%×技能基础伤害) -- local arr = RoleManager.Query(function (r) return r.camp == atkRole.camp end) -- local n = 0 -- for i=1, #arr do -- n = n + arr[i]:GetRoleData(RoleDataName.TeamDamageBocusFactor) -- end -- damage = floor(max(damage * (1 + n / #arr - defRole:GetRoleData(RoleDataName.TeamDamageReduceFactor)), 0.3 * damage)) -- end --加入被动效果 local damagingFunc = function(dmgDeduction) damage = damage - dmgDeduction end atkRole.Event:DispatchEvent(BattleEventName.PassiveDamaging, damagingFunc, defRole, damage, skill, dotType, bCrit,damageType, dotType,isDirect) defRole.Event:DispatchEvent(BattleEventName.PassiveBeDamaging, damagingFunc, atkRole, damage, skill, dotType, bCrit) BattleLogic.Event:DispatchEvent(BattleEventName.PassiveDamaging, damagingFunc, atkRole, defRole, damage, skill, dotType, bCrit,damageType, dotType,isDirect) -- 计算护盾减伤 damage = BattleUtil.CalShield(atkRole, defRole, damage,skill) -- 造成的最终伤害 local damagingFunc = function(dmgDeduction) damage = damage - dmgDeduction end atkRole.Event:DispatchEvent(BattleEventName.FinalDamage, damagingFunc, defRole, damage, skill, dotType, bCrit, damageType) defRole.Event:DispatchEvent(BattleEventName.FinalBeDamage, damagingFunc, atkRole, damage, skill, dotType, bCrit, damageType) defRole.Event:DispatchEvent(BattleEventName.FinalBeDamageEnd, damagingFunc, atkRole, damage, skill, dotType, bCrit, damageType,isDirect) BattleLogic.Event:DispatchEvent(BattleEventName.FinalDamage, damagingFunc, atkRole, defRole, damage, skill, dotType, bCrit, damageType) -- return BattleUtil.FinalDamage(skill, atkRole, defRole, damage, bCrit, damageType, dotType,isDirect) end -- 怒气计算 function BattleUtil.CalRage(caster, target, value, countType) -- 角色身上有无敌盾,不扣除怒气 by:wangzhenxing 2020/08/10 14:56 if (countType==3 or countType==4) -- 降怒 and (target.isImmuneReduceRage -- 免疫降怒 或者 有无敌盾 or BattleLogic.BuffMgr:HasBuff(target, BuffName.Shield, function (buff) return buff.shieldType and buff.shieldType == ShieldTypeName.AllReduce end)) then return end local lastRage=target.Rage -- 操作怒气 local deltaRage = target:AddRage(value, countType) BattleLogic.Event:DispatchEvent(BattleEventName.RecordRageChange, caster, target, deltaRage,countType,value,lastRage) -- 用于记录统计 BattleLogic.Event:DispatchEvent(BattleEventName.RecordRage, caster, target, deltaRage) end --检测是否有是金翅大鹏有不灭效果 function BattleUtil.CheckIsNoDead(target) if target then return target.isHaveNoDead or BattleLogic.BuffMgr:HasBuff(target,BuffName.NoDead) end return false end --检测列表是否包含值 function BattleUtil.ChecklistIsContainValue(_list,_value) if _list and _value then for key, value in pairs(_list) do if value ==_value then return true end end end return false end -- 根据id获取额外技能 function BattleUtil.GetExtraSkillbyId(id) if id==1 then return ExtraReleaseSkill.skill1 elseif id==2 then return ExtraReleaseSkill.skill2 elseif id==3 then return ExtraReleaseSkill.skill3 elseif id==4 then return ExtraReleaseSkill.skill4 elseif id==5 then return ExtraReleaseSkill.skill5 elseif id==6 then return ExtraReleaseSkill.skill6 end end function BattleUtil.FinalDamage(skill, atkRole, defRole, damage, bCrit, damageType, dotType,isDirect) -- 灵兽无效 if defRole.type == BattleUnitType.Monster then return end if damage < 0 then damage = 0 end local finalDmg = defRole.data:SubValue(RoleDataName.Hp, damage) if finalDmg >= 0 then if defRole:GetRoleData(RoleDataName.Hp) <= 0 and not defRole:IsDead() then defRole:SetDead(damage) defRole.Event:DispatchEvent(BattleEventName.RoleDead, atkRole) atkRole.Event:DispatchEvent(BattleEventName.RoleKill, defRole,skill) BattleLogic.Event:DispatchEvent(BattleEventName.BattleRoleDead, defRole, atkRole,skill,dotType) end atkRole.Event:DispatchEvent(BattleEventName.RoleDamage, defRole, damage, bCrit, finalDmg, damageType, dotType, skill) defRole.Event:DispatchEvent(BattleEventName.RoleBeDamaged, atkRole, damage, bCrit, finalDmg, damageType, dotType, skill) BattleLogic.Event:DispatchEvent(BattleEventName.RoleDamage, atkRole, defRole, damage, bCrit, finalDmg, damageType, dotType, skill) BattleLogic.Event:DispatchEvent(BattleEventName.RoleBeDamaged, defRole, atkRole, damage, bCrit, finalDmg, damageType, dotType, skill) if bCrit then atkRole.Event:DispatchEvent(BattleEventName.RoleCrit, defRole, damage, bCrit, finalDmg, damageType, skill) defRole.Event:DispatchEvent(BattleEventName.RoleBeCrit, atkRole, damage, bCrit, finalDmg, damageType, skill) end if skill then atkRole.Event:DispatchEvent(BattleEventName.RoleHit, defRole, damage, bCrit, finalDmg, damageType, skill,isDirect) defRole.Event:DispatchEvent(BattleEventName.RoleBeHit, atkRole, damage, bCrit, finalDmg, damageType, skill,isDirect) --如果目标是主燃烧目标 or 目标身上有燃烧效果 if atkRole.curMainTarget==defRole or BattleLogic.BuffMgr:HasBuff(defRole, BuffName.DOT,function(buff) return buff.damageType == 1 end) then atkRole.Event:DispatchEvent(BattleEventName.HitRoleInBurn,skill,defRole) end end --如果不是技能带的伤害,并且是直接伤害就,,,,, --用于处理不触发特性并且是直接伤害的伤害 isDirect 暂时先为bool值,后期可根据需求做修改扩展 by:王振兴 2020/10/12 16:18 if isDirect and not skill then atkRole.Event:DispatchEvent(BattleEventName.RoleHit, defRole, damage, bCrit, finalDmg, damageType, skill,isDirect) defRole.Event:DispatchEvent(BattleEventName.RoleBeHit, atkRole, damage, bCrit, finalDmg, damageType, skill,isDirect) end end -- 战斗记录用 BattleLogic.Event:DispatchEvent(BattleEventName.RecordDamage, atkRole, defRole, damage) -- BattleLogManager.Log( "Final Damage", "acamp", atkRole.camp, "apos", atkRole.position, "tcamp", defRole.camp, "tpos", defRole.position, "damage", damage, "dotType", tostring(dotType) ) return finalDmg end --执行完整的命中,伤害,暴击计算,返回命中,暴击 --skill造成伤害的技能 atkRole攻击者 defRole受击者 damageType伤害类型 baseFactor伤害系数 ignoreDef无视防御参数 dotType是持续伤害类型 function BattleUtil.CalDamage(skill, atkRole, defRole, damageType, baseFactor, ignoreDef, dotType) -- 灵兽无效 if defRole.type == BattleUnitType.Monster then return end -- 判断是否命中 if skill and not skill:CheckTargetIsHit(defRole) then BattleLogic.Event:DispatchEvent(BattleEventName.HitMiss, atkRole, defRole, skill) atkRole.Event:DispatchEvent(BattleEventName.HitMiss, defRole, skill) defRole.Event:DispatchEvent(BattleEventName.BeHitMiss, atkRole, skill) return 0 end -- 如果是队伍技能,计算真实伤害,则damageType为伤害值 if atkRole.isTeam and not defRole:IsDead() then return BattleUtil.ApplyDamage(skill, atkRole, defRole, damageType), false end -- 计算技能额外伤害系数加成 baseFactor = baseFactor or 1 local factorFunc = function(exFactor) baseFactor = baseFactor + exFactor end atkRole.Event:DispatchEvent(BattleEventName.RoleDamageBefore, defRole, factorFunc, damageType, skill) defRole.Event:DispatchEvent(BattleEventName.RoleBeDamagedBefore, atkRole, factorFunc, damageType, skill) baseFactor = BattleUtil.ErrorCorrection(baseFactor) local baseDamage -- 防御(据伤害类型决定) local defence = 0 if damageType == 1 then --1 物理 2 魔法 defence = defRole:GetRoleData(RoleDataName.PhysicalDefence) else defence = defRole:GetRoleData(RoleDataName.MagicDefence) end -- 攻击力 local attack = atkRole:GetRoleData(RoleDataName.Attack) -- 无视防御系数 ignoreDef = 1 - (ignoreDef or 0) -- 基础伤害 = 攻击力 - 防御力 baseDamage = max(attack - BattleUtil.FP_Mul(0.5, defence, ignoreDef), 0) -- 基础伤害增加系数 local addDamageFactor = 1 + atkRole:GetRoleData(RoleDataName.DamageBocusFactor) - defRole:GetRoleData(RoleDataName.DamageReduceFactor) -- 是否暴击: 暴击率 = 自身暴击率 - 对方抗暴率 local bCrit = false local critRandom = Random.Range01() --特殊处理 白骨精附加的普攻不会必定暴击 local mustCrit=atkRole.mustCrit if atkRole.roleId==10091 and skill and skill.type==BattleSkillType.Normal and skill.isAdd then mustCrit=false end local critCondition = clamp(atkRole:GetRoleData(RoleDataName.Crit) - defRole:GetRoleData(RoleDataName.Tenacity), 0, 1) bCrit = critRandom <= critCondition bCrit =mustCrit or bCrit or defRole.isFlagCrit == true -- 必定暴击 -- 计算暴伤害系数 local critDamageFactor = 1 local critDamageReduceFactor = 0 -- 暴击伤害减免 --计算暴击 if bCrit then --加入被动效果 触发暴击被动 local cl = {} local onCritDamageReduceFactor = function(v, ct) if v then table.insert(cl, {v, ct}) end end atkRole.Event:DispatchEvent(BattleEventName.CritDamageReduceFactor, onCritDamageReduceFactor, atkRole, defRole) defRole.Event:DispatchEvent(BattleEventName.CritDamageReduceFactor, onCritDamageReduceFactor, atkRole, defRole) BattleLogic.Event:DispatchEvent(BattleEventName.CritDamageReduceFactor, onCritDamageReduceFactor, atkRole, defRole) critDamageReduceFactor = max(BattleUtil.CountChangeList(critDamageReduceFactor, cl), 0) -- 计算额外暴击伤害 critDamageFactor = 1.3 + atkRole:GetRoleData(RoleDataName.CritDamageFactor) - critDamageReduceFactor --加入被动效果 触发暴击被动 local critFunc = function(critEx) critDamageFactor = critEx end atkRole.Event:DispatchEvent(BattleEventName.PassiveCriting, critFunc,skill) end -- 公式伤害 = 基础伤害 * 基础伤害系数 * 增伤系数 * 爆伤系数 local fixDamage = floor(BattleUtil.FP_Mul(baseDamage, baseFactor, addDamageFactor, critDamageFactor)) -- 公式计算完成 local damageFunc = function(damage) fixDamage = damage end atkRole.Event:DispatchEvent(BattleEventName.RoleDamageAfter, defRole, damageFunc, fixDamage,skill) defRole.Event:DispatchEvent(BattleEventName.RoleBeDamagedAfter, atkRole, damageFunc, fixDamage) fixDamage = max(floor(attack * 0.1), fixDamage) local finalDmg = 0 --计算实际造成的扣血 if not defRole:IsRealDead() then finalDmg = BattleUtil.ApplyDamage(skill, atkRole, defRole, fixDamage, bCrit, damageType, dotType) end return finalDmg, bCrit end function BattleUtil.CalTreat(castRole, targetRole, value, baseFactor,skill) -- 灵兽无效 if targetRole.type == BattleUnitType.Monster then return end BattleLogic.Event:DispatchEvent(BattleEventName.DisposeRoleCtrl_noheal, castRole,targetRole) if targetRole.ctrl_noheal or targetRole:IsDead() then --禁疗和死亡无法加血 --禁疗并且没有死亡的单位显示血量+0 不走后面代码,防止触发后面的被动 by:王振兴 2021/1/27 if targetRole.ctrl_noheal and not targetRole:IsDead() then targetRole.Event:DispatchEvent(BattleEventName.RoleBeTreated, castRole, 0, 0) end return end -- 是否暴击: 暴击率 = 自身暴击率 - 对方抗暴率 local bCrit = false local critRandom = Random.Range01() local critCondition = castRole:GetRoleData(RoleDataName.Crit) bCrit = critRandom <= critCondition bCrit = bCrit or targetRole.isFlagCrit == true -- 必定暴击 -- 计算暴伤害系数 local critDamageFactor = 1 --计算暴击 if bCrit then --伤害有个+1.3 不知道干什么用的就给去了 by:wangxhenxing 2020/10/10 18:46 critDamageFactor = 1.3 + castRole:GetRoleData(RoleDataName.CritDamageFactor) end -- 基础伤害增加系数 local addDamageFactor = 1 + castRole:GetRoleData(RoleDataName.DamageBocusFactor) targetRole.Event:DispatchEvent(BattleEventName.RoleBeHealed, castRole) BattleUtil.ApplyTreat(castRole, targetRole, value, baseFactor,critDamageFactor,addDamageFactor,skill) end function BattleUtil.ApplyTreat(castRole, targetRole, value, baseFactor,critDamageFactor,addDamageFactor,skill) -- 灵兽无效 if targetRole.type == BattleUnitType.Monster then return end BattleLogic.Event:DispatchEvent(BattleEventName.DisposeRoleCtrl_noheal, castRole,targetRole) if targetRole.ctrl_noheal or targetRole:IsDead() then --禁疗和死亡无法加血 --禁疗并且没有死亡的单位显示血量+0 不走后面代码,防止触发后面的被动 by:王振兴 2021/1/27 if targetRole.ctrl_noheal and not targetRole:IsDead() then targetRole.Event:DispatchEvent(BattleEventName.RoleBeTreated, castRole, 0, 0) end return end baseFactor = baseFactor or 1 local maxHp = targetRole:GetRoleData(RoleDataName.MaxHp) local hp = targetRole:GetRoleData(RoleDataName.Hp) -- 计算被动对治疗系数的影响 local treatFactorFunc = function(df, dt) baseFactor = BattleUtil.CountValue(baseFactor, df, dt) end castRole.Event:DispatchEvent(BattleEventName.PassiveTreatingFactor, treatFactorFunc, targetRole,skill) targetRole.Event:DispatchEvent(BattleEventName.PassiveBeTreatedFactor, treatFactorFunc, castRole) local factor = castRole.isTeam and 1 or castRole:GetRoleData(RoleDataName.TreatFacter) --释放者为team则不计算治疗加成属性 local factor2 = targetRole:GetRoleData(RoleDataName.CureFacter) local baseTreat = BattleUtil.FP_Mul(value, baseFactor, factor, factor2,critDamageFactor,addDamageFactor) --加入被动效果 local cl = {} local function treatingFunc(v, ct) if v then table.insert(cl, {v, ct}) end end -- local treatingFunc = function(exFactor) baseTreat = floor(baseTreat * (exFactor + 1) + 0.5) end castRole.Event:DispatchEvent(BattleEventName.PassiveTreating, treatingFunc, targetRole) targetRole.Event:DispatchEvent(BattleEventName.PassiveBeTreated, treatingFunc, castRole) baseTreat = BattleUtil.CountChangeList(baseTreat, cl) -- 取整 local baseTreat = floor(baseTreat + 0.5) local treat = min(baseTreat, maxHp - hp) if treat > 0 then targetRole.data:AddValue(RoleDataName.Hp, treat) end castRole.Event:DispatchEvent(BattleEventName.RoleTreat, targetRole, treat, baseTreat) targetRole.Event:DispatchEvent(BattleEventName.RoleBeTreated, castRole, treat, baseTreat) --添加发送到battleLogic的治疗消息,用于计算总的战斗伤害值 BattleLogic.Event:DispatchEvent(BattleEventName.RoleBeTreated, castRole, treat, baseTreat) -- 战斗记录用 BattleLogic.Event:DispatchEvent(BattleEventName.RecordTreat, castRole, targetRole, baseTreat) BattleLogManager.Log( "Final Treat", "acamp", castRole.camp, "apos", castRole.position, "tcamp", targetRole.camp, "tpos", targetRole.position, "value", value ) end -- 检测命中 function BattleUtil.CheckIsHit(atkRole, defRole,skill) -- 是否命中: 命中 = 自身命中率 - 对方闪避率 local isHit = false local mustHit = atkRole.mustHit --特殊处理 白骨精附加的普攻不会必定暴击 if atkRole.roleId==10091 and skill and skill.type==BattleSkillType.Normal and skill.isAdd then mustHit=false end local hitRandom = Random.Range01() local hitCondition = clamp(atkRole:GetRoleData(RoleDataName.Hit) - defRole:GetRoleData(RoleDataName.Dodge), 0, 1) isHit = hitRandom <= hitCondition return mustHit or isHit end --获取table的长度 function BattleUtil.LengthOfTable(table) if not table then return 0 end local length = 0 for i, v in pairs(table) do length = length + 1 end return length end function BattleUtil.RandomAction(rand, action) if Random.Range01() <= rand and action then action() return true end return false end -- function BattleUtil.RandomControl(rand, ctrl, caster, target, round) local cl = {} local function _CallBack(v, ct) if v then table.insert(cl, {v, ct}) end end caster.Event:DispatchEvent(BattleEventName.PassiveRandomControl, _CallBack, ctrl, target) target.Event:DispatchEvent(BattleEventName.PassiveBeRandomControl, _CallBack, ctrl, target) rand = BattleUtil.CountChangeList(rand, cl) local buff = Buff.Create(caster, BuffName.Control, round, ctrl) local isAdd=BattleUtil.RandomAction(rand, function() target:AddBuff(buff) end) if not isAdd then BattleLogic.Event:DispatchEvent(BattleEventName.RoleAddBuffFail,buff) end return isAdd end -- function BattleUtil.RandomDot(rand, dot, caster, target, round, interval, damage) local cl = {} local dcl = {} local function _CallBack(v, ct, dv, dct) if v then table.insert(cl, {v, ct}) end if dv then table.insert(dcl, {dv, dct}) end end caster.Event:DispatchEvent(BattleEventName.PassiveRandomDot, _CallBack, dot) target.Event:DispatchEvent(BattleEventName.PassiveBeRandomDot, _CallBack, dot) rand = BattleUtil.CountChangeList(rand, cl) damage = floor(BattleUtil.CountChangeList(damage, dcl)) return BattleUtil.RandomAction(rand, function() local buff = Buff.Create(caster, BuffName.DOT, round, interval, dot, damage) buff.isRealDamage = true target:AddBuff(buff) 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.Sort(arr, comp) if #arr <= 1 then return arr end for i=1, #arr do for j = #arr, i+1, -1 do if comp(arr[j-1], arr[j]) then arr[j-1], arr[j] = arr[j], arr[j-1] end end end return arr 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) end -- 计算数值 function BattleUtil.CountValue(v1, v2, ct) local v = v1 if ct == 1 then --加算 v = v + v2 elseif ct == 2 then --乘加算(百分比属性加算) v = v * (1 + v2) elseif ct == 3 then --减算 v = v - v2 elseif ct == 4 then --乘减算(百分比属性减算) v = v * (1 - v2) elseif ct == 5 then -- 覆盖 v = v2 end -- 做一个正确性检测 -- v = BattleUtil.ErrorCorrection(v) return v end -- 计算数值改变 function BattleUtil.CountChangeList(v, changeList) local aplist = {} local splist = {} local cplist = {} local fv = v -- 先算绝对值 for _, change in ipairs(changeList) do local cv = change[1] local ct = change[2] if ct then if ct == 1 or ct == 3 then fv = BattleUtil.CountValue(fv, cv, ct) elseif ct == 2 then table.insert(aplist, change) elseif ct == 4 then table.insert(splist, change) elseif ct == 5 then table.insert(cplist, change) end end end -- 加乘(对基数进行加乘) for _, change in ipairs(aplist) do local cv = change[1] local ct = change[2] fv = fv + (BattleUtil.CountValue(v, cv, ct) - v) end -- 减乘(对最终数值进行减乘算) for _, change in ipairs(splist) do local cv = change[1] local ct = change[2] fv = BattleUtil.CountValue(fv, cv, ct) end -- 覆盖 for _, change in ipairs(cplist) do local cv = change[1] local ct = change[2] fv = BattleUtil.CountValue(fv, cv, ct) end return fv end -- 检测技能伤害治疗加乘 function BattleUtil.CheckSkillDamageHeal(f, caster, target) local cl = {} local function _CallBack(v, ct) if v then table.insert(cl, {v, ct}) end end caster.Event:DispatchEvent(BattleEventName.PassiveSkillDamageHeal, _CallBack) target.Event:DispatchEvent(BattleEventName.PassiveBeSkillDamageHeal, _CallBack) f = BattleUtil.CountChangeList(f, cl) return f end -- 检测技能伤害治疗加乘 function BattleUtil.CheckSeckill(bf, kf, caster, target) local bcl = {} local kcl = {} local function _CallBack(bv, bct, kv, kct) if bv and bct then table.insert(bcl, {bv, bct}) end if kv and kct then table.insert(kcl, {kv, kct}) end end caster.Event:DispatchEvent(BattleEventName.PassiveSeckill, _CallBack) target.Event:DispatchEvent(BattleEventName.PassiveBeSeckill, _CallBack) bf = BattleUtil.CountChangeList(bf, bcl) kf = BattleUtil.CountChangeList(kf, kcl) return bf, kf end -- 获取位置类型 -- 1 前排 -- 2 后排 function BattleUtil.GetRolePosType(pos) if pos <= 3 then return 1 elseif pos > 3 then return 2 end end -- 根据位置类型获取数据 function BattleUtil.GetRoleListByPosType(camp, posType) if posType == 1 then return RoleManager.Query(function (r) return r.camp == camp and r.position <= 3 end) elseif posType == 2 then return RoleManager.Query(function (r) return r.camp == camp and r.position > 3 end) end end -- 通用增加属性的方法 function BattleUtil.AddProp(role, prop, value, ct) if ct == 1 then --加算 role.data:AddValue(BattlePropList[prop], value) elseif ct == 2 then --乘加算(百分比属性加算) role.data:AddPencentValue(BattlePropList[prop], value) elseif ct == 3 then --减算 role.data:SubValue(BattlePropList[prop], value) elseif ct == 4 then --乘减算(百分比属性减算) role.data:SubPencentValue(BattlePropList[prop], value) end end -- 比较值(默认返回true) -- 0:不比较返回默认true -- 1:大于 -- 2:小于 -- 3:等于 -- 4:大于等于 -- 5:小于等于 function BattleUtil.CompareValue(v1, v2, comType) if comType == 1 then return v1 > v2 elseif comType == 2 then return v1 < v2 elseif comType == 3 then return v1 == v2 elseif comType == 4 then return v1 >= v2 elseif comType == 5 then return v1 <= v2 end return true end