public float GetResistanceMod(DamageType damageType, WorldObject damageSource, float weaponResistanceMod) { var ignoreMagicResist = damageSource != null ? damageSource.IgnoreMagicResist : false; var resistanceType = Creature.GetResistanceType(damageType); if (ignoreMagicResist) { return((float)Creature.GetNaturalResistance(resistanceType)); } else { return((float)Creature.GetResistanceMod(resistanceType, weaponResistanceMod)); } }
/// <summary> /// Calculates the damage for a spell projectile /// Used by war magic, void magic, and life magic projectiles /// </summary> public float?CalculateDamage(WorldObject source, WorldObject caster, Creature target, ref bool criticalHit, ref bool critDefended, ref bool overpower) { var sourcePlayer = source as Player; var targetPlayer = target as Player; if (source == null || !target.IsAlive || targetPlayer != null && targetPlayer.Invincible) { return(null); } // check lifestone protection if (targetPlayer != null && targetPlayer.UnderLifestoneProtection) { if (sourcePlayer != null) { sourcePlayer.Session.Network.EnqueueSend(new GameMessageSystemChat($"The Lifestone's magic protects {targetPlayer.Name} from the attack!", ChatMessageType.Magic)); } targetPlayer.HandleLifestoneProtection(); return(null); } var critDamageBonus = 0.0f; var weaponCritDamageMod = 1.0f; var weaponResistanceMod = 1.0f; var resistanceMod = 1.0f; // life magic var lifeMagicDamage = 0.0f; // war/void magic var baseDamage = 0; var skillBonus = 0.0f; var finalDamage = 0.0f; var resistanceType = Creature.GetResistanceType(Spell.DamageType); var sourceCreature = source as Creature; if (sourceCreature?.Overpower != null) { overpower = Creature.GetOverpower(sourceCreature, target); } var resisted = source.TryResistSpell(target, Spell, caster, true); if (resisted && !overpower) { return(null); } CreatureSkill attackSkill = null; if (sourceCreature != null) { attackSkill = sourceCreature.GetCreatureSkill(Spell.School); } // critical hit var criticalChance = GetWeaponMagicCritFrequency(sourceCreature, attackSkill, target); if (ThreadSafeRandom.Next(0.0f, 1.0f) < criticalChance) { if (targetPlayer != null && targetPlayer.AugmentationCriticalDefense > 0) { var criticalDefenseMod = sourcePlayer != null ? 0.05f : 0.25f; var criticalDefenseChance = targetPlayer.AugmentationCriticalDefense * criticalDefenseMod; if (criticalDefenseChance > ThreadSafeRandom.Next(0.0f, 1.0f)) { critDefended = true; } } if (!critDefended) { criticalHit = true; } } var absorbMod = GetAbsorbMod(target); bool isPVP = sourcePlayer != null && targetPlayer != null; if (isPVP && Spell.IsHarmful) { Player.UpdatePKTimers(sourcePlayer, targetPlayer); } var elementalDamageMod = GetCasterElementalDamageModifier(sourceCreature, target, Spell.DamageType); // Possible 2x + damage bonus for the slayer property var slayerMod = GetWeaponCreatureSlayerModifier(sourceCreature, target); // life magic projectiles: ie., martyr's hecatomb if (Spell.MetaSpellType == ACE.Entity.Enum.SpellType.LifeProjectile) { lifeMagicDamage = LifeProjectileDamage * Spell.DamageRatio; // could life magic projectiles crit? // if so, did they use the same 1.5x formula as war magic, instead of 2.0x? if (criticalHit) { weaponCritDamageMod = GetWeaponCritDamageMod(sourceCreature, attackSkill, target); critDamageBonus = lifeMagicDamage * 0.5f * weaponCritDamageMod; } weaponResistanceMod = GetWeaponResistanceModifier(sourceCreature, attackSkill, Spell.DamageType); // if attacker/weapon has IgnoreMagicResist directly, do not transfer to spell projectile // only pass if SpellProjectile has it directly, such as 2637 - Invoking Aun Tanua resistanceMod = (float)Math.Max(0.0f, target.GetResistanceMod(resistanceType, this, null, weaponResistanceMod)); finalDamage = (lifeMagicDamage + critDamageBonus) * elementalDamageMod * slayerMod * resistanceMod * absorbMod; } // war/void magic projectiles else { if (criticalHit) { // Original: // http://acpedia.org/wiki/Announcements_-_2002/08_-_Atonement#Letter_to_the_Players // Critical Strikes: In addition to the skill-based damage bonus, each projectile spell has a 2% chance of causing a critical hit on the target and doing increased damage. // A magical critical hit is similar in some respects to melee critical hits (although the damage calculation is handled differently). // While a melee critical hit automatically does twice the maximum damage of the weapon, a magical critical hit will do an additional half the minimum damage of the spell. // For instance, a magical critical hit from a level 7 spell, which does 110-180 points of damage, would add an additional 55 points of damage to the spell. // Later updated for PvE only: // http://acpedia.org/wiki/Announcements_-_2004/07_-_Treaties_in_Stone#Letter_to_the_Players // Currently when a War Magic spell scores a critical hit, it adds a multiple of the base damage of the spell to a normal damage roll. // Starting in July, War Magic critical hits will instead add a multiple of the maximum damage of the spell. // No more crits that do less damage than non-crits! if (isPVP) // PvP: 50% of the MIN damage added to normal damage roll { critDamageBonus = Spell.MinDamage * 0.5f; } else // PvE: 50% of the MAX damage added to normal damage roll { critDamageBonus = Spell.MaxDamage * 0.5f; } weaponCritDamageMod = GetWeaponCritDamageMod(sourceCreature, attackSkill, target); critDamageBonus *= weaponCritDamageMod; } /* War Magic skill-based damage bonus * http://acpedia.org/wiki/Announcements_-_2002/08_-_Atonement#Letter_to_the_Players */ if (sourcePlayer != null) { // per retail stats, level 8 difficulty is capped to 350 instead of 400 // without this, level 7s have the potential to deal more damage than level 8s var difficulty = Math.Min(Spell.Power, 350); // was skillMod possibility capped to 1.3x for level 7 spells in retail, instead of level 8 difficulty cap? var magicSkill = sourcePlayer.GetCreatureSkill(Spell.School).Current; if (magicSkill > difficulty) { // Bonus clamped to a maximum of 50% //var percentageBonus = Math.Clamp((magicSkill - Spell.Power) / 100.0f, 0.0f, 0.5f); var percentageBonus = (magicSkill - difficulty) / 1000.0f; skillBonus = Spell.MinDamage * percentageBonus; } } baseDamage = ThreadSafeRandom.Next(Spell.MinDamage, Spell.MaxDamage); weaponResistanceMod = GetWeaponResistanceModifier(sourceCreature, attackSkill, Spell.DamageType); // if attacker/weapon has IgnoreMagicResist directly, do not transfer to spell projectile // only pass if SpellProjectile has it directly, such as 2637 - Invoking Aun Tanua resistanceMod = (float)Math.Max(0.0f, target.GetResistanceMod(resistanceType, this, null, weaponResistanceMod)); if (sourcePlayer != null && targetPlayer != null && Spell.DamageType == DamageType.Nether) { // for direct damage from void spells in pvp, // apply void_pvp_modifier *on top of* the player's natural resistance to nether // this supposedly brings the direct damage from void spells in pvp closer to retail resistanceMod *= (float)PropertyManager.GetDouble("void_pvp_modifier").Item; } finalDamage = baseDamage + critDamageBonus + skillBonus; finalDamage *= elementalDamageMod * slayerMod * resistanceMod * absorbMod; } // show debug info if (sourceCreature != null && sourceCreature.DebugDamage.HasFlag(Creature.DebugDamageType.Attacker)) { ShowInfo(sourceCreature, Spell, attackSkill, criticalChance, criticalHit, critDefended, overpower, weaponCritDamageMod, skillBonus, baseDamage, critDamageBonus, elementalDamageMod, slayerMod, weaponResistanceMod, resistanceMod, absorbMod, LifeProjectileDamage, lifeMagicDamage, finalDamage); } if (target.DebugDamage.HasFlag(Creature.DebugDamageType.Defender)) { ShowInfo(target, Spell, attackSkill, criticalChance, criticalHit, critDefended, overpower, weaponCritDamageMod, skillBonus, baseDamage, critDamageBonus, elementalDamageMod, slayerMod, weaponResistanceMod, resistanceMod, absorbMod, LifeProjectileDamage, lifeMagicDamage, finalDamage); } return(finalDamage); }
/// <summary> /// Calculates the damage for a spell projectile /// Used by war magic, void magic, and life magic projectiles /// </summary> public double?CalculateDamage(WorldObject _source, Creature target, ref bool criticalHit) { var source = _source as Creature; var sourcePlayer = source as Player; var targetPlayer = target as Player; if (source == null || targetPlayer != null && targetPlayer.Invincible == true) { return(null); } // target already dead? if (target.Health.Current <= 0) { return(-1); } // check lifestone protection if (targetPlayer != null && targetPlayer.UnderLifestoneProtection) { targetPlayer.HandleLifestoneProtection(); return(null); } double damageBonus = 0.0f, warSkillBonus = 0.0f, finalDamage = 0.0f; var resistanceType = Creature.GetResistanceType(Spell.DamageType); var resisted = source.ResistSpell(target, Spell); if (resisted != null && resisted == true) { return(null); } CreatureSkill attackSkill = null; var sourceCreature = source as Creature; if (sourceCreature != null) { attackSkill = sourceCreature.GetCreatureSkill(Spell.School); } // critical hit var critical = GetWeaponMagicCritFrequencyModifier(source, attackSkill, target); if (ThreadSafeRandom.Next(0.0f, 1.0f) < critical) { var criticalDefended = false; if (targetPlayer != null && targetPlayer.AugmentationCriticalDefense > 0) { var criticalDefenseMod = sourcePlayer != null ? 0.05f : 0.25f; var criticalDefenseChance = targetPlayer.AugmentationCriticalDefense * criticalDefenseMod; if (criticalDefenseChance > ThreadSafeRandom.Next(0.0f, 1.0f)) { criticalDefended = true; } } if (!criticalDefended) { criticalHit = true; } } var shieldMod = GetShieldMod(target); bool isPVP = sourcePlayer != null && targetPlayer != null; if (isPVP && Spell.IsHarmful) { Player.UpdatePKTimers(sourcePlayer, targetPlayer); } var elementalDmgBonus = GetCasterElementalDamageModifier(source, target, Spell.DamageType); // Possible 2x + damage bonus for the slayer property var slayerBonus = GetWeaponCreatureSlayerModifier(source, target); // life magic projectiles: ie., martyr's hecatomb if (Spell.School == MagicSchool.LifeMagic) { var lifeMagicDamage = LifeProjectileDamage * Spell.DamageRatio; // could life magic projectiles crit? // if so, did they use the same 1.5x formula as war magic, instead of 2.0x? if (criticalHit) { damageBonus = lifeMagicDamage * 0.5f * GetWeaponCritDamageMod(source, attackSkill, target); } finalDamage = (lifeMagicDamage + damageBonus) * elementalDmgBonus * slayerBonus * shieldMod; return(finalDamage); } // war magic projectiles (and void currently) else { if (criticalHit) { if (isPVP) // PvP: 50% of the MIN damage added to normal damage roll { damageBonus = Spell.MinDamage * 0.5f; } else // PvE: 50% of the MAX damage added to normal damage roll { damageBonus = Spell.MaxDamage * 0.5f; } var critDamageMod = GetWeaponCritDamageMod(source, attackSkill, target); damageBonus *= critDamageMod; } /* War Magic skill-based damage bonus * http://acpedia.org/wiki/Announcements_-_2002/08_-_Atonement#Letter_to_the_Players */ if (sourcePlayer != null && Spell.School == MagicSchool.WarMagic) { var warSkill = source.GetCreatureSkill(Spell.School).Current; if (warSkill > Spell.Power) { // Bonus clamped to a maximum of 50% var percentageBonus = Math.Clamp((warSkill - Spell.Power) / 100.0f, 0.0f, 0.5f); warSkillBonus = Spell.MinDamage * percentageBonus; } } var baseDamage = ThreadSafeRandom.Next(Spell.MinDamage, Spell.MaxDamage); var weaponResistanceMod = GetWeaponResistanceModifier(source, attackSkill, Spell.DamageType); finalDamage = baseDamage + damageBonus + warSkillBonus; finalDamage *= target.GetResistanceMod(resistanceType, null, weaponResistanceMod) * elementalDmgBonus * slayerBonus * shieldMod; return(finalDamage); } }
/// <summary> /// Calculates the damage for a spell projectile /// Used by war magic, void magic, and life magic projectiles /// </summary> public double?CalculateDamage(WorldObject source, WorldObject caster, Creature target, ref bool criticalHit, ref bool critDefended, ref bool overpower) { var sourcePlayer = source as Player; var targetPlayer = target as Player; if (source == null || targetPlayer != null && targetPlayer.Invincible == true) { return(null); } // target already dead? if (target.Health.Current <= 0) { return(-1); } // check lifestone protection if (targetPlayer != null && targetPlayer.UnderLifestoneProtection) { if (sourcePlayer != null) { sourcePlayer.Session.Network.EnqueueSend(new GameMessageSystemChat($"The Lifestone's magic protects {targetPlayer.Name} from the attack!", ChatMessageType.Magic)); } targetPlayer.HandleLifestoneProtection(); return(null); } double damageBonus = 0.0f, warSkillBonus = 0.0f, finalDamage = 0.0f; var resistanceType = Creature.GetResistanceType(Spell.DamageType); var sourceCreature = source as Creature; if (sourceCreature?.Overpower != null) { overpower = Creature.GetOverpower(sourceCreature, target); } var resisted = source.ResistSpell(target, Spell, caster); if (resisted == true && !overpower) { return(null); } CreatureSkill attackSkill = null; if (sourceCreature != null) { attackSkill = sourceCreature.GetCreatureSkill(Spell.School); } // critical hit var critical = GetWeaponMagicCritFrequency(sourceCreature, attackSkill, target); if (ThreadSafeRandom.Next(0.0f, 1.0f) < critical) { if (targetPlayer != null && targetPlayer.AugmentationCriticalDefense > 0) { var criticalDefenseMod = sourcePlayer != null ? 0.05f : 0.25f; var criticalDefenseChance = targetPlayer.AugmentationCriticalDefense * criticalDefenseMod; if (criticalDefenseChance > ThreadSafeRandom.Next(0.0f, 1.0f)) { critDefended = true; } } if (!critDefended) { criticalHit = true; } } var absorbMod = GetAbsorbMod(target); bool isPVP = sourcePlayer != null && targetPlayer != null; if (isPVP && Spell.IsHarmful) { Player.UpdatePKTimers(sourcePlayer, targetPlayer); } var elementalDmgBonus = GetCasterElementalDamageModifier(sourceCreature, target, Spell.DamageType); // Possible 2x + damage bonus for the slayer property var slayerBonus = GetWeaponCreatureSlayerModifier(sourceCreature, target); // life magic projectiles: ie., martyr's hecatomb if (Spell.School == MagicSchool.LifeMagic) { var lifeMagicDamage = LifeProjectileDamage * Spell.DamageRatio; // could life magic projectiles crit? // if so, did they use the same 1.5x formula as war magic, instead of 2.0x? if (criticalHit) { damageBonus = lifeMagicDamage * 0.5f * GetWeaponCritDamageMod(sourceCreature, attackSkill, target); } finalDamage = (lifeMagicDamage + damageBonus) * elementalDmgBonus * slayerBonus * absorbMod; return(finalDamage); } // war/void magic projectiles else { if (criticalHit) { // Original: // http://acpedia.org/wiki/Announcements_-_2002/08_-_Atonement#Letter_to_the_Players // Critical Strikes: In addition to the skill-based damage bonus, each projectile spell has a 2% chance of causing a critical hit on the target and doing increased damage. // A magical critical hit is similar in some respects to melee critical hits (although the damage calculation is handled differently). // While a melee critical hit automatically does twice the maximum damage of the weapon, a magical critical hit will do an additional half the minimum damage of the spell. // For instance, a magical critical hit from a level 7 spell, which does 110-180 points of damage, would add an additional 55 points of damage to the spell. // Later updated for PvE only: // http://acpedia.org/wiki/Announcements_-_2004/07_-_Treaties_in_Stone#Letter_to_the_Players // Currently when a War Magic spell scores a critical hit, it adds a multiple of the base damage of the spell to a normal damage roll. // Starting in July, War Magic critical hits will instead add a multiple of the maximum damage of the spell. // No more crits that do less damage than non-crits! if (isPVP) // PvP: 50% of the MIN damage added to normal damage roll { damageBonus = Spell.MinDamage * 0.5f; } else // PvE: 50% of the MAX damage added to normal damage roll { damageBonus = Spell.MaxDamage * 0.5f; } var critDamageMod = GetWeaponCritDamageMod(sourceCreature, attackSkill, target); damageBonus *= critDamageMod; } /* War Magic skill-based damage bonus * http://acpedia.org/wiki/Announcements_-_2002/08_-_Atonement#Letter_to_the_Players */ if (sourcePlayer != null) { // per retail stats, level 8 difficulty is capped to 350 instead of 400 // without this, level 7s have the potential to deal more damage than level 8s var difficulty = Math.Min(Spell.Power, 350); var magicSkill = sourcePlayer.GetCreatureSkill(Spell.School).Current; if (magicSkill > difficulty) { // Bonus clamped to a maximum of 50% //var percentageBonus = Math.Clamp((magicSkill - Spell.Power) / 100.0f, 0.0f, 0.5f); var percentageBonus = (magicSkill - difficulty) / 1000.0f; warSkillBonus = Spell.MinDamage * percentageBonus; } } var baseDamage = ThreadSafeRandom.Next(Spell.MinDamage, Spell.MaxDamage); var weaponResistanceMod = GetWeaponResistanceModifier(sourceCreature, attackSkill, Spell.DamageType); var resistanceMod = Math.Max(0.0f, target.GetResistanceMod(resistanceType, null, weaponResistanceMod)); finalDamage = baseDamage + damageBonus + warSkillBonus; finalDamage *= resistanceMod * elementalDmgBonus * slayerBonus * absorbMod; return(finalDamage); } }
/// <summary> /// Calculates the damage for a spell projectile /// Used by war magic, void magic, and life magic projectiles /// </summary> public double?CalculateDamage(WorldObject source, Creature target, ref bool criticalHit, ref bool critDefended, ref bool overpower) { var sourcePlayer = source as Player; var targetPlayer = target as Player; if (source == null || targetPlayer != null && targetPlayer.Invincible == true) { return(null); } // target already dead? if (target.Health.Current <= 0) { return(-1); } // check lifestone protection if (targetPlayer != null && targetPlayer.UnderLifestoneProtection) { if (sourcePlayer != null) { sourcePlayer.Session.Network.EnqueueSend(new GameMessageSystemChat($"The Lifestone's magic protects {targetPlayer.Name} from the attack!", ChatMessageType.Magic)); } targetPlayer.HandleLifestoneProtection(); return(null); } double damageBonus = 0.0f, warSkillBonus = 0.0f, finalDamage = 0.0f; var resistanceType = Creature.GetResistanceType(Spell.DamageType); var sourceCreature = source as Creature; if (sourceCreature?.Overpower != null) { overpower = Creature.GetOverpower(sourceCreature, target); } var resisted = source.ResistSpell(target, Spell); if (resisted == true && !overpower) { return(null); } CreatureSkill attackSkill = null; if (sourceCreature != null) { attackSkill = sourceCreature.GetCreatureSkill(Spell.School); } // critical hit var critical = GetWeaponMagicCritFrequencyModifier(sourceCreature, attackSkill, target); if (ThreadSafeRandom.Next(0.0f, 1.0f) < critical) { if (targetPlayer != null && targetPlayer.AugmentationCriticalDefense > 0) { var criticalDefenseMod = sourcePlayer != null ? 0.05f : 0.25f; var criticalDefenseChance = targetPlayer.AugmentationCriticalDefense * criticalDefenseMod; if (criticalDefenseChance > ThreadSafeRandom.Next(0.0f, 1.0f)) { critDefended = true; } } if (!critDefended) { criticalHit = true; } } var absorbMod = GetAbsorbMod(target); bool isPVP = sourcePlayer != null && targetPlayer != null; if (isPVP && Spell.IsHarmful) { Player.UpdatePKTimers(sourcePlayer, targetPlayer); } var elementalDmgBonus = GetCasterElementalDamageModifier(sourceCreature, target, Spell.DamageType); // Possible 2x + damage bonus for the slayer property var slayerBonus = GetWeaponCreatureSlayerModifier(sourceCreature, target); // life magic projectiles: ie., martyr's hecatomb if (Spell.School == MagicSchool.LifeMagic) { var lifeMagicDamage = LifeProjectileDamage * Spell.DamageRatio; // could life magic projectiles crit? // if so, did they use the same 1.5x formula as war magic, instead of 2.0x? if (criticalHit) { damageBonus = lifeMagicDamage * 0.5f * GetWeaponCritDamageMod(sourceCreature, attackSkill, target); } finalDamage = (lifeMagicDamage + damageBonus) * elementalDmgBonus * slayerBonus * absorbMod; return(finalDamage); } // war/void magic projectiles else { if (criticalHit) { if (isPVP) // PvP: 50% of the MIN damage added to normal damage roll { damageBonus = Spell.MinDamage * 0.5f; } else // PvE: 50% of the MAX damage added to normal damage roll { damageBonus = Spell.MaxDamage * 0.5f; } var critDamageMod = GetWeaponCritDamageMod(sourceCreature, attackSkill, target); damageBonus *= critDamageMod; } /* War Magic skill-based damage bonus * http://acpedia.org/wiki/Announcements_-_2002/08_-_Atonement#Letter_to_the_Players */ if (sourcePlayer != null) { // per retail stats, level 8 difficulty is capped to 350 instead of 400 // without this, level 7s have the potential to deal more damage than level 8s var difficulty = Math.Min(Spell.Power, 350); var magicSkill = sourcePlayer.GetCreatureSkill(Spell.School).Current; if (magicSkill > difficulty) { // Bonus clamped to a maximum of 50% //var percentageBonus = Math.Clamp((magicSkill - Spell.Power) / 100.0f, 0.0f, 0.5f); var percentageBonus = (magicSkill - difficulty) / 1000.0f; warSkillBonus = Spell.MinDamage * percentageBonus; } } var baseDamage = ThreadSafeRandom.Next(Spell.MinDamage, Spell.MaxDamage); var weaponResistanceMod = GetWeaponResistanceModifier(sourceCreature, attackSkill, Spell.DamageType); finalDamage = baseDamage + damageBonus + warSkillBonus; finalDamage *= target.GetResistanceMod(resistanceType, null, weaponResistanceMod) * elementalDmgBonus * slayerBonus * absorbMod; return(finalDamage); } }