/// <summary> /// Calculates damage to target with resist chance and stores it in ad /// </summary> /// <param name="target">spell target</param> /// <param name="effectiveness">value from 0..1 to modify damage</param> /// <returns>attack data</returns> public virtual AttackData CalculateDamageToTarget(GameLiving target, double effectiveness) { AttackData ad = new AttackData(); ad.Attacker = m_caster; ad.Target = target; ad.AttackType = AttackData.eAttackType.Spell; ad.SpellHandler = this; ad.AttackResult = GameLiving.eAttackResult.HitUnstyled; double minVariance; double maxVariance; CalculateDamageVariance(target, out minVariance, out maxVariance); double spellDamage = CalculateDamageBase(target); if (m_caster is GamePlayer) { effectiveness += m_caster.GetModified(eProperty.SpellDamage) * 0.01; // Relic bonus applied to damage, does not alter effectiveness or increase cap spellDamage *= (1.0 + RelicMgr.GetRelicBonusModifier(m_caster.Realm, eRelicType.Magic)); } // Apply casters effectiveness spellDamage *= m_caster.Effectiveness; int finalDamage = Util.Random((int)(minVariance * spellDamage), (int)(maxVariance * spellDamage)); // Live testing done Summer 2009 by Bluraven, Tolakram Levels 40, 45, 50, 55, 60, 65, 70 // Damage reduced by chance < 55, no extra damage increase noted with hitchance > 100 int hitChance = CalculateToHitChance(ad.Target); finalDamage = AdjustDamageForHitChance(finalDamage, hitChance); // apply spell effectiveness finalDamage = (int)(finalDamage * effectiveness); if ((m_caster is GamePlayer || (m_caster is GameNPC && (m_caster as GameNPC).Brain is IControlledBrain && m_caster.Realm != 0))) { if (target is GamePlayer) finalDamage = (int)((double)finalDamage * ServerProperties.Properties.PVP_SPELL_DAMAGE); else if (target is GameNPC) finalDamage = (int)((double)finalDamage * ServerProperties.Properties.PVE_SPELL_DAMAGE); } // Well the PenetrateResistBuff is NOT ResistPierce GameSpellEffect penPierce = SpellHandler.FindEffectOnTarget(m_caster, "PenetrateResists"); if (penPierce != null) { finalDamage = (int)(finalDamage * (1.0 + penPierce.Spell.Value / 100.0)); } int cdamage = 0; if (finalDamage < 0) finalDamage = 0; eDamageType damageType = DetermineSpellDamageType(); #region Resists eProperty property = target.GetResistTypeForDamage(damageType); // The Daoc resistsystem is since 1.65 a 2category system. // - First category are Item/Race/Buff/RvrBanners resists that are displayed in the characteroverview. // - Second category are resists that are given through RAs like avoidance of magic, brilliance aura of deflection. // Those resist affect ONLY the spelldamage. Not the duration, not the effectiveness of debuffs. // so calculation is (finaldamage * Category1Modification) * Category2Modification // -> Remark for the future: VampirResistBuff is Category2 too. // - avi #region Primary Resists int primaryResistModifier = ad.Target.GetResist(damageType); /* Resist Pierce * Resipierce is a special bonus which has been introduced with TrialsOfAtlantis. * At the calculation of SpellDamage, it reduces the resistance that the victim recives * through ITEMBONUSES for the specified percentage. * http://de.daocpedia.eu/index.php/Resistenz_durchdringen (translated) */ int resiPierce = Caster.GetModified(eProperty.ResistPierce); GamePlayer ply = Caster as GamePlayer; if (resiPierce > 0 && Spell.SpellType != "Archery") { //substract max ItemBonus of property of target, but atleast 0. primaryResistModifier -= Math.Max(0, Math.Min(ad.Target.ItemBonus[(int)property], resiPierce)); } #endregion #region Secondary Resists //Using the resist BuffBonusCategory2 - its unused in ResistCalculator int secondaryResistModifier = target.SpecBuffBonusCategory[(int)property]; if (secondaryResistModifier > 80) secondaryResistModifier = 80; #endregion int resistModifier = 0; //primary resists resistModifier += (int)(finalDamage * (double)primaryResistModifier * -0.01); //secondary resists resistModifier += (int)((finalDamage + (double)resistModifier) * (double)secondaryResistModifier * -0.01); //apply resists finalDamage += resistModifier; #endregion // Apply damage cap (this can be raised by effectiveness) if (finalDamage > DamageCap(effectiveness)) { finalDamage = (int)DamageCap(effectiveness); } if (finalDamage < 0) finalDamage = 0; int criticalchance = (m_caster.SpellCriticalChance); if (Util.Chance(Math.Min(50, criticalchance)) && (finalDamage >= 1)) { int critmax = (ad.Target is GamePlayer) ? finalDamage / 2 : finalDamage; cdamage = Util.Random(finalDamage / 10, critmax); //think min crit is 10% of damage } //Andraste if(ad.Target is GamePlayer && ad.Target.GetModified(eProperty.Conversion)>0) { int manaconversion=(int)Math.Round(((double)ad.Damage+(double)ad.CriticalDamage)*(double)ad.Target.GetModified(eProperty.Conversion)/200); //int enduconversion=(int)Math.Round((double)manaconversion*(double)ad.Target.MaxEndurance/(double)ad.Target.MaxMana); int enduconversion=(int)Math.Round(((double)ad.Damage+(double)ad.CriticalDamage)*(double)ad.Target.GetModified(eProperty.Conversion)/200); if(ad.Target.Mana+manaconversion>ad.Target.MaxMana) manaconversion=ad.Target.MaxMana-ad.Target.Mana; if(ad.Target.Endurance+enduconversion>ad.Target.MaxEndurance) enduconversion=ad.Target.MaxEndurance-ad.Target.Endurance; if(manaconversion<1) manaconversion=0; if(enduconversion<1) enduconversion=0; if(manaconversion>=1) (ad.Target as GamePlayer).Out.SendMessage("You gain "+manaconversion+" power points", eChatType.CT_Spell, eChatLoc.CL_SystemWindow); if(enduconversion>=1) (ad.Target as GamePlayer).Out.SendMessage("You gain "+enduconversion+" endurance points", eChatType.CT_Spell, eChatLoc.CL_SystemWindow); ad.Target.Endurance+=enduconversion; if(ad.Target.Endurance>ad.Target.MaxEndurance) ad.Target.Endurance=ad.Target.MaxEndurance; ad.Target.Mana+=manaconversion; if(ad.Target.Mana>ad.Target.MaxMana) ad.Target.Mana=ad.Target.MaxMana; } ad.Damage = finalDamage; ad.CriticalDamage = cdamage; ad.DamageType = damageType; ad.Modifier = resistModifier; // Attacked living may modify the attack data. Primarily used for keep doors and components. ad.Target.ModifyAttack(ad); m_lastAttackData = ad; return ad; }
public override AttackData CalculateDamageToTarget(GameLiving target, double effectiveness) { GamePlayer player = Caster as GamePlayer; if (player == null) { return(null); } InventoryItem weapon = null; if (player.ActiveWeaponSlot.ToString() == "TwoHanded") { weapon = player.Inventory.GetItem((eInventorySlot)12); } if (player.ActiveWeaponSlot.ToString() == "Standard") { weapon = player.Inventory.GetItem((eInventorySlot)10); } if (weapon == null) { return(null); } //create the AttackData AttackData ad = new AttackData(); ad.Attacker = player; ad.Target = target; ad.Damage = 0; ad.CriticalDamage = 0; ad.WeaponSpeed = player.AttackSpeed(weapon) / 100; ad.DamageType = player.AttackDamageType(weapon); ad.Weapon = weapon; ad.IsOffHand = weapon.Hand == 2; //we need to figure out which armor piece they are going to hit. //figure out the attacktype switch (weapon.Item_Type) { default: case Slot.RIGHTHAND: case Slot.LEFTHAND: ad.AttackType = AttackData.eAttackType.MeleeOneHand; break; case Slot.TWOHAND: ad.AttackType = AttackData.eAttackType.MeleeTwoHand; break; } //Throw Weapon is subject to all the conventional attack results, parry, evade, block, etc. ad.AttackResult = ad.Target.CalculateEnemyAttackResult(ad, weapon); if (ad.AttackResult == GameLiving.eAttackResult.HitUnstyled || ad.AttackResult == GameLiving.eAttackResult.HitStyle) { //we only need to calculate the damage if the attack was a success. double damage = player.AttackDamage(weapon) * effectiveness; if (target is GamePlayer) { ad.ArmorHitLocation = ((GamePlayer)target).CalculateArmorHitLocation(ad); } InventoryItem armor = null; if (target.Inventory != null) { armor = target.Inventory.GetItem((eInventorySlot)ad.ArmorHitLocation); } //calculate the lowerboundary of the damage int lowerboundary = (player.WeaponSpecLevel(weapon) - 1) * 50 / (ad.Target.EffectiveLevel + 1) + 75; lowerboundary = Math.Max(lowerboundary, 75); lowerboundary = Math.Min(lowerboundary, 125); damage *= (player.GetWeaponSkill(weapon) + 90.68) / (ad.Target.GetArmorAF(ad.ArmorHitLocation) + 20 * 4.67); //If they have badge of Valor, we need to modify the damage if (ad.Attacker.EffectList.GetOfType <BadgeOfValorEffect>() != null) { damage *= 1.0 + Math.Min(0.85, ad.Target.GetArmorAbsorb(ad.ArmorHitLocation)); } else { damage *= 1.0 - Math.Min(0.85, ad.Target.GetArmorAbsorb(ad.ArmorHitLocation)); } damage *= (lowerboundary + Util.Random(50)) * 0.01; ad.Modifier = (int)(damage * (ad.Target.GetResist(ad.DamageType) + SkillBase.GetArmorResist(armor, ad.DamageType)) * -0.01); damage += ad.Modifier; int resist = (int)(damage * ad.Target.GetDamageResist(target.GetResistTypeForDamage(ad.DamageType)) * -0.01); eProperty property = ad.Target.GetResistTypeForDamage(ad.DamageType); int secondaryResistModifier = ad.Target.SpecBuffBonusCategory[(int)property]; int resistModifier = 0; resistModifier += (int)((ad.Damage + (double)resistModifier) * (double)secondaryResistModifier * -0.01); damage += resist; damage += resistModifier; ad.Modifier += resist; ad.Damage = (int)damage; ad.UncappedDamage = ad.Damage; ad.Damage = Math.Min(ad.Damage, (int)(player.UnstyledDamageCap(weapon) * effectiveness)); ad.Damage = (int)((double)ad.Damage * ServerProperties.Properties.PVP_MELEE_DAMAGE); if (ad.Damage == 0) { ad.AttackResult = DOL.GS.GameLiving.eAttackResult.Missed; } ad.CriticalDamage = player.GetMeleeCriticalDamage(ad, weapon); } else { //They failed, do they do not get disarmed, and the spell is not disabled for the full duration, //just the modified swing speed, this is in milliseconds int attackSpeed = player.AttackSpeed(weapon); player.TempProperties.setProperty(DISABLE, attackSpeed); } return(ad); }
public override AttackData CalculateDamageToTarget(GameLiving target, double effectiveness) { GamePlayer player = Caster as GamePlayer; if (player == null) return null; InventoryItem weapon = null; if (player.ActiveWeaponSlot.ToString() == "TwoHanded") weapon = player.Inventory.GetItem((eInventorySlot)12); if (player.ActiveWeaponSlot.ToString() == "Standard") weapon = player.Inventory.GetItem((eInventorySlot)10); if (weapon == null) return null; //create the AttackData AttackData ad = new AttackData(); ad.Attacker = player; ad.Target = target; ad.Damage = 0; ad.CriticalDamage = 0; ad.WeaponSpeed = player.AttackSpeed(weapon) / 100; ad.DamageType = player.AttackDamageType(weapon); ad.Weapon = weapon; ad.IsOffHand = weapon.Hand == 2; //we need to figure out which armor piece they are going to hit. //figure out the attacktype switch (weapon.Item_Type) { default: case Slot.RIGHTHAND: case Slot.LEFTHAND: ad.AttackType = AttackData.eAttackType.MeleeOneHand; break; case Slot.TWOHAND: ad.AttackType = AttackData.eAttackType.MeleeTwoHand; break; } //Throw Weapon is subject to all the conventional attack results, parry, evade, block, etc. ad.AttackResult = ad.Target.CalculateEnemyAttackResult(ad, weapon); if (ad.AttackResult == GameLiving.eAttackResult.HitUnstyled || ad.AttackResult == GameLiving.eAttackResult.HitStyle) { //we only need to calculate the damage if the attack was a success. double damage = player.AttackDamage(weapon) * effectiveness; if (target is GamePlayer) ad.ArmorHitLocation = ((GamePlayer)target).CalculateArmorHitLocation(ad); InventoryItem armor = null; if (target.Inventory != null) armor = target.Inventory.GetItem((eInventorySlot)ad.ArmorHitLocation); //calculate the lowerboundary of the damage int lowerboundary = (player.WeaponSpecLevel(weapon) - 1) * 50 / (ad.Target.EffectiveLevel + 1) + 75; lowerboundary = Math.Max(lowerboundary, 75); lowerboundary = Math.Min(lowerboundary, 125); damage *= (player.GetWeaponSkill(weapon) + 90.68) / (ad.Target.GetArmorAF(ad.ArmorHitLocation) + 20 * 4.67); //If they have badge of Valor, we need to modify the damage if (ad.Attacker.EffectList.GetOfType<BadgeOfValorEffect>() != null) damage *= 1.0 + Math.Min(0.85, ad.Target.GetArmorAbsorb(ad.ArmorHitLocation)); else damage *= 1.0 - Math.Min(0.85, ad.Target.GetArmorAbsorb(ad.ArmorHitLocation)); damage *= (lowerboundary + Util.Random(50)) * 0.01; ad.Modifier = (int)(damage * (ad.Target.GetResist(ad.DamageType) + SkillBase.GetArmorResist(armor, ad.DamageType)) * -0.01); damage += ad.Modifier; int resist = (int)(damage * ad.Target.GetDamageResist(target.GetResistTypeForDamage(ad.DamageType)) * -0.01); eProperty property = ad.Target.GetResistTypeForDamage(ad.DamageType); int secondaryResistModifier = ad.Target.SpecBuffBonusCategory[(int)property]; int resistModifier = 0; resistModifier += (int)((ad.Damage + (double)resistModifier) * (double)secondaryResistModifier * -0.01); damage += resist; damage += resistModifier; ad.Modifier += resist; ad.Damage = (int)damage; ad.UncappedDamage = ad.Damage; ad.Damage = Math.Min(ad.Damage, (int)(player.UnstyledDamageCap(weapon) * effectiveness)); ad.Damage = (int)((double)ad.Damage * ServerProperties.Properties.PVP_MELEE_DAMAGE); if (ad.Damage == 0) ad.AttackResult = DOL.GS.GameLiving.eAttackResult.Missed; ad.CriticalDamage = player.GetMeleeCriticalDamage(ad, weapon); } else { //They failed, do they do not get disarmed, and the spell is not disabled for the full duration, //just the modified swing speed, this is in milliseconds int attackSpeed = player.AttackSpeed(weapon); player.TempProperties.setProperty(DISABLE, attackSpeed); } return ad; }