public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState, Cycle baseCycle) { Cycle cycle = Cycle.New(needsDisplayCalculations, castingState); cycle.Name = baseCycle.Name; cycle.AreaEffect = baseCycle.AreaEffect; // uptime float fightDuration = castingState.CalculationOptions.FightDuration; float effectDuration = Solver.MirrorImageDuration; float effectCooldown = Solver.MirrorImageCooldown; int activations = 0; float total; if (fightDuration < effectDuration) { total = fightDuration; activations = 1; } else { total = effectDuration; activations = 1; fightDuration -= effectDuration; int count = (int)(fightDuration / effectCooldown); total += effectDuration * count; activations += count; fightDuration -= effectCooldown * count; fightDuration -= effectCooldown - effectDuration; if (fightDuration > 0) { total += fightDuration; activations++; } } Spell mirrorImage = castingState.GetSpell(SpellId.MirrorImage); // activations * gcd in fightDuration float gcd = castingState.Solver.BaseGlobalCooldown + castingState.CalculationOptions.LatencyGCD; cycle.AddCycle(needsDisplayCalculations, baseCycle, (castingState.CalculationOptions.FightDuration - activations * gcd) / baseCycle.CastTime); cycle.CastTime += activations * gcd; cycle.costPerSecond += activations * (int)(0.10 * SpellTemplate.BaseMana[castingState.CalculationOptions.PlayerLevel]); //effectDamagePerSecond += (mirrorImage.AverageDamage + spellPower * mirrorImage.DamagePerSpellPower) / mirrorImage.CastTime; cycle.damagePerSecond += total * mirrorImage.AverageDamage / mirrorImage.CastTime; cycle.DpsPerSpellPower += total * mirrorImage.DamagePerSpellPower / mirrorImage.CastTime; cycle.Calculate(); cycle.Note = baseCycle.Note; return cycle; }
public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState, Cycle baseCycle) { Cycle cycle = Cycle.New(needsDisplayCalculations, castingState); cycle.Name = "Mage Ward+" + baseCycle.Name; Spell MageWard = castingState.GetSpell(SpellId.MageWard); // 1 ward every 30 seconds cycle.AreaEffect = baseCycle.AreaEffect; cycle.AddSpell(needsDisplayCalculations, MageWard, 1); cycle.AddCycle(needsDisplayCalculations, baseCycle, (30 - MageWard.CastTime) / baseCycle.CastTime); cycle.Calculate(); cycle.Note = baseCycle.Note; return cycle; }
public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState, Cycle baseCycle, bool averaged) { Cycle cycle = Cycle.New(needsDisplayCalculations, castingState); cycle.Name = baseCycle.Name; cycle.AreaEffect = baseCycle.AreaEffect; Spell FlameOrb = castingState.GetSpell(SpellId.FlameOrb); // 1 flame orb in 15 seconds // 1 flame orb in 60 seconds (averaged) cycle.AddSpell(needsDisplayCalculations, FlameOrb, 1); cycle.AddCycle(needsDisplayCalculations, baseCycle, ((averaged ? 60 : 15) - FlameOrb.CastTime) / baseCycle.CastTime); cycle.Calculate(); cycle.Note = baseCycle.Note; return cycle; }
public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState, Cycle baseCycle) { Cycle cycle = Cycle.New(needsDisplayCalculations, castingState); cycle.Name = baseCycle.Name; cycle.AreaEffect = baseCycle.AreaEffect; Spell Combustion = castingState.GetSpell(SpellId.Combustion); // 1 combustion in 10 seconds // the dot duplication is currently calculated in individual spells // consider splitting that out for display purposes cycle.AddSpell(needsDisplayCalculations, Combustion, 1); cycle.AddCycle(needsDisplayCalculations, baseCycle, (10 - Combustion.CastTime) / baseCycle.CastTime); cycle.Calculate(); cycle.Note = baseCycle.Note; return cycle; }
public void AddToCycle(Solver solver, Cycle cycle, Spell rawSpell, float weight0, float weight1, float weight2, float weight3, float weight4) { MageTalents mageTalents = solver.MageTalents; float weight = weight0 + weight1 + weight2 + weight3 + weight4; cycle.CastTime += weight * rawSpell.CastTime; cycle.CastProcs += weight * rawSpell.CastProcs; cycle.CastProcs2 += weight * rawSpell.CastProcs2; cycle.NukeProcs += weight * rawSpell.NukeProcs; cycle.NukeProcs2 += weight * rawSpell.NukeProcs2; cycle.Ticks += weight * rawSpell.Ticks; cycle.HitProcs += weight * rawSpell.HitProcs; cycle.CritProcs += weight * rawSpell.CritProcs; cycle.TargetProcs += weight * rawSpell.TargetProcs; cycle.costPerSecond += weight * rawSpell.AverageCost; cycle.DamageProcs += weight * rawSpell.HitProcs; float multiplier = (weight * rawSpell.AdditiveSpellModifier + arcaneBlastDamageMultiplier * (weight1 + 2 * weight2 + 3 * weight3 + 4 * weight4)) / rawSpell.AdditiveSpellModifier; cycle.DpsPerSpellPower += multiplier * rawSpell.DamagePerSpellPower; //cycle.DpsPerMastery += multiplier * rawSpell.DamagePerMastery; cycle.damagePerSecond += multiplier * rawSpell.AverageDamage; cycle.threatPerSecond += multiplier * rawSpell.AverageThreat; }
public void AddToCycle(Solver solver, Cycle cycle, Spell rawSpell, float weight0, float weight1, float weight2, float weight3, float weight4) { MageTalents mageTalents = solver.MageTalents; float weight = weight0 + weight1 + weight2 + weight3 + weight4; float hasteMultiplier = (rawSpell.CastTime - rawSpell.Latency) / (rawSpell.BaseCastTime); // if some are below gcd then we have to use different calculations if (hasteMultiplier * (rawSpell.BaseCastTime - castTimeMultiplier * 0.4f) <= Math.Max(hasteMultiplier * rawSpell.GlobalCooldown, Spell.GlobalCooldownLimit)) { float channelReduction; cycle.CastTime += weight0 * CalculateCastTime(cycle.CastingState, rawSpell.InterruptProtection, rawSpell.CritRate, false, rawSpell.BaseCastTime, out channelReduction); cycle.CastTime += weight1 * CalculateCastTime(cycle.CastingState, rawSpell.InterruptProtection, rawSpell.CritRate, false, rawSpell.BaseCastTime - castTimeMultiplier * 0.1f, out channelReduction); cycle.CastTime += weight2 * CalculateCastTime(cycle.CastingState, rawSpell.InterruptProtection, rawSpell.CritRate, false, rawSpell.BaseCastTime - castTimeMultiplier * 0.2f, out channelReduction); cycle.CastTime += weight3 * CalculateCastTime(cycle.CastingState, rawSpell.InterruptProtection, rawSpell.CritRate, false, rawSpell.BaseCastTime - castTimeMultiplier * 0.3f, out channelReduction); cycle.CastTime += weight4 * CalculateCastTime(cycle.CastingState, rawSpell.InterruptProtection, rawSpell.CritRate, false, rawSpell.BaseCastTime - castTimeMultiplier * 0.4f, out channelReduction); } else { cycle.CastTime += weight * rawSpell.CastTime - castTimeMultiplier * (weight1 * 0.1f + weight2 * 0.2f + weight3 * 0.3f + weight4 * 0.4f) * hasteMultiplier; } cycle.CastProcs += weight * rawSpell.CastProcs; cycle.CastProcs2 += weight * rawSpell.CastProcs2; cycle.NukeProcs += weight * rawSpell.NukeProcs; cycle.NukeProcs2 += weight * rawSpell.NukeProcs2; cycle.Ticks += weight * rawSpell.Ticks; cycle.HitProcs += weight * rawSpell.HitProcs; cycle.CritProcs += weight * rawSpell.CritProcs; cycle.TargetProcs += weight * rawSpell.TargetProcs; cycle.DamageProcs += weight * rawSpell.HitProcs; double roundCost = Math.Round(rawSpell.BaseCost * rawSpell.CostAmplifier); cycle.costPerSecond += (1 - solver.ClearcastingChance) * (weight0 * (float)Math.Floor(roundCost * rawSpell.CostModifier) + weight1 * (float)Math.Floor(roundCost * (rawSpell.CostModifier + arcaneBlastManaMultiplier)) + weight2 * (float)Math.Floor(roundCost * (rawSpell.CostModifier + 2 * arcaneBlastManaMultiplier)) + weight3 * (float)Math.Floor(roundCost * (rawSpell.CostModifier + 3 * arcaneBlastManaMultiplier)) + weight4 * (float)Math.Floor(roundCost * (rawSpell.CostModifier + 4 * arcaneBlastManaMultiplier))); cycle.costPerSecond -= weight * rawSpell.CritRate * rawSpell.BaseCost * 0.15f * mageTalents.MasterOfElements; //cycle.costPerSecond -= weight * BaseUntalentedCastTime / 60f * solver.BaseStats.ManaRestoreFromBaseManaPPM * solver.CalculationOptions.BaseMana; float multiplier = (weight * rawSpell.AdditiveSpellModifier + arcaneBlastDamageMultiplier * (weight1 + 2 * weight2 + 3 * weight3 + 4 * weight4)) / rawSpell.AdditiveSpellModifier; cycle.DpsPerSpellPower += multiplier * rawSpell.DamagePerSpellPower; cycle.DpsPerCrit += multiplier * rawSpell.DamagePerCrit; //cycle.DpsPerMastery += multiplier * rawSpell.DamagePerMastery; cycle.damagePerSecond += multiplier * rawSpell.AverageDamage; cycle.threatPerSecond += multiplier * rawSpell.AverageThreat; }
public Cycle GetCycle(CycleId cycleId) { //Cycle c = Cycles[(int)cycleId]; //if (c != null) return c; Cycle c = null; //if (Cycles.TryGetValue((int)cycleId, out c)) return c; for (int i = 0; i < CyclesCount; i++) { Cycle cycle = Cycles[i]; if (cycle.CycleId == cycleId) return cycle; } if (CalculationOptions.AdvancedHasteProcs) { c = GetAveragedHasteCycle(cycleId); } if (c == null) { c = GetNewCycle(cycleId); } if (c != null) { if (cycleId != CycleId.ArcaneManaNeutral) // if cycle is based on other cycles make sure we don't double count mixins { if (UseMageWard) { c = MageWardCycle.GetCycle(Solver.NeedsDisplayCalculations, this, c); } if (CalculationOptions.MirrorImage == 1) { c = MirrorImageCycle.GetCycle(Solver.NeedsDisplayCalculations, this, c); } if (FlameOrb) { // add flame orb mix-in c = FlameOrbCycle.GetCycle(Solver.NeedsDisplayCalculations, this, c, false); } if (CalculationOptions.PlayerLevel >= 81 && CalculationOptions.FlameOrb == 1) { c = FlameOrbCycle.GetCycle(Solver.NeedsDisplayCalculations, this, c, true); } if (Combustion) { // add combustion mix-in c = CombustionCycle.GetCycle(Solver.NeedsDisplayCalculations, this, c); } } c.CycleId = cycleId; //Cycles[(int)cycleId] = c; //Cycles.Add(c); if (CyclesCount >= Cycles.Length) { int length = 2 * Cycles.Length; Cycle[] destinationArray = new Cycle[length]; Array.Copy(Cycles, 0, destinationArray, 0, CyclesCount); Cycles = destinationArray; } Cycles[CyclesCount++] = c; } return c; }
private void CycleGeneratorComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { string armor; Solver solver; CalculationOptionsMage calculationOptions = character.CalculationOptions as CalculationOptionsMage; CalculationsMage calculations = (CalculationsMage)Calculations.Instance; switch ((string)((ComboBoxItem)CycleGeneratorComboBox.SelectedItem).Content) { case "Arcane": default: armor = "Mage Armor"; solver = new Solver(character, calculationOptions, false, false, false, 0, armor, false, false, false, false, true, false, false); solver.Initialize(null); castingState = new CastingState(solver, 0, false, 0); generator = new ArcaneCycleGeneratorBeta(castingState, true, false, false, false); break; case "Arcane Dragonwrath": armor = "Mage Armor"; solver = new Solver(character, calculationOptions, false, false, false, 0, armor, false, false, false, false, true, false, false); solver.Initialize(null); castingState = new CastingState(solver, 0, false, 0); generator = new ArcaneCycleGeneratorLegendary(castingState, true, false, false, false); break; case "Arcane Hyper Regen": armor = "Mage Armor"; solver = new Solver(character, calculationOptions, false, false, false, 0, armor, false, false, false, false, true, false, false); solver.Initialize(null); castingState = new CastingState(solver, 0, false, 0); generator = new ArcaneCycleGeneratorBeta(castingState, true, false, false, true); break; case "Arcane AOE": armor = "Mage Armor"; solver = new Solver(character, calculationOptions, false, false, false, 0, armor, false, false, false, false, true, false, false); solver.Initialize(null); castingState = new CastingState(solver, 0, false, 0); generator = new ArcaneAOECycleGenerator(castingState, true, false, false); break; case "Frost": armor = "Molten Armor"; solver = new Solver(character, calculationOptions, false, false, false, 0, armor, false, false, false, false, true, false, false); solver.Initialize(null); castingState = new CastingState(solver, 0, false, 0); generator = new FrostCycleGeneratorBeta(castingState, false, 0.0f, false, 0.0f); break; case "Frost+Deep Freeze": armor = "Molten Armor"; solver = new Solver(character, calculationOptions, false, false, false, 0, armor, false, false, false, false, true, false, false); solver.Initialize(null); castingState = new CastingState(solver, 0, false, 0); generator = new FrostCycleGeneratorBeta(castingState, true, 30.0f, false, 0.0f); break; case "Frost+Freeze": armor = "Molten Armor"; solver = new Solver(character, calculationOptions, false, false, false, 0, armor, false, false, false, false, true, false, false); solver.Initialize(null); castingState = new CastingState(solver, 0, false, 0); generator = new FrostCycleGeneratorBeta(castingState, false, 0.0f, true, 25.0f); break; case "Frost+Freeze+Deep Freeze": armor = "Molten Armor"; solver = new Solver(character, calculationOptions, false, false, false, 0, armor, false, false, false, false, true, false, false); solver.Initialize(null); castingState = new CastingState(solver, 0, false, 0); generator = new FrostCycleGeneratorBeta(castingState, true, 30.0f, true, 25.0f); break; } if (castingState == null || generator == null) { return; } if (character.Ranged != null) { wand = new WandTemplate(solver, (MagicSchool)character.Ranged.Item.DamageType, character.Ranged.Item.MinDamage, character.Ranged.Item.MaxDamage, character.Ranged.Item.Speed).GetSpell(castingState); } StringBuilder sb = new StringBuilder(); sb.AppendLine(generator.StateDescription); sb.AppendLine(); for (int i = 0; i < generator.ControlOptions.Length; i++) { sb.Append(i); sb.Append(": "); sb.Append(generator.StateList[Array.IndexOf(generator.ControlIndex, i)]); sb.Append(": "); List<int> keys = new List<int>(); foreach (var kvp in generator.SpellMap[i]) { keys.Add(generator.SpellList.IndexOf(kvp.Key)); } keys.Sort(); foreach (var key in keys) { sb.Append(key); sb.Append("="); sb.Append(generator.SpellList[key]); sb.Append(" "); } sb.AppendLine(); } sb.AppendLine(); sb.AppendLine("Transitions:"); sb.AppendLine(); for (int i = 0; i < generator.ControlOptions.Length; i++) { foreach (var kvp in generator.SpellMap[i]) { sb.Append(i); sb.Append(": "); sb.Append(kvp.Key); sb.Append(" => "); List<int> list = new List<int>(); for (int s = 0; s < generator.ControlIndex.Length; s++) { if (generator.ControlIndex[s] == i) { foreach (CycleControlledStateTransition transition in generator.StateList[s].Transitions) { string n; if (transition.Spell != null) { n = transition.Spell.Name; } else { n = "Pause"; } if (n == kvp.Key) { int target = generator.ControlIndex[transition.TargetState.Index]; if (!list.Contains(target)) { list.Add(target); } } } } } list.Sort(); sb.Append(string.Join(",", list)); sb.AppendLine(); } } Description.Text = sb.ToString(); ControlString.Text = generator.ConvertCycleNameInternalToEasy(new string('0', generator.ControlOptions.Length)); //ControlString.SelectAll(); ControlString.Focus(); Calculate_Click(null, null); }
private void AddSpellsFromCycle(Cycle cycle, double weight) { foreach (var spell in cycle.Spell) { Spell.Add(new SpellData() { Spell = spell.Spell, DotUptime = spell.DotUptime, Weight = (float)weight * spell.Weight }); } }
public void AddCycle(bool needsDisplayCalculations, Cycle cycle, double weight) { if (needsDisplayCalculations) { AddSpellsFromCycle(cycle, weight); } CastTime += weight * cycle.CastTime; CastProcs += weight * cycle.CastProcs; CastProcs2 += weight * cycle.CastProcs2; NukeProcs += weight * cycle.NukeProcs; NukeProcs2 += weight * cycle.NukeProcs2; Ticks += weight * cycle.Ticks; HitProcs += weight * cycle.HitProcs; CritProcs += weight * cycle.CritProcs; IgniteProcs += weight * cycle.IgniteProcs; DotProcs += weight * cycle.DotProcs; TargetProcs += weight * cycle.TargetProcs; DamageProcs += weight * cycle.DamageProcs; Absorbed += weight * cycle.Absorbed; costPerSecond += weight * cycle.CastTime * cycle.costPerSecond; damagePerSecond += weight * cycle.CastTime * cycle.damagePerSecond; threatPerSecond += weight * cycle.CastTime * cycle.threatPerSecond; DpsPerSpellPower += weight * cycle.CastTime * cycle.DpsPerSpellPower; DpsPerMastery += weight * cycle.CastTime * cycle.DpsPerMastery; DpsPerCrit += weight * cycle.CastTime * cycle.DpsPerCrit; }
public List<Cycle> Analyze(CastingState castingState, Cycle wand, System.ComponentModel.BackgroundWorker worker) { Dictionary<string, Cycle> cycleDict = new Dictionary<string, Cycle>(); int j; // reset for (int i = 0; i < ControlValue.Length; i++) { ControlValue[i] = 0; } // count total cycles int total = 0; do { total++; j = ControlValue.Length - 1; ControlValue[j]++; while (ControlValue[j] >= ControlOptions[j]) { ControlValue[j] = 0; j--; if (j < 0) { break; } ControlValue[j]++; } } while (j >= 0); // reset for (int i = 0; i < ControlValue.Length; i++) { ControlValue[i] = 0; } int count = 0; do { if (worker != null && worker.CancellationPending) { break; } if (worker != null && count % 100 == 0) { worker.ReportProgress((100 * count) / total, count + "/" + total); } count++; string name = ""; for (int i = 0; i < ControlValue.Length; i++) { name += ControlValue[i].ToString(); } GenericCycle generic = new GenericCycle(name, castingState, StateList, false); if (!cycleDict.ContainsKey(generic.SpellDistribution)) { cycleDict.Add(generic.SpellDistribution, generic); } // increment control j = ControlValue.Length - 1; ControlValue[j]++; while (ControlValue[j] >= ControlOptions[j]) { ControlValue[j] = 0; j--; if (j < 0) { break; } ControlValue[j]++; } } while (j >= 0); if (wand != null) { cycleDict["Wand"] = wand; } List<Cycle> cyclePalette = new List<Cycle>(); double maxdps = 0; Cycle maxdpsCycle = null; foreach (Cycle cycle in cycleDict.Values) { if (cycle.DamagePerSecond > maxdps) { maxdpsCycle = cycle; maxdps = cycle.DamagePerSecond; } } cyclePalette.Add(maxdpsCycle); Cycle mindpmCycle; do { Cycle highdpsCycle = cyclePalette[cyclePalette.Count - 1]; RESTART: mindpmCycle = null; double mindpm = double.PositiveInfinity; foreach (Cycle cycle in cycleDict.Values) { double dpm = (cycle.DamagePerSecond - highdpsCycle.DamagePerSecond) / (cycle.ManaPerSecond - highdpsCycle.ManaPerSecond); if (dpm > 0 && dpm < mindpm && cycle.ManaPerSecond < highdpsCycle.ManaPerSecond) { mindpm = dpm; mindpmCycle = cycle; } } if (mindpmCycle != null) { // validate cycle pair theory foreach (Cycle cycle in cycleDict.Values) { double dpm = (cycle.DamagePerSecond - mindpmCycle.DamagePerSecond) / (cycle.ManaPerSecond - mindpmCycle.ManaPerSecond); if (cycle != highdpsCycle && cycle.DamagePerSecond > mindpmCycle.DamagePerSecond && dpm > mindpm + 0.000001) { highdpsCycle = cycle; goto RESTART; } } cyclePalette.Add(mindpmCycle); } } while (mindpmCycle != null); return cyclePalette; }
public List<Cycle> Analyze(CastingState castingState, Cycle wand) { return Analyze(castingState, wand, null); }