--公式计算器 local Expression = require("Infrast/Expression") local TablePool = require("Infrast/TablePool") local AttrSystem = require "Battle/Logic/Entity/System/AttrSystem" local BattleEventSystem = require"Battle/Logic/Event/BattleEventSystem" local EventSystem = require("Event/EventSystem") local COMMON_NO_PSEFFECT_HEAL_BUFF = 200032 local HurtFormulaStep = LuaConst.HurtFormulaStepEnum local EDamageFactorReasonType = LuaConst.EDamageFactorReasonType local rawget = rawget local rawset = rawset local assert = assert local pcall = pcall local pairs = pairs local ipairs = ipairs local type = type local next = next local setmetatable = setmetatable local LuaConst = LuaConst local FP = FP local FP_One = FP.Const.One local FP_Zero = FP.Const.Zero local FPConst = FP.Const local newV1 = FP.newV1 local tonumberV1 = FP.tonumberV1 local FormulaCalculator = {} local private = { --战力压制信息缓存列表 GsSubjugateCache = {}, --PVP缓存 PVEGsSubjugateCache = {}, --PVE缓存 EVPGsSubjugateCache = {} --EVP缓存 } local Const_NOBuff = -1 local Const_Normal = "N" local Const_MusouNormal = "MN" local Const_NormalAtkCompear = newV1(1.111) local Const_LowAtkRate = newV1(0.1) local Const_CritParam_c_reciprocal = newV1(0.1) --10 的倒数 local Const_CritParam_a = newV1(4000) --暴击率的参数 a local Const_CritParam_b = newV1(4600) --暴击率的参数 b local Const_CritParam_M = newV1(0.8) --暴击率的参数 M local Const_CritParam_N = newV1(0) --暴击率的参数 N local Const_Crit_Max = newV1(0.8) local Const_Crit_Min = newV1(0) local Const_CritEffParam_c_reciprocal = newV1(0.1) --暴击效果的参数 10 的倒数 local Const_CritEffParam_a = newV1(2150) --暴击效果的参数 a local Const_CritEffParam_b = newV1(3600) --暴击效果的参数 b local Const_CritEffParam_M = newV1(3) --暴击效果的参数 M local Const_CritEffParam_N = newV1(1.2) --暴击效果的参数 N local Const_CritEff_Max = newV1(3) local Const_CritEff_Min = newV1(1.2) local Const_ParryParam_c_reciprocal = newV1(0.1) --格挡率的参数 10 的倒数 local Const_ParryParam_a = newV1(4000) --格挡率的参数 a local Const_ParryParam_b = newV1(4600) --格挡率的参数 b local Const_ParryParam_M = newV1(0.4) --格挡率的参数 M local Const_ParryParam_N = newV1(0) --格挡率的参数 N local Const_Parry_Max = newV1(0.4) local Const_Parry_Min = newV1(0) local Const_ParryEffParam_c_reciprocal = newV1(0.1) --格挡效果的参数 10 的倒数 local Const_ParryEffParam_a = newV1(1900) --格挡效果的参数 a local Const_ParryEffParam_b = newV1(2400) --格挡效果的参数 b local Const_ParryEffParam_M = newV1(0.8) --格挡效果的参数 M local Const_ParryEffParam_N = newV1(0.15) --格挡效果的参数 N local Const_ParryEff_Max = newV1(0.8) local Const_ParryEff_Min = newV1(0.15) local PVP_SUBJUGATE_RANGE_MAX = nil --pvp强度差值最大值 local PVP_SUBJUGATE_RANGE_MIN = nil --pvp强度差值最小值 local PVP_SUBJUGATE_LIMIT = nil --pvp属性压制系数最大值 local OP_SUBJUGATE_FACTOR function FormulaCalculator.Init() if not FormulaCalculator.isInited then FormulaCalculator.isInited = true FormulaCalculator.InitConst() end end function FormulaCalculator.InitConst() FormulaCalculator.isInited = true Const_CritParam_a:Reset(DataSheetManager.ConstData:GetDataByID("Crit_A").FloatValue) Const_CritParam_b:Reset(DataSheetManager.ConstData:GetDataByID("Crit_B").FloatValue) Const_CritParam_c_reciprocal:Reset(1 / DataSheetManager.ConstData:GetDataByID("Crit_C").FloatValue) Const_CritParam_M:Reset(DataSheetManager.ConstData:GetDataByID("Crit_M").FloatValue) Const_CritParam_N:Reset(DataSheetManager.ConstData:GetDataByID("Crit_N").FloatValue) Const_Crit_Max:Reset(DataSheetManager.ConstData:GetDataByID("Crit_Max").FloatValue) Const_Crit_Min:Reset(DataSheetManager.ConstData:GetDataByID("Crit_Min").FloatValue) Const_CritEffParam_a:Reset(DataSheetManager.ConstData:GetDataByID("CritEff_A").FloatValue) Const_CritEffParam_b:Reset(DataSheetManager.ConstData:GetDataByID("CritEff_B").FloatValue) Const_CritEffParam_c_reciprocal:Reset(1 / DataSheetManager.ConstData:GetDataByID("CritEff_C").FloatValue) Const_CritEffParam_M:Reset(DataSheetManager.ConstData:GetDataByID("CritEff_M").FloatValue) Const_CritEffParam_N:Reset(DataSheetManager.ConstData:GetDataByID("CritEff_N").FloatValue) Const_CritEff_Max:Reset(DataSheetManager.ConstData:GetDataByID("CritEff_Max").FloatValue) Const_CritEff_Min:Reset(DataSheetManager.ConstData:GetDataByID("CritEff_Min").FloatValue) Const_ParryParam_a:Reset(DataSheetManager.ConstData:GetDataByID("Parry_A").FloatValue) Const_ParryParam_b:Reset(DataSheetManager.ConstData:GetDataByID("Parry_B").FloatValue) Const_ParryParam_c_reciprocal:Reset(1 / DataSheetManager.ConstData:GetDataByID("Parry_C").FloatValue) Const_ParryParam_M:Reset(DataSheetManager.ConstData:GetDataByID("Parry_M").FloatValue) Const_ParryParam_N:Reset(DataSheetManager.ConstData:GetDataByID("Parry_N").FloatValue) Const_Parry_Max:Reset(DataSheetManager.ConstData:GetDataByID("Parry_Max").FloatValue) Const_Parry_Min:Reset(DataSheetManager.ConstData:GetDataByID("Parry_Min").FloatValue) Const_ParryEffParam_a:Reset(DataSheetManager.ConstData:GetDataByID("ParryEff_A").FloatValue) Const_ParryEffParam_b:Reset(DataSheetManager.ConstData:GetDataByID("ParryEff_B").FloatValue) Const_ParryEffParam_c_reciprocal:Reset(1 / DataSheetManager.ConstData:GetDataByID("ParryEff_C").FloatValue) Const_ParryEffParam_M:Reset(DataSheetManager.ConstData:GetDataByID("ParryEff_M").FloatValue) Const_ParryEffParam_N:Reset(DataSheetManager.ConstData:GetDataByID("ParryEff_N").FloatValue) Const_ParryEff_Max:Reset(DataSheetManager.ConstData:GetDataByID("ParryEff_Max").FloatValue) Const_ParryEff_Min:Reset(DataSheetManager.ConstData:GetDataByID("ParryEff_Min").FloatValue) OP_SUBJUGATE_FACTOR = newV1(1) OP_SUBJUGATE_FACTOR:Add(DataSheetManager.ConstData:GetDataByID("OfficialSubjugateRate").FloatValue) PVP_SUBJUGATE_RANGE_MAX = newV1(0):Reset(DataSheetManager.ConstData:GetDataByID("PVPSubjugateLimit").FloatValue) PVP_SUBJUGATE_RANGE_MIN = newV1(0):Sub(PVP_SUBJUGATE_RANGE_MAX) PVP_SUBJUGATE_LIMIT = newV1(0):Reset(DataSheetManager.ConstData:GetDataByID("PVPSubjugateRange").FloatValue) end FormulaCalculator.Init() local Common_RateDeltaParam = newV1(-1000) local _tempCommonV1_1 = newV1(0) local _tempCommonV1_2 = newV1(0) local _tempResultV1 = newV1(0) local _hurtResultV1 = newV1(0) local _hurtRealDeltaV1 = newV1(0) --战斗计算公式环境 local CalcEnv = { currAttrCalc = nil, --属性别名 EntityAttrMT = { __index = function(t, k) return rawget(t._attr, k) or rawget(t._attr.AttrInfo, k) end, __newindex = function(t, k, v) error('use add/sub/mul/div to modify attributes in expression:'..k) end }, --数学计算 math = { min = function(a, b) if(type(a) == "number") then a = newV1(a) end if(type(b) == "number") then b = newV1(b) end return FP.Math.Min(a,b) end, max = function(a, b) if(type(a) == "number") then a = newV1(a) end if(type(b) == "number") then b = newV1(b) end return FP.Math.Max(a,b) end, }, } --表示式接口 function CalcEnv.add(...) return CalcEnv.currAttrCalc:Add(...) end function CalcEnv.sub(...) return CalcEnv.currAttrCalc:Sub(...) end function CalcEnv.mul(...) return CalcEnv.currAttrCalc:Mul(...) end function CalcEnv.div(...) return CalcEnv.currAttrCalc:Div(...) end function CalcEnv.hasBuff(...) return CalcEnv.currAttrCalc:HasBuff(...) end function CalcEnv.missileHitCountToNHurt(...) return CalcEnv.currAttrCalc:SetMissiltHitCountRate(...) end --环境的缓存池 CalcEnv.ExpEnvPool = TablePool( function(env, buffID, opEntity, aimEntity, opAttr, aimAttr) if env then rawset(env.op.attr, "_attr", opAttr) rawset(env.aim.attr, "_attr", aimAttr) else env = { --数学库 m = CalcEnv.math, -- 环境常量 hp = "hp", am = "am", sa = "sa", pc = "pc", -- 施法者 op = { attr = setmetatable({ _attr = opAttr }, CalcEnv.EntityAttrMT), --添加表达式接口 add = CalcEnv.add, sub = CalcEnv.sub, mul = CalcEnv.mul, div = CalcEnv.div, hasBuff = CalcEnv.hasBuff, }, -- 受法者 aim = { attr = setmetatable({ _attr = aimAttr }, CalcEnv.EntityAttrMT), --添加表达式接口 add = CalcEnv.add, sub = CalcEnv.sub, mul = CalcEnv.mul, div = CalcEnv.div, hasBuff = CalcEnv.hasBuff, }, -- 子弹撞击数改变一般伤害公式的子弹攻击倍率 missileHitCountToNHurt = CalcEnv.missileHitCountToNHurt, } --所有属性都添加到环境里去 for k, v in pairs(LuaConst.AttrType) do env[k] = k end end return env end, function(env) rawset(env.op.attr, "_attr", nil) rawset(env.aim.attr, "_attr", nil) end ) --属性计算相关接口 local AttrCalc = {} AttrCalc.__index = AttrCalc ------------- ↓一次性伤害计算参数↓------------------------------------------------------------ -- 一次性伤害计算系数都只会生效一次伤害计算,然后就被reset。通常搭配 local MAX_DAMAGE_FACTOR = FP.newV1(192) --最大伤害系数监控,稳定后可以删除 local MAX_FINAL_DAMAGE_FACTOR = FP.newV1(3) --最大伤害系数监控,稳定后可以删除 --叠加伤害系数 function AttrCalc:PileDamageFactor(factor, ...) if self.dmgFactor then self.dmgFactor = self.dmgFactor:Mul(factor) else if type(factor) == "number" then factor = newV1(factor) else factor = factor:cloneV1() end self.dmgFactor = factor end if self.dmgFactor > MAX_DAMAGE_FACTOR then logging.error(LTAG.ERROR, "HYW : 警告! 伤害系数过大,当前值 : ", self.dmgFactor) end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_13, factor, ...) end function AttrCalc:PileFinalDamageFactor(factor) if self.finalDmgFactor then self.finalDmgFactor = self.finalDmgFactor:Mul(factor) else if type(factor) == "number" then factor = newV1(factor) else factor = factor:cloneV1() end self.finalDmgFactor = factor end if self.finalDmgFactor > MAX_FINAL_DAMAGE_FACTOR then logging.error(LTAG.ERROR, "HYW : 警告! 伤害系数过大,当前值 : ", self.finalDmgFactor) end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_PileFinalDmgFactor, factor, self.finalDmgFactor) end function AttrCalc:PileAmFactor(factor) if self.amFactor then self.amFactor = self.amFactor:Mul(factor) else if type(factor) == "number" then factor = newV1(factor) else factor = factor:cloneV1() end self.amFactor = factor end end --仅跳过减疗 function AttrCalc:SkipNegBehealEff() self.skipNegBehealEff = true end function AttrCalc:PileHealFactor(factor) if self.healFactor then self.healFactor = self.healFactor:Mul(factor) else if type(factor) == "number" then factor = newV1(factor) else factor = factor:cloneV1() end self.healFactor = factor end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_PileHealFactor, factor, self.healFactor) end function AttrCalc:PilePCLossFactor(factor) if self.pcLossFactor then self.pcLossFactor = self.pcLossFactor:Mul(factor) else if type(factor) == "number" then factor = newV1(factor) else factor = factor:cloneV1() end self.pcLossFactor = factor end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_PilePCLossFactor, factor, self.pcLossFactor) end --叠加格挡强度比例(加法) function AttrCalc:PileParryEffRatioPlus(ratio) if self.parryEffRatioPlus then self.parryEffRatioPlus = self.parryEffRatioPlus:Add(ratio) else if type(ratio) == "number" then ratio = newV1(ratio) else ratio = ratio:cloneV1() end self.parryEffRatioPlus = ratio end -- if self.parryEffRatioPlus > MAX_antiParry_FACTOR then -- logging.error(LTAG.ERROR, "HYW : 警告! antiParry系数过大,当前值 : ", self.parryEffRatioPlus) -- end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_PileParryEffRatioPlus, ratio, self.parryEffRatioPlus) end --叠加破击强度比例(减法) function AttrCalc:PileAntiParryEffRatioPlus(ratio) if self.parryEffRatioPlus then self.parryEffRatioPlus = self.parryEffRatioPlus:Sub(ratio) else if type(ratio) == "number" then ratio = newV1(-ratio) else ratio = ratio:cloneV1() ratio:Mul(-1) end self.parryEffRatioPlus = ratio end -- if self.parryEffRatioPlus > MAX_antiParry_FACTOR then -- logging.error(LTAG.ERROR, "HYW : 警告! antiParry系数过大,当前值 : ", self.parryEffRatioPlus) -- end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_PileAntiParryEffRatioPlus, ratio, self.parryEffRatioPlus) end --叠加格挡率(加法) function AttrCalc:PileParryRatePlus(plus) if self.parryRatePlus then self.parryRatePlus = self.parryRatePlus:Add(plus) else if type(plus) == "number" then plus = newV1(plus) else plus = plus:cloneV1() end self.parryRatePlus = plus end -- if self.parryRatePlus > MAX_parryRate_PLUS then -- logging.error(LTAG.ERROR, "HYW : 警告! parryRate附加过大,当前值 : ", self.parryRatePlus) -- end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_PileParryRatePlus, plus, self.parryRatePlus) end --叠加破击率(减法) function AttrCalc:PileAntiParryRatePlus(plus) if self.parryRatePlus then self.parryRatePlus = self.parryRatePlus:Sub(plus) else if type(plus) == "number" then plus = newV1(-plus) else plus = plus:cloneV1() plus:Mul(-1) end self.parryRatePlus = plus end -- if self.parryRatePlus > MAX_antiParryRate_PLUS then -- logging.error(LTAG.ERROR, "HYW : 警告! antiParryRate附加过大,当前值 : ", self.parryRatePlus) -- end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_PileAntiParryRatePlus, plus, self.parryRatePlus) end --叠加暴击率(加法) function AttrCalc:PileCritRatePlus(plus) if self.critRatePlus then self.critRatePlus = self.critRatePlus:Add(plus) else if type(plus) == "number" then plus = newV1(plus) else plus = plus:cloneV1() end self.critRatePlus = plus end -- if self.critRatePlus > MAX_critRate_PLUS then -- logging.error(LTAG.ERROR, "HYW : 警告! critRate附加过大,当前值 : ", self.critRatePlus) -- end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_PileCritRatePlus, plus, self.critRatePlus) end --叠加抗暴率(减法) function AttrCalc:PileAntiCritRatePlus(plus) if self.critRatePlus then self.critRatePlus = self.critRatePlus:Sub(plus) else if type(plus) == "number" then plus = newV1(-plus) else plus = plus:cloneV1() plus:Mul(-1) end self.critRatePlus = plus end -- if self.critRatePlus > MAX_critRate_PLUS then -- logging.error(LTAG.ERROR, "HYW : 警告! critRate附加过大,当前值 : ", self.critRatePlus) -- end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_PileAntiCritRatePlus, plus, self.critRatePlus) end function AttrCalc:PileCritEffRatioPlus(plus) if self.critEffRatioPlus then self.critEffRatioPlus = self.critEffRatioPlus:Add(plus) else if type(plus) == "number" then plus = newV1(plus) else plus = plus:cloneV1() end self.critEffRatioPlus = plus end -- if self.critEffRatioPlus > MAX_critEffRatio_PLUS then -- logging.error(LTAG.ERROR, "HYW : 警告! critEffRatio附加过大,当前值 : ", self.critEffRatioPlus) -- end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_PileCritEffRatioPlus, plus, self.critEffRatioPlus) end function AttrCalc:PileAntiCritEffRatioPlus(plus) if self.critEffRatioPlus then self.critEffRatioPlus = self.critEffRatioPlus:Sub(plus) else if type(plus) == "number" then plus = newV1(-plus) else plus = plus:cloneV1() plus:Mul(-1) end self.critEffRatioPlus = plus end -- if self.critEffRatioPlus > MAX_critEffRatio_PLUS then -- logging.error(LTAG.ERROR, "HYW : 警告! critEffRatio附加过大,当前值 : ", self.critEffRatioPlus) -- end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_PileAntiCritEffRatioPlus, plus, self.critEffRatioPlus) end function AttrCalc:PileMissileHitRate(factor) self.missileHitRate:Mul(factor) end ------------- ↑一次性伤害计算参数↑------------------------------------------------------------ function FormulaCalculator.ClearPrivateValue() for k,v in pairs(private) do if type(v) ~= "function" then if type(v) == "table" then table.clear(v) else private[k] = nil end end end end function FormulaCalculator.OnInitLevel(levelType) FormulaCalculator.ClearPrivateValue() local isSuccess, dataCfg = DataSheetManager.SubjugateData:TryGetDataByLevelType(levelType) private.SubjugateData = dataCfg private.SubjugateDataPVE = LevelManager.CurLevelFunc:GetSubjugateDataPVE() -- 之前从 ConstData的PVPDmgModifier_xx 策划说不要了,要用 PVPDmgModifierNew 表的配置 --[[isSuccess, dataCfg = DataSheetManager.ConstData:TryGetDataByID("PVPDmgModifier_" .. levelType) private.PVPDmgModifier = dataCfg if isSuccess then private.PVPDmgModifier = private.PVPDmgModifier.FloatValue:cloneV1() else private.PVPDmgModifier = nil end--]] isSuccess, dataCfg = DataSheetManager.PVPDmgModifierNew:TryGetDataByLevelFeatureID(levelType) if isSuccess then local openServerDays = LevelManager.GetOpenServerDays() for _, info in ipairs(dataCfg.DmgModifier_Table) do if openServerDays >= info.OpenSeverDay[1] and openServerDays <= info.OpenSeverDay[2] then private.PVPDmgModifier = newV1(info.PVPDmgModifier) private.PVPHealModifier = newV1(info.AddHPModifier) break end end else private.PVPDmgModifier = nil private.PVPHealModifier = nil end if #CalcEnv > 0 then logging.error(LTAG.ERROR, "HYW : 致命错误! #CalcEnv > 0 @FormulaCalculator.OnInitLevel, 可能会造成战斗不一致") end end function FormulaCalculator.OnExitLevel() private.SubjugateData = nil private.SubjugateDataPVE = nil private.PVPDmgModifier = nil private.PVPHealModifier = nil table.clear(private.GsSubjugateCache) table.clear(private.PVEGsSubjugateCache) table.clear(private.EVPGsSubjugateCache) end function AttrCalc:PileSubjugateDamageFactor(attacker, defender) local isAttackerHero = attacker:IsHero() or attacker:IsMasterHero() local isDefenderHero = defender:IsHero() or defender:IsMasterHero() if isAttackerHero and isDefenderHero then --PVP模式战力压制 local subjugateData = private.SubjugateData if subjugateData then local factor = private.GetGsSubjugateFactor(attacker:GetGs(), defender:GetGs(), subjugateData) --logging.error(LTAG.ERROR, "HYW : PileGsSubjugateDamageFactor : ", factor) if factor then self:PileDamageFactor(factor, EDamageFactorReasonType.PVP_GS_SUBJUGATE, attacker:GetGs(), defender:GetGs()) --EventSystem.Dispatch(EventID.TryAddAttackLog,HurtFormulaStep.Step_14, factor, attacker:GetGs(), defender:GetGs()) end if subjugateData.OfficialSubjugate == 1 then --代表这个类型的关卡开启官职压制 factor = private.GetOpSubjugateFactor(attacker:GetOp(), defender:GetOp(), subjugateData) if factor then self:PileDamageFactor(factor, EDamageFactorReasonType.OFFICIAL_POSITION_SUBJUGATE) end end end elseif isAttackerHero and not isDefenderHero then --PVE模式战力压制 if private.SubjugateDataPVE then local subjugatePveFactor = private.GetPVEGsSubjugateFactor(attacker:GetGs(),private.SubjugateDataPVE) self:PileDamageFactor(subjugatePveFactor, EDamageFactorReasonType.PVE_GS_SUBJUGATE, attacker:GetGs(), private.SubjugateDataPVE.ID) --EventSystem.Dispatch(EventID.TryAddAttackLog,HurtFormulaStep.Step_14, subjugatePveFactor, attacker:GetGs(), defender:GetGs()) end elseif not isAttackerHero and isDefenderHero then --EVP模式战力压制 if private.SubjugateDataPVE then local subjugateEvpFactor = private.GetEVPGsSubjugateFactor(defender:GetGs(),private.SubjugateDataPVE) self:PileDamageFactor(subjugateEvpFactor, EDamageFactorReasonType.EVP_GS_SUBJUGATE, defender:GetGs(), private.SubjugateDataPVE.ID) --EventSystem.Dispatch(EventID.TryAddAttackLog,HurtFormulaStep.Step_14, subjugateEvpFactor, attacker:GetGs(), defender:GetGs()) end end --EVE无需战力压制 end function AttrCalc:ResetDamageFactor() self.dmgFactor = nil end function AttrCalc:ResetFinalDamageFactor() self.finalDmgFactor = nil end function AttrCalc:ResetAmFactor() self.amFactor = nil end function AttrCalc:ResetHealFactor() self.healFactor = nil end function AttrCalc:ResetPCLossFactor() self.pcLossFactor = nil end function AttrCalc:ResetFinalDamageOverrideValue() self.finalDmgOverrideValue = nil end --应用dmgFactor,并把dmgFactor置空 function AttrCalc:ApplyDamageFactor(fpV1) if self.dmgFactor then fpV1:Mul(math.max(tonumberV1(self.dmgFactor),0)) --负数的dmgFactor会把伤害置零,负多少没影响 EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_TotalDmgFactor, self.dmgFactor) self:ResetDamageFactor() end end function AttrCalc:TryApplyFinalDamageFactor(fpV1, targetEntity, sourceEntity) if self.finalDmgFactor then local oldValue = tonumberV1(fpV1) local factorNum = math.max(tonumberV1(self.finalDmgFactor), 0) fpV1:Mul(factorNum) --负数的 finalDmgFactor 会把伤害置零,负多少没影响 BattleEventSystem.AfterApplyFinalDamageFactor(tonumberV1(fpV1), oldValue, factorNum, targetEntity, sourceEntity) self.finalDmgFactor = nil end end --应用amFactor,并把amFactor置空 function AttrCalc:ApplyAmFactor(fpV1) if self.amFactor then fpV1:Mul(math.max(tonumberV1(self.amFactor),0)) --负数的amFactor会把am改变置零,负多少没影响 self:ResetAmFactor() end end --应用healFactor,并把healFactor置空 function AttrCalc:ApplyHealFactor(fpV1) if self.healFactor then if self.healFactor > FP_One or not self.skipNegBehealEff then fpV1:Mul(math.max(tonumberV1(self.healFactor),0)) --负数的healFactor会把治疗置零,负多少没影响 self:ResetHealFactor() end end end function AttrCalc:ApplyPCLossFactor(fpV1) if self.pcLossFactor then fpV1:Mul(math.max(tonumberV1(self.pcLossFactor),0)) --负数的pcLossFactor会把治疗置零,负多少没影响 self:ResetPCLossFactor() end end function AttrCalc:TryApplyCritRatePlus(fpV1) if self.critRatePlus then fpV1:Add(self.critRatePlus) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_CirtRatePlus, self.critRatePlus) self.critRatePlus:Reset(0) --一次性附加值清除 end end function AttrCalc:TryApplyCritEffRatioPlus(fpV1) if self.critEffRatioPlus then fpV1:Add(self.critEffRatioPlus) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_17, self.critEffRatioPlus, fpV1) self.critEffRatioPlus:Reset(0) end end function AttrCalc:TryApplyParryRatePlus(fpV1) if self.parryRatePlus then fpV1:Add(self.parryRatePlus) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_ApplyParryRatePlus, self.parryRatePlus, fpV1) self.parryRatePlus:Reset(0) end end function AttrCalc:TryApplyParryEffRatioPlus(fpV1) if self.parryEffRatioPlus then fpV1:Add(self.parryEffRatioPlus) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_18, self.parryEffRatioPlus, fpV1) self.parryEffRatioPlus:Reset(0) end end function AttrCalc:TryApplyDamage7OverrideValue(fpV1, opcode) if self.dmg7OverrideValue then fpV1:Reset(self.dmg7OverrideValue) if opcode == "sub" then fpV1:Mul(-1) elseif opcode == "add" and fpV1 > FPConst.Zero then --2023年8月17日 伤血情况下不再可以变更符号,限制死为负数。因为策划配了一些add负数的公式,所以这里得这样做才能满足现在的需求。但这个搞法可能会导致无法实现回光返照这类技能。 fpV1:Mul(-1) end self.dmg7OverrideValue = nil ----一次性重写值清除 end end function AttrCalc:ApplyFinalDamageOverrideValue(fpV1, opcode) if self.finalDmgOverrideValue then fpV1:Reset(self.finalDmgOverrideValue) if opcode == "sub" then fpV1:Mul(-1) end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_FinalDamageOverrideValue, fpV1) self.finalDmgOverrideValue = nil --一次性重写值清除 end end function AttrCalc:ApplyFinalHealthOverrideValue(fpV1, opcode) if self.finalHealOverrideValue then fpV1:Reset(self.finalHealOverrideValue) self.finalHealOverrideValue = nil --一次性重写值清除 end end function AttrCalc:ApplyFinalLifeStealOverrideValue(fpV1) if self.finalLifeStealOverrideValue then fpV1:Reset(self.finalLifeStealOverrideValue) self.finalLifeStealOverrideValue = nil end end -- ↓ 应该是不用了,现在有attrcalc,不用一次性管理了 --使用attrModify.rate,之后会重置attrModify.rate。 (一些情况下attrModify.rate被设计为一次性的,使用后就必须重置) -- function AttrCalc:UseRate() -- local rate = self.rate:cloneV1() -- self.rate:Reset(1) -- return rate -- end function AttrCalc:SetMissiltHitCountRate(...) local hitRateList = {...} local missileHitRate = nil if self.missileHitCount > #hitRateList then missileHitRate = hitRateList[#hitRateList] else missileHitRate = hitRateList[self.missileHitCount] end local params = self.HurtNormalParams local missileData, attackerAttr, hurterAttr, rate, targetEntity, sourceEntity,hurtBuffId = params[1], params[2], params[3], params[4], params[5], params[6],params[7] private.HurtNormal(missileData, attackerAttr, hurterAttr, rate , missileHitRate,targetEntity,sourceEntity,hurtBuffId) end function AttrCalc:HasBuff(target, buffID) local targetEntity = nil if target == self.expEnv.op then targetEntity = self.opEntity else targetEntity = self.aimEntity end local updateData = targetEntity.components.buff:GetBuffUpdateData(buffID) if updateData then return true end return false end --自定义公式走这 -- opcode :操作符(add、sub、mul、div这些) -- prop : 属性枚举 -- value : 进行操作过后的属性值(raw值,可能还会被修改,比如限制为大于0) function AttrCalc:Modify(target, targetEntity, opcode, prop, delta, value, casterEntity) local attr = target.attr._attr local initAttr = attr.InitAttr local changeParam1 = nil local changeParam2 = nil local finalDelta = delta:cloneV1() if prop == LuaConst.RealtimeAttrType.hp then--血量 local result = value:cloneV1() delta:Reset(result):Sub(attr.hp) result:Clamp(FPConst.Zero, attr:GetAttrValue(LuaConst.AttrType.hplmt)) finalDelta:Reset(result):Sub(attr.hp) if finalDelta < FPConst.Zero then --这里面的delta为负数 self:ApplyDamageFactor(delta) self:TryApplyDamage7OverrideValue(delta, opcode) if self.finalDmgFactor then delta:Mul(-1) --这里乘以-1,因为 TryApplyFinalDamageFactor 里需要接收负数 self:TryApplyFinalDamageFactor(delta, targetEntity, casterEntity)--此后delta是伤害值8,并且不会再改变。伤害值8会作为伤害冒字和伤害统计用的值。2024年3月18日 HYW delta:Mul(-1) --再乘以-1恢复回原值 end if delta < FPConst.Zero then BattleEventSystem.BeforeFinalDmgOverride(tonumberV1(delta), targetEntity, casterEntity, nil) end if self.finalDmgOverrideValue then self:ApplyFinalDamageOverrideValue(finalDelta, opcode) else finalDelta:Reset(delta) end private.HPFilterBuff(targetEntity, casterEntity, finalDelta) result:Reset(finalDelta):Add(attr.hp) result:Clamp(FPConst.Zero, attr:GetAttrValue(LuaConst.AttrType.hplmt)) elseif delta > FPConst.Zero then --这里面的delta为正数,代表回血 finalDelta:Reset(delta) --这里把finalDelta作为临时变量用一下 local behealeffValue = attr:GetAttrValue(LuaConst.AttrType.behealeff) if behealeffValue > FP_Zero or not self.skipNegBehealEff then delta:Mul(behealeffValue):Add(finalDelta)--这里把finalDelta作为临时变量用一下 end if delta < FPConst.Zero then delta:Reset(0) end result:Reset(delta):Add(attr.hp) result:Clamp(FPConst.Zero, attr:GetAttrValue(LuaConst.AttrType.hplmt)) finalDelta:Reset(result):Sub(attr.hp) if self.finalHealOverrideValue then self:ApplyFinalHealthOverrideValue(finalDelta, opcode) end end --rawset(attr, prop, result)--old rawset不方便做功能,改为调接口 attr:SetAttrBaseValue(prop,result)--new private.AfterHPChange(targetEntity,self.opEntity,delta,finalDelta,result,opcode,self.hpChangeType) changeParam1 = self.hpChangeType changeParam2 = self.sourceBuffId elseif prop == LuaConst.RealtimeAttrType.sa then--无双值 local result = value:cloneV1() result:Clamp(FPConst.Zero, attr:GetAttrValue(LuaConst.AttrType.salmt)) finalDelta:Reset(result):Sub(attr.sa) --rawset(attr, prop, result)--old rawset不方便做功能,改为调接口 attr:SetAttrBaseValue(prop,result)--new SystemManager.OnSAChange(targetEntity,delta,result) elseif prop == LuaConst.RealtimeAttrType.am then--霸体 local result = value:cloneV1() delta:Reset(result):Sub(attr.am) self:ApplyAmFactor(delta) result:Reset(delta):Add(attr.am) result:Clamp(FPConst.Zero, attr:GetAttrValue(LuaConst.AttrType.amlmt)) finalDelta:Reset(result):Sub(attr.am) if finalDelta ~= FPConst.Zero then --rawset(attr, prop, result)--old rawset不方便做功能,改为调接口 attr:SetAttrBaseValue(prop,result)--new EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_AmChange, finalDelta) SystemManager.OnAMChange(targetEntity,delta,result) end elseif prop == LuaConst.RealtimeAttrType.pc then--护盾 local result = value:cloneV1() finalDelta:Reset(result):Sub(attr.pc) --rawset(attr, prop, result)--old rawset不方便做功能,改为调接口 attr:SetAttrBaseValue(prop,result)--new if opcode == "add" then SystemManager.OnAddPCAttr(targetEntity,self.sourceBuffId,delta, self.sourceEntityId) elseif opcode == "sub" then -- 直接子弹减少pc,必须用 SystemManager.OnSubPCAttr(targetEntity, casterEntity, result, false, true) end else if rawget(attr.AttrInfo, prop) then local result = DataSheetUtil.AttrDataGetResult(prop,value,initAttr[prop]) -- 策划的限制倍数 finalDelta:Reset(result):Sub(attr:GetAttrValue(prop)) --rawset(attr.AttrInfo, prop, result)--old rawset不方便做功能,改为调接口 attr:SetAttrBaseValue(prop,result)--new local calData = RuntimeDataManager.New_AttrCalculate(self.sourceBuffId, self.sourceEntityId, delta, opcode) --TODO:感觉有个对象池比较好 AttrSystem.CollectModify(targetEntity,prop,calData) else error('unknown property:'..prop) end end BattleEventSystem.AfterEntityAttrChange(tonumberV1(finalDelta),prop,targetEntity,self.opEntity,changeParam1,changeParam2) return finalDelta end --公式类的计算,只有一些情况下才需要使用rate,目前仅有LuaConst.RealtimeAttrType里的才使用(2021年8月12日 HYW), 且pc的增加不使用rate(2022年3月25日) function AttrCalc:ShouldApplyRate(prop, delta) --这块有大问题,非常不灵活,需要拓展。ShouldApplyRate应该从buff配置确定,需要传入更多信息量 return AttrSystem.IsRealtimeAttrType(prop) and (prop ~= LuaConst.RealtimeAttrType.pc or delta < FPConst.Zero) --2022年3月25日 新增pc增加不使用rate end function AttrCalc:Add(target, prop, delta) local targetEntity = nil if target == self.expEnv.op then targetEntity = self.opEntity else targetEntity = self.aimEntity end local deltaResult = newV1(0) deltaResult:Reset(delta) if self:ShouldApplyRate(prop, delta) then deltaResult:Mul(self.rate) end local changeEventParam1 local changeEventParam2 if prop == LuaConst.RealtimeAttrType.hp then changeEventParam1 = self.hpChangeType changeEventParam2 = self.sourceBuffId end BattleEventSystem.BeforeEntityAttrChange(tonumberV1(deltaResult),prop,targetEntity,self.opEntity,self.missile and self.missile.MissileData,changeEventParam1,changeEventParam2) if prop == LuaConst.RealtimeAttrType.hp then if deltaResult > FP.Const.Zero then if targetEntity.isHero and private.PVPHealModifier then self:PileHealFactor(private.PVPHealModifier) end self:ApplyHealFactor(deltaResult) end end local value = target.attr[prop] + deltaResult self:Modify(target, targetEntity, 'add', prop, deltaResult, value, self.opEntity) end function AttrCalc:Sub(target, prop, delta) local targetEntity = nil if target == self.expEnv.op then targetEntity = self.opEntity else targetEntity = self.aimEntity end local deltaResult = newV1(0) deltaResult:Reset(delta) if self:ShouldApplyRate(prop, delta) then deltaResult:Mul(self.rate) end local changeEventParam1 local changeEventParam2 if prop == LuaConst.RealtimeAttrType.hp then--血量 changeEventParam1 = self.hpChangeType changeEventParam2 = self.sourceBuffId private.TryPVPSubjugate(targetEntity, self.opEntity, deltaResult) end BattleEventSystem.BeforeEntityAttrChange(-tonumberV1(deltaResult),prop,targetEntity,self.opEntity,self.missile and self.missile.MissileData,changeEventParam1,changeEventParam2) local value = target.attr[prop] - deltaResult self:Modify(target, targetEntity, 'sub', prop, deltaResult, value, self.opEntity) end function AttrCalc:Mul(target, prop, delta) local targetEntity = nil if target == self.expEnv.op then targetEntity = self.opEntity else targetEntity = self.aimEntity end local deltaResult = newV1(0) deltaResult:Reset(delta):Sub(FP.Const.One) if self:ShouldApplyRate(prop, delta) then deltaResult:Mul(self.rate) end deltaResult:Add(FP.Const.One) local oldValue = target.attr._attr:GetAttrBaseValue(prop) local value = oldValue * deltaResult local changeEventParam1 local changeEventParam2 if prop == LuaConst.RealtimeAttrType.hp then changeEventParam1 = self.hpChangeType changeEventParam2 = self.sourceBuffId end BattleEventSystem.BeforeEntityAttrChange(tonumberV1(value - oldValue),prop,targetEntity,self.opEntity,self.missile and self.missile.MissileData,changeEventParam1,changeEventParam2) self:Modify(target, targetEntity, 'mul', prop, deltaResult, value, self.opEntity) end function AttrCalc:Div(target, prop, delta) local targetEntity = nil if target == self.expEnv.op then targetEntity = self.opEntity else targetEntity = self.aimEntity end local deltaResult = newV1(0) deltaResult:Reset(delta):Sub(FP.Const.One) if self:ShouldApplyRate(prop, delta) then deltaResult:Mul(self.rate) end deltaResult:Add(FP.Const.One) local oldValue = target.attr._attr:GetAttrBaseValue(prop) local value = oldValue / deltaResult local changeEventParam1 local changeEventParam2 if prop == LuaConst.RealtimeAttrType.hp then changeEventParam1 = self.hpChangeType changeEventParam2 = self.sourceBuffId end BattleEventSystem.BeforeEntityAttrChange(tonumberV1(value - oldValue),prop,targetEntity,self.opEntity,self.missile and self.missile.MissileData,changeEventParam1,changeEventParam2) self:Modify(target, targetEntity, 'div', prop, deltaResult, value, self.opEntity) end --属性计算缓存池 CalcEnv.AttrCalcPool = TablePool( function(calc, hpChangeType) if calc then calc.rate:Reset(1) -- 一次性buff效果系数(如为伤害则是伤害系数)。 calc.hpChangeType = hpChangeType or LuaConst.EHpChangeType.NORMAL calc.missileHitCount = 0-- 子弹产生效果时碰撞的人数(当前帧) calc.missileHitRate:Reset(1) -- 子弹产生的特殊伤害系数 calc.missile = nil --子弹 else calc = setmetatable( { expEnv = nil, --本次计算的环境 rate = newV1(1), -- 一次性buff效果系数(如为伤害则是伤害系数)。 hpChangeType = hpChangeType or LuaConst.EHpChangeType.NORMAL, missileHitCount = 0,-- 子弹产生效果时碰撞的人数(当前帧) missileHitRate = newV1(1), -- 子弹产生的特殊伤害系数 missile = nil, --子弹 HurtNormalParams = {}, -- 一般伤害产生需要的系数 critRatePlus = nil, --一次性暴击率附加。0.05代表额外提升5%暴击率,-0.05代表减少5%暴击率。使用后置空 critEffRatioPlus = nil, --一次性暴击效果附加。0.05代表额外提升5%暴击效果,-0.05代表减少5%暴击效果。使用后置空 parryRatePlus = nil, --一次性格挡率附加。0.05代表额外提升5%格挡率。-0.05代表减少5%格挡率。使用后置空 parryEffRatioPlus = nil, --一次性格挡效果比例附加。0.05代表额外提升5%格挡比例。-0.05代表减少5%格挡比例。使用后置空 dmgFactor = nil, --一次性伤害系数。为nil时不生效。1代表1倍伤害,2代表2倍。使用后置空 healFactor = nil, --一次性治疗系数。为nil时不生效。1代表1倍治疗,2代表2倍。使用后置空 pcLossFactor = nil, --一次性护盾改变系数。为为nil时不生效。1代表1倍数值改表,2代表2倍数据改变。使用后置空 amFactor = nil, --一次性am改变系数。为nil时不生效,1代表1倍改变,2代表2倍,使用后置空 finalDmgOverrideValue = nil, --一次性最终伤害重写值,这次伤害会被直接重写为这个值(直接替换,并且是最终伤害) finalHealOverrideValue = nil, --一次性最终治疗重写值,这次治疗会被直接重写为这个值(直接替换,并且是最终治疗) skipNegBehealEff = nil, --是否跳过负的治疗系数修饰(是否跳过减疗,仅会跳过减疗) }, AttrCalc) end return calc end, function(calc) assert(calc.expEnv == nil) local rate = calc.rate rate:Reset(1) local missileHitRate = calc.missileHitRate missileHitRate:Reset(1) local HurtNormalParams = calc.HurtNormalParams for k in pairs(HurtNormalParams) do -- 一般伤害产生需要的系数 HurtNormalParams[k] = nil end for k,v in pairs(calc) do calc[k] = nil end calc.rate = rate calc.missileHitRate = missileHitRate calc.HurtNormalParams = HurtNormalParams -- calc.rate:Reset(1) -- calc.hpChangeType = hpChangeType or LuaConst.EHpChangeType.NORMAL -- calc.missileHitCount = 0-- 子弹产生效果时碰撞的人数(当前帧) -- calc.missileHitRate:Reset(1) -- 子弹产生的特殊伤害系数 -- calc.critRatePlus = nil --一次性暴击率附加。0.05代表额外提升5%暴击率,-0.05代表减少5%暴击率。使用后置空 -- calc.critEffRatioPlus = nil --一次性暴击效果附加。0.05代表额外提升5%暴击效果,-0.05代表减少5%暴击效果。使用后置空 -- calc.parryRatePlus = nil --一次性格挡率附加。0.05代表额外提升5%格挡率。-0.05代表减少5%格挡率。使用后置空 -- calc.parryEffRatioPlus = nil --一次性格挡效果比例附加。0.05代表额外提升5%格挡比例。-0.05代表减少5%格挡比例。使用后置空 -- calc.dmgFactor = nil --一次性伤害系数。为nil时不生效。1代表1倍伤害,2代表2倍。使用后置空 -- calc.finalDmgFactor = nil --一次性伤害系数2。为nil时不生效。1代表1倍伤害,2代表2倍。使用后置空 -- calc.healFactor = nil --一次性治疗系数。为nil时不生效。1代表1倍治疗,2代表2倍。使用后置空 -- calc.pcLossFactor = nil --一次性护盾改变系数。为为nil时不生效。1代表1倍数值改表,2代表2倍数据改变。使用后置空 -- calc.amFactor = nil --一次性am改变系数。为nil时不生效,1代表1倍改变,2代表2倍,使用后置空 -- calc.finalDmgOverrideValue = nil --一次性最终伤害重写值,这次伤害会被直接重写为这个值(直接替换,并且是最终伤害) -- calc.finalHealOverrideValue = nil --一次性最终治疗重写值,这次治疗会被直接重写为这个值(直接替换,并且是最终治疗) end ) --表达式计算过程中的属性保护 local function ErrorOnNewIndex(t, k, v) error('newindex on attributes in expression') end local attrDefMT = { __newindex = ErrorOnNewIndex } local attrRefCount = {} local attrOriginMT = {} local attrCurrMT = {} local attrCurrMTPool = TablePool( function(mt, origin) if mt then mt.__index = origin.__index else mt = { __index = origin.__index, __newindex = ErrorOnNewIndex } end return mt end, function(mt) mt.__index = nil end ) local function CaptureMT(attr) local ref = attrRefCount[attr] if ref then attrRefCount[attr] = ref + 1 else local originMT = getmetatable(attr) if originMT then attrOriginMT[attr] = originMT local currMT = attrCurrMTPool.TryGet(originMT) setmetatable(attr, currMT) attrCurrMT[attr] = currMT else attrOriginMT[attr] = attrDefMT setmetatable(attr, attrDefMT) attrCurrMT[attr] = attrDefMT end attrRefCount[attr] = 1 end end local function RestoreMT(attr) local ref = attrRefCount[attr] - 1 if ref > 0 then attrRefCount[attr] = ref else local currMT = attrCurrMT[attr] if currMT == attrDefMT then setmetatable(attr, nil) else setmetatable(attr, attrOriginMT[attr]) attrCurrMTPool.Recycle(currMT) end attrOriginMT[attr] = nil attrCurrMT[attr] = nil attrRefCount[attr] = nil end end --整个计算过程的开始、结束入口 function CalcEnv:BeginCalc(hpChangeType) local attrCalc = self.AttrCalcPool.TryGet(hpChangeType) table.insert(self, attrCalc) self.currAttrCalc = attrCalc return attrCalc end function CalcEnv:EndCalc() local attrCalc = table.remove(self) assert(attrCalc) self.AttrCalcPool.Recycle(attrCalc) local depth = #self if depth > 0 then self.currAttrCalc = self[depth] else --DEBUG 确认执行完后所有对象都进行了释放 assert(next(attrOriginMT) == nil) assert(next(attrCurrMT) == nil) assert(next(attrRefCount) == nil) end end function CalcEnv:BeginExp(buffID, opEntity, aimEntity, opAttr, aimAttr) local expEnv = self.ExpEnvPool.TryGet(buffID, opEntity, aimEntity, opAttr, aimAttr) local calc = self.currAttrCalc calc.expEnv = expEnv calc.sourceBuffId = buffID calc.sourceEntityId = opEntity._logicInitData.EntityID calc.opEntity = opEntity calc.aimEntity = aimEntity return expEnv end function CalcEnv:EndExp(expEnv) self.ExpEnvPool.Recycle(expEnv) local calc = self.currAttrCalc calc.expEnv = nil calc.opEntity = nil calc.aimEntity = nil end --所有自定义公式都走这 --与这个方法相对的是HurtNormal,HurtNormal会使用默认的标准伤害公式,仅仅会改变血量 function private.Result(buffID, expStr, opEntity, aimEntity) if expStr == nil or expStr == '' then return end local opAttr = opEntity.components.attr local opAttrInfo = opAttr.AttrInfo local aimAttr = aimEntity.components.attr local aimAttrInfo = aimAttr.AttrInfo --为属性在表达式环境中添加保护,禁止新增字段写入,避免因为数据配置出现运行错误 CaptureMT(opAttr) CaptureMT(opAttrInfo) CaptureMT(aimAttr) CaptureMT(aimAttrInfo) --执行表达式 local expEnv = CalcEnv:BeginExp(buffID, opEntity, aimEntity, opAttr, aimAttr) local suc, r1 ,r2 ,r3 = pcall(Expression.Execute, expStr, expEnv) if not suc then logging.error(LTAG.ERROR, expStr, r1) end CalcEnv:EndExp(expEnv) expEnv = nil --执行完毕后恢复属性的元表 RestoreMT(opAttr) RestoreMT(opAttrInfo) RestoreMT(aimAttr) RestoreMT(aimAttrInfo) return r1,r2,r3 end --一般暴击率的计算 function private.GetNormalCritRate(attackerAttr,hurterAttr) return private.CommonRatioCalculate( attackerAttr[LuaConst.AttrType.crit], hurterAttr[LuaConst.AttrType.anticrit], Const_CritParam_a, Const_CritParam_b, Const_CritParam_c_reciprocal, Const_CritParam_M, Const_CritParam_N, attackerAttr[LuaConst.AttrType.critrate], hurterAttr[LuaConst.AttrType.anticritrate], Const_Crit_Min, Const_Crit_Max, HurtFormulaStep.Step_1) end --一般暴击倍率的计算 function private.GetNormalCritEff(attackerAttr,hurterAttr) return private.CommonRatioCalculate( attackerAttr[LuaConst.AttrType.criteff], hurterAttr[LuaConst.AttrType.anticriteff], Const_CritEffParam_a, Const_CritEffParam_b, Const_CritEffParam_c_reciprocal, Const_CritEffParam_M, Const_CritEffParam_N, attackerAttr[LuaConst.AttrType.criteffrate], hurterAttr[LuaConst.AttrType.anticriteffrate], Const_CritEff_Min, Const_CritEff_Max, HurtFormulaStep.Step_2) end -- 一般格挡率的计算 function private.GetNormalParryRate(attackerAttr,hurterAttr) return private.CommonRatioCalculate( hurterAttr[LuaConst.AttrType.parry], attackerAttr[LuaConst.AttrType.antiparry], Const_ParryParam_a, Const_ParryParam_b, Const_ParryParam_c_reciprocal, Const_ParryParam_M, Const_ParryParam_N, hurterAttr[LuaConst.AttrType.parryrate], attackerAttr[LuaConst.AttrType.antiparryrate], Const_Parry_Min, Const_Parry_Max, HurtFormulaStep.Step_3) end --一般格挡倍率的计算,返回的是减伤比例,比如0.15代表减伤15% function private.GetNormalParryEff(attackerAttr,hurterAttr) return private.CommonRatioCalculate( hurterAttr[LuaConst.AttrType.parryeff], attackerAttr[LuaConst.AttrType.antiparryeff], Const_ParryEffParam_a, Const_ParryEffParam_b, Const_ParryEffParam_c_reciprocal, Const_ParryEffParam_M, Const_ParryEffParam_N, hurterAttr[LuaConst.AttrType.parryeffrate], attackerAttr[LuaConst.AttrType.antiparryeffrate], Const_ParryEff_Min, Const_ParryEff_Max, HurtFormulaStep.Step_4) end --通用比例计算,适用于暴击率、暴击伤害倍率、格挡率、格挡减伤比例 -- posAttrValue,正向作用属性,比如暴击值、格挡值 -- negAttrValue,反向作用属性,比如暴抗值、反格挡值 --a、b、c_reciprocal、m、n,控制常数,不同属性的计算,这些都会不同 --注意c_reciprocal是c的倒数 --plus:比例加数,在计算最后直接附加 --cut:比例减数,在计算最后直接减少 function private.CommonRatioCalculate(posAttrValue,negAttrValue,a,b,c_reciprocal,m,n,plus,cut,finalMin,finalMax,logType) local value = posAttrValue:cloneV1() value:Sub(negAttrValue):Mul(c_reciprocal) -- (属性 - 抗性) / c value:Add(b) -- (属性 - 抗性) / c + b if value <= FPConst.Tenth then -- max(上一步的值,0.1) --这里防止除0,不搞0,搞0.1也够了, value:Reset(FPConst.Tenth) end _tempResultV1:Reset(a):Div(value) --a / 上一步的值 value:Reset(_tempResultV1) value:Mul(-1):Add(1) -- 1 - 上一步的值 value:Mul(m) --m * 上一步 if value < n then value:Reset(n) end value:Add(plus) value:Sub(cut) if value < finalMin then value:Reset(finalMin) elseif value > finalMax then value:Reset(finalMax) end if logType then EventSystem.Dispatch(EventID.TryAddAttackLog, logType,plus,cut,m,a,posAttrValue,negAttrValue,1 / FP.tonumberV1(c_reciprocal),b,n,finalMin,finalMax,value) end return value end local ILLEGAL_EVENTDMGBOUNUS_MIN = 1000 local _findmgCache = FP.newV1(0) local _anitfindmgCache = FP.newV1(0) local _findmgvarCache = FP.newV1(0) local _anitfindmgvarCache = FP.newV1(0) local _tempBaseHurt = FP.newV1(0) local _tempNoPercentHurt = FP.newV1(0) -- 一般伤害计算 --_hurtResultV1:最终会是伤害值7,为正数 --_hurtRealDeltaV1:实际伤害值(实际hp改变量),为正数 function private.HurtNormal(missileData, attackerAttr, hurterAttr ,rate , missileHitRate ,targetEntity,sourceEntity,hurtBuffId) local skillAtk = missileData.SkillAtkBonus --技能附加攻击力 local missileDmgRate = missileData.EventDmgBonus -- 子弹增益系数 if missileDmgRate >= ILLEGAL_EVENTDMGBOUNUS_MIN then logging.error(LTAG.ERROR, "HYW :不合法的子弹伤害系数 : ", missileDmgRate, " missileID : ", missileData.ID) end local attrType = LuaConst.AttrType _hurtResultV1:Reset(skillAtk):Add(attackerAttr[attrType.atk]) if private.PVPDmgModifier and (sourceEntity.isHero or sourceEntity.isAdjuntant) and (targetEntity.isHero) then _tempCommonV1_1:Reset(private.PVPDmgModifier):Sub(0.1) _tempResultV1:Reset(private.PVPDmgModifier):Mul(hurterAttr[attrType.def]):Div(_tempCommonV1_1) if _hurtResultV1 > _tempResultV1 then _hurtResultV1:Sub(hurterAttr[attrType.def]):Mul(private.PVPDmgModifier) else _hurtResultV1:Mul(Const_LowAtkRate) end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_10, skillAtk, attackerAttr[attrType.atk], hurterAttr[attrType.def], _hurtResultV1, private.PVPDmgModifier) else _tempResultV1:Reset(Const_NormalAtkCompear):Mul(hurterAttr[attrType.def]) if _hurtResultV1 > _tempResultV1 then _hurtResultV1:Sub(hurterAttr[attrType.def]) else _hurtResultV1:Mul(Const_LowAtkRate) end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_10, skillAtk, attackerAttr[attrType.atk], hurterAttr[attrType.def], _hurtResultV1) end _hurtResultV1:Mul(missileDmgRate):Mul(missileHitRate) _tempNoPercentHurt:Reset(_hurtResultV1) _findmgCache:Reset(attackerAttr[attrType.findmg]) --这里得缓存,否则Cheat打印伤害公式的时候打印的值在 BattleEventSystem.BeforeEntityHPChange 进行过修改的情况下会出错 _anitfindmgCache:Reset(hurterAttr[attrType.anitfindmg]) --这里得缓存,否则Cheat打印伤害公式的时候打印的值在 BattleEventSystem.BeforeEntityHPChange 进行过修改的情况下会出错 _tempResultV1:Reset(FPConst.One):Add(_findmgCache):Sub(_anitfindmgCache)--自身属性伤害加成 _hurtResultV1:Mul(_tempResultV1) _findmgvarCache:Reset(attackerAttr[attrType.findmgvar]) --这里得缓存,否则Cheat打印伤害公式的时候打印的值在 BattleEventSystem.BeforeEntityHPChange 进行过修改的情况下会出错 _anitfindmgvarCache:Reset(hurterAttr[attrType.anitfindmgvar]) --这里得缓存,否则Cheat打印伤害公式的时候打印的值在 BattleEventSystem.BeforeEntityHPChange 进行过修改的情况下会出错 _tempResultV1:Reset(FPConst.One):Add(_findmgvarCache):Sub(_anitfindmgvarCache)--buff伤害加成 _hurtResultV1:Mul(_tempResultV1) --此处计算子弹大生命百分比伤害流程 if missileData.EventDmgPercentage and missileData.EventDmgPercentage > 0 then _tempResultV1:Reset(targetEntity:GetMaxHp()):Mul(missileData.EventDmgPercentage) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_15, missileData.EventDmgPercentage, targetEntity:GetMaxHp(), _tempResultV1, _tempNoPercentHurt, missileDmgRate) _hurtResultV1:Add(_tempResultV1) else EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_15, 0, targetEntity:GetMaxHp(), 0, _tempNoPercentHurt, missileDmgRate) end --EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_16, _hurtResultV1) _hurtResultV1:Mul(rate) private.TryPVPSubjugate(targetEntity, sourceEntity, _hurtResultV1) local hurtResultNegative = -tonumberV1(_hurtResultV1) --注意!! BattleEventSystem.BeforeEntityHPChange事件必须在这里,不能在ApplyXXXDamageXXX之后,这样才能让buff改变ApplyXXXDamageXXX后的结果 if _hurtResultV1 > FPConst.Zero then BattleEventSystem.BeforeEntityHPChange(hurtResultNegative,targetEntity,sourceEntity,missileData,CalcEnv.currAttrCalc.hpChangeType) end CalcEnv.currAttrCalc:ApplyDamageFactor(_hurtResultV1) CalcEnv.currAttrCalc:TryApplyDamage7OverrideValue(_hurtResultV1) if CalcEnv.currAttrCalc.finalDmgFactor then CalcEnv.currAttrCalc:TryApplyFinalDamageFactor(_hurtResultV1, targetEntity, sourceEntity) --此后_hurtResultV1是伤害值8 ,并且不会再改变。伤害值8会作为伤害冒字和伤害统计用的值。2024年3月18日 HYW end if _hurtResultV1 > FPConst.Zero then local finalHurtResultNegative = -tonumberV1(_hurtResultV1) BattleEventSystem.BeforeFinalDmgOverride(finalHurtResultNegative,targetEntity,sourceEntity,missileData) end if CalcEnv.currAttrCalc.finalDmgOverrideValue then CalcEnv.currAttrCalc:ApplyFinalDamageOverrideValue(_hurtRealDeltaV1) else _hurtRealDeltaV1:Reset(_hurtResultV1) end --_hurtRealDeltaV1此时是最终伤害值,通常是正数(损血的情况下是正数),在后面会被设为实际伤害值(实际hp改变量) private.HPFilterBuff(targetEntity, sourceEntity, _hurtRealDeltaV1) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_11, missileDmgRate, missileHitRate,_findmgCache,_anitfindmgCache,_findmgvarCache,_anitfindmgvarCache,_hurtResultV1) local hp = targetEntity.components.attr.hp _hurtRealDeltaV1:Clamp(FPConst.Zero,hp)--这里必须得clamp,因为_hurtRealDeltaV1需要保存实际掉血的信息量,所以得clamp --_hurtRealDeltaV1此时是实际伤害值(实际hp改变量) targetEntity.components.attr:AttrSub("hp",_hurtRealDeltaV1) local hpChangeType = LuaConst.EHpChangeType.NORMAL private.AfterHPChange(targetEntity,sourceEntity,_hurtResultV1:cloneV1():Negative(),_hurtRealDeltaV1:cloneV1():Negative(),hp,"sub",hpChangeType, nil, missileData) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_5, sourceEntity.components.attr,targetEntity.components.attr,missileData, true) if _hurtResultV1 > FPConst.Zero then BattleEventSystem.AfterEntityHPChange(-tonumberV1(_hurtRealDeltaV1), targetEntity, sourceEntity, hpChangeType, hurtBuffId, missileData) --这句只能放这里,不能放到private.AfterHPChange,因为BeforeEntityAttrChange、AfterEntityAttrChange事件不能跟这里统一 end --SystemManager.OnHPChange(targetEntity,_hurtResultV1:Negative(),_hurtRealDeltaV1:Negative(),hp,"sub") end local _lifeStealTemp = newV1(0) local _oldHpTemp = newV1(0) function private.TryStealLife(damage,operator,attacker,damage7) if operator == "sub" then if damage == FPConst.Zero then damage = damage7 end if damage < FPConst.Zero then _lifeStealTemp:Reset(attacker:GetAttrValue(LuaConst.AttrType.lifeSteal)) if _lifeStealTemp > FPConst.Zero then _lifeStealTemp:Mul(damage) _lifeStealTemp:Negative() _oldHpTemp:Reset(attacker.components.attr.hp) BattleEventSystem.BeforeEntityGetFinalLifeSteal(attacker, tonumberV1(_lifeStealTemp)) CalcEnv.currAttrCalc:ApplyFinalLifeStealOverrideValue(_lifeStealTemp) -- old↓ 直接通过修改属性来改血量,会绕过buff的免疫互斥,导致禁疗时(添加500010时)也可以吸血 -- attacker.components.attr:AttrAdd("hp",_lifeStealTemp) -- private.AfterHPChange(attacker,attacker,_lifeStealTemp,_lifeStealTemp,attacker.components.attr.hp,"add",LuaConst.EHpChangeType.LIFE_STEAL,LuaConst.EHpChangeBatch.LIFE_STEAL) -- BattleEventSystem.AfterEntityHPChange(tonumberV1(_oldHpTemp:Sub(attacker.components.attr.hp):Negative()),attacker,attacker,LuaConst.EHpChangeType.LIFE_STEAL) --这句只能放这里,不能放到private.AfterHPChange,因为BeforeEntityAttrChange、AfterEntityAttrChange事件不能跟这里统一 -- old↑ -- new↓ 通过通用加血buff来吸血,让策划可以用免疫互斥来禁用吸血 local buffCtrlParam = RuntimeDataManager.New_BuffCtrl() buffCtrlParam.BuffOverRideFomula = "aim:add(hp," .. tonumberV1(_lifeStealTemp) ..")" buffCtrlParam.HpChangeType = LuaConst.EHpChangeType.LIFE_STEAL SystemManager.AddBuff( attacker, COMMON_NO_PSEFFECT_HEAL_BUFF, attacker, nil,buffCtrlParam) -- new↑ end end end end --计算PVP属性压制 --PVP属性压制:pvpfindmg和antipvpfindmg提供的伤害值系数 local _tempPVPSubjugateV1 = FP.newV1(0) local _tempPVPSubjugateV1_2 = FP.newV1(0) function private.TryPVPSubjugate(target, attacker, damage) if target:IsHero() and attacker:IsHero() then local pvpfindmg = attacker:GetAttrValue(LuaConst.AttrType.pvpfindmg) local antipvpfindmg = target:GetAttrValue(LuaConst.AttrType.antipvpfindmg) _tempPVPSubjugateV1:Reset(pvpfindmg):Sub(antipvpfindmg) --此时是没有限制到范围的pvpAttrDiff if _tempPVPSubjugateV1 > PVP_SUBJUGATE_RANGE_MAX then _tempPVPSubjugateV1:Reset(PVP_SUBJUGATE_RANGE_MAX) elseif _tempPVPSubjugateV1 < PVP_SUBJUGATE_RANGE_MIN then _tempPVPSubjugateV1:Reset(PVP_SUBJUGATE_RANGE_MIN) end --_tempPVPSubjugateV1此时是pvpAttrDiff if _tempPVPSubjugateV1 > FPConst.Zero then _tempPVPSubjugateV1:Div(PVP_SUBJUGATE_RANGE_MAX):Mul(PVP_SUBJUGATE_LIMIT):Add(FPConst.One) damage:Mul(_tempPVPSubjugateV1) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_PvPAttrFactor, _tempPVPSubjugateV1) elseif _tempPVPSubjugateV1 < FPConst.Zero then _tempPVPSubjugateV1:Div(PVP_SUBJUGATE_RANGE_MAX):Mul(PVP_SUBJUGATE_LIMIT):Mul(-1):Add(FPConst.One) damage:Div(_tempPVPSubjugateV1) _tempPVPSubjugateV1_2:Reset(1):Div(_tempPVPSubjugateV1) _tempPVPSubjugateV1:Reset(_tempPVPSubjugateV1_2) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_PvPAttrFactor, _tempPVPSubjugateV1) end else EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_PvPAttrFactor, 1) end end local _absorbNegTemp = newV1(0) local damagePCTemp = newV1(0) --血量减少时,尝试pc保护罩抵消 function private.HPFilterBuff(aimEntity, opEntity, damage) BattleEventSystem.BeforeEntityPCChange(aimEntity, opEntity, damage) CalcEnv.currAttrCalc:ApplyPCLossFactor(damage) local attrcomp = aimEntity.components.attr if attrcomp.pc[1] <= 0 then return end local absorb = newV1(0) damagePCTemp:Reset(damage) if damage < FPConst.Zero then damagePCTemp:Negative() if damagePCTemp > attrcomp.pc then absorb:Reset(attrcomp.pc) damage:Add(attrcomp.pc) damagePCTemp:Sub(attrcomp.pc) else absorb:Reset(damagePCTemp) damage:Reset() damagePCTemp:Reset() end else if damagePCTemp > attrcomp.pc then absorb:Reset(attrcomp.pc) damage:Sub(attrcomp.pc) else absorb:Reset(damage) damage:Reset() end damagePCTemp:Reset(damage) end if absorb[1] > 0 then -- 消减护盾 --attrcomp.pc:Sub(absorb) attrcomp:AttrSub("pc",absorb) _absorbNegTemp:Reset(absorb) _absorbNegTemp:Negative() if aimEntity ~= opEntity then private.TryStealLife(_absorbNegTemp,"sub",opEntity,damagePCTemp) end SystemManager.OnSubPCAttr(aimEntity, opEntity, absorb, false, true) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_12, absorb, damage) end end -- delta : 用来显示冒字的值,通常是伤害值7 -- finalDelta : 实际改变值 function private.AfterHPChange(target, caster, delta, finalDelta, result, operator, hpChangeType, batch, missileData) if caster == nil then logging.error(LTAG.ERROR, "HYW : 出现了caster为nil的HPChange事件!! (无害Log,程序用,测试可忽略)") end if hpChangeType == LuaConst.EHpChangeType.LIFE_STEAL and batch == nil then batch = LuaConst.EHpChangeBatch.LIFE_STEAL --吸血默认设置为吸血batch end if target ~= caster then private.TryStealLife(finalDelta,operator,caster,delta) end SystemManager.OnHPChange(target, caster, delta, finalDelta, result, operator, hpChangeType, batch, missileData) end --对外的接口 --所有公式都走这,自定义的非自定义的都走这 function FormulaCalculator.CalculateResult(buffData, updateData, targetEntity, sourceEntity, calTimes ,hpChangeType) if not buffData then return end local calcHpChangeType = hpChangeType or LuaConst.EHpChangeType.NORMAL if updateData.MissileHurtID then -- 子弹伤害配置产生 local attrCalc = CalcEnv:BeginCalc(calcHpChangeType) attrCalc.missile = updateData.MissileOfInstantBuff private.CalculateHurtResult(buffData, updateData, targetEntity, sourceEntity, calTimes) CalcEnv:EndCalc() return end if not sourceEntity then -- 如果无buff产生者,那么就默认是自己给自己加(如关卡事件添加buff) sourceEntity = targetEntity end local dostr = string.isNilOrEmpty(updateData.BuffOverRideFomula) and buffData.BuffFormula or updateData.BuffOverRideFomula do local attrCalc = CalcEnv:BeginCalc(calcHpChangeType) attrCalc.missile = updateData.MissileOfInstantBuff attrCalc.rate:Reset(calTimes):Mul(updateData.BuffLayer) -- buff层数 private.Result(buffData.BuffID, dostr, sourceEntity, targetEntity) CalcEnv:EndCalc() end end function private.IsNormalFormula(formula) return formula == Const_Normal or formula == Const_MusouNormal end function private.IsMusouNormalFormula(formula) return formula == Const_MusouNormal end --对外的接口 --只有子弹的计算走这,会处理暴击格挡的计算 function private.CalculateHurtResult(buffData, updateData, targetEntity, sourceEntity, calTimes) local attrCalc = CalcEnv.currAttrCalc if not sourceEntity then -- 如果无buff产生者,那么就默认是自己给自己加(如关卡事件添加buff) logging.error(LTAG.ERROR, "GWS : 子弹伤害不存在来源!!! 请立即连续战斗程序@郭卫松 !!!") return end if not calTimes then calTimes = 1 end local missileData = nil if updateData.IsTracker then missileData = sourceEntity:GetTrackerData(updateData.MissileHurtID) else missileData = sourceEntity:GetMissileData(updateData.MissileHurtID) end if not missileData then return end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_0,sourceEntity,targetEntity,missileData) BattleEventSystem.BeforeCalculateHurtResult(targetEntity, sourceEntity, missileData, updateData.MissileHitCount or 0, attrCalc.hpChangeType) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_5, sourceEntity.components.attr,targetEntity.components.attr,missileData) local attackerAttr = sourceEntity.components.attr.AttrInfo -- 攻击者属性 local hurterAttr = targetEntity.components.attr.AttrInfo -- 受伤者属性 if sourceEntity ~= targetEntity then attrCalc:PileSubjugateDamageFactor(sourceEntity,targetEntity) end local uiDamageType = LuaConst.UIDamageType.Normal --暴击 local critEff = nil if missileData.HurtCritFomulaRate ~= "" then local critRate if private.IsNormalFormula(missileData.HurtCritFomulaRate) then critRate = private.GetNormalCritRate(attackerAttr,hurterAttr) attrCalc:TryApplyCritRatePlus(critRate) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_FinalCritRate, critRate) else local dostrCR = "return "..missileData.HurtCritFomulaRate critRate = private.Result(Const_NOBuff, dostrCR, sourceEntity, targetEntity) if type(critRate) == "number" then critRate = newV1(critRate) end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_7, missileData.HurtCritFomulaRate,critRate ) end local randomCRate = LogicRandom.GetRandom01(sourceEntity ,101) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_6 ,randomCRate) if critRate >= randomCRate then BattleEventSystem.AfterCritBeforeApplyCritEff(targetEntity, sourceEntity, missileData) if private.IsNormalFormula(missileData.HurtCritFomulaResult) then critEff = private.GetNormalCritEff(attackerAttr,hurterAttr) attrCalc:TryApplyCritEffRatioPlus(critEff) else local dostrCRes = "return "..missileData.HurtCritFomulaResult critEff = private.Result(Const_NOBuff, dostrCRes, sourceEntity, targetEntity) end --EventSystem.Dispatch(EventID.TryAddAttackLog, 2, attackerAttr[LuaConst.AttrType.criteff],hurterAttr[LuaConst.AttrType.anticriteff],critEff) uiDamageType = LuaConst.UIDamageType.Critical else EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_NoCrit) end end --格挡 local parryEff = nil if missileData.HurtPentrRate ~= "" and targetEntity ~= sourceEntity then --如果目标和发起者是同一个人,则不算格挡 local parryRate if private.IsNormalFormula(missileData.HurtPentrRate) then parryRate = private.GetNormalParryRate(attackerAttr,hurterAttr) attrCalc:TryApplyParryRatePlus(parryRate) else local dostrPRate = "return "..missileData.HurtPentrRate parryRate = private.Result(Const_NOBuff, dostrPRate, sourceEntity, targetEntity) if type(parryRate) == "number" then parryRate = newV1(parryRate) end EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_7, missileData.HurtPentrRate ,parryRate) end local randomPRate = LogicRandom.GetRandom01(sourceEntity,102) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_6 ,randomPRate) if parryRate >= randomPRate then if private.IsNormalFormula(missileData.HurtPentrResult) then parryEff = private.GetNormalParryEff(attackerAttr,hurterAttr) attrCalc:TryApplyParryEffRatioPlus(parryEff) else local dostrPRes = "return "..missileData.HurtPentrResult parryEff = private.Result(Const_NOBuff, dostrPRes, sourceEntity, targetEntity) if type(parryEff) == "number" then parryEff = newV1(parryEff) end end if parryEff > FP.Const.One then parryEff:Reset(1) end --EventSystem.Dispatch(EventID.TryAddAttackLog, 2, hurterAttr[LuaConst.AttrType.parryeff],attackerAttr[LuaConst.AttrType.antiparryeff],parryEff) if uiDamageType == LuaConst.UIDamageType.Critical then uiDamageType = LuaConst.UIDamageType.CritAndParry else uiDamageType = LuaConst.UIDamageType.Parry end else EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_NoParry) end end SystemManager.SetEntityUIDamageType(targetEntity,uiDamageType) attrCalc.missileHitCount = updateData.MissileHitCount or 0 attrCalc.rate:Reset(calTimes):Mul(updateData.BuffLayer) -- buff层数 if critEff then attrCalc.rate:Mul(critEff) end if parryEff then attrCalc.rate:Mul(FP.Math.Min(FPConst.One-parryEff ,FPConst.One)) end if updateData.MissileDamageFactor then attrCalc:PileDamageFactor(updateData.MissileDamageFactor, EDamageFactorReasonType.MISSILE) end local recordComp = sourceEntity.components.record local missileDmgFactor = recordComp.MissileDmgFactorDic[missileData.ID] if missileDmgFactor then attrCalc:PileDamageFactor(missileDmgFactor, EDamageFactorReasonType.MISSILE) end local missileGroupDmgFactor = recordComp.MissileGroupDmgFactorDic[missileData.GroupID] if missileGroupDmgFactor then attrCalc:PileDamageFactor(missileGroupDmgFactor, EDamageFactorReasonType.MISSILE) end if not string.isNilOrEmpty(missileData.HurtBuffFormula) then if private.IsNormalFormula(missileData.HurtBuffFormula) then -- 一般伤害 if private.IsMusouNormalFormula(missileData.HurtBuffFormula) then attrCalc:PileDamageFactor(sourceEntity.components.skillBase:GetMusouDynamicDmgFactor(), EDamageFactorReasonType.MUSOU) end private.HurtNormal(missileData, attackerAttr, hurterAttr, attrCalc.rate:cloneV1() , attrCalc.missileHitRate,targetEntity,sourceEntity,buffData.BuffID) else -- 特殊伤害公式 或 除伤害外的其他公式 attrCalc.HurtNormalParams[1] = missileData attrCalc.HurtNormalParams[2] = attackerAttr attrCalc.HurtNormalParams[3] = hurterAttr attrCalc.HurtNormalParams[4] = attrCalc.rate:cloneV1() attrCalc.HurtNormalParams[5] = targetEntity attrCalc.HurtNormalParams[6] = sourceEntity attrCalc.HurtNormalParams[7] = buffData.BuffID private.Result(buffData.BuffID, missileData.HurtBuffFormula, sourceEntity, targetEntity) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_7, missileData.HurtBuffFormula) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_5, sourceEntity.components.attr,targetEntity.components.attr,missileData, true) end else -- buff表默认公式 local dostr = updateData.BuffOverRideFomula or buffData.BuffFormula private.Result(buffData.BuffID, dostr, sourceEntity, targetEntity) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_5, sourceEntity.components.attr,targetEntity.components.attr,missileData, true) end attrCalc.rate:Reset(1) end ----针对无buff的公式计算 function FormulaCalculator.CalculateResultNOBuff(doStr,sourceEntity, targetEntity ) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_0,sourceEntity,targetEntity) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_5, sourceEntity.components.attr,targetEntity.components.attr) CalcEnv:BeginCalc() private.Result(Const_NOBuff, doStr, sourceEntity, targetEntity) CalcEnv:EndCalc() EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_7, doStr) EventSystem.Dispatch(EventID.TryAddAttackLog, HurtFormulaStep.Step_5, sourceEntity.components.attr,targetEntity.components.attr) end function FormulaCalculator.PileAmFactor(factor) CalcEnv.currAttrCalc:PileAmFactor(factor) end function FormulaCalculator.PileDamageFactor(factor) CalcEnv.currAttrCalc:PileDamageFactor(factor, EDamageFactorReasonType.BUFF_OF_BATTLEFFECT) end function FormulaCalculator.PileFinalDamageFactor(factor) CalcEnv.currAttrCalc:PileFinalDamageFactor(factor) end function FormulaCalculator.ResetDamageFactor() CalcEnv.currAttrCalc:ResetDamageFactor() CalcEnv.currAttrCalc:ResetFinalDamageFactor() end --只会跳过减疗 function FormulaCalculator.SkipNegBehealEff() CalcEnv.currAttrCalc:SkipNegBehealEff() end function FormulaCalculator.PileHealFactor(factor) CalcEnv.currAttrCalc:PileHealFactor(factor) end function FormulaCalculator.PilePCLossFactor(factor) CalcEnv.currAttrCalc:PilePCLossFactor(factor) end function FormulaCalculator.PileParryEffRatioPlus(ratio) CalcEnv.currAttrCalc:PileParryEffRatioPlus(ratio) end function FormulaCalculator.PileAntiParryEffRatioPlus(ratio) CalcEnv.currAttrCalc:PileAntiParryEffRatioPlus(ratio) end function FormulaCalculator.PileParryRatePlus(plus) CalcEnv.currAttrCalc:PileParryRatePlus(plus) end function FormulaCalculator.PileAntiParryRatePlus(plus) CalcEnv.currAttrCalc:PileAntiParryRatePlus(plus) end function FormulaCalculator.PileCritRatePlus(plus) CalcEnv.currAttrCalc:PileCritRatePlus(plus) end function FormulaCalculator.PileAntiCritRatePlus(plus) CalcEnv.currAttrCalc:PileAntiCritRatePlus(plus) end function FormulaCalculator.PileCritEffRatioPlus(plus) CalcEnv.currAttrCalc:PileCritEffRatioPlus(plus) end function FormulaCalculator.PileAntiCritEffRatioPlus(plus) CalcEnv.currAttrCalc:PileAntiCritEffRatioPlus(plus) end function FormulaCalculator.PileMissileHitRate(rate) CalcEnv.currAttrCalc:PileMissileHitRate(rate) end function FormulaCalculator.SetDamage7OverrideValue(value) CalcEnv.currAttrCalc.dmg7OverrideValue = value end --归零这次伤害计算的最终伤害值 function FormulaCalculator.FinalDamageMakeZero() CalcEnv.currAttrCalc.finalDmgOverrideValue = 0 end --可以传入FP或者number, 设置的是正数。比如设置100,代表会把最终的「伤害」设为100,会扣HP function FormulaCalculator.SetFinalDamageOverrideValue(value) CalcEnv.currAttrCalc.finalDmgOverrideValue = value end --归零这次治疗计算的最终值 function FormulaCalculator.FinalHealthMakeZero() CalcEnv.currAttrCalc.finalHealOverrideValue = 0 end --设置这次治疗计算的最终治疗值 function FormulaCalculator.SetFinalHealOverrideValue(value) CalcEnv.currAttrCalc.finalHealOverrideValue = value end -- 如果value小于当前的finalDmgOverrideValue,就设置为value。 可以传入FP或者number, 设置的是正数。比如设置100,代表会把最终的「伤害」设为100,会扣HP function FormulaCalculator.SetFinalDamageOverrideValueIfSmaller(value) if CalcEnv.currAttrCalc.finalDmgOverrideValue == nil then CalcEnv.currAttrCalc.finalDmgOverrideValue = value else _tempCommonV1_1:Reset(CalcEnv.currAttrCalc.finalDmgOverrideValue) _tempCommonV1_2:Reset(value) if _tempCommonV1_1 > _tempCommonV1_2 then CalcEnv.currAttrCalc.finalDmgOverrideValue = value end end end -- 如果value小于当前的 finalLifeStealOverrideValue,就设置为value。 可以传入FP或者number, 设置的是正数。比如设置100,代表会把最终的「吸血量」设为100,效果是获得100点吸血 function FormulaCalculator.SetFinalLifeStealOverrideValueIfSmallser(value) if CalcEnv.currAttrCalc.finalLifeStealOverrideValue == nil then CalcEnv.currAttrCalc.finalLifeStealOverrideValue = value else _tempCommonV1_1:Reset(CalcEnv.currAttrCalc.finalLifeStealOverrideValue) _tempCommonV1_2:Reset(value) if _tempCommonV1_1 > _tempCommonV1_2 then CalcEnv.currAttrCalc.finalLifeStealOverrideValue = value end end end --归零这次伤害计算的最终吸血值 function FormulaCalculator.FinalLifeStealMakeZero() CalcEnv.currAttrCalc.finalLifeStealOverrideValue = 0 end local _sbjTmp1 = newV1(1) local _sbjTmp2 = newV1(1) --返回PVP战力压制系数 function private.GetGsSubjugateFactor(gsA, gsD, subjugateData) local factor = nil if private.GsSubjugateCache[gsA] and private.GsSubjugateCache[gsA][gsD] then --直接从缓存拿 factor = private.GsSubjugateCache[gsA][gsD] else --这里感觉拼接gsA, gsD 2个key为1个key太费了,就没拼接 --缓存里没有就计算 factor = private.CalculateGsSubjugateFactor(gsA, gsD, subjugateData) private.GsSubjugateCache[gsA] = private.GsSubjugateCache[gsA] or {} private.GsSubjugateCache[gsA][gsD] = factor end if factor then factor = factor:cloneV1() end --logging.error(LTAG.ERROR, "HYW : factor : ", factor) return factor end --返回官职压制系数( op : official position,策划定的官职的英文) function private.GetOpSubjugateFactor(opA, opD, subjugateData) local factor = nil if opA and opD then if opA > opD then factor = OP_SUBJUGATE_FACTOR end end return factor end --返回PVE战力压制系数 function private.GetPVEGsSubjugateFactor(gsA, subjugateDataPVE) local factor = private.PVEGsSubjugateCache[gsA] if not factor then local segmentList = subjugateDataPVE.Segments_Table local index, segment = private.GetPVEGsSegmentData(gsA,segmentList) if index == 1 then factor = newV1(segment.PVE_LowerLimit) elseif index == nil then local count = #segmentList factor = newV1(segmentList[count].PVE_UpperLimit) else local preSegment = subjugateDataPVE.Segments_Table[index - 1] _sbjTmp1:Reset(gsA):Sub(preSegment.PowerPoint) _sbjTmp2:Reset(segment.PowerPoint):Sub(preSegment.PowerPoint) factor = newV1(segment.PVE_UpperLimit):Sub(segment.PVE_LowerLimit):Mul(_sbjTmp1):Div(_sbjTmp2):Add(segment.PVE_LowerLimit) end private.PVEGsSubjugateCache[gsA] = factor end return factor:cloneV1() end --返回EVP战力压制系数 function private.GetEVPGsSubjugateFactor(gsD, subjugateDataPVE) local factor = private.EVPGsSubjugateCache[gsD] if not factor then local segmentList = subjugateDataPVE.Segments_Table local index, segment = private.GetPVEGsSegmentData(gsD,segmentList) if index == 1 then factor = newV1(segment.EVP_UpperLimit) elseif index == nil then local count = #segmentList factor = newV1(segmentList[count].EVP_LowerLimit) else local preSegment = subjugateDataPVE.Segments_Table[index - 1] _sbjTmp1:Reset(gsD):Sub(preSegment.PowerPoint) _sbjTmp2:Reset(segment.PowerPoint):Sub(preSegment.PowerPoint) factor = newV1(segment.EVP_LowerLimit):Sub(segment.EVP_UpperLimit):Mul(_sbjTmp1):Div(_sbjTmp2):Add(segment.EVP_UpperLimit) end private.EVPGsSubjugateCache[gsD] = factor end return factor:cloneV1() end function private.CalculateGsSubjugateFactor(gsA,gsD,subjugateData) if gsA > 0 and gsD > 0 then if gsA ~= gsD then if subjugateData then local segmentData = private.GetGsSegmentData(gsD,subjugateData) return private._CalculateGsSubjugateFactor(newV1(gsA/gsD), segmentData.Param_a, segmentData.Param_b, segmentData.Param_c, segmentData.Param_d, segmentData.Param_m, segmentData.Param_n) end end end return newV1(1) end function private.GetGsSegmentData(gsD, subjugateData) local segmentData = nil for i,v in ipairs(subjugateData.Segments_Table) do if gsD >= v.PowerPoint then segmentData = v else break end end return segmentData end function private.GetPVEGsSegmentData(gs, segmentList) for i,v in ipairs(segmentList) do if gs <= v.PowerPoint then return i, v end end end -- pp = 文档里的PowerPercent , gsA/gsD -- a,b,c,d,m,n 文档里的 a,b,c,d,m,n , 一般是通过读取数据表读的 function private._CalculateGsSubjugateFactor(pp,a,b,c,d,m,n) local factor = newV1(1) _sbjTmp1:Reset(1) -- pp = 文档里的PowerPercent if pp < FPConst.One then if pp < FPConst.One - d then factor:Reset(n) elseif pp < FPConst.One - b then factor:Sub( (_sbjTmp1:Sub(pp):Sub(b)):Div(d - b):Mul(FPConst.One - n)) else factor:Reset(1) end else local ppReverse = FPConst.One / pp if FPConst.One - a <= ppReverse then factor:Reset(1) elseif FPConst.One - c <= ppReverse then factor:Add(_sbjTmp1:Sub(ppReverse):Sub(a):Div(c-a):Mul(m-FPConst.One)) else factor:Reset(m) end end --logging.error(LTAG.ERROR, "HYW : factor : ", factor, " type(a) : ", type(a)) return factor end --返回战力压制的分段,用作显示 function FormulaCalculator.CalculateGsSubjugateSection(gsA, gsD, levelType) local section = 5 --代表不压制 if gsA ~= gsD then local subjugateData = DataSheetManager.SubjugateData:GetDataByLevelType(levelType) if subjugateData then local segmentData = private.GetGsSegmentData(gsD,subjugateData) local a = segmentData.Param_a local b = segmentData.Param_b local c = segmentData.Param_c local d = segmentData.Param_d local m = segmentData.Param_m local n = segmentData.Param_n -- pp = 文档里的PowerPercent , gsA/gsD local pp = newV1(gsA/gsD) if pp < FPConst.One then if pp < FPConst.One - d then section = 1 elseif pp < FPConst.One - c then section = 2 elseif pp < FPConst.One - b then section = 3 elseif pp < FPConst.One - a then section = 4 else section = 5 end else local ppReverse = newV1(gsA / gsD) if ppReverse > FPConst.One - a then section = 5 elseif ppReverse > FPConst.One - b then section = 6 elseif ppReverse > FPConst.One - c then section = 7 elseif ppReverse > FPConst.One - d then section = 8 else section = 9 end end end end return section end ------------------ 战力数值自适应工具方法↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓--------------------------------- --计算虚拟玩家属性,用于EValueAdaptiveType.BY_FORMULA_SERVER_GS 类型的数值自适应 function FormulaCalculator.CalculateStandardPlayerAttribute(recommandGs) local standardPlayerAttrDic = {} local playerStandardPowerData = DataSheetManager.PlayerStandardPower:GetDataByID(1) --默认用第1行的 if recommandGs == nil or recommandGs <= 0 then logging.error(LTAG.ERROR, "HYW : 计算StandardPlayer属性错误,没有服务器战力!!! 设为默认战力3000 关卡ID :", LevelManager.GetCurLevelID()) recommandGs = 3000 end local count = 0 for _,data in DataSheetManager.PlayerStandardPower:GetEnumerator() do if recommandGs >= data.PowerPoint then playerStandardPowerData = data count = count + 1 else break end end local isSuccess, nextRowPlayerStandardPowerData = DataSheetManager.PlayerStandardPower:TryGetDataByID(playerStandardPowerData.ID + 1) local gsRatio = nil if nextRowPlayerStandardPowerData and count > 1 then --策划需求:第一行和最后一行,都不计算战力比率(等价于战力比率设为0) gsRatio = newV1(recommandGs) --文档中的“战力比率” gsRatio:Sub(playerStandardPowerData.PowerPoint) local temp = newV1(nextRowPlayerStandardPowerData.PowerPoint):Sub(playerStandardPowerData.PowerPoint) gsRatio:Div(temp) --战力比率 计算完毕 else --策划需求:第一行和最后一行,都不计算战力比率(等价于战力比率设为0) nextRowPlayerStandardPowerData = playerStandardPowerData--如果nextRowPlayerStandardPowerData为空,代表是最后一行,此时nextRowPlayerStandardPowerData设为playerStandardPowerData) gsRatio = newV1(0) --如果nextRowPlayerStandardPowerData为空,代表是最后一行,此时gsRatio设为0即可) end local type1AttrRate = --文档中的"实际一级属性配比" FormulaCalculator.CalculateRealValueOfPlayerStandardPower(playerStandardPowerData, nextRowPlayerStandardPowerData, gsRatio, "Type1AttrRate") standardPlayerAttrDic.type1AttrRate = type1AttrRate local type2AttrRate = --文档中的"实际二级属性配比" FormulaCalculator.CalculateRealValueOfPlayerStandardPower(playerStandardPowerData, nextRowPlayerStandardPowerData, gsRatio, "Type2AttrRate") standardPlayerAttrDic.type2AttrRate = type2AttrRate local extraDamage = --文档中的"实际额外伤害" FormulaCalculator.CalculateRealValueOfPlayerStandardPower(playerStandardPowerData, nextRowPlayerStandardPowerData, gsRatio, "ExtraDamage") standardPlayerAttrDic.extraDamage = extraDamage local extraResistance = --文档中的"实际额外减伤" FormulaCalculator.CalculateRealValueOfPlayerStandardPower(playerStandardPowerData, nextRowPlayerStandardPowerData, gsRatio, "ExtraResistance") standardPlayerAttrDic.extraResistance = extraResistance local skillRate = --文档中的"实际技能倍率" FormulaCalculator.CalculateRealValueOfPlayerStandardPower(playerStandardPowerData, nextRowPlayerStandardPowerData, gsRatio, "SkillRate") standardPlayerAttrDic.skillRate = skillRate local heroCount = playerStandardPowerData.HeroCount standardPlayerAttrDic.heroCount = heroCount local AttrTypeId = LuaConst.AttrTypeId standardPlayerAttrDic.hplmt = newV1(recommandGs) standardPlayerAttrDic.hplmt:Mul(type1AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.hplmt).GSParam):Div(4) standardPlayerAttrDic.def = newV1(recommandGs) standardPlayerAttrDic.def:Mul(type1AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.def).GSParam):Div(4) standardPlayerAttrDic.atk = newV1(recommandGs) standardPlayerAttrDic.atk:Mul(type1AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.atk).GSParam):Div(2) standardPlayerAttrDic.crit = newV1(recommandGs) standardPlayerAttrDic.crit:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.crit).GSParam):Div(8) standardPlayerAttrDic.anticrit = newV1(recommandGs) standardPlayerAttrDic.anticrit:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.anticrit).GSParam):Div(8) standardPlayerAttrDic.criteff = newV1(recommandGs) standardPlayerAttrDic.criteff:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.criteff).GSParam):Div(8) standardPlayerAttrDic.anticriteff = newV1(recommandGs) standardPlayerAttrDic.anticriteff:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.anticriteff).GSParam):Div(8) standardPlayerAttrDic.parry = newV1(recommandGs) standardPlayerAttrDic.parry:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.parry).GSParam):Div(8) standardPlayerAttrDic.antiparry = newV1(recommandGs) standardPlayerAttrDic.antiparry:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.antiparry).GSParam):Div(8) standardPlayerAttrDic.parryeff = newV1(recommandGs) standardPlayerAttrDic.parryeff:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.parryeff).GSParam):Div(8) standardPlayerAttrDic.antiparryeff = newV1(recommandGs) standardPlayerAttrDic.antiparryeff:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.antiparryeff).GSParam):Div(8) return standardPlayerAttrDic end --region gws :主播PC包需要的特殊的计算武将属性的方法 function FormulaCalculator.CalculateGameStreamerPlayerAttribute(recommandGs,useHeroCount, heroType) -- recommandGs是总战力 ,heroType -- 武将职业(1-破军,2-猛将,3-智囊,4-神射,5-王辅,6战士) local standardPlayerAttrDic = {} local playerStandardPowerData = DataSheetManager.PlayerStandardPower:GetDataByID(1) --默认用第1行的 local count = 0 for _,data in DataSheetManager.PlayerStandardPower:GetEnumerator() do if recommandGs >= data.PowerPoint then playerStandardPowerData = data count = count + 1 else break end end local has, nextRowPlayerStandardPowerData = DataSheetManager.PlayerStandardPower:TryGetDataByID(playerStandardPowerData.ID + 1) local gsRatio = nil if has and count > 1 then --策划需求:第一行和最后一行,都不计算战力比率(等价于战力比率设为0) gsRatio = newV1(recommandGs) --文档中的“战力比率” gsRatio:Sub(playerStandardPowerData.PowerPoint) local temp = newV1(nextRowPlayerStandardPowerData.PowerPoint):Sub(playerStandardPowerData.PowerPoint) gsRatio:Div(temp) --战力比率 计算完毕 else --策划需求:第一行和最后一行,都不计算战力比率(等价于战力比率设为0) nextRowPlayerStandardPowerData = playerStandardPowerData--如果nextRowPlayerStandardPowerData为空,代表是最后一行,此时nextRowPlayerStandardPowerData设为playerStandardPowerData) gsRatio = newV1(0) --如果nextRowPlayerStandardPowerData为空,代表是最后一行,此时gsRatio设为0即可) end local type1AttrRate = --文档中的"实际一级属性配比" FormulaCalculator.CalculateRealValueOfPlayerStandardPower(playerStandardPowerData, nextRowPlayerStandardPowerData, gsRatio, "Type1AttrRate") local type2AttrRate = --文档中的"实际二级属性配比" FormulaCalculator.CalculateRealValueOfPlayerStandardPower(playerStandardPowerData, nextRowPlayerStandardPowerData, gsRatio, "Type2AttrRate") local heroCount = useHeroCount -- playerStandardPowerData.HeroCount 玩家实际使用的武将个数,不是表中的配置 local AttrTypeId = LuaConst.AttrTypeId standardPlayerAttrDic.hplmt = newV1(recommandGs) standardPlayerAttrDic.hplmt:Mul(type1AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.hplmt).GSParam):Div(4) standardPlayerAttrDic.def = newV1(recommandGs) standardPlayerAttrDic.def:Mul(type1AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.def).GSParam):Div(4) if heroType == LuaConst.EHeroProfessionType.MENG then standardPlayerAttrDic.hplmt:Mul(1.15) standardPlayerAttrDic.def:Mul(1.15) elseif heroType ~= LuaConst.EHeroProfessionType.FU then standardPlayerAttrDic.hplmt:Mul(0.85) standardPlayerAttrDic.def:Mul(0.85) end standardPlayerAttrDic.atk = newV1(recommandGs) standardPlayerAttrDic.atk:Mul(type1AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.atk).GSParam):Div(2) if heroType == LuaConst.EHeroProfessionType.MENG then standardPlayerAttrDic.atk:Mul(0.85) elseif heroType ~= LuaConst.EHeroProfessionType.FU then standardPlayerAttrDic.atk:Mul(1.15) end standardPlayerAttrDic.crit = newV1(recommandGs) standardPlayerAttrDic.crit:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.crit).GSParam):Div(8) standardPlayerAttrDic.anticrit = newV1(recommandGs) standardPlayerAttrDic.anticrit:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.anticrit).GSParam):Div(8) standardPlayerAttrDic.criteff = newV1(recommandGs) standardPlayerAttrDic.criteff:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.criteff).GSParam):Div(8) standardPlayerAttrDic.anticriteff = newV1(recommandGs) standardPlayerAttrDic.anticriteff:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.anticriteff).GSParam):Div(8) standardPlayerAttrDic.parry = newV1(recommandGs) standardPlayerAttrDic.parry:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.parry).GSParam):Div(8) standardPlayerAttrDic.antiparry = newV1(recommandGs) standardPlayerAttrDic.antiparry:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.antiparry).GSParam):Div(8) standardPlayerAttrDic.parryeff = newV1(recommandGs) standardPlayerAttrDic.parryeff:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.parryeff).GSParam):Div(8) standardPlayerAttrDic.antiparryeff = newV1(recommandGs) standardPlayerAttrDic.antiparryeff:Mul(type2AttrRate):Div(heroCount):Div(DataSheetManager.AttrData:GetDataByID(AttrTypeId.antiparryeff).GSParam):Div(8) return standardPlayerAttrDic, playerStandardPowerData end --endregion 主播PC包需要的特殊的计算武将属性的方法 ↑ --region gws :通过推荐战力计算出属性(和主播PC包基本一样)。群雄演武用 function FormulaCalculator.Calculate9v9RobotEnemyPlayerAttribute(recommandGs, useHeroCount, heroType, isMainHero) local standardPlayerAttrDic, playerStandardPowerData = FormulaCalculator.CalculateGameStreamerPlayerAttribute(recommandGs, useHeroCount, heroType) if isMainHero then standardPlayerAttrDic.salmt = 100 standardPlayerAttrDic.findmgvar = playerStandardPowerData.ExtraDamage standardPlayerAttrDic.anitfindmgvar = playerStandardPowerData.ExtraResistance end return standardPlayerAttrDic end --endregion 通过推荐战力计算出属性。群雄演武用 --region gws :通过推荐战力计算出属性(和主播PC包一样)。目前使用的玩法:世界boss的模拟玩家机器人、 function FormulaCalculator.CalculateRobotEnemyPlayerAttribute(recommandGs, useHeroCount, heroType, isMainHero) local standardPlayerAttrDic, playerStandardPowerData = FormulaCalculator.CalculateGameStreamerPlayerAttribute(recommandGs, useHeroCount, heroType) if isMainHero then standardPlayerAttrDic.salmt = 100 standardPlayerAttrDic.findmgvar = playerStandardPowerData.ExtraDamage standardPlayerAttrDic.anitfindmgvar = playerStandardPowerData.ExtraResistance end return standardPlayerAttrDic end --endregion 通过推荐战力计算出属性。目前使用的玩法:世界boss的模拟玩家机器人、 function FormulaCalculator.CalculateRealValueOfPlayerStandardPower(data, nextData, gsRatio, rowName) local realValue = newV1(nextData[rowName]) --文档中的"实际一级属性配比" realValue:Sub(data[rowName]) realValue:Mul(gsRatio) realValue:Add(data[rowName]) return realValue end --data:可以传MonsterValueDataByPowerPoint表一行数据。 也可以传一个table,且这个table具有所有 MonsterValueDataByPowerPoint 的字段 function FormulaCalculator.CalculateMonsterAttrByStandardPlayerAttr(standardPlayerAttrDic, data, useHeroCount) local attributeDic = {} if standardPlayerAttrDic then --amlmt attributeDic.amlmt = newV1(data.Amlmt) --def attributeDic.def = newV1(tonumberV1(standardPlayerAttrDic.def)):Mul(data.DefRate) --hplmt attributeDic.hplmt = newV1(tonumberV1(standardPlayerAttrDic.atk)):Mul(0.1) local temp = newV1(tonumberV1(standardPlayerAttrDic.atk)):Sub(attributeDic.def) if attributeDic.hplmt < temp then attributeDic.hplmt:Reset(temp) end temp:Reset(data.PVECrit):Mul(data.PVECriteff):Add(1):Sub(data.PVECrit) attributeDic.hplmt:Mul(temp) attributeDic.hplmt:Mul(standardPlayerAttrDic.skillRate) temp:Reset(1):Sub(data.EVPParryeff):Mul(data.EVPParry):Add(1):Sub(data.EVPParry) attributeDic.hplmt:Mul(temp) temp:Reset(1):Add(tonumberV1(standardPlayerAttrDic.extraDamage)) attributeDic.hplmt:Mul(temp) attributeDic.hplmt:Mul(data.PVEKillTime) --atk attributeDic.atk = newV1(tonumberV1(standardPlayerAttrDic.hplmt)) if useHeroCount then attributeDic.atk:Mul(data.ArmyCount) end attributeDic.atk:Div(data.EVPKillTime) temp:Reset(1):Sub(standardPlayerAttrDic.extraResistance) attributeDic.atk:Div(temp) temp:Reset(data.EVPCrit):Mul(data.EVPCriteff):Add(1):Sub(data.EVPCrit) attributeDic.atk:Div(temp) temp:Reset(1):Sub(data.PVEParryeff):Mul(data.PVEParry):Add(1):Sub(data.PVEParry) attributeDic.atk:Div(temp):Add(standardPlayerAttrDic.def) local crit_C = DataSheetManager.ConstData:GetDataByID("Crit_C").FloatValue local criteff_C = DataSheetManager.ConstData:GetDataByID("CritEff_C").FloatValue local parry_C = DataSheetManager.ConstData:GetDataByID("Parry_C").FloatValue local parryeff_C = DataSheetManager.ConstData:GetDataByID("ParryEff_C").FloatValue --crit attributeDic.crit = newV1(tonumberV1(Const_CritParam_a)) temp:Reset(data.EVPCrit):Mul(-1):Mul(1000):Div(Const_CritParam_M):Add(1000) --attributeDic.crit:Div(temp):Sub(Const_CritParam_b):Mul(crit_C):Add(standardPlayerAttrDic.anticrit)--old误差大 --new↓ 误差小 attributeDic.crit:Mul(1000):Div(temp) attributeDic.crit:Sub(Const_CritParam_b):Mul(crit_C):Add(standardPlayerAttrDic.anticrit) --new↑ --anticrit attributeDic.anticrit = newV1(tonumberV1(Const_CritParam_a)) temp:Reset(data.PVECrit):Mul(-1):Mul(1000):Div(Const_CritParam_M):Add(1000) --attributeDic.anticrit:Div(temp):Sub(Const_CritParam_b):Mul(crit_C):Mul(-1):Add(standardPlayerAttrDic.crit) --old误差大 --new↓ 误差小 attributeDic.anticrit:Mul(1000):Div(temp) attributeDic.anticrit:Sub(Const_CritParam_b):Mul(crit_C):Mul(-1):Add(standardPlayerAttrDic.crit) --new↑ --criteff attributeDic.criteff = newV1(tonumberV1(Const_CritEffParam_a)) temp:Reset(data.EVPCriteff):Mul(-1):Mul(1000):Div(Const_CritEffParam_M):Add(1000) --attributeDic.criteff:Div(temp):Sub(Const_CritEffParam_b):Mul(criteff_C):Add(standardPlayerAttrDic.anticriteff)--old误差大 --new↓ 误差小 attributeDic.criteff:Mul(1000):Div(temp) attributeDic.criteff:Sub(Const_CritEffParam_b):Mul(criteff_C):Add(standardPlayerAttrDic.anticriteff) --new↑ --anticriteff attributeDic.anticriteff = newV1(tonumberV1(Const_CritEffParam_a)) temp:Reset(data.PVECriteff):Mul(-1):Mul(1000):Div(Const_CritEffParam_M):Add(1000) --attributeDic.anticriteff:Div(temp):Sub(Const_CritEffParam_b):Mul(criteff_C):Mul(-1):Add(standardPlayerAttrDic.criteff)--old误差大 --new↓ 误差小 attributeDic.anticriteff:Mul(1000):Div(temp) attributeDic.anticriteff:Sub(Const_CritEffParam_b):Mul(criteff_C):Mul(-1):Add(standardPlayerAttrDic.criteff) --new↑ --parry attributeDic.parry = newV1(tonumberV1(Const_ParryParam_a)) temp:Reset(data.EVPParry):Mul(-1):Mul(1000):Div(Const_ParryParam_M):Add(1000) --attributeDic.parry:Div(temp):Sub(Const_ParryParam_b):Mul(parry_C):Add(standardPlayerAttrDic.antiparry)--old误差大 --new↓ 误差小 attributeDic.parry:Mul(1000):Div(temp) attributeDic.parry:Sub(Const_ParryParam_b):Mul(parry_C):Add(standardPlayerAttrDic.antiparry) --new↑ --antiparry attributeDic.antiparry = newV1(tonumberV1(Const_ParryParam_a)) temp:Reset(data.PVEParry):Mul(-1):Mul(1000):Div(Const_ParryParam_M):Add(1000) --attributeDic.antiparry:Div(temp):Sub(Const_ParryParam_b):Mul(parry_C):Mul(-1):Add(standardPlayerAttrDic.parry)--old误差大 --new↓ 误差小 attributeDic.antiparry:Mul(1000):Div(temp) attributeDic.antiparry:Sub(Const_ParryParam_b):Mul(parry_C):Mul(-1):Add(standardPlayerAttrDic.parry) --new↑ --parryeff attributeDic.parryeff = newV1(tonumberV1(Const_ParryEffParam_a)) temp:Reset(data.EVPParryeff):Mul(-1):Mul(1000):Div(Const_ParryEffParam_M):Add(1000) --attributeDic.parryeff:Div(temp):Sub(Const_ParryEffParam_b):Mul(parryeff_C):Add(standardPlayerAttrDic.antiparryeff)--old误差大 --new↓ 误差小 attributeDic.parryeff:Mul(1000):Div(temp) attributeDic.parryeff:Sub(Const_ParryEffParam_b):Mul(parryeff_C):Add(standardPlayerAttrDic.antiparryeff) --new↑ --antiparryeff attributeDic.antiparryeff = newV1(tonumberV1(Const_ParryEffParam_a)) temp:Reset(data.PVEParryeff):Mul(-1):Mul(1000):Div(Const_ParryEffParam_M):Add(1000) --attributeDic.antiparryeff:Div(temp):Sub(Const_ParryEffParam_b):Mul(parryeff_C):Mul(-1):Add(standardPlayerAttrDic.parryeff)--old误差大 --new↓ 误差小 attributeDic.antiparryeff:Mul(1000):Div(temp) attributeDic.antiparryeff:Sub(Const_ParryEffParam_b):Mul(parryeff_C):Mul(-1):Add(standardPlayerAttrDic.parryeff) --new↑ end return attributeDic end --------------------------------↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑------------------------------------------------------------- return FormulaCalculator