Exemple #1
0
        public virtual void CalculateDerivedStats(CastingState castingState, bool outOfFiveSecondRule, bool pom, bool spammedDot, bool round, bool forceHit, bool forceMiss, bool dotUptime)
        {
            MageTalents            mageTalents        = castingState.MageTalents;
            Stats                  baseStats          = castingState.BaseStats;
            CalculationOptionsMage calculationOptions = castingState.CalculationOptions;

            if (AreaEffect)
            {
                // do not count debuffs for aoe effects, can't assume it will be up on all
                // do not include molten fury (molten fury relates to boss), instead amplify all by average
                if (castingState.MoltenFury)
                {
                    SpellModifier /= (1 + 0.04f * castingState.MageTalents.MoltenFury);
                }
                if (castingState.MageTalents.MoltenFury > 0)
                {
                    SpellModifier *= (1 + 0.04f * castingState.MageTalents.MoltenFury * castingState.CalculationOptions.MoltenFuryPercentage);
                }
            }

            SpellModifier *= AdditiveSpellModifier;

            if (CritRate < 0.0f)
            {
                CritRate = 0.0f;
            }
            if (CritRate > 1.0f)
            {
                CritRate = 1.0f;
            }

            Ticks     = template.Ticks;
            CastProcs = template.CastProcs;
            HitProcs  = Ticks * HitRate;
            if (AreaEffect)
            {
                TargetProcs = HitProcs * castingState.CalculationOptions.AoeTargets;
            }
            else
            {
                TargetProcs = HitProcs;
            }

            Pom = pom;
            if (Instant)
            {
                InterruptProtection = 1;
            }

            CastTime = template.CalculateCastTime(castingState, InterruptProtection, CritRate, pom, BaseCastTime, out ChannelReduction);

            // add crit rate for on use stacking crit effects (would be better if it was computed
            // on cycle level, but right now the architecture doesn't allow that too well)
            // we'd actually need some iterations of this as cast time can depend on crit etc, just ignore that for now
            for (int i = 0; i < castingState.Solver.StackingNonHasteEffectCooldownsCount; i++)
            {
                EffectCooldown effectCooldown = castingState.Solver.StackingNonHasteEffectCooldowns[i];
                if (castingState.EffectsActive(effectCooldown.Mask))
                {
                    Stats stats = effectCooldown.SpecialEffect.Stats;
                    for (int j = 0; j < stats._rawSpecialEffectDataSize; j++)
                    {
                        SpecialEffect effect = stats._rawSpecialEffectData[j];
                        if (effect.Chance == 1f && effect.Cooldown == 0f && (effect.Trigger == Trigger.DamageSpellCrit || effect.Trigger == Trigger.SpellCrit))
                        {
                            if (effect.Stats.CritRating < 0 && effectCooldown.SpecialEffect.Stats.CritRating > 0)
                            {
                                float critScale = castingState.CalculationOptions.LevelScalingFactor / 1400f;
                                CritRate += SpecialEffect.GetAverageStackingCritRate(CastTime, effectCooldown.SpecialEffect.Duration, HitRate, CritRate, effectCooldown.SpecialEffect.Stats.CritRating * critScale, effect.Stats.CritRating * critScale, effect.MaxStack);
                                if (CritRate > 1.0f)
                                {
                                    CritRate = 1.0f;
                                }
                            }
                        }
                    }
                }
            }

            if (castingState.Frozen)
            {
                CritRate *= (1 + castingState.MageTalents.Shatter);
                if (CritRate > 1.0f)
                {
                    CritRate = 1.0f;
                }
            }

            CritProcs = HitProcs * CritRate;
            if ((MagicSchool == MagicSchool.Fire || MagicSchool == MagicSchool.FrostFire) && mageTalents.Ignite > 0)
            {
                IgniteProcs = CritProcs;
            }
            else
            {
                IgniteProcs = 0;
            }

            if (DotTickInterval > 0)
            {
                // non-spammed we have to take into account haste on dot duration and increase in number of ticks
                // probably don't want to take into account haste procs as that might skew optimization thresholds as we're averaging cast time over procs
                // reevaluate this if needed
                float x = DotTickInterval / DotDuration;
                DotExtraTicks   = (float)Math.Floor((castingState.CastingSpeed - 1) / x + 0.5);
                DotFullDuration = (DotDuration + DotTickInterval * DotExtraTicks) / castingState.CastingSpeed;
                if (spammedDot)
                {
                    // spammed dots no longer clip on reapplication
                    DotProcs = Math.Min(CastTime, DotDuration) / DotTickInterval;
                }
                else
                {
                    DotProcs = DotDuration / DotTickInterval + DotExtraTicks;
                }
            }
            else
            {
                DotProcs        = 0;
                DotFullDuration = 0;
                DotExtraTicks   = 0;
            }

            SpammedDot = spammedDot;
            if ((BaseMinDamage > 0 || BasePeriodicDamage > 0) && !forceMiss)
            {
                if (dotUptime)
                {
                    CalculateDirectAverageDamage(castingState.Solver, RawSpellDamage, forceHit);
                    AverageThreat = AverageDamage * ThreatMultiplier;

                    CalculateDotAverageDamage(castingState.Solver, RawSpellDamage, forceHit);
                    DotAverageThreat = DotAverageDamage * ThreatMultiplier;
                }
                else
                {
                    CalculateAverageDamage(castingState.Solver, RawSpellDamage, spammedDot, forceHit);
                    AverageThreat = AverageDamage * ThreatMultiplier;
                }
            }
            else
            {
                AverageDamage             = 0;
                AverageThreat             = 0;
                DamagePerSpellPower       = 0;
                DamagePerMastery          = 0;
                DamagePerCrit             = 0;
                IgniteDamage              = 0;
                IgniteDamagePerSpellPower = 0;
                IgniteDamagePerMastery    = 0;
                IgniteDamagePerCrit       = 0;
                if (dotUptime)
                {
                    DotAverageDamage       = 0;
                    DotAverageThreat       = 0;
                    DotDamagePerSpellPower = 0;
                    DotDamagePerMastery    = 0;
                    DotDamagePerCrit       = 0;
                }
            }
            if (ChannelReduction != 0)
            {
                Ticks               *= (1 - ChannelReduction);
                HitProcs            *= (1 - ChannelReduction);
                CritProcs           *= (1 - ChannelReduction);
                TargetProcs         *= (1 - ChannelReduction);
                CastProcs            = CastProcs2 + (CastProcs - CastProcs2) * (1 - ChannelReduction);
                AverageDamage       *= (1 - ChannelReduction);
                AverageThreat       *= (1 - ChannelReduction);
                DamagePerSpellPower *= (1 - ChannelReduction);
                DamagePerMastery    *= (1 - ChannelReduction);
                DamagePerCrit       *= (1 - ChannelReduction);
            }
            AverageCost = CalculateCost(castingState.Solver, round);

            Absorb      = 0;
            TotalAbsorb = 0;

            if (outOfFiveSecondRule)
            {
                OO5SR = 1;
            }
            else
            {
                OO5SR = 0;
            }
        }
