// Calculate damage and casting time for a single, direct-damage spell. public void DoMainNuke(CharacterCalculationsMoonkin calcs, ref Spell mainNuke, float spellPower, float spellHit, float spellCrit, float spellHaste, float naturesGraceUptime, float latency) { float naturesGraceBonusHaste = 0.15f; float overallDamageModifier = mainNuke.AllDamageModifier * (1 + calcs.BasicStats.BonusSpellDamageMultiplier) * (1 + calcs.BasicStats.BonusDamageMultiplier); // Add a check for the higher of the two spell schools, as Starsurge always chooses the higher one overallDamageModifier *= mainNuke.School == SpellSchool.Arcane ? (1 + calcs.BasicStats.BonusArcaneDamageMultiplier) : (mainNuke.School == SpellSchool.Nature ? (1 + calcs.BasicStats.BonusNatureDamageMultiplier) : (1 + (calcs.BasicStats.BonusArcaneDamageMultiplier > calcs.BasicStats.BonusNatureDamageMultiplier ? calcs.BasicStats.BonusArcaneDamageMultiplier : calcs.BasicStats.BonusNatureDamageMultiplier))); float gcd = 1.5f / (1.0f + spellHaste); float ngGcd = gcd / (1 + naturesGraceBonusHaste); float instantCast = (float)Math.Max(gcd, 1.0f) + latency; float instantCastNG = (float)Math.Max(ngGcd, 1.0f) + latency; float totalCritChance = spellCrit + mainNuke.CriticalChanceModifier; float baseCastTime = (float)Math.Max(mainNuke.BaseCastTime / (1 + spellHaste), instantCast); float ngCastTime = (float)Math.Max(mainNuke.BaseCastTime / (1 + spellHaste) / (1 + naturesGraceBonusHaste), instantCastNG); mainNuke.CastTime = (1 - naturesGraceUptime) * baseCastTime + naturesGraceUptime * ngCastTime; // Damage calculations float damagePerNormalHit = (mainNuke.BaseDamage + mainNuke.SpellDamageModifier * spellPower) * overallDamageModifier; float damagePerCrit = damagePerNormalHit * mainNuke.CriticalDamageModifier; mainNuke.DamagePerHit = (totalCritChance * damagePerCrit + (1 - totalCritChance) * damagePerNormalHit) * spellHit; mainNuke.AverageEnergy = mainNuke.BaseEnergy; }
public Spell(Spell copy) { this.Name = copy.Name; this.School = copy.School == SpellSchool.Arcane ? SpellSchool.Arcane : SpellSchool.Nature; this.BaseCastTime = copy.BaseCastTime; this.BaseDamage = copy.BaseDamage; this.AllDamageModifier = copy.AllDamageModifier; this.BaseManaCost = copy.BaseManaCost; this.CriticalChanceModifier = copy.CriticalChanceModifier; this.CriticalDamageModifier = copy.CriticalDamageModifier; this.DotEffect = copy.DotEffect == null ? null : new DotEffect(copy.DotEffect); this.SpellDamageModifier = copy.SpellDamageModifier; this.BaseEnergy = copy.BaseEnergy; }
// Calculate damage and casting time for a damage-over-time effect. public void DoDotSpell(CharacterCalculationsMoonkin calcs, ref Spell dotSpell, float spellPower, float spellHit, float spellCrit, float spellHaste, float naturesGraceUptime, float latency) { float naturesGraceBonusHaste = 0.15f; float schoolMultiplier = dotSpell.School == SpellSchool.Arcane ? calcs.BasicStats.BonusArcaneDamageMultiplier : calcs.BasicStats.BonusNatureDamageMultiplier; float overallDamageModifier = dotSpell.AllDamageModifier * (1 + calcs.BasicStats.BonusSpellDamageMultiplier) * (1 + calcs.BasicStats.BonusDamageMultiplier) * (1 + schoolMultiplier); float dotEffectDamageModifier = dotSpell.DotEffect.AllDamageModifier * (1 + calcs.BasicStats.BonusSpellDamageMultiplier) * (1 + calcs.BasicStats.BonusDamageMultiplier) * (1 + schoolMultiplier); float gcd = 1.5f / (1.0f + spellHaste); float ngGcd = gcd / (1 + naturesGraceBonusHaste); float instantCast = (float)Math.Max(gcd, 1.0f) + latency; float instantCastNG = (float)Math.Max(ngGcd, 1.0f) + latency; dotSpell.CastTime = naturesGraceUptime * instantCastNG + (1 - naturesGraceUptime) * instantCast; // Flatly calculated tick rate float baseTickRate = dotSpell.DotEffect.BaseTickLength / (1 + spellHaste); float ngTickRate = baseTickRate / (1 + naturesGraceBonusHaste); // Round the tick rate to the nearest millisecond baseTickRate = ((int)Math.Floor(baseTickRate * 1000 + 0.5f)) / 1000f; ngTickRate = ((int)Math.Floor(ngTickRate * 1000 + 0.5f)) / 1000f; // Round the number of ticks up if > .5, down if <= .5 int baseTicks = (int)Math.Ceiling((dotSpell.DotEffect.BaseDuration / baseTickRate) - 0.5f); int ngTicks = (int)Math.Ceiling((dotSpell.DotEffect.BaseDuration / ngTickRate) - 0.5f); dotSpell.DotEffect.NumberOfTicks = naturesGraceUptime * ngTicks + (1 - naturesGraceUptime) * baseTicks; float baseDuration = baseTickRate * baseTicks; float ngDuration = ngTickRate * ngTicks; dotSpell.DotEffect.Duration = naturesGraceUptime * ngDuration + (1 - naturesGraceUptime) * baseDuration; dotSpell.DotEffect.TickLength = (1 - naturesGraceUptime) * baseTickRate + naturesGraceUptime * ngTickRate; float mfDirectDamage = (dotSpell.BaseDamage + dotSpell.SpellDamageModifier * spellPower) * overallDamageModifier; float mfCritDamage = mfDirectDamage * dotSpell.CriticalDamageModifier; float totalCritChance = spellCrit + dotSpell.CriticalChanceModifier; dotSpell.DamagePerHit = (totalCritChance * mfCritDamage + (1 - totalCritChance) * mfDirectDamage) * spellHit; float normalDamagePerTick = dotSpell.DotEffect.TickDamage + dotSpell.DotEffect.SpellDamageModifierPerTick * spellPower; float critDamagePerTick = normalDamagePerTick * dotSpell.CriticalDamageModifier; float damagePerTick = (totalCritChance * critDamagePerTick + (1 - totalCritChance) * normalDamagePerTick) * dotEffectDamageModifier; dotSpell.DotEffect.DamagePerHit = dotSpell.DotEffect.NumberOfTicks * damagePerTick * spellHit; dotSpell.AverageEnergy = dotSpell.BaseEnergy; }