private void rdbScryer_CheckedChanged(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.AldorScryer = rdbScryer.Checked ? "Scryer" : "Aldor"; Character.OnItemsChanged(); }
private void cmbTargetLevel_SelectedIndexChanged(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.TargetLevel = int.Parse(cmbTargetLevel.SelectedItem.ToString()); Character.OnItemsChanged(); }
private void txtFightLength_Leave(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.FightLength = float.Parse(txtFightLength.Text); Character.OnItemsChanged(); }
private void txtLatency_TextChanged(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.Latency = float.Parse(txtLatency.Text); Character.OnItemsChanged(); }
private void txtManaPotDelay_Leave(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.ManaPotDelay = float.Parse(txtManaPotDelay.Text); Character.OnItemsChanged(); }
// Non-rotation-specific mana calculations private float GetEffectiveManaPool(Character character, CalculationOptionsMoonkin calcOpts, CharacterCalculationsMoonkin calcs) { float fightLength = calcs.FightLength * 60.0f; float innervateCooldown = 360 - calcs.BasicStats.InnervateCooldownReduction; // Mana/5 calculations float totalManaRegen = calcs.ManaRegen5SR * fightLength; // Mana pot calculations float manaRestoredByPots = 0.0f; foreach (Buff b in character.ActiveBuffs) { if (b.Stats.ManaRestore > 0) { manaRestoredByPots = b.Stats.ManaRestore; break; } } // Innervate calculations float innervateDelay = calcOpts.InnervateDelay * 60.0f; int numInnervates = (calcOpts.Innervate && fightLength - innervateDelay > 0) ? ((int)(fightLength - innervateDelay) / (int)innervateCooldown + 1) : 0; float totalInnervateMana = numInnervates * CalculationsMoonkin.BaseMana * (4.5f + (character.DruidTalents.GlyphOfInnervate ? 0.9f : 0.0f)); // Replenishment calculations float replenishmentPerTick = calcs.BasicStats.Mana * calcs.BasicStats.ManaRestoreFromMaxManaPerSecond; float replenishmentMana = calcOpts.ReplenishmentUptime * replenishmentPerTick * calcs.FightLength * 60; return(calcs.BasicStats.Mana + totalInnervateMana + totalManaRegen + manaRestoredByPots + replenishmentMana); }
private void txtShadowPriest_Leave(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.ShadowPriest = float.Parse(txtShadowPriest.Text); Character.OnItemsChanged(); }
private void cmbPotType_SelectedIndexChanged(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.ManaPotType = cmbPotType.SelectedItem.ToString(); Character.OnItemsChanged(); }
private void chkMetagem_Leave(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; Character.EnforceMetagemRequirements = chkMetagem.Checked; Character.OnItemsChanged(); }
private void txtInnervateWeaponSpi_Leave(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.InnervateWeaponSpi = float.Parse(txtInnervateWeaponSpi.Text); Character.OnItemsChanged(); }
/*private void chkManaPots_CheckedChanged(object sender, EventArgs e) * { * CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; * calcOpts.ManaPots = chkManaPots.Checked; * cmbPotType.Enabled = chkManaPots.Checked; * Character.OnCalculationsInvalidated(); * } * * private void cmbPotType_SelectedIndexChanged(object sender, EventArgs e) * { * CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; * calcOpts.ManaPotType = cmbPotType.SelectedItem.ToString(); * Character.OnCalculationsInvalidated(); * }*/ private void txtInnervateDelay_Leave(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.InnervateDelay = float.Parse(txtInnervateDelay.Text); Character.OnCalculationsInvalidated(); }
private void chkPtrMode_CheckedChanged(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.PTRMode = chkPtrMode.Checked; Character.OnCalculationsInvalidated(); }
private void cmbUserRotation_SelectedIndexChanged(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.UserRotation = cmbUserRotation.SelectedItem.ToString(); Character.OnCalculationsInvalidated(); }
private void trkReplenishmentUptime_ValueChanged(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.ReplenishmentUptime = trkReplenishmentUptime.Value / 100.0f; lblUptimeValue.Text = trkReplenishmentUptime.Value.ToString(); Character.OnCalculationsInvalidated(); }
private void chkInnervate_CheckedChanged(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.Innervate = chkInnervate.Checked; txtInnervateDelay.Enabled = chkInnervate.Checked; Character.OnItemsChanged(); }
private void trkTreantLifespan_ValueChanged(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.TreantLifespan = trkTreantLifespan.Value / 100.0f; lblLifespanValue.Text = trkTreantLifespan.Value.ToString(); Character.OnCalculationsInvalidated(); }
public override ICalculationOptionBase DeserializeDataObject(string xml) { System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(CalculationOptionsMoonkin)); System.IO.StringReader reader = new System.IO.StringReader(xml); CalculationOptionsMoonkin calcOpts = serializer.Deserialize(reader) as CalculationOptionsMoonkin; return(calcOpts); }
private void chkManaPots_CheckedChanged(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.ManaPots = chkManaPots.Checked; cmbPotType.Enabled = chkManaPots.Checked; txtManaPotDelay.Enabled = chkManaPots.Checked; Character.OnItemsChanged(); }
private void chkInnervateWeapon_CheckedChanged(object sender, EventArgs e) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.InnervateWeapon = chkInnervateWeapon.Checked; txtInnervateWeaponInt.Enabled = chkInnervateWeapon.Checked; txtInnervateWeaponSpi.Enabled = chkInnervateWeapon.Checked; Character.OnItemsChanged(); }
public override CharacterCalculationsBase GetCharacterCalculations(Character character, Item additionalItem) { CharacterCalculationsMoonkin calcs = new CharacterCalculationsMoonkin(); Stats stats = GetCharacterStats(character, additionalItem); calcs.BasicStats = stats; float hitRatingMultiplier = 1.0f / CalculationsMoonkin.hitRatingConversionFactor; float critRatingMultiplier = 1.0f / CalculationsMoonkin.critRatingConversionFactor; calcs.SpellCrit = stats.SpellCritRating * critRatingMultiplier; calcs.SpellHit = stats.SpellHitRating * hitRatingMultiplier; CalculationOptionsMoonkin calcOpts = character.CalculationOptions as CalculationOptionsMoonkin; // All spells: Damage +((0.08/0.16/0.25) * Int) switch (calcOpts.LunarGuidance) { case 1: stats.SpellDamageFromIntellectPercentage += 0.08f; break; case 2: stats.SpellDamageFromIntellectPercentage += 0.16f; break; case 3: stats.SpellDamageFromIntellectPercentage += 0.25f; break; default: stats.SpellDamageFromIntellectPercentage += 0.0f; break; } calcs.ArcaneDamage = stats.SpellDamageRating + stats.SpellArcaneDamageRating + stats.SpellDamageFromIntellectPercentage * stats.Intellect + stats.SpellDamageFromSpiritPercentage * stats.Spirit; calcs.NatureDamage = stats.SpellDamageRating + stats.SpellNatureDamageRating + stats.SpellDamageFromIntellectPercentage * stats.Intellect + stats.SpellDamageFromSpiritPercentage * stats.Spirit; calcs.Latency = calcOpts.Latency; calcs.FightLength = calcOpts.FightLength; calcs.TargetLevel = calcOpts.TargetLevel; calcs.Scryer = calcOpts.AldorScryer == "Scryer"; // 2.4 spirit regen float baseRegenConstant = 0.00932715221261f; float spiritRegen = 0.001f + baseRegenConstant * (float)Math.Sqrt(calcs.BasicStats.Intellect) * calcs.BasicStats.Spirit; calcs.ManaRegen = spiritRegen + stats.Mp5 / 5f; calcs.ManaRegen5SR = spiritRegen * stats.SpellCombatManaRegeneration + stats.Mp5 / 5f; // Run the solver to do final calculations MoonkinSolver.Solve(character, ref calcs); return(calcs); }
public void LoadCalculationOptions() { _loadingCalculationOptions = true; if (Character.CalculationOptions == null) { Character.CalculationOptions = new CalculationOptionsMoonkin(); } calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; // Model Specific Code // _loadingCalculationOptions = false; }
// Load the options into the form protected override void LoadCalculationOptions() { if (Character.CalculationOptions == null) { Character.CalculationOptions = new CalculationOptionsMoonkin(); } CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; cmbTargetLevel.SelectedItem = calcOpts.TargetLevel.ToString(); txtLatency.Text = calcOpts.Latency.ToString(); txtFightLength.Text = calcOpts.FightLength.ToString(); chkInnervate.Checked = calcOpts.Innervate; //chkManaPots.Checked = calcOpts.ManaPots; //cmbPotType.SelectedItem = calcOpts.ManaPotType; //cmbPotType.Enabled = chkManaPots.Checked; txtInnervateDelay.Text = calcOpts.InnervateDelay.ToString(); txtInnervateDelay.Enabled = chkInnervate.Checked; trkReplenishmentUptime.Value = (int)(calcOpts.ReplenishmentUptime * 100); trkTreantLifespan.Value = (int)(calcOpts.TreantLifespan * 100); cmbUserRotation.SelectedItem = calcOpts.UserRotation; chkPtrMode.Checked = calcOpts.PTRMode; }
// Non-rotation-specific mana calculations private float GetEffectiveManaPool(Character character, CalculationOptionsMoonkin calcOpts, CharacterCalculationsMoonkin calcs) { float fightLength = character.BossOptions.BerserkTimer * 60.0f; float innervateCooldown = 180; // Mana/5 calculations float totalManaRegen = calcs.ManaRegen * fightLength; // Mana pot calculations float manaRestoredByPots = 0.0f; foreach (Buff b in character.ActiveBuffs) { if (b.Stats.ManaRestore > 0) { manaRestoredByPots = b.Stats.ManaRestore; break; } } // Innervate calculations float innervateDelay = calcOpts.InnervateDelay * 60.0f; int numInnervates = (calcOpts.Innervate && fightLength - innervateDelay > 0) ? ((int)(fightLength - innervateDelay) / (int)innervateCooldown + 1) : 0; float totalInnervateMana = numInnervates * 0.2f * calcs.BasicStats.Mana; totalInnervateMana *= 1 + 0.15f * character.DruidTalents.Dreamstate; // Replenishment calculations float replenishmentPerTick = calcs.BasicStats.Mana * calcs.BasicStats.ManaRestoreFromMaxManaPerSecond; float replenishmentMana = calcOpts.ReplenishmentUptime * replenishmentPerTick * character.BossOptions.BerserkTimer * 60; return calcs.BasicStats.Mana + totalInnervateMana + totalManaRegen + manaRestoredByPots + replenishmentMana; }
public void LoadCalculationOptions() { _loadingCalculationOptions = true; if (Character.CalculationOptions == null) Character.CalculationOptions = new CalculationOptionsMoonkin(); calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; // Model Specific Code // _loadingCalculationOptions = false; }
// Load the options into the form protected override void LoadCalculationOptions() { if (Character.CalculationOptions == null) { Character.CalculationOptions = new CalculationOptionsMoonkin(Character); } //if (!Character.CalculationOptions.ContainsKey("TargetLevel")) // calcOpts.TargetLevel = "73"; //if (!Character.CalculationOptions.ContainsKey("EnforceMetagemRequirements")) // character.EnforceMetagemRequirements = "No"; //if (!Character.CalculationOptions.ContainsKey("Latency")) // calcOpts.Latency = "0.4"; //if (!Character.CalculationOptions.ContainsKey("FightLength")) // calcOpts.FightLength = "5"; //if (!Character.CalculationOptions.ContainsKey("Innervate")) // calcOpts.Innervate = "No"; //if (!Character.CalculationOptions.ContainsKey("InnervateDelay")) // calcOpts.InnervateDelay = "1"; //if (!Character.CalculationOptions.ContainsKey("ShadowPriest")) // calcOpts.ShadowPriest = "0"; //if (!Character.CalculationOptions.ContainsKey("ManaPots")) // calcOpts.ManaPots = "No"; //if (!Character.CalculationOptions.ContainsKey("ManaPotDelay")) // calcOpts.ManaPotDelay = "1.5"; //if (!Character.CalculationOptions.ContainsKey("ManaPotType")) // calcOpts.ManaPotType = "Super Mana Potion"; //if (!Character.CalculationOptions.ContainsKey("InnervateWeapon")) // calcOpts.InnervateWeapon = "No"; //if (!Character.CalculationOptions.ContainsKey("InnervateWeaponInt")) // calcOpts.InnervateWeaponInt = "0"; //if (!Character.CalculationOptions.ContainsKey("InnervateWeaponSpi")) // calcOpts.InnervateWeaponSpi = "0"; //if (!Character.CalculationOptions.ContainsKey("AldorScryer")) // calcOpts.AldorScryer = "Aldor"; CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; cmbTargetLevel.SelectedItem = calcOpts.TargetLevel.ToString(); chkMetagem.Checked = Character.EnforceMetagemRequirements; txtLatency.Text = calcOpts.Latency.ToString(); txtFightLength.Text = calcOpts.FightLength.ToString(); txtShadowPriest.Text = calcOpts.ShadowPriest.ToString(); chkInnervate.Checked = calcOpts.Innervate; chkManaPots.Checked = calcOpts.ManaPots; cmbPotType.SelectedItem = calcOpts.ManaPotType; cmbPotType.Enabled = chkManaPots.Checked; txtInnervateDelay.Text = calcOpts.InnervateDelay.ToString(); txtInnervateDelay.Enabled = chkInnervate.Checked; txtManaPotDelay.Text = calcOpts.ManaPotDelay.ToString(); txtManaPotDelay.Enabled = chkManaPots.Checked; chkInnervateWeapon.Checked = calcOpts.InnervateWeapon; txtInnervateWeaponInt.Enabled = chkInnervateWeapon.Checked; txtInnervateWeaponInt.Text = calcOpts.InnervateWeaponInt.ToString(); txtInnervateWeaponSpi.Enabled = chkInnervateWeapon.Checked; txtInnervateWeaponSpi.Text = calcOpts.InnervateWeaponSpi.ToString(); rdbAldor.Checked = calcOpts.AldorScryer == "Aldor"; rdbScryer.Checked = calcOpts.AldorScryer == "Scryer"; if (talents != null) { talents.LoadCalculationOptions(); } }
public Stats GetBuffsStats(Character character, CalculationOptionsMoonkin calcOpts) { List<Buff> removedBuffs = new List<Buff>(); List<Buff> addedBuffs = new List<Buff>(); //float hasRelevantBuff; #region Passive Ability Auto-Fixing // Removes the Trueshot Aura Buff and it's equivalents Unleashed Rage and Abomination's Might if you are // maintaining it yourself. We are now calculating this internally for better accuracy and to provide // value to relevant talents /*{ hasRelevantBuff = character.HunterTalents.TrueshotAura; Buff a = Buff.GetBuffByName("Trueshot Aura"); Buff b = Buff.GetBuffByName("Unleashed Rage"); Buff c = Buff.GetBuffByName("Abomination's Might"); if (hasRelevantBuff > 0) { if (character.ActiveBuffs.Contains(a)) { character.ActiveBuffs.Remove(a); removedBuffs.Add(a); } if (character.ActiveBuffs.Contains(b)) { character.ActiveBuffs.Remove(b); removedBuffs.Add(b); } if (character.ActiveBuffs.Contains(c)) { character.ActiveBuffs.Remove(c); removedBuffs.Add(c); } } } // Removes the Hunter's Mark Buff and it's Children 'Glyphed', 'Improved' and 'Both' if you are // maintaining it yourself. We are now calculating this internally for better accuracy and to provide // value to relevant talents { hasRelevantBuff = character.HunterTalents.ImprovedHuntersMark + (character.HunterTalents.GlyphOfHuntersMark ? 1 : 0); Buff a = Buff.GetBuffByName("Hunter's Mark"); Buff b = Buff.GetBuffByName("Glyphed Hunter's Mark"); Buff c = Buff.GetBuffByName("Improved Hunter's Mark"); Buff d = Buff.GetBuffByName("Improved and Glyphed Hunter's Mark"); // Since we are doing base Hunter's mark ourselves, we still don't want to double-dip if (character.ActiveBuffs.Contains(a)) { character.ActiveBuffs.Remove(a); /*removedBuffs.Add(a);*//* } // If we have an enhanced Hunter's Mark, kill the Buff if (hasRelevantBuff > 0) { if (character.ActiveBuffs.Contains(b)) { character.ActiveBuffs.Remove(b); /*removedBuffs.Add(b);*//* } if (character.ActiveBuffs.Contains(c)) { character.ActiveBuffs.Remove(c); /*removedBuffs.Add(c);*//* } if (character.ActiveBuffs.Contains(d)) { character.ActiveBuffs.Remove(d); /*removedBuffs.Add(c);*//* } } }*/ #endregion Stats statsBuffs = GetBuffsStats(character.ActiveBuffs, character.SetBonusCount); foreach (Buff b in removedBuffs) { character.ActiveBuffsAdd(b); } foreach (Buff b in addedBuffs) { character.ActiveBuffs.Remove(b); } return statsBuffs; }
private static float GetEffectiveManaPool(Character character, CharacterCalculationsMoonkin calcs) { float fightLength = calcs.FightLength * 60.0f; float innervateCooldown = 360 - calcs.BasicStats.InnervateCooldownReduction; // Mana/5 calculations float totalManaRegen = calcs.ManaRegen5SR * fightLength; CalculationOptionsMoonkin calcOpts = character.CalculationOptions as CalculationOptionsMoonkin; // Mana pot calculations float manaPotDelay = calcOpts.ManaPotDelay * 60.0f; int numPots = calcOpts.ManaPots && fightLength - manaPotDelay > 0 ? ((int)(fightLength - manaPotDelay) / 120 + 1) : 0; float manaRestoredByPots = 0.0f; if (numPots > 0) { float manaPerPot = 0.0f; if (calcOpts.ManaPotType == "Super Mana Potion") { manaPerPot = 2400.0f; } if (calcOpts.ManaPotType == "Fel Mana Potion") { manaPerPot = 3200.0f; } // Bonus from Alchemist's Stone if (calcs.BasicStats.BonusManaPotion > 0) { manaPerPot *= 1 + calcs.BasicStats.BonusManaPotion; } manaRestoredByPots = numPots * manaPerPot; } // Innervate calculations float innervateDelay = calcOpts.InnervateDelay * 60.0f; int numInnervates = calcOpts.Innervate && fightLength - innervateDelay > 0 ? ((int)(fightLength - innervateDelay) / (int)innervateCooldown + 1) : 0; float totalInnervateMana = 0.0f; if (numInnervates > 0) { // Innervate mana rate increases only spirit-based regen float spiritRegen = (calcs.ManaRegen - calcs.BasicStats.Mp5 / 5f); // Add in calculations for an innervate weapon if (calcOpts.InnervateWeapon) { float baseRegenConstant = 0.00932715221261f; // Calculate the intellect from a weapon swap float userIntellect = calcs.BasicStats.Intellect - (character.MainHand == null ? 0 : character.MainHand.Stats.Intellect) - (character.OffHand == null ? 0 : character.OffHand.Stats.Intellect) + calcOpts.InnervateWeaponInt; // Do the same with spirit float userSpirit = calcs.BasicStats.Spirit - (character.MainHand == null ? 0 : character.MainHand.Stats.Spirit) - (character.OffHand == null ? 0 : character.OffHand.Stats.Spirit) + calcOpts.InnervateWeaponSpi; // The new spirit regen for innervate periods uses the new weapon stats spiritRegen = baseRegenConstant * (float)Math.Sqrt(userIntellect) * userSpirit; } float innervateManaRate = spiritRegen * 4 + calcs.BasicStats.Mp5 / 5f; float innervateTime = numInnervates * 20.0f; totalInnervateMana = innervateManaRate * innervateTime - (numInnervates * calcs.BasicStats.Mana * 0.04f); } // Shadow priest calculations float sPriestMp5 = calcOpts.ShadowPriest; float sPriestMana = sPriestMp5 / 5 * fightLength; return(calcs.BasicStats.Mana + totalInnervateMana + totalManaRegen + manaRestoredByPots + sPriestMana); }
private static void UpdateSpells(Character character, ref CharacterCalculationsMoonkin calcs) { Stats stats = calcs.BasicStats; CalculationOptionsMoonkin calcOpts = character.CalculationOptions as CalculationOptionsMoonkin; // Add (possibly talented) +spelldmg // Starfire: Damage +(0.04 * Wrath of Cenarius) // Wrath: Damage +(0.02 * Wrath of Cenarius) wrath.SpellDamageModifier += 0.02f * calcOpts.WrathofCenarius; starfire.SpellDamageModifier += 0.04f * calcOpts.WrathofCenarius; // Add spell damage from idols starfire.DamagePerHit += stats.StarfireDmg; moonfire.DamagePerHit += stats.MoonfireDmg; wrath.DamagePerHit += stats.WrathDmg; // Add spell-specific damage // Starfire, Moonfire, Wrath: Damage +(0.02 * Moonfury) wrath.SpecialDamageModifier *= 1.0f + (0.02f * calcOpts.Moonfury); moonfire.SpecialDamageModifier *= 1.0f + (0.02f * calcOpts.Moonfury); starfire.SpecialDamageModifier *= 1.0f + (0.02f * calcOpts.Moonfury); // Wrath, Insect Swarm: Nature spell damage multipliers wrath.SpecialDamageModifier *= ((1 + calcs.BasicStats.BonusNatureSpellPowerMultiplier) * (1 + calcs.BasicStats.BonusSpellPowerMultiplier)); insectSwarm.SpecialDamageModifier *= ((1 + calcs.BasicStats.BonusNatureSpellPowerMultiplier) * (1 + calcs.BasicStats.BonusSpellPowerMultiplier)); // Starfire, Moonfire: Arcane damage multipliers starfire.SpecialDamageModifier *= ((1 + calcs.BasicStats.BonusArcaneSpellPowerMultiplier) * (1 + calcs.BasicStats.BonusSpellPowerMultiplier)); moonfire.SpecialDamageModifier *= ((1 + calcs.BasicStats.BonusArcaneSpellPowerMultiplier) * (1 + calcs.BasicStats.BonusSpellPowerMultiplier)); // Level-based partial resistances wrath.SpecialDamageModifier *= 1 - 0.02f * (calcs.TargetLevel - 70); starfire.SpecialDamageModifier *= 1 - 0.02f * (calcs.TargetLevel - 70); moonfire.SpecialDamageModifier *= 1 - 0.02f * (calcs.TargetLevel - 70); // Insect Swarm is a binary spell // Add spell-specific crit chance // Wrath, Starfire: Crit chance +(0.02 * Focused Starlight) wrath.SpecialCriticalModifier += 0.02f * calcOpts.FocusedStarlight; starfire.SpecialCriticalModifier += 0.02f * calcOpts.FocusedStarlight; // Moonfire: Damage, Crit chance +(0.05 * Imp Moonfire) moonfire.SpecialDamageModifier *= 1.0f + (0.05f * calcOpts.ImpMoonfire); moonfire.SpecialCriticalModifier += 0.05f * calcOpts.ImpMoonfire; // Add spell-specific critical strike damage // Starfire, Moonfire, Wrath: Crit damage +(0.2 * Vengeance) starfire.CriticalHitMultiplier *= 1 + 0.2f * calcOpts.Vengeance; moonfire.CriticalHitMultiplier *= 1 + 0.2f * calcOpts.Vengeance; wrath.CriticalHitMultiplier *= 1 + 0.2f * calcOpts.Vengeance; // Chaotic Skyfire Diamond starfire.CriticalHitMultiplier *= 1.0f + 1.5f / 0.5f * stats.BonusSpellCritMultiplier; moonfire.CriticalHitMultiplier *= 1.0f + 1.5f / 0.5f * stats.BonusSpellCritMultiplier; wrath.CriticalHitMultiplier *= 1.0f + 1.5f / 0.5f * stats.BonusSpellCritMultiplier; // Reduce spell-specific mana costs // Starfire, Moonfire, Wrath: Mana cost -(0.03 * Moonglow) starfire.ManaCost *= 1.0f - (0.03f * calcOpts.Moonglow); moonfire.ManaCost *= 1.0f - (0.03f * calcOpts.Moonglow); wrath.ManaCost *= 1.0f - (0.03f * calcOpts.Moonglow); // Reduce spell-specific cast times // Wrath, Starfire: Cast time -(0.1 * Starlight Wrath) wrath.CastTime -= 0.1f * calcOpts.StarlightWrath; starfire.CastTime -= 0.1f * calcOpts.StarlightWrath; // Add set bonuses moonfire.DoT.Duration += stats.MoonfireExtension; starfire.SpecialCriticalModifier += stats.StarfireCritChance; }
public static void Solve(Character character, ref CharacterCalculationsMoonkin calcs) { // Try to reset the cached results dictionary on each call cachedResults = new Dictionary <string, RotationData>(); float effectiveSpellHit = calcs.BasicStats.SpellHitRating; CalculationOptionsMoonkin calcOpts = character.CalculationOptions as CalculationOptionsMoonkin; bool naturesGrace = calcOpts.NaturesGrace > 0 ? true : false; float fightLength = calcs.FightLength * 60.0f; float baseHitRate = 0.83f; switch (calcs.TargetLevel) { case 70: baseHitRate = 0.96f; break; case 71: baseHitRate = 0.95f; break; case 72: baseHitRate = 0.94f; break; case 73: baseHitRate = 0.83f; break; default: baseHitRate = 0.83f; break; } if (baseHitRate + effectiveSpellHit / CalculationsMoonkin.hitRatingConversionFactor > 0.99f) { effectiveSpellHit = CalculationsMoonkin.hitRatingConversionFactor * (0.99f - baseHitRate); } RecreateSpells(character, ref calcs); float maxDPS = 0.0f; float maxRawDPS = 0.0f; foreach (SpellRotation rotation in SpellRotations) { // Reset all parameters to defaults Spell.GlobalCooldown = 1.5f; float effectiveArcaneDamage = calcs.ArcaneDamage; float effectiveNatureDamage = calcs.NatureDamage; float effectiveSpellCrit = calcs.BasicStats.SpellCritRating; float effectiveSpellHaste = calcs.BasicStats.SpellHasteRating; float effectiveMana = GetEffectiveManaPool(character, calcs); // Trinkets trinketExtraDPS = 0.0f; // Do a pre-emptive call to rotation.DPS to get corrected cast times for spells rotation.DPS(effectiveArcaneDamage, effectiveNatureDamage, baseHitRate + effectiveSpellHit / CalculationsMoonkin.hitRatingConversionFactor, effectiveSpellCrit / CalculationsMoonkin.critRatingConversionFactor, effectiveSpellHaste / CalculationsMoonkin.hasteRatingConversionFactor, effectiveMana, fightLength, naturesGrace, calcs.BasicStats.StarfireBonusWithDot, calcs.Latency); rotation.ResetRotationalVariables(); DoTrinketCalcs(calcs, rotation, baseHitRate + effectiveSpellHit / CalculationsMoonkin.hitRatingConversionFactor, ref effectiveArcaneDamage, ref effectiveNatureDamage, ref effectiveSpellCrit, ref effectiveSpellHaste); // JoW/mana restore procs effectiveMana += DoManaRestoreCalcs(calcs, rotation, baseHitRate + effectiveSpellHit / CalculationsMoonkin.hitRatingConversionFactor) * (fightLength / rotation.Duration); // Calculate average global cooldown based on effective haste rating (includes trinkets) Spell.GlobalCooldown /= 1 + effectiveSpellHaste * (1 / CalculationsMoonkin.hasteRatingConversionFactor); // Reset the cast time on Insect Swarm and Moonfire, since this is affected by haste insectSwarm.CastTime = Spell.GlobalCooldown; moonfire.CastTime = Spell.GlobalCooldown; // Incorporate Nature's Grace with Moonfire into the rotational calculations if (naturesGrace && rotation.HasMoonfire && rotation.StarfireCount > 0) { float critFromGear = effectiveSpellCrit * (1 / CalculationsMoonkin.critRatingConversionFactor); starfire.CastTime -= ((1 - (rotation.AverageCritChance + critFromGear)) * (moonfire.SpecialCriticalModifier + critFromGear) * 0.5f) / rotation.StarfireCount; } float currentDPS = rotation.DPS(effectiveArcaneDamage, effectiveNatureDamage, baseHitRate + effectiveSpellHit / CalculationsMoonkin.hitRatingConversionFactor, effectiveSpellCrit / CalculationsMoonkin.critRatingConversionFactor, effectiveSpellHaste / CalculationsMoonkin.hasteRatingConversionFactor, effectiveMana, fightLength, naturesGrace, calcs.BasicStats.StarfireBonusWithDot, calcs.Latency) + trinketExtraDPS; // Restore Starfire's cast time because the object is reused if (naturesGrace && rotation.HasMoonfire && rotation.StarfireCount > 0) { float critFromGear = effectiveSpellCrit * (1 / CalculationsMoonkin.critRatingConversionFactor); starfire.CastTime += ((1 - (rotation.AverageCritChance + critFromGear)) * (moonfire.SpecialCriticalModifier + critFromGear) * 0.5f) / rotation.StarfireCount; } float currentRawDPS = rotation.RawDPS + trinketExtraDPS; if (currentDPS > maxDPS) { calcs.SelectedRotation = rotation; maxDPS = currentDPS; } if (currentRawDPS > maxRawDPS) { calcs.MaxDPSRotation = rotation; maxRawDPS = currentRawDPS; } cachedResults[rotation.Name] = new RotationData() { RawDPS = currentRawDPS, DPS = currentDPS, DPM = rotation.DPM, TimeToOOM = rotation.TimeToOOM }; } calcs.SubPoints = new float[] { maxDPS, maxRawDPS }; calcs.OverallPoints = calcs.SubPoints[0] + calcs.SubPoints[1]; calcs.Rotations = cachedResults; }
// Perform damage and mana calculations for all spells in the given rotation. Returns damage done over the total duration. public float DamageDone(Character character, CharacterCalculationsMoonkin calcs, float treantLifespan, float spellPower, float spellHit, float spellCrit, float spellHaste, float masteryPoints, float latency) { CalculationOptionsMoonkin calcOpts = character.CalculationOptions as CalculationOptionsMoonkin; DruidTalents talents = character.DruidTalents; Spell sf = Solver.Starfire; Spell ss = Solver.Starsurge; Spell w = Solver.Wrath; Spell mf = Solver.Moonfire; Spell iSw = Solver.InsectSwarm; // 4.1: The bug causing the Eclipse buff to be rounded down to the nearest percent has been fixed float eclipseBonus = 1 + MoonkinSolver.ECLIPSE_BASE + masteryPoints * 0.02f; RotationData.NaturesGraceUptime = (float)GetInterpolatedNGUpime(spellHaste, calcs.BasicStats.BonusWrathEnergy > 0, calcs.BasicStats.T13FourPieceActive, talents.GlyphOfStarfire); RotationData.Duration = (float)GetInterpolatedCastTime(calcs.SpellHaste, calcs.BasicStats.BonusWrathEnergy > 0, calcs.BasicStats.T13FourPieceActive, talents.GlyphOfStarfire); double[] castDistribution = GetInterpolatedCastTable(calcs.SpellHaste, calcs.BasicStats.BonusWrathEnergy > 0, calcs.BasicStats.T13FourPieceActive, talents.GlyphOfStarfire); double percentOfMoonfiresExtended = talents.GlyphOfStarfire ? GetPercentOfMoonfiresExtended(calcs.SpellHaste, calcs.BasicStats.BonusWrathEnergy > 0, calcs.BasicStats.T13FourPieceActive) : 0; DoMainNuke(calcs, ref sf, spellPower, spellHit, spellCrit, spellHaste, RotationData.NaturesGraceUptime, latency); DoMainNuke(calcs, ref ss, spellPower, spellHit, spellCrit, spellHaste, RotationData.NaturesGraceUptime, latency); DoMainNuke(calcs, ref w, spellPower, spellHit, spellCrit, spellHaste, RotationData.NaturesGraceUptime, latency); double gcd = Math.Max(1, 1.5 / (1 + spellHaste)) + latency; double ngGcd = Math.Max(1, 1.5 / (1 + spellHaste) / (1 + 0.05 * talents.NaturesGrace)) + latency; // Moonfire related local variables float mfBaseDur, mfMeanDur, mfMaxDur, mfMeanMaxDur, mfTicks, mfMaxTicks; mfBaseDur = mf.DotEffect.BaseDuration; mfMaxDur = mfBaseDur + (talents.GlyphOfStarfire ? 9f : 0f); // Determine Nature's Grace uptime against Moonfire float mfNGUptime = (float)Math.Min(2 * mfMaxDur / RotationData.Duration, 1); DoDotSpell(calcs, ref mf, spellPower, spellHit, spellCrit, spellHaste, mfNGUptime, latency); // Insect Swarm never benefits from Nature's Grace DoDotSpell(calcs, ref iSw, spellPower, spellHit, spellCrit, spellHaste, 0, latency); mfTicks = mf.DotEffect.NumberOfTicks; mfMaxTicks = mfTicks + (talents.GlyphOfStarfire ? 6 : 0); mfMeanDur = mf.DotEffect.Duration; mfMeanMaxDur = mf.DotEffect.Duration + (talents.GlyphOfStarfire ? 6 * mf.DotEffect.TickLength : 0f); RotationData.MoonfireAvgCast = mf.CastTime; RotationData.InsectSwarmAvgCast = iSw.CastTime; // Break the cast distribution down into its component cast counts double wrathCasts = castDistribution[1] * RotationData.Duration / w.CastTime; double eclipseWrathCasts = castDistribution[5] * RotationData.Duration / w.CastTime; double nonEclipsedWrathPercentage = castDistribution[1] / (castDistribution[1] + castDistribution[5]); double eclipsedWrathPercentage = castDistribution[5] / (castDistribution[1] + castDistribution[5]); RotationData.WrathAvgHit = (float)(nonEclipsedWrathPercentage * w.DamagePerHit + eclipsedWrathPercentage * w.DamagePerHit * eclipseBonus); RotationData.WrathAvgEnergy = w.AverageEnergy; RotationData.WrathCount = (float)(wrathCasts + eclipseWrathCasts); double starfireCasts = castDistribution[0] * RotationData.Duration / sf.CastTime; double eclipseStarfireCasts = castDistribution[4] * RotationData.Duration / sf.CastTime; double nonEclipsedStarfirePercentage = castDistribution[0] / (castDistribution[0] + castDistribution[4]); double eclipsedStarfirePercentage = castDistribution[4] / (castDistribution[0] + castDistribution[4]); RotationData.StarfireAvgHit = (float)(nonEclipsedStarfirePercentage * sf.DamagePerHit + eclipsedStarfirePercentage * sf.DamagePerHit * eclipseBonus); RotationData.StarfireAvgEnergy = sf.AverageEnergy; RotationData.StarfireCount = (float)(starfireCasts + eclipseStarfireCasts); double starsurgeCasts = castDistribution[2] * RotationData.Duration / ss.CastTime; double eclipseStarsurgeCasts = castDistribution[6] * RotationData.Duration / ss.CastTime; double shootingStarsProcs = castDistribution[3] * RotationData.Duration / gcd; double eclipseShootingStarsProcs = castDistribution[7] * RotationData.Duration / gcd; double allStarsurgePercentage = castDistribution[2] + castDistribution[6] + castDistribution[3] + castDistribution[7]; double nonEclipsedStarsurgePercentage = (castDistribution[2] + castDistribution[3]) / allStarsurgePercentage; double eclipsedStarsurgePercentage = (castDistribution[6] + castDistribution[7]) / allStarsurgePercentage; double starsurgePercentage = (castDistribution[2] + castDistribution[6]) / allStarsurgePercentage; double shootingStarsPercentage = (castDistribution[3] + castDistribution[7]) / allStarsurgePercentage; RotationData.StarSurgeAvgHit = (float)(nonEclipsedStarsurgePercentage * ss.DamagePerHit + eclipsedStarsurgePercentage * ss.DamagePerHit * eclipseBonus); RotationData.StarSurgeAvgEnergy = ss.AverageEnergy; RotationData.StarSurgeCount = (float)(starsurgeCasts + eclipseStarsurgeCasts + shootingStarsProcs + eclipseShootingStarsProcs); double moonfireCasts = castDistribution[8] * RotationData.Duration / mf.CastTime; double eclipsedMoonfireCasts = castDistribution[10] * RotationData.Duration / mf.CastTime; double nonEclipsedMoonfirePercentage = castDistribution[8] / (castDistribution[8] + castDistribution[10]); double eclipsedMoonfirePercentage = castDistribution[10] / (castDistribution[8] + castDistribution[10]); RotationData.MoonfireCasts = (float)(moonfireCasts + eclipsedMoonfireCasts); double insectSwarmCasts = castDistribution[9] * RotationData.Duration / iSw.CastTime; double eclipsedInsectSwarmCasts = castDistribution[11] * RotationData.Duration / iSw.CastTime; double nonEclipsedInsectSwarmPercentage = castDistribution[9] / (castDistribution[9] + castDistribution[11]); double eclipsedInsectSwarmPercentage = castDistribution[11] / (castDistribution[9] + castDistribution[11]); RotationData.InsectSwarmCasts = (float)(insectSwarmCasts + eclipsedInsectSwarmCasts); double unextendedMoonfireAverage = nonEclipsedMoonfirePercentage * (mf.DamagePerHit + mf.DotEffect.DamagePerHit) + eclipsedMoonfirePercentage * (mf.DamagePerHit + mf.DotEffect.DamagePerHit) * eclipseBonus; double mfExtendedDotDamage = mfMaxTicks * (mf.DotEffect.DamagePerHit / mf.DotEffect.NumberOfTicks); double extendedMoonfireAverage = nonEclipsedMoonfirePercentage * (mf.DamagePerHit + mfExtendedDotDamage) + eclipsedMoonfirePercentage * (mf.DamagePerHit + mfExtendedDotDamage) * eclipseBonus; RotationData.MoonfireTicks = (float)(percentOfMoonfiresExtended * mfMaxTicks + (1 - percentOfMoonfiresExtended) * mfTicks); RotationData.MoonfireDuration = (float)(percentOfMoonfiresExtended * mfMeanDur + (1 - percentOfMoonfiresExtended) * mfMeanMaxDur); RotationData.MoonfireAvgHit = (float)(percentOfMoonfiresExtended * extendedMoonfireAverage + (1 - percentOfMoonfiresExtended) * unextendedMoonfireAverage); RotationData.InsectSwarmTicks = RotationData.InsectSwarmCasts * iSw.DotEffect.NumberOfTicks; RotationData.InsectSwarmDuration = iSw.DotEffect.Duration; RotationData.InsectSwarmAvgHit = (float)(nonEclipsedInsectSwarmPercentage * iSw.DotEffect.DamagePerHit + eclipsedInsectSwarmPercentage * iSw.DotEffect.DamagePerHit * eclipseBonus); RotationData.StarfireAvgCast = sf.CastTime; RotationData.WrathAvgCast = w.CastTime; RotationData.AverageInstantCast = (float)(gcd * (1 - RotationData.NaturesGraceUptime) + ngGcd * RotationData.NaturesGraceUptime); RotationData.StarSurgeAvgCast = (float)(starsurgePercentage * ss.CastTime + shootingStarsPercentage * RotationData.AverageInstantCast); // Modify the rotation duration to simulate the energy bonus from Dragonwrath procs if (calcs.BasicStats.DragonwrathProc > 0) { float baselineNukeDuration = RotationData.StarfireCount * RotationData.StarfireAvgCast + RotationData.WrathCount * RotationData.WrathAvgCast + RotationData.StarSurgeCount * RotationData.StarSurgeAvgCast; float dragonwrathNukeDuration = baselineNukeDuration / (1 + MoonkinSolver.DRAGONWRATH_PROC_RATE); RotationData.Duration -= (baselineNukeDuration - dragonwrathNukeDuration); } RotationData.LunarUptime = (float)(castDistribution[4] + 0.5 * castDistribution[6] + 0.5 * castDistribution[7] + 0.5 * castDistribution[10]); RotationData.SolarUptime = (float)(castDistribution[5] + 0.5 * castDistribution[6] + 0.5 * castDistribution[7] + 0.5 * castDistribution[10] + castDistribution[11]); float starfallReduction = (float)(starsurgeCasts + shootingStarsProcs + eclipseStarsurgeCasts + eclipseShootingStarsProcs) * 5f; float starfallCooldown = (90f - (talents.GlyphOfStarfall ? 30f : 0f)) - (talents.GlyphOfStarsurge ? starfallReduction : 0); float starfallRatio = talents.Starfall == 1 ? (RotationData.StarfallCastMode == StarfallMode.OnCooldown ? RotationData.AverageInstantCast / (starfallCooldown + RotationData.AverageInstantCast) : 0f) : 0f; float starfallTime = RotationData.StarfallCastMode == StarfallMode.LunarOnly ? RotationData.AverageInstantCast : 0f; float treantRatio = talents.ForceOfNature == 1 ? RotationData.AverageInstantCast / (180f + RotationData.AverageInstantCast) : 0; float starfallBaseDamage = (talents.Starfall > 0 && RotationData.StarfallCastMode == StarfallMode.Unused) ? 0 : DoStarfallCalcs(calcs, spellPower, spellHit, spellCrit); starfallBaseDamage *= 1 + (talents.GlyphOfFocus ? 0.1f : 0f); // Dragonwrath starfallBaseDamage *= 1 + (calcs.BasicStats.DragonwrathProc > 0 ? MoonkinSolver.DRAGONWRATH_PROC_RATE : 0f); float starfallEclipseDamage = starfallBaseDamage * eclipseBonus; RotationData.TreantDamage = talents.ForceOfNature == 0 ? 0 : DoTreeCalcs(calcs, character.Level, character.BossOptions.Level, spellPower, treantLifespan); // T12 2-piece: 2-sec cast, 5192-6035 damage, affected by hit, 15-sec duration float T122PieceHitDamage = (5192 + 6035) / 2f * spellHit * (1 + calcs.BasicStats.BonusFireDamageMultiplier); // I'm going to assume a 150% crit modifier on the 2T12 proc until I'm told otherwise float T122PieceCritDamage = T122PieceHitDamage * 1.5f; // Use 2.5% crit rate based on EJ testing // Hard-code 4.5 casts/proc based on EJ testing float T122PieceBaseDamage = (0.975f * T122PieceHitDamage + 0.025f * T122PieceCritDamage) * 4.5f; // Without glyph of Starsurge, you cannot fit a Starfall in every Lunar eclipse. // The actual result will be better than 1/2, because you will be able to cast SFall later in each Eclipse as the fight goes on, // but you will miss a Lunar proc entirely eventually. float starfallCooldownOverlap = starfallCooldown - RotationData.Duration; float rotationsToMiss = starfallCooldownOverlap > 0 ? RotationData.Duration * RotationData.LunarUptime / starfallCooldownOverlap : 0f; float starfallFraction = rotationsToMiss > 0 ? (float)(Math.Ceiling(rotationsToMiss) / (Math.Ceiling(rotationsToMiss) + 1)) : 1f; RotationData.StarfallCasts = RotationData.StarfallCastMode == StarfallMode.OnCooldown ? starfallRatio * RotationData.Duration / RotationData.AverageInstantCast : (RotationData.StarfallCastMode == StarfallMode.LunarOnly ? starfallFraction : 0f); RotationData.TreantCasts = treantRatio * RotationData.Duration / RotationData.AverageInstantCast; RotationData.StarfallStars = 10f; if (RotationData.StarfallCastMode == StarfallMode.LunarOnly) { RotationData.LunarUptime += starfallFraction * RotationData.AverageInstantCast / RotationData.Duration; } else if (RotationData.StarfallCastMode == StarfallMode.OnCooldown) { RotationData.SolarUptime *= 1 + starfallRatio; RotationData.LunarUptime *= 1 + starfallRatio; } RotationData.Duration += RotationData.StarfallCasts * RotationData.AverageInstantCast + RotationData.TreantCasts * RotationData.AverageInstantCast; RotationData.StarfallDamage = RotationData.StarfallCastMode == StarfallMode.OnCooldown ? RotationData.LunarUptime * starfallEclipseDamage + (1 - RotationData.LunarUptime) * starfallBaseDamage : starfallEclipseDamage; float moonfireDamage = RotationData.MoonfireAvgHit * RotationData.MoonfireCasts; float insectSwarmDamage = RotationData.InsectSwarmAvgHit * RotationData.InsectSwarmCasts; // Calculate total damage done for external cooldowns per rotation float starfallDamage = RotationData.StarfallDamage * RotationData.StarfallCasts; float treantDamage = RotationData.TreantDamage * RotationData.TreantCasts; float T122PieceDamage = 0f; if (calcs.BasicStats.ContainsSpecialEffect(se => se.Trigger == Trigger.MageNukeCast)) { foreach (SpecialEffect effect in calcs.BasicStats.SpecialEffects(se => se.Trigger == Trigger.MageNukeCast)) { T122PieceDamage = T122PieceBaseDamage * effect.GetAverageUptime(RotationData.Duration / (RotationData.WrathCount + RotationData.StarfireCount), 1f); } } // Calculate mana cost per cast. // Starfall - 35% of base mana float starfallManaCost = (int)(0.35f * MoonkinSolver.BaseMana) - calcs.BasicStats.SpellsManaCostReduction - calcs.BasicStats.NatureSpellsManaCostReduction; // Force of Nature - 12% of base mana float treantManaCost = (int)(0.12f * MoonkinSolver.BaseMana) - calcs.BasicStats.SpellsManaCostReduction - calcs.BasicStats.NatureSpellsManaCostReduction; RotationData.CastCount = RotationData.WrathCount + RotationData.StarfireCount + RotationData.StarSurgeCount + RotationData.MoonfireCasts + RotationData.InsectSwarmCasts + RotationData.StarfallCasts + RotationData.TreantCasts; RotationData.DotTicks = RotationData.InsectSwarmTicks + RotationData.MoonfireTicks; RotationData.ManaUsed = RotationData.WrathCount * w.BaseManaCost + RotationData.StarfireCount * sf.BaseManaCost + RotationData.StarSurgeCount * ss.BaseManaCost + RotationData.MoonfireCasts * mf.BaseManaCost + RotationData.InsectSwarmCasts * iSw.BaseManaCost + RotationData.StarfallCasts * starfallManaCost + RotationData.TreantCasts * treantManaCost; float manaSavingsFromOOC = MoonkinSolver.OOC_PROC_CHANCE * (RotationData.MoonfireCasts / RotationData.CastCount * mf.BaseManaCost) + MoonkinSolver.OOC_PROC_CHANCE * (RotationData.InsectSwarmCasts / RotationData.CastCount * iSw.BaseManaCost) + MoonkinSolver.OOC_PROC_CHANCE * (RotationData.StarfireCount / RotationData.CastCount * sf.BaseManaCost) + MoonkinSolver.OOC_PROC_CHANCE * (RotationData.WrathCount / RotationData.CastCount * w.BaseManaCost) + MoonkinSolver.OOC_PROC_CHANCE * (RotationData.StarSurgeCount / RotationData.CastCount * ss.BaseManaCost) + MoonkinSolver.OOC_PROC_CHANCE * (RotationData.StarfallCasts / RotationData.CastCount * starfallManaCost); RotationData.ManaUsed -= manaSavingsFromOOC; RotationData.ManaGained = 2 * MoonkinSolver.EUPHORIA_PERCENT * talents.Euphoria * calcs.BasicStats.Mana; return(RotationData.WrathAvgHit * RotationData.WrathCount + RotationData.StarfireAvgHit * RotationData.StarfireCount + RotationData.StarSurgeAvgHit * RotationData.StarSurgeCount + moonfireDamage + insectSwarmDamage + treantDamage + starfallDamage + T122PieceDamage); }
public override Stats GetCharacterStats(Character character, Item additionalItem) { // Start off with a slightly modified form of druid base character stats calculations Stats statsRace = character.Race == Character.CharacterRace.NightElf ? new Stats() { Health = 3434f, Mana = 2470f, Stamina = 82f, Agility = 75f, Intellect = 120f, Spirit = 133f } : new Stats() { Health = 3434f, Mana = 2470f, Stamina = 85f, Agility = 64.5f, Intellect = 115f, Spirit = 135f }; // Get the gear/enchants/buffs stats loaded in Stats statsBaseGear = GetItemStats(character, additionalItem); Stats statsEnchants = GetEnchantsStats(character); Stats statsBuffs = GetBuffsStats(character.ActiveBuffs); Stats statsGearEnchantsBuffs = statsBaseGear + statsEnchants + statsBuffs; CalculationOptionsMoonkin calcOpts = character.CalculationOptions as CalculationOptionsMoonkin; // Create the total stats object Stats statsTotal = statsGearEnchantsBuffs + statsRace; // Base stats: Intellect, Stamina, Spirit, Agility statsTotal.Intellect = (float)Math.Floor((Math.Floor(statsRace.Intellect * (1 + statsRace.BonusIntellectMultiplier)) + statsGearEnchantsBuffs.Intellect * (1 + statsRace.BonusIntellectMultiplier)) * (1 + statsGearEnchantsBuffs.BonusIntellectMultiplier)); statsTotal.Stamina = (float)Math.Floor((Math.Floor(statsRace.Stamina * (1 + statsRace.BonusStaminaMultiplier)) + statsGearEnchantsBuffs.Stamina * (1 + statsRace.BonusStaminaMultiplier)) * (1 + statsGearEnchantsBuffs.BonusStaminaMultiplier)); statsTotal.Agility = (float)Math.Floor((Math.Floor(statsRace.Agility * (1 + statsRace.BonusAgilityMultiplier)) + statsGearEnchantsBuffs.Agility * (1 + statsRace.BonusAgilityMultiplier)) * (1 + statsGearEnchantsBuffs.BonusAgilityMultiplier)); statsTotal.Spirit = (float)Math.Floor((Math.Floor(statsRace.Spirit * (1 + statsRace.BonusSpiritMultiplier)) + statsGearEnchantsBuffs.Spirit * (1 + statsRace.BonusSpiritMultiplier)) * (1 + statsGearEnchantsBuffs.BonusSpiritMultiplier)); // Base stats: Intellect% +(0.04 * Heart of the Wild) statsTotal.Intellect *= 1 + 0.04f * calcOpts.HotW; // Base stats: Stam%, Int%, Spi%, Agi% +(0.01 * Survival of the Fittest) statsTotal.Intellect *= 1 + 0.01f * calcOpts.SotF; statsTotal.Stamina *= 1 + 0.01f * calcOpts.SotF; statsTotal.Agility *= 1 + 0.01f * calcOpts.SotF; statsTotal.Spirit *= 1 + 0.01f * calcOpts.SotF; // Base stats: Spirit% +(0.05 * Living Spirit) statsTotal.Spirit *= 1 + 0.05f * calcOpts.LivingSpirit; // Bonus multipliers statsTotal.BonusAgilityMultiplier = ((1 + statsRace.BonusAgilityMultiplier) * (1 + statsGearEnchantsBuffs.BonusAgilityMultiplier)) - 1; statsTotal.BonusStaminaMultiplier = ((1 + statsRace.BonusStaminaMultiplier) * (1 + statsGearEnchantsBuffs.BonusStaminaMultiplier)) - 1; statsTotal.BonusIntellectMultiplier = ((1 + statsRace.BonusIntellectMultiplier) * (1 + statsGearEnchantsBuffs.BonusIntellectMultiplier)) - 1; statsTotal.BonusSpiritMultiplier = ((1 + statsRace.BonusSpiritMultiplier) * (1 + statsGearEnchantsBuffs.BonusSpiritMultiplier)) - 1; // Derived stats: Health, mana pool, armor statsTotal.Health = (float)Math.Round(((statsRace.Health + statsGearEnchantsBuffs.Health + (statsTotal.Stamina * 10f)) * (character.Race == Character.CharacterRace.Tauren ? 1.05f : 1f))); statsTotal.Mana = (float)Math.Round(statsRace.Mana + 15f * statsTotal.Intellect) - 380; statsTotal.Armor = (float)Math.Round(statsGearEnchantsBuffs.Armor + statsTotal.Agility * 2f); // Regen mechanic: mp5 +((0.1 * Intensity) * Spiritmp5()) statsTotal.SpellCombatManaRegeneration += 0.1f * calcOpts.Intensity; // Regen mechanic: mp5 +(0.04/0.07/0.10) * Int) float dreamstatePercent = 0.0f; switch (calcOpts.Dreamstate) { case 1: dreamstatePercent = 0.04f; break; case 2: dreamstatePercent = 0.07f; break; case 3: dreamstatePercent = 0.1f; break; default: dreamstatePercent = 0.0f; break; } statsTotal.Mp5 += (float)(int)(dreamstatePercent * statsTotal.Intellect); // Hit rating // All spells: Hit% +(0.02 * Balance of Power) statsTotal.SpellHitRating += 0.02f * calcOpts.BalanceofPower * 1262f; // Crit rating // Application order: Stats, Talents, Gear // Add druid base crit statsTotal.SpellCritRating += (0.0185f * 2208f); // Add intellect-based crit rating to crit (all classes except warlock: 1/80) statsTotal.SpellCritRating += (statsTotal.Intellect / 8000.0f) * 2208f; // All spells: Crit% + (0.01 * Natural Perfection) statsTotal.SpellCritRating += 0.01f * calcOpts.NaturalPerfection * 2208f; // Add the crit bonus from the idol, if present if (character.ActiveBuffsContains("Moonkin Aura")) { statsTotal.SpellCritRating += statsTotal.IdolCritRating; } return(statsTotal); }
// Update character calculation options when a talent point is set private void comboBox_SelectedIndexChanged(object sender, EventArgs e) { if (!_loading) { CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; calcOpts.StarlightWrath = cmbStarlightWrath.SelectedIndex; calcOpts.ForceofNature = cmbForceofNature.SelectedIndex; calcOpts.WrathofCenarius = cmbWrathofCenarius.SelectedIndex; calcOpts.ImprovedFF = cmbImprovedFF.SelectedIndex; calcOpts.MoonkinForm = cmbMoonkinForm.SelectedIndex; calcOpts.Dreamstate = cmbDreamstate.SelectedIndex; calcOpts.BalanceofPower = cmbBalanceofPower.SelectedIndex; calcOpts.Moonfury = cmbMoonfury.SelectedIndex; calcOpts.Moonglow = cmbMoonglow.SelectedIndex; calcOpts.NaturesGrace = cmbNaturesGrace.SelectedIndex; calcOpts.LunarGuidance = cmbLunarGuidance.SelectedIndex; calcOpts.CelestialFocus = cmbCelestialFocus.SelectedIndex; calcOpts.Vengeance = cmbVengeance.SelectedIndex; calcOpts.NaturesReach = cmbNaturesReach.SelectedIndex; calcOpts.InsectSwarm = cmbInsectSwarm.SelectedIndex; calcOpts.Brambles = cmbBrambles.SelectedIndex; calcOpts.ImpMoonfire = cmbImpMoonfire.SelectedIndex; calcOpts.FocusedStarlight = cmbFocusedStarlight.SelectedIndex; calcOpts.ControlofNature = cmbControlofNature.SelectedIndex; calcOpts.ImpNaturesGrasp = cmbImpNaturesGrasp.SelectedIndex; calcOpts.NaturesGrasp = cmbNaturesGrasp.SelectedIndex; calcOpts.Ferocity = cmbFerocity.SelectedIndex; calcOpts.FeralAggression = cmbFeralAggression.SelectedIndex; calcOpts.FeralInstinct = cmbFeralInstinct.SelectedIndex; calcOpts.BrutalImpact = cmbBrutalImpact.SelectedIndex; calcOpts.ThickHide = cmbThickHide.SelectedIndex; calcOpts.FeralSwiftness = cmbFeralSwiftness.SelectedIndex; calcOpts.FeralCharge = cmbFeralCharge.SelectedIndex; calcOpts.SharpenedClaws = cmbSharpenedClaws.SelectedIndex; calcOpts.ShreddingAttacks = cmbShreddingAttacks.SelectedIndex; calcOpts.PredatoryStrikes = cmbPredatoryStrikes.SelectedIndex; calcOpts.PrimalFury = cmbPrimalFury.SelectedIndex; calcOpts.SavageFury = cmbSavageFury.SelectedIndex; calcOpts.FeralFaerieFire = cmbFeralFaerieFire.SelectedIndex; calcOpts.NurturingInstinct = cmbNurturingInstinct.SelectedIndex; calcOpts.HotW = cmbHotW.SelectedIndex; calcOpts.SotF = cmbSotF.SelectedIndex; calcOpts.PrimalTenacity = cmbPrimalTenacity.SelectedIndex; calcOpts.LotP = cmbLotP.SelectedIndex; calcOpts.ImprovedLotP = cmbImprovedLotP.SelectedIndex; calcOpts.Mangle = cmbMangle.SelectedIndex; calcOpts.PredatoryInstincts = cmbPredatoryInstincts.SelectedIndex; calcOpts.TreeofLife = cmbTreeofLife.SelectedIndex; calcOpts.ImprovedMotW = cmbImprovedMotW.SelectedIndex; calcOpts.EmpoweredRejuv = cmbEmpoweredRejuv.SelectedIndex; calcOpts.Furor = cmbFuror.SelectedIndex; calcOpts.NaturalPerfection = cmbNaturalPerfection.SelectedIndex; calcOpts.Naturalist = cmbNaturalist.SelectedIndex; calcOpts.Swiftmend = cmbSwiftmend.SelectedIndex; calcOpts.NaturesFocus = cmbNaturesFocus.SelectedIndex; calcOpts.LivingSpirit = cmbLivingSpirit.SelectedIndex; calcOpts.NaturalShapeshifter = cmbNaturalShapeshifter.SelectedIndex; calcOpts.ImprovedRegrowth = cmbImprovedRegrowth.SelectedIndex; calcOpts.Intensity = cmbIntensity.SelectedIndex; calcOpts.EmpoweredTouch = cmbEmpoweredTouch.SelectedIndex; calcOpts.Subtlety = cmbSubtlety.SelectedIndex; calcOpts.ImpTranquility = cmbImpTranquility.SelectedIndex; calcOpts.OmenofClarity = cmbOmenofClarity.SelectedIndex; calcOpts.GiftofNature = cmbGiftofNature.SelectedIndex; calcOpts.TranquilSpirit = cmbTranquilSpirit.SelectedIndex; calcOpts.NaturesSwiftness = cmbNaturesSwiftness.SelectedIndex; calcOpts.ImprovedRejuv = cmbImprovedRejuv.SelectedIndex; //ComboBox cb = (ComboBox)sender; //string talent = cb.Name.Substring(3); //Character.CalculationOptions[talent] = cb.SelectedItem.ToString(); Character.OnItemsChanged(); } }
// Load talent points from a character's calculation options. public void LoadCalculationOptions() { _loading = true; CalculationOptionsMoonkin calcOpts = Character.CalculationOptions as CalculationOptionsMoonkin; cmbStarlightWrath.SelectedItem = calcOpts.StarlightWrath.ToString(); cmbForceofNature.SelectedItem = calcOpts.ForceofNature.ToString(); cmbWrathofCenarius.SelectedItem = calcOpts.WrathofCenarius.ToString(); cmbImprovedFF.SelectedItem = calcOpts.ImprovedFF.ToString(); cmbMoonkinForm.SelectedItem = calcOpts.MoonkinForm.ToString(); cmbDreamstate.SelectedItem = calcOpts.Dreamstate.ToString(); cmbBalanceofPower.SelectedItem = calcOpts.BalanceofPower.ToString(); cmbMoonfury.SelectedItem = calcOpts.Moonfury.ToString(); cmbMoonglow.SelectedItem = calcOpts.Moonglow.ToString(); cmbNaturesGrace.SelectedItem = calcOpts.NaturesGrace.ToString(); cmbLunarGuidance.SelectedItem = calcOpts.LunarGuidance.ToString(); cmbCelestialFocus.SelectedItem = calcOpts.CelestialFocus.ToString(); cmbVengeance.SelectedItem = calcOpts.Vengeance.ToString(); cmbNaturesReach.SelectedItem = calcOpts.NaturesReach.ToString(); cmbInsectSwarm.SelectedItem = calcOpts.InsectSwarm.ToString(); cmbBrambles.SelectedItem = calcOpts.Brambles.ToString(); cmbImpMoonfire.SelectedItem = calcOpts.ImpMoonfire.ToString(); cmbFocusedStarlight.SelectedItem = calcOpts.FocusedStarlight.ToString(); cmbControlofNature.SelectedItem = calcOpts.ControlofNature.ToString(); cmbImpNaturesGrasp.SelectedItem = calcOpts.ImpNaturesGrasp.ToString(); cmbNaturesGrasp.SelectedItem = calcOpts.NaturesGrasp.ToString(); cmbFerocity.SelectedItem = calcOpts.Ferocity.ToString(); cmbFeralAggression.SelectedItem = calcOpts.FeralAggression.ToString(); cmbFeralInstinct.SelectedItem = calcOpts.FeralInstinct.ToString(); cmbBrutalImpact.SelectedItem = calcOpts.BrutalImpact.ToString(); cmbThickHide.SelectedItem = calcOpts.ThickHide.ToString(); cmbFeralSwiftness.SelectedItem = calcOpts.FeralSwiftness.ToString(); cmbFeralCharge.SelectedItem = calcOpts.FeralCharge.ToString(); cmbSharpenedClaws.SelectedItem = calcOpts.SharpenedClaws.ToString(); cmbShreddingAttacks.SelectedItem = calcOpts.ShreddingAttacks.ToString(); cmbPredatoryStrikes.SelectedItem = calcOpts.PredatoryStrikes.ToString(); cmbPrimalFury.SelectedItem = calcOpts.PrimalFury.ToString(); cmbSavageFury.SelectedItem = calcOpts.SavageFury.ToString(); cmbFeralFaerieFire.SelectedItem = calcOpts.FeralFaerieFire.ToString(); cmbNurturingInstinct.SelectedItem = calcOpts.NurturingInstinct.ToString(); cmbHotW.SelectedItem = calcOpts.HotW.ToString(); cmbSotF.SelectedItem = calcOpts.SotF.ToString(); cmbPrimalTenacity.SelectedItem = calcOpts.PrimalTenacity.ToString(); cmbLotP.SelectedItem = calcOpts.LotP.ToString(); cmbImprovedLotP.SelectedItem = calcOpts.ImprovedLotP.ToString(); cmbMangle.SelectedItem = calcOpts.Mangle.ToString(); cmbPredatoryInstincts.SelectedItem = calcOpts.PredatoryInstincts.ToString(); cmbTreeofLife.SelectedItem = calcOpts.TreeofLife.ToString(); cmbImprovedMotW.SelectedItem = calcOpts.ImprovedMotW.ToString(); cmbEmpoweredRejuv.SelectedItem = calcOpts.EmpoweredRejuv.ToString(); cmbFuror.SelectedItem = calcOpts.Furor.ToString(); cmbNaturalPerfection.SelectedItem = calcOpts.NaturalPerfection.ToString(); cmbNaturalist.SelectedItem = calcOpts.Naturalist.ToString(); cmbSwiftmend.SelectedItem = calcOpts.Swiftmend.ToString(); cmbNaturesFocus.SelectedItem = calcOpts.NaturesFocus.ToString(); cmbLivingSpirit.SelectedItem = calcOpts.LivingSpirit.ToString(); cmbNaturalShapeshifter.SelectedItem = calcOpts.NaturalShapeshifter.ToString(); cmbImprovedRegrowth.SelectedItem = calcOpts.ImprovedRegrowth.ToString(); cmbIntensity.SelectedItem = calcOpts.Intensity.ToString(); cmbEmpoweredTouch.SelectedItem = calcOpts.EmpoweredTouch.ToString(); cmbSubtlety.SelectedItem = calcOpts.Subtlety.ToString(); cmbImpTranquility.SelectedItem = calcOpts.ImpTranquility.ToString(); cmbOmenofClarity.SelectedItem = calcOpts.OmenofClarity.ToString(); cmbGiftofNature.SelectedItem = calcOpts.GiftofNature.ToString(); cmbTranquilSpirit.SelectedItem = calcOpts.TranquilSpirit.ToString(); cmbNaturesSwiftness.SelectedItem = calcOpts.NaturesSwiftness.ToString(); cmbImprovedRejuv.SelectedItem = calcOpts.ImprovedRejuv.ToString(); _loading = false; //// Iterate through all controls on the form //foreach (Control c in Controls) //{ // // Iterate into group boxes only // if (c is GroupBox) // { // // Iterate through all controls in the group box // foreach (Control innerControl in c.Controls) // { // // Load calculation options into combo boxes only // if (innerControl is ComboBox) // { // // Get the substring that is the actual talent name // ComboBox cb = (ComboBox)innerControl; // string talent = cb.Name.Substring(3); // // If the talent is not in the calculation options, add it // if (!Character.CalculationOptions.ContainsKey(talent)) // Character.CalculationOptions[talent] = "0"; // // Load the value from the character into the combo box // cb.SelectedItem = Character.CalculationOptions[talent]; // } // } // } //} }