public Skill(CombatStats combats, AbilityType abilityType, DamageType damageType, bool usesWeapon, bool righteousVengeance) { Combats = combats; AbilityType = abilityType; DamageType = damageType; UsesWeapon = usesWeapon; RighteousVengeance = righteousVengeance; }
public Simulator(CombatStats combats, Ability[] rotation, decimal simulationTime) : base(combats) { if (rotation == null) { throw new ArgumentNullException("rotation"); } Ability[] effectiveRotation = RemoveUnavailableAbilitiesFromRotation(rotation, combats); Rotation = effectiveRotation; Solution = GetCombinedSolutionWithBloodlust(combats, effectiveRotation, simulationTime); }
protected Rotation(CombatStats combats) { if (combats == null) { throw new ArgumentNullException("combats"); } Combats = combats; CS = combats.Talents.CrusaderStrike == 0 ? (Skill) new NullCrusaderStrike(combats) : (Skill) new CrusaderStrike(combats); DS = combats.Talents.DivineStorm == 0 ? (Skill) new NullCrusaderStrike(combats) : (Skill) new DivineStorm(combats); Exo = new Exorcism(combats); HoW = new HammerOfWrath(combats); Cons = new Consecration(combats); White = new White(combats); HoR = new HandOfReckoning(combats); switch (combats.CalcOpts.Seal) { case SealOf.Righteousness: Seal = new SealOfRighteousness(combats); SealDot = new NullSealDoT(combats); Judge = new JudgementOfRighteousness(combats); break; case SealOf.Command: if (combats.Talents.SealOfCommand == 0) { goto default; } Seal = new SealOfCommand(combats); SealDot = new NullSealDoT(combats); Judge = new JudgementOfCommand(combats); break; case SealOf.Vengeance: float stack = AverageSoVStackSize(); Seal = new SealOfVengeance(combats, stack); SealDot = new SealOfVengeanceDoT(combats, stack); Judge = new JudgementOfVengeance(combats, stack); break; default: Seal = new NullSeal(combats); SealDot = new NullSealDoT(combats); Judge = new NullJudgement(combats); break; } }
/// <summary> /// Calculates the solution with concrete parameters /// </summary> private static RotationSolution GetSolution( CombatStats combats, Ability[] rotation, decimal simulationTime, float divineStormCooldown, float spellHaste) { return(SimulatorEngine.SimulateRotation(new SimulatorParameters( rotation, combats.CalcOpts.Wait, combats.CalcOpts.Delay, combats.Stats.JudgementCDReduction > 0, combats.Talents.ImprovedJudgements, combats.Talents.GlyphOfConsecration, divineStormCooldown, spellHaste, simulationTime))); }
private static Ability[] RemoveUnavailableAbilitiesFromRotation( Ability[] rotation, CombatStats combats) { Ability[] result = rotation; if (combats.Talents.CrusaderStrike == 0) { List <Ability> abilities = new List <Ability>(result); abilities.Remove(Ability.CrusaderStrike); result = abilities.ToArray(); } if (combats.Talents.DivineStorm == 0) { List <Ability> abilities = new List <Ability>(result); abilities.Remove(Ability.DivineStorm); result = abilities.ToArray(); } return(result); }
/// <summary> /// Calculates the solution by combining subsolutions with and withou Bloodlust /// </summary> private static RotationSolution GetCombinedSolutionWithBloodlust( CombatStats combats, Ability[] rotation, decimal simulationTime) { const float bloodlustDuration = 40f; const float secondsPerMinute = 60f; const float bloodlustHaste = 0.3f; // in seconds float fightLengthWithBloodlust = combats.CalcOpts.Bloodlust ? Math.Min(combats.CalcOpts.FightLength * secondsPerMinute, bloodlustDuration) : 0; // in seconds float fightLengthWithoutBloodlust = Math.Max(0, combats.CalcOpts.FightLength * secondsPerMinute - fightLengthWithBloodlust); float bloodlustSpellHaste = (1 + combats.Stats.SpellHaste) * (1 + bloodlustHaste) - 1; float normalSwingTime = combats.BaseWeaponSpeed / (1 + combats.Stats.PhysicalHaste); float bloodlustSwingTime = normalSwingTime / (1 + bloodlustHaste); return(RotationSolution.Combine( () => GetCombinedSolutionWithDivineStormCooldown( combats, rotation, simulationTime, combats.Stats.SpellHaste, normalSwingTime), fightLengthWithoutBloodlust, () => GetCombinedSolutionWithDivineStormCooldown( combats, rotation, simulationTime, bloodlustSpellHaste, bloodlustSwingTime), fightLengthWithBloodlust)); }
/// <summary> /// Calculates the solution by combining subsolutions with the boss above and under 20% health /// </summary> private static RotationSolution GetCombinedSolutionWithUnder20PercentHealth( CombatStats combats, Ability[] rotation, decimal simulationTime, float divineStormCooldown, float spellHaste) { return(RotationSolution.Combine( () => GetSolution( combats, RemoveHammerOfWrathFromRotation(rotation), simulationTime, divineStormCooldown, spellHaste), 1 - combats.CalcOpts.TimeUnder20, () => GetSolution( combats, rotation, simulationTime, divineStormCooldown, spellHaste), combats.CalcOpts.TimeUnder20)); }
public MagicDamage(CombatStats combats, float amount) : base(combats, AbilityType.Spell, DamageType.Magic, false, false) { this.amount = amount; }
public NullJudgement(CombatStats combats) : base(combats, AbilityType.Melee, DamageType.Holy, true, false) { }
public JudgementOfCommand(CombatStats combats) : base(combats, AbilityType.Range, DamageType.Holy, true, true) { }
public NullSealDoT(CombatStats combats) : base(combats, AbilityType.Melee, DamageType.Holy, true, false) { }
public HandOfReckoning(CombatStats combats) : base(combats, AbilityType.Spell, DamageType.Holy, false, false) { }
public White(CombatStats combats) : base(combats, AbilityType.Melee, DamageType.Physical, true, false) { }
public NullDivineStorm(CombatStats combats) : base(combats, AbilityType.Melee, DamageType.Physical, true, true) { }
public JudgementOfVengeance(CombatStats combats, float averageStack) : base(combats, AbilityType.Range, DamageType.Holy, true, true) { AverageStackSize = averageStack; }
public SealOfCommand(CombatStats combats) : base(combats, AbilityType.Melee, DamageType.Holy, true, false) { }
public Consecration(CombatStats combats) : base(combats, AbilityType.Spell, DamageType.Holy, false, false) { }
public Exorcism(CombatStats combats) : base(combats, AbilityType.Spell, DamageType.Holy, false, false) { }
public HammerOfWrath(CombatStats combats) : base(combats, AbilityType.Range, DamageType.Holy, false, false) { }
public JudgementOfRighteousness(CombatStats combats) : base(combats, AbilityType.Range, DamageType.Holy, true, true) { }
public SealOfRighteousness(CombatStats combats) : base(combats, AbilityType.Spell, DamageType.Holy, true, false) { }
public NullCrusaderStrike(CombatStats combats) : base(combats, AbilityType.Melee, DamageType.Physical, true, true) { }
public SealOfVengeanceDoT(CombatStats combats, float averageStack) : base(combats, AbilityType.Spell, DamageType.Holy, false, false) { AverageStackSize = averageStack; }
public SealOfVengeance(CombatStats combats, float averageStack) : base(combats, AbilityType.Melee, DamageType.Holy, true, false) { AverageStackSize = averageStack; }
/// <summary> /// Calculates the solution by combining subsolutions with different Divine Storm cooldowns, /// if 2 piece T10 bonus is active. /// </summary> private static RotationSolution GetCombinedSolutionWithDivineStormCooldown( CombatStats combats, Ability[] rotation, decimal simulationTime, float spellHaste, float swingTime) { const float normalDivineStormCooldown = 10; const float cooldownRangeStep = 0.6f; if (combats.Stats.DivineStormRefresh == 0) { return(GetCombinedSolutionWithUnder20PercentHealth( combats, rotation, simulationTime, normalDivineStormCooldown, spellHaste)); } // Calculate solutions for different Divine Storm cooldowns // and combine them weighted by their neighbourhood cooldown range probabilities RotationSolution result = null; float resultProbability = 0; for ( float cooldownRangeStart = 0; cooldownRangeStart < normalDivineStormCooldown; cooldownRangeStart += cooldownRangeStep) { float currentSolutionProbability = GetT10DivineStormCooldownProbability( swingTime, cooldownRangeStart, Math.Min(normalDivineStormCooldown, cooldownRangeStart + cooldownRangeStep), combats.Stats.DivineStormRefresh); result = RotationSolution.Combine( () => result, resultProbability, () => GetCombinedSolutionWithUnder20PercentHealth( combats, rotation, simulationTime, Math.Min( normalDivineStormCooldown, cooldownRangeStart + cooldownRangeStart / 2 + combats.CalcOpts.Delay), spellHaste), currentSolutionProbability); resultProbability += currentSolutionProbability; } // Combine with normal Divine Storm cooldown in cases when T10 doesn't proc return(RotationSolution.Combine( () => result, resultProbability, () => GetCombinedSolutionWithUnder20PercentHealth( combats, rotation, simulationTime, normalDivineStormCooldown, spellHaste), 1 - resultProbability)); }
public EffectiveCooldown(CombatStats combats) : base(combats) { }