Exemple #2
0
        public virtual void CalculateDerivedStats(CastingState castingState, bool outOfFiveSecondRule, bool pom, bool spammedDot, bool round, bool forceHit, bool forceMiss, bool dotUptime)
        {
            MageTalents            mageTalents        = castingState.MageTalents;
            Stats                  baseStats          = castingState.BaseStats;
            CalculationOptionsMage calculationOptions = castingState.CalculationOptions;

            SpellModifier *= AdditiveSpellModifier;

            if (CritRate < 0.0f)
            {
                CritRate = 0.0f;
            }
            if (CritRate > 1.0f)
            {
                CritRate = 1.0f;
            }

            Ticks     = template.Ticks;
            CastProcs = template.CastProcs;
            HitProcs  = Ticks * HitRate;
            CritProcs = HitProcs * CritRate;
            if ((MagicSchool == MagicSchool.Fire || MagicSchool == MagicSchool.FrostFire) && mageTalents.Ignite > 0)
            {
                IgniteProcs = CritProcs;
            }
            else
            {
                IgniteProcs = 0;
            }
            TargetProcs = HitProcs;

            Pom = pom;
            if (Instant)
            {
                InterruptProtection = 1;
            }

            CastTime = template.CalculateCastTime(castingState, InterruptProtection, CritRate, pom, BaseCastTime, out ChannelReduction);

            // add crit rate for on use stacking crit effects (would be better if it was computed
            // on cycle level, but right now the architecture doesn't allow that too well)
            // we'd actually need some iterations of this as cast time can depend on crit etc, just ignore that for now
            for (int i = 0; i < castingState.Solver.StackingNonHasteEffectCooldownsCount; i++)
            {
                EffectCooldown effectCooldown = castingState.Solver.StackingNonHasteEffectCooldowns[i];
                if (castingState.EffectsActive(effectCooldown.Mask))
                {
                    Stats stats = effectCooldown.SpecialEffect.Stats;
                    for (int j = 0; j < stats._rawSpecialEffectDataSize; j++)
                    {
                        SpecialEffect effect = stats._rawSpecialEffectData[j];
                        if (effect.Chance == 1f && effect.Cooldown == 0f && (effect.Trigger == Trigger.DamageSpellCrit || effect.Trigger == Trigger.SpellCrit))
                        {
                            if (effect.Stats.CritRating < 0 && effectCooldown.SpecialEffect.Stats.CritRating > 0)
                            {
                                float critScale = castingState.CalculationOptions.LevelScalingFactor / 1400f;
                                CritRate += SpecialEffect.GetAverageStackingCritRate(CastTime, effectCooldown.SpecialEffect.Duration, HitRate, CritRate, effectCooldown.SpecialEffect.Stats.CritRating * critScale, effect.Stats.CritRating * critScale, effect.MaxStack);
                                if (CritRate > 1.0f)
                                {
                                    CritRate = 1.0f;
                                }
                            }
                        }
                    }
                }
            }

            if (DotTickInterval > 0)
            {
                if (spammedDot)
                {
                    DotProcs = (float)Math.Floor(Math.Min(CastTime, DotDuration) / DotTickInterval);
                }
                else
                {
                    DotProcs = DotDuration / DotTickInterval;
                }
            }
            else
            {
                DotProcs = 0;
            }

            SpammedDot = spammedDot;
            if (Ticks > 0 && !forceMiss)
            {
                if (dotUptime)
                {
                    AverageDamage = CalculateDirectAverageDamage(castingState.Solver, RawSpellDamage, forceHit, out DamagePerSpellPower, out IgniteDamage, out IgniteDamagePerSpellPower);
                    AverageThreat = AverageDamage * ThreatMultiplier;

                    DotAverageDamage = CalculateDotAverageDamage(baseStats, calculationOptions, RawSpellDamage, forceHit, out DotDamagePerSpellPower);
                    DotAverageThreat = DotAverageDamage * ThreatMultiplier;
                }
                else
                {
                    AverageDamage = CalculateAverageDamage(castingState.Solver, RawSpellDamage, spammedDot, forceHit, out DamagePerSpellPower, out IgniteDamage, out IgniteDamagePerSpellPower);
                    AverageThreat = AverageDamage * ThreatMultiplier;
                }
            }
            else
            {
                AverageDamage             = 0;
                AverageThreat             = 0;
                DamagePerSpellPower       = 0;
                IgniteDamage              = 0;
                IgniteDamagePerSpellPower = 0;
                if (dotUptime)
                {
                    DotAverageDamage       = 0;
                    DotAverageThreat       = 0;
                    DotDamagePerSpellPower = 0;
                }
            }
            if (ChannelReduction != 0)
            {
                Ticks               *= (1 - ChannelReduction);
                HitProcs            *= (1 - ChannelReduction);
                CritProcs           *= (1 - ChannelReduction);
                TargetProcs         *= (1 - ChannelReduction);
                CastProcs            = CastProcs2 + (CastProcs - CastProcs2) * (1 - ChannelReduction);
                AverageDamage       *= (1 - ChannelReduction);
                AverageThreat       *= (1 - ChannelReduction);
                DamagePerSpellPower *= (1 - ChannelReduction);
            }
            AverageCost = CalculateCost(castingState.Solver, round);

            Absorb      = 0;
            TotalAbsorb = 0;

            if (outOfFiveSecondRule)
            {
                OO5SR = 1;
            }
            else
            {
                OO5SR = 0;
            }
        }