// Computes accuracy. public void AccuracyRating(AttributeSet attrs) { Accuracy = attrs["+# Accuracy Rating"][0]; // Local weapon accuracy bonus. if (Local.ContainsKey("+# to Accuracy Rating")) { Accuracy += Local["+# to Accuracy Rating"][0]; } float incAcc = 0; // Local weapon accuracy bonus. if (Local.ContainsKey("#% increased Accuracy Rating")) { incAcc += Local["#% increased Accuracy Rating"][0]; } // Gems & global bonuses. if (attrs.ContainsKey("+# to Accuracy Rating")) { Accuracy += attrs["+# to Accuracy Rating"][0]; } if (attrs.ContainsKey("#% increased Accuracy Rating")) { incAcc += attrs["#% increased Accuracy Rating"][0]; } if (attrs.ContainsKey("#% reduced Accuracy Rating")) { incAcc += attrs["#% reduced Accuracy Rating"][0]; } foreach (var attr in attrs.Matches(ReIncreasedAccuracyRatingWithWeaponType)) { Match m = ReIncreasedAccuracyRatingWithWeaponType.Match(attr.Key); WeaponType weaponType; if (WithWeaponType.TryGetValue(m.Groups[2].Value, out weaponType) && Nature.Is(weaponType)) { incAcc += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; } } if (Compute.IsDualWielding && attrs.ContainsKey("#% increased Accuracy Rating while Dual Wielding")) { incAcc += attrs["#% increased Accuracy Rating while Dual Wielding"][0]; } if (incAcc != 0) { Accuracy = IncreaseValueByPercentage(Accuracy, incAcc); } }
List <float> GetValuePairOf(string gemName, string attr, int level, int quality = 0) { AttributeSet attrs = ItemDB.AttributesOf(gemName, level, quality); return(attrs.ContainsKey(attr) ? ItemDB.AttributesOf(gemName, level, quality)[attr] : new List <float> { float.NaN, float.NaN }); }
// Computes critical strike chance and multiplier. public void CriticalStrike(AttributeSet attrs) { // Critical chance. if (ResoluteTechnique) CriticalChance = 0; else { if (CriticalChance > 0) { float incCC = 0; if (attrs.ContainsKey("#% increased Critical Strike Chance")) incCC += attrs["#% increased Critical Strike Chance"][0]; if (attrs.ContainsKey("#% increased Global Critical Strike Chance")) incCC += attrs["#% increased Global Critical Strike Chance"][0]; if (IsWieldingStaff && attrs.ContainsKey("#% increased Global Critical Strike Chance while wielding a Staff")) incCC += attrs["#% increased Global Critical Strike Chance while wielding a Staff"][0]; if (Nature.Is(DamageSource.Spell)) { if (attrs.ContainsKey("#% increased Critical Strike Chance for Spells")) incCC += attrs["#% increased Critical Strike Chance for Spells"][0]; if (attrs.ContainsKey("#% increased Global Critical Strike Chance for Spells")) incCC += attrs["#% increased Global Critical Strike Chance for Spells"][0]; } else // Attack { foreach (var attr in attrs.Matches(ReIncreasedCriticalChanceWithWeaponType)) { Match m = ReIncreasedCriticalChanceWithWeaponType.Match(attr.Key); if (WithWeaponType.ContainsKey(m.Groups[2].Value) && Nature.Is(WithWeaponType[m.Groups[2].Value])) incCC += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; } if (IsDualWielding && attrs.ContainsKey("#% increased Weapon Critical Strike Chance while Dual Wielding")) incCC += attrs["#% increased Weapon Critical Strike Chance while Dual Wielding"][0]; } // Form specific. foreach (var attr in attrs.Matches(ReIncreasedCriticalChanceForm)) { Match m = ReIncreasedCriticalChanceForm.Match(attr.Key); if (DamageNature.Forms.ContainsKey(m.Groups[2].Value) && Nature.Is(DamageNature.Forms[m.Groups[2].Value])) incCC += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; } if (incCC > 0) CriticalChance = IncreaseValueByPercentage(CriticalChance, incCC); // Critical chance can not be less than 5% nor more than 95%. // @see http://pathofexile.gamepedia.com/Critical_Strike if (CriticalChance < 5) CriticalChance = 5; else if (CriticalChance > 95) CriticalChance = 95; float incCM = 0; if (attrs.ContainsKey("#% increased Critical Strike Multiplier")) incCM += attrs["#% increased Critical Strike Multiplier"][0]; if (attrs.ContainsKey("#% increased Global Critical Strike Multiplier")) incCM += attrs["#% increased Global Critical Strike Multiplier"][0]; if (IsWieldingStaff && attrs.ContainsKey("#% increased Global Critical Strike Multiplier while wielding a Staff")) incCM += attrs["#% increased Global Critical Strike Multiplier while wielding a Staff"][0]; if (Nature.Is(DamageSource.Spell)) { if (attrs.ContainsKey("#% increased Critical Strike Multiplier for Spells")) incCM += attrs["#% increased Critical Strike Multiplier for Spells"][0]; if (attrs.ContainsKey("#% increased Global Critical Strike Multiplier for Spells")) incCM += attrs["#% increased Global Critical Strike Multiplier for Spells"][0]; } else // Attack { foreach (var attr in attrs.Matches(ReIncreasedCriticalMultiplierWithWeaponType)) { Match m = ReIncreasedCriticalMultiplierWithWeaponType.Match(attr.Key); if (WithWeaponType.ContainsKey(m.Groups[2].Value) && Nature.Is(WithWeaponType[m.Groups[2].Value])) incCM += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; } if (IsDualWielding && attrs.ContainsKey("#% increased Weapon Critical Strike Multiplier while Dual Wielding")) incCM += attrs["#% increased Weapon Critical Strike Multiplier while Dual Wielding"][0]; } // Form specific. foreach (var attr in attrs.Matches(ReIncreasedCriticalMultiplierForm)) { Match m = ReIncreasedCriticalMultiplierForm.Match(attr.Key); if (DamageNature.Forms.ContainsKey(m.Groups[2].Value) && Nature.Is(DamageNature.Forms[m.Groups[2].Value])) incCM += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; } if (incCM > 0) CriticalMultiplier = IncreaseValueByPercentage(CriticalMultiplier, incCM); } } }
// Computes attacks or casts per second. public void AttackSpeed(AttackSkill skill, AttributeSet attrs) { if (Nature.Is(DamageSource.Attack)) { // If gem has own Attacks per Second, use it instead of weapon one. if (skill.Local.ContainsKey("Attacks per Second: #")) { APS = skill.Local["Attacks per Second: #"][0]; // Apply local increased attack speed of weapon. if (Local.ContainsKey("#% increased Attack Speed")) APS = IncreaseValueByPercentage(APS, Local["#% increased Attack Speed"][0]); } float incAS = 0; if (attrs.ContainsKey("#% increased Attack Speed")) incAS += attrs["#% increased Attack Speed"][0]; if (attrs.ContainsKey("#% reduced Attack Speed")) incAS -= attrs["#% reduced Attack Speed"][0]; if (attrs.ContainsKey("#% increased Attack and Cast Speed")) incAS += attrs["#% increased Attack and Cast Speed"][0]; if (attrs.ContainsKey("#% reduced Attack and Cast Speed")) incAS -= attrs["#% reduced Attack and Cast Speed"][0]; foreach (var attr in attrs.MatchesAny(new Regex[] { ReIncreasedAttackSpeedWithWeaponHandOrType, ReIncreasedAttackSpeedType })) { Match m = ReIncreasedAttackSpeedWithWeaponHandOrType.Match(attr.Key); if (m.Success) { if (WithWeaponHand.ContainsKey(m.Groups[2].Value) && Nature.Is(WithWeaponHand[m.Groups[2].Value])) incAS += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; else if (WithWeaponType.ContainsKey(m.Groups[2].Value) && Nature.Is(WithWeaponType[m.Groups[2].Value])) incAS += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; } else { m = ReIncreasedAttackSpeedType.Match(attr.Key); if (m.Success) { // XXX: Not sure there are any mods with WeaponType here (Melee string in mod is DamageForm now, maybe Unarmed should be form as well). if (Weapon.Types.ContainsKey(m.Groups[2].Value) && Nature.Is(Weapon.Types[m.Groups[2].Value])) incAS += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; else if (DamageNature.Forms.ContainsKey(m.Groups[2].Value) && Nature.Is(DamageNature.Forms[m.Groups[2].Value])) incAS += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; } } } if (IsDualWielding && attrs.ContainsKey("#% increased Attack Speed while Dual Wielding")) incAS += attrs["#% increased Attack Speed while Dual Wielding"][0]; if (incAS != 0) APS = IncreaseValueByPercentage(APS, incAS); float moreAS = 0; if (attrs.ContainsKey("#% more Attack Speed")) moreAS += attrs["#% more Attack Speed"][0]; if (attrs.ContainsKey("#% less Attack Speed")) moreAS -= attrs["#% less Attack Speed"][0]; foreach (var attr in attrs.Matches(ReMoreAttackSpeedType)) { Match m = ReMoreAttackSpeedType.Match(attr.Key); if (m.Success) { // XXX: Not sure there are any mods with WeaponType here (Melee string in mod is DamageForm now, maybe Unarmed should be form as well). if (Weapon.Types.ContainsKey(m.Groups[2].Value) && Nature.Is(Weapon.Types[m.Groups[2].Value])) moreAS += m.Groups[1].Value == "more" ? attr.Value[0] : -attr.Value[0]; else if (DamageNature.Forms.ContainsKey(m.Groups[2].Value) && Nature.Is(DamageNature.Forms[m.Groups[2].Value])) moreAS += m.Groups[1].Value == "more" ? attr.Value[0] : -attr.Value[0]; } } if (moreAS != 0) APS = IncreaseValueByPercentage(APS, moreAS); APS = RoundHalfDownEvenValue(APS, 2); } else // Spell (use Cast Time directly). { float incCS = 0; if (attrs.ContainsKey("#% increased Cast Speed")) incCS += attrs["#% increased Cast Speed"][0]; if (attrs.ContainsKey("#% reduced Cast Speed")) incCS -= attrs["#% reduced Cast Speed"][0]; if (attrs.ContainsKey("#% increased Attack and Cast Speed")) incCS += attrs["#% increased Attack and Cast Speed"][0]; if (attrs.ContainsKey("#% reduced Attack and Cast Speed")) incCS -= attrs["#% reduced Attack and Cast Speed"][0]; if (IsDualWielding && attrs.ContainsKey("#% increased Cast Speed while Dual Wielding")) incCS += attrs["#% increased Cast Speed while Dual Wielding"][0]; if (incCS != 0) CastTime = RoundValue(CastTime / ((100 + incCS) / 100), 3); float moreCS = 0; if (attrs.ContainsKey("#% more Cast Speed")) moreCS += attrs["#% more Cast Speed"][0]; if (attrs.ContainsKey("#% less Cast Speed")) moreCS -= attrs["#% less Cast Speed"][0]; if (moreCS != 0) CastTime = FloorValue(CastTime / ((100 + moreCS) / 100), 3); APS = RoundValue(1 / CastTime, 2); } }
// Computes accuracy. public void AccuracyRating(AttributeSet attrs) { Accuracy = attrs["+# Accuracy Rating"][0]; // Local weapon accuracy bonus. if (Local.ContainsKey("+# to Accuracy Rating")) Accuracy += Local["+# to Accuracy Rating"][0]; float incAcc = 0; // Local weapon accuracy bonus. if (Local.ContainsKey("#% increased Accuracy Rating")) incAcc += Local["#% increased Accuracy Rating"][0]; // Gems & global bonuses. if (attrs.ContainsKey("+# to Accuracy Rating")) Accuracy += attrs["+# to Accuracy Rating"][0]; if (attrs.ContainsKey("#% increased Accuracy Rating")) incAcc += attrs["#% increased Accuracy Rating"][0]; if (attrs.ContainsKey("#% reduced Accuracy Rating")) incAcc += attrs["#% reduced Accuracy Rating"][0]; foreach (var attr in attrs.Matches(ReIncreasedAccuracyRatingWithWeaponType)) { Match m = ReIncreasedAccuracyRatingWithWeaponType.Match(attr.Key); if (Nature.Is(WithWeaponType[m.Groups[2].Value])) incAcc += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; } if (IsDualWielding && attrs.ContainsKey("#% increased Accuracy Rating while Dual Wielding")) incAcc += attrs["#% increased Accuracy Rating while Dual Wielding"][0]; if (incAcc != 0) Accuracy = IncreaseValueByPercentage(Accuracy, incAcc); }
// Initializes structures. public static void Initialize(SkillTree skillTree, ItemAttributes itemAttrs) { Items = itemAttrs.Equip.ToList(); MainHand = new Weapon(WeaponHand.Main, Items.Find(i => i.Class == ItemClass.MainHand)); OffHand = new Weapon(WeaponHand.Off, Items.Find(i => i.Class == ItemClass.OffHand)); // If main hand weapon has Counts as Dual Wielding modifier, then clone weapon to off hand. // @see http://pathofexile.gamepedia.com/Wings_of_Entropy if (MainHand.Attributes.ContainsKey("Counts as Dual Wielding")) OffHand = MainHand.Clone(WeaponHand.Off); IsDualWielding = MainHand.IsWeapon() && OffHand.IsWeapon(); if (IsDualWielding) { // Set dual wielded bit on weapons. MainHand.Hand |= WeaponHand.DualWielded; OffHand.Hand |= WeaponHand.DualWielded; } IsWieldingShield = MainHand.Is(WeaponType.Shield) || OffHand.Is(WeaponType.Shield); IsWieldingStaff = MainHand.Is(WeaponType.Staff); Level = skillTree.Level; if (Level < 1) Level = 1; else if (Level > 100) Level = 100; Global = new AttributeSet(); Tree = new AttributeSet(skillTree.SelectedAttributesWithoutImplicit); Global.Add(Tree); // Keystones. Acrobatics = Tree.ContainsKey("#% Chance to Dodge Attacks. #% less Armour and Energy Shield, #% less Chance to Block Spells and Attacks"); AvatarOfFire = Tree.ContainsKey("Deal no Non-Fire Damage"); BloodMagic = Tree.ContainsKey("Removes all mana. Spend Life instead of Mana for Skills"); ChaosInoculation = Tree.ContainsKey("Maximum Life becomes #, Immune to Chaos Damage"); IronGrip = Tree.ContainsKey("The increase to Physical Damage from Strength applies to Projectile Attacks as well as Melee Attacks"); IronReflexes = Tree.ContainsKey("Converts all Evasion Rating to Armour. Dexterity provides no bonus to Evasion Rating"); NecromanticAegis = Tree.ContainsKey("All bonuses from an equipped Shield apply to your Minions instead of you"); ResoluteTechnique = Tree.ContainsKey("Never deal Critical Strikes"); VaalPact = Tree.ContainsKey("Life Leech applies instantly at #% effectiveness. Life Regeneration has no effect."); ZealotsOath = Tree.ContainsKey("Life Regeneration applies to Energy Shield instead of Life"); Equipment = new AttributeSet(); foreach (ItemAttributes.Attribute attr in itemAttrs.NonLocalMods) Equipment.Add(attr.TextAttribute, new List<float>(attr.Value)); if (NecromanticAegis && OffHand.IsShield()) { // Remove all bonuses of shield from equipment set. // @see http://pathofexile.gamepedia.com/Necromantic_Aegis foreach (var attr in OffHand.Attributes) Equipment.Remove(attr); // Remove all bonuses from shield itself. OffHand.Attributes.Clear(); } Global.Add(Equipment); CoreAttributes(); Implicit = new AttributeSet(SkillTree.ImplicitAttributes(Global, Level)); Global.Add(Implicit); // Innate dual wielding bonuses. // @see http://pathofexile.gamepedia.com/Dual_wielding if (IsDualWielding) { Global["#% more Attack Speed"] = new List<float>() { 10 }; Global["#% more Physical Damage with Weapons"] = new List<float>() { 20 }; } }
// Computes critical strike chance and multiplier. public void CriticalStrike(AttributeSet attrs) { // Critical chance. if (Compute.ResoluteTechnique) { CriticalChance = 0; } else { if (CriticalChance > 0) { float incCC = 0; if (attrs.ContainsKey("#% increased Critical Strike Chance")) { incCC += attrs["#% increased Critical Strike Chance"][0]; } if (attrs.ContainsKey("#% increased Global Critical Strike Chance")) { incCC += attrs["#% increased Global Critical Strike Chance"][0]; } if (Compute.IsWieldingStaff && attrs.ContainsKey("#% increased Global Critical Strike Chance while wielding a Staff")) { incCC += attrs["#% increased Global Critical Strike Chance while wielding a Staff"][0]; } if (Nature.Is(DamageSource.Spell)) { if (attrs.ContainsKey("#% increased Critical Strike Chance for Spells")) { incCC += attrs["#% increased Critical Strike Chance for Spells"][0]; } if (attrs.ContainsKey("#% increased Global Critical Strike Chance for Spells")) { incCC += attrs["#% increased Global Critical Strike Chance for Spells"][0]; } } else // Attack { foreach (var attr in attrs.Matches(ReIncreasedCriticalChanceWithWeaponType)) { Match m = ReIncreasedCriticalChanceWithWeaponType.Match(attr.Key); if (WithWeaponType.ContainsKey(m.Groups[2].Value) && Nature.Is(WithWeaponType[m.Groups[2].Value])) { incCC += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; } } if (Compute.IsDualWielding && attrs.ContainsKey("#% increased Weapon Critical Strike Chance while Dual Wielding")) { incCC += attrs["#% increased Weapon Critical Strike Chance while Dual Wielding"][0]; } } // Form specific. foreach (var attr in attrs.Matches(ReIncreasedCriticalChanceForm)) { Match m = ReIncreasedCriticalChanceForm.Match(attr.Key); if (DamageNature.Forms.ContainsKey(m.Groups[2].Value) && Nature.Is(DamageNature.Forms[m.Groups[2].Value])) { incCC += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; } } if (incCC > 0) { CriticalChance = IncreaseValueByPercentage(CriticalChance, incCC); } // Critical chance can not be less than 5% nor more than 95%. // @see http://pathofexile.gamepedia.com/Critical_Strike if (CriticalChance < 5) { CriticalChance = 5; } else if (CriticalChance > 95) { CriticalChance = 95; } float incCM = 0; if (attrs.ContainsKey("+#% to Critical Strike Multiplier")) { incCM += attrs["+#% to Critical Strike Multiplier"][0]; } if (attrs.ContainsKey("+#% to Global Critical Strike Multiplier")) { incCM += attrs["+#% to Global Critical Strike Multiplier"][0]; } if (Compute.IsWieldingStaff && attrs.ContainsKey("+#% to Global Critical Strike Multiplier while wielding a Staff")) { incCM += attrs["+#% to Global Critical Strike Multiplier while wielding a Staff"][0]; } if (Nature.Is(DamageSource.Spell)) { if (attrs.ContainsKey("+#% to Critical Strike Multiplier for Spells")) { incCM += attrs["+#% to Critical Strike Multiplier for Spells"][0]; } if (attrs.ContainsKey("+#% to Global Critical Strike Multiplier for Spells")) { incCM += attrs["+#% to Global Critical Strike Multiplier for Spells"][0]; } } else // Attack { foreach (var attr in attrs.Matches(ReIncreasedCriticalMultiplierWithWeaponType)) { Match m = ReIncreasedCriticalMultiplierWithWeaponType.Match(attr.Key); if (WithWeaponType.ContainsKey(m.Groups[2].Value) && Nature.Is(WithWeaponType[m.Groups[2].Value])) { incCM += m.Groups[1].Value == "+" ? attr.Value[0] : -attr.Value[0]; } } if (Compute.IsDualWielding && attrs.ContainsKey("+#% to Weapon Critical Strike Multiplier while Dual Wielding")) { incCM += attrs["+#% to Weapon Critical Strike Multiplier while Dual Wielding"][0]; } } // Form specific. foreach (var attr in attrs.Matches(ReIncreasedCriticalMultiplierForm)) { Match m = ReIncreasedCriticalMultiplierForm.Match(attr.Key); if (DamageNature.Forms.ContainsKey(m.Groups[2].Value) && Nature.Is(DamageNature.Forms[m.Groups[2].Value])) { incCM += m.Groups[1].Value == "+" ? attr.Value[0] : -attr.Value[0]; } } CriticalMultiplier += incCM; if (attrs.ContainsKey("No Critical Strike Multiplier")) { CriticalMultiplier = 100; } } } }
// Computes attacks or casts per second. public void AttackSpeed(AttackSkill skill, AttributeSet attrs) { if (Nature.Is(DamageSource.Attack)) { // If gem has own Attacks per Second, use it instead of weapon one. if (skill.Local.ContainsKey("Attacks per Second: #")) { APS = skill.Local["Attacks per Second: #"][0]; // Apply local increased attack speed of weapon. if (Local.ContainsKey("#% increased Attack Speed")) { APS = IncreaseValueByPercentage(APS, Local["#% increased Attack Speed"][0]); } } float incAS = 0; if (attrs.ContainsKey("#% increased Attack Speed")) { incAS += attrs["#% increased Attack Speed"][0]; } if (attrs.ContainsKey("#% reduced Attack Speed")) { incAS -= attrs["#% reduced Attack Speed"][0]; } if (attrs.ContainsKey("#% increased Attack and Cast Speed")) { incAS += attrs["#% increased Attack and Cast Speed"][0]; } if (attrs.ContainsKey("#% reduced Attack and Cast Speed")) { incAS -= attrs["#% reduced Attack and Cast Speed"][0]; } foreach (var attr in attrs.MatchesAny(new Regex[] { ReIncreasedAttackSpeedWithWeaponHandOrType, ReIncreasedAttackSpeedType })) { Match m = ReIncreasedAttackSpeedWithWeaponHandOrType.Match(attr.Key); if (m.Success) { if (WithWeaponHand.ContainsKey(m.Groups[2].Value) && Nature.Is(WithWeaponHand[m.Groups[2].Value])) { incAS += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; } else if (WithWeaponType.ContainsKey(m.Groups[2].Value) && Nature.Is(WithWeaponType[m.Groups[2].Value])) { incAS += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; } } else { m = ReIncreasedAttackSpeedType.Match(attr.Key); if (m.Success) { // XXX: Not sure there are any mods with WeaponType here (Melee string in mod is DamageForm now, maybe Unarmed should be form as well). if (Weapon.Types.ContainsKey(m.Groups[2].Value) && Nature.Is(Weapon.Types[m.Groups[2].Value])) { incAS += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; } else if (DamageNature.Forms.ContainsKey(m.Groups[2].Value) && Nature.Is(DamageNature.Forms[m.Groups[2].Value])) { incAS += m.Groups[1].Value == "increased" ? attr.Value[0] : -attr.Value[0]; } } } } if (Compute.IsDualWielding && attrs.ContainsKey("#% increased Attack Speed while Dual Wielding")) { incAS += attrs["#% increased Attack Speed while Dual Wielding"][0]; } if (Compute.OffHand.IsShield() && attrs.ContainsKey("#% increased Attack Speed while holding a Shield")) { incAS += attrs["#% increased Attack Speed while holding a Shield"][0]; } if (incAS != 0) { APS = IncreaseValueByPercentage(APS, incAS); } float moreAS = 1; if (attrs.ContainsKey("#% more Attack Speed")) { moreAS *= 1 + attrs["#% more Attack Speed"][0] / 100; } if (attrs.ContainsKey("#% less Attack Speed")) { moreAS *= 1 - attrs["#% less Attack Speed"][0] / 100; } foreach (var attr in attrs.Matches(ReMoreAttackSpeedType)) { Match m = ReMoreAttackSpeedType.Match(attr.Key); if (m.Success) { // XXX: Not sure there are any mods with WeaponType here (Melee string in mod is DamageForm now, maybe Unarmed should be form as well). if (Weapon.Types.ContainsKey(m.Groups[2].Value) && Nature.Is(Weapon.Types[m.Groups[2].Value]) || DamageNature.Forms.ContainsKey(m.Groups[2].Value) && Nature.Is(DamageNature.Forms[m.Groups[2].Value])) { moreAS *= m.Groups[1].Value == "more" ? 1 + attr.Value[0] / 100 : 1 - attr.Value[0] / 100; } } } APS = APS * moreAS; APS = RoundHalfDownEvenValue(APS, 2); } else // Spell (use Cast Time directly). { float incCS = 0; if (attrs.ContainsKey("#% increased Cast Speed")) { incCS += attrs["#% increased Cast Speed"][0]; } if (attrs.ContainsKey("#% reduced Cast Speed")) { incCS -= attrs["#% reduced Cast Speed"][0]; } if (attrs.ContainsKey("#% increased Attack and Cast Speed")) { incCS += attrs["#% increased Attack and Cast Speed"][0]; } if (attrs.ContainsKey("#% reduced Attack and Cast Speed")) { incCS -= attrs["#% reduced Attack and Cast Speed"][0]; } if (Compute.IsDualWielding && attrs.ContainsKey("#% increased Cast Speed while Dual Wielding")) { incCS += attrs["#% increased Cast Speed while Dual Wielding"][0]; } if (incCS != 0) { CastTime = RoundValue(CastTime / ((100 + incCS) / 100), 3); } float moreCS = 0; if (attrs.ContainsKey("#% more Cast Speed")) { moreCS += attrs["#% more Cast Speed"][0]; } if (attrs.ContainsKey("#% less Cast Speed")) { moreCS -= attrs["#% less Cast Speed"][0]; } if (moreCS != 0) { CastTime = FloorValue(CastTime / ((100 + moreCS) / 100), 3); } APS = RoundValue(1 / CastTime, 2); } }
// Applies item modifiers. public void Apply(Item item) { // Add skill gem attributes. Local.Add(GemDB.Instance.AttributesOf(Gem, item)); CreateSources(); // Lists of damage added, increased and multipliers to apply. List <Damage.Added> adds = new List <Damage.Added>(); List <Damage.Increased> increases = new List <Damage.Increased>(); List <Damage.More> mores = new List <Damage.More>(); // Collect damage conversions from gems, equipment and tree. // Collect damage added from gems and equipment. foreach (var attr in Local) { Damage.Converted conv = Damage.Converted.Create(DamageConversionSource.Gem, attr); if (conv != null) { Converts.Add(conv); } // Damage added from gems is always applied. Damage.Added added = Damage.Added.Create(Nature.Source, attr); if (added != null) { adds.Add(added); } } foreach (var attr in Equipment) { Damage.Converted conv = Damage.Converted.Create(DamageConversionSource.Equipment, attr); if (conv != null) { Converts.Add(conv); } // Whether damage added from equipment applies to the current DamageSource is decided in Create(). Damage.Added added = Damage.Added.Create(Nature.Source, attr); if (added != null) { adds.Add(added); } } foreach (var attr in Tree) { Damage.Converted conv = Damage.Converted.Create(DamageConversionSource.Tree, attr); if (conv != null) { Converts.Add(conv); } } // Merge local gems and global attributes. AttributeSet attrs = Compute.Global.Merge(Local); // Iron Grip. if (Compute.IronGrip || attrs.ContainsKey("Strength's damage bonus applies to Projectile Attacks made with Supported Skills")) { // Create projectile attack damage bonus from value of implicit melee physical damage increase. float bonus = Implicit["#% increased Melee Physical Damage"][0]; attrs.AddAsSum("#% increased Projectile Weapon Damage", bonus); } // Iron Will. if (attrs.ContainsKey("Strength's damage bonus applies to Spell Damage as well for Supported Skills")) { // Create spell damage bonus from value of implicit melee physical damage increase. float bonus = Implicit["#% increased Melee Physical Damage"][0]; attrs.AddAsSum("#% increased Spell Damage", bonus); } // Collect damage gains, increases and multipliers. foreach (var attr in attrs) { var gained = Damage.Gained.Create(attr); if (gained != null) { Gains.Add(gained); } var increased = Damage.Increased.Create(attr); if (increased != null) { increases.Add(increased); } var more = Damage.More.Create(attr, Compute); if (more != null) { mores.Add(more); } } foreach (AttackSource source in Sources) { ApplyAttackSource(adds, increases, mores, attrs, source); } }
public Computation(SkillTree skillTree, ItemAttributes itemAttrs) { Items = itemAttrs.Equip.ToList(); MainHand = new Weapon(WeaponHand.Main, itemAttrs.MainHand); OffHand = new Weapon(WeaponHand.Off, itemAttrs.OffHand); // If main hand weapon has Counts as Dual Wielding modifier, then clone weapon to off hand. // @see http://pathofexile.gamepedia.com/Wings_of_Entropy if (MainHand.Attributes.ContainsKey("Counts as Dual Wielding")) { OffHand = MainHand.Clone(WeaponHand.Off); } IsDualWielding = MainHand.IsWeapon() && OffHand.IsWeapon(); if (IsDualWielding) { // Set dual wielded bit on weapons. MainHand.Hand |= WeaponHand.DualWielded; OffHand.Hand |= WeaponHand.DualWielded; } IsWieldingShield = MainHand.Is(WeaponType.Shield) || OffHand.Is(WeaponType.Shield); IsWieldingStaff = MainHand.Is(WeaponType.Staff); Level = skillTree.Level; if (Level < 1) { Level = 1; } else if (Level > 100) { Level = 100; } Tree = new AttributeSet(skillTree?.SelectedAttributesWithoutImplicit); Global.Add(Tree); // Keystones. Acrobatics = Tree.ContainsKey("#% Chance to Dodge Attacks. #% less Armour and Energy Shield, #% less Chance to Block Spells and Attacks"); AvatarOfFire = Tree.ContainsKey("Deal no Non-Fire Damage"); BloodMagic = Tree.ContainsKey("Removes all mana. Spend Life instead of Mana for Skills"); ChaosInoculation = Tree.ContainsKey("Maximum Life becomes #, Immune to Chaos Damage"); IronGrip = Tree.ContainsKey("The increase to Physical Damage from Strength applies to Projectile Attacks as well as Melee Attacks"); IronReflexes = Tree.ContainsKey("Converts all Evasion Rating to Armour. Dexterity provides no bonus to Evasion Rating"); NecromanticAegis = Tree.ContainsKey("All bonuses from an equipped Shield apply to your Minions instead of you"); ResoluteTechnique = Tree.ContainsKey("Never deal Critical Strikes"); VaalPact = Tree.ContainsKey("Life Leech applies instantly at #% effectiveness. Life Regeneration has no effect."); ZealotsOath = Tree.ContainsKey("Life Regeneration applies to Energy Shield instead of Life"); foreach (var attr in itemAttrs.NonLocalMods) { Equipment.Add(attr.Attribute, new List <float>(attr.Value)); } if (NecromanticAegis && OffHand.IsShield()) { // Remove all bonuses of shield from equipment set. // @see http://pathofexile.gamepedia.com/Necromantic_Aegis foreach (var attr in OffHand.Attributes) { Equipment.Remove(attr); } // Remove all bonuses from shield itself. OffHand.Attributes.Clear(); } Global.Add(Equipment); if (Global.ContainsKey("Armour received from Body Armour is doubled") && itemAttrs.Armor != null) { var armorProp = itemAttrs.Armor.Properties.FirstOrDefault(m => m.Attribute == "Armour: #"); if (armorProp != null && armorProp.Value.Any()) { Global["Armour: #"][0] += armorProp.Value[0]; } } ComputeCoreAttributes(); Implicit = new AttributeSet(SkillTree.ImplicitAttributes(Global, Level)); Global.Add(Implicit); // Innate dual wielding bonuses. // @see http://pathofexile.gamepedia.com/Dual_wielding if (IsDualWielding) { Global["#% more Attack Speed"] = new List <float>() { 10 }; Global["#% more Physical Damage with Weapons"] = new List <float>() { 20 }; } }
// Chance to Evade = 1 - Attacker's Accuracy / ( Attacker's Accuracy + (Defender's Evasion / 4) ^ 0.8 ) // @see http://pathofexile.gamepedia.com/Evasion public float ChanceToEvade(int level, float evasionRating) { if (Global.ContainsKey("Cannot Evade enemy Attacks")) { return(0); // The modifier can be from other source than Unwavering Stance. } int maa = MonsterAverageAccuracy[level]; return(RoundValue((float)(1 - maa / (maa + Math.Pow(evasionRating / 4, 0.8))) * 100, 0)); }