using CommonAI; using CommonAI.Data; using CommonAI.Zone.Formula; using CommonAI.Zone.Helper; using CommonLang; using CommonLang.Log; using System; using System.Diagnostics; using XmdsCommon.Message; using XmdsCommon.Plugin; namespace XmdsCommonServer.Plugin.XmdsSkillTemplate.DamageCalculator { /// /// Author: justsogo /// Description: 伤害计算器.用于计算伤害结果、公式. /// /// public class XmdsDamageCalculator { //固定系数 //private static readonly float Coefficient_Attack = 1.0f; //攻击系数 //防御系数 private static readonly int[] Coefficient_Defence = new int[13]{ 4342, 4342, 4543, 4793, 5085, 5411, 5763, 6131, 6501, 6855, 7165, 7396, 7500}; //pve怪物K值 private static readonly int[] monster_Defence = new int[13]{ 0, 100, 300, 800, 2000, 5000, 10000, 15000, 20000, 20000, 20000, 20000, 20000}; //PVP伤害系统 private static readonly float PVP_DAMAGE_COEF = 0.7f; //攻击系数 //boss等级压制 private static readonly float BOSS_LEVEL_SUBDUE = 0.05f; //神器对无神器伤害加成 private static readonly int S_ArtifactDamage = 1000; //神器属性 private const float Coefficient_Artifact = 1.1f; //随从受伤K系数 private static readonly float PET_HIT_DAMAGE_K = 2.0f; //万分比. public static float PERER = 10000.0f; //获得当次攻击结果类型(暴击、闪避、招架、普通攻击). public static XmdsCommonServer.Plugin.XmdsVirtual.AttackRlt GetAttckRlt(float hitRate, float criRate, float pierceRate, Random random) { int sum = 1 * 100 * 1000; //普通攻击几率. int normalRate = 0; //暴击. int realCriRate = CUtils.CastInt(criRate * sum); //暴击区间. int start_cri = 0; int end_cri = 0; //招架区间. int start_parry = 0; int end_parry = 0; //普通攻击区间. int start_normal = 0; int end_normal = 0; float overflow = realCriRate - sum; //超过100. if (overflow > 0) { start_parry = end_normal; end_parry = start_parry; start_cri = 0; end_cri = start_cri + realCriRate; } else { normalRate = (sum - realCriRate); start_normal = 0; end_normal = start_normal + normalRate; start_parry = end_normal; end_parry = start_parry; start_cri = 0; end_cri = start_cri + realCriRate; } int k = (random.Next(0, sum)); #region 调试信息. //FormatLog("普通区间[{0}-{1})", start_normal, end_normal); //FormatLog("招架区间[{0}-{1})", start_parry, end_parry); //FormatLog("闪避区间[{0}-{1})", start_dodge, end_dodge); //FormatLog("暴击区间[{0}-{1})", start_cri, end_cri); #endregion if (IsBetween(k, start_parry, end_parry)) { return XmdsCommonServer.Plugin.XmdsVirtual.AttackRlt.ParryAttack; } else if (IsBetween(k, start_cri, end_cri)) { return XmdsCommonServer.Plugin.XmdsVirtual.AttackRlt.CritAttack; } else if (IsBetween(k, start_normal, end_normal)) { return XmdsCommonServer.Plugin.XmdsVirtual.AttackRlt.NormalAttack; } XmdsVirtual.FormatLog("攻击结果计算异常"); return XmdsCommonServer.Plugin.XmdsVirtual.AttackRlt.NormalAttack; } //判断是否在区间内[). private static bool IsBetween(int num, int start, int end) { if (num >= start && num < end) { return true; } else { return false; } } #region 新战斗公式. /// /// 判断是否在所指定范围内. /// public static bool IsInRandomRange(int val, Random random, int range) { bool ret; int r = random.Next(range); ret = (r <= val) ? true : false; return ret; } /// /// 获得指定范围的值. /// public static int GetValueFromRange(Random random, int rangeStart, int rangeEnd) { int ret = random.Next(rangeStart, rangeEnd); return ret; } /// /// 获得技能伤害(面板+技能效果) /// /// /// /// /// public static int GetSkillDamage(int CharDamage, float PerDamage, int ExdDamge) { int ret = 0; ret = CUtils.CastInt(CharDamage * (PerDamage / PERER) + ExdDamge); return ret; } /// /// 获得暴击伤害. /// /// /// /// /// public static int GetCritDamage(int damage, XmdsVirtual attacker, XmdsVirtual hitter) { int baseCritDamage = attacker.MirrorProp.CritDamage - hitter.MirrorProp.CritDamageRes; if (attacker.IsPlayerUnit() && hitter.IsBoss()) { baseCritDamage += attacker.MirrorProp.ToBossCritDamage ; } return baseCritDamage; } public static int GetCritHealDamage(int damage, XmdsVirtual attacker, XmdsVirtual hitter) { return attacker.MirrorProp.CritDamage; } private static int GetDefenceAddition(int level) { if (level < 0 || level > 12) { return Coefficient_Defence[0]; } return Coefficient_Defence[level]; } private static int GetMonsterDefAddition(int level) { if (level < 0 || level > 12) { return monster_Defence[0]; } return monster_Defence[level]; } /// /// 根据攻击类型获得伤害值. /// /// /// /// /// /// public static int GetDamage(int damageBaseValue, XmdsVirtual attacker, XmdsVirtual hitter, AttackSource source) { //攻击与防御公式:伤害=k1*A*(1-D*(1-P)/(D*(1-p)+k2)) //0. 技能总伤害加成. XmdsSkillType FromSkillType = source == null ? XmdsSkillType.none : source.FromSkillType; if (FromSkillType == XmdsSkillType.active || FromSkillType == XmdsSkillType.petGiveAcitve || FromSkillType == XmdsSkillType.cardSkill) { damageBaseValue = CUtils.CastInt(damageBaseValue * (1 + (attacker.MirrorProp.SkillDamageAdd) / XmdsDamageCalculator.PERER)); } //1. 计算防御 //真实防御 int attackIgnoreDef = source == null ? 0 : source.ignoreDef; double realDef = ((hitter.MirrorProp.Defence - attacker.MirrorProp.IgnoreDefense) * (PERER - attacker.MirrorProp.IgnoreDefensePer - attackIgnoreDef) / PERER); //完全破防, if(realDef < 0) { //XmdsVirtual.FormatLog(LoggerLevel.ERROR, "0. 防御异常 : {0}, {1}, {2}, {3}, {4}, {5}", // realDef, hitter.GetStateLv(), hitter.MirrorProp.Defence, attacker.MirrorProp.IgnoreDefense, hitter.mUnit.Info.Name, attacker.mUnit.Info.Name); realDef = 0; } //防御系数 double DefCoef = realDef / (realDef + GetDefenceAddition(attacker.GetStateLv())); //2. 计算伤害增加,减免 int addDamage = attacker.MirrorProp.AllDmgAdd; int damageReduce = hitter.MirrorProp.AllDmgReduce; int monsterDmgChg = 0; //怪物与玩家间伤害变更 int playerDmgChg = 0; //玩家与玩家间伤害变更 int artifaceMainDamage = 0; // 神器伤害 float monsterAtkPer = 1.0f; // 怪打玩家猎妖相关属性叠加 if (attacker.IsPlayerUnit()) { if(hitter.IsPlayerUnit()) { //MMO-14874: 2021.3.30修改成玩家间生效 playerDmgChg += attacker.MirrorProp.PlayerDamageAdd; playerDmgChg -= hitter.MirrorProp.PlayerDamageReduce; //3. 杀意值附加,仅限玩家之间PK playerDmgChg += (attacker.MirrorProp.KillValuePer - hitter.MirrorProp.KillValuePer); //4. 2021.05.11修改:神器属性加成。有对无,无对有。都是基础加成 // 去掉弱克 if (attacker.GetArtifactIndex() != (int)ArtifactType.None) { if(hitter.GetArtifactDefenceIndex() != (int)ArtifactType.None) { if (((int)attacker.GetArtifactIndex() + 1) % 5 == hitter.GetArtifactDefenceIndex())//强克, 取神器克制属性 { artifaceMainDamage += attacker.MirrorProp.ArtifactRestraint[attacker.GetArtifactIndex()]; } //else if ((hitter.GetArtifactIndex() + 2) % 4 == attacker.GetArtifactIndex())//弱克 //{ // artifaceMainDamage += (attacker.MirrorProp.ArtifactRestraint[attacker.GetArtifactIndex()] / 2 - hitter.MirrorProp.ArtifactResist[hitter.GetArtifactIndex()]); //} else if (((int)hitter.GetArtifactDefenceIndex() + 1) % 5 == attacker.GetArtifactIndex()) //被强克, 取背饰抵御属性 { artifaceMainDamage -= hitter.MirrorProp.ArtifactResist[hitter.GetArtifactDefenceIndex()]; } //else if ((attacker.GetArtifactIndex() + 2) % 4 == hitter.GetArtifactIndex()) //被弱克 //{ // artifaceMainDamage -= hitter.MirrorProp.ArtifactResist[hitter.GetArtifactIndex()] / 2; //} } else { artifaceMainDamage += (S_ArtifactDamage + attacker.MirrorProp.ArtifactRestraint[attacker.GetArtifactIndex()]); //有神器对无背饰 } } else if(hitter.GetArtifactDefenceIndex() != (int)ArtifactType.None) { artifaceMainDamage -= (S_ArtifactDamage + hitter.MirrorProp.ArtifactResist[hitter.GetArtifactDefenceIndex()]); //无神器对有背饰 } //Console.WriteLine("最终神器属性变更:" + artifaceMainDamage); //5. 五行元素伤害加成() for (int i = 0; i <= (int)ArtifactType.Fire; i++) { if (attacker.MirrorProp.ArtifactAttack[i] == 0) continue; // 单个五行元素攻击加成上限5% // 攻击者元素攻击 / (攻击者元素攻击 + 2 * 受击者元素防御) artifaceMainDamage += 500 * attacker.MirrorProp.ArtifactAttack[i] / (attacker.MirrorProp.ArtifactAttack[i] + 2 * hitter.MirrorProp.ArtifactDefense[i]); } } else { //攻击者是玩家, 受击者是怪物 //6. 怪物伤害加成 monsterDmgChg += attacker.MirrorProp.monsterDamageAdd; //7. 天命属性伤害加成 (宠物命格) UnitFateType hitterFateType = hitter.GetUnitFateType(); if (hitterFateType != UnitFateType.None) { if (hitterFateType < UnitFateType.None || hitterFateType > UnitFateType.Five) { XmdsVirtual.FormatLog(LoggerLevel.ERROR, "单位天赋错误:" + hitter.mInfo.ID + ", 天命值:" + hitterFateType); return 0; } UnitFateType restraintType = (hitterFateType == UnitFateType.One ? UnitFateType.Five : (hitterFateType - 1)); // 队伍宠物 monsterDmgChg += attacker.mUnit.GetTeamFateValue(restraintType); //个人天命属性加成 monsterDmgChg += attacker.MirrorProp.MonsterRestraint[(int)restraintType-1]; } //8. MMO-17397: 额外扭曲系统:玩家神兵克制怪物命格 //怪物的天命对应五行:1金 2木 3土 4水 5火 if (attacker.IsHasArtifact() && (hitterFateType == UnitFateType.None || attacker.IsArtifactRestrain(hitterFateType))) { monsterDmgChg += attacker.MirrorProp.ArtifactRestraint[attacker.GetArtifactIndex()]; } //9. 玩家猎妖伤害值 //damageBaseValue += attacker.MirrorProp.MaxMonsterAttack; } } else { //攻击者为怪物, 受击者是玩家 if (hitter.IsPlayerUnit()) { monsterDmgChg -= hitter.MirrorProp.monsterDamageReduce; //猎妖防御系数 if(hitter.GetStateLv() > 0) { int atkMonsterDef = GetMonsterDefAddition(attacker.GetStateLv()); if(atkMonsterDef > 0) { monsterAtkPer = 2.0f * atkMonsterDef / (atkMonsterDef + hitter.MirrorProp.MaxMonsterDef); } } } } float allDmgChgFinal = GetFinalDamageValue(addDamage - damageReduce); float monsterDmgChgFinal = GetFinalDamageValue(monsterDmgChg); float playerDmgChgFinal = GetFinalDamageValue(playerDmgChg); float artifaceDmgChgFinal = GetFinalDamageValue(artifaceMainDamage); int damage = CUtils.CastInt(damageBaseValue * (1.0f - DefCoef) * allDmgChgFinal * monsterDmgChgFinal * playerDmgChgFinal * artifaceDmgChgFinal * monsterAtkPer); //异常日志输出--justsogo #if JSG_DMG_LOG if (damageBaseValue > 50 && (damage <= 1 || damage > 30000000)) { XmdsVirtual.FormatLog(LoggerLevel.ERROR, "----1. 伤害异常 : {0}, {1}, {2}, {3}, 防御信息:{4}, {5}, {6}", attacker.mInfo.Name, hitter.mInfo.Name, FromSkillType, damage, hitter.MirrorProp.Defence, attacker.MirrorProp.IgnoreDefense, attacker.MirrorProp.IgnoreDefensePer); int spellInfo = source.FromSpell == null ? 0 : source.FromSpell.ID; XmdsVirtual.FormatLog(LoggerLevel.ERROR, "2. 伤害异常 : {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}", damageBaseValue, DefCoef, damageReduce, addDamage, artifaceMainDamage, spellInfo, attacker.mUnit.PlayerUUID, hitter.mUnit.PlayerUUID); //XmdsVirtual.FormatLog(LoggerLevel.ERROR, "3. 伤害异常受击防御 : {0},攻击穿透:{1},防御系数:{2},杀意信息:{3},{4}", // hitter.MirrorProp.Defence, attacker.MirrorProp.IgnoreDefensePer, GetDefenceAddition(hitter.GetStateLv()), // hitter.MirrorProp.KillValuePer, attacker.MirrorProp.KillValuePer); } #endif //Console.WriteLine("受击ID: " + hitter.mUnit.ID + ", " + damage); if (attacker.IsPlayerUnit()) { if(hitter.IsPlayerUnit()) { damage = CUtils.CastInt(damage * PVP_DAMAGE_COEF); } } else if(attacker.IsLvRepress() && attacker.mUnit.Level > hitter.mUnit.Level) { //LvRepress damage = CUtils.CastInt(damage * (1 + (attacker.mUnit.Level - hitter.mUnit.Level) * BOSS_LEVEL_SUBDUE)); } return Math.Max(damage, 1); } public static int GetPetDamage(int damageBaseValue, XmdsVirtual pet) { //防御属性 float finalDef = pet.MirrorProp.Defence; float ingoreDmg = 1.0f - finalDef / (finalDef + GetDefenceAddition(pet.GetStateLv())); //伤害变更(免伤,受伤加深) float allDmgChg = GetFinalDamageValue(pet.MirrorProp.AllDmgAdd - pet.MirrorProp.AllDmgReduce); int finalDmg = Math.Max(1, (int)(damageBaseValue * PET_HIT_DAMAGE_K * ingoreDmg * allDmgChg)); return finalDmg; } private static float GetFinalDamageValue(int value) { if (value < 0) { return 1.0f + Math.Max(-XmdsConstConfig.DAMAGE_CHG_MAX, value) * XmdsUnitProp.PER; } else { return 1.0f + Math.Min(XmdsConstConfig.DAMAGE_CHG_MAX, value) * XmdsUnitProp.PER; } } public static int GetDefByLevel(int level) { if(level <= 70) { return Coefficient_Defence[0]; } int UpLevel = Math.Min(12 ,(level - 70) / 10); return Coefficient_Defence[UpLevel]; } #endregion } }