/// <summary> /// Get Character Stats for multiple calls. Allowing means by which to stack different sets/Special effects. /// </summary> /// <param name="character"></param> /// <param name="additionalItem"></param> /// <param name="sType">Enum describing which set of stats we want.</param> /// <returns></returns> private StatsDK GetCharacterStats(Character character, Item additionalItem, StatType sType, TankDKChar TDK, Rotation rot = null) { StatsDK statsTotal = new StatsDK(); if (null == character.CalculationOptions) { // Possibly put some error text here. return statsTotal; } // Warning TDK can be blank at this point. TDK.Char = character; TDK.calcOpts = character.CalculationOptions as CalculationOptionsTankDK; TDK.bo = character.BossOptions; // Start populating data w/ Basic racial & class baseline. Stats BStats = BaseStats.GetBaseStats(character); statsTotal.Accumulate(BStats); statsTotal.BaseAgility = BStats.Agility; AccumulateItemStats(statsTotal, character, additionalItem); // Stack only the info we care about. statsTotal = GetRelevantStatsLocal(statsTotal); AccumulateBuffsStats(statsTotal, character.ActiveBuffs); AccumulateSetBonusStats(statsTotal, character.SetBonusCount); #region Tier Bonuses: Tank #region T11 int tierCount; if (character.SetBonusCount.TryGetValue("Magma Plated Battlearmor", out tierCount)) { if (tierCount >= 2) { statsTotal.b2T11_Tank = true; } if (tierCount >= 4) { statsTotal.b4T11_Tank = true; } } if (statsTotal.b4T11_Tank) statsTotal.AddSpecialEffect(_SE_IBF[1]); else statsTotal.AddSpecialEffect(_SE_IBF[0]); #endregion #region T12 if (character.SetBonusCount.TryGetValue("Elementium Deathplate Battlearmor", out tierCount)) { if (tierCount >= 2) { statsTotal.b2T12_Tank = true; } if (tierCount >= 4) { statsTotal.b4T12_Tank = true; } } if (statsTotal.b2T12_Tank) { // Your melee attacks cause Burning Blood on your target, // which deals 800 Fire damage every 2 for 6 sec and // causes your abilities to behave as if you had 2 diseases // present on the target. // Implemented in CombatState DiseaseCount statsTotal.FireDamage = 800 / 2; } if (statsTotal.b4T12_Tank) { // Your when your Dancing Rune Weapon expires, it grants 15% additional parry chance for 12 sec. // Implemented in DRW talent Static Special Effect. } #endregion #region T13 if (character.SetBonusCount.TryGetValue("Necrotic Boneplate Armor", out tierCount)) { if (tierCount >= 2) { statsTotal.b2T13_Tank = true; } if (tierCount >= 4) { statsTotal.b4T13_Tank = true; } } if (statsTotal.b2T13_Tank) { // When an attack drops your health below 35%, one of your Blood Runes // will immediately activate and convert into a Death Rune for the next // 20 sec. This effect cannot occur more than once every 45 sec. } if (statsTotal.b4T13_Tank) { // Your Vampiric Blood ability also affects all party and raid members // for 50% of the effect it has on you. } #endregion #endregion Rawr.DPSDK.CalculationsDPSDK.RemoveDuplicateRunes(statsTotal, character, true/*statsTotal.bDW*/); Rawr.DPSDK.CalculationsDPSDK.AccumulateTalents(statsTotal, character); Rawr.DPSDK.CalculationsDPSDK.AccumulatePresenceStats(statsTotal, Presence.Blood, character.DeathKnightTalents); statsTotal.ArcaneResistance += statsTotal.ArcaneResistanceBuff; statsTotal.ArcaneResistanceBuff = 0f; statsTotal.FireResistance += statsTotal.FireResistanceBuff; statsTotal.FireResistanceBuff = 0f; statsTotal.FrostResistance += statsTotal.FrostResistanceBuff; statsTotal.FrostResistanceBuff = 0f; statsTotal.NatureResistance += statsTotal.NatureResistanceBuff; statsTotal.NatureResistanceBuff = 0f; statsTotal.ShadowResistance += statsTotal.ShadowResistanceBuff; statsTotal.ShadowResistanceBuff = 0f; /* At this point, we're combined all the data from gear and talents and all that happy jazz. * However, we haven't applied any special effects nor have we applied any multipliers. * Many special effects are now getting dependant upon combat info (rotations). */ StatsDK PreRatingsBase = statsTotal.Clone() as StatsDK; // Apply the ratings to actual stats. ProcessRatings(statsTotal); ProcessAvoidance(statsTotal, TDK.bo.Level, TDK.Char, PreRatingsBase); statsTotal.EffectiveParry = 0; if (character.MainHand != null) { statsTotal.EffectiveParry = statsTotal.Parry; } float fChanceToGetHit = 1f - Math.Min(1f, statsTotal.Miss + statsTotal.Dodge + statsTotal.EffectiveParry); // Now comes the special handling for secondary stats passes that are dependant upon Boss & Rotation values. if (sType != StatType.Unbuffed && (null != TDK.bo && null != rot)) // Make sure we have the rotation and Boss info. { #region Special Effects #region Talent: Bone Shield if (character.DeathKnightTalents.BoneShield > 0) { int BSStacks = 4; // The number of bones by default. if (Rawr.Properties.GeneralSettings.Default.PTRMode) BSStacks = 6; // The number of bones by default. float BoneLossRate = Math.Max(2f, TDK.bo.DynamicCompiler_Attacks.AttackSpeed / fChanceToGetHit); // 2 sec internal cooldown on loosing bones so the DK can't get spammed to death. float moveVal = character.DeathKnightTalents.GlyphofBoneShield ? 0.15f : 0f; SpecialEffect primary = new SpecialEffect(Trigger.Use, new Stats() { DamageTakenReductionMultiplier = 0.20f, BonusDamageMultiplier = 0.02f, MovementSpeed = moveVal, }, BoneLossRate * BSStacks, 60) {BypassCache = true,}; statsTotal.AddSpecialEffect(primary); } #endregion #region Vengeance // Vengence has the chance to increase AP. int iVengenceMax = (int)(statsTotal.Stamina + (BaseStats.GetBaseStats(character).Health) * .1); int iAttackPowerMax = (int)statsTotal.AttackPower + iVengenceMax; float mitigatedDPS = TDK.bo.GetDPSByType(TDK.role, 0, statsTotal.DamageTakenReductionMultiplier, 0, .14f, statsTotal.Miss, statsTotal.Dodge, statsTotal.EffectiveParry, 0, 0, 0, 0, 0, 0, 0); //statsTotal.ArcaneResistance, statsTotal.FireResistance, statsTotal.FrostResistance, statsTotal.NatureResistance, statsTotal.ShadowResistance); mitigatedDPS = mitigatedDPS * (1 - (float)StatConversion.GetArmorDamageReduction(TDK.bo.Level, statsTotal.Armor, 0f, 0f)); float APStackSingle = mitigatedDPS * 0.05f * TDK.bo.DynamicCompiler_Attacks.AttackSpeed; int APStackCountMax = (int)Math.Floor(iVengenceMax / APStackSingle); SpecialEffect seVeng = new SpecialEffect(Trigger.DamageTaken, new Stats() { AttackPower = APStackSingle }, 2 * 10, 0, 1, APStackCountMax) { BypassCache = true, }; Dictionary<Trigger, float> triggerInterval = new Dictionary<Trigger,float>(); Dictionary<Trigger, float> triggerChance = new Dictionary<Trigger,float>(); triggerInterval.Add(Trigger.DamageTaken, TDK.bo.DynamicCompiler_Attacks.AttackSpeed); triggerChance.Add(Trigger.DamageTaken, 1f); // MitigatedDPS already factors in avoidance. statsTotal.VengenceAttackPower = seVeng.GetAverageStats(triggerInterval, triggerChance).AttackPower; statsTotal.AttackPower += statsTotal.VengenceAttackPower * TDK.calcOpts.VengeanceWeight; #endregion statsTotal.AddSpecialEffect(_SE_DeathPact); // For now we just factor them in once. Rawr.DPSDK.StatsSpecialEffects se = new Rawr.DPSDK.StatsSpecialEffects(rot.m_CT, rot, TDK.bo); StatsDK statSE = new StatsDK(); foreach (SpecialEffect effect in statsTotal.SpecialEffects()) { if (HasRelevantStats(effect.Stats)) { statSE.Accumulate(se.getSpecialEffects(effect)); // statsTotal.Accumulate(se.getSpecialEffects(effect)); // This is done further down. } } // Darkmoon card greatness procs if (statSE.HighestStat > 0 || statSE.Paragon > 0) { if (statSE.Strength >= statSE.Agility) { statSE.Strength += statSE.HighestStat + statSE.Paragon; } else if (statSE.Agility > statSE.Strength) { statSE.Agility += statSE.HighestStat + statSE.Paragon; } statSE.HighestStat = 0; statSE.Paragon = 0; } // Any Modifiers from stats need to be applied to statSE statSE.Strength = StatConversion.ApplyMultiplier(statSE.Strength, statsTotal.BonusStrengthMultiplier); statSE.Agility = StatConversion.ApplyMultiplier(statSE.Agility, statsTotal.BonusAgilityMultiplier); statSE.Stamina = StatConversion.ApplyMultiplier(statSE.Stamina, statsTotal.BonusStaminaMultiplier); // statSE.Stamina = (float)Math.Floor(statSE.Stamina); statSE.Armor = StatConversion.ApplyMultiplier(statSE.Armor, statsTotal.BaseArmorMultiplier); statSE.AttackPower = StatConversion.ApplyMultiplier(statSE.AttackPower, statsTotal.BonusAttackPowerMultiplier); statSE.BonusArmor = StatConversion.ApplyMultiplier(statSE.BonusArmor, statsTotal.BonusArmorMultiplier); statSE.Armor += statSE.BonusArmor; statSE.Health += StatConversion.GetHealthFromStamina(statSE.Stamina) + statSE.BattlemasterHealthProc; statSE.Health = statSE.Health * (1 + statSE.BonusHealthMultiplier); statsTotal.BonusHealthMultiplier = ((1 + statsTotal.BonusHealthMultiplier) * (1 + statSE.BonusHealthMultiplier)) - 1 ; if (character.DeathKnightTalents.BladedArmor > 0) { statSE.AttackPower += (statSE.Armor / 180f) * (float)character.DeathKnightTalents.BladedArmor; } statSE.AttackPower += StatConversion.ApplyMultiplier((statSE.Strength * 2), statsTotal.BonusAttackPowerMultiplier); statSE.ParryRating += statSE.Strength * 0.27f; // Any Modifiers from statSE need to be applied to stats statsTotal.Strength = StatConversion.ApplyMultiplier(statsTotal.Strength, statSE.BonusStrengthMultiplier); statsTotal.Agility = StatConversion.ApplyMultiplier(statsTotal.Agility, statSE.BonusAgilityMultiplier); statsTotal.Stamina = StatConversion.ApplyMultiplier(statsTotal.Stamina, statSE.BonusStaminaMultiplier); // stats.Stamina = (float)Math.Floor(stats.Stamina); statsTotal.Armor = StatConversion.ApplyMultiplier(statsTotal.Armor, statSE.BaseArmorMultiplier); statsTotal.AttackPower = StatConversion.ApplyMultiplier(statsTotal.AttackPower, statSE.BonusAttackPowerMultiplier); statsTotal.BonusArmor = StatConversion.ApplyMultiplier(statsTotal.BonusArmor, statSE.BonusArmorMultiplier); statsTotal.Accumulate(statSE); PreRatingsBase.Miss += statSE.Miss; PreRatingsBase.Dodge += statSE.Dodge; PreRatingsBase.Parry += statSE.Parry; #if DEBUG if (float.IsNaN(statsTotal.Stamina)) throw new Exception("Something very wrong in stats."); #endif #endregion // Special effects } // Apply the Multipliers ProcessStatModifiers(statsTotal, character.DeathKnightTalents.BladedArmor, character); ProcessAvoidance(statsTotal, TDK.bo.Level, TDK.Char, PreRatingsBase); if (character.MainHand != null) { statsTotal.EffectiveParry = statsTotal.Parry; } return (statsTotal); }
/// <summary> /// GetCharacterStats is the 2nd-most calculation intensive method in a model. Here the model will /// combine all of the information about the character, including race, gear, enchants, buffs, /// calculationoptions, etc., to form a single combined Stats object. Three of the methods below /// can be called from this method to help total up stats: GetItemStats(character, additionalItem), /// GetEnchantsStats(character), and GetBuffsStats(character.ActiveBuffs). /// </summary> /// <param name="character">The character whose stats should be totaled.</param> /// <param name="additionalItem">An additional item to treat the character as wearing. /// This is used for gems, which don't have a slot on the character to fit in, so are just /// added onto the character, in order to get gem calculations.</param> /// <returns>A Stats object containing the final totaled values of all character stats.</returns> public override Stats GetCharacterStats(Character character, Item additionalItem) { StatsDK statsTotal = new StatsDK(); if (null == character) { #if DEBUG throw new Exception("Character is Null"); #else return statsTotal; #endif } CalculationOptionsDPSDK calcOpts = character.CalculationOptions as CalculationOptionsDPSDK; if (null == calcOpts) { calcOpts = new CalculationOptionsDPSDK(); } DeathKnightTalents talents = character.DeathKnightTalents; if (null == talents) { return statsTotal; } statsTotal.Accumulate(GetRaceStats(character)); AccumulateItemStats(statsTotal, character, additionalItem); statsTotal = GetRelevantStats(statsTotal) as StatsDK; // GetRel removes any stats specific to the StatsDK object. statsTotal.bDW = false; if (character.MainHand != null && character.OffHand != null) statsTotal.bDW = true; RemoveDuplicateRunes(statsTotal, character, statsTotal.bDW); AccumulateBuffsStats(statsTotal, character.ActiveBuffs); #region Tank #region T11 int tierCount; if (character.SetBonusCount.TryGetValue("Magma Plated Battlearmor", out tierCount)) { if (tierCount >= 2) { statsTotal.b2T11_Tank = true; } if (tierCount >= 4) { statsTotal.b4T11_Tank = true; } } if (statsTotal.b4T11_Tank) statsTotal.AddSpecialEffect(_SE_IBF[1]); else statsTotal.AddSpecialEffect(_SE_IBF[0]); #endregion #region T12 if (character.SetBonusCount.TryGetValue("Elementium Deathplate Battlearmor", out tierCount)) { if (tierCount >= 2) { statsTotal.b2T12_Tank = true; } if (tierCount >= 4) { statsTotal.b4T12_Tank = true; } } if (statsTotal.b2T12_Tank) { // Your melee attacks cause Burning Blood on your target, // which deals 800 Fire damage every 2 for 6 sec and // causes your abilities to behave as if you had 2 diseases // present on the target. // Implemented in CombatState DiseaseCount statsTotal.FireDamage = 800 / 2; } if (statsTotal.b4T12_Tank) { // Your Dancing Rune Weapon grants 15% additional parry chance. // Implemented in DRW talent Static Special Effect. } #endregion #region T13 if (character.SetBonusCount.TryGetValue("Necrotic Boneplate Armor", out tierCount)) { if (tierCount >= 2) { statsTotal.b2T13_Tank = true; } if (tierCount >= 4) { statsTotal.b4T13_Tank = true; } } if (statsTotal.b2T13_Tank) { // When an attack drops your health below 35%, one of your Blood Runes // will immediately activate and convert into a Death Rune for the next // 20 sec. This effect cannot occur more than once every 45 sec. } if (statsTotal.b4T13_Tank) { // Your Vampiric Blood ability also affects all party and raid members // for 50% of the effect it has on you. } #endregion #endregion #region DPS #region T11 if (character.SetBonusCount.TryGetValue("Magma Plated Battlegear", out tierCount)) { if (tierCount >= 2) { statsTotal.b2T11_DPS = true; if (tierCount >= 4) { statsTotal.b4T11_DPS = true; } } if (statsTotal.b2T11_DPS) { // increase the crit chance of your DeathCoil & FS by 5% statsTotal.BonusCritChanceDeathCoil += .05f; statsTotal.BonusCritChanceFrostStrike += .05f; } if (statsTotal.b4T11_DPS) { // Each time you gain a Death Rune or trigger your Killing Machine talent, // you also gain 1% increased attack power for 30 sec. Stacks up to 3 times. statsTotal.AddSpecialEffect(new SpecialEffect(Trigger.DeathRuneGained, new Stats() { BonusAttackPowerMultiplier = 0.01f, }, 30, 0, 1f, 3)); statsTotal.AddSpecialEffect(new SpecialEffect(Trigger.KillingMachine, new Stats() { BonusAttackPowerMultiplier = 0.01f, }, 30, 0, 1f, 3)); } } #endregion #region T12 if (character.SetBonusCount.TryGetValue("Elementium Deathplate Battlegear", out tierCount)) { if (tierCount >= 2) { statsTotal.b2T12_DPS = true; if (tierCount >= 4) { statsTotal.b4T12_DPS = true; } } } if (statsTotal.b2T12_DPS) { // Horn of Winter also grats 3 RPp5 statsTotal.RPp5 += 3; } if (statsTotal.b4T12_DPS) { // Your Obliterate and Scourge Strike abilities instantly deal 6% additional damage as Fire damage. // Implemented in Oblit and SS classes. } #endregion #region T13 if (character.SetBonusCount.TryGetValue("Necrotic Boneplate Battlegear", out tierCount)) { if (tierCount >= 2) { statsTotal.b2T13_DPS = true; } if (tierCount >= 4) { statsTotal.b4T13_DPS = true; } } if (statsTotal.b2T13_DPS) { // Sudden Doom has a 30% chance and Rime has a 60% chance // to grant 2 charges when triggered instead of 1. } if (statsTotal.b4T13_DPS) { // Runic Empowerment has a 25% chance and Runic Corruption // has a 40% chance to also grant 710 mastery rating for 12 sec when activated. } #endregion #endregion AccumulateTalents(statsTotal, character); AccumulatePresenceStats(statsTotal, calcOpts.presence, talents); return (statsTotal); }
/// <summary>Build the talent effects.</summary> public static void AccumulateTalents(StatsDK FullCharacterStats, Character character) { Stats newStats = new Stats(); FullCharacterStats.Mastery += StatConversion.GetMasteryFromRating(FullCharacterStats.MasteryRating); // Runic Focus: FullCharacterStats.SpellHit += 0.09f; // Which talent tree focus? #region Talent Speciality Rotation.Type r = GetSpec(character.DeathKnightTalents); switch (r) { case Rotation.Type.Blood: { // Special abilities for being blood // Heart Strike // Veteran of the third war // Stamina +9% FullCharacterStats.BonusStaminaMultiplier += .09f; // Expertise +6 FullCharacterStats.Expertise += 6; // Blood Rites // Whenever you hit with Death Strike or Obliterate, the Frost and Unholy Runes // will become Death Runes when they activate. Death Runes count as a Blood, Frost or Unholy Rune. // Vengence // Each time you take damage, you gain 5% of the damage taken as attack power, up to a maximum of 10% of your health. // Mastery: Blood Shield // Each Time you heal yourself w/ DS you gain a shield worth 50% of the amount healed // Each Point of Mastery increases the shield by 6.25% break; } case Rotation.Type.Frost: { // Special abilities for being Frost // Frost Strike // Icy Talons // Melee Attack speed +20% FullCharacterStats.PhysicalHaste = AddStatMultiplierStat(FullCharacterStats.PhysicalHaste, .2f); FullCharacterStats.BonusRuneRegeneration -= .2f; // Only this haste doesn't affect Rune Regen. // Blood of the North // Blood runes are death runes. // Mastery: Frozen Heart // Increases all frost damage by 16%. // Each point of mastery increases frost damage by an additional 2.0% FullCharacterStats.BonusFrostDamageMultiplier += .16f + (.02f * FullCharacterStats.Mastery); break; } case Rotation.Type.Unholy: { // Special abilities for being Unholy // Scourge Strike // Master of Ghouls // Reduces the CD on Raise dead by 60 sec. // The ghoul summoned is considered your pet w/o a limited duration. // Reaping // Whenever you hit with Blood strike, pestilence, or Festering strike, the runes spent will // become death runes when they activate. // Unholy Might // Str +25% FullCharacterStats.BonusStrengthMultiplier += .25f; // Mastery: Dreadblade. // Increases shadow damage by 20% + // Each point of mastery increases shadow damage by an additional 2.5% FullCharacterStats.BonusShadowDamageMultiplier += .2f + (.025f * FullCharacterStats.Mastery); break; } } #endregion #region Blood Talents // Butchery // 1RPp5 per Point if (character.DeathKnightTalents.Butchery > 0) { FullCharacterStats.RPp5 += 1 * character.DeathKnightTalents.Butchery; } // Blade Barrier // Reduce damage by 2% per point for 10 sec. if (character.DeathKnightTalents.BladeBarrier > 0) { // If you don't have your Blood Runes on CD, you're doing it wrong. FullCharacterStats.DamageTakenReductionMultiplier = 1f - (1f - FullCharacterStats.DamageTakenReductionMultiplier) * (1f - .02f * character.DeathKnightTalents.BladeBarrier); } // Bladed Armor // 2 AP per point per 180 Armor if (character.DeathKnightTalents.BladedArmor > 0) { // If you don't have your Blood Runes on CD, you're doing it wrong. FullCharacterStats.AttackPower += (2 * character.DeathKnightTalents.BladedArmor) * (FullCharacterStats.Armor / 180); } // Improved Blood Tap // Reduces Blood tap CD by 15 sec * pts. // Scent of Blood // 15% after Dodge, Parry or damage received causing 1 melee hit per point to generate 10 runic power. // Implemented in WhiteSwing. // Scarlet Fever // Those hit by BB do have a 50/100% chance to reduce damage dealt by 10% for 30 sec. if (character.DeathKnightTalents.ScarletFever > 0) { // Like Blade Barrier, this should always be up. // Be sure to put this in the rotation solver for Tanking Rotations. // JOTHAY TODO: Isn't this conflicting with the Buffs pane? FullCharacterStats.DamageTakenReductionMultiplier = 1f - (1f - FullCharacterStats.DamageTakenReductionMultiplier) * (1f - .05f * character.DeathKnightTalents.ScarletFever); } // Hand of Doom // Reduces the CD for Strangulate by 30/60 sec. if (r == Rotation.Type.Blood) { // Blood-Caked Blade // 10% chance per point to cause Blood-Caked strike // Implmented in WhiteDamage ability file. // Bone Shield // 6 Bones // Takes 20% less damage from all sources // Does 2% more damage to target // Each damaging attack consumes a bone. // Lasts 5 mins // Toughness // Increases Armor Value from items by 3% per point. if (character.DeathKnightTalents.Toughness > 0) { FullCharacterStats.BaseArmorMultiplier = AddStatMultiplierStat(FullCharacterStats.BaseArmorMultiplier, (.03f * character.DeathKnightTalents.Toughness)); } // Abominations Might // increase AP by 5%/10% of raid. // 1% per point increase to str. if (character.DeathKnightTalents.AbominationsMight > 0) { // This happens no matter what: FullCharacterStats.BonusStrengthMultiplier += (0.01f * character.DeathKnightTalents.AbominationsMight); // This happens only if there isn't Trueshot Aura/Unleashed Rage/Abom's might available: if (!(character.ActiveBuffsContains("Trueshot Aura") || character.ActiveBuffsContains("Unleashed Rage") || character.ActiveBuffsContains("Abomination's Might"))) { FullCharacterStats.BonusAttackPowerMultiplier += (.05f * character.DeathKnightTalents.AbominationsMight); } } // Sanguine Fortitude // Buff's IBF: // While Active, your IBF reduces Dam taken by 15/30% and costs 50/100% less RP to activate. // CD duration? 3min suggested on pwnwear. // Cost? This is a CD stacker. // TODO: look into CD stacking code./max v average values. // Blood Parasite // Melee Attacks have 5% * PTS chance of spawning a blood worm. // Blood worm attacks your enemies, gorging itself on blood // until it bursts to heal nearby allies. Lasts 20 sec. if (character.DeathKnightTalents.BloodParasite > 0) { float fDamageDone = 200f; // TODO: Put this in a way to increase DPS. float fBWAttackSpeed = 1.4f; // TODO: Validate this speed. float fBWDuration = 20f; float avgstacks = 5; // TODO: Figure out the best way to determine avg Stacks of BloodGorged float WormHealth = (FullCharacterStats.Health * 0.35f); _SE_Bloodworms = new SpecialEffect[] { null, new SpecialEffect(Trigger.MeleeAttack, new Stats() { Healed = ((avgstacks * WormHealth * .05f) / fBWDuration), PhysicalDamage = (fDamageDone/fBWAttackSpeed) }, fBWDuration, 0, .05f * 1), new SpecialEffect(Trigger.MeleeAttack, new Stats() { Healed = ((avgstacks * WormHealth * .05f) / fBWDuration), PhysicalDamage = (fDamageDone/fBWAttackSpeed) }, fBWDuration, 0, .05f * 2), }; FullCharacterStats.AddSpecialEffect(_SE_Bloodworms[character.DeathKnightTalents.BloodParasite]); } // Improved Blood Presence // Reduces chance to be critically hit while in blood presence by 3/6% // In addition while in Frost or Unholy, retain the 2/4% Dam reduction. // Implemented in AccumulatePresenceStats() // Will of the Necropolis // Dam that takes you below 35% health or while at less than 35% is reduced by 5% per point. if (character.DeathKnightTalents.WillOfTheNecropolis > 0) { // Need to factor in the damage taken aspect of the trigger. // Using the assumption that the tank will be at < 35% health about that % of the time. FullCharacterStats.AddSpecialEffect(_SE_WillOfTheNecropolis[character.DeathKnightTalents.WillOfTheNecropolis]); } // Rune Tap // Convert 1 BR to 10% health. if (character.DeathKnightTalents.RuneTap > 0) { FullCharacterStats.AddSpecialEffect(_SE_RuneTap); } // Vampiric Blood // temp 15% of max health and // increases health generated by 25% for 10 sec. // 1 min CD. if (character.DeathKnightTalents.VampiricBlood > 0) { FullCharacterStats.AddSpecialEffect(_SE_VampiricBlood[character.DeathKnightTalents.GlyphofVampiricBlood ? 1 : 0]); } // Improved Death Strike if (character.DeathKnightTalents.ImprovedDeathStrike > 0) { FullCharacterStats.BonusDamageDeathStrike += (.40f * character.DeathKnightTalents.ImprovedDeathStrike); // Also improves DS Healing. Implemented in TankDK heals section. } // Crimson Scourge // Increases the damage dealt by your Blood Boil by 20/40%, and when you Plague Strike a target that is already // infected with your Blood Plague, there is a 50/100% chance that your next Blood Boil will consume no runes. if (character.DeathKnightTalents.CrimsonScourge > 0) { // Part 1 implmented in BB Ability // TODO: Part 2 implement in rotation. } // Dancing Rune Weapon if (character.DeathKnightTalents.DancingRuneWeapon > 0) { uint u4T12 = FullCharacterStats.b4T12_Tank ? 1u : 0u; uint uGDRW = character.DeathKnightTalents.GlyphofDancingRuneWeapon ? 1u : 0u; FullCharacterStats.AddSpecialEffect(_SE_DRW[u4T12][uGDRW]); } } #endregion #region Frost Talents // Runic Power Mastery // Increases Max RP by 10 per point if (character.DeathKnightTalents.RunicPowerMastery > 0) { FullCharacterStats.BonusMaxRunicPower += 10 * character.DeathKnightTalents.RunicPowerMastery; } // Icy Reach // Increases range of IT & CoI and HB by 5 yards per point. // Nerves of Cold Steel // Increase hit w/ 1H weapons by 1% per point // Increase damage done by off hand weapons by 8/16/25% per point // Implement off-hand weapon buff in combat shot roation if (character.MainHand != null && (character.MainHand.Slot == ItemSlot.MainHand || character.MainHand.Slot == ItemSlot.OneHand)) { FullCharacterStats.PhysicalHit += (character.DeathKnightTalents.NervesOfColdSteel * .01f); } // Lichborne // for 10 sec, immune to charm, fear, sleep // CD 2 Mins // On a Pale Horse // Reduce duration of Movement slowing effects by 15% per point // increase mount speed by 10% per point if (character.DeathKnightTalents.OnAPaleHorse > 0) { // Now w/ boss handler, reduce the duration of the movement slowing effects. } // Endless Winter // Mind Freeze RP cost is reduced by 50% per point. if (character.DeathKnightTalents.EndlessWinter > 0) { } if (r == Rotation.Type.Frost) { // Merciless Combat // addtional 6% per point damage for IT, HB, Oblit, and FS // on targets of less than 35% health. if (character.DeathKnightTalents.MercilessCombat > 0) { // implemented in the abilities section (increase the damage done by 15% * 35%) } // Chill of the Grave // CoI, HB, IT and Oblit generate 5 RP per point. if (character.DeathKnightTalents.ChillOfTheGrave > 0) { // Implemented in the abilities. } // Killing Machine // Melee attacks have a chance to make OB, or FS a crit. // increased proc per point. // Research Suggests 5 PPM at 3/3 if (character.DeathKnightTalents.KillingMachine > 0) { // FullCharacterStats.AddSpecialEffect(_KM[character.DeathKnightTalents.KillingMachine]); // Implemented in Frost Rotation } // Rime // Oblit has a 15% per point your next IT or HB consumes no runes if (character.DeathKnightTalents.Rime > 0) { // Implemented in FrostRotation. } // Pillar of Frost // 1 min CD, 20 sec dur // Str +20% if (character.DeathKnightTalents.PillarOfFrost > 0) { FullCharacterStats.AddSpecialEffect(_SE_PillarOfFrost); } // Improved Icy Talons // increases the melee haste of the group/raid by 10% // increases your haste by 5% all the time. if (character.DeathKnightTalents.ImprovedIcyTalons > 0) { FullCharacterStats.PhysicalHaste = AddStatMultiplierStat(FullCharacterStats.PhysicalHaste, 0.05f); if (!character.ActiveBuffsContains("Improved Icy Talons") && !character.ActiveBuffsContains("Windfury Totem")) { FullCharacterStats.PhysicalHaste = AddStatMultiplierStat(FullCharacterStats.PhysicalHaste, .1f); FullCharacterStats.RangedHaste += .1f; } } // Brittle Bones: // Str +2% per point // FF chills the bones of its victims increasing damage taken by 2% per point. if (character.DeathKnightTalents.BrittleBones > 0) { FullCharacterStats.BonusStrengthMultiplier += .02f * character.DeathKnightTalents.BrittleBones; FullCharacterStats.BonusDamageMultiplier += .02f * character.DeathKnightTalents.BrittleBones; } // Chilblains // FF victimes are movement reduced 25% per point // Hungering Cold // Spell that freezes all enemies w/ 10 yards. // Improved Frost Presence // Increases your bonus damage while in Frost Presence by an additional 2% per point. // In addition, while in Blood Presence or Unholy Presence, you retain 2% per point increased runic power generation from Frost Presence. if (character.DeathKnightTalents.ImprovedFrostPresence > 0) { FullCharacterStats.BonusDamageMultiplier += (0.02f * character.DeathKnightTalents.ImprovedFrostPresence); } // Threat of Thassarian: // When dual-wielding, your Death Strikes, Obliterates, Plague Strikes, // Blood Strikes and Frost Strikes and Rune Strike (as of 3.2.2) have a 30/60/100% chance // to also deal damage with your off-hand weapon. if (character.DeathKnightTalents.ThreatOfThassarian > 0) { // implemented in the abilities } // Might of the Frozen Wastes // When wielding a two-handed weapon, your autoattacks have a 15% chance to generate 10 Runic Power. if (character.DeathKnightTalents.MightOfTheFrozenWastes > 0) { // WhiteDamage Bonus in WhiteDamage Ability. if (character.MainHand != null && character.MainHand.Slot == ItemSlot.TwoHand) FullCharacterStats.BonusPhysicalDamageMultiplier += (.1f/3) * character.DeathKnightTalents.MightOfTheFrozenWastes; } // Howling Blast. } #endregion #region UnHoly Talents // Unholy Command // reduces CD of DG by 5 sec per point // Virulence // if (character.DeathKnightTalents.Virulence > 0) { FullCharacterStats.BonusDiseaseDamageMultiplier += (.1f * character.DeathKnightTalents.Virulence); } // Epidemic // Increases Duration of BP and FF by 4 sec per point // Implemented in the abilities page. // Desecration // PS and SS cause Desecrated Ground effect. // Targets are slowed by 25% per point // Not Implemented. // Resilient Infection // When your diseases are dispelled you have a 50/100% to activate a // Frost rune if FF was dispelled // Unholy rune if BP was dispelled // Not Implemented // Morbidity // increases dam & healing of DC by 5% per point // increases dam of DnD by 10% sec per point if (character.DeathKnightTalents.Morbidity > 0) { // implemented in abilities. } if (r == Rotation.Type.Unholy) { // Runic Corruption // Reduces the cost of your Death Coil by 3 per point, and causes // your Runic Empowerment ability to no longer refresh a depleted // rune, but instead to increase your rune regeneration rate by 50/100% for 3 sec. if (character.DeathKnightTalents.RunicCorruption > 0) { // Implmented in rotation. } // Unholy Frenzy // Induces a friendly unit into a killing frenzy for 30 sec. // The target is Enraged, which increases their melee and ranged haste by 20%, // but causes them to lose health equal to 2% of their maximum health every 3 sec. // TODO: // Contagion // Increases the damage of your diseases spread via Pestilence by 50/100%. if (character.DeathKnightTalents.Contagion > 0) FullCharacterStats.BonusDiseaseDamageMultiplier += .5f * character.DeathKnightTalents.Contagion; // Shadow Infusion // When you cast Death Coil, you have a 33% per point chance to empower your active Ghoul, // increasing its damage dealt by 10% for 30 sec. Stacks up to 5 times. // TODO: Implement in Rotation & Ghoul // Magic Suppression // AMS absorbs additional 8, 16, 25% of spell damage. // Rage of Rivendare // Increases the damage of your Plague Strike, Scourge Strike, and Festering Strike abilities by 15% per point. if (character.DeathKnightTalents.RageOfRivendare > 0) { // Implemented in the abilities. } // Unholy Blight // Causes the victims of your Death Coil to be surrounded by a vile swarm of unholy insects, // taking 10% of the damage done by the Death Coil over 10 sec, and preventing any diseases on the victim from being dispelled. // Implemented in the DeathCoil ability. // AntiMagic Zone // Creates a zone where party/raid members take 75% less spell damage // Lasts 10 secs or X damage. if (character.DeathKnightTalents.AntiMagicZone > 0) { FullCharacterStats.AddSpecialEffect(_SE_AntiMagicZone); } // Improved Unholy Presence // Grants you an additional 2% haste while in Unholy Presence. // In addition, while in Blood Presence or Frost Presence, you retain 8% increased movement speed from Unholy Presence. // Implemented in Presence Stats. // Dark Transformation // Consume 5 charges of Shadow Infusion on your Ghoul to transform it into a powerful // undead monstrosity for 30 sec. The Ghoul's abilities are empowered and take on new // functions while the transformation is active. // TODO: implement in Ghoul // Ebon Plaguebringer // Your Plague Strike, Icy Touch, Chains of Ice, and Outbreak abilities also infect // their target with Ebon Plague, which increases damage taken from your diseases // by 15/30% and all magic damage taken by an additional 8%. if (character.DeathKnightTalents.EbonPlaguebringer > 0) { if (!character.ActiveBuffsContains("Earth and Moon") && !character.ActiveBuffsContains("Curse of the Elements") && !character.ActiveBuffsContains("Ebon Plaguebringer")) { float fBonus = .08f; FullCharacterStats.BonusArcaneDamageMultiplier += fBonus; FullCharacterStats.BonusFireDamageMultiplier += fBonus; FullCharacterStats.BonusFrostDamageMultiplier += fBonus; FullCharacterStats.BonusHolyDamageMultiplier += fBonus; FullCharacterStats.BonusNatureDamageMultiplier += fBonus; FullCharacterStats.BonusShadowDamageMultiplier += fBonus; } FullCharacterStats.BonusDiseaseDamageMultiplier += (.15f * character.DeathKnightTalents.EbonPlaguebringer); } // Sudden Doom // Your auto attacks have a 5% per point chance to make your next Death Coil cost no runic power. // TODO: To Implment in DeathCoil // Summon Gargoyle } #endregion }
public override Stats GetRelevantStats(Stats stats) { StatsDK s = new StatsDK() { // Core stats Strength = stats.Strength, Agility = stats.Agility, Stamina = stats.Stamina, ExpertiseRating = stats.ExpertiseRating, AttackPower = stats.AttackPower, MasteryRating = stats.MasteryRating, // Other Base Stats HasteRating = stats.HasteRating, HitRating = stats.HitRating, CritRating = stats.CritRating, Armor = stats.Armor, BonusArmor = stats.BonusArmor, Resilience = stats.Resilience, // Secondary Stats Health = stats.Health, SpellHaste = stats.SpellHaste, PhysicalCrit = stats.PhysicalCrit, PhysicalHaste = stats.PhysicalHaste, PhysicalHit = stats.PhysicalHit, SpellCrit = stats.SpellCrit, SpellCritOnTarget = stats.SpellCritOnTarget, SpellHit = stats.SpellHit, SpellPenetration = stats.SpellPenetration, // Dam stats WeaponDamage = stats.WeaponDamage, PhysicalDamage = stats.PhysicalDamage, ShadowDamage = stats.ShadowDamage, ArcaneDamage = stats.ArcaneDamage, FireDamage = stats.FireDamage, FrostDamage = stats.FrostDamage, HolyDamage = stats.HolyDamage, NatureDamage = stats.NatureDamage, // Bonus to stat BonusHealthMultiplier = stats.BonusHealthMultiplier, BonusStrengthMultiplier = stats.BonusStrengthMultiplier, BonusStaminaMultiplier = stats.BonusStaminaMultiplier, BonusAgilityMultiplier = stats.BonusAgilityMultiplier, BonusCritDamageMultiplier = stats.BonusCritDamageMultiplier, BonusAttackPowerMultiplier = stats.BonusAttackPowerMultiplier, // Bonus to Dam // *Dam BonusWhiteDamageMultiplier = stats.BonusWhiteDamageMultiplier, BonusDamageMultiplier = stats.BonusDamageMultiplier, BonusPhysicalDamageMultiplier = stats.BonusPhysicalDamageMultiplier, BonusShadowDamageMultiplier = stats.BonusShadowDamageMultiplier, BonusFrostDamageMultiplier = stats.BonusFrostDamageMultiplier, BonusDiseaseDamageMultiplier = stats.BonusDiseaseDamageMultiplier, // +Dam BonusFrostWeaponDamage = stats.BonusFrostWeaponDamage, BonusDamageScourgeStrike = stats.BonusDamageScourgeStrike, BonusDamageBloodStrike = stats.BonusDamageBloodStrike, BonusDamageDeathCoil = stats.BonusDamageDeathCoil, BonusDamageDeathStrike = stats.BonusDamageDeathStrike, BonusDamageFrostStrike = stats.BonusDamageFrostStrike, BonusDamageHeartStrike = stats.BonusDamageHeartStrike, BonusDamageIcyTouch = stats.BonusDamageIcyTouch, BonusDamageObliterate = stats.BonusDamageObliterate, // Crit BonusCritChanceDeathCoil = stats.BonusCritChanceDeathCoil, BonusCritChanceFrostStrike = stats.BonusCritChanceFrostStrike, BonusCritChanceObliterate = stats.BonusCritChanceObliterate, // Other CinderglacierProc = stats.CinderglacierProc, HighestStat = stats.HighestStat, HighestSecondaryStat = stats.HighestSecondaryStat, Paragon = stats.Paragon, ThreatIncreaseMultiplier = stats.ThreatIncreaseMultiplier, ThreatReductionMultiplier = stats.ThreatReductionMultiplier, TargetArmorReduction = stats.TargetArmorReduction, // BossHandler SnareRootDurReduc = stats.SnareRootDurReduc, FearDurReduc = stats.FearDurReduc, StunDurReduc = stats.StunDurReduc, MovementSpeed = stats.MovementSpeed, }; foreach (SpecialEffect effect in stats.SpecialEffects()) { if (HasRelevantStats(effect.Stats)) { if (effect.Trigger == Trigger.DamageDone || effect.Trigger == Trigger.DamageOrHealingDone || effect.Trigger == Trigger.DamageSpellCast || effect.Trigger == Trigger.DamageSpellCrit || effect.Trigger == Trigger.DamageSpellHit || effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellCrit || effect.Trigger == Trigger.SpellHit || effect.Trigger == Trigger.DoTTick || effect.Trigger == Trigger.MeleeCrit || effect.Trigger == Trigger.MeleeHit || effect.Trigger == Trigger.CurrentHandHit || effect.Trigger == Trigger.MainHandHit || effect.Trigger == Trigger.OffHandHit || effect.Trigger == Trigger.PhysicalCrit || effect.Trigger == Trigger.PhysicalHit || effect.Trigger == Trigger.PhysicalAttack || effect.Trigger == Trigger.BloodStrikeHit || effect.Trigger == Trigger.HeartStrikeHit || effect.Trigger == Trigger.ScourgeStrikeHit || effect.Trigger == Trigger.ObliterateHit || effect.Trigger == Trigger.DeathStrikeHit || effect.Trigger == Trigger.IcyTouchHit || effect.Trigger == Trigger.PlagueStrikeHit || effect.Trigger == Trigger.RuneStrikeHit || effect.Trigger == Trigger.DeathRuneGained || effect.Trigger == Trigger.Use) { s.AddSpecialEffect(effect); } } } return s; }