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 if BattleLogic.IsOpenBattleRecord then BattleLogic.RecordDamage({...}) end return f end function BattleUtil.ChooseTarget(role, chooseId) local chooseType = floor(chooseId / 10000) % 10 local chooseWeight = floor(chooseId / 100) % 10 local sort = floor(chooseId / 10) % 10 local num = chooseId % 10 local arr if chooseType == 1 then arr = BattleLogic.Query(function (r) return r.camp == role.camp end) elseif chooseType == 2 then if role.lockTarget and not role.lockTarget.isDead and num == 1 then --嘲讽时对单个敌军生效 return {role.lockTarget} end arr = BattleLogic.Query(function (r) return r.camp ~= role.camp end) elseif chooseType == 3 then if role.ctrl_blind then --致盲时自身变随机友军 arr = BattleLogic.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.isDead then --嘲讽时对仇恨目标生效 return {role.lockTarget} end if role.ctrl_blind then --致盲时仇恨目标变随机 arr = BattleLogic.Query(function (r) return r.camp ~= role.camp end) BattleUtil.RandomList(arr) return {arr[1]} end return {BattleLogic.GetAggro(role.camp)} else arr = BattleLogic.Query() end if chooseWeight == 0 or role.ctrl_blind then --致盲时排序无效 BattleUtil.RandomList(arr) elseif chooseWeight == 1 then BattleUtil.Sort(arr, function(a, b) local r1 = a:GetRoleData(RoleDataName.Hp) local r2 = b:GetRoleData(RoleDataName.Hp) if sort == 1 then return r1 > r2 else return r1 < r2 end end) elseif chooseWeight == 2 then 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) elseif chooseWeight == 3 then BattleUtil.Sort(arr, function(a, b) local r1 = a:GetRoleData(RoleDataName.Attack) local r2 = b:GetRoleData(RoleDataName.Attack) if sort == 1 then return r1 > r2 else return r1 < r2 end end) elseif chooseWeight == 4 then BattleUtil.Sort(arr, function(a, b) local r1 = a:GetRoleData(RoleDataName.PhysicalDefence) local r2 = b:GetRoleData(RoleDataName.PhysicalDefence) if sort == 1 then return r1 > r2 else return r1 < r2 end end) elseif chooseWeight == 5 then BattleUtil.Sort(arr, function(a, b) local r1 = a:GetRoleData(RoleDataName.PhysicalDefence) local r2 = b:GetRoleData(RoleDataName.PhysicalDefence) if sort == 1 then return r1 > r2 else return r1 < r2 end end) elseif chooseWeight == 6 then BattleUtil.Sort(arr, function(a, b) local r1 = a:GetRoleData(RoleDataName.MagicDefence) local r2 = b:GetRoleData(RoleDataName.MagicDefence) if sort == 1 then return r1 > r2 else return r1 < r2 end end) elseif chooseWeight == 7 then BattleUtil.Sort(arr, function(a, b) local r1 = a:GetSkillCD() local r2 = b:GetSkillCD() if sort == 1 then return r1 > r2 else return r1 < r2 end end) end return arr 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.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.CalShield(atkRole, defRole, damage) for i=1, defRole.shield.size do local buff = defRole.shield.buffer[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 return damage end function BattleUtil.ApplyDamage(atkRole, defRole, damage, bCrit, damageType, isDot) bCrit = bCrit or false damageType = damageType or 0 isDot = isDot or false if atkRole.isTeam then --max(技能基础伤害*(1+已方异妖伤害加成-目标异妖伤害减免),30%×技能基础伤害) local arr = BattleLogic.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) defRole.Event:DispatchEvent(BattleEventName.PassiveBeDamaging, damagingFunc, atkRole, damage) if damage > 0 then local finalDmg = defRole.data:SubValue(RoleDataName.Hp, damage) if finalDmg > 0 then if defRole:GetRoleData(RoleDataName.Hp) <= 0 then defRole.isDead = true BattleLogic.BuffMgr:ClearBuff(defRole) defRole.Event:DispatchEvent(BattleEventName.RoleDead) BattleLogic.Event:DispatchEvent(BattleEventName.BattleRoleDead, defRole) if defRole.camp == 1 then BattleLogic.WaitForTrigger(1, function () BattleLogic.Event:DispatchEvent(BattleEventName.ZoomChange, BattleLogic.GetAggro(0), 1) end) end end atkRole.Event:DispatchEvent(BattleEventName.RoleDamage, defRole, damage, bCrit, finalDmg, damageType) defRole.Event:DispatchEvent(BattleEventName.RoleBeDamaged, atkRole, damage, bCrit, finalDmg, damageType) if bCrit then atkRole.Event:DispatchEvent(BattleEventName.RoleCrit, defRole, damage, bCrit, finalDmg, damageType) defRole.Event:DispatchEvent(BattleEventName.RoleBeCrit, atkRole, damage, bCrit, finalDmg, damageType) end if not isDot then atkRole.Event:DispatchEvent(BattleEventName.RoleHit, defRole, damage, bCrit, finalDmg, damageType) defRole.Event:DispatchEvent(BattleEventName.RoleBeHit, atkRole, damage, bCrit, finalDmg, damageType) end end return finalDmg else return damage end end --执行完整的命中,伤害,暴击计算,返回命中,暴击 --atkRole攻击者 defRole受击者 damageType伤害类型 baseFactor伤害系数 ignoreDef无视防御参数 isDot是否是dot function BattleUtil.CalDamage(atkRole, defRole, damageType, baseFactor, ignoreDef, isDot) if atkRole.isTeam and not defRole.isDead then --如果是队伍技能,计算真实伤害,则damageType为伤害值 return BattleUtil.ApplyDamage(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) defRole.Event:DispatchEvent(BattleEventName.RoleBeDamagedBefore, atkRole, factorFunc, damageType) local bCrit = false local baseDamage ignoreDef = 1 - (ignoreDef or 0) bCrit = Random.Range01() <= clamp(atkRole:GetRoleData(RoleDataName.Crit)-defRole:GetRoleData(RoleDataName.Tenacity), 0, 1) 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) --计算暴击 if bCrit or defRole.isFlagCrit then local critDamageFactor = atkRole:GetRoleData(RoleDataName.CritDamageFactor) --加入被动效果 local critFunc = function(critEx) critDamageFactor = critEx end atkRole.Event:DispatchEvent(BattleEventName.PassiveCriting, critFunc) baseDamage = max(BattleUtil.FP_Mul(attack, critDamageFactor) - BattleUtil.FP_Mul(0.5, defence, ignoreDef), 0) else baseDamage = max(attack - BattleUtil.FP_Mul(0.5, defence, ignoreDef), 0) end local elementDamageReduceFactor = RoleDataName.FireDamageReduceFactor if atkRole.element == 1 then elementDamageReduceFactor = RoleDataName.FireDamageReduceFactor elseif atkRole.element == 2 then elementDamageReduceFactor = RoleDataName.WindDamageReduceFactor elseif atkRole.element == 3 then elementDamageReduceFactor = RoleDataName.IceDamageReduceFactor elseif atkRole.element == 4 then elementDamageReduceFactor = RoleDataName.LandDamageReduceFactor elseif atkRole.element == 5 then elementDamageReduceFactor = RoleDataName.LightDamageReduceFactor elseif atkRole.element == 6 then elementDamageReduceFactor = RoleDataName.DarkDamageReduceFactor end --伤害 =(基础伤害*(1+己伤害加成-目标伤害减免)*(1+己方属性伤害加成-目标属性伤害减免),10%*己攻) baseDamage = BattleUtil.FP_Mul(baseDamage, baseFactor, 1 + atkRole:GetRoleData(RoleDataName.DamageBocusFactor) - defRole:GetRoleData(RoleDataName.DamageReduceFactor), (1 + atkRole:GetRoleData(RoleDataName.ElementDamageBocusFactor) - defRole:GetRoleData(elementDamageReduceFactor))) baseDamage = floor(max(baseDamage, 0.1 * attack)) local func for i=1, atkRole.exCalDmgList.size do func = atkRole.exCalDmgList.buffer[i] baseDamage = func(baseDamage) end baseDamage = BattleUtil.CalShield(atkRole, defRole, baseDamage) local finalDmg = 0 --计算实际造成的扣血 if not defRole.isDead then finalDmg = BattleUtil.ApplyDamage(atkRole, defRole, baseDamage, bCrit, damageType, isDot) end return finalDmg, bCrit end function BattleUtil.CalTreat(castRole, targetRole, value, baseFactor) if targetRole.ctrl_noheal or targetRole.isDead then --禁疗和死亡无法加血 return end targetRole.Event:DispatchEvent(BattleEventName.RoleBeHealed, castRole) BattleUtil.ApplyTreat(castRole, targetRole, value, baseFactor) end function BattleUtil.ApplyTreat(castRole, targetRole, value, baseFactor) baseFactor = baseFactor or 1 local maxHp = targetRole:GetRoleData(RoleDataName.MaxHp) local hp = targetRole:GetRoleData(RoleDataName.Hp) local factor = castRole.isTeam and 1 or castRole:GetRoleData(RoleDataName.TreatFacter) --释放者为team则不计算治疗加成属性 local factor2 = targetRole:GetRoleData(RoleDataName.CureFacter) local baseTreat = floor(BattleUtil.FP_Mul(value, baseFactor, factor, factor2) + 0.5) --加入被动效果 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) local treat = min(baseTreat, maxHp - hp) if treat > 0 then targetRole.data:AddValue(RoleDataName.Hp, treat) castRole.Event:DispatchEvent(BattleEventName.RoleTreat, targetRole, treat) targetRole.Event:DispatchEvent(BattleEventName.RoleBeTreated, castRole, treat) end 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.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