public void AbilityDK_IcyTouch_Basic() { // TODO: Get this so we don't have to do this work every test. Stats characterStats = new Stats(); characterStats = BaseStats.GetBaseStats(85, CharacterClass.DeathKnight, CharacterRace.Undead); CombatState state = new CombatState(); state.m_Stats = characterStats as StatsDK; state.m_Talents = new DeathKnightTalents(); // We're going to create IcyTouch and ensure that we can access everything for that // ability that is used by a DK. /* * AbilityDK_IcyTouch IT = new AbilityDK_IcyTouch(state); * * // Frost Fever application. is skipped for the purposes of this test. * Assert.IsTrue(IT.szName == "Icy Touch", "Name"); * Assert.AreEqual(IT.AbilityCost[(int)DKCostTypes.Blood], 0, "Blood Cost"); * Assert.AreEqual(IT.AbilityCost[(int)DKCostTypes.Frost], 1, "Frost Cost"); * Assert.AreEqual(IT.AbilityCost[(int)DKCostTypes.UnHoly], 0, "Unholy Cost"); * Assert.AreEqual(-10, IT.AbilityCost[(int)DKCostTypes.RunicPower], "RP Cost/Gain"); * Assert.AreEqual((uint)((245 + 227) / 2), IT.uBaseDamage, "Base Damage"); * Assert.AreEqual(20u, IT.uRange, "Range"); * Assert.AreEqual(IT.tDamageType, ItemDamageType.Frost, "Damage Type"); * Assert.AreEqual(IT.Cooldown, 1500u, "Cooldown"); * // With the addition of GetTotalDamage function we need to add it into the basic IT check. * Assert.AreEqual((int)IT.uBaseDamage, IT.GetTotalDamage(), "GetTotalDamage"); * */ }
public void GetDRAvoidanceChanceTest_Warr_TestTableDef10000() { const float testValue = 10000f; ItemInstance[] IIArray = new ItemInstance[1]; Character toon = new Character("TestWarrior", "Malygos", CharacterRegion.US, CharacterRace.Human, new BossOptions(), IIArray, new System.Collections.Generic.List <Buff>(), "ProtWarr"); // TODO: Initialize to an appropriate value Assert.IsNotNull(toon); //toon.Level = 80; //Asumption here. toon.Class = CharacterClass.Warrior; Stats stats = new Stats(); stats += BaseStats.GetBaseStats(toon); stats.Defense = 400; stats.DefenseRating = testValue; uint TargetLevel = 80; //float levelDiff = 0.006f; float[] expected = new float[HitResultCount]; expected[(int)HitResult.Miss] = 0.16f; expected[(int)HitResult.Dodge] = 0.7650f; expected[(int)HitResult.Parry] = 0.4700f; // Miss test float actual = (float)System.Math.Round((double)StatConversion.GetDRAvoidanceChance(toon, stats, HitResult.Miss, TargetLevel), 4); Assert.AreEqual(expected[(int)HitResult.Miss], actual, HitResult.Miss.ToString()); // Dodge Test actual = (float)System.Math.Round((double)StatConversion.GetDRAvoidanceChance(toon, stats, HitResult.Dodge, TargetLevel), 4); Assert.AreEqual(expected[(int)HitResult.Dodge], actual, HitResult.Dodge.ToString()); // Parry Test actual = (float)System.Math.Round((double)StatConversion.GetDRAvoidanceChance(toon, stats, HitResult.Parry, TargetLevel), 4); Assert.AreEqual(expected[(int)HitResult.Parry], actual, HitResult.Parry.ToString()); }
/// <param name="stats"> /// This should already have buffStats factored in. /// </param> public CharacterCalculationsWarlock(Character character, Stats stats, Stats petBuffs) { Character = character; CalcOpts = character.CalculationOptions as CalculationOptionsWarlock; BossOpts = character.BossOptions; Talents = character.WarlockTalents; Stats = stats; PreProcStats = Stats.Clone(); PetBuffs = petBuffs; BaseMana = BaseStats.GetBaseStats(character).Mana; BaseIntellect = BaseStats.GetBaseStats(character).Intellect; Spells = new Dictionary <string, Spell>(); CastSpells = new Dictionary <string, Spell>(); HitChance = Math.Min(1f, CalcOpts.GetBaseHitRate() / 100f + CalcSpellHit()); int temp; if (character.SetBonusCount.TryGetValue("Shadowflame Regalia", out temp)) { Warlock_T11_2P = (temp >= 2); Warlock_T11_4P = (temp >= 4); } if (!CalcOpts.Pet.Equals("None") && (Demonology || !CalcOpts.Pet.Equals("Felguard"))) { Type type = Type.GetType("Rawr.Warlock." + CalcOpts.Pet); Pet = (Pet)Activator.CreateInstance(type, new object[] { this }); } float personalDps = CalcPersonalDps(); float petDps = CalcPetDps(); SubPoints = new float[] { personalDps, petDps }; OverallPoints = personalDps + petDps; }
/// <summary> /// Instant, 1 min cd, Self (Any) /// Generates 10 rage at the cost of health and then generates an additional 10 rage over 10 sec. /// </summary> /// <TalentsAffecting>Improved Bloodrge [+(25*Pts)% Rage Generated], Intensify Rage [-(1/9*Pts]% Cooldown]</TalentsAffecting> /// <GlyphsAffecting>Glyph of Bloodrage [-100% Health Cost]</GlyphsAffecting> public Bloodrage(Character c, Stats s, CombatFactors cf, WhiteAttacks wa, CalculationOptionsDPSWarr co, BossOptions bo) { Char = c; StatS = s; combatFactors = cf; Whiteattacks = wa; CalcOpts = co; BossOpts = bo; // Name = "Bloodrage"; Description = "Generates 10 rage at the cost of health and then generates an additional 10 rage over 10 sec."; AbilIterater = (int)Rawr.DPSWarr.CalculationOptionsDPSWarr.Maintenances.Bloodrage_; Cd = 60f * (1f - 1f / 9f * Talents.IntensifyRage); // In Seconds Duration = 10f; // In Seconds // Rage is actually reversed in the rotation RageCost = -(20f // Base + 10f) // Over Time * (1f + Talents.ImprovedBloodrage * 0.25f); // Talent Bonus StanceOkArms = StanceOkDef = StanceOkFury = true; Stats Base = BaseStats.GetBaseStats(Char.Level, CharacterClass.Warrior, Char.Race); float baseHealth = Base.Health + StatConversion.GetHealthFromStamina(Base.Stamina, CharacterClass.Warrior); HealingBase = -1f * (float)Math.Floor(baseHealth) * 0.16f; HealingBonus = (Talents.GlyphOfBloodrage ? 0f : 1f); UseHitTable = false; UsesGCD = false; UseReact = true; // Initialize(); }
public void SetManaRegen() //Check { baseMana = BaseStats.GetBaseStats(_character).Mana; float replenishRegen = (_stats.Mana * _stats.ManaRestoreFromMaxManaPerSecond) * 5f; float primalWisdomRegen = (((hitsPerSMH + hitsPerSOH) * 0.40f) * (baseMana * 0.05f)) * 5f; baseRegen = baseMana * 0.05f; manaRegen = _stats.Mp5 + baseRegen + replenishRegen + primalWisdomRegen; }
public void SetManaRegen() { baseMana = BaseStats.GetBaseStats(_character).Mana; float spiRegen = StatConversion.GetSpiritRegenSec(_stats.Spirit, _stats.Intellect); float replenishRegen = _stats.Mana * _stats.ManaRestoreFromMaxManaPerSecond; float judgementRegen = _stats.ManaRestoreFromBaseManaPPM / 60f * baseMana; manaRegen = _stats.Mp5 / 5 + spiRegen + replenishRegen + judgementRegen; }
public override Stats GetCharacterStats(Character character, Item additionalItem) { CalculationOptionsHealPriest calcOpts = character.CalculationOptions as CalculationOptionsHealPriest; StatsPriest statsTotal = new StatsPriest() { SpellHaste = PriestInformation.GetDarkness(character.PriestTalents.Darkness), InnerFire = true, BonusIntellectMultiplier = 0.05f, // Cloth bonus. PriestSpec = PriestSpec.GetPriestSpec(character.PriestTalents), }; if (statsTotal.PriestSpec == ePriestSpec.Spec_Disc) { statsTotal.SpellCombatManaRegeneration = 0.5f; statsTotal.BonusIntellectMultiplier = 0.15f; } else if (statsTotal.PriestSpec == ePriestSpec.Spec_Holy) { statsTotal.SpellCombatManaRegeneration = 0.5f + PriestInformation.GetHolyConcentration(character.PriestTalents.HolyConcentration); statsTotal.BonusHealingDoneMultiplier = 0.15f; } else if (statsTotal.PriestSpec == ePriestSpec.Spec_ERROR) { throw new Exception("Unpossible Talent Spec!"); } statsTotal.Accumulate(BaseStats.GetBaseStats(character)); statsTotal.Accumulate(GetItemStats(character, additionalItem)); statsTotal.Accumulate(GetBuffsStats(character, calcOpts)); statsTotal.Stamina = (float)Math.Floor((statsTotal.Stamina) * (1 + statsTotal.BonusStaminaMultiplier)); statsTotal.Intellect = (float)Math.Floor((statsTotal.Intellect) * (1 + statsTotal.BonusIntellectMultiplier)); statsTotal.Spirit = (float)Math.Floor((statsTotal.Spirit) * (1 + statsTotal.BonusSpiritMultiplier)); statsTotal.SpellPower += (statsTotal.InnerFire ? PriestInformation.GetInnerFireSpellPowerBonus(character) : 0) + (statsTotal.Intellect - 10); statsTotal.SpellPower *= (1f + statsTotal.BonusSpellPowerMultiplier); statsTotal.Mana += StatConversion.GetManaFromIntellect(statsTotal.Intellect); statsTotal.Mana *= (1f + statsTotal.BonusManaMultiplier); statsTotal.Health += StatConversion.GetHealthFromStamina(statsTotal.Stamina); statsTotal.Health = (float)Math.Floor(statsTotal.Health * (1f + statsTotal.BonusHealthMultiplier)); statsTotal.SpellCrit += StatConversion.GetSpellCritFromIntellect(statsTotal.Intellect) + StatConversion.GetSpellCritFromRating(statsTotal.CritRating); statsTotal.SpellHaste = (1f + statsTotal.SpellHaste) * (1f + StatConversion.GetSpellHasteFromRating(statsTotal.HasteRating)) - 1f; statsTotal.Armor *= (1 + (statsTotal.InnerFire ? PriestInformation.GetInnerFireArmorBonus(character) : 0)); if (statsTotal.PriestSpec == ePriestSpec.Spec_Disc) { statsTotal.ShieldDiscipline = (PriestInformation.DisciplineMasteryBase + StatConversion.GetMasteryFromRating(statsTotal.MasteryRating)) * PriestInformation.DisciplineMasteryEffect; } else if (statsTotal.PriestSpec == ePriestSpec.Spec_Holy) { statsTotal.EchoofLight = (PriestInformation.HolyMasteryBase + StatConversion.GetMasteryFromRating(statsTotal.MasteryRating)) * PriestInformation.HolyMasteryEffect; } return(statsTotal); }
public override Stats GetCharacterStats(Character character, Item additionalItem) { WarlockTalents talents = character.WarlockTalents; CalculationOptionsWarlock calcOpts = character.CalculationOptions as CalculationOptionsWarlock; BossOptions bossOpts = character.BossOptions; Stats stats = BaseStats.GetBaseStats(character); AccumulateItemStats(stats, character, additionalItem); AccumulateBuffsStats(stats, character.ActiveBuffs); AccumulateSetBonusStats(stats, character.SetBonusCount); ApplyPetsRaidBuff(stats, calcOpts.Pet, talents, character.ActiveBuffs, calcOpts); float[] demonicEmbraceValues = { 0f, .04f, .07f, .1f }; Stats statsTalents = new Stats { BonusStaminaMultiplier = demonicEmbraceValues[talents.DemonicEmbrace] //Demonic Embrace }; if (talents.Eradication > 0) { float[] eradicationValues = { 0f, .06f, .12f, .20f }; statsTalents.AddSpecialEffect( new SpecialEffect( Trigger.CorruptionTick, new Stats() { SpellHaste = eradicationValues[talents.Eradication] }, 10f, //duration 0f, //cooldown .06f)); //chance } stats.Accumulate(statsTalents); stats.ManaRestoreFromMaxManaPerSecond = Math.Max( stats.ManaRestoreFromMaxManaPerSecond, .001f * Spell.CalcUprate(talents.SoulLeech > 0 ? 1f : 0f, 15f, bossOpts.BerserkTimer * 1.1f)); return(stats); }
public void GetDRAvoidanceChanceTest_DK_TestFromForums() { ItemInstance[] IIArray = new ItemInstance[1]; Character toon = new Character("TestDK", "Malygos", CharacterRegion.US, CharacterRace.Human, new BossOptions(), IIArray, new System.Collections.Generic.List <Buff>(), "TankDK"); // TODO: Initialize to an appropriate value Assert.IsNotNull(toon); //toon.Level = 80; //Asumption here. toon.Class = CharacterClass.DeathKnight; Stats stats = new Stats(); stats += BaseStats.GetBaseStats(toon); stats.Miss += .03f; // 3% Miss from talents stats.Defense = 425; // 25 Def from SSG rune stats.Dodge += .05f; // 5% dodge from talents. stats.DefenseRating = 566f; uint TargetLevel = 83; //float levelDiff = 0.006f; float[] expected = new float[HitResultCount]; expected[(int)HitResult.Miss] = 0.121f; expected[(int)HitResult.Dodge] = 0.134f; expected[(int)HitResult.Parry] = 0.098f; expected[(int)HitResult.Block] = .05f; expected[(int)HitResult.Crit] = .05f; expected[(int)HitResult.AnyMiss] = 0; expected[(int)HitResult.AnyHit] = 0; expected[(int)HitResult.Glance] = .05f; expected[(int)HitResult.Resist] = .05f; expected[(int)HitResult.Hit] = .05f; // Iterate through the hit result types. for (HitResult i = 0; i < (HitResult)HitResultCount; i++) { float actual = (float)System.Math.Round((double)StatConversion.GetDRAvoidanceChance(toon, stats, i, TargetLevel), 3); Assert.AreEqual(expected[(int)i], actual, i.ToString()); } }
/// <param name="stats"> /// This should already have buffStats factored in. /// </param> public CharacterCalculationsWarlock( Character character, Stats stats, Stats petBuffs) { Character = character; Options = (CalculationOptionsWarlock)character.CalculationOptions; if (Options == null) { Options = CalculationOptionsWarlock.MakeDefaultOptions(); } Talents = character.WarlockTalents; Stats = stats; PreProcStats = Stats.Clone(); PetBuffs = petBuffs; BaseMana = BaseStats.GetBaseStats(character).Mana; Spells = new Dictionary <string, Spell>(); CastSpells = new Dictionary <string, Spell>(); HitChance = Math.Min( 1f, Options.GetBaseHitRate() / 100f + CalcSpellHit()); if (!Options.Pet.Equals("None") && (Talents.SummonFelguard > 0 || !Options.Pet.Equals("Felguard"))) { Type type = Type.GetType("Rawr.Warlock." + Options.Pet); Pet = (Pet)Activator.CreateInstance( type, new object[] { this }); } float personalDps = CalcPersonalDps(); float petDps = CalcPetDps(); float raidBuff = CalcRaidBuff(); SubPoints = new float[] { personalDps, petDps, raidBuff }; OverallPoints = personalDps + petDps + raidBuff; }
public virtual void UpdateSpell() { HasDirectDamage = false; HasDirectHeal = false; HasAbsorb = false; HasOverTimeDamage = false; HasOverTimeHeal = false; float hc = 1f / (1f + stats.SpellHaste); IsInstant = BaseCastTime == 0f; if (IsInstant) { CastTime = 0f; } else { CastTime = Math.Max(1f, BaseCastTime * hc); } GlobalCooldown = Math.Max(1f, BaseGlobalCooldown * hc); CritChance = stats.SpellCrit; CritMultiplier = 1.5f * (1f + stats.BonusCritHealMultiplier); ManaCost = BaseManaCost * BaseStats.GetBaseStats(character).Mana; // priestInformation.BaseMana; if (IsInstant) { ManaCost *= PriestInformation.GetMentalAgility(character.PriestTalents.MentalAgility); } }
public override float GetOptimizableCalculationValue(string calculation) { switch (calculation) { case "Health": return(basicStats.Health); case "Resilience": return(basicStats.Resilience); case "Mana": return(basicStats.Mana); case "Haste Rating": return(basicStats.HasteRating); case "Haste %": return(basicStats.SpellHaste * 100f); case "Crit Rating": return(basicStats.CritRating); case "MB Crit %": return(new MindBlast(basicStats, character, BaseStats.GetBaseStats(character).Mana, (character.CalculationOptions as CalculationOptionsShadowPriest).PTR).CritChance * 100f); case "Hit Rating": return(basicStats.HitRating); case "MF cast time (ms)": return(new MindFlay(basicStats, character, BaseStats.GetBaseStats(character).Mana, (character.CalculationOptions as CalculationOptionsShadowPriest).PTR).CastTime * 1000f); case "Armor": return(basicStats.Armor + basicStats.BonusArmor); case "Arcane Resistance": return(basicStats.ArcaneResistance + basicStats.ArcaneResistanceBuff); case "Fire Resistance": return(basicStats.FireResistance + basicStats.FireResistanceBuff); case "Frost Resistance": return(basicStats.FrostResistance + basicStats.FrostResistance); case "Nature Resistance": return(basicStats.NatureResistance + basicStats.NatureResistanceBuff); case "Shadow Resistance": return(basicStats.ShadowResistance + basicStats.ShadowResistanceBuff); } return(0f); }
/// <summary> /// Builds a dictionary containing the values to display for each of the calculations defined in /// CharacterDisplayCalculationLabels. The key should be the Label of each display calculation, /// and the value should be the value to display, optionally appended with '*' followed by any /// string you'd like displayed as a tooltip on the value. /// </summary> /// <returns>A Dictionary<string, string> containing the values to display for each of the /// calculations defined in CharacterDisplayCalculationLabels.</returns> public override Dictionary <string, string> GetCharacterDisplayCalculationValues() { Dictionary <string, string> dictValues = new Dictionary <string, string>(); #region Simulation stats dictValues.Add("Rotation", String.Format("{0}*{1}", Name, Abilities)); dictValues.Add("Warlock DPS", String.Format("{0:0}", DpsPoints)); dictValues.Add("Pet DPS", String.Format("{0:0}", PetDPSPoints)); dictValues.Add("Total DPS", String.Format("{0:0}", OverallPoints)); dictValues.Add("Damage Done", String.Format("{0:0}", OverallDamage)); dictValues.Add("Mana Used", String.Format("{0:0}", TotalManaCost)); #endregion #region HP/Mana stats dictValues.Add("Health", String.Format("{0:0}", TotalStats.Health)); dictValues.Add("Mana", String.Format("{0:0}", TotalStats.Mana)); #endregion #region Base stats dictValues.Add("Strength", String.Format("{0}", TotalStats.Strength)); dictValues.Add("Agility", String.Format("{0}", TotalStats.Agility)); dictValues.Add("Stamina", String.Format("{0}", TotalStats.Stamina)); dictValues.Add("Intellect", String.Format("{0}", TotalStats.Intellect)); dictValues.Add("Spirit", String.Format("{0}", TotalStats.Spirit)); dictValues.Add("Armor", String.Format("{0}", TotalStats.Armor)); #endregion #region Pet stats Minion minion = MinionFactory.CreateMinion(Options.Pet, Character, TotalStats); if (minion != null) { dictValues.Add("Pet Strength", String.Format("{0}", minion.Strength())); dictValues.Add("Pet Agility", String.Format("{0}", minion.Agility())); dictValues.Add("Pet Stamina", String.Format("{0:0}", minion.Stamina())); dictValues.Add("Pet Intellect", String.Format("{0:0}", minion.Intellect())); dictValues.Add("Pet Spirit", String.Format("{0}", minion.Spirit())); dictValues.Add("Pet Armor", String.Format("{0}", minion.Armor())); } #endregion #region Spell stats //pet scaling consts: http://www.wowwiki.com/Warlock_minions const float petInheritedAttackPowerPercentage = 0.57f; const float petInheritedSpellPowerPercentage = 0.15f; dictValues.Add("Bonus Damage", String.Format("{0}*Shadow Damage\t{1}\r\nFire Damage\t{2}\r\n\r\nYour Fire Damage increases your pet's Attack Power by {3} and Spell Damage by {4}.", TotalStats.SpellPower, TotalStats.SpellPower + TotalStats.SpellShadowDamageRating, TotalStats.SpellPower + TotalStats.SpellFireDamageRating, Math.Round((TotalStats.SpellPower + TotalStats.SpellFireDamageRating) * petInheritedAttackPowerPercentage, 0), Math.Round((TotalStats.SpellPower + TotalStats.SpellFireDamageRating) * petInheritedSpellPowerPercentage, 0) )); #region Hit / Miss chance //float bonusHit = TotalStats.SpellHit; float onePercentOfHitRating = (1 / StatConversion.GetSpellHitFromRating(1)); float hitFromRating = StatConversion.GetSpellHitFromRating(TotalStats.HitRating); float hitFromTalents = (Character.WarlockTalents.Suppression * 0.01f); float hitFromBuffs = (TotalStats.SpellHit - hitFromRating - hitFromTalents); float targetHit = (Options.TargetHit / 100f); float totalHit = (targetHit + TotalStats.SpellHit); float missChance = (totalHit > 1 ? 0 : (1 - totalHit)); //calculate the amount of hit rating that is over or under the cap float hitDelta = (totalHit > 1) ? (float)Math.Floor((totalHit - 1) * onePercentOfHitRating) : (float)Math.Ceiling((1 - totalHit) * onePercentOfHitRating); //now we can calculate the hitcap value float hitCap = (totalHit > 1) ? TotalStats.HitRating - hitDelta : TotalStats.HitRating + hitDelta; dictValues.Add("Hit Rating", String.Format("{0}*{1:0.00%} Hit Chance (max 100%) | {2:0.00%} Miss Chance \r\n\r\n" + "{3:0.00%}\t Base Hit Chance on a Level {4:0} target\r\n" + "{5:0.00%}\t from {6:0} Hit Rating [gear, food and/or flasks]\r\n" + "{7:0.00%}\t from Talent: Suppression\r\n" + "{8:0.00%}\t from Buffs: Racial and/or Spell Hit Chance Taken\r\n\r\n" + "{9}\r\n\r\n" + "Hit Rating caps:\r\n" + "446 - hard cap (no hit from talents, gear or buffs)\r\n" + "420 - Heroic Presence\r\n" + "368 - Suppression\r\n" + "342 - Suppression and Heroic Presence\r\n" + "289 - Suppression, Improved Faerie Fire / Misery\r\n" + "263 - Suppression, Improved Faerie Fire / Misery and Heroic Presence", TotalStats.HitRating, totalHit, missChance, targetHit, Options.TargetLevel, hitFromRating, TotalStats.HitRating, hitFromTalents, hitFromBuffs, String.Format("You are {0} hit rating {1} the {2} cap.", hitDelta, ((totalHit > 1) ? "above" : "below"), hitCap) )); dictValues.Add("Miss chance", String.Format("{0:0.00%}", missChance)); #endregion #region Crit % Stats statsBase = BaseStats.GetBaseStats(Character); float critFromRating = StatConversion.GetSpellCritFromRating(TotalStats.CritRating); float critFromIntellect = StatConversion.GetSpellCritFromIntellect(TotalStats.Intellect); float critFromBuffs = TotalStats.SpellCrit - statsBase.SpellCrit - critFromRating - critFromIntellect - (Character.WarlockTalents.DemonicTactics * 0.02f) - (Character.WarlockTalents.Backlash * 0.01f); dictValues.Add("Crit Chance", String.Format("{0:0.00%}*" + "{1:0.00%}\tfrom {2:0} Spell Crit rating\r\n" + "{3:0.00%}\tfrom {4:0} Intellect\r\n" + "{5:0.000%}\tfrom Warlock Class Bonus\r\n" + "{6:0%}\tfrom Talent: Demonic Tactics\r\n" + "{7:0%}\tfrom Talent: Backlash\r\n" + "{8:0%}\tfrom Buffs", TotalStats.SpellCrit, critFromRating, TotalStats.CritRating, critFromIntellect, TotalStats.Intellect, statsBase.SpellCrit, (Character.WarlockTalents.DemonicTactics * 0.02f), (Character.WarlockTalents.Backlash * 0.01f), critFromBuffs )); #endregion dictValues.Add("Haste Rating", String.Format("{0}%*{1}%\tfrom {2} Haste rating\r\n{3}%\tfrom Buffs\r\n{4}s\tGlobal Cooldown", (TotalStats.SpellHaste * 100f).ToString("0.00"), (StatConversion.GetSpellHasteFromRating(TotalStats.HasteRating) * 100f).ToString("0.00"), TotalStats.HasteRating, (TotalStats.SpellHaste * 100f - StatConversion.GetSpellHasteFromRating(TotalStats.HasteRating) * 100f).ToString("0.00"), Math.Max(1.0f, 1.5f / (1 + TotalStats.SpellHaste)).ToString("0.00"))); dictValues.Add("Mana Regen", String.Format("{0}*{0} mana regenerated every 5 seconds while not casting\r\n{1} mana regenerated every 5 seconds while casting", GetManaRegenOutOfCombat(), GetManaRegenInCombat())); #endregion #region Shadow school dictValues.Add("Shadow Bolt", new ShadowBolt(TotalStats, Character, Options).ToString()); if (Character.WarlockTalents.Haunt > 0) { dictValues.Add("Haunt", new Haunt(TotalStats, Character, Options).ToString()); } else { dictValues.Add("Haunt", "- *Required talent not available"); } dictValues.Add("Corruption", new Corruption(TotalStats, Character, Options).ToString()); dictValues.Add("Curse of Agony", new CurseOfAgony(TotalStats, Character, Options).ToString()); dictValues.Add("Curse of Doom", new CurseOfDoom(TotalStats, Character, Options).ToString()); if (Character.WarlockTalents.UnstableAffliction > 0) { dictValues.Add("Unstable Affliction", new UnstableAffliction(TotalStats, Character, Options).ToString()); } else { dictValues.Add("Unstable Affliction", "- *Required talent not available"); } dictValues.Add("Death Coil", new DeathCoil(TotalStats, Character, Options).ToString()); dictValues.Add("Drain Life", new DrainLife(TotalStats, Character, Options).ToString()); dictValues.Add("Drain Soul", new DrainSoul(TotalStats, Character, Options).ToString()); dictValues.Add("Seed of Corruption", new SeedOfCorruption(TotalStats, Character, Options).ToString()); dictValues.Add("Shadowflame", new Shadowflame(TotalStats, Character, Options).ToString()); if (Character.WarlockTalents.Shadowburn > 0) { dictValues.Add("Shadowburn", new Shadowburn(TotalStats, Character, Options).ToString()); } else { dictValues.Add("Shadowburn", "- *Required talent not available"); } if (Character.WarlockTalents.Shadowfury > 0) { dictValues.Add("Shadowfury", new Shadowfury(TotalStats, Character, Options).ToString()); } else { dictValues.Add("Shadowfury", "- *Required talent not available"); } dictValues.Add("Life Tap", new LifeTap(TotalStats, Character, Options).ToString()); if (Character.WarlockTalents.DarkPact > 0) { dictValues.Add("Dark Pact", new DarkPact(TotalStats, Character, Options).ToString()); } else { dictValues.Add("Dark Pact", "- *Required talent not available"); } #endregion #region Fire school dictValues.Add("Incinerate", new Incinerate(TotalStats, Character, Options).ToString()); dictValues.Add("Immolate", new Immolate(TotalStats, Character, Options).ToString()); if (Character.WarlockTalents.Conflagrate > 0) { dictValues.Add("Conflagrate", new Conflagrate(TotalStats, Character, Options).ToString()); } else { dictValues.Add("Conflagrate", "- *Required talent not available"); } if (Character.WarlockTalents.ChaosBolt > 0) { dictValues.Add("Chaos Bolt", new ChaosBolt(TotalStats, Character, Options).ToString()); } else { dictValues.Add("Chaos Bolt", "- *Required talent not available"); } dictValues.Add("Rain of Fire", new RainOfFire(TotalStats, Character, Options).ToString()); dictValues.Add("Hellfire", new Hellfire(TotalStats, Character, Options).ToString()); if (Character.WarlockTalents.Metamorphosis > 0) { dictValues.Add("Immolation Aura", new ImmolationAura(TotalStats, Character, Options).ToString()); } else { dictValues.Add("Immolation Aura", "- *Required talent not available"); } dictValues.Add("Searing Pain", new SearingPain(TotalStats, Character, Options).ToString()); dictValues.Add("Soul Fire", new SoulFire(TotalStats, Character, Options).ToString()); #endregion return(dictValues); }
/// <summary> /// Calculate the mana required to perform this ability. /// </summary> public virtual float Mana() { Stats statsBase = BaseStats.GetBaseStats(Character); return((float)Math.Floor(statsBase.Mana * Cost())); }
public Stats GetCharacterStats(Character character, Item additionalItem, bool computeAverageStats, CharacterCalculationsHealadin calc) { CalculationOptionsHealadin calcOpts = character.CalculationOptions as CalculationOptionsHealadin; BossOptions bossOpts = character.BossOptions; PaladinTalents talents = character.PaladinTalents; float fightLength = bossOpts.BerserkTimer; Stats statsRace = BaseStats.GetBaseStats(character.Level, CharacterClass.Paladin, character.Race); Stats statsBaseGear = GetItemStats(character, additionalItem); Stats statsBuffs = GetBuffsStats(character, calcOpts); Stats stats = statsBaseGear + statsBuffs + statsRace; ConvertRatings(stats, talents, calcOpts); if (computeAverageStats) { Stats statsAverage = new Stats(); foreach (SpecialEffect effect in stats.SpecialEffects()) { float trigger = 0f; if (calc == null) { trigger = 1.5f / calcOpts.Activity / (1f + stats.SpellHaste); if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit) { trigger *= stats.SpellCrit; } } else { if (effect.Trigger == Trigger.HealingSpellCast || effect.Trigger == Trigger.HealingSpellHit) { trigger = 1f / Rotation.GetHealingCastsPerSec(calc); } else if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit) { trigger = 1f / Rotation.GetHealingCritsPerSec(calc); } else if (effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit) { trigger = 1f / Rotation.GetSpellCastsPerSec(calc); } else if (effect.Trigger == Trigger.DamageOrHealingDone) { trigger = 1f / Rotation.GetHealingCastsPerSec(calc); } else if (effect.Trigger == Trigger.Use) { trigger = 0f; foreach (SpecialEffect childEffect in effect.Stats.SpecialEffects()) { float childTrigger = 0f; if (effect.Trigger == Trigger.HealingSpellCast || effect.Trigger == Trigger.HealingSpellHit) { childTrigger = 1f / Rotation.GetHealingCastsPerSec(calc); } else if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit) { childTrigger = 1f / Rotation.GetHealingCritsPerSec(calc); } else if (effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit) { childTrigger = 1f / Rotation.GetSpellCastsPerSec(calc); } statsAverage.Accumulate(childEffect.Stats, effect.GetAverageUptime(0.0f, 1.0f) * childEffect.GetAverageStackSize(childTrigger, 1f, 1.5f, effect.Duration)); } } else { continue; } } statsAverage.Accumulate(effect.GetAverageStats(trigger, 1f, 1.5f, fightLength)); } statsAverage.ManaRestore *= fightLength; statsAverage.Healed *= fightLength; statsAverage.HealedPerSP *= fightLength; stats = statsBaseGear + statsBuffs + statsRace + statsAverage; ConvertRatings(stats, talents, calcOpts); } #region Set Bonuses int T11Count; character.SetBonusCount.TryGetValue("Reinforced Sapphirium Regalia", out T11Count); stats.BonusCritChanceDeathCoil = 0; // using this for Holy Light crit bonus, for now stats.BonusCritChanceFrostStrike = 0; // yes, I'm pure evil, using this to track 4T11 if (T11Count >= 2) { // T11 Pally 2 piece bonus: add 5% crit to HL stats.BonusCritChanceDeathCoil = 0.05f; } if (T11Count >= 4) { // T11 Pally 4 piece bonus: 540 spirit buff for 6 secs after HS cast stats.BonusCritChanceFrostStrike = 1; } #endregion Set Bonuses return(stats); }
public static void CalculateNewStats(LivingObject lobj) { if (lobj.ObjectType == OBJECTTYPE.PLAYER) { PlayerObject pobj = (PlayerObject)lobj; BaseStats stats = BaseStats.GetBaseStats(pobj); pobj.MaxHealth = stats.Health; pobj.MaxPower = stats.Power; pobj.BaseStrength = stats.Strength; pobj.BaseStamina = stats.Stamina; pobj.BaseAgility = stats.Agility; pobj.BaseIntellect = stats.Intellect; pobj.BaseSpirit = stats.Spirit; CalculateInvStats(pobj); } else if (lobj.ObjectType == OBJECTTYPE.UNIT) { UnitBase uobj = (UnitBase)lobj; int basehealth = 60; int basestamina = Convert.ToInt32(((float)lobj.Level * ((float)lobj.Level * 0.2f)) - 1); if (basestamina < (uobj.Level - 1)) { basestamina = uobj.Level - 1; } int health = basehealth + (basestamina * 10); if (uobj.Level < 10) { switch (uobj.Level) { case 1: uobj.BaseAttackTime = 2000; uobj.MinDamage = (float)2.0; uobj.MaxDamage = (float)4.0; break; case 2: uobj.BaseAttackTime = 2600; uobj.MinDamage = (float)3.0; uobj.MaxDamage = (float)6.0; break; case 3: uobj.BaseAttackTime = 2200; uobj.MinDamage = (float)3.0; uobj.MaxDamage = (float)6.0; break; case 4: uobj.BaseAttackTime = 2000; uobj.MinDamage = (float)3.0; uobj.MaxDamage = (float)6.0; break; case 5: uobj.BaseAttackTime = 1800; uobj.MinDamage = (float)3.0; uobj.MaxDamage = (float)6.0; break; case 6: uobj.BaseAttackTime = 2100; uobj.MinDamage = (float)4.0; uobj.MaxDamage = (float)8.0; break; case 7: uobj.BaseAttackTime = 1950; uobj.MinDamage = (float)4.0; uobj.MaxDamage = (float)8.0; break; case 8: uobj.BaseAttackTime = 1800; uobj.MinDamage = (float)4.0; uobj.MaxDamage = (float)8.0; break; case 9: uobj.BaseAttackTime = 2200; uobj.MinDamage = (float)5.0; uobj.MaxDamage = (float)10.0; break; } } else { uobj.BaseAttackTime = 2000; uobj.MinDamage = (float)uobj.Level / (float)2.0; uobj.MaxDamage = (float)uobj.Level; } uobj.MaxHealth = health; uobj.MaxPower = 0; } }
public override Stats GetCharacterStats(Character character, Item additionalItem) { CalculationOptionsElemental calcOpts = character.CalculationOptions as CalculationOptionsElemental; Stats statsRace = BaseStats.GetBaseStats(character); Stats statsItems = GetItemStats(character, additionalItem); Stats statsBuffs = GetBuffsStats(character, calcOpts); Stats statsTotal = statsRace + statsItems + statsBuffs; if (statsTotal.HighestStat > 0) { if (statsTotal.Spirit > statsTotal.Intellect) { statsTotal.Spirit += (statsTotal.HighestStat * 15f / 50f); } else { statsTotal.Intellect += (statsTotal.HighestStat * 15f / 50f); } } statsTotal.Strength *= 1 + statsTotal.BonusStrengthMultiplier; statsTotal.Agility *= 1 + statsTotal.BonusAgilityMultiplier; statsTotal.Stamina *= 1 + statsTotal.BonusStaminaMultiplier; statsTotal.Intellect *= 1 + statsTotal.BonusIntellectMultiplier; statsTotal.Spirit *= 1 + statsTotal.BonusSpiritMultiplier; statsTotal.Strength = (float)Math.Floor(statsTotal.Strength); statsTotal.Agility = (float)Math.Floor(statsTotal.Agility); statsTotal.Stamina = (float)Math.Floor(statsTotal.Stamina); statsTotal.Intellect = (float)Math.Floor(statsTotal.Intellect); statsTotal.Spirit = (float)Math.Floor(statsTotal.Spirit); if (Character.ValidateArmorSpecialization(character, ItemType.Mail)) { statsTotal.Intellect *= 1.05f; } statsTotal.AttackPower += statsTotal.Strength + statsTotal.Agility; statsTotal.Mana += StatConversion.GetManaFromIntellect(statsTotal.Intellect); statsTotal.Mana *= (float)Math.Round(1f + statsTotal.BonusManaMultiplier); statsTotal.Health += StatConversion.GetHealthFromStamina(statsTotal.Stamina); statsTotal.Health *= (float)Math.Round(1f + statsTotal.BonusHealthMultiplier); statsTotal.SpellCrit += StatConversion.GetSpellCritFromRating(statsTotal.CritRating); statsTotal.SpellCrit += StatConversion.GetSpellCritFromIntellect(statsTotal.Intellect); statsTotal.SpellCrit += statsTotal.SpellCritOnTarget; statsTotal.SpellHit += StatConversion.GetSpellHitFromRating(statsTotal.HitRating + ((.33f * character.ShamanTalents.ElementalPrecision) * statsTotal.Spirit)); // Flametongue weapon assumed statsTotal.SpellPower += (float)Math.Floor(747.78 * (1f + character.ShamanTalents.ElementalWeapons * .2f)); if (character.ShamanTalents.GlyphofFlametongueWeapon) { statsTotal.SpellCrit += .02f; } // Water shield assumed statsTotal.Mp5 += 100; if (character.ShamanTalents.GlyphofWaterShield) { statsTotal.Mp5 += 30; } return(statsTotal); }
public override Dictionary <string, string> GetCharacterDisplayCalculationValues() { Dictionary <string, string> dictValues = new Dictionary <string, string>(); Stats baseStats = BaseStats.GetBaseStats(character); dictValues.Add("Health", BasicStats.Health.ToString()); dictValues.Add("Stamina", BasicStats.Stamina.ToString()); float ResilienceCap = 0.15f, ResilienceFromRating = StatConversion.GetCritReductionFromResilience(1); float Resilience = StatConversion.GetCritReductionFromResilience(BasicStats.Resilience); dictValues.Add("Resilience", string.Format("{0}*-{1}% Damage from DoT and Mana Drains\n\r-{1}% Chance to be crit\r\n-{2}% Damage from Crits.\r\n{3}", BasicStats.Resilience.ToString(), (Resilience * 100f).ToString("0.00"), (Resilience * 100f * 2.2f).ToString("0.00"), (Resilience > ResilienceCap)?(string.Format("{0} rating above cap", ((float)Math.Floor((Resilience - ResilienceCap) / ResilienceFromRating)).ToString("0"))):(string.Format("{0} rating below cap", ((float)Math.Ceiling((ResilienceCap - Resilience) / ResilienceFromRating)).ToString("0"))))); dictValues.Add("Mana", BasicStats.Mana.ToString()); dictValues.Add("Intellect", BasicStats.Intellect.ToString()); dictValues.Add("Spirit", Math.Floor(BasicStats.Spirit).ToString("0")); dictValues.Add("Spell Power", string.Format("{0}*{1} from Inner Fire", Math.Floor(BasicStats.SpellPower).ToString("0"), BasicStats.PriestInnerFire * CalculationsHealPriest.GetInnerFireSpellPowerBonus(character))); //dictValues.Add("Healing", Math.Floor(BasicStats.SpellPower * 1.88f).ToString("0")); dictValues.Add("In FSR MP5", string.Format("{0}*{1} from MP5\r\n{2} from Meditation\r\n{3} Outside FSR\r\n{4} OFSR w/MP5", (BasicStats.Mp5 + RegenInFSR).ToString("0"), BasicStats.Mp5.ToString("0"), RegenInFSR.ToString("0"), RegenOutFSR.ToString("0"), (BasicStats.Mp5 + RegenOutFSR).ToString("0"))); dictValues.Add("Spell Crit", string.Format("{0}%*{1}% from Intellect\r\n{2}% from {6} Crit rating\r\n{3}% from Focused Will\r\n{4}% Class Base\r\n{5}% from Buffs", (BasicStats.SpellCrit * 100f).ToString("0.00"), (StatConversion.GetSpellCritFromIntellect(BasicStats.Intellect) * 100f).ToString("0.00"), (StatConversion.GetSpellCritFromRating(BasicStats.CritRating) * 100f).ToString("0.00"), character.PriestTalents.FocusedWill.ToString("0"), (baseStats.SpellCrit * 100f).ToString("0.00"), (BasicStats.SpellCrit * 100f - baseStats.SpellCrit * 100f - StatConversion.GetSpellCritFromRating(BasicStats.CritRating) * 100f - StatConversion.GetSpellCritFromIntellect(BasicStats.Intellect) * 100f - character.PriestTalents.FocusedWill * 1f).ToString("0.00"), BasicStats.CritRating)); dictValues.Add("Healing Crit", string.Format("{0}%*{1} ({1}%) points in Holy Specialization\r\n{2} ({3}%) points in Renewed Hope", ((BasicStats.SpellCrit * 100f) + character.PriestTalents.HolySpecialization * 1f + character.PriestTalents.RenewedHope * 2f).ToString("0.00"), character.PriestTalents.HolySpecialization, character.PriestTalents.RenewedHope, character.PriestTalents.RenewedHope * 2)); dictValues.Add("Spell Haste", string.Format("{0}%*{1}% from {2} Haste rating\r\n{3}% ({6}) points in Enlightenment\r\n{4}% from Buffs\r\n{5}s Global Cooldown", (BasicStats.SpellHaste * 100f).ToString("0.00"), (StatConversion.GetSpellHasteFromRating(BasicStats.HasteRating) * 100f).ToString("0.00"), BasicStats.HasteRating.ToString(), (character.PriestTalents.Enlightenment * 2).ToString("0"), (((1 + BasicStats.SpellHaste) / (1 + StatConversion.GetSpellHasteFromRating(BasicStats.HasteRating)) / (1 + character.PriestTalents.Enlightenment * 0.02f) - 1) * 100f).ToString("0.00"), Math.Max(1.0f, 1.5f / (1 + BasicStats.SpellHaste)).ToString("0.00"), character.PriestTalents.Enlightenment)); dictValues.Add("Armor", string.Format("{0}*{1}% Damage Reduction.", (BasicStats.Armor + BasicStats.BonusArmor).ToString("0"), (StatConversion.GetArmorDamageReduction(80, (BasicStats.Armor + BasicStats.BonusArmor), 0f, 0f, 0f) * 100f).ToString("0.00"))); float[] Resistances = { 0, BasicStats.ArcaneResistance + BasicStats.ArcaneResistanceBuff, BasicStats.FireResistance + BasicStats.FireResistanceBuff, BasicStats.FrostResistance + BasicStats.FrostResistanceBuff, BasicStats.NatureResistance + BasicStats.NatureResistanceBuff, BasicStats.ShadowResistance + BasicStats.ShadowResistanceBuff, }; string[] ResistanceNames = { "None", "Arcane", "Fire", "Frost", "Nature", "Shadow", }; string ResistanceString = "*Resistances:"; float MaxResist = Resistances[0]; int MaxResistIndex = 0; float AvgResist = 0f; for (int x = 1; x < Resistances.Length; x++) { AvgResist += Resistances[x]; if (Resistances[x] > MaxResist) { MaxResist = Resistances[x]; MaxResistIndex = x; } ResistanceString += string.Format("\r\n{0} : {1}", ResistanceNames[x], Resistances[x]); } AvgResist /= (Resistances.Length - 1); if (AvgResist == 0) { ResistanceString = "None" + ResistanceString; } else { string ResistanceName = (MaxResist == AvgResist) ? "All" : ResistanceNames[MaxResistIndex]; ResistanceString = string.Format("{0} : {1}", ResistanceName, MaxResist.ToString("0")) + ResistanceString; ResistanceString += string.Format("\r\n\r\nResist ({0}):", ResistanceName); ResistanceString += string.Format("\r\n{0}", StatConversion.GetResistanceTableString(character.Level + 3, character.Level, MaxResist, 0)); } dictValues.Add("Resistance", ResistanceString); BaseSolver solver; if ((character.CalculationOptions as CalculationOptionsHealPriest).Role == eRole.CUSTOM) { solver = new AdvancedSolver(BasicStats, character); } else { solver = new Solver(BasicStats, character); } solver.Calculate(this); dictValues.Add("Role", string.Format("{0}*{1}", solver.Role, solver.ActionList)); dictValues.Add("Burst", string.Format("{0}", HPSBurstPoints.ToString("0"))); dictValues.Add("Sustained", string.Format("{0}", HPSSustainPoints.ToString("0"))); dictValues.Add("Renew", new Renew(BasicStats, character).ToString()); dictValues.Add("Flash Heal", new FlashHeal(BasicStats, character).ToString()); dictValues.Add("Greater Heal", new Heal(BasicStats, character).ToString()); dictValues.Add("PoH", new PrayerOfHealing(BasicStats, character).ToString()); dictValues.Add("Binding Heal", new BindingHeal(BasicStats, character).ToString()); dictValues.Add("Prayer of Mending", new PrayerOfMending(BasicStats, character).ToString()); dictValues.Add("Power Word Shield", new PowerWordShield(BasicStats, character).ToString()); dictValues.Add("Holy Nova", new HolyNova(BasicStats, character).ToString()); if (character.PriestTalents.CircleOfHealing > 0) { dictValues.Add("CoH", new CircleOfHealing(BasicStats, character).ToString()); } else { dictValues.Add("CoH", "- *No required talents"); } if (character.PriestTalents.Lightwell > 0) { dictValues.Add("Lightwell", new Lightwell(BasicStats, character).ToString()); } else { dictValues.Add("Lightwell", "- *No required talents"); } if (character.PriestTalents.Penance > 0) { dictValues.Add("Penance", new Penance(BasicStats, character).ToString()); } else { dictValues.Add("Penance", "- *No required talents"); } if (Race == CharacterRace.Draenei) { dictValues.Add("Gift of the Naaru", new GiftOfTheNaaru(BasicStats, character).ToString()); } else { dictValues.Add("Gift of the Naaru", "-"); } dictValues.Add("Divine Hymn", new DivineHymn(BasicStats, character).ToString()); dictValues.Add("Resurrection", new Resurrection(BasicStats, character).ToString()); return(dictValues); }
public override Dictionary <string, string> GetCharacterDisplayCalculationValues() { Dictionary <string, string> dictValues = new Dictionary <string, string>(); Buff activeBuff; string s; Stats baseStats = BaseStats.GetBaseStats(Character); #region General dictValues["Health"] = BasicStats.Health.ToString("0"); dictValues["Mana"] = BasicStats.Mana.ToString("0"); dictValues["Item Level"] = String.Format("{0}*Lowest: {1}\nHighest: {2}", Character.AvgWornItemLevel.ToString("0"), Character.MinWornItemLevel.ToString("0"), Character.MaxWornItemLevel.ToString("0")); dictValues["Speed"] = String.Format("{0}%*{0}% Run speed", ((1f + BasicStats.MovementSpeed) * 100f).ToString("0")); #endregion #region Attributes dictValues["Strength"] = BasicStats.Strength.ToString(); dictValues["Agility"] = BasicStats.Agility.ToString(); dictValues["Stamina"] = BasicStats.Stamina.ToString(); dictValues["Intellect"] = BasicStats.Intellect.ToString(); dictValues["Spirit"] = BasicStats.Spirit.ToString(); #endregion #region Spell #region Spell Power s = String.Empty; float intPower = BasicStats.Intellect - 10; if (BasicStats.InnerFire) { s += String.Format("\n{0} from Inner Fire", PriestInformation.GetInnerFireSpellPowerBonus(Character)); } activeBuff = GetActiveBuffsByGroup("Spell Power"); if (activeBuff != null) { s += makeActiveBuffTextPercent(activeBuff, activeBuff.Stats.BonusSpellPowerMultiplier); } dictValues["Spell Power"] = String.Format("{0}*{1} from {2} Intellect{3}", BasicStats.SpellPower.ToString("0"), intPower.ToString("0"), BasicStats.Intellect.ToString("0"), s ); #endregion #region Haste s = String.Empty; if (Character.PriestTalents.Darkness > 0) { s += String.Format("\n{0}% from {1} points in Darkness", Character.PriestTalents.Darkness, Character.PriestTalents.Darkness); } activeBuff = GetActiveBuffsByGroup("Spell Haste"); if (activeBuff != null) { s += makeActiveBuffTextPercent(activeBuff, activeBuff.Stats.SpellHaste); } activeBuff = GetActiveBuffsByGroup("Dark Intent"); if (activeBuff != null) { s += makeActiveBuffTextPercent(activeBuff, activeBuff.Stats.SpellHaste); } dictValues["Haste"] = String.Format("{0}%*{1}% from {2} Haste Rating{3}", (BasicStats.SpellHaste * 100f).ToString("0.00"), (StatConversion.GetSpellHasteFromRating(BasicStats.HasteRating) * 100f).ToString("0.00"), BasicStats.HasteRating.ToString("0"), s ); #endregion dictValues["Hit"] = (BasicStats.SpellHit * 100f).ToString("0.00"); dictValues["Penetration"] = BasicStats.SpellPenetration.ToString("0"); #region Mana Regen float manaRegen = StatConversion.GetSpiritRegenSec(BasicStats.Spirit, BasicStats.Intellect) * 5f; s = String.Format("\n{0} Mana per 5 sec from Base Mana Regeneration", (baseStats.Mana * 0.05f).ToString("0")); activeBuff = GetActiveBuffsByGroup("Mana Regeneration"); if (activeBuff != null) { s += makeActiveBuffText(activeBuff, activeBuff.Stats.Mp5); } dictValues["Mana Regen"] = String.Format("{0}*{1} from Spirit based regen{2}", (manaRegen + BasicStats.Mp5).ToString("0"), manaRegen.ToString("0"), s ); dictValues["Combat Regen"] = String.Format("{0}*{1} from Spirit based regen{2}", (manaRegen * BasicStats.SpellCombatManaRegeneration + BasicStats.Mp5).ToString("0"), (manaRegen * BasicStats.SpellCombatManaRegeneration).ToString("0"), s ); #endregion #region Crit s = String.Empty; activeBuff = GetActiveBuffsByGroup("Critical Strike Chance"); if (activeBuff != null) { s += makeActiveBuffTextPercent(activeBuff, activeBuff.Stats.SpellCrit); } activeBuff = GetActiveBuffsByGroup("Focus Magic, Spell Critical Strike Chance"); if (activeBuff != null) { s += makeActiveBuffTextPercent(activeBuff, activeBuff.Stats.SpellCrit); } dictValues["Crit Chance"] = String.Format("{0}%*{1}% from {2} Crit Rating\n{3}% from {4} Intellect\n{5}% from Priest base{6}", (BasicStats.SpellCrit * 100f).ToString("0.00"), (StatConversion.GetSpellCritFromRating(BasicStats.CritRating) * 100f).ToString("0.00"), BasicStats.CritRating.ToString("0"), (StatConversion.GetSpellCritFromIntellect(BasicStats.Intellect) * 100f).ToString("0.00"), BasicStats.Intellect.ToString("0"), (baseStats.SpellCrit * 100f).ToString("0.00"), s ); #endregion #region Mastery s = string.Empty; float masteryBase = 0, masteryBonus = 0; if (BasicStats.PriestSpec == ePriestSpec.Spec_Disc) { masteryBase = PriestInformation.DisciplineMasteryBase; masteryBonus = PriestInformation.DisciplineMasteryEffect * 100f; s += String.Format("\n\nEach point of mastery increases the potency of Absorbs by an additional {0}%.", masteryBonus.ToString("0.00")); } else if (BasicStats.PriestSpec == ePriestSpec.Spec_Holy) { masteryBase = PriestInformation.HolyMasteryBase; masteryBonus = PriestInformation.HolyMasteryEffect * 100f; s += String.Format("\n\nEach point of mastery provides an additional {0}% healing over 6 sec.", masteryBonus.ToString("0.00")); } dictValues["Mastery"] = String.Format("{0}%*{1}% from {2} Mastery Rating\n{3}% from {4} Base Mastery{5}", ((StatConversion.GetMasteryFromRating(BasicStats.MasteryRating) + masteryBase) * masteryBonus).ToString("0.00"), (StatConversion.GetMasteryFromRating(BasicStats.MasteryRating) * masteryBonus).ToString("0.00"), BasicStats.MasteryRating.ToString("0"), (masteryBase * masteryBonus).ToString("0.00"), masteryBase.ToString("0"), s ); #endregion #endregion #region Defense dictValues["Armor"] = String.Format("{0}*{1}% physical damage reduction from same level target", BasicStats.Armor.ToString("0"), (StatConversion.GetDamageReductionFromArmor(Character.Level, BasicStats.Armor) * 100f).ToString("0.00")); dictValues["Dodge"] = String.Format("{0}%", (BasicStats.Dodge * 100f).ToString("0.00")); dictValues["Resilience"] = String.Format("{0}*{1}% damage reduction on attacks from other players\n{2}% damage reduction from spells", BasicStats.Resilience.ToString("0"), (StatConversion.GetDamageReductionFromResilience(BasicStats.Resilience) * 100f).ToString("0.00"), (Character.PriestTalents.InnerSanctum * 2f).ToString("0")); #endregion #region Resistance string resistTxt = "{0}*PvP\n{1}\n\nBoss\n{2}"; string[] resistList = { "Arcane", "Fire", "Frost", "Nature", "Shadow" }; float[] resistances = { BasicStats.ArcaneResistance + BasicStats.ArcaneResistanceBuff, BasicStats.FireResistance + BasicStats.FireResistanceBuff, BasicStats.FrostResistance + BasicStats.FrostResistanceBuff, BasicStats.NatureResistance + BasicStats.NatureResistanceBuff, BasicStats.ShadowResistance + BasicStats.ShadowResistanceBuff }; for (int x = 0; x < resistList.Length; x++) { dictValues[resistList[x]] = String.Format(resistTxt, resistances[x].ToString("0"), StatConversion.GetResistanceTableString(Character.Level, Character.Level, resistances[x], 0f), StatConversion.GetResistanceTableString(Character.Level + 3, Character.Level, resistances[x], 0f) ); } #endregion #region Model CalculationOptionsHealPriest calcOpts = Character.CalculationOptions as CalculationOptionsHealPriest; if (calcOpts != null) { PriestSolver solver = PriestModels.GetModel(this, calcOpts, true); solver.Solve(); List <string> reqs = solver.MeetsRequirements(); string disp; if (reqs.Count > 0) { disp = String.Format("{0}\n\n{1}", solver.Name, String.Join("\n", reqs)); } else { disp = solver.Name; } dictValues["Role"] = disp; dictValues["Burst Goal"] = this.BurstGoal.ToString("0"); dictValues["Sust. Goal"] = this.SustainGoal.ToString("0"); dictValues["Mana Goal"] = this.ManaGoal.ToString("0"); dictValues["Burst"] = this.BurstPoints.ToString("0"); dictValues["Sustained"] = this.SustainPoints.ToString("0"); dictValues["Mana "] = this.ManaPoints.ToString("0"); } #endregion #region Holy Spells SpellHeal spellHeal = new SpellHeal(Character, BasicStats); dictValues["Heal"] = String.Format("{0}*{1}", spellHeal.HPS().ToString("0"), spellHeal.ToString()); SpellGreaterHeal spellGreaterHeal = new SpellGreaterHeal(Character, BasicStats); dictValues["Greater Heal"] = String.Format("{0}*{1}", spellGreaterHeal.HPS().ToString("0"), spellGreaterHeal.ToString()); SpellFlashHeal spellFlashHeal = new SpellFlashHeal(Character, BasicStats); dictValues["Flash Heal"] = String.Format("{0}*{1}", spellFlashHeal.HPS().ToString("0"), spellFlashHeal.ToString()); SpellBindingHeal spellBindingHeal = new SpellBindingHeal(Character, BasicStats); dictValues["Binding Heal"] = String.Format("{0}*{1}", spellBindingHeal.HPS().ToString("0"), spellBindingHeal.ToString()); SpellRenew spellRenew = new SpellRenew(Character, BasicStats); dictValues["Renew"] = String.Format("{0}*{1}", spellRenew.HPS().ToString("0"), spellRenew.ToString()); if (Character.PriestTalents.Lightwell > 0) { SpellLightwell spellLW = new SpellLightwell(Character, BasicStats); dictValues["Lightwell"] = String.Format("{0}*{1}", spellLW.HPS().ToString("0"), spellLW.ToString()); } else { dictValues["Lightwell"] = "N/A*You do not have the talent required."; } SpellPrayerOfHealing spellProH = new SpellPrayerOfHealing(Character, BasicStats); dictValues["ProH"] = String.Format("{0}*{1}", spellProH.HPS().ToString("0"), spellProH.ToString()); SpellHolyNova spellHolyNova = new SpellHolyNova(Character, BasicStats); dictValues["Holy Nova"] = String.Format("NYI*{1}", spellHolyNova.HPS().ToString("0"), spellHolyNova.ToString()); if (Character.PriestTalents.CircleOfHealing > 0) { SpellCircleOfHealing spellCoH = new SpellCircleOfHealing(Character, BasicStats); dictValues["CoH"] = String.Format("{0}*{1}", spellCoH.HPS().ToString("0"), spellCoH.ToString()); } else { dictValues["CoH"] = "N/A*You do not have the talent required."; } if (BasicStats.PriestSpec == ePriestSpec.Spec_Disc) { SpellPenance spellPenance = new SpellPenance(Character, BasicStats); dictValues["Penance"] = String.Format("{0}*{1}", spellPenance.HPS().ToString("0"), spellPenance.ToString()); } else { dictValues["Penance"] = "N/A*You do not have the correct Talent specialization."; } if (Character.PriestTalents.Revelations > 0) { SpellSerenity spellSerenity = new SpellSerenity(Character, BasicStats); dictValues["HW Serenity"] = String.Format("{0}*{1}", spellSerenity.HPS().ToString("0"), spellSerenity.ToString()); SpellSanctuary spellSanctuary = new SpellSanctuary(Character, BasicStats); dictValues["HW Sanctuary"] = String.Format("{0}*{1}", spellSanctuary.HPS().ToString("0"), spellSanctuary.ToString()); } else { dictValues["HW Serenity"] = "N/A*You do not have the talent required."; dictValues["HW Sanctuary"] = "N/A*You do not have the talent required."; } SpellPrayerOfMending spellProM = new SpellPrayerOfMending(Character, BasicStats, 1); dictValues["ProM"] = String.Format("{0}*{1}", spellProM.HPS().ToString("0"), spellProM.ToString()); spellProM = new SpellPrayerOfMending(Character, BasicStats); dictValues["ProM 5 Hits"] = String.Format("{0}*{1}", spellProM.HPS().ToString("0"), spellProM.ToString()); SpellPowerWordShield spellPWS = new SpellPowerWordShield(Character, BasicStats); dictValues["PWS"] = String.Format("{0}*{1}", spellPWS.HPS().ToString("0"), spellPWS.ToString()); SpellDivineHymn spellDivineHymn = new SpellDivineHymn(Character, BasicStats); dictValues["Divine Hymn"] = String.Format("{0}*{1}", spellDivineHymn.HPS().ToString("0"), spellDivineHymn.ToString()); if (Character.Race == CharacterRace.Draenei) { SpellGiftOfTheNaaru spellGoat = new SpellGiftOfTheNaaru(Character, BasicStats); dictValues["Gift of the Naaru"] = String.Format("{0}*{1}", spellGoat.HPS().ToString("0"), spellGoat.ToString()); } else { dictValues["Gift of the Naaru"] = "N/A*You are not a spacegoat!"; } SpellResurrection spellResurrection = new SpellResurrection(Character, BasicStats); dictValues["Resurrection"] = String.Format("{0}*{1}", spellResurrection.CastTime.ToString("0.00"), spellResurrection.ToString()); #endregion #region Shadow Spells #endregion return(dictValues); }
public void UpdateCalcs(bool firstPass) { // talents if (_calcOpts.PriorityInUse(EnhanceAbility.StormStrike)) { stormstrikeBonusCrit = .25f * _talents.Stormstrike + (_talents.GlyphofStormstrike ? .1f : 0f); } else { stormstrikeBonusCrit = 0f; } //set bonus enhance4T11 = 0f; _character.SetBonusCount.TryGetValue("Battlegear of the Raging Elements", out setCount); if (setCount >= 4) { enhance4T11 = 0.1f; } critMultiplierSpell = 1.5f * (1 + _stats.BonusSpellCritDamageMultiplier); critMultiplierMelee = 2f * (1 + _stats.BonusCritDamageMultiplier); // Melee float hitBonus = _stats.PhysicalHit + StatConversion.GetHitFromRating(_stats.HitRating) + 0.06f; //DualWieldSpecialization expertiseBonusMH = GetDPRfromExp(_stats.Expertise + StatConversion.GetExpertiseFromRating(_stats.ExpertiseRating) + BaseStats.GetRacialExpertise(_character, ItemSlot.MainHand)); expertiseBonusOH = GetDPRfromExp(_stats.Expertise + StatConversion.GetExpertiseFromRating(_stats.ExpertiseRating) + BaseStats.GetRacialExpertise(_character, ItemSlot.OffHand)); float meleeCritModifier = _stats.PhysicalCrit; float baseMeleeCrit = StatConversion.GetCritFromRating(_stats.CritRating) + StatConversion.GetCritFromAgility(_stats.Agility, _character.Class) + .01f * _talents.Acuity; chanceDodgeMH = Math.Max(0f, DodgeChanceCap - expertiseBonusMH); chanceDodgeOH = Math.Max(0f, DodgeChanceCap - expertiseBonusOH); float ParryChance = ParryChanceCap - expertiseBonusMH; //chanceParryMH = (float)Math.Max(0f, _bossOpts.InBack ? ParryChance * PecentageInfrontBoss : ParryChance); ParryChance = ParryChanceCap - expertiseBonusOH; //chanceParryOH = (float)Math.Max(0f, _bossOpts.InBack ? ParryChance * PecentageInfrontBoss : ParryChance); chanceWhiteMissMH = Math.Max(0f, WhiteHitCap - hitBonus) + chanceDodgeMH + chanceParryMH; chanceWhiteMissOH = Math.Max(0f, WhiteHitCap - hitBonus) + chanceDodgeOH + chanceParryOH; chanceYellowMissMH = Math.Max(0f, YellowHitCap - hitBonus) + chanceDodgeMH + chanceParryMH; // base miss 8% now chanceYellowMissOH = Math.Max(0f, YellowHitCap - hitBonus) + chanceDodgeOH + chanceParryOH; // base miss 8% now // SetCritValues((1 + _stats.BonusCritChance) * (baseMeleeCrit + meleeCritModifier) + .00005f); //fudge factor for rounding SetCritValues(baseMeleeCrit + meleeCritModifier + .00005f); //fudge factor for rounding // set two export values so that ED crit isn't included exportMeleeCritMH = chanceWhiteCritMH + whiteCritDepression; exportMeleeCritOH = chanceWhiteCritOH + whiteCritDepression; // Spells ftBonusCrit = 0f; if (_calcOpts.MainhandImbue == "Flametongue") { ftBonusCrit += _talents.GlyphofFlametongueWeapon ? .02f : 0f; } if (_calcOpts.OffhandImbue == "Flametongue") { ftBonusCrit += _talents.GlyphofFlametongueWeapon ? .02f : 0f; } if (baseStats == null) { baseStats = BaseStats.GetBaseStats(_character); } elemPrecMod = _talents.ElementalPrecision > 0 ? (_stats.Spirit - baseStats.Spirit) * (_talents.ElementalPrecision / 3f) : 0f; float hitBonusSpell = _stats.SpellHit + StatConversion.GetSpellHitFromRating(_stats.HitRating + elemPrecMod); chanceSpellMiss = Math.Max(0f, SpellMissRate - hitBonusSpell); overSpellHitCap = Math.Max(0f, hitBonusSpell - SpellMissRate); float spellCritModifier = _stats.SpellCrit + _stats.SpellCritOnTarget + ftBonusCrit; float baseSpellCrit = StatConversion.GetSpellCritFromRating(_stats.CritRating) + StatConversion.GetSpellCritFromIntellect(_stats.Intellect) + .01f * _talents.Acuity; //chanceSpellCrit = Math.Min(0.75f, (1 + _stats.BonusCritChance) * (baseSpellCrit + spellCritModifier) + .00005f); //fudge factor for rounding chanceSpellCrit = Math.Min(0.75f, baseSpellCrit + spellCritModifier + .00005f); //fudge factor for rounding float hasteBonus = StatConversion.GetHasteFromRating(_stats.HasteRating, _character.Class); unhastedMHSpeed = _character.MainHand == null ? 3.0f : _character.MainHand.Item.Speed; unhastedOHSpeed = _character.OffHand == null ? 3.0f : _character.OffHand.Item.Speed; float baseHastedMHSpeed = unhastedMHSpeed / (1f + hasteBonus) / (1f + _stats.PhysicalHaste); float baseHastedOHSpeed = unhastedOHSpeed / (1f + hasteBonus) / (1f + _stats.PhysicalHaste); float chanceToProcWFPerHit = .2f + (_character.ShamanTalents.GlyphofWindfuryWeapon ? .02f : 0f); if (_bossOpts.MultiTargs && _bossOpts.Targets != null && _bossOpts.Targets.Count > 0) { foreach (TargetGroup tg in _bossOpts.Targets) { if (tg.Frequency <= 0 || tg.Chance <= 0) { continue; //bad one, skip it } float upTime = (tg.Frequency / fightLength * (tg.Duration / 1000f) * tg.Chance) / fightLength; multiTargetMultiplier += (Math.Max(10, tg.NumTargs - (tg.NearBoss ? 0 : 1))) * upTime; } } //The Swing Loop //This is where we figure out feedback systems -- WF, MW, ED, Flurry, etc. //-------------- flurryUptime = 1f; uWUptime = 0f; //uFUptime = 0f; edUptime = 0f; float stormstrikeSpeed = firstPass ? (_talents.Stormstrike == 1 ? 8f : 0f) : AbilityCooldown(EnhanceAbility.StormStrike); float shockSpeed = firstPass ? BaseShockSpeed : AbilityCooldown(EnhanceAbility.EarthShock); float lavaLashSpeed = firstPass ? 10f : AbilityCooldown(EnhanceAbility.LavaLash); float fireNovaSpeed = firstPass ? BaseFireNovaSpeed : AbilityCooldown(EnhanceAbility.FireNova); if (_calcOpts.PriorityInUse(EnhanceAbility.MagmaTotem)) { fireTotemUptime = firstPass ? 1.0f : 60f / AbilityCooldown(EnhanceAbility.MagmaTotem); } else if (_calcOpts.PriorityInUse(EnhanceAbility.SearingTotem)) { fireTotemUptime = firstPass ? 1.0f : 60f / AbilityCooldown(EnhanceAbility.SearingTotem); } else if (_calcOpts.PriorityInUse(EnhanceAbility.RefreshTotems)) // if no Searing or Magma totem use refresh of Flametongue totem. { fireTotemUptime = firstPass ? 1.0f : 300f / AbilityCooldown(EnhanceAbility.RefreshTotems); } float mwPPM = (10f / 3f) * _talents.MaelstromWeapon; float flurryHasteBonus = .10f * _talents.Flurry; float uWHasteBonus = .4f + .1f * _talents.ElementalWeapons; float edCritBonus = .03f * _talents.ElementalDevastation; float staticShockChance = .15f * _character.ShamanTalents.StaticShock; hitsPerSMHSS = 0f; hitsPerSOHSS = 0f; hitsPerSOH = 0f; hitsPerSMH = 0f; hitsPerSWF = 0f; if (_talents.Stormstrike == 1) { hitsPerSMHSS = (1f - chanceYellowMissMH) / stormstrikeSpeed; hitsPerSOHSS = (1f - 2 * chanceYellowMissOH) / stormstrikeSpeed; //OH only swings if MH connect } hitsPerSLL = lavaLashSpeed == 0 ? 0f : (1f - chanceYellowMissOH) / lavaLashSpeed; float swingsPerSMHMelee = 0f; float swingsPerSOHMelee = 0f; float wfProcsPerSecond = 0f; float mwProcsPerSecond = 0f; secondsToFiveStack = 10f; float averageMeleeCritChance = (chanceWhiteCritMH + chanceWhiteCritOH + chanceYellowCritMH + chanceYellowCritOH) / 4f; float averageMeleeHitChance = ((1f - chanceWhiteMissMH - chanceDodgeMH - chanceParryMH) + (1f - chanceWhiteMissOH - chanceDodgeOH - chanceParryOH)) / 2f; float averageMeleeMissChance = (chanceWhiteMissMH + chanceWhiteMissOH) / 2f; float whiteHitsPerSMH = 0f; float whiteHitsPerSOH = 0f; float moteHitsPerS = 0f; float yellowHitsPerSMH = 0f; float yellowHitsPerSOH = 0f; float flameTongueHitsPerSecond = 0f; for (int i = 0; i < 5; i++) { // float bonusHaste = (1f + (flurryUptime * flurryHasteBonus)); float bonusHaste = 1 / (1 - flurryUptime + flurryUptime / (1 + flurryHasteBonus)) / (1 - uWUptime + uWUptime / (1 + uWHasteBonus)); // use time based not proc based flurryUptime hastedMHSpeed = baseHastedMHSpeed / bonusHaste; hastedOHSpeed = baseHastedOHSpeed / bonusHaste; swingsPerSMHMelee = 1f / hastedMHSpeed; swingsPerSOHMelee = (hastedOHSpeed == 0f) ? 0f : 1f / hastedOHSpeed; whiteHitsPerSMH = ChanceWhiteHitMH * swingsPerSMHMelee; whiteHitsPerSOH = ChanceWhiteHitOH * swingsPerSOHMelee; moteHitsPerS = _stats.MoteOfAnger * 2 * AverageWhiteHitChance; // Windfury model if (_calcOpts.MainhandImbue == "Windfury") { float hitsThatProcWFPerS = whiteHitsPerSMH + hitsPerSMHSS; if (unhastedOHSpeed != 0f) { hitsThatProcWFPerS += moteHitsPerS / 2; // half the hits will be OH and thus won't proc WF } else { hitsThatProcWFPerS += moteHitsPerS; // if no offhand then all motes will be MH weapon by definition } float maxExpectedWFPerFight = hitsThatProcWFPerS * chanceToProcWFPerHit * fightLength; float ineligibleSeconds = maxExpectedWFPerFight * (3.25f - hastedMHSpeed); float expectedWFPerFight = hitsThatProcWFPerS * chanceToProcWFPerHit * (fightLength - ineligibleSeconds); wfProcsPerSecond = expectedWFPerFight / fightLength; hitsPerSWF = 3f * wfProcsPerSecond * (1f - chanceYellowMissMH); } yellowHitsPerSMH = hitsPerSWF + hitsPerSMHSS; yellowHitsPerSOH = hitsPerSOHSS + hitsPerSLL; //Due to attack table, a white swing has the same chance to crit as a yellow hit // Old Flurry calc changed 10 Nov 2009 // couldCritSwingsPerSecond = whiteHitsPerSMH + whiteHitsPerSOH + yellowHitsPerSMH + yellowHitsPerSOH; // float swingsThatConsumeFlurryPerSecond = swingsPerSMHMelee + swingsPerSOHMelee; // flurryUptime = 1f - (float)Math.Pow(1 - averageMeleeCritChance, (3 / swingsThatConsumeFlurryPerSecond) * couldCritSwingsPerSecond); // old formulae flurryUptime = CalculateFlurryUptime(averageMeleeCritChance, averageMeleeHitChance, averageMeleeMissChance); //uWUptime = (float)Math.Max(12f / 15f, ??); //FIXME!!!! uWUptime = 7.5f / 15f; //Temp Uptime until above line is fixed // Maelstrom Weapon time to 5 stacks calc if (unhastedOHSpeed != 0f) { hitsPerSMH = whiteHitsPerSMH + yellowHitsPerSMH + moteHitsPerS / 2; hitsPerSOH = whiteHitsPerSOH + yellowHitsPerSOH + moteHitsPerS / 2; mwProcsPerSecond = (mwPPM / (60f / unhastedMHSpeed)) * hitsPerSMH + (mwPPM / (60f / unhastedOHSpeed)) * hitsPerSOH; } else { hitsPerSMH = whiteHitsPerSMH + yellowHitsPerSMH + moteHitsPerS; hitsPerSOH = 0f; mwProcsPerSecond = (mwPPM / (60f / unhastedMHSpeed)) * hitsPerSMH; } secondsToFiveStack = 5f / mwProcsPerSecond; // Elemental Devastation Uptime calc staticShocksPerSecond = (hitsPerSLL + hitsPerSMHSS + hitsPerSOHSS) * staticShockChance; flameTongueHitsPerSecond = (_calcOpts.MainhandImbue == "Flametongue" ? HitsPerSMH : 0f) + ((_calcOpts.OffhandImbue == "Flametongue") ? HitsPerSOH : 0f); spellAttacksPerSec = (1f / secondsToFiveStack + 1f / shockSpeed + 1f / fireNovaSpeed + staticShocksPerSecond) // + flameTongueHitsPerSecond) * (1f - chanceSpellMiss); float couldCritSpellsPerS = spellAttacksPerSec; edUptime = 1f - (float)Math.Pow(1 - chanceSpellCrit, 10 * couldCritSpellsPerS); averageMeleeCritChance = (chanceWhiteCritMH + chanceWhiteCritOH + chanceYellowCritMH + chanceYellowCritOH) / 4f + edUptime * edCritBonus; } float yellowAttacksPerSecond = hitsPerSWF + hitsPerSMHSS; if (unhastedMHSpeed != 0) { yellowAttacksPerSecond += hitsPerSOHSS; } // set output variables edBonusCrit = edUptime * edCritBonus; //SetCritValues((1 + _stats.BonusCritChance) * (baseMeleeCrit + meleeCritModifier) + edBonusCrit + .00005f); //fudge factor for rounding SetCritValues(baseMeleeCrit + meleeCritModifier + edBonusCrit + .00005f); //fudge factor for rounding meleeAttacksPerSec = hitsPerSMH + hitsPerSOH; meleeCritsPerSec = (whiteHitsPerSMH * chanceWhiteCritMH) + (whiteHitsPerSOH * chanceWhiteCritOH) + (yellowHitsPerSMH * chanceYellowCritMH) + (yellowHitsPerSOH * chanceYellowCritOH) + (_stats.MoteOfAnger * 2 * AverageWhiteCritChance); spellCritsPerSec = spellAttacksPerSec * ChanceSpellCrit; spellCastsPerSec = spellAttacksPerSec; spellMissesPerSec = spellAttacksPerSec * chanceSpellMiss; chanceMeleeHit = meleeAttacksPerSec / (swingsPerSMHMelee + swingsPerSOHMelee + 2f * wfProcsPerSecond + .25f + 1f / 6f); maxMana = _stats.Mana; float spellhaste = _stats.SpellHaste + StatConversion.GetSpellHasteFromRating(_stats.HasteRating); averageFSDotTime = _talents.GlyphofFlameShock ? 27f : 18f; averageFSTickTime = 3f / (1f + spellhaste); }
public Stats GetCharacterStats(Character character, Item additionalItem, bool computeAverageStats, CharacterCalculationsHealadin calc) { PaladinTalents talents = character.PaladinTalents; CalculationOptionsHealadin calcOpts = character.CalculationOptions as CalculationOptionsHealadin; if (calcOpts == null) { calcOpts = new CalculationOptionsHealadin(); } #if (RAWR3) BossOptions bossOpts = character.BossOptions; if (bossOpts == null) { bossOpts = new BossOptions(); } #endif #if (RAWR3) float fightLength = bossOpts.BerserkTimer * 60f; #else float fightLength = calcOpts.Length * 60f; #endif Stats statsRace = BaseStats.GetBaseStats(character.Level, CharacterClass.Paladin, character.Race); Stats statsBaseGear = GetItemStats(character, additionalItem); Stats statsBuffs = GetBuffsStats(character, calcOpts); Stats stats = statsBaseGear + statsBuffs + statsRace; ConvertRatings(stats, talents, calcOpts); if (computeAverageStats) { Stats statsAverage = new Stats(); foreach (SpecialEffect effect in stats.SpecialEffects()) { float trigger = 0f; if (calc == null) { trigger = 1.5f / calcOpts.Activity / (1f + stats.SpellHaste); if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit) { trigger *= stats.SpellCrit; } else if (effect.Trigger == Trigger.HolyShockCast) { trigger = 6f / calcOpts.HolyShock; } } else { if (effect.Trigger == Trigger.HealingSpellCast || effect.Trigger == Trigger.HealingSpellHit) { trigger = 1f / Rotation.GetHealingCastsPerSec(calc); } else if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit) { trigger = 1f / Rotation.GetHealingCritsPerSec(calc); } else if (effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit) { trigger = 1f / Rotation.GetSpellCastsPerSec(calc); } else if (effect.Trigger == Trigger.DamageOrHealingDone) { trigger = 1f / Rotation.GetHealingCastsPerSec(calc); } else if (effect.Trigger == Trigger.HolyShockCast) { trigger = 6f / calcOpts.HolyShock; } else if (effect.Trigger == Trigger.Use) { trigger = 0f; foreach (SpecialEffect childEffect in effect.Stats.SpecialEffects()) { float childTrigger = 0f; if (effect.Trigger == Trigger.HealingSpellCast || effect.Trigger == Trigger.HealingSpellHit) { childTrigger = 1f / Rotation.GetHealingCastsPerSec(calc); } else if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit) { childTrigger = 1f / Rotation.GetHealingCritsPerSec(calc); } else if (effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit) { childTrigger = 1f / Rotation.GetSpellCastsPerSec(calc); } statsAverage.Accumulate(childEffect.Stats, effect.GetAverageUptime(0.0f, 1.0f) * childEffect.GetAverageStackSize(childTrigger, 1f, 1.5f, effect.Duration)); } } else if (effect.Trigger == Trigger.HolyLightCast) { trigger = 1f / Rotation.GetHolyLightCastsPerSec(calc); } else { continue; } } statsAverage.Accumulate(effect.GetAverageStats(trigger, 1f, 1.5f, fightLength)); } statsAverage.ManaRestore *= fightLength; statsAverage.Healed *= fightLength; stats = statsBaseGear + statsBuffs + statsRace + statsAverage; ConvertRatings(stats, talents, calcOpts); } return(stats); }
public EnhSim(Character character, CalculationOptionsEnhance calcOpts, BossOptions bossOpts) { _character = character; _calcOpts = calcOpts; _bossOpts = bossOpts; CalculationsEnhance ce = new CalculationsEnhance(); CharacterCalculationsEnhance calcs = ce.GetCharacterCalculations(character, null) as CharacterCalculationsEnhance; Stats stats = calcs.EnhSimStats; CombatStats cs = new CombatStats(character, stats, _calcOpts, bossOpts); getSpecialsNames(character, stats); StringBuilder sb = new StringBuilder(); sb.AppendLine(); sb.AppendLine("##########################################"); sb.AppendLine("### Rawr.Enhance Data Export to EnhSim ###"); sb.AppendLine("##########################################"); sb.AppendLine(); sb.AppendLine("config_source rawr"); sb.AppendLine(); float MHSpeed = character.MainHand == null ? 3.0f : character.MainHand.Item.Speed; float wdpsMH = character.MainHand == null ? 46.3f : character.MainHand.Item.DPS; float OHSpeed = character.OffHand == null ? 3.0f : character.OffHand.Item.Speed; float wdpsOH = character.OffHand == null ? 46.3f : character.OffHand.Item.DPS; sb.AppendLine("race " + character.Race.ToString().ToLower()); sb.AppendLine("mh_speed " + MHSpeed.ToString("F1", CultureInfo.InvariantCulture)); sb.AppendLine("oh_speed " + OHSpeed.ToString("F1", CultureInfo.InvariantCulture)); sb.AppendLine("mh_dps " + wdpsMH.ToString("F1", CultureInfo.InvariantCulture)); sb.AppendLine("oh_dps " + wdpsOH.ToString("F1", CultureInfo.InvariantCulture)); sb.AppendLine("str " + stats.Strength.ToString("F0", CultureInfo.InvariantCulture)); sb.AppendLine("agi " + stats.Agility.ToString("F0", CultureInfo.InvariantCulture)); sb.AppendLine("int " + stats.Intellect.ToString("F0", CultureInfo.InvariantCulture)); sb.AppendLine("spi " + stats.Spirit.ToString("F0", CultureInfo.InvariantCulture)); sb.AppendLine("mastery_rating " + stats.MasteryRating.ToString("F0", CultureInfo.InvariantCulture)); float chanceCrit = cs.ExportMeleeCritMH * 100f; sb.AppendLine("mh_crit " + chanceCrit.ToString("F2", CultureInfo.InvariantCulture)); chanceCrit = cs.ExportMeleeCritOH * 100f; sb.AppendLine("oh_crit " + chanceCrit.ToString("F2", CultureInfo.InvariantCulture)); float hitBonus = StatConversion.GetHitFromRating(stats.HitRating) * 100f + 6f; if (character.Race == CharacterRace.Draenei) { hitBonus += 1f; } sb.AppendLine("mh_hit " + hitBonus.ToString("F2", CultureInfo.InvariantCulture)); sb.AppendLine("oh_hit " + hitBonus.ToString("F2", CultureInfo.InvariantCulture)); sb.AppendLine("mh_expertise_rating " + stats.ExpertiseRating.ToString("F0", CultureInfo.InvariantCulture)); sb.AppendLine("oh_expertise_rating " + stats.ExpertiseRating.ToString("F0", CultureInfo.InvariantCulture)); float unleashedRage = 0f; switch (character.ShamanTalents.UnleashedRage) { case 1: unleashedRage = .05f; break; case 2: unleashedRage = .10f; break; } sb.AppendLine("ap " + (stats.AttackPower * (1f + unleashedRage)).ToString("F0", CultureInfo.InvariantCulture)); float hasteBonus = StatConversion.GetHasteFromRating(stats.HasteRating, CharacterClass.Shaman) * 100f; sb.AppendLine("melee_haste " + hasteBonus.ToString("F2", CultureInfo.InvariantCulture)); float MQUnleashedRageSpellpower = stats.AttackPower * unleashedRage * 0.50f; sb.AppendLine("spellpower " + (stats.SpellPower + MQUnleashedRageSpellpower).ToString("F0", CultureInfo.InvariantCulture)); float chanceSpellCrit = cs.DisplaySpellCrit * 100f; sb.AppendLine("spell_crit " + chanceSpellCrit.ToString("F2", CultureInfo.InvariantCulture)); float elemPrec = character.ShamanTalents.ElementalPrecision > 0 ? (stats.Spirit - BaseStats.GetBaseStats(character).Spirit) * (character.ShamanTalents.ElementalPrecision / 3f) : 0f; hitBonus = StatConversion.GetSpellHitFromRating(stats.HitRating + elemPrec) * 100f; if (character.Race == CharacterRace.Draenei) { hitBonus += 1f; } sb.AppendLine("spell_hit " + hitBonus.ToString("F2", CultureInfo.InvariantCulture)); hasteBonus = StatConversion.GetSpellHasteFromRating(stats.HasteRating) * 100f; sb.AppendLine("spell_haste " + hasteBonus.ToString("F2", CultureInfo.InvariantCulture)); sb.AppendLine("max_mana " + stats.Mana.ToString()); sb.AppendLine("mp5 " + stats.Mp5.ToString()); sb.AppendLine(); sb.AppendLine("mh_imbue " + _calcOpts.MainhandImbue.ToString().ToLower()); sb.AppendLine("oh_imbue " + _calcOpts.OffhandImbue.ToString().ToLower()); sb.AppendLine(); sb.AppendLine("mh_enchant " + _mhEnchant); sb.AppendLine("oh_enchant " + _ohEnchant); String weaponType = "-"; if (character.MainHand != null) { if (character.MainHand.Type == ItemType.OneHandAxe || character.MainHand.Type == ItemType.TwoHandAxe) { weaponType = "axe"; } if (character.MainHand.Type == ItemType.FistWeapon) { weaponType = "fist"; } if (character.MainHand.Type == ItemType.OneHandMace || character.MainHand.Type == ItemType.TwoHandMace) { weaponType = "mace"; } } sb.AppendLine("mh_weapon " + weaponType); weaponType = "-"; if (character.OffHand != null) { if (character.OffHand.Type == ItemType.OneHandAxe) { weaponType = "axe"; } if (character.OffHand.Type == ItemType.FistWeapon) { weaponType = "fist"; } if (character.OffHand.Type == ItemType.OneHandMace) { weaponType = "mace"; } } sb.AppendLine("oh_weapon " + weaponType); sb.AppendLine(); sb.AppendLine("trinket1 " + _trinket1name); sb.AppendLine("trinket2 " + _trinket2name); sb.AppendLine(); sb.AppendLine(getSetBonuses(character)); sb.AppendLine("metagem " + _metagem); sb.AppendLine(); string glovesEnchant = character.HandsTinkering == null ? string.Empty : character.HandsTinkering.Name; if (glovesEnchant == "Synapse Springs") { sb.AppendLine("gloves_enchant synapse_springs"); } else if (glovesEnchant == "Tazik Shocker") { sb.AppendLine("gloves_enchant tazik_shocker"); } else { sb.AppendLine("gloves_enchant -"); } string cloakEnchant = character.BackEnchant == null ? string.Empty : character.BackEnchant.Name; if (cloakEnchant == "Lightweave Embroidery") { sb.AppendLine("cloak_enchant lightweave_embroidery"); } else if (cloakEnchant == "Swordguard Embroidery") { sb.AppendLine("cloak_enchant swordguard_embroidery"); } else { sb.AppendLine("cloak_enchant -"); } string weaponSetProc = "-"; if (character.MainHand != null && character.OffHand != null) { if (character.MainHand.Id == 63537 && character.OffHand.Id == 63538) { weaponSetProc = "agony_and_torment"; } } sb.AppendLine("weapon_set_proc " + weaponSetProc); /*addGlyphs(character, sb); * sb.AppendLine(); * sb.AppendLine("#############"); * sb.AppendLine("## Talents ##"); * sb.AppendLine("#############"); * sb.AppendLine("primary_talent enhancement"); * sb.AppendLine(); * sb.AppendLine("elemental_weapons " + character.ShamanTalents.ElementalWeapons + "/2"); * sb.AppendLine("focused_strikes " + character.ShamanTalents.FocusedStrikes + "/3"); * sb.AppendLine("improved_shields " + character.ShamanTalents.ImprovedShields + "/3"); * sb.AppendLine("elemental_devastation " + character.ShamanTalents.ElementalDevastation + "/3"); * sb.AppendLine("flurry " + character.ShamanTalents.Flurry + "/3"); * sb.AppendLine("static_shock " + character.ShamanTalents.StaticShock + "/3"); * sb.AppendLine("improved_fire_nova " + character.ShamanTalents.ImprovedFireNova + "/2"); * sb.AppendLine("searing_flames " + character.ShamanTalents.SearingFlames + "/3"); * sb.AppendLine("frozen_power " + character.ShamanTalents.FrozenPower + "/2"); * sb.AppendLine("shamanistic_rage " + character.ShamanTalents.ShamanisticRage + "/1"); * sb.AppendLine("unleashed_rage " + character.ShamanTalents.UnleashedRage + "/2"); * sb.AppendLine("maelstrom_weapon " + character.ShamanTalents.MaelstromWeapon + "/3"); * sb.AppendLine("improved_lava_lash " + character.ShamanTalents.ImprovedLavaLash + "/2"); * sb.AppendLine(); * //elemental talents in EnhSim have not been updated, so keep exporting old talent choices where appropriate. * sb.AppendLine("convection " + character.ShamanTalents.Convection + "/2"); * sb.AppendLine("concussion " + character.ShamanTalents.Concussion + "/3"); * sb.AppendLine("call_of_flame " + character.ShamanTalents.CallOfFlame + "/2"); * sb.AppendLine("reverberation " + character.ShamanTalents.Reverberation + "/2"); * sb.AppendLine("elemental_precision " + character.ShamanTalents.ElementalPrecision + "/3"); * sb.AppendLine("elemental_focus " + character.ShamanTalents.ElementalFocus + "/1"); * sb.AppendLine("elemental_oath " + character.ShamanTalents.ElementalOath + "/2"); * sb.AppendLine("lava_flows " + character.ShamanTalents.LavaFlows + "/3"); * sb.AppendLine("storm_earth_and_fire " + "0" + "/3"); * sb.AppendLine("elemental_mastery " + character.ShamanTalents.ElementalMastery + "/1"); * sb.AppendLine("feedback " + character.ShamanTalents.Feedback + "/3"); * sb.AppendLine("lava_surge " + character.ShamanTalents.LavaSurge + "/2"); * sb.AppendLine(); * * addBuffs(character, sb); * // add extras * sb.AppendLine(); * sb.AppendLine("combat_length " + (_bossOpts.BerserkTimer/60f).ToString("F2", CultureInfo.InvariantCulture));*/ _configText = sb.ToString(); }
public override Dictionary <string, string> GetCharacterDisplayCalculationValues() { Dictionary <string, string> dictValues = new Dictionary <string, string>(); CalculationOptionsShadowPriest calcOpts = character.CalculationOptions as CalculationOptionsShadowPriest; BossOptions BossOpts = character.BossOptions; Stats baseStats = BaseStats.GetBaseStats(character.Level, character.Class, character.Race); bool Ptr = calcOpts.PTR; dictValues.Add("Health", BasicStats.Health.ToString()); float ResilienceCap = 0.15f, ResilienceFromRating = StatConversion.GetCritReductionFromResilience(1); float Resilience = StatConversion.GetCritReductionFromResilience(BasicStats.Resilience); dictValues.Add("Resilience", string.Format("{0}*-{1}% Damage from DoT and Mana Drains\n\r-{1}% Chance to be crit\r\n-{2}% Damage from Crits.\r\n{3}", BasicStats.Resilience.ToString(), (Resilience * 100f).ToString("0.00"), (Resilience * 100f * 2.2f).ToString("0.00"), (Resilience > ResilienceCap) ? (string.Format("{0} rating above cap", ((float)Math.Floor((Resilience - ResilienceCap) / ResilienceFromRating)).ToString("0"))) : (string.Format("{0} rating below cap", ((float)Math.Ceiling((ResilienceCap - Resilience) / ResilienceFromRating)).ToString("0"))))); dictValues.Add("Stamina", BasicStats.Stamina.ToString()); dictValues.Add("Mana", BasicStats.Mana.ToString()); dictValues.Add("Intellect", BasicStats.Intellect.ToString()); dictValues.Add("Spirit", Math.Floor(BasicStats.Spirit).ToString("0")); dictValues.Add("Spell Power", String.Format("{0}*{1} Bonus Shadow\r\n{2} Bonus Holy\r\n{3} from Inner Fire", Math.Floor(BasicStats.SpellPower), Math.Floor(BasicStats.SpellPower + BasicStats.SpellShadowDamageRating), Math.Floor(BasicStats.SpellPower /*+ BasicStats.SpellHolyDamageRating*/), BasicStats.PriestInnerFire * CalculationsShadowPriest.GetInnerFireSpellPowerBonus(character))); dictValues.Add("Regen", String.Format("{0}*MP5: {1}\r\nOutFSR: {2}", RegenInFSR.ToString("0"), BasicStats.Mp5.ToString(), RegenOutFSR.ToString("0"))); dictValues.Add("Crit", string.Format("{0}%*{1}% from {2} Spell Crit rating\r\n{3}% from Intellect\r\n{4}% from Focused Will\r\n{5}% from Base Crit\r\n{6}% from Buffs\r\n{7}% on Mind Blast, Mind Flay and Mind Sear.\r\n{8}% on VT, SW:P and DP\r\n{9}% on Smite, Holy Fire and Penance.", (BasicStats.SpellCrit * 100f).ToString("0.00"), (StatConversion.GetSpellCritFromRating(BasicStats.CritRating) * 100f).ToString("0.00"), BasicStats.CritRating.ToString("0"), (StatConversion.GetSpellCritFromIntellect(BasicStats.Intellect) * 100f).ToString("0.00"), character.PriestTalents.FocusedWill, (baseStats.SpellCrit * 100f).ToString("0.00"), (BasicStats.SpellCrit * 100f - StatConversion.GetSpellCritFromRating(BasicStats.CritRating) * 100f - StatConversion.GetSpellCritFromIntellect(BasicStats.Intellect) * 100f - baseStats.SpellCrit * 100f - character.PriestTalents.FocusedWill).ToString("0.00"), (BasicStats.SpellCrit * 100f + character.PriestTalents.MindMelt * 2f).ToString("0.00"), (BasicStats.SpellCrit * 100f + character.PriestTalents.MindMelt * 3f).ToString("0.00"), (BasicStats.SpellCrit * 100f + character.PriestTalents.HolySpecialization * 1f).ToString("0.00"))); #if RAWR3 || SILVERLIGHT float Hit = 100 - (StatConversion.GetSpellMiss(character.Level - BossOpts.Level, false) * 100); #else float Hit = 100 - (StatConversion.GetSpellMiss(-calcOpts.TargetLevel, false) * 100); #endif float BonusHit = BasicStats.SpellHit * 100f; float RacialHit = 0; string RacialText = ""; if (character.Race == CharacterRace.Draenei) { RacialHit = 1; RacialText = "1% from Draenei Racial\r\n"; if (!character.ActiveBuffsContains("Heroic Presence")) { BonusHit += 1; } } float DebuffHit = character.PriestTalents.Misery * 1f; if (character.ActiveBuffsConflictingBuffContains("Spell Hit Chance Taken")) { DebuffHit = 3f; } else { BonusHit += DebuffHit; } float RHitRating = 0.01f / StatConversion.GetSpellHitFromRating(1); float ShadowFocusHit = character.PriestTalents.ShadowFocus * 1f; float HitShadow = Hit + BonusHit + ShadowFocusHit; float HitHoly = Hit + BonusHit; dictValues.Add("Hit", string.Format("{0}%*{1}% from {2} Hit Rating\r\n{3}% from Buffs\r\n{4}% from {5} points in Misery\r\n{6}% from {7} points in Shadow Focus\r\n{8}{9}% Hit with Shadow spells, {10}\r\n{11}% Hit with Holy spells, {12}", BonusHit.ToString("0.00"), (StatConversion.GetSpellHitFromRating(BasicStats.HitRating) * 100f).ToString("0.00"), BasicStats.HitRating, (BonusHit - StatConversion.GetSpellHitFromRating(BasicStats.HitRating) * 100f - RacialHit - DebuffHit).ToString("0.00"), DebuffHit, character.PriestTalents.Misery, ShadowFocusHit, character.PriestTalents.ShadowFocus, RacialText, HitShadow.ToString("0.00"), (HitShadow > 100f) ? string.Format("{0} hit rating above cap", Math.Floor((HitShadow - 100f) * RHitRating)) : string.Format("{0} hit rating below cap", Math.Ceiling((100f - HitShadow) * RHitRating)), HitHoly.ToString("0.00"), (HitHoly > 100f) ? string.Format("{0} hit rating above cap", Math.Floor((HitHoly - 100f) * RHitRating)) : string.Format("{0} hit rating below cap", Math.Ceiling((100f - HitHoly) * RHitRating)))); dictValues.Add("Haste", string.Format("{0}%*{1}% from {2} Haste rating\r\n{3}% ({6}) points in Enlightenment\r\n{4}% from Buffs\r\n{5}s Global Cooldown", (BasicStats.SpellHaste * 100f).ToString("0.00"), (StatConversion.GetSpellHasteFromRating(BasicStats.HasteRating) * 100f).ToString("0.00"), BasicStats.HasteRating.ToString(), (character.PriestTalents.Enlightenment * 2).ToString("0"), (((1f + BasicStats.SpellHaste) / (1f + StatConversion.GetSpellHasteFromRating(BasicStats.HasteRating)) / (1f + character.PriestTalents.Enlightenment * 0.02f) - 1f) * 100f).ToString("0.00"), Math.Max(1.0f, 1.5f / (1 + BasicStats.SpellHaste)).ToString("0.00"), character.PriestTalents.Enlightenment)); dictValues.Add("Armor", string.Format("{0}*{1}% Damage Reduction.", (BasicStats.Armor + BasicStats.BonusArmor).ToString("0"), (StatConversion.GetArmorDamageReduction(80, (BasicStats.Armor + BasicStats.BonusArmor), 0f, 0f, 0f) * 100f).ToString("0.00"))); float[] Resistances = { 0, BasicStats.ArcaneResistance + BasicStats.ArcaneResistanceBuff, BasicStats.FireResistance + BasicStats.FireResistanceBuff, BasicStats.FrostResistance + BasicStats.FrostResistanceBuff, BasicStats.NatureResistance + BasicStats.NatureResistanceBuff, BasicStats.ShadowResistance + BasicStats.ShadowResistanceBuff, }; string[] ResistanceNames = { "None", "Arcane", "Fire", "Frost", "Nature", "Shadow", }; string ResistanceString = "*Resistances:"; float MaxResist = Resistances[0]; int MaxResistIndex = 0; float AvgResist = 0f; for (int x = 1; x < Resistances.Length; x++) { AvgResist += Resistances[x]; if (Resistances[x] > MaxResist) { MaxResist = Resistances[x]; MaxResistIndex = x; } ResistanceString += string.Format("\r\n{0} : {1}", ResistanceNames[x], Resistances[x]); } AvgResist /= (Resistances.Length - 1); if (AvgResist == 0) { ResistanceString = "None" + ResistanceString; } else { string ResistanceName = (MaxResist == AvgResist) ? "All" : ResistanceNames[MaxResistIndex]; ResistanceString = string.Format("{0} : {1}", ResistanceName, MaxResist.ToString("0")) + ResistanceString; ResistanceString += string.Format("\r\n\r\nResist ({0}):", ResistanceName); ResistanceString += string.Format("\r\n{0}", StatConversion.GetResistanceTableString(character.Level + 3, character.Level, MaxResist, 0)); } dictValues.Add("Resistance", ResistanceString); SolverBase solver = GetSolver(character, BasicStats); solver.Calculate(this); dictValues.Add("Rotation", string.Format("{0}*{1}", solver.Name, solver.Rotation)); if (solver.SpellSimulation != null) { String s = "Spell Cast List:"; int i = 0; foreach (Spell spell in solver.SpellSimulation) { if (i++ % 10 == 0) { s += "\r\n"; } s += ", " + spell.Name; } s += "\r\n---Repeat---"; dictValues.Add("Castlist", string.Format("{0}*{1}", solver.SpellSimulation.Count, s)); } else { dictValues.Add("Castlist", "Empty"); } dictValues.Add("DPS", string.Format("{0}*Damage Pr Second", solver.DPS.ToString("0"))); //dictValues.Add("SustainDPS", string.Format("{0}*Mana restrained DPS", solver.SustainDPS.ToString("0"))); float baseMana = BaseStats.GetBaseStats(character).Mana; dictValues.Add("SW Pain", new ShadowWordPain(BasicStats, character, baseMana, Ptr).ToString()); DevouringPlague dp = new DevouringPlague(BasicStats, character, baseMana, Ptr); dictValues.Add("Devouring Plague", dp.ToString()); if (dp.ImprovedDP != null) { dictValues.Add("Imp. Devouring Plague", dp.ImprovedDP.ToString()); } else { dictValues.Add("Imp. Devouring Plague", "- *No required talents"); } dictValues.Add("SW Death", new ShadowWordDeath(BasicStats, character, baseMana, Ptr).ToString()); dictValues.Add("Mind Blast", new MindBlast(BasicStats, character, baseMana, Ptr).ToString()); dictValues.Add("PW Shield", new PowerWordShield(BasicStats, character, baseMana, Ptr).ToString()); if (character.PriestTalents.VampiricTouch > 0) { dictValues.Add("Vampiric Touch", new VampiricTouch(BasicStats, character, baseMana, Ptr).ToString()); } else { dictValues.Add("Vampiric Touch", "- *No required talents"); } if (character.PriestTalents.MindFlay > 0) { dictValues.Add("Mind Flay", new MindFlay(BasicStats, character, baseMana, Ptr).ToString()); } else { dictValues.Add("Mind Flay", "- *No required talents"); } dictValues.Add("Shadowfiend", new Shadowfiend(BasicStats, character, baseMana, Ptr).ToString()); dictValues.Add("Smite", new Smite(BasicStats, character, baseMana, Ptr).ToString()); dictValues.Add("Holy Fire", new HolyFire(BasicStats, character, baseMana, Ptr).ToString()); if (character.PriestTalents.Penance > 0) { dictValues.Add("Penance", new Penance(BasicStats, character, baseMana, Ptr).ToString()); } else { dictValues.Add("Penance", "- *No required talents"); } return(dictValues); }
public static void solve(CharacterCalculationsElemental calculatedStats, CalculationOptionsElemental calcOpts, BossOptions bossOpts) { Stats stats = calculatedStats.BasicStats; Character character = calculatedStats.LocalCharacter; ShamanTalents talents = character.ShamanTalents; /* Effects: * Clearcasting (-40% mana cost next 2 spells) * Glyph of flame shock or not * Clearcasting (5/10% more total damage) * Elemental Mastery (+15% haste chance, 15 sec/3 min cd) * Trinkets * * Assume LvB used on CD and FS either after LvB, on dot drop or before LvB * Filler: LB * NYI Optional: use of CL */ Estimation e; Rotation rot; float damage; Stats procStats; #if RAWR3 || SILVERLIGHT float FightDuration = bossOpts.BerserkTimer; #else float FightDuration = calcOpts.FightDuration; #endif // WITHOUT PROCS e = new Estimation(stats, new Stats { }, talents, calcOpts); rot = e.getPriorityRotation(calcOpts.RotationType); // WITH PROCS int nPasses = 2, k; for (k = 0; k < nPasses; k++) { procStats = DoSpecialEffects(character, stats, rot, FightDuration); //procStats = getTrinketStats(character, stats, calcOpts.FightDuration, rot); e.Update(stats, procStats, talents, calcOpts); rot = e.getPriorityRotation(calcOpts.RotationType); } // Thunderstorm usage float thunderstormRegen = 0f; #region Thunderstorm if (calcOpts.UseThunderstorm) { float procsPerSecond = Thunderstorm.getProcsPerSecond(talents.GlyphofThunder, (int)FightDuration); thunderstormRegen += (talents.GlyphofThunderstorm ? .1f : .08f) * stats.Mana * procsPerSecond * 5; } #endregion /* Regen variables: (divide by 5 for regen per second) * While casting: ManaRegInFSR * During regen: ManaRegOutFSR */ #region Calculate Regen float spiRegen = 5 * StatConversion.GetSpiritRegenSec(stats.Spirit, stats.Intellect); float replenishRegen = 5 * stats.Mana * stats.ManaRestoreFromMaxManaPerSecond; float judgementRegen = 5 * rot.GetBaseCastTime() / rot.Duration * stats.ManaRestoreFromBaseManaPPM / 60f * BaseStats.GetBaseStats(character).Mana; float ManaRegInFSR = spiRegen * stats.SpellCombatManaRegeneration + stats.Mp5 + replenishRegen + judgementRegen + thunderstormRegen; float ManaRegOutFSR = spiRegen + stats.Mp5 + replenishRegen + thunderstormRegen; float ManaRegen = ManaRegInFSR; #endregion // TotalDamage, CastFraction, TimeUntilOOM #region Calculate total damage in the fight float TimeUntilOOM = 0; float effectiveMPS = rot.MPS - ManaRegen / 5f; if (effectiveMPS <= 0) { TimeUntilOOM = FightDuration; } else { TimeUntilOOM = (calculatedStats.BasicStats.Mana) / effectiveMPS; } if (TimeUntilOOM > FightDuration) { TimeUntilOOM = FightDuration; } #region SpecialEffects from procs etc. procStats = DoSpecialEffects(character, stats, rot, FightDuration); //procStats = getTrinketStats(character, stats, calcOpts.FightDuration, rot); //damage procs (Thunder Capacitor etc.) are effected by spellcrit and damage debuffs damage = procStats.ArcaneDamage * (1 + stats.BonusArcaneDamageMultiplier) + procStats.NatureDamage * (1 + stats.BonusNatureDamageMultiplier) + procStats.FireDamage * (1 + stats.BonusFireDamageMultiplier) + procStats.ShadowDamage * (1 + stats.BonusShadowDamageMultiplier); if (damage > 0) { damage *= (1 + stats.SpellCrit * .5f); // but only with the normal 50% dmg bonus rot.DPS += damage; } #endregion float TotalDamage = TimeUntilOOM * rot.DPS; float TimeToRegenFull = 5f * calculatedStats.BasicStats.Mana / ManaRegOutFSR; float TimeToBurnAll = calculatedStats.BasicStats.Mana / effectiveMPS; float CastFraction = 1f; if (ManaRegOutFSR > 0 && FightDuration > TimeUntilOOM) { float timeLeft = FightDuration - TimeUntilOOM; if (TimeToRegenFull + TimeToBurnAll == 0) { CastFraction = 0; } else { CastFraction = TimeToBurnAll / (TimeToRegenFull + TimeToBurnAll); } TotalDamage += timeLeft * rot.DPS * CastFraction; } #endregion float bsRatio = ((float)calcOpts.BSRatio) * 0.01f; calculatedStats.BurstPoints = (1f - bsRatio) * 2f * rot.DPS; calculatedStats.SustainedPoints = bsRatio * 2f * TotalDamage / FightDuration; calculatedStats.OverallPoints = calculatedStats.BurstPoints + calculatedStats.SustainedPoints; calculatedStats.CombatStats = stats.Clone(); calculatedStats.CombatStats.Accumulate(procStats); calculatedStats.ManaRegenInFSR = ManaRegInFSR; calculatedStats.ManaRegenOutFSR = ManaRegOutFSR; calculatedStats.ReplenishMP5 = replenishRegen; calculatedStats.LightningBolt = rot.LB; calculatedStats.ChainLightning = rot.CL; calculatedStats.FlameShock = rot.FS; calculatedStats.LavaBurst = rot.LvB; calculatedStats.EarthShock = rot.ES; calculatedStats.FrostShock = rot.FrS; calculatedStats.FireNova = rot.FN; calculatedStats.SearingTotem = rot.ST; calculatedStats.MagmaTotem = rot.MT; calculatedStats.TimeToOOM = TimeUntilOOM; calculatedStats.CastRegenFraction = CastFraction; calculatedStats.CastsPerSecond = rot.getCastsPerSecond(); calculatedStats.CritsPerSecond = rot.getWeightedCritchance() * rot.getCastsPerSecond(); calculatedStats.MissesPerSecond = rot.getCastsPerSecond() * (1f - rot.getWeightedHitchance()); calculatedStats.LvBPerSecond = rot.getCastsPerSecond(typeof(LavaBurst)); calculatedStats.LBPerSecond = rot.getCastsPerSecond(typeof(LightningBolt)); calculatedStats.FSPerSecond = rot.getCastsPerSecond(typeof(FlameShock)); calculatedStats.LatencyPerSecond = rot.LatencyPerSecond; calculatedStats.RotationDPS = rot.DPS; calculatedStats.RotationMPS = rot.MPS; calculatedStats.TotalDPS = TotalDamage / FightDuration; rot.ClearCasting.TryGetValue(typeof(FlameShock), out calculatedStats.ClearCast_FlameShock); rot.ClearCasting.TryGetValue(typeof(LavaBurst), out calculatedStats.ClearCast_LavaBurst); rot.ClearCasting.TryGetValue(typeof(LightningBolt), out calculatedStats.ClearCast_LightningBolt); calculatedStats.Rotation = rot.ToString(); calculatedStats.RotationDetails = rot.ToDetailedString(); }
private List <Ability> SetupAbilities() { List <Ability> abilities = new List <Ability>(); float convection = 1f - _talents.Convection * 0.02f; float baseMana = BaseStats.GetBaseStats(_character).Mana; float elementalFocus = (_talents.ElementalFocus == 1) ? .6f * _cs.ChanceSpellCrit : 1f; float ESMana = _talents.ShamanisticFocus == 1 ? baseMana * 0.55f * 0.18f : baseMana * 0.18f; // 45% reduction if Shamanistic Focus float FSMana = _talents.ShamanisticFocus == 1 ? baseMana * 0.55f * 0.17f : baseMana * 0.17f; // 45% reduction if Shamanistic Focus float fireElementalCD = _talents.GlyphofFireElementalTotem ? 300f : 600f; float gcd = Math.Max(1.0f, 1.5f / (1f + _stats.SpellHaste + StatConversion.GetSpellHasteFromRating(_stats.HasteRating))); int priority = _calcOpts.GetAbilityPriorityValue(EnhanceAbility.ShamanisticRage); if (priority > 0 && _talents.ShamanisticRage == 1) { abilities.Add(new Ability(EnhanceAbility.ShamanisticRage, 60f, 1.5f, 0f, priority, false, true)); } priority = _calcOpts.GetAbilityPriorityValue(EnhanceAbility.FeralSpirits); if (priority > 0 && _talents.FeralSpirit == 1) { abilities.Add(new Ability(EnhanceAbility.FeralSpirits, 180f, gcd, 0.12f * baseMana, priority, false, false)); } priority = _calcOpts.GetAbilityPriorityValue(EnhanceAbility.LightningBolt); if (priority > 0 && _talents.MaelstromWeapon > 0) { abilities.Add(new Ability(EnhanceAbility.LightningBolt, _cs.SecondsToFiveStack, gcd, 0.1f * baseMana * convection * elementalFocus, priority, false, false)); } priority = _calcOpts.GetAbilityPriorityValue(EnhanceAbility.FlameShock); if (priority > 0) { if (_talents.GlyphofShocking) { abilities.Add(new Ability(EnhanceAbility.FlameShock, _cs.AverageFSDotTime, 1.0f, FSMana * convection * elementalFocus, priority, false, false)); } else { abilities.Add(new Ability(EnhanceAbility.FlameShock, _cs.AverageFSDotTime, gcd, FSMana * convection * elementalFocus, priority, false, false)); } } priority = _calcOpts.GetAbilityPriorityValue(EnhanceAbility.StormStrike); if (priority > 0 && _talents.Stormstrike == 1) { abilities.Add(new Ability(EnhanceAbility.StormStrike, 8f, 1.5f, 0.08f * baseMana, priority, false, true)); } priority = _calcOpts.GetAbilityPriorityValue(EnhanceAbility.EarthShock); if (priority > 0) { if (_talents.GlyphofShocking) { abilities.Add(new Ability(EnhanceAbility.EarthShock, _cs.BaseShockSpeed, 1.0f, ESMana * convection * elementalFocus, priority, false, false)); } else { abilities.Add(new Ability(EnhanceAbility.EarthShock, _cs.BaseShockSpeed, gcd, ESMana * convection * elementalFocus, priority, false, false)); } } priority = _calcOpts.GetAbilityPriorityValue(EnhanceAbility.LavaLash); if (priority > 0 && _talents.LavaLash == 1) { abilities.Add(new Ability(EnhanceAbility.LavaLash, 6f, 1.5f, 0.04f * baseMana, priority, false, false)); } priority = _calcOpts.GetAbilityPriorityValue(EnhanceAbility.FireNova); if (priority > 0) { abilities.Add(new Ability(EnhanceAbility.FireNova, _cs.BaseFireNovaSpeed, gcd, 0.22f * baseMana, priority, false, false)); } priority = _calcOpts.GetAbilityPriorityValue(EnhanceAbility.FireElemental); if (priority > 0 && _calcOpts.FireElemental) { abilities.Add(new Ability(EnhanceAbility.FireElemental, fireElementalCD, 1.0f, 0.23f * baseMana, priority, false, false)); } priority = _calcOpts.GetAbilityPriorityValue(EnhanceAbility.MagmaTotem); if (priority > 0 && _calcOpts.Magma) { abilities.Add(new Ability(EnhanceAbility.MagmaTotem, 20f, 1.0f, 0.27f * baseMana * elementalFocus, priority, false, false)); } priority = _calcOpts.GetAbilityPriorityValue(EnhanceAbility.SearingTotem); if (priority > 0 && !_calcOpts.Magma) { abilities.Add(new Ability(EnhanceAbility.SearingTotem, 60f, 1.0f, 0.07f * baseMana * elementalFocus, priority, false, false)); } priority = _calcOpts.GetAbilityPriorityValue(EnhanceAbility.LightningShield); if (priority > 0 && _talents.StaticShock > 0) { abilities.Add(new Ability(EnhanceAbility.LightningShield, _cs.StaticShockAvDuration, gcd, 0f, priority, true, false)); } priority = _calcOpts.GetAbilityPriorityValue(EnhanceAbility.RefreshTotems); if (priority > 0) { abilities.Add(new Ability(EnhanceAbility.RefreshTotems, 300f, 1.0f, 0.24f * baseMana, _calcOpts.GetAbilityPriorityValue(EnhanceAbility.RefreshTotems), true, false)); // patch 3.2 takes just 1 second GCD to refresh totems. } abilities.Sort(); return(abilities); }
/// <summary>Gets the total Stats of the Character</summary> /// <param name="character"> /// The Character to get the total Stats of /// </param> /// <param name="additionalItem"> /// An additional item to grant the Character the stats of (as if it /// were worn) /// </param> /// <returns>The total stats for the Character</returns> public override Stats GetCharacterStats( Character character, Item additionalItem) { WarlockTalents talents = character.WarlockTalents; CalculationOptionsWarlock options = character.CalculationOptions as CalculationOptionsWarlock; Stats stats = BaseStats.GetBaseStats(character); // Items AccumulateItemStats(stats, character, additionalItem); // Buffs AccumulateBuffsStats(stats, character.ActiveBuffs); if (options.Imbue.Equals("Grand Spellstone")) { stats.HasteRating += 60f * (1f + talents.MasterConjuror * 1.5f); } else { Debug.Assert(options.Imbue.Equals("Grand Firestone")); stats.CritRating += 49f * (1f + talents.MasterConjuror * 1.5f); } ApplyPetsRaidBuff( stats, options.Pet, talents, character.ActiveBuffs); float aegis = 1f + talents.DemonicAegis * 0.10f; stats.SpellPower += 180f * aegis; // fel armor stats.SpellDamageFromSpiritPercentage += .3f * aegis; // fel armor // Talents float[] talentValues = { 0f, .04f, .07f, .1f }; Stats statsTalents = new Stats { //Demonic Embrace: increases your stamina by 4/7/10% BonusStaminaMultiplier = talentValues[talents.DemonicEmbrace], //Fel Vitality: increases your maximum Health & Mana by 1/2/3% BonusHealthMultiplier = talents.FelVitality * 0.01f, BonusManaMultiplier = talents.FelVitality * 0.01f, //Suppression: increases your chance to hit with spells by //1/2/3% SpellHit = (talents.Suppression * 0.01f), //Demonic Tactics: increases your spell crit chance by //2/4/6/8/10% //Backlash: increases your spell crit chance by 1/2/3% BonusCritChance = talents.DemonicTactics * 0.02f + talents.Backlash * 0.01f }; if (talents.Eradication > 0) { talentValues = new float[] { 0f, .06f, .12f, .20f }; statsTalents.AddSpecialEffect( new SpecialEffect( Trigger.CorruptionTick, new Stats() { SpellHaste = talentValues[talents.Eradication] }, 6f, 0f, .06f)); } stats.Accumulate(statsTalents); stats.ManaRestoreFromMaxManaPerSecond = Math.Max( stats.ManaRestoreFromMaxManaPerSecond, .002f * Spell.CalcUprate( talents.ImprovedSoulLeech * .5f, 15f, options.Duration * 1.1f)); return(stats); }
public override Stats GetCharacterStats(Character character, Item additionalItem) { PriestTalents talents = character.PriestTalents; Stats statsTotal = new Stats(); Stats baseStats = BaseStats.GetBaseStats(character.Level, character.Class, character.Race); Stats itemStats = GetItemStats(character, additionalItem); Stats buffStats = GetBuffsStats(character, _calculationOptions); // Get the gear/enchants/buffs stats loaded in statsTotal.Accumulate(baseStats); statsTotal.Accumulate(itemStats); statsTotal.Accumulate(buffStats); Stats statsTalents = new Stats() { // we can only wear items that are cloth so we always have our specialization, even naked. BonusIntellectMultiplier = 0.05f, BonusShadowDamageMultiplier = (1 + 0.02f * talents.TwinDisciplines) * (1 + 0.02f * talents.TwistedFaith) * (1 + 0.15f * talents.Shadowform) - 1, BonusHolyDamageMultiplier = (1 + 0.02f * talents.TwinDisciplines) - 1, // this is the shadow priest model so they must have 'Shadow Power' BonusSpellPowerMultiplier = .15f, }; statsTotal.Accumulate(statsTalents); statsTotal.Stamina = (float)Math.Floor(statsTotal.Stamina * (1 + statsTotal.BonusStaminaMultiplier)); statsTotal.Intellect += (float)Math.Floor(itemStats.Intellect * statsTotal.BonusIntellectMultiplier); statsTotal.Spirit = (float)Math.Round(statsTotal.Spirit * (1 + statsTotal.BonusSpiritMultiplier)); statsTotal.Health += (float)Math.Floor(StatConversion.GetHealthFromStamina(statsTotal.Stamina) * (1f + statsTotal.BonusHealthMultiplier)); statsTotal.Mana = (float)Math.Round(statsTotal.Mana + StatConversion.GetManaFromIntellect(statsTotal.Intellect)); statsTotal.Mana = (float)Math.Round(statsTotal.Mana * (1f + statsTotal.BonusManaMultiplier)); statsTotal.SpellPower += statsTotal.Intellect - 10; float hasteFromRating = StatConversion.GetSpellHasteFromRating(statsTotal.HasteRating); float talentedHaste = (1 + hasteFromRating) * (1 + talents.Darkness * .01f) - 1; statsTotal.SpellHaste += character.Race == CharacterRace.Goblin ? talentedHaste * 1.01f : talentedHaste; float baseBonus = (float)Math.Floor(baseStats.Spirit * statsTotal.BonusSpiritMultiplier); float itemBonus = (float)Math.Floor(itemStats.Spirit * statsTotal.BonusSpiritMultiplier); float spiritFromItemsAndEffects = baseBonus + itemBonus + itemStats.Spirit; float hitRatingFromSpirit = (0.5f * talents.TwistedFaith) * Math.Max(0f, spiritFromItemsAndEffects); statsTotal.HitRating += hitRatingFromSpirit; statsTotal.SpellHit += StatConversion.GetSpellHitFromRating(statsTotal.HitRating); // ignoring the base crit percentage here as the in-game tooltip says that the int -> crit conversion contains the base. float critFromInt = StatConversion.GetSpellCritFromIntellect(statsTotal.Intellect) + 0.012375f; float critFromRating = StatConversion.GetSpellCritFromRating(statsTotal.CritRating); statsTotal.SpellCrit = character.Race == CharacterRace.Worgen ? (critFromInt + critFromRating) + .01f : (critFromInt + critFromRating); // Armor statsTotal.Armor = statsTotal.Armor * (1f + statsTotal.BaseArmorMultiplier); statsTotal.BonusArmor = statsTotal.BonusArmor * (1f + statsTotal.BonusArmorMultiplier); statsTotal.Armor += statsTotal.BonusArmor; statsTotal.Armor = (float)Math.Round(statsTotal.Armor); return(statsTotal); }