private static DamageHandler HandleCrit(SkillCast skillCast) { double damage = skillCast.GetDamageRate(); bool crit = skillCast.RollCrit(); if (crit) { damage += damage; } DamageHandler toReturn = new DamageHandler(damage, crit); return(toReturn); }
public static DamageHandler CalculateDamage(SkillCast skill, IFieldActor source, IFieldActor target, double luckCoefficient) { // TODO: get accuracyWeakness from enemy stats from enemy buff. new stat recommended const double AccuracyWeakness = 0; double hitRate = (source.Stats[StatAttribute.Accuracy].Total + AccuracyWeakness) / Math.Max(target.Stats[StatAttribute.Evasion].Total, 0.1); if (Random.Shared.NextDouble() > hitRate) { return(new(source, target, 0, HitType.Miss)); // we missed } bool isCrit = skill.IsGuaranteedCrit() || RollCrit(source, target, luckCoefficient); double finalCritDamage = 1; if (isCrit) { // TODO: get critResist from enemy stats from enemy buff. new stat recommended const double CritResist = 1; double critDamage = 1000 + source.Stats[StatAttribute.CritDamage].Total; finalCritDamage = CritResist * ((critDamage / 1000) - 1) + 1; } double damageBonus = 1 + FetchMultiplier(source.Stats, StatAttribute.TotalDamage); damageBonus *= finalCritDamage; switch (skill.GetElement()) { case Element.Fire: damageBonus += FetchMultiplier(source.Stats, StatAttribute.FireDamage); break; case Element.Ice: damageBonus += FetchMultiplier(source.Stats, StatAttribute.IceDamage); break; case Element.Electric: damageBonus += FetchMultiplier(source.Stats, StatAttribute.ElectricDamage); break; case Element.Holy: damageBonus += FetchMultiplier(source.Stats, StatAttribute.HolyDamage); break; case Element.Dark: damageBonus += FetchMultiplier(source.Stats, StatAttribute.DarkDamage); break; case Element.Poison: damageBonus += FetchMultiplier(source.Stats, StatAttribute.PoisonDamage); break; } SkillRangeType rangeType = skill.GetRangeType(); if (rangeType != SkillRangeType.Special) { damageBonus += FetchMultiplier(source.Stats, rangeType == SkillRangeType.Melee ? StatAttribute.MeleeDamage : StatAttribute.RangedDamage); } bool isBoss = false; if (target is INpc npc) { isBoss = npc.Value.IsBoss(); } damageBonus += isBoss ? FetchMultiplier(source.Stats, StatAttribute.BossDamage) : 0; // TODO: properly fetch enemy attack speed weakness from enemy buff. new stat recommended const double AttackSpeedWeakness = 0; damageBonus += AttackSpeedWeakness * FetchMultiplier(source.Stats, StatAttribute.AttackSpeed); double damageMultiplier = damageBonus * skill.GetDamageRate(); // TODO: properly fetch enemy pierce resistance from enemy buff. new stat recommended const double EnemyPierceResistance = 1; double defensePierce = 1 - Math.Min(0.3, EnemyPierceResistance * FetchMultiplier(source.Stats, StatAttribute.Pierce)); damageMultiplier *= 1 / (Math.Max(target.Stats[StatAttribute.Defense].Total, 1) * defensePierce); bool isPhysical = skill.GetSkillDamageType() == DamageType.Physical; StatAttribute resistanceStat = isPhysical ? StatAttribute.PhysicalRes : StatAttribute.MagicRes; StatAttribute attackStat = isPhysical ? StatAttribute.PhysicalAtk : StatAttribute.MagicAtk; StatAttribute piercingStat = isPhysical ? StatAttribute.PhysicalPiercing : StatAttribute.MagicPiercing; double targetRes = target.Stats[resistanceStat].Total; double attackType = source.Stats[attackStat].Total; double resPierce = FetchMultiplier(source.Stats, piercingStat); double resistance = (1500.0 - Math.Max(0, targetRes - 1500 * resPierce)) / 1500; // does this need to be divided by anything at all to account for raw physical attack? damageMultiplier *= attackType * resistance; // TODO: apply special standalone multipliers like Spicy Maple Noodles buff? it seems to have had it's own multiplier. new stat recommended const double FinalDamageMultiplier = 1; damageMultiplier *= FinalDamageMultiplier; double attackDamage = 300; if (source is IFieldActor <Player> player) { double bonusAttack = player.Stats[StatAttribute.BonusAtk].Total + 0.4 * player.Stats[StatAttribute.PetBonusAtk].Total; // TODO: properly fetch enemy bonus attack weakness from enemy buff. new stat recommended const double BonusAttackWeakness = 1; double minDamage = player.Stats[StatAttribute.MinWeaponAtk].Total + BonusAttackWeakness * bonusAttack; double maxDamage = player.Stats[StatAttribute.MaxWeaponAtk].Total + BonusAttackWeakness * bonusAttack; attackDamage = minDamage + (maxDamage - minDamage) * Random.Shared.NextDouble(); } attackDamage *= damageMultiplier; return(new(source, target, Math.Max(1, attackDamage), isCrit ? HitType.Critical : HitType.Normal)); }