예제 #1
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            Spell FrB;
            float K;
            cycle.Name = "FrBFB";

            FrB = castingState.GetSpell(SpellId.Frostbolt);
            Spell FB = castingState.GetSpell(SpellId.FireballBF);

            // FrB      1 - brainFreeze
            // FrB-FB   brainFreeze

            float T8 = 0;

            K = 0.05f * castingState.MageTalents.BrainFreeze / (1 - T8);

            cycle.AddSpell(needsDisplayCalculations, FrB, 1);
            cycle.AddSpell(needsDisplayCalculations, FB, K);
            cycle.Calculate();
            return cycle;
        }
예제 #2
0
        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;
        }
예제 #3
0
        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;
        }
예제 #4
0
        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;
        }
예제 #5
0
        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;
        }
예제 #6
0
        public FrostCycleGenerator(CastingState castingState, bool useLatencyCombos, bool useDeepFreeze)
        {
            this.useLatencyCombos = useLatencyCombos;

            FrB = castingState.GetSpell(SpellId.Frostbolt);
            FrBS = castingState.FrozenState.GetSpell(SpellId.Frostbolt);
            FB = castingState.GetSpell(SpellId.FireballBF);
            FBS = castingState.FrozenState.GetSpell(SpellId.FireballBF);
            IL = castingState.GetSpell(SpellId.IceLance);
            ILS = castingState.FrozenState.GetSpell(SpellId.IceLance);
            DFS = castingState.FrozenState.GetSpell(SpellId.DeepFreeze);

            BF = 0.05f * castingState.MageTalents.BrainFreeze;
            FOF = (castingState.MageTalents.FingersOfFrost == 2 ? 0.15f : 0.07f * castingState.MageTalents.FingersOfFrost);
            T8 = 0;
            deepFreeze = useDeepFreeze;

            GenerateStateDescription();
        }
예제 #7
0
        public FrostCycleGeneratorBeta(CastingState castingState, bool useDeepFreeze, float deepFreezeCooldown, bool useFreeze, float freezeCooldown)
        {
            this.deepFreezeCooldown = deepFreezeCooldown;
            this.deepFreeze = useDeepFreeze;
            this.freezeCooldown = freezeCooldown;
            this.freeze = useFreeze;

            FrB = castingState.GetSpell(SpellId.Frostbolt);
            FrB.Label = "Frostbolt";
            FFB = castingState.GetSpell(SpellId.FrostfireBoltBF);
            FFB.Label = "FrostfireBolt";
            FFBF = castingState.FrozenState.GetSpell(SpellId.FrostfireBoltBF);
            FFBF.Label = "Frozen+FrostfireBolt";
            IL = castingState.FrozenState.GetSpell(SpellId.IceLance);
            IL.Label = "Frozen+IceLance";
            DF = castingState.FrozenState.GetSpell(SpellId.DeepFreeze);
            DF.Label = "Frozen+DeepFreeze";

            BF = 0.05f * castingState.MageTalents.BrainFreeze;
            FOF = (castingState.MageTalents.FingersOfFrost == 3 ? 0.2f : 0.07f * castingState.MageTalents.FingersOfFrost);

            GenerateStateDescription();
        }
예제 #8
0
        public AB2ABarMBAM(bool needsDisplayCalculations, CastingState castingState)
            : base(needsDisplayCalculations, castingState)
        {
            float K1, K2, K3, K4;
            Name = "AB2ABarMBAM";

            Spell AB0 = castingState.GetSpell(SpellId.ArcaneBlast0);
            Spell AB1 = castingState.GetSpell(SpellId.ArcaneBlast1);
            Spell ABar = castingState.GetSpell(SpellId.ArcaneBarrage);
            Spell ABar2 = castingState.GetSpell(SpellId.ArcaneBarrage2);
            Spell MBAM = castingState.GetSpell(SpellId.ArcaneMissilesMB);
            Spell MBAM2 = castingState.GetSpell(SpellId.ArcaneMissilesMB2);

            float MB = 0.04f * castingState.MageTalents.MissileBarrage;

            //S0:
            //AB0-AB1-ABar2            (1 - MB) * (1 - MB) * (1 - MB)
            //AB0-AB1-ABar2-MBAM       (1 - MB) * (1 - (1 - MB) * (1 - MB))
            //AB0-AB1-MBAM2-ABar       MB * (1 - MB)
            //AB0-AB1-MBAM2-ABar-MBAM  MB * MB


            K1 = (1 - MB) * (1 - MB) * (1 - MB);
            K2 = (1 - MB) * (1 - (1 - MB) * (1 - MB));
            K3 = MB * (1 - MB);
            K4 = MB * MB;

            //AB0-AB1-ABar2
            AddSpell(needsDisplayCalculations, AB0, K1);
            AddSpell(needsDisplayCalculations, AB1, K1);
            if (AB0.CastTime + AB1.CastTime + ABar2.CastTime < 3.0) AddPause(3.0f + castingState.CalculationOptions.LatencyGCD - AB0.CastTime - AB1.CastTime - ABar2.CastTime, K1);
            AddSpell(needsDisplayCalculations, ABar2, K1);

            //AB0-AB1-ABar2-MBAM
            AddSpell(needsDisplayCalculations, AB0, K2);
            AddSpell(needsDisplayCalculations, AB1, K2);
            if (AB0.CastTime + AB1.CastTime + ABar2.CastTime < 3.0) AddPause(3.0f + castingState.CalculationOptions.LatencyGCD - AB0.CastTime - AB1.CastTime - ABar2.CastTime, K2);
            AddSpell(needsDisplayCalculations, ABar2, K2);
            AddSpell(needsDisplayCalculations, MBAM, K2);

            //AB0-AB1-MBAM2-ABar
            AddSpell(needsDisplayCalculations, AB0, K3);
            AddSpell(needsDisplayCalculations, AB1, K3);
            AddSpell(needsDisplayCalculations, MBAM2, K3);
            if (AB0.CastTime + AB1.CastTime + MBAM2.CastTime + ABar.CastTime < 3.0) AddPause(3.0f + castingState.CalculationOptions.LatencyGCD - AB0.CastTime - AB1.CastTime - ABar.CastTime - MBAM2.CastTime, K3);
            AddSpell(needsDisplayCalculations, ABar, K3);

            //AB0-AB1-MBAM2-ABar
            AddSpell(needsDisplayCalculations, AB0, K4);
            AddSpell(needsDisplayCalculations, AB1, K4);
            AddSpell(needsDisplayCalculations, MBAM2, K4);
            if (AB0.CastTime + AB1.CastTime + MBAM2.CastTime + ABar.CastTime < 3.0) AddPause(3.0f + castingState.CalculationOptions.LatencyGCD - AB0.CastTime - AB1.CastTime - ABar.CastTime - MBAM2.CastTime, K4);
            AddSpell(needsDisplayCalculations, ABar, K4);
            AddSpell(needsDisplayCalculations, MBAM, K4);

            Calculate();
        }
예제 #9
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            cycle.Name = "AB4ABar34AM";

            // S0:
            // AB0-AB1-AB2-AB3-ABar                => S0    (1 - MB) * (1 - MB) * (1 - MB) * (1 - MB) * (1 - MB)
            // AB0-AB1-AB2-AB3-ABar-AB0-AB1-AB2-AM => S0    (1 - MB) * (1 - MB) * (1 - MB) * (1 - (1 - MB) * (1 - MB))
            // AB0-AB1-AB2-AB3-AM                  => S0    (1 - MB) * (1 - MB) * MB
            // AB0-AB1-AB2-AM                      => S0    (1 - (1 - MB) * (1 - MB))

            Spell AM = castingState.GetSpell(SpellId.ArcaneMissiles);
            Spell ABar = castingState.GetSpell(SpellId.ArcaneBarrage);

            float MB = 0.4f;
            float K2 = (1 - MB) * (1 - MB);
            float K3 = K2 * (1 - MB);
            float K4 = K2 * K2;
            float K0 = K3 * (1 - K2);
            float K5 = K3 * K2;
            float ABcast;

            Spell AB0 = castingState.GetSpell(SpellId.ArcaneBlast0);
            Spell AB1 = castingState.GetSpell(SpellId.ArcaneBlast1);
            Spell AB2 = castingState.GetSpell(SpellId.ArcaneBlast2);
            Spell AB3 = castingState.GetSpell(SpellId.ArcaneBlast3);
            cycle.AddSpell(needsDisplayCalculations, AB0, 1 + K0);
            cycle.AddSpell(needsDisplayCalculations, AB1, 1 + K0);
            cycle.AddSpell(needsDisplayCalculations, AB2, 1 + K0);
            cycle.AddSpell(needsDisplayCalculations, AB3, K2);
            ABcast = AB0.CastTime;

            cycle.AddSpell(needsDisplayCalculations, AM, 1 - K5);
            cycle.AddSpell(needsDisplayCalculations, ABar, K3);
            // a bit overkill on pause, but make sure we respect the ABar cooldown
            if (4 * ABcast + ABar.CastTime < ABar.Cooldown)
            {
                cycle.AddPause(ABar.Cooldown - 4 * ABcast - ABar.CastTime, K3);
            }

            cycle.Calculate();
            return cycle;
        }
예제 #10
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            cycle.Name = "AB2ABar02AMABABar";

            if (castingState.Solver.Mage2T10)
            {
                // doesn't support haste transferring over several loops

                // S0:
                // AB0-AB1-ABar            => S0    (1-MB)*(1-MB)*(1-MB)
                // AB0-AB1-AM-AB0-ABar     => S0    (1-MB)*(1-MB)*MB
                // AM-AB0-ABar             => S0    (1 - (1-MB)*(1-MB))

                Spell ABar = castingState.GetSpell(SpellId.ArcaneBarrage);
                Spell AM = castingState.GetSpell(SpellId.ArcaneMissiles);                
                Spell AB0T = castingState.Tier10TwoPieceState.GetSpell(SpellId.ArcaneBlast0);
                Spell ABarT = castingState.Tier10TwoPieceState.GetSpell(SpellId.ArcaneBarrage);
                Spell AB0 = castingState.GetSpell(SpellId.ArcaneBlast0);
                Spell AB1 = castingState.GetSpell(SpellId.ArcaneBlast1);

                float MB = 0.4f;
                float K2 = (1 - MB) * (1 - MB);
                float K3 = K2 * (1 - MB);
                float K4 = K2 * K2;

                cycle.AddSpell(needsDisplayCalculations, AB0, K2);
                cycle.AddSpell(needsDisplayCalculations, AB1, K2);
                cycle.AddSpell(needsDisplayCalculations, ABar, K3);
                cycle.AddSpell(needsDisplayCalculations, AM, 1 - K3);
                cycle.AddSpell(needsDisplayCalculations, AB0T, 1 - K3);
                cycle.AddSpell(needsDisplayCalculations, ABarT, 1 - K3);
                if (AB0.CastTime + AB1.CastTime + ABar.CastTime < ABar.Cooldown)
                {
                    cycle.AddPause(ABar.Cooldown - AB0.CastTime - AB1.CastTime - ABar.CastTime, K3);
                }
                if (AM.CastTime + AB0T.CastTime + ABarT.CastTime < ABar.Cooldown)
                {
                    cycle.AddPause(ABar.Cooldown - AM.CastTime - AB0T.CastTime - ABarT.CastTime, 1 - K2);
                }
            }
            else
            {
                Spell ABar = castingState.GetSpell(SpellId.ArcaneBarrage);
                Spell AM = castingState.GetSpell(SpellId.ArcaneMissiles);
                Spell AB0 = castingState.GetSpell(SpellId.ArcaneBlast0);
                Spell AB1 = castingState.GetSpell(SpellId.ArcaneBlast1);

                float MB = 0.4f;
                float K2 = (1 - MB) * (1 - MB);
                float K3 = K2 * (1 - MB);
                float K4 = K2 * K2;

                cycle.AddSpell(needsDisplayCalculations, AB0, K2 + 1 - K3);
                cycle.AddSpell(needsDisplayCalculations, AB1, K2);
                cycle.AddSpell(needsDisplayCalculations, ABar, K3 + 1 - K3);
                cycle.AddSpell(needsDisplayCalculations, AM, 1 - K3);
                if (AB0.CastTime + AB1.CastTime + ABar.CastTime < ABar.Cooldown)
                {
                    cycle.AddPause(ABar.Cooldown - AB0.CastTime - AB1.CastTime - ABar.CastTime, K3);
                }
                if (AM.CastTime + AB0.CastTime + ABar.CastTime < ABar.Cooldown)
                {
                    cycle.AddPause(ABar.Cooldown - AM.CastTime - AB0.CastTime - ABar.CastTime, 1 - K2);
                }
            }

            cycle.Calculate();
            return cycle;
        }
예제 #11
0
        public ABABarSlow(bool needsDisplayCalculations, CastingState castingState)
            : base(needsDisplayCalculations, castingState)
        {
            float MB;
            float X;
            float S0;
            float S1;
            // TODO not updated for 3.0.8 mode, consider deprecated?
            Name = "ABABarSlow";

            Spell AB = castingState.GetSpell(SpellId.ArcaneBlast0);
            Spell ABar = castingState.MaintainSnareState.GetSpell(SpellId.ArcaneBarrage);
            Spell MBAM = castingState.MaintainSnareState.GetSpell(SpellId.ArcaneMissilesMB);
            Spell Slow = castingState.GetSpell(SpellId.Slow);

            MB = 0.04f * castingState.MageTalents.MissileBarrage;

            //S0
            //AB-Pause-ABar     1 - X  (1 - MB) * (1 - MB) => S0, 1 - (1 - MB) * (1 - MB) => S1
            //AB-Slow-ABar      X

            //S1
            //MBAM-Pause-ABar   1 - X  (1 - MB) => S0, MB => S1
            //MBAM-Slow-ABar    X

            //S0 + S1 = 1
            //S0a = (1 - X) * ((1 - MB) * (1 - MB) * S0 + (1 - MB) * S1)
            //S0b = X * ((1 - MB) * (1 - MB) * S0 + (1 - MB) * S1)
            //S1a = (1 - X) * ((1 - (1 - MB) * (1 - MB)) * S0 + MB * S1)
            //S1b = X * ((1 - (1 - MB) * (1 - MB)) * S0 + MB * S1)

            //S0 = (1 - MB) * (1 - MB) * S0 + (1 - MB) * S1
            //S1 = (1 - (1 - MB) * (1 - MB)) * S0 + MB * S1

            //S0 * (1 - (1 - MB) * (1 - MB) + (1 - MB)) = (1 - MB)

            //S0 = (1 - MB) / (1 + (1 - MB) * MB)
            //S1 = (2 - MB) * MB / (1 + (1 - MB) * MB)

            //time casting slow / all time casting = time(Slow) / 15

            //value = (1 - X) * S0 * (value(AB) + value(ABar) + value(Pause)) + X * S0 * (value(AB) + value(ABar) + value(Slow)) + (1 - X) * S1 * (value(MBAM) + value(ABar) + value(Pause)) * X * S1 * (value(MBAM) + value(ABar) + value(Slow))
            //value = S0 * value(AB-ABar) + X * S0 * value(Slow) + S1 * value(MBAM-ABar) + X * S1 * value(Slow) + (1 - X) * value(Pause)
            //value = S0 * value(AB-ABar) + S1 * value(MBAM-ABar) + X * value(Slow) + (1 - X) * value(Pause)

            // X = (S0 * time(AB-ABar) + S1 * time(MBAM-ABar) + time(Pause)) / (15 - time(Slow) + time(Pause))

            S0 = (1 - MB) / (1 + (1 - MB) * MB);
            S1 = (2 - MB) * MB / (1 + (1 - MB) * MB);
            float Pause = 0.0f;
            if (AB.CastTime + ABar.CastTime < 3.0) Pause = 3.0f + castingState.CalculationOptions.LatencyGCD - AB.CastTime - ABar.CastTime;
            X = (S0 * (AB.CastTime + ABar.CastTime) + S1 * (MBAM.CastTime + ABar.CastTime) + Pause) / (15.0f - Slow.CastTime + Pause);

            //AB-ABar
            AddSpell(needsDisplayCalculations, ABar, (1 - X) * S0);
            AddSpell(needsDisplayCalculations, AB, (1 - X) * S0);
            if (AB.CastTime + ABar.CastTime < 3.0) AddPause(3.0f + castingState.CalculationOptions.LatencyGCD - AB.CastTime - ABar.CastTime, (1 - X) * S0);

            //ABar-MBAM
            AddSpell(needsDisplayCalculations, ABar, (1 - X) * S1);
            AddSpell(needsDisplayCalculations, MBAM, (1 - X) * S1);
            if (MBAM.CastTime + ABar.CastTime < 3.0) AddPause(3.0f + castingState.CalculationOptions.LatencyGCD - MBAM.CastTime - ABar.CastTime, (1 - X) * S1);

            //AB-ABar-Slow
            AddSpell(needsDisplayCalculations, ABar, X * S0);
            AddSpell(needsDisplayCalculations, AB, X * S0);
            AddSpell(needsDisplayCalculations, Slow, X * S0);
            if (AB.CastTime + ABar.CastTime + Slow.CastTime < 3.0) AddPause(3.0f + castingState.CalculationOptions.LatencyGCD - AB.CastTime - ABar.CastTime - Slow.CastTime, X * S0);

            //ABar-MBAM-Slow
            AddSpell(needsDisplayCalculations, ABar, X * S1);
            AddSpell(needsDisplayCalculations, MBAM, X * S1);
            AddSpell(needsDisplayCalculations, Slow, X * S1);
            if (MBAM.CastTime + ABar.CastTime + Slow.CastTime < 3.0) AddPause(3.0f + castingState.CalculationOptions.LatencyGCD - MBAM.CastTime - ABar.CastTime - Slow.CastTime, X * S1);

            Calculate();
        }
예제 #12
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            Spell FB;
            Spell Sc;
            Spell Pyro;
            float K;
            float X;
            cycle.Name = "FBScPyro";
            cycle.ProvidesScorch = true;

            FB = castingState.GetSpell(SpellId.Fireball);
            Sc = castingState.GetSpell(SpellId.Scorch);
            Pyro = castingState.GetSpell(SpellId.PyroblastPOMDotUptime);
            Spell PyroSpam = castingState.GetSpell(SpellId.PyroblastPOMSpammed);

            int averageScorchesNeeded = (int)Math.Ceiling(3f / (float)castingState.MageTalents.ImprovedScorch);
            int extraScorches = 0;

            // proportion of time casting non-scorch spells has to be less than gap := (30 - (averageScorchesNeeded + extraScorches)) / (30 - extraScorches)
            // 0 HS charge:
            // FB     => 0 HS charge    (1 - FBcrit) * X
            //        => 1 HS charge    FBcrit * X
            // Sc     => 0 HS charge    (1 - SCcrit) * (1 - X)
            //           1 HS charge    SCcrit * (1 - X)
            // 1 HS charge:
            // FB     => 0 HS charge    (1 - FBcrit) * X + (1 - H) * FBcrit * X
            // FBPyro => 0 HS charge    H * FBcrit * X
            // Sc     => 0 HS charge    (1 - SCcrit) * (1 - X) + (1 - H) * SCcrit * (1 - X)
            // ScPyro => 0 HS charge    H * SCcrit * (1 - X)

            // S0 = FB0a + FB0b + Sc0a + Sc0b
            // S1 = FB1 + FBPyro + Sc1 + ScPyro

            // solve for stationary distribution
            // FB0a = (1 - FBcrit) * X * S0
            // FB0b = FBcrit * X * S0
            // Sc0a = (1 - SCcrit) * (1 - X) * S0
            // Sc0b = SCcrit * (1 - X) * S0
            // FB1 = ((1 - FBcrit) * X + (1 - H) * FBcrit * X) * S1
            // FBPyro = H * FBcrit * X * S1
            // Sc1 = ((1 - SCcrit) * (1 - X) + (1 - H) * SCcrit * (1 - X)) * S1
            // ScPyro = H * SCcrit * (1 - X) * S1

            // S0 + S1 = 1
            // S0 = FB0a + Sc0a + S1
            // S1 = FB0b + Sc0b

            // S1 = (FBcrit * X  + SCcrit * (1 - X)) * S0
            // C := (FBcrit * X  + SCcrit * (1 - X))
            //    = X * (FBcrit - SCcrit) + SCcrit

            // S1 = C * (1 - S1)
            // S1 = C / (1 + C)
            // S0 = 1 / (1 + C)

            // value = (X * value(FB) + (1 - X) * value(Sc)) * 1 / (1 + C) + (X * value(FB) + (1 - X) * value(Sc) + H * (FBcrit * X + SCcrit * (1 - X)) * value(Pyro) / (1 - T8)) * C / (1 + C)
            //         X * value(FB) + (1 - X) * value(Sc) + value(Pyro) * H * C * C / (1 + C) / (1 - T8)

            // (X * time(FB) + time(Pyro) * H * C * C / (1 + C)) / [X * time(FB) + (1 - X) * time(Sc) + time(Pyro) * H * C * C / (1 + C)] = gap
            // (X * time(FB) + time(Pyro) * H * C * C / (1 + C)) = gap * [X * time(FB) + time(Pyro) * H * C * C / (1 + C)] + gap * (1 - X) * time(Sc)
            // (X * time(FB) + time(Pyro) * H * C * C / (1 + C)) * (1 - gap) = gap * (1 - X) * time(Sc)
            // (X * (1 + C) * time(FB) + time(Pyro) * H * C * C) * (1 - gap) = gap * (1 - X) * (1 + C) * time(Sc)
            // (X * (1 + C) * time(FB) + time(Pyro) * H * C * C) * (1 - gap) = gap * (1 + C) * time(Sc) - gap * X * (1 + C) * time(Sc)
            // (X * time(FB) + X * C * time(FB) + time(Pyro) * H * C * C) * (1 - gap) = gap * time(Sc) + gap * C * time(Sc) - gap * X * time(Sc) - gap * X * C * time(Sc)
            // (X * time(FB) + X * (X * (FBcrit - SCcrit) + SCcrit) * time(FB) + time(Pyro) * H * (X * (FBcrit - SCcrit) + SCcrit) * (X * (FBcrit - SCcrit) + SCcrit)) * (1 - gap) = gap * time(Sc) + gap * (X * (FBcrit - SCcrit) + SCcrit) * time(Sc) - gap * X * time(Sc) - gap * X * (X * (FBcrit - SCcrit) + SCcrit) * time(Sc)
            // X * time(FB) * (1 - gap) + X * (X * (FBcrit - SCcrit) + SCcrit) * time(FB) * (1 - gap) + time(Pyro) * H * (X * (FBcrit - SCcrit) + SCcrit) * (X * (FBcrit - SCcrit) + SCcrit) * (1 - gap) = gap * time(Sc) + gap * (X * (FBcrit - SCcrit) + SCcrit) * time(Sc) - gap * X * time(Sc) - gap * X * (X * (FBcrit - SCcrit) + SCcrit) * time(Sc)
            // X * [time(FB) * (1 - gap) + SCcrit * time(FB) * (1 - gap) + 2 * (FBcrit - SCcrit) * SCcrit * time(Pyro) * H * (1 - gap)] + X * X * [(FBcrit - SCcrit) * time(FB) * (1 - gap) + (FBcrit - SCcrit) * (FBcrit - SCcrit) * time(Pyro) * H * (1 - gap)] + SCcrit * SCcrit * time(Pyro) * H * (1 - gap) = gap * time(Sc) + gap * (X * (FBcrit - SCcrit) + SCcrit) * time(Sc) - gap * X * time(Sc) - gap * X * (X * (FBcrit - SCcrit) + SCcrit) * time(Sc)
            // X * X * [(FBcrit - SCcrit) * time(FB) * (1 - gap) + (FBcrit - SCcrit) * (FBcrit - SCcrit) * time(Pyro) * H * (1 - gap) + gap * (FBcrit - SCcrit) * time(Sc)] + X * [time(FB) * (1 - gap) + SCcrit * time(FB) * (1 - gap) + 2 * (FBcrit - SCcrit) * SCcrit * time(Pyro) * H * (1 - gap) - gap * (FBcrit - SCcrit) * time(Sc) + gap * time(Sc) + gap * SCcrit * time(Sc)] + [SCcrit * SCcrit * time(Pyro) * H * (1 - gap) - gap * time(Sc) - gap * SCcrit * time(Sc)] = 0

            // A2 :=
            // (FBcrit - SCcrit) * time(FB) * (1 - gap) + (FBcrit - SCcrit) * (FBcrit - SCcrit) * time(Pyro) * H * (1 - gap) + gap * (FBcrit - SCcrit) * time(Sc)
            // (FBcrit - SCcrit) * [time(FB) * (1 - gap) + (FBcrit - SCcrit) * time(Pyro) * H * (1 - gap) + gap * time(Sc)]
            // (FBcrit - SCcrit) * [time(FB) * (1 - gap) + (FBcrit - SCcrit) * time(Pyro) * H * (1 - gap) - (1 - gap) * time(Sc) + time(Sc)]
            // (FBcrit - SCcrit) * [(1 - gap) * (time(FB) + (FBcrit - SCcrit) * time(Pyro) * H - time(Sc)) + time(Sc)]
            // A1 :=
            // time(FB) * (1 - gap) + SCcrit * time(FB) * (1 - gap) + 2 * (FBcrit - SCcrit) * SCcrit * time(Pyro) * H * (1 - gap) - gap * (FBcrit - SCcrit) * time(Sc) + gap * time(Sc) + gap * SCcrit * time(Sc)
            // time(FB) * [(1 - gap) + SCcrit * (1 - gap)] + time(Pyro) * H * [2 * (FBcrit - SCcrit) * SCcrit * (1 - gap)] + time(Sc) * [gap + gap * SCcrit - gap * (FBcrit - SCcrit)]
            // time(FB) * (1 - gap) * (1 + SCcrit) + time(Pyro) * H * [2 * (FBcrit - SCcrit) * SCcrit * (1 - gap)] + time(Sc) * gap * [1 + 2 * SCcrit - FBcrit]
            // (1 - gap) * [time(FB) * (1 + SCcrit) + time(Pyro) * H * 2 * (FBcrit - SCcrit) * SCcrit - time(Sc) * (1 + 2 * SCcrit - FBcrit)] + time(Sc) * (1 + 2 * SCcrit - FBcrit)
            // A0 :=
            // SCcrit * SCcrit * time(Pyro) * H * (1 - gap) - gap * time(Sc) * (1 + SCcrit)
            // (1 - gap) * (SCcrit * SCcrit * time(Pyro) * H + time(Sc) * (1 + SCcrit)) - time(Sc) * (1 + SCcrit)

            // A2 * X * X + A1 * X + A0 = 0
            // X = [- A1 +/- sqrt[A1 * A1 - 4 * A2 * A0]] / (2 * A2)

            // A1 * A1 - 4 * A2 * A0

            float T8 = 0;

            float gap = (30.0f - (averageScorchesNeeded + extraScorches) * Sc.CastTime) / (30.0f - extraScorches * Sc.CastTime);
            if (castingState.MageTalents.ImprovedScorch == 0)
            {
                cycle.ProvidesScorch = false;
                gap = 1.0f;
            }
            float FBcrit = FB.CritRate;
            float SCcrit = Sc.CritRate;
            float H = castingState.MageTalents.HotStreak / 3.0f;
#if RAWR4
            if (castingState.Solver.Specialization != Specialization.Fire) H = 0.0f;
#else
            if (castingState.MageTalents.Pyroblast == 0) H = 0.0f;
#endif
            float A2 = (FBcrit - SCcrit) * FB.CastTime * (1 - gap) + (FBcrit - SCcrit) * (FBcrit - SCcrit) * Pyro.CastTime / (1 - T8) * H * (1 - gap) + gap * (FBcrit - SCcrit) * Sc.CastTime;
            float A1 = FB.CastTime * (1 - gap) * (1 + SCcrit) + Pyro.CastTime / (1 - T8) * H * (2 * (FBcrit - SCcrit) * SCcrit * (1 - gap)) + Sc.CastTime * gap * (1 + 2 * SCcrit - FBcrit);
            float A0 = SCcrit * SCcrit * Pyro.CastTime / (1 - T8) * H * (1 - gap) - gap * Sc.CastTime * (1 + SCcrit);
            if (Math.Abs(A2) < 0.00001)
            {
                X = -A0 / A1;
            }
            else
            {
                X = (float)((-A1 + Math.Sqrt(A1 * A1 - 4 * A2 * A0)) / (2 * A2));
            }
            if (gap == 1.0f) X = 1.0f; //avoid rounding errors
            float C = X * (FBcrit - SCcrit) + SCcrit;
            K = H * C * C / (1 + C) / (1 - T8);

            float hasteFactor = 1.0f;
            if (castingState.Solver.Mage2T10)
            {
                // p = K / (1 + K)
                // N = (5 * 1.12 - Pyro.CastTime) * (1 + K) / (FB.CastTime * X + LB.CastTime * (1-X) + Pyro.CastTime * K)
                hasteFactor = 1.12f / ((float)Math.Pow(1 - K / (1.0f + K), (5 * 1.12 - Pyro.CastTime) * (1 + K) / (FB.CastTime * X + Sc.CastTime * (1 - X) + Pyro.CastTime * K) + 0.5f) * 0.12f + 1f);
            }


            // pyro dot uptime 

            //A := [x * cFB * DFB + (1 - x) * cLB * DLB]  ~ (x * cFB + (1 - x) * cLB)* D[x * FB + (1 - x) * LB]
            //B := [x * (1-cFB) * DFB + (1 - x) * (1-cLB) * DLB] ~ (1 - (x * cFB + (1- x) * cLB)) * D[x * FB + (1 - x) * LB]

            float averageTicks = 0f;
            float k1 = 0;
            float k2 = C * C * H;
            float totalChance = k2;
            float averageCastTime = X * (FB.CastTime - Sc.CastTime) + Sc.CastTime;
            int n = 2;

            averageTicks += Math.Min((int)(Pyro.CastTime / hasteFactor / 3.0f), 4) * T8;
            averageTicks += Math.Min((int)((Pyro.CastTime + n * averageCastTime) / hasteFactor / 3.0f), 4) * (1 - T8) * k2;

            while ((Pyro.CastTime + n * averageCastTime) / hasteFactor < 12)
            {
                float tmp = k1;
                k1 = k2;
                k2 = C * (1 - C * H) * tmp + (1 - C) * k1;
                totalChance += k2;
                n++;
                averageTicks += Math.Min((int)((Pyro.CastTime + n * averageCastTime) / hasteFactor / 3.0f), 4) * (1 - T8) * k2;
            }
            averageTicks += 4 * (1 - T8) * (1 - totalChance);

            cycle.AddSpell(needsDisplayCalculations, FB, X);
            cycle.AddSpell(needsDisplayCalculations, Sc, 1 - X);
            cycle.AddSpell(needsDisplayCalculations, Pyro, K, averageTicks / 4.0f);
            cycle.CastTime /= hasteFactor;
            cycle.Calculate();
            return cycle;
        }
예제 #13
0
        public static Cycle GetSolvedCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            Spell FrB, FFB, FFBS, ILS, DFS;
            float KFrB, KFFB, KFFBS, KILS, KDFS;
            cycle.Name = "FrBDFFFBIL";

            FrB = castingState.GetSpell(SpellId.Frostbolt);
            FFB = castingState.GetSpell(SpellId.FrostfireBoltBF);
            FFBS = castingState.FrozenState.GetSpell(SpellId.FrostfireBoltBF);
            ILS = castingState.FrozenState.GetSpell(SpellId.IceLance);
            DFS = castingState.FrozenState.GetSpell(SpellId.DeepFreeze);

            // get the right distribution bank
            float[,] castDistribution;
            float[,] castDistributionFFO;
            if (castingState.Solver.Mage4T11)
            {
                castDistribution = CastDistributionT11;
                castDistributionFFO = CastDistributionT11FFO;
            }
            else if (castingState.Solver.Mage4T12)
            {
                castDistribution = CastDistributionT12;
                castDistributionFFO = CastDistributionT12FFO;
            }
            else
            {
                castDistribution = CastDistribution;
                castDistributionFFO = CastDistributionFFO;
            }

            // check if we have interpolation nodes ready
            float r = (castingState.CastingSpeed - 1) / 0.05f;
            int i = (int)r;
            r -= i;

            // if we're out of bounds just use the edge
            if (i + 1 >= 21)
            {
                i = 19;
                r = 1;
            }

            // uncomment this to get code for cast distributions to paste
            /*lock (castDistribution)
            {
                for (i = 0; i < 21; i++)
                {
                    CastingState state = castingState.Clone();
                    state.CastingSpeed = 1 + i * 0.05f;
                    state.ReferenceCastingState = castingState;
                    SolveCycle(state, false, out castDistribution[i, 0], out castDistribution[i, 1], out castDistribution[i, 2], out castDistribution[i, 3], out castDistribution[i, 4]);
                    System.Diagnostics.Trace.WriteLine(string.Format("\t{{{0}f,	{1}f,	{2}f,	{3}f,	{4}f}},", castDistribution[i, 0], castDistribution[i, 1], castDistribution[i, 2], castDistribution[i, 3], castDistribution[i, 4]));
                }
                Console.WriteLine();
                for (i = 0; i < 21; i++)
                {
                    CastingState state = castingState.Clone();
                    state.CastingSpeed = 1 + i * 0.05f;
                    state.ReferenceCastingState = castingState;
                    SolveCycle(state, true, out castDistribution[i, 0], out castDistribution[i, 1], out castDistribution[i, 2], out castDistribution[i, 3], out castDistribution[i, 4]);
                    System.Diagnostics.Trace.WriteLine(string.Format("\t{{{0}f,	{1}f,	{2}f,	{3}f,	{4}f}},", castDistribution[i, 0], castDistribution[i, 1], castDistribution[i, 2], castDistribution[i, 3], castDistribution[i, 4]));
                }
                Console.WriteLine();
            }*/

            if (castingState.CalculationOptions.FlameOrb == 0 || (castingState.CalculationOptions.FlameOrb == 2 && !castingState.FlameOrb))
            {
                KFrB = castDistribution[i, 0] + r * (castDistribution[i + 1, 0] - castDistribution[i, 0]);
                KFFB = castDistribution[i, 1] + r * (castDistribution[i + 1, 1] - castDistribution[i, 1]);
                KFFBS = castDistribution[i, 2] + r * (castDistribution[i + 1, 2] - castDistribution[i, 2]);
                KILS = castDistribution[i, 3] + r * (castDistribution[i + 1, 3] - castDistribution[i, 3]);
                KDFS = castDistribution[i, 4] + r * (castDistribution[i + 1, 4] - castDistribution[i, 4]);
            }
            else if (castingState.CalculationOptions.FlameOrb == 1)
            {
                KFrB = 0.75f * (castDistribution[i, 0] + r * (castDistribution[i + 1, 0] - castDistribution[i, 0])) + 0.25f * (castDistributionFFO[i, 0] + r * (castDistributionFFO[i + 1, 0] - castDistributionFFO[i, 0]));
                KFFB = 0.75f * (castDistribution[i, 1] + r * (castDistribution[i + 1, 1] - castDistribution[i, 1])) + 0.25f * (castDistributionFFO[i, 1] + r * (castDistributionFFO[i + 1, 1] - castDistributionFFO[i, 1]));
                KFFBS = 0.75f * (castDistribution[i, 2] + r * (castDistribution[i + 1, 2] - castDistribution[i, 2])) + 0.25f * (castDistributionFFO[i, 2] + r * (castDistributionFFO[i + 1, 2] - castDistributionFFO[i, 2]));
                KILS = 0.75f * (castDistribution[i, 3] + r * (castDistribution[i + 1, 3] - castDistribution[i, 3])) + 0.25f * (castDistributionFFO[i, 3] + r * (castDistributionFFO[i + 1, 3] - castDistributionFFO[i, 3]));
                KDFS = 0.75f * (castDistribution[i, 4] + r * (castDistribution[i + 1, 4] - castDistribution[i, 4])) + 0.25f * (castDistributionFFO[i, 4] + r * (castDistributionFFO[i + 1, 4] - castDistributionFFO[i, 4]));
            }
            else //if (castingState.CalculationOptions.FlameOrb == 2 && castingState.FlameOrb)
            {
                KFrB = castDistributionFFO[i, 0] + r * (castDistributionFFO[i + 1, 0] - castDistributionFFO[i, 0]);
                KFFB = castDistributionFFO[i, 1] + r * (castDistributionFFO[i + 1, 1] - castDistributionFFO[i, 1]);
                KFFBS = castDistributionFFO[i, 2] + r * (castDistributionFFO[i + 1, 2] - castDistributionFFO[i, 2]);
                KILS = castDistributionFFO[i, 3] + r * (castDistributionFFO[i + 1, 3] - castDistributionFFO[i, 3]);
                KDFS = castDistributionFFO[i, 4] + r * (castDistributionFFO[i + 1, 4] - castDistributionFFO[i, 4]);
            }

            cycle.AddSpell(needsDisplayCalculations, FrB, KFrB);
            cycle.AddSpell(needsDisplayCalculations, FFB, KFFB);
            cycle.AddSpell(needsDisplayCalculations, FFBS, KFFBS);
            cycle.AddSpell(needsDisplayCalculations, ILS, KILS);
            cycle.AddSpell(needsDisplayCalculations, DFS, KDFS);
            cycle.Calculate();
            return cycle;
        }
예제 #14
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState, int targets)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            Spell FFB;
            Spell LB;
            Spell Pyro;
            float X;
            float K = 0;
            if (targets > 1)
            {
                cycle.Name = "FFBLB3Pyro";
                LB = castingState.GetSpell(SpellId.LivingBombAOE);
                cycle.AreaEffect = true;
            }
            else
            {
                cycle.Name = "FFBLBPyro";
                LB = castingState.GetSpell(SpellId.LivingBomb);
            }

            FFB = castingState.GetSpell(SpellId.FrostfireBolt);
            Pyro = castingState.GetSpell(SpellId.PyroblastPOMDotUptime);

            // CATA model

            // LB doesn't interact with hot streak, so we can just use the FBPyro HS model and insert LB as a filler

            // Pyro/FB K = ((FBc^2-FBc)*FBk-FBc^2)/(FBc*FBk-FBc-1)
            // LB/FB X

            // value = value(FB) + X * value(LB) + K * value(Pyro)

            // time(LB) * X / [time(FB) + time(LB) * X + time(Pyro) * K] = time(LB) / LBrecastInterval
            // LBrecastInterval * X = time(FB) + time(LB) * X + time(Pyro) * K
            // (LBrecastInterval - time(LB)) * X = time(FB) + time(Pyro) * K

            // X = (time(FB) + time(Pyro) * K) / (LBrecastInterval - time(LB))

            // more accurate LB uptime model
            // LB is cast every dotduration + half of average non LB spell duration
            // average non lb cast time = (time(FB) + time(Pyro) * K) / (1 + K)

            // LBrecastInterval = LB.DotFullDuration + 0.5 * (time(FB) + time(Pyro) * K) / (1 + K)

            float FFBc = FFB.CritRate;
            float FFBHSc = FFB.CritRate - FFB.NonHSCritRate;
            float FFBk = Math.Max(-2.73f * FFBHSc + 0.95f, 0f);
            if (castingState.Solver.Mage4T12)
            {
                FFBk = Math.Min(0.3f + FFBk, 1f);
            }
            K = ((FFBc * FFBc - FFBc) * FFBk - FFBc * FFBc) / (FFBc * FFBk - FFBc - 1);
            if (castingState.Solver.Specialization != Specialization.Fire) K = 0.0f;

            float LBrecastInterval = LB.DotFullDuration + 0.5f * (FFB.CastTime + Pyro.CastTime * K) / (1 + K);
            X = (FFB.CastTime + Pyro.CastTime * K) / (LBrecastInterval - targets * LB.CastTime);

            // pyro dot uptime 

            float averageDuration = 0f;
            float k0 = 1;
            float k1 = 0;
            float k2 = 0;
            float totalChance = k2;
            float n = 2;

            //averageDuration += Math.Min((Pyro.CastTime + n * (FB.CastTime + X * LB.CastTime)), Pyro.DotFullDuration) * k2;

            while ((Pyro.CastTime + n * (FFB.CastTime + targets * X * LB.CastTime)) < Pyro.DotFullDuration)
            {
                float tmp = k1;
                k2 = k0 * FFBc * FFBk + k1 * FFBc;
                k1 = k0 * FFBc * (1 - FFBk);
                k0 = (k0 + tmp) * (1 - FFBc);
                totalChance += k2;
                n++;
                averageDuration += Math.Min((Pyro.CastTime + n * (FFB.CastTime + targets * X * LB.CastTime)), Pyro.DotFullDuration) * k2;
            }
            averageDuration += Pyro.DotFullDuration * (1 - totalChance);

            cycle.AddSpell(needsDisplayCalculations, FFB, 1);
            cycle.AddSpell(needsDisplayCalculations, LB, targets * X);
            cycle.AddSpell(needsDisplayCalculations, Pyro, K, averageDuration / Pyro.DotFullDuration);
            cycle.Calculate();
            return cycle;
        }
예제 #15
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            Spell FFB;
            float K;
            cycle.Name = "FFBPyro";

            FFB = castingState.GetSpell(SpellId.FrostfireBolt);
            Spell Pyro = castingState.GetSpell(SpellId.PyroblastPOMDotUptime);

            // no Pyro
            // FB => no Pyro 1 - c*c/(1+c)
            //    => Pyro c*c/(1+c)
            // Pyro
            // Pyro => no Pyro

            // 1 - c*c/(1+c)
            // FB

            // c*c/(1+c)

            float T8 = 0;

            K = FFB.CritRate * FFB.CritRate / (1.0f + FFB.CritRate) * castingState.MageTalents.HotStreak / 3.0f / (1 - T8);
#if RAWR4
            if (castingState.Solver.Specialization != Specialization.Fire) K = 0.0f;
#else
            if (castingState.MageTalents.Pyroblast == 0) K = 0.0f;
#endif

            float hasteFactor = 1.0f;
            if (castingState.Solver.Mage2T10)
            {
                // p = K / (1 + K)
                // N = (5 * 1.12 - Pyro.CastTime) * (1 + K) / (FB.CastTime * X + LB.CastTime * (1-X) + Pyro.CastTime * K)
                hasteFactor = 1.12f / ((float)Math.Pow(1 - K / (1.0f + K), (5 * 1.12 - Pyro.CastTime) * (1 + K) / (FFB.CastTime + Pyro.CastTime * K) + 0.5f) * 0.12f + 1f);
            }

            // pyro dot uptime 

            //A := [x * cFB * DFB + (1 - x) * cLB * DLB]  ~ (x * cFB + (1 - x) * cLB)* D[x * FB + (1 - x) * LB]
            //B := [x * (1-cFB) * DFB + (1 - x) * (1-cLB) * DLB] ~ (1 - (x * cFB + (1- x) * cLB)) * D[x * FB + (1 - x) * LB]

            float averageTicks = 0f;
            float C = FFB.CritRate;
            float H = castingState.MageTalents.HotStreak / 3.0f;
            float k1 = 0;
            float k2 = C * C * H;
            float totalChance = k2;
            float averageCastTime = FFB.CastTime;
            int n = 2;

            averageTicks += Math.Min((int)(Pyro.CastTime / hasteFactor / 3.0f), 4) * T8;
            averageTicks += Math.Min((int)((Pyro.CastTime + n * averageCastTime) / hasteFactor / 3.0f), 4) * (1 - T8) * k2;

            while ((Pyro.CastTime + n * averageCastTime) / hasteFactor < 12)
            {
                float tmp = k1;
                k1 = k2;
                k2 = C * (1 - C * H) * tmp + (1 - C) * k1;
                totalChance += k2;
                n++;
                averageTicks += Math.Min((int)((Pyro.CastTime + n * averageCastTime) / hasteFactor / 3.0f), 4) * (1 - T8) * k2;
            }
            averageTicks += 4 * (1 - T8) * (1 - totalChance);

            cycle.AddSpell(needsDisplayCalculations, FFB, 1);
            cycle.AddSpell(needsDisplayCalculations, Pyro, K, averageTicks / 4.0f);
            cycle.CastTime /= hasteFactor;
            cycle.Calculate();
            return cycle;
        }
예제 #16
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            cycle.Name = "AB3ABar023AM";

            if (castingState.Solver.Mage2T10)
            {
                // doesn't support haste transferring over several loops

                // S0:
                // AB0-AB1-AB2-ABar    => S1    (1 - MB) * (1 - MB)
                // AB0-AB1-AB2-AM      => S0    (1 - MB) * MB
                // AB0-AB1-AM          => S0    MB
                // S1:
                // AB0-AB1-AB2-ABar    => S1    (1 - MB) * (1 - MB) * (1 - MB) * (1 - MB)
                // AB0-AB1-AB2-AM      => S0    (1 - MB) * (1 - MB) * (1 - MB) * MB
                // AB0-AB1-AM          => S0    (1 - MB) * (1 - MB) * MB
                // AM                  => S0    (1 - (1 - MB) * (1 - MB))

                // K2 := (1-MB)*(1-MB)
                // K4 := K2 * K2

                // S0 = (1 - K2) * S0 + (1 - K4) * S1
                // S1 = K2 * S0 + K4 * S1
                // S0 + S1 = 1

                // S0 = (1-K4)/(1-K4+K2)

                Spell ABar = castingState.GetSpell(SpellId.ArcaneBarrage);
                Spell AM = castingState.GetSpell(SpellId.ArcaneMissiles);
                Spell AMT = castingState.Tier10TwoPieceState.GetSpell(SpellId.ArcaneMissiles);

                float m2T10time = 5.0f - castingState.CalculationOptions.LatencyChannel;
                Spell AB0A = (m2T10time > 0.0f) ? castingState.Tier10TwoPieceState.GetSpell(SpellId.ArcaneBlast0) : castingState.GetSpell(SpellId.ArcaneBlast0);
                m2T10time -= AB0A.CastTime;
                Spell AB1A = (m2T10time > 0.0f) ? castingState.Tier10TwoPieceState.GetSpell(SpellId.ArcaneBlast1) : castingState.GetSpell(SpellId.ArcaneBlast1);
                m2T10time -= AB1A.CastTime;
                Spell AM2A = (m2T10time > 0.0f) ? castingState.Tier10TwoPieceState.GetSpell(SpellId.ArcaneMissiles) : castingState.GetSpell(SpellId.ArcaneMissiles);
                Spell AB2A = (m2T10time > 0.0f) ? castingState.Tier10TwoPieceState.GetSpell(SpellId.ArcaneBlast2) : castingState.GetSpell(SpellId.ArcaneBlast2);
                m2T10time -= AB2A.CastTime;
                Spell AM3A = (m2T10time > 0.0f) ? castingState.Tier10TwoPieceState.GetSpell(SpellId.ArcaneMissiles) : castingState.GetSpell(SpellId.ArcaneMissiles);
                Spell ABar3A = (m2T10time > 0.0f) ? castingState.Tier10TwoPieceState.GetSpell(SpellId.ArcaneBarrage) : castingState.GetSpell(SpellId.ArcaneBarrage);

                Spell AB0C = castingState.GetSpell(SpellId.ArcaneBlast0);
                Spell AB1C = castingState.GetSpell(SpellId.ArcaneBlast1);
                Spell AMC = castingState.GetSpell(SpellId.ArcaneMissiles);
                Spell AB2C = castingState.GetSpell(SpellId.ArcaneBlast2);
                Spell ABarC = castingState.GetSpell(SpellId.ArcaneBarrage);

                float MB = 0.4f;
                float K2 = (1 - MB) * (1 - MB);
                float K4 = K2 * K2;

                float S0 = (1 - K4) / (1 - K4 + K2);
                float S1 = 1 - S0;

                cycle.AddSpell(needsDisplayCalculations, AB0A, S0);
                cycle.AddSpell(needsDisplayCalculations, AB1A, S0);
                cycle.AddSpell(needsDisplayCalculations, AB2A, S0 * (1 - MB));
                cycle.AddSpell(needsDisplayCalculations, AM2A, S0 * MB);
                cycle.AddSpell(needsDisplayCalculations, AM3A, S0 * (1 - MB) * MB);
                cycle.AddSpell(needsDisplayCalculations, ABar3A, S0 * K2);

                cycle.AddSpell(needsDisplayCalculations, AB0C, S1 * K2);
                cycle.AddSpell(needsDisplayCalculations, AB1C, S1 * K2);
                cycle.AddSpell(needsDisplayCalculations, AB2C, S1 * K2 * (1 - MB));
                cycle.AddSpell(needsDisplayCalculations, AMC, S1 * (1 - K4));
                cycle.AddSpell(needsDisplayCalculations, ABarC, S1 * K4);
            }
            else
            {
                // S0:
                // AB0-AB1-AB2-ABar    => S1    (1 - MB) * (1 - MB) * (1 - MB) * (1 - MB)
                // AB0-AB1-AB2-ABar-AM => S0    (1 - MB) * (1 - MB) * (1 - (1 - MB) * (1 - MB))
                // AB0-AB1-AB2-AM      => S0    (1 - MB) * MB
                // AB0-AB1-AM          => S0    MB

                Spell AM = castingState.GetSpell(SpellId.ArcaneMissiles);
                Spell ABar = castingState.GetSpell(SpellId.ArcaneBarrage);

                float MB = 0.4f;
                float K2 = (1 - MB) * (1 - MB);
                float K4 = K2 * K2;
                float ABcast;

                Spell AB0 = castingState.GetSpell(SpellId.ArcaneBlast0);
                Spell AB1 = castingState.GetSpell(SpellId.ArcaneBlast1);
                Spell AB2 = castingState.GetSpell(SpellId.ArcaneBlast2);
                cycle.AddSpell(needsDisplayCalculations, AB0, 1);
                cycle.AddSpell(needsDisplayCalculations, AB1, 1);
                cycle.AddSpell(needsDisplayCalculations, AB2, 1 - MB);
                ABcast = AB0.CastTime;

                cycle.AddSpell(needsDisplayCalculations, AM, 1 - K4);
                cycle.AddSpell(needsDisplayCalculations, ABar, K2);
                // a bit overkill on pause, but make sure we respect the ABar cooldown
                if (3 * ABcast + ABar.CastTime < ABar.Cooldown)
                {
                    cycle.AddPause(ABar.Cooldown - 3 * ABcast - ABar.CastTime, K2);
                }
            }

            cycle.Calculate();
            return cycle;
        }
예제 #17
0
        public FireCycleGenerator(CastingState castingState)
        {
            FB = new Spell[2];
            Sc = new Spell[2];
            LB = new Spell[2];
            Pyro = new Spell[2];

            FB[0] = castingState.GetSpell(SpellId.Fireball);
            Sc[0] = castingState.GetSpell(SpellId.Scorch);
            LB[0] = castingState.GetSpell(SpellId.LivingBomb);
            Pyro[0] = castingState.GetSpell(SpellId.PyroblastPOM); // does not account for dot uptime
            FB[0].Label = "Fireball";
            Sc[0].Label = "Scorch";
            LB[0].Label = "Living Bomb";
            Pyro[0].Label = "Pyroblast";

            FB[1] = castingState.Tier10TwoPieceState.GetSpell(SpellId.Fireball);
            Sc[1] = castingState.Tier10TwoPieceState.GetSpell(SpellId.Scorch);
            LB[1] = castingState.Tier10TwoPieceState.GetSpell(SpellId.LivingBomb);
            Pyro[1] = castingState.Tier10TwoPieceState.GetSpell(SpellId.PyroblastPOM); // does not account for dot uptime
            FB[1].Label = "2T10:Fireball";
            Sc[1].Label = "2T10:Scorch";
            LB[1].Label = "2T10:Living Bomb";
            Pyro[1].Label = "2T10:Pyroblast";

            HS = castingState.MageTalents.HotStreak / 3.0f;
            T8 = 0;
            //maintainScorch = castingState.CalculationOptions.MaintainScorch;
            livingBombGlyph = castingState.MageTalents.GlyphOfLivingBomb;
            LBDotCritRate = castingState.FireCritRate;
            T10 = castingState.Solver.Mage2T10;

            GenerateStateDescription();
        }
예제 #18
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            Spell FFB;
            Spell Sc;
            Spell Pyro;
            float K;
            float X;
            cycle.Name = "FFBScPyro";
            cycle.ProvidesScorch = true;

            FFB = castingState.GetSpell(SpellId.FrostfireBolt);
            Sc = castingState.GetSpell(SpellId.Scorch);
            Pyro = castingState.GetSpell(SpellId.PyroblastPOMDotUptime);

            int averageScorchesNeeded = (int)Math.Ceiling(3f / (float)castingState.MageTalents.ImprovedScorch);
            int extraScorches = 0;

            float T8 = 0;

            float gap = (30.0f - (averageScorchesNeeded + extraScorches) * Sc.CastTime) / (30.0f - extraScorches * Sc.CastTime);
            if (castingState.MageTalents.ImprovedScorch == 0)
            {
                cycle.ProvidesScorch = false;
                gap = 1.0f;
            }
            float FFBcrit = FFB.CritRate;
            float SCcrit = Sc.CritRate;
            float H = castingState.MageTalents.HotStreak / 3.0f;
#if RAWR4
            if (castingState.Solver.Specialization != Specialization.Fire) H = 0.0f;
#else
            if (castingState.MageTalents.Pyroblast == 0) H = 0.0f;
#endif
            float A2 = (FFBcrit - SCcrit) * FFB.CastTime * (1 - gap) + (FFBcrit - SCcrit) * (FFBcrit - SCcrit) * Pyro.CastTime / (1 - T8) * H * (1 - gap) + gap * (FFBcrit - SCcrit) * Sc.CastTime;
            float A1 = FFB.CastTime * (1 - gap) * (1 + SCcrit) + Pyro.CastTime / (1 - T8) * H * (2 * (FFBcrit - SCcrit) * SCcrit * (1 - gap)) + Sc.CastTime * gap * (1 + 2 * SCcrit - FFBcrit);
            float A0 = SCcrit * SCcrit * Pyro.CastTime / (1 - T8) * H * (1 - gap) - gap * Sc.CastTime * (1 + SCcrit);
            if (Math.Abs(A2) < 0.00001)
            {
                X = -A0 / A1;
            }
            else
            {
                X = (float)((-A1 + Math.Sqrt(A1 * A1 - 4 * A2 * A0)) / (2 * A2));
            }
            if (gap == 1.0f) X = 1.0f; //avoid rounding errors
            float C = X * (FFBcrit - SCcrit) + SCcrit;
            K = H * C * C / (1 + C) / (1 - T8);

            float hasteFactor = 1.0f;
            if (castingState.Solver.Mage2T10)
            {
                // p = K / (1 + K)
                // N = (5 * 1.12 - Pyro.CastTime) * (1 + K) / (FB.CastTime * X + LB.CastTime * (1-X) + Pyro.CastTime * K)
                hasteFactor = 1.12f / ((float)Math.Pow(1 - K / (1.0f + K), (5 * 1.12 - Pyro.CastTime) * (1 + K) / (FFB.CastTime * X + Sc.CastTime * (1 - X) + Pyro.CastTime * K) + 0.5f) * 0.12f + 1f);
            }


            // pyro dot uptime 

            //A := [x * cFB * DFB + (1 - x) * cLB * DLB]  ~ (x * cFB + (1 - x) * cLB)* D[x * FB + (1 - x) * LB]
            //B := [x * (1-cFB) * DFB + (1 - x) * (1-cLB) * DLB] ~ (1 - (x * cFB + (1- x) * cLB)) * D[x * FB + (1 - x) * LB]

            float averageTicks = 0f;
            float k1 = 0;
            float k2 = C * C * H;
            float totalChance = k2;
            float averageCastTime = X * (FFB.CastTime - Sc.CastTime) + Sc.CastTime;
            int n = 2;

            averageTicks += Math.Min((int)(Pyro.CastTime / hasteFactor / 3.0f), 4) * T8;
            averageTicks += Math.Min((int)((Pyro.CastTime + n * averageCastTime) / hasteFactor / 3.0f), 4) * (1 - T8) * k2;

            while ((Pyro.CastTime + n * averageCastTime) / hasteFactor < 12)
            {
                float tmp = k1;
                k1 = k2;
                k2 = C * (1 - C * H) * tmp + (1 - C) * k1;
                totalChance += k2;
                n++;
                averageTicks += Math.Min((int)((Pyro.CastTime + n * averageCastTime) / hasteFactor / 3.0f), 4) * (1 - T8) * k2;
            }
            averageTicks += 4 * (1 - T8) * (1 - totalChance);

            cycle.AddSpell(needsDisplayCalculations, FFB, X);
            cycle.AddSpell(needsDisplayCalculations, Sc, 1 - X);
            cycle.AddSpell(needsDisplayCalculations, Pyro, K, averageTicks / 4.0f);
            cycle.CastTime /= hasteFactor;
            cycle.Calculate();
            return cycle;
        }
예제 #19
0
        public static void SolveCycle(CastingState castingState, bool useFFO, out float KFrB, out float KFFB, out float KFFBS, out float KILS, out float KDFS)
        {
            Spell FrB, FFB, FFBS, ILS, DFS;
            float RFrB = 0, RFFB = 0, RFFBS = 0, RILS = 0, RDFS = 0;
            int CFrB = 0, CFFB = 0, CFFBS = 0, CILS = 0, CDFS = 0;

            FrB = castingState.GetSpell(SpellId.Frostbolt);
            FFB = castingState.GetSpell(SpellId.FrostfireBoltBF);
            FFBS = castingState.FrozenState.GetSpell(SpellId.FrostfireBoltBF);
            ILS = castingState.FrozenState.GetSpell(SpellId.IceLance);
            DFS = castingState.FrozenState.GetSpell(SpellId.DeepFreeze);

            // FFB on FOF only, if Freeze is off cooldown only use it if FOF is off
            // IL on FOF if Freeze is off cooldown, otherwise on FOF2 only

            float bf = 0.05f * castingState.MageTalents.BrainFreeze;
            float fof = (castingState.MageTalents.FingersOfFrost == 3 ? 0.2f : 0.07f * castingState.MageTalents.FingersOfFrost);

            // override this so we don't have to store so many variations (means talent graphs won't show value for this talent)
            bf = 0.3f; // testing possible 4T12 value
            fof = 0.2f;

            float dfCooldown = 0;
            float freezeCooldown = 0;
            int fofActual = 0;
            int fofRegistered = 0;
            bool bfRegistered = false;
            bool bfActual = false;
            float ffo = 1;

            Random rnd = new Random();

            bool stable;
            float errorMargin = 0.000001f;

            do
            {
                for (int c = 0; c < 1000000; c++)
                {
                    if (dfCooldown == 0.0f && (fofRegistered > 0 || freezeCooldown == 0))
                    {
                        CDFS++;
                        if (fofRegistered > 0)
                        {
                            bfRegistered = bfActual;
                            fofActual = Math.Max(0, fofActual - 1);
                            fofRegistered = fofActual;
                            dfCooldown = Math.Max(0, 30f - DFS.CastTime);
                            freezeCooldown = Math.Max(0, freezeCooldown - DFS.CastTime);
                        }
                        else
                        {
                            bfRegistered = bfActual;
                            fofActual = 1;
                            fofRegistered = fofActual;
                            dfCooldown = Math.Max(0, 30f - DFS.CastTime);
                            freezeCooldown = Math.Max(0, 25f - DFS.CastTime);
                        }
                        while (useFFO && ffo < DFS.CastTime)
                        {
                            bool fofProc = rnd.NextDouble() < fof;
                            bool bfProc = rnd.NextDouble() < bf;
                            bfActual = bfProc || bfActual;
                            if (fofProc)
                            {
                                fofActual = Math.Min(2, fofActual + 1);
                            }
                            ffo += 1;
                        }
                        if (useFFO)
                        {
                            ffo -= DFS.CastTime;
                        }
                    }
                    else if (bfRegistered && ((fofRegistered > 0 && freezeCooldown > 0) || (fofRegistered == 0 && freezeCooldown == 0)))
                    {
                        CFFBS++;
                        if (fofRegistered > 0)
                        {
                            bool fofProc = rnd.NextDouble() < fof;
                            bfActual = false;
                            bfRegistered = false;
                            fofActual = Math.Max(0, fofActual - 1);
                            dfCooldown = Math.Max(0, dfCooldown - FFBS.CastTime);
                            freezeCooldown = Math.Max(0, freezeCooldown - FFBS.CastTime);
                            if (fofProc)
                            {
                                fofActual++;
                            }
                            fofRegistered = fofActual;
                        }
                        else
                        {
                            bool fofProc = rnd.NextDouble() < fof;
                            bfActual = false;
                            bfRegistered = false;
                            fofActual = Math.Max(0, 2 - 1);
                            dfCooldown = Math.Max(0, dfCooldown - FFBS.CastTime);
                            freezeCooldown = Math.Max(0, 25.0f - FFBS.CastTime);
                            if (fofProc)
                            {
                                fofActual++;
                            }
                            fofRegistered = fofActual;
                        }
                        while (useFFO && ffo < FFBS.CastTime)
                        {
                            bool fofProc = rnd.NextDouble() < fof;
                            bool bfProc = rnd.NextDouble() < bf;
                            bfActual = bfProc || bfActual;
                            if (fofProc)
                            {
                                fofActual = Math.Min(2, fofActual + 1);
                            }
                            ffo += 1;
                        }
                        if (useFFO)
                        {
                            ffo -= FFBS.CastTime;
                        }
                    }
                    else if (fofRegistered == 2 || (fofRegistered == 1 && freezeCooldown < ILS.CastTime))
                    {
                        CILS++;
                        bfRegistered = bfActual;
                        fofActual = Math.Max(0, fofActual - 1);
                        fofRegistered = fofActual;
                        dfCooldown = Math.Max(0, dfCooldown - ILS.CastTime);
                        freezeCooldown = Math.Max(0, freezeCooldown - ILS.CastTime);
                        while (useFFO && ffo < ILS.CastTime)
                        {
                            bool fofProc = rnd.NextDouble() < fof;
                            bool bfProc = rnd.NextDouble() < bf;
                            bfActual = bfProc || bfActual;
                            if (fofProc)
                            {
                                fofActual = Math.Min(2, fofActual + 1);
                            }
                            ffo += 1;
                        }
                        if (useFFO)
                        {
                            ffo -= ILS.CastTime;
                        }
                    }
                    else if (fofRegistered == 0 && freezeCooldown == 0)
                    {
                        CILS++;
                        bfRegistered = bfActual;
                        fofActual = Math.Max(0, 2 - 1);
                        fofRegistered = fofActual;
                        dfCooldown = Math.Max(0, dfCooldown - ILS.CastTime);
                        freezeCooldown = Math.Max(0, 25.0f - ILS.CastTime);
                        while (useFFO && ffo < ILS.CastTime)
                        {
                            bool fofProc = rnd.NextDouble() < fof;
                            bool bfProc = rnd.NextDouble() < bf;
                            bfActual = bfProc || bfActual;
                            if (fofProc)
                            {
                                fofActual = Math.Min(2, fofActual + 1);
                            }
                            ffo += 1;
                        }
                        if (useFFO)
                        {
                            ffo -= ILS.CastTime;
                        }
                    }
                    else
                    {
                        while (useFFO && ffo < FrB.CastTime)
                        {
                            bool fofProcffo = rnd.NextDouble() < fof;
                            bool bfProcffo = rnd.NextDouble() < bf;
                            bfActual = bfProcffo || bfActual;
                            if (fofProcffo)
                            {
                                fofActual = Math.Min(2, fofActual + 1);
                            }
                            ffo += 1;
                        }
                        if (useFFO)
                        {
                            ffo -= FrB.CastTime;
                        }
                        CFrB++;
                        bool fofProc = rnd.NextDouble() < fof;
                        bool bfProc = rnd.NextDouble() < bf;
                        bfRegistered = bfActual;
                        bfActual = bfProc || bfActual;
                        fofRegistered = fofActual;
                        if (fofProc)
                        {
                            fofActual = Math.Min(2, fofActual + 1);
                        }
                        dfCooldown = Math.Max(0, dfCooldown - FrB.CastTime);
                        freezeCooldown = Math.Max(0, freezeCooldown - FrB.CastTime);
                    }
                }

                float total = CDFS + CFFB + CFFBS + CFrB + CILS;
                KDFS = CDFS / total;
                KFFB = CFFB / total;
                KFFBS = CFFBS / total;
                KFrB = CFrB / total;
                KILS = CILS / total;
                stable = Math.Abs(KDFS - RDFS) < errorMargin &&
                    Math.Abs(KFFB - RFFB) < errorMargin &&
                    Math.Abs(KFFBS - RFFBS) < errorMargin &&
                    Math.Abs(KFrB - RFrB) < errorMargin &&
                    Math.Abs(KILS - RILS) < errorMargin;
                RDFS = KDFS;
                RFFB = KFFB;
                RFFBS = KFFBS;
                RFrB = KFrB;
                RILS = KILS;
            } while (!stable);
        }
예제 #20
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            float K;
            cycle.Name = "FBPyro";

            Spell FB = castingState.GetSpell(SpellId.Fireball);
            Spell Pyro = castingState.GetSpell(SpellId.PyroblastPOMDotUptime);

            // in cata pyro can also proc hot streak (not true, only hardcasted pyro can proc...)
            // using T3 hot streak model from http://elitistjerks.com/f75/t104767-fire_cataclysm_discussion/p12/#post1766032
            // using averaged crit rate model with reset on T3 proc

            // S0: no proc, 0 count
            // FB   => S0   1-FBc
            //      => S1   FBc*(1-FBk)
            //      => S2   FBc*FBk
            // S1: no proc, 1 count
            // FB   => S0   1-FBc
            //      => S2   FBc
            // S2: proc, 0 count
            // Pyro  => S0   1

            // S0 = S0 * (1-FBc) + S1 * (1 - FBc) + S2
            // S1 = S0 * FBc*(1-FBk)
            // S2 = S0 * FBc*FBk + S1 * FBc
            // S0 + S1 + S2 = 1

            // full model

            // S0=-1/(FBc^2*(FBk-1)-FBc-1)
            // S1=(FBc*(FBk-1))/(FBc^2*(FBk-1)-FBc-1)
            // S2=(FBc^2*(FBk-1)-FBc*FBk)/(FBc^2*(FBk-1)-FBc-1)

            // pyro per FB ratio

            // ((FBc^2-FBc)*FBk-FBc^2)/(FBc*FBk-FBc-1)

            float FBc = FB.CritRate;
            float FBHSc = FB.CritRate - FB.NonHSCritRate;
            float FBk = Math.Max(-2.73f * FBHSc + 0.95f, 0f);
            if (castingState.Solver.Mage4T12)
            {
                // basing on http://elitistjerks.com/f75/t110326-cataclysm_fire_mage_compendium/p21/#post1946836
                FBk = Math.Min(0.3f + FBk, 1f);
            }
            K = ((FBc * FBc - FBc) * FBk - FBc * FBc) / (FBc * FBk - FBc - 1);
            if (castingState.Solver.Specialization != Specialization.Fire) K = 0.0f;

            // CATA model for Pyro dot uptime

            // S0: no proc, 0 count
            // FB   => S0   1-FBc
            //      => S1   FBc*(1-FBk)
            //      => S2   FBc*FBk
            // S1: no proc, 1 count
            // FB   => S0   1-FBc
            //      => S2   FBc
            // S2: proc, 0 count
            // Pyro  => S0   1

            // k0 = 1
            // k1 = 0
            // k2 = 0

            // n=>n+1

            // k0' = (k0+k1)*(1-FBc)
            // k1' = k0*FBc*(1-FBk)
            // k2' = k0*FBc*FBk + k1*FBc

            float averageDuration = 0f;
            float C = FB.CritRate;
            float HS = castingState.MageTalents.HotStreak / 3.0f;
            float k0 = 1;
            float k1 = 0;
            float k2 = 0;
            float totalChance = k2;
            float n = 2; // heuristic filler to account for realistic dot uptime

            //averageDuration += Math.Min((Pyro.CastTime + n * FB.CastTime), Pyro.DotFullDuration) * k2;            

            while ((Pyro.CastTime + n * FB.CastTime) < Pyro.DotFullDuration)
            {
                float tmp = k1;
                k2 = k0 * FBc * FBk + k1 * FBc;
                k1 = k0 * FBc * (1 - FBk);
                k0 = (k0 + tmp) * (1 - FBc);
                totalChance += k2;
                n++;
                averageDuration += Math.Min((Pyro.CastTime + n * FB.CastTime), Pyro.DotFullDuration) * k2;
            }
            averageDuration += Pyro.DotFullDuration * (1 - totalChance);


            cycle.AddSpell(needsDisplayCalculations, FB, 1);
            cycle.AddSpell(needsDisplayCalculations, Pyro, K, averageDuration / Pyro.DotFullDuration);
            cycle.Calculate();
            return cycle;
        }
예제 #21
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            Spell FrB, FrBS, FB, FBS, ILS;
            float KFrB, KFrBS, KFB, KFBS, KILS;
            cycle.Name = "FrBFBIL";

            float T8 = 0;

            // S00: FOF0, BF0
            // FrB => S21    fof * bf
            //        S20    fof * (1-bf)
            //        S01    (1-fof) * bf
            //        S00    (1-fof)*(1-bf)

            // S01: FOF0, BF1
            // FrB => S22    fof
            //        S02    (1-fof)

            // S02: FOF0, BF2
            // FB => S00    (1-T8)
            //    => S02    T8

            // S10: FOF1, BF0
            // FrBS-ILS => S12    fof * bf
            //             S10    fof * (1-bf)
            //             S02    (1-fof) * bf
            //             S00    (1-fof)*(1-bf)

            // S11: FOF1, BF1
            // FrBS-FBS => S10    fof*(1-T8)
            //             S11    fof*T8
            //             S00    (1-fof)*(1-T8)
            //             S02    (1-fof)*T8

            // S12 = S11

            // S20: FOF0, BF0
            // FrBS => S21    fof * bf
            //         S20    fof * (1-bf)
            //         S11    (1-fof) * bf
            //         S10    (1-fof)*(1-bf)

            // S21: FOF0, BF1
            // FrBS => S22    fof
            //         S12    (1-fof)

            // S22 = S21

            // S00 = (1-fof)*(1-bf) * S00 + S02*(1-T8) + (1-fof)*(1-bf) * S10 + (1-fof)*(1-T8) * S11
            // S01 = (1-fof) * bf * S00
            // S02 = (1-fof) * S01 + T8 * S02 + (1-fof) * bf * S10 + (1-fof)*T8 * S11
            // S10 = fof * (1-bf) * S10 + fof*(1-T8) * S11 + (1-fof)*(1-bf) * S20
            // S11 = fof * bf * S10 + fof*T8 * S11 + (1-fof) * bf * S20 + (1-fof) * S21
            // S20 = fof * (1-bf) * S00 + fof * (1-bf) * S20
            // S21 = fof * bf * S00 + fof * S01 + fof * bf * S20 + fof * S21
            // S00 + S01 + S02 + S10 + S11 + S20 + S21 = 1

            // solved symbolically

            float bf = 0.05f * castingState.MageTalents.BrainFreeze;
            float fof = (castingState.MageTalents.FingersOfFrost == 2 ? 0.15f : 0.07f * castingState.MageTalents.FingersOfFrost);

            //float div = ((bf * bf * bf - bf) * fof * fof * fof * fof + (3 * bf - bf * bf * bf) * fof * fof * fof + (bf * bf * bf - 4 * bf + 1) * fof * fof * fof + (-bf * bf * bf - 2 * bf * bf + 2 * bf) * fof - 2 * bf - 1);
            //float S00 = ((bf * bf - bf) * fof * fof * fof + (-bf * bf + 3 * bf - 1) * fof * fof + (2 - 2 * bf) * fof - 1) / div;
            //float S01 = -((bf * bf * bf - bf * bf) * fof * fof * fof * fof + (-2 * bf * bf * bf + 4 * bf * bf - bf) * fof * fof * fof + (bf * bf * bf - 5 * bf * bf + 3 * bf) * fof * fof + (2 * bf * bf - 3 * bf) * fof + bf) / div;
            //float S02 = ((bf * bf - bf) * fof * fof * fof * fof + (-bf * bf * bf - bf * bf + 3 * bf) * fof * fof * fof + (2 * bf * bf * bf - 4 * bf) * fof * fof + (3 * bf - bf * bf * bf) * fof - bf) / div;
            //float S10 = ((bf * bf - bf) * fof * fof * fof * fof + (3 * bf - 2 * bf * bf) * fof * fof * fof + (2 * bf * bf - 5 * bf + 1) * fof * fof + (-bf * bf + 2 * bf - 1) * fof) / div;
            //float S11 = ((bf * bf * bf - 2 * bf * bf + bf) * fof * fof * fof * fof + (-bf * bf * bf + 4 * bf * bf - 3 * bf) * fof * fof * fof + (5 * bf - 4 * bf * bf) * fof * fof + (bf * bf - 3 * bf) * fof) / div;
            //float S20 = -((bf * bf - bf) * fof * fof * fof + (-bf * bf + 2 * bf - 1) * fof * fof + (1 - bf) * fof) / div;
            //float S21 = ((bf * bf * bf - bf * bf) * fof * fof * fof * fof + (-bf * bf * bf + 3 * bf * bf - bf) * fof * fof * fof + (2 * bf - 3 * bf * bf) * fof * fof - 2 * bf * fof) / div;

            float S00 = (fof - 1) * ((bf - 1) * fof + 1) * (T8 - 1) * (fof * (T8 - bf) - 1);
            float S01 = -bf * (fof - 1) * (fof - 1) * ((bf - 1) * fof + 1) * (T8 - 1) * (fof * (T8 - bf) - 1);
            float S02 = -bf * (fof - 1) * (fof * ((fof - 1) * ((bf - 1) * fof - bf + 2) * T8 - fof * ((bf - 1) * fof - bf * bf + 2) - bf * bf + 2) - 1);
            float S10 = fof * (T8 - 1) * (fof * ((bf * (fof - 1) - 1) * ((bf - 1) * fof + 1) * T8 - bf * (fof * ((bf - 1) * fof - 2 * bf + 3) + 2 * bf - 5) - 1) + (bf - 1) * (bf - 1));
            float S11 = -bf * fof * (fof * ((bf - 1) * fof * ((bf - 1) * fof - bf + 3) - 4 * bf + 5) + bf - 3) * (T8 - 1);
            float S20 = -(bf - 1) * (fof - 1) * fof * (T8 - 1) * (fof * (T8 - bf) - 1);
            float S21 = bf * fof * (fof * ((bf - 1) * fof - bf + 2) - 2) * (T8 - 1) * (fof * (T8 - bf) - 1);

            float div = S00 + S01 + S02 + S10 + S11 + S20 + S21;

            KFrB = (S00 + S01) / div;
            KFB = S02 / div;
            KFrBS = (S10 + S11 + S20 + S21) / div;
            KFBS = S11 / div;
            KILS = S10 / div;

            FrB = castingState.GetSpell(SpellId.Frostbolt);
            FrBS = castingState.FrozenState.GetSpell(SpellId.Frostbolt);
            FB = castingState.GetSpell(SpellId.FireballBF);
            FBS = castingState.FrozenState.GetSpell(SpellId.FireballBF);
            ILS = castingState.FrozenState.GetSpell(SpellId.IceLance);

            cycle.AddSpell(needsDisplayCalculations, FrB, KFrB);
            cycle.AddSpell(needsDisplayCalculations, FB, KFB);
            cycle.AddSpell(needsDisplayCalculations, FrBS, KFrBS);
            cycle.AddSpell(needsDisplayCalculations, FBS, KFBS);
            cycle.AddSpell(needsDisplayCalculations, ILS, KILS);
            cycle.Calculate();
            return cycle;
        }
예제 #22
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            Spell FB;
            Spell Sc;
            Spell LB;
            Spell Pyro;
            float K;
            float X;
            float Y;
            cycle.Name = "FBScLBPyro";
            cycle.ProvidesScorch = true;

            FB = castingState.GetSpell(SpellId.Fireball);
            Sc = castingState.GetSpell(SpellId.Scorch);
            LB = castingState.GetSpell(SpellId.LivingBomb);
            Pyro = castingState.GetSpell(SpellId.PyroblastPOMDotUptime);

            int averageScorchesNeeded = (int)Math.Ceiling(3f / (float)castingState.MageTalents.ImprovedScorch);
            int extraScorches = 0;

            float T8 = 0;
            float C, H, averageCastTime;

                // 3.1 calculations

                // 0 HS charge:
                // FB     => 0 HS charge    (1 - FBcrit) * X
                //        => 1 HS charge    FBcrit * X
                // LB     => 0 HS charge    (1 - LBcrit) * (1 - X - Y)
                //        => 1 HS charge    LBcrit * (1 - X - Y)
                // Sc     => 0 HS charge    (1 - SCcrit) * Y
                //           1 HS charge    SCcrit * Y
                // 1 HS charge:
                // FB     => 0 HS charge    (1 - FBcrit) * X + (1 - H) * FBcrit * X
                // FBPyro => 0 HS charge    H * FBcrit * X
                // LB     => 0 HS charge    (1 - LBcrit) * (1 - X - Y) + (1 - H) * LBcrit * (1 - X - Y)
                // LBPyro => 0 HS charge    H * LBcrit * (1 - X - Y)
                // Sc     => 0 HS charge    (1 - SCcrit) * Y + (1 - H) * SCcrit * Y
                // ScPyro => 0 HS charge    H * SCcrit * Y

                // S0 + S1 = 1
                // C := FBcrit * X + SCcrit * Y + LBcrit * (1 - X - Y)
                // S0 = S0 * (1 - C) + S1
                // S1 = S0 * C
                // 1 - S0 = S0 * C
                // S0 = 1 / (1 + C)
                // S1 = C / (1 + C)

                // value = (X * value(FB) + Y * value(Sc) + (1 - X - Y) * value(LB)) * 1 / (1 + C) + (X * value(FB) + Y * value(Sc) + (1 - X - Y) * value(LB) + H * C * value(Pyro)) * C / (1 + C)
                //         X * value(FB) + Y * value(Sc) + (1 - X - Y) * value(LB) + value(Pyro) * H * C * C / (1 + C) / (1 - T8)

                // (1 - X - Y) * time(LB) / [X * time(FB) + Y * time(Sc) + (1 - X - Y) * time(LB) + time(Pyro) / (1 - T8) * H * C * C / (1 + C)] = time(LB) / 12
                // Z = 1 - X - Y
                // Z * time(LB) / [X * time(FB) + Y * time(Sc) + Z * time(LB) + time(Pyro) / (1 - T8) * H * C * C / (1 + C)] = time(LB) / 12
                // 12 * Z = X * time(FB) + Y * time(Sc) + Z * time(LB) + time(Pyro) * H * C * C / (1 + C) / (1 - T8)
                // T := X * time(FB) + Y * time(Sc) + Z * time(LB) + time(Pyro) * H * C * C / (1 + C) / (1 - T8)
                // 12 * Z = T

                // (X * time(FB) + Z * time(LB) + time(Pyro) * H * C * C / (1 + C) / (1 - T8)) / T = gap
                // (T - Y * time(Sc)) / T = gap
                // T * (1 - gap) = Y * time(Sc)
                // if gap = 1 => Y = 0
                // 12 * Z * (1 - gap) = Y * time(Sc)
                // X = 1 - Y * [1 + time(Sc) / (12 * (1 - gap))]
                // P := 1 + time(Sc) / (12 * (1 - gap))
                // X = 1 - P * Y
                // Z = 1 - X - Y = 1 - 1 + P * Y - Y = Y * (P - 1)
                // C = (FBcrit * X  + SCcrit * Y + LBcrit * Z)
                //     (FBcrit * (1 - P * Y) + SCcrit * Y + LBcrit * Y * (P - 1))
                //     (FBcrit + Y * (SCcrit - FBcrit * P + LBcrit * (P - 1)))
                // C / (1 + C) = (FBcrit + Y * (SCcrit - FBcrit * P + LBcrit * (P - 1))) / (1 + FBcrit + Y * (SCcrit - FBcrit * P + LBcrit * (P - 1)))
                // 12 * Y * (P - 1) = T
                // CY := SCcrit - FBcrit * P + LBcrit * (P - 1)
                // C = FBcrit + Y * CY

                // T =
                // X * time(FB) + Y * time(Sc) + Z * time(LB) + time(Pyro) * H * C * C / (1 + C) / (1 - T8)
                // (1 - P * Y) * time(FB) + Y * time(Sc) + Y * (P - 1) * time(LB) + time(Pyro) * H * C * C / (1 + C) / (1 - T8)
                // time(FB) + Y * [time(Sc) - P * time(FB) + (P - 1) * time(LB)] + time(Pyro) * H * C * C / (1 + C) / (1 - T8)

                // 0 = time(FB) + Y * [time(Sc) - P * time(FB) + (P - 1) * time(LB) - 12 * (P - 1)] + time(Pyro) * H * C * C / (1 + C) / (1 - T8)
                // T1 := time(Sc) - P * time(FB) + (P - 1) * time(LB) - 12 * (P - 1)
                // 0 = time(FB) + Y * T1 + time(Pyro) * H * C * C / (1 + C) / (1 - T8)
                // 0 = time(FB) + C * time(FB) + Y * T1 + Y * C * T1 + time(Pyro) / (1 - T8) * H * C * C
                // 0 = time(FB) + (FBcrit + Y * CY) * time(FB) + Y * T1 + Y * (FBcrit + Y * CY) * T1 + time(Pyro) / (1 - T8) * H * (FBcrit + Y * CY) * (FBcrit + Y * CY)
                // 0 = [time(FB) + FBcrit * time(FB) + time(Pyro) / (1 - T8) * H * FBcrit * FBcrit] + Y * [CY * time(FB) + T1 + FBcrit * T1 + 2 * time(Pyro) / (1 - T8) * H * FBcrit * CY] + Y * Y * [CY * T1 + time(Pyro) / (1 - T8) * H * CY * CY]

                float gap = (30.0f - (averageScorchesNeeded + extraScorches) * Sc.CastTime) / (30.0f - extraScorches * Sc.CastTime);
                if (castingState.MageTalents.ImprovedScorch == 0)
                {
                    cycle.ProvidesScorch = false;
                    gap = 1.0f;
                }
                float hasteFactor = 1.0f;

                if (gap == 1.0f)
                {
                    Y = 0.0f;
                    float FBcrit = FB.CritRate;
                    float LBcrit = LB.CritRate;
                    H = castingState.MageTalents.HotStreak / 3.0f;
#if RAWR4
                    if (castingState.Solver.Specialization != Specialization.Fire) H = 0.0f;
#else
                    if (castingState.MageTalents.Pyroblast == 0) H = 0.0f;
#endif
                    float A2 = (FBcrit - LBcrit) * (LB.CastTime - FB.CastTime - 12) - (FBcrit - LBcrit) * (FBcrit - LBcrit) * Pyro.CastTime / (1 - T8) * H;
                    float A1 = (FBcrit - LBcrit) * (12 - LB.CastTime) + (LB.CastTime - FB.CastTime - 12) * (1 + LBcrit) - Pyro.CastTime / (1 - T8) * H * 2 * LBcrit * (FBcrit - LBcrit);
                    float A0 = (1 + LBcrit) * (12 - LB.CastTime) - Pyro.CastTime / (1 - T8) * H * LBcrit * LBcrit;
                    if (Math.Abs(A2) < 0.00001)
                    {
                        X = -A0 / A1;
                    }
                    else
                    {
                        X = (float)((-A1 - Math.Sqrt(A1 * A1 - 4 * A2 * A0)) / (2 * A2));
                    }
                    C = LBcrit + X * (FBcrit - LBcrit);
                    K = H * C * C / (1 + C) / (1 - T8);

                    // first order correction for lower LB uptime
                    if (castingState.Solver.Mage2T10)
                    {
                        // p = K / (1 + K)
                        // N = (5 * 1.12 - Pyro.CastTime) * (1 + K) / (FB.CastTime * X + LB.CastTime * (1-X) + Pyro.CastTime * K)
                        hasteFactor = 1.12f / ((float)Math.Pow(1 - K / (1.0f + K), (5 * 1.12 - Pyro.CastTime) * (1 + K) / (FB.CastTime * X + LB.CastTime * (1 - X) + Pyro.CastTime * K) + 0.5f) * 0.12f + 1f);
                    }

                    // LBrecastInterval = 12 + 0.5 * ((time(FB) * X + time(Pyro) * K) / (X + K))
                    float LBrecastInterval = 12 + 0.5f * ((FB.CastTime * FB.CastTime * X + Pyro.CastTime * Pyro.CastTime * K) / (FB.CastTime * X + Pyro.CastTime * K)) / hasteFactor;

                    // now recalculate the spell distribution under the new uptime assumption
                    A2 = (FBcrit - LBcrit) * (LB.CastTime / hasteFactor - FB.CastTime / hasteFactor - LBrecastInterval) - (FBcrit - LBcrit) * (FBcrit - LBcrit) * Pyro.CastTime / hasteFactor / (1 - T8) * H;
                    A1 = (FBcrit - LBcrit) * (LBrecastInterval - LB.CastTime / hasteFactor) + (LB.CastTime / hasteFactor - FB.CastTime / hasteFactor - LBrecastInterval) * (1 + LBcrit) - Pyro.CastTime / hasteFactor / (1 - T8) * H * 2 * LBcrit * (FBcrit - LBcrit);
                    A0 = (1 + LBcrit) * (LBrecastInterval - LB.CastTime / hasteFactor) - Pyro.CastTime / hasteFactor / (1 - T8) * H * LBcrit * LBcrit;
                    if (Math.Abs(A2) < 0.00001)
                    {
                        X = -A0 / A1;
                    }
                    else
                    {
                        X = (float)((-A1 - Math.Sqrt(A1 * A1 - 4 * A2 * A0)) / (2 * A2));
                    }
                    C = LBcrit + X * (FBcrit - LBcrit);
                    averageCastTime = LB.CastTime + X * (FB.CastTime - LB.CastTime);
                    K = H * C * C / (1 + C) / (1 - T8);
                }
                else
                {
                    float P = 1.0f + Sc.CastTime / (12.0f * (1.0f - gap));
                    float FBcrit = FB.CritRate;
                    float SCcrit = Sc.CritRate;
                    float LBcrit = LB.CritRate;
                    H = castingState.MageTalents.HotStreak / 3.0f;
#if RAWR4
                    if (castingState.Solver.Specialization != Specialization.Fire) H = 0.0f;
#else
                    if (castingState.MageTalents.Pyroblast == 0) H = 0.0f;
#endif
                    float T1 = Sc.CastTime - P * FB.CastTime + (P - 1) * LB.CastTime - 12 * (P - 1);
                    float CY = SCcrit - FBcrit * P + LBcrit * (P - 1);

                    float A2 = CY * T1 + Pyro.CastTime / (1 - T8) * H * CY * CY;
                    float A1 = CY * FB.CastTime + T1 + FBcrit * T1 + 2 * Pyro.CastTime / (1 - T8) * H * FBcrit * CY;
                    float A0 = FB.CastTime + FBcrit * FB.CastTime + Pyro.CastTime / (1 - T8) * H * FBcrit * FBcrit;
                    if (Math.Abs(A2) < 0.00001)
                    {
                        Y = -A0 / A1;
                    }
                    else
                    {
                        Y = (float)((-A1 - Math.Sqrt(A1 * A1 - 4 * A2 * A0)) / (2 * A2));
                    }
                    X = 1 - P * Y;
                    C = (FBcrit * X + SCcrit * Y + LBcrit * (1 - X - Y));
                    K = H * C * C / (1 + C) / (1 - T8);

                    if (castingState.Solver.Mage2T10)
                    {
                        // p = K / (1 + K)
                        // N = (5 * 1.12 - Pyro.CastTime) * (1 + K) / (FB.CastTime * X + LB.CastTime * (1-X) + Pyro.CastTime * K)
                        hasteFactor = 1.12f / ((float)Math.Pow(1 - K / (1.0f + K), (5 * 1.12 - Pyro.CastTime) * (1 + K) / (FB.CastTime * X + Sc.CastTime * Y + LB.CastTime * (1 - X - Y) + Pyro.CastTime * K) + 0.5f) * 0.12f + 1f);
                    }

                    float LBrecastInterval = 12 + 0.5f * ((FB.CastTime * FB.CastTime * X + Sc.CastTime * Sc.CastTime * Y + Pyro.CastTime * Pyro.CastTime * K) / (FB.CastTime * X + Sc.CastTime * Y + Pyro.CastTime * K)) / hasteFactor;

                    P = 1.0f + Sc.CastTime / hasteFactor / (LBrecastInterval * (1.0f - gap));
                    T1 = Sc.CastTime / hasteFactor - P * FB.CastTime / hasteFactor + (P - 1) * LB.CastTime / hasteFactor - LBrecastInterval * (P - 1);
                    CY = SCcrit - FBcrit * P + LBcrit * (P - 1);

                    A2 = CY * T1 + Pyro.CastTime / hasteFactor / (1 - T8) * H * CY * CY;
                    A1 = CY * FB.CastTime / hasteFactor + T1 + FBcrit * T1 + 2 * Pyro.CastTime / hasteFactor / (1 - T8) * H * FBcrit * CY;
                    A0 = FB.CastTime / hasteFactor + FBcrit * FB.CastTime / hasteFactor + Pyro.CastTime / hasteFactor / (1 - T8) * H * FBcrit * FBcrit;
                    if (Math.Abs(A2) < 0.00001)
                    {
                        Y = -A0 / A1;
                    }
                    else
                    {
                        Y = (float)((-A1 - Math.Sqrt(A1 * A1 - 4 * A2 * A0)) / (2 * A2));
                    }
                    X = 1 - P * Y;
                    C = (FBcrit * X + SCcrit * Y + LBcrit * (1 - X - Y));
                    averageCastTime = (FB.CastTime * X + Sc.CastTime * Y + LB.CastTime * (1 - X - Y));
                    K = H * C * C / (1 + C) / (1 - T8);
                }

            // pyro dot uptime 

            //A := [x * cFB * DFB + (1 - x) * cLB * DLB]  ~ (x * cFB + (1 - x) * cLB)* D[x * FB + (1 - x) * LB]
            //B := [x * (1-cFB) * DFB + (1 - x) * (1-cLB) * DLB] ~ (1 - (x * cFB + (1- x) * cLB)) * D[x * FB + (1 - x) * LB]

            float averageTicks = 0f;
            float k1 = 0;
            float k2 = C * C * H;
            float totalChance = k2;
            int n = 2;

            averageTicks += Math.Min((int)(Pyro.CastTime / hasteFactor / 3.0f), 4) * T8;
            averageTicks += Math.Min((int)((Pyro.CastTime + n * averageCastTime) / hasteFactor / 3.0f), 4) * (1 - T8) * k2;

            while ((Pyro.CastTime + n * averageCastTime) / hasteFactor < 12)
            {
                float tmp = k1;
                k1 = k2;
                k2 = C * (1 - C * H) * tmp + (1 - C) * k1;
                totalChance += k2;
                n++;
                averageTicks += Math.Min((int)((Pyro.CastTime + n * averageCastTime) / hasteFactor / 3.0f), 4) * (1 - T8) * k2;
            }
            averageTicks += 4 * (1 - T8) * (1 - totalChance);

            cycle.AddSpell(needsDisplayCalculations, FB, X);
            cycle.AddSpell(needsDisplayCalculations, Sc, Y);
            cycle.AddSpell(needsDisplayCalculations, LB, 1 - X - Y);
            cycle.AddSpell(needsDisplayCalculations, Pyro, K, averageTicks / 4.0f);
            cycle.CastTime /= hasteFactor;
            cycle.Calculate();
            return cycle;
        }
예제 #23
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            Spell FrB, FFB, FFBS, ILS, DFS;
            float KFrB, KFrB2, KFFB, KFFBS, KILS, KDFS;
            cycle.Name = "FrBDFFFBIL";

            // S00: FOF00, BF00
            // FrB => S11    fof * bf * (1-Y)
            //        S10    fof * (1-bf) * (1-Y)
            //        S01    (1-fof) * bf * (1-Y)
            //        S00    (1-fof)*(1-bf) * (1-Y)
            // -   => S40    Y

            // S01: FOF00, BF10
            // FrB => S12    fof * (1-Y)
            //        S02    (1-fof) * (1-Y)
            // -   => S41    Y

            // S02: FOF00, BF11
            // FrB => S12    fof * (1-Y)
            //        S02    (1-fof) * (1-Y)
            // -   => S42    Y

            // S10: FOF10, BF00
            // FrB => S31    fof * bf * (1-Y)
            //        S30    fof * (1-bf) * (1-Y)
            //        S21    (1-fof) * bf * (1-Y)
            //        S20    (1-fof)*(1-bf) * (1-Y)
            // -   => S40    Y

            // S11: FOF10, BF10
            // FrB => S32    fof * (1-Y)
            //        S22    (1-fof) * (1-Y)
            // -   => S41    Y

            // S12: FOF10, BF11
            // FrB => S32    (1-fof) * (1-Y)
            //        S22    fof * (1-Y)
            // -   => S42    Y

            // S20: FOF11, BF00
            // FrB => S31    fof * bf * (1-X)
            //        S30    fof * (1-bf) * (1-X)
            //        S21    (1-fof) * bf * (1-X)
            //        S20    (1-fof)*(1-bf) * (1-X)
            // DF  => S00    X

            // S21: FOF11, BF10
            // FrB => S32    fof * (1-X)
            //        S22    (1-fof) * (1-X)
            // DF  => S02    X

            // S22: FOF11, BF11
            // FFBS => S00   (1-fof)*(1-X)
            //         S20   fof*(1-X)
            // DF   => S02   X

            // S30: FOF21, B00
            // FrB => S41    bf * (1-X)
            //        S40    (1-bf) * (1-X)
            // DF  => S20    X

            // S31: FOF21, BF10
            // FrB => S42    (1-X)
            // DF  => S22    X

            // S32: FOF21, BF11
            // FFBS => S20   (1-fof)*(1-X)
            //         S40   fof*(1-X)
            // DF   => S22   X

            // S40: FOF22, B00
            // IL  => S20    1-X
            // DF  => S20    X

            // S41: FOF22, B10
            // IL  => S22    1-X
            // DF  => S22    X

            // S42: FOF22, BF11
            // FFBS => S20   (1-fof)*(1-X)
            //         S40   fof*(1-X)
            // DF   => S22   X

            // S00 = S00 * (1-fof)*(1-bf) * (1-Y) + S20 * X + S22 * (1-fof)*(1-X)
            // S01 = S00 * (1-fof) * bf * (1-Y)
            // S02 = S01 * (1-fof) * (1-Y) + S02 * (1-fof) * (1-Y) + S21 * X + S22 * X
            // S10 = S00 * fof * (1-bf) * (1-Y)
            // S11 = S00 * fof * bf * (1-Y)
            // S12 = S01 * fof * (1-Y) + S02 * fof * (1-Y)
            // S20 = S10 * (1-fof)*(1-bf) * (1-Y) + S20 * (1-fof)*(1-bf) * (1-X) + S22 * fof*(1-X) + S30 * X + S32 * (1-fof)*(1-X) + S40 + S42 * (1-fof)*(1-X)
            // S21 = S10 * (1-fof) * bf * (1-Y) + S20 * (1-fof) * bf * (1-X)
            // S22 = S11 * (1-fof) * (1-Y) + S12 * fof * (1-Y) + S21 * (1-fof) * (1-X) + S31 * X + S32 * X + S41 + S42 * X
            // S30 = S10 * fof * (1-bf) * (1-Y) + S20 * fof * (1-bf) * (1-X)
            // S31 = S10 * fof * bf * (1-Y) + S20 * fof * bf * (1-X)
            // S32 = S11 * fof * (1-Y) + S12 * (1-fof) * (1-Y) + S21 * fof * (1-X)
            // S40 = S00 * Y + S10 * Y + S30 * (1-bf) * (1-X) + S32 * fof*(1-X) + S42 * fof*(1-X)
            // S41 = S01 * Y + S11 * Y + S30 * bf * (1-X)
            // S42 = S02 * Y + S12 * Y + S31 * (1-X)
            // S00 + S01 + S02 + S10 + S11 + S12 + S20 + S21 + S22 + S30 + S31 + S32 + S40 + S41 + S42 = 1

            // solved symbolically
            // solve([S00 = S00 * (1-fof)*(1-bf) * (1-Y) + S20 * X + S22 * (1-fof)*(1-X),S01 = S00 * (1-fof) * bf * (1-Y),S02 = S01 * (1-fof) * (1-Y) + S02 * (1-fof) * (1-Y) + S21 * X + S22 * X,S10 = S00 * fof * (1-bf) * (1-Y),S11 = S00 * fof * bf * (1-Y),S12 = S01 * fof * (1-Y) + S02 * fof * (1-Y),S20 = S10 * (1-fof)*(1-bf) * (1-Y) + S20 * (1-fof)*(1-bf) * (1-X) + S22 * fof*(1-X) + S30 * X + S32 * (1-fof)*(1-X) + S40 + S42 * (1-fof)*(1-X),S21 = S10 * (1-fof) * bf * (1-Y) + S20 * (1-fof) * bf * (1-X),S22 = S11 * (1-fof) * (1-Y) + S12 * fof * (1-Y) + S21 * (1-fof) * (1-X) + S31 * X + S32 * X + S41 + S42 * X,S30 = S10 * fof * (1-bf) * (1-Y) + S20 * fof * (1-bf) * (1-X),S31 = S10 * fof * bf * (1-Y) + S20 * fof * bf * (1-X),S32 = S11 * fof * (1-Y) + S12 * (1-fof) * (1-Y) + S21 * fof * (1-X),S40 = S00 * Y + S10 * Y + S30 * (1-bf) * (1-X) + S32 * fof*(1-X) + S42 * fof*(1-X),S41 = S01 * Y + S11 * Y + S30 * bf * (1-X),S42 = S02 * Y + S12 * Y + S31 * (1-X),S00 + S01 + S02 + S10 + S11 + S12 + S20 + S21 + S22 + S30 + S31 + S32 + S40 + S41 + S42 = 1,fof=0.2,bf=0.15], [S00,S01,S02,S10,S11,S12,S20,S21,S22,S30,S31,S32,S40,S41,S42,fof,bf]);

            // S00=((480000*X^4-6440000*X^3+6440000*X^2-480000*X)*Y^2+(-6240000*X^4+126440000*X^3-33880000*X^2-76600000*X-9720000)*Y-840000*X^4+21950000*X^3+1190000*X^2-19870000*X-2430000)
            // S02=((57600*X^4-772800*X^3+772800*X^2-57600*X)*Y^3+(1853100*X^4-3543525*X^3+10315725*X^2-10646400*X-1166400)*Y^2+(-8469000*X^4+9007950*X^3+23115150*X^2-861900*X+2332800)*Y-191700*X^4-2629125*X^3+671325*X^2-18621600*X-1166400)
            // S20=((81600*X^3-163200*X^2+81600*X)*Y^4+(-1224000*X^3-11899600*X^2+22031200*X-8907600)*Y^3+(2060400*X^3+88837500*X^2-27086200*X-63811700)*Y^2+(-775200*X^3+43676600*X^2+2752400*X-45653800)*Y-142800*X^3+4548700*X^2+2221000*X-6626900)
            // S01 = S00 * (1-fof) * bf * (1-Y)
            // S10 = S00 * fof * (1-bf) * (1-Y)
            // S11 = S00 * fof * bf * (1-Y)
            // S21 = S10 * (1-fof) * bf * (1-Y) + S20 * (1-fof) * bf * (1-X)
            // S30 = S10 * fof * (1-bf) * (1-Y) + S20 * fof * (1-bf) * (1-X)
            // S31 = S10 * fof * bf * (1-Y) + S20 * fof * bf * (1-X)
            // S12 = S01 * fof * (1-Y) + S02 * fof * (1-Y)
            // S32 = S11 * fof * (1-Y) + S12 * (1-fof) * (1-Y) + S21 * fof * (1-X)
            // S41 = S01 * Y + S11 * Y + S30 * bf * (1-X)
            // S42 = S02 * Y + S12 * Y + S31 * (1-X)
            // S22 = S11 * (1-fof) * (1-Y) + S12 * fof * (1-Y) + S21 * (1-fof) * (1-X) + S31 * X + S32 * X + S41 + S42 * X
            // S40 = S00 * Y + S10 * Y + S30 * (1-bf) * (1-X) + S32 * fof*(1-X) + S42 * fof*(1-X)

            FrB = castingState.GetSpell(SpellId.Frostbolt);
            FFB = castingState.GetSpell(SpellId.FrostfireBoltBF);
            FFBS = castingState.FrozenState.GetSpell(SpellId.FrostfireBoltBF);
            ILS = castingState.FrozenState.GetSpell(SpellId.IceLance);
            DFS = castingState.FrozenState.GetSpell(SpellId.DeepFreeze);

            float bf = 0.05f * castingState.MageTalents.BrainFreeze;
            float fof = (castingState.MageTalents.FingersOfFrost == 3 ? 0.2f : 0.07f * castingState.MageTalents.FingersOfFrost);
            float fof2 = fof * fof;
            float fof3 = fof2 * fof;
            float fof4 = fof3 * fof;
            float bf2 = bf * bf;
            float bf3 = bf2 * bf;

            // states are split into S0,S1 (fof not registered) vs S2,S3,S4 (fof registered)
            // ABBBaaBBBaaBBBaABBBaaBBBaaBBB
            // A*Y freezes in B*time(B) + A*(1-Y)*time(a)
            // A*Y <= R / 25 * (B*time(B) + A*(1-Y)*time(a))
            // A*Y <= R / 25 * B*time(B) + R / 25 * A*time(a) - R / 25 * A*time(a) * Y
            // A*Y*(1 + R / 25 * time(a)) <= R / 25 * B*time(B) + R / 25 * A*time(a)

            // Y = R/25 * (B*time(B) + A*time(a)) / (A * (1 + R / 25 * time(a)))

            // B*X*time(DF)/(B*time(B) + A*(1-Y)*time(a))=K*time(DF)/cool(DF)

            // heruistic tuning parameters
            float R = 1.05f; // overestimate because we don't have IL to eat down FOF when freeze is coming off cooldown in the model
            if (castingState.CalculationOptions.FlameOrb == 1)
            {
                fof *= 1.8f;
            }
            else if (castingState.CalculationOptions.FlameOrb == 2 && castingState.FlameOrb)
            {
                fof *= 5;
            }
            float K = 0.95f;

            // crude initial guess (fof=0.9,nonfof=0.1)
            float Y = R / 25f * (0.9f * (0.5f * DFS.CastTime + 0.5f * FrB.CastTime) + 0.1f * FrB.CastTime) / (0.1f * (1 + R / 25f * FrB.CastTime));
            float X = K * DFS.CastTime / DFS.Cooldown * (0.9f * (0.5f * DFS.CastTime + 0.5f * FrB.CastTime) + 0.1f * (1 - Y) * FrB.CastTime) / (0.9f * DFS.CastTime);

            float S00 = -((480000 * X * X * X * X - 6440000 * X * X * X + 6440000 * X * X - 480000 * X) * Y * Y + (-6240000 * X * X * X * X + 126440000 * X * X * X - 33880000 * X * X - 76600000 * X - 9720000) * Y - 840000 * X * X * X * X + 21950000 * X * X * X + 1190000 * X * X - 19870000 * X - 2430000);
            float S02 = -((57600 * X * X * X * X - 772800 * X * X * X + 772800 * X * X - 57600 * X) * Y * Y * Y + (1853100 * X * X * X * X - 3543525 * X * X * X + 10315725 * X * X - 10646400 * X - 1166400) * Y * Y + (-8469000 * X * X * X * X + 9007950 * X * X * X + 23115150 * X * X - 861900 * X + 2332800) * Y - 191700 * X * X * X * X - 2629125 * X * X * X + 671325 * X * X - 18621600 * X - 1166400);
            float S20 = -((81600 * X * X * X - 163200 * X * X + 81600 * X) * Y * Y * Y * Y + (-1224000 * X * X * X - 11899600 * X * X + 22031200 * X - 8907600) * Y * Y * Y + (2060400 * X * X * X + 88837500 * X * X - 27086200 * X - 63811700) * Y * Y + (-775200 * X * X * X + 43676600 * X * X + 2752400 * X - 45653800) * Y - 142800 * X * X * X + 4548700 * X * X + 2221000 * X - 6626900);
            float S01 = S00 * (1-fof) * bf * (1-Y);
            float S10 = S00 * fof * (1-bf) * (1-Y);
            float S11 = S00 * fof * bf * (1-Y);
            float S21 = S10 * (1-fof) * bf * (1-Y) + S20 * (1-fof) * bf * (1-X);
            float S30 = S10 * fof * (1-bf) * (1-Y) + S20 * fof * (1-bf) * (1-X);
            float S31 = S10 * fof * bf * (1-Y) + S20 * fof * bf * (1-X);
            float S12 = S01 * fof * (1-Y) + S02 * fof * (1-Y);
            float S32 = S11 * fof * (1-Y) + S12 * (1-fof) * (1-Y) + S21 * fof * (1-X);
            float S41 = S01 * Y + S11 * Y + S30 * bf * (1-X);
            float S42 = S02 * Y + S12 * Y + S31 * (1-X);
            float S22 = S11 * (1-fof) * (1-Y) + S12 * fof * (1-Y) + S21 * (1-fof) * (1-X) + S31 * X + S32 * X + S41 + S42 * X;
            float S40 = S00 * Y + S10 * Y + S30 * (1-bf) * (1-X) + S32 * fof*(1-X) + S42 * fof*(1-X);

            float div = S00 + S01 + S02 + S10 + S11 + S12 + S20 + S21 + S22 + S30 + S31 + S32 + S40 + S41 + S42;

            KFrB = ((S00 + S01 + S02 + S10 + S11 + S12) * (1 - Y) + (S20 + S21 + S30 + S31) * (1 - X)) / div;
            KFrB2 = ((S00 + S01 + S02 + S10 + S11 + S12) + (S20 + S21 + S30 + S31) * (1 - X)) / div;
            KFFB = 0 / div;
            KFFBS = ((S22 + S32 + S42) * (1 - X)) / div;
            KILS = (S40 + S41) * (1 - X) / div;
            KDFS = (S20 + S21 + S22 + S30 + S31 + S32 + S40 + S41 + S42) * X / div;

            for (int i = 0; i < 5; i++)
            {
                float T = KFrB * FrB.CastTime + KFFB * FFB.CastTime + KFFBS * FFBS.CastTime + KILS * ILS.CastTime + KDFS * DFS.CastTime;
                float T2 = KFrB2 * FrB.CastTime + KFFB * FFB.CastTime + KFFBS * FFBS.CastTime + KILS * ILS.CastTime + KDFS * DFS.CastTime;

                // better estimate
                // TODO better probabilistic model
                Y = R / 25 * T2 / ((S00 + S01 + S02 + S10 + S11 + S12) / div * (1 + R / 25 * FrB.CastTime));
                X = K / DFS.Cooldown * T / ((S20 + S21 + S22 + S30 + S31 + S32 + S40 + S41 + S42) / div);

                // recalculate shares based on revised estimate
                S00 = -((480000 * X * X * X * X - 6440000 * X * X * X + 6440000 * X * X - 480000 * X) * Y * Y + (-6240000 * X * X * X * X + 126440000 * X * X * X - 33880000 * X * X - 76600000 * X - 9720000) * Y - 840000 * X * X * X * X + 21950000 * X * X * X + 1190000 * X * X - 19870000 * X - 2430000);
                S02 = -((57600 * X * X * X * X - 772800 * X * X * X + 772800 * X * X - 57600 * X) * Y * Y * Y + (1853100 * X * X * X * X - 3543525 * X * X * X + 10315725 * X * X - 10646400 * X - 1166400) * Y * Y + (-8469000 * X * X * X * X + 9007950 * X * X * X + 23115150 * X * X - 861900 * X + 2332800) * Y - 191700 * X * X * X * X - 2629125 * X * X * X + 671325 * X * X - 18621600 * X - 1166400);
                S20 = -((81600 * X * X * X - 163200 * X * X + 81600 * X) * Y * Y * Y * Y + (-1224000 * X * X * X - 11899600 * X * X + 22031200 * X - 8907600) * Y * Y * Y + (2060400 * X * X * X + 88837500 * X * X - 27086200 * X - 63811700) * Y * Y + (-775200 * X * X * X + 43676600 * X * X + 2752400 * X - 45653800) * Y - 142800 * X * X * X + 4548700 * X * X + 2221000 * X - 6626900);
                S01 = S00 * (1 - fof) * bf * (1 - Y);
                S10 = S00 * fof * (1 - bf) * (1 - Y);
                S11 = S00 * fof * bf * (1 - Y);
                S21 = S10 * (1 - fof) * bf * (1 - Y) + S20 * (1 - fof) * bf * (1 - X);
                S30 = S10 * fof * (1 - bf) * (1 - Y) + S20 * fof * (1 - bf) * (1 - X);
                S31 = S10 * fof * bf * (1 - Y) + S20 * fof * bf * (1 - X);
                S12 = S01 * fof * (1 - Y) + S02 * fof * (1 - Y);
                S32 = S11 * fof * (1 - Y) + S12 * (1 - fof) * (1 - Y) + S21 * fof * (1 - X);
                S41 = S01 * Y + S11 * Y + S30 * bf * (1 - X);
                S42 = S02 * Y + S12 * Y + S31 * (1 - X);
                S22 = S11 * (1 - fof) * (1 - Y) + S12 * fof * (1 - Y) + S21 * (1 - fof) * (1 - X) + S31 * X + S32 * X + S41 + S42 * X;
                S40 = S00 * Y + S10 * Y + S30 * (1 - bf) * (1 - X) + S32 * fof * (1 - X) + S42 * fof * (1 - X);

                div = S00 + S01 + S02 + S10 + S11 + S12 + S20 + S21 + S22 + S30 + S31 + S32 + S40 + S41 + S42;

                KFrB = ((S00 + S01 + S02 + S10 + S11 + S12) * (1 - Y) + (S20 + S21 + S30 + S31) * (1 - X)) / div;
                KFrB2 = ((S00 + S01 + S02 + S10 + S11 + S12) + (S20 + S21 + S30 + S31) * (1 - X)) / div;
                KFFB = 0 / div;
                KFFBS = ((S22 + S32 + S42) * (1 - X)) / div;
                KILS = (S40 + S41) * (1 - X) / div;
                KDFS = (S20 + S21 + S22 + S30 + S31 + S32 + S40 + S41 + S42) * X / div;
            }

            //div = KFrB + KFFBS + KILS + KDFS;
            //KFrB /= div;
            //KFFBS /= div;
            //KILS /= div;
            //KDFS /= div;

            cycle.AddSpell(needsDisplayCalculations, FrB, KFrB);
            cycle.AddSpell(needsDisplayCalculations, FFB, KFFB);
            cycle.AddSpell(needsDisplayCalculations, FFBS, KFFBS);
            cycle.AddSpell(needsDisplayCalculations, ILS, KILS);
            cycle.AddSpell(needsDisplayCalculations, DFS, KDFS);
            cycle.Calculate();
            return cycle;
        }
예제 #24
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            cycle.Name = "ABABar1AM";

            // S0:
            // AB0-ABar         => S0    (1-MB)*(1-MB)
            // AB0-ABar-AB0-AM  => S0    (1-MB)*MB
            // AB0-AM           => S0    MB

            Spell ABar = castingState.GetSpell(SpellId.ArcaneBarrage);
            Spell AM = castingState.GetSpell(SpellId.ArcaneMissiles);
            Spell AB0 = castingState.GetSpell(SpellId.ArcaneBlast0);

            float MB = 0.4f;
            float K2 = (1 - MB) * (1 - MB);
            float K3 = MB * (1 - MB);

            cycle.AddSpell(needsDisplayCalculations, AB0, 1 + K3);
            cycle.AddSpell(needsDisplayCalculations, ABar, 1 - MB);
            cycle.AddSpell(needsDisplayCalculations, AM, 1 - K2);
            cycle.AddPause(ABar.Cooldown - ABar.CastTime - AB0.CastTime, 1 - MB);

            cycle.Calculate();
            return cycle;
        }
예제 #25
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            Spell FrB, FrBS, FB, FBS, ILS, DFS;
            float KFrB, KFrBS, KFB, KFBS, KILS, KDFS;
            cycle.Name = "FrBDFFBIL";

            //float T8 = CalculationOptionsMage.SetBonus4T8ProcRate * castingState.BaseStats.Mage4T8;

            // S00: FOF0, BF0
            // FrB => S21    fof * bf
            //        S20    fof * (1-bf)
            //        S01    (1-fof) * bf
            //        S00    (1-fof)*(1-bf)

            // S01: FOF0, BF1
            // FrB => S22    fof
            //        S02    (1-fof)

            // S02: FOF0, BF2
            // FB => S00    1

            // S10: FOF1, BF0
            // FrBS-ILS => S12    X*fof * bf
            //             S10    X*fof * (1-bf)
            //             S02    X*(1-fof) * bf
            //             S00    X*(1-fof)*(1-bf)
            // FrBS-DFS => S12    (1-X)*fof*bf
            //             S10    (1-X)*fof * (1-bf)
            //             S02    (1-X)*(1-fof) * bf
            //             S00    (1-X)*(1-fof)*(1-bf)

            // S11: FOF1, BF1
            // FrBS-FBS => S10    X*fof
            //             S00    X*(1-fof)
            // FrBS-DFS => S12    (1-X)*fof
            //             S02    (1-X)*(1-fof)

            // S12 = S11

            // S20: FOF0, BF0
            // FrBS => S21    fof * bf
            //         S20    fof * (1-bf)
            //         S11    (1-fof) * bf
            //         S10    (1-fof)*(1-bf)

            // S21: FOF0, BF1
            // FrBS => S22    fof
            //         S12    (1-fof)

            // S22 = S21

            // S00 = (1-fof)*(1-bf) * S00 + S02 + (1-fof)*(1-bf) * S10 + X*(1-fof) * S11
            // S01 = (1-fof) * bf * S00
            // S02 = (1-fof) * S01 + (1-fof) * bf * S10 + (1-X)*(1-fof) * S11
            // S10 = fof * (1-bf) * S10 + X*fof * S11 + (1-fof)*(1-bf) * S20
            // S11 = fof * bf * S10 + (1-X)*fof * S11 + (1-fof) * bf * S20 + (1-fof) * S21
            // S20 = fof * (1-bf) * S00 + fof * (1-bf) * S20
            // S21 = fof * bf * S00 + fof * S01 + fof * bf * S20 + fof * S21
            // S00 + S01 + S02 + S10 + S11 + S20 + S21 = 1

            // solved symbolically

            FrB = castingState.GetSpell(SpellId.Frostbolt);
            FrBS = castingState.FrozenState.GetSpell(SpellId.Frostbolt);
            FB = castingState.GetSpell(SpellId.FireballBF);
            FBS = castingState.FrozenState.GetSpell(SpellId.FireballBF);
            ILS = castingState.FrozenState.GetSpell(SpellId.IceLance);
            DFS = castingState.FrozenState.GetSpell(SpellId.DeepFreeze);

            float bf = 0.05f * castingState.MageTalents.BrainFreeze;
            float fof = (castingState.MageTalents.FingersOfFrost == 2 ? 0.15f : 0.07f * castingState.MageTalents.FingersOfFrost);
            float fof2 = fof * fof;
            float fof3 = fof2 * fof;
            float fof4 = fof3 * fof;
            float bf2 = bf * bf;
            float bf3 = bf2 * bf;

            // shatters until deep freeze ~ Poisson
            // share of shatters that are deep freeze = sum_i=0..inf Pi / sum_i=0..inf (i+1)*Pi = 1 / (1 + mean)

            // crude initial guess
            float X = 1.0f - 1.0f / (1.0f + (DFS.Cooldown - DFS.CastTime) / (FrB.CastTime * (1 / fof + 1) + ILS.CastTime));

            float S00 = (((bf - 1) * fof3 + (2 - bf) * fof2 - fof) * X + (bf2 - 2 * bf + 1) * fof3 + (-bf2 + 4 * bf - 3) * fof2 + (3 - 2 * bf) * fof - 1);
            float S01 = -(((bf2 - bf) * fof4 + (3 * bf - 2 * bf2) * fof3 + (bf2 - 3 * bf) * fof2 + bf * fof) * X + (bf3 - 2 * bf2 + bf) * fof4 + (-2 * bf3 + 6 * bf2 - 4 * bf) * fof3 + (bf3 - 6 * bf2 + 6 * bf) * fof2 + (2 * bf2 - 4 * bf) * fof + bf);
            float S02 = (((bf2 - bf) * fof4 + (4 * bf - 3 * bf2) * fof3 + (3 * bf2 - 5 * bf) * fof2 + (2 * bf - bf2) * fof) * X + (-bf3 + 2 * bf2 - bf) * fof3 + (2 * bf3 - 3 * bf2 + bf) * fof2 + (-bf3 + bf2 + bf) * fof - bf);
            float S10 = (((bf2 - bf) * fof4 + (-bf2 + bf + 1) * fof3 + (-bf - 1) * fof2) * X + (-bf2 + 2 * bf - 1) * fof3 + (2 * bf2 - 4 * bf + 2) * fof2 + (-bf2 + 2 * bf - 1) * fof);
            float S11 = ((bf3 - 2 * bf2 + bf) * fof4 + (-bf3 + 4 * bf2 - 3 * bf) * fof3 + (5 * bf - 4 * bf2) * fof2 + (bf2 - 3 * bf) * fof);
            float S20 = -(((bf - 1) * fof3 + (1 - bf) * fof2) * X + (bf2 - 2 * bf + 1) * fof3 + (-bf2 + 3 * bf - 2) * fof2 + (1 - bf) * fof);
            float S21 = (((bf2 - bf) * fof4 + (2 * bf - bf2) * fof3 - 2 * bf * fof2) * X + (bf3 - 2 * bf2 + bf) * fof4 + (-bf3 + 4 * bf2 - 3 * bf) * fof3 + (4 * bf - 3 * bf2) * fof2 - 2 * bf * fof);

            float div = S00 + S01 + S02 + S10 + S11 + S20 + S21;            

            KFrB = (S00 + S01) / div;
            KFB = S02 / div;
            KFrBS = (S10 + S11 + S20 + S21) / div;
            KFBS = X * S11 / div;
            KILS = X * S10 / div;
            KDFS = (1 - X) * (S10 + S11) / div;

            float hasteFactor = 1.0f;

            float T = KFrB * FrB.CastTime + KFB * FB.CastTime + KFrBS * FrBS.CastTime + KFBS * FBS.CastTime + KILS * ILS.CastTime + KDFS * DFS.CastTime;
            float T0 = KFBS * FBS.CastTime + KILS * ILS.CastTime + KDFS * DFS.CastTime;
            float T1 = KFBS * FBS.CastTime + KFB * FB.CastTime;

            if (castingState.Solver.Mage2T10)
            {
                // we'll make a lot of assumptions here and just assume that 2T10 haste is uniformly distributed over all
                // spells and doesn't have an impact on state space
                // also ignore the possible refresh of 2T10
                // each proc gives 12% haste for 5 sec
                // we have on average one proc every T/T1 * FB.CastTime
                // we have some feedback loop here, speeding up the cycle increases the rate of procs
                // hastedShare = (5-FB.CastTimeAverage) / (T/T1 * FB.CastTimeAverage)
                // hastedCastShare = (5-FB.CastTimeAverage) / (T/T1 * FB.CastTime) * 1.12
                // average haste = 1 / (1-hastedCastShare*0.12/1.12)
                // TODO this is all a bunch of voodoo, redo the math when you're thinking straight
                hasteFactor = 1.0f / (1.0f - (5 - FB.CastTime) / (T / T1 * FB.CastTime) * 0.12f);

                // alternative model based on reduction to single state space and expanding for haste
                // probability of being hasted = 1 - (1-p)^(N-1)
                // where
                // K := (KFrB + KFB + KFrBS + KFBS + KILS + KDFS)
                // p = probability of haste generating spell = (KFBS + KFB) / K
                // N = average number of spells affected by haste = (haste duration - average cast time of haste generating spell) / (average cast time of hasted spells)
                //   = (5 - T1 / 1.12 / K) / (T / 1.12 / K)
                //   = (5 * 1.12 * K - T1) / T
                // hasteFactor = 1 / (((1-p)^(N-1)) * 1 + (1 - (1-p)^(N-1)) * 1/1.12)
                //             = 1.12 / (((1-p)^(N-1)) * 0.12 + 1)
                //             = 1.12 / (1 + 0.12 * (1 - (KFBS + KFB) / K)^((5 * 1.12 * K - T1) / T - 1))
                //float K = KFrB + KFB + KFrBS + KFBS + KILS + KDFS;
                //hasteFactor = 1.12f / (1.0f + 0.12f * (float)Math.Pow(1.0f - ((KFBS + KFB) / K), ((5.0f * 1.12f * K - T1) / T - 1.0f)));
            }

            if (fof > 0) // nothing new here if we don't have fof
            {
                // better estimate for percentage of shatter combos that are deep freeze
                // TODO better probabilistic model for DF percentage
                X = 1.0f - 1.0f / (1.0f + (DFS.Cooldown - DFS.CastTime / hasteFactor) / (DFS.CastTime / hasteFactor * T / T0));

                // recalculate shares based on revised estimate
                S00 = (((bf - 1) * fof3 + (2 - bf) * fof2 - fof) * X + (bf2 - 2 * bf + 1) * fof3 + (-bf2 + 4 * bf - 3) * fof2 + (3 - 2 * bf) * fof - 1);
                S01 = -(((bf2 - bf) * fof4 + (3 * bf - 2 * bf2) * fof3 + (bf2 - 3 * bf) * fof2 + bf * fof) * X + (bf3 - 2 * bf2 + bf) * fof4 + (-2 * bf3 + 6 * bf2 - 4 * bf) * fof3 + (bf3 - 6 * bf2 + 6 * bf) * fof2 + (2 * bf2 - 4 * bf) * fof + bf);
                S02 = (((bf2 - bf) * fof4 + (4 * bf - 3 * bf2) * fof3 + (3 * bf2 - 5 * bf) * fof2 + (2 * bf - bf2) * fof) * X + (-bf3 + 2 * bf2 - bf) * fof3 + (2 * bf3 - 3 * bf2 + bf) * fof2 + (-bf3 + bf2 + bf) * fof - bf);
                S10 = (((bf2 - bf) * fof4 + (-bf2 + bf + 1) * fof3 + (-bf - 1) * fof2) * X + (-bf2 + 2 * bf - 1) * fof3 + (2 * bf2 - 4 * bf + 2) * fof2 + (-bf2 + 2 * bf - 1) * fof);
                S11 = ((bf3 - 2 * bf2 + bf) * fof4 + (-bf3 + 4 * bf2 - 3 * bf) * fof3 + (5 * bf - 4 * bf2) * fof2 + (bf2 - 3 * bf) * fof);
                S20 = -(((bf - 1) * fof3 + (1 - bf) * fof2) * X + (bf2 - 2 * bf + 1) * fof3 + (-bf2 + 3 * bf - 2) * fof2 + (1 - bf) * fof);
                S21 = (((bf2 - bf) * fof4 + (2 * bf - bf2) * fof3 - 2 * bf * fof2) * X + (bf3 - 2 * bf2 + bf) * fof4 + (-bf3 + 4 * bf2 - 3 * bf) * fof3 + (4 * bf - 3 * bf2) * fof2 - 2 * bf * fof);

                div = S00 + S01 + S02 + S10 + S11 + S20 + S21;

                KFrB = (S00 + S01) / div;
                KFB = S02 / div;
                KFrBS = (S10 + S11 + S20 + S21) / div;
                KFBS = X * S11 / div;
                KILS = X * S10 / div;
                KDFS = (1 - X) * (S10 + S11) / div;
            }

            cycle.AddSpell(needsDisplayCalculations, FrB, KFrB);
            cycle.AddSpell(needsDisplayCalculations, FB, KFB);
            cycle.AddSpell(needsDisplayCalculations, FrBS, KFrBS);
            cycle.AddSpell(needsDisplayCalculations, FBS, KFBS);
            cycle.AddSpell(needsDisplayCalculations, ILS, KILS);
            cycle.AddSpell(needsDisplayCalculations, DFS, KDFS);
            cycle.CastTime /= hasteFactor; // ignores latency effects, but it'll have to do for now
            cycle.Calculate();
            return cycle;
        }
예제 #26
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            Spell FFB;
            Spell Sc;
            Spell LB;
            Spell Pyro;
            float K;
            float X;
            float Y;
            cycle.Name = "FFBScLBPyro";
            cycle.ProvidesScorch = true;

            FFB = castingState.GetSpell(SpellId.FrostfireBolt);
            Sc = castingState.GetSpell(SpellId.Scorch);
            LB = castingState.GetSpell(SpellId.LivingBomb);
            Pyro = castingState.GetSpell(SpellId.PyroblastPOMDotUptime);

            int averageScorchesNeeded = (int)Math.Ceiling(3f / (float)castingState.MageTalents.ImprovedScorch);
            int extraScorches = 0;

            float T8 = 0;

            float gap = (30.0f - (averageScorchesNeeded + extraScorches) * Sc.CastTime) / (30.0f - extraScorches * Sc.CastTime);
            if (castingState.MageTalents.ImprovedScorch == 0)
            {
                cycle.ProvidesScorch = false;
                gap = 1.0f;
            }
            float hasteFactor = 1.0f;
            float C, H, averageCastTime;

                if (gap == 1.0f)
                {
                    Y = 0.0f;
                    float FFBcrit = FFB.CritRate;
                    float LBcrit = LB.CritRate;
                    H = castingState.MageTalents.HotStreak / 3.0f;
#if RAWR4
                    if (castingState.Solver.Specialization != Specialization.Fire) H = 0.0f;
#else
                    if (castingState.MageTalents.Pyroblast == 0) H = 0.0f;
#endif
                    float A2 = (FFBcrit - LBcrit) * (LB.CastTime - FFB.CastTime - 12) - (FFBcrit - LBcrit) * (FFBcrit - LBcrit) * Pyro.CastTime / (1 - T8) * H;
                    float A1 = (FFBcrit - LBcrit) * (12 - LB.CastTime) + (LB.CastTime - FFB.CastTime - 12) * (1 + LBcrit) - Pyro.CastTime / (1 - T8) * H * 2 * LBcrit * (FFBcrit - LBcrit);
                    float A0 = (1 + LBcrit) * (12 - LB.CastTime) - Pyro.CastTime / (1 - T8) * H * LBcrit * LBcrit;
                    if (Math.Abs(A2) < 0.00001)
                    {
                        X = -A0 / A1;
                    }
                    else
                    {
                        X = (float)((-A1 - Math.Sqrt(A1 * A1 - 4 * A2 * A0)) / (2 * A2));
                    }
                    C = LBcrit + X * (FFBcrit - LBcrit);
                    K = H * C * C / (1 + C) / (1 - T8);

                    if (castingState.Solver.Mage2T10)
                    {
                        // p = K / (1 + K)
                        // N = (5 * 1.12 - Pyro.CastTime) * (1 + K) / (FB.CastTime * X + LB.CastTime * (1-X) + Pyro.CastTime * K)
                        hasteFactor = 1.12f / ((float)Math.Pow(1 - K / (1.0f + K), (5 * 1.12 - Pyro.CastTime) * (1 + K) / (FFB.CastTime * X + LB.CastTime * (1 - X) + Pyro.CastTime * K) + 0.5f) * 0.12f + 1f);
                    }

                    float LBrecastInterval = 12 + 0.5f * ((FFB.CastTime * FFB.CastTime * X + Pyro.CastTime * Pyro.CastTime * K) / (FFB.CastTime * X + Pyro.CastTime * K)) / hasteFactor;

                    A2 = (FFBcrit - LBcrit) * (LB.CastTime / hasteFactor - FFB.CastTime / hasteFactor - LBrecastInterval) - (FFBcrit - LBcrit) * (FFBcrit - LBcrit) * Pyro.CastTime / hasteFactor / (1 - T8) * H;
                    A1 = (FFBcrit - LBcrit) * (LBrecastInterval - LB.CastTime / hasteFactor) + (LB.CastTime / hasteFactor - FFB.CastTime / hasteFactor - LBrecastInterval) * (1 + LBcrit) - Pyro.CastTime / hasteFactor / (1 - T8) * H * 2 * LBcrit * (FFBcrit - LBcrit);
                    A0 = (1 + LBcrit) * (LBrecastInterval - LB.CastTime / hasteFactor) - Pyro.CastTime / hasteFactor / (1 - T8) * H * LBcrit * LBcrit;
                    if (Math.Abs(A2) < 0.00001)
                    {
                        X = -A0 / A1;
                    }
                    else
                    {
                        X = (float)((-A1 - Math.Sqrt(A1 * A1 - 4 * A2 * A0)) / (2 * A2));
                    }
                    C = LBcrit + X * (FFBcrit - LBcrit);
                    averageCastTime = LB.CastTime + X * (FFB.CastTime - LB.CastTime);
                    K = H * C * C / (1 + C) / (1 - T8);
                }
                else
                {
                    float P = 1.0f + Sc.CastTime / (12.0f * (1.0f - gap));
                    float FFBcrit = FFB.CritRate;
                    float SCcrit = Sc.CritRate;
                    float LBcrit = LB.CritRate;
                    H = castingState.MageTalents.HotStreak / 3.0f;
#if RAWR4
                    if (castingState.Solver.Specialization != Specialization.Fire) H = 0.0f;
#else
                    if (castingState.MageTalents.Pyroblast == 0) H = 0.0f;
#endif
                    float T1 = Sc.CastTime - P * FFB.CastTime + (P - 1) * LB.CastTime - 12 * (P - 1);
                    float CY = SCcrit - FFBcrit * P + LBcrit * (P - 1);

                    float A2 = CY * T1 + Pyro.CastTime / (1 - T8) * H * CY * CY;
                    float A1 = CY * FFB.CastTime + T1 + FFBcrit * T1 + 2 * Pyro.CastTime / (1 - T8) * H * FFBcrit * CY;
                    float A0 = FFB.CastTime + FFBcrit * FFB.CastTime + Pyro.CastTime / (1 - T8) * H * FFBcrit * FFBcrit;
                    if (Math.Abs(A2) < 0.00001)
                    {
                        Y = -A0 / A1;
                    }
                    else
                    {
                        Y = (float)((-A1 - Math.Sqrt(A1 * A1 - 4 * A2 * A0)) / (2 * A2));
                    }
                    X = 1 - P * Y;
                    C = (FFBcrit * X + SCcrit * Y + LBcrit * (1 - X - Y));
                    K = H * C * C / (1 + C) / (1 - T8);

                    if (castingState.Solver.Mage2T10)
                    {
                        // p = K / (1 + K)
                        // N = (5 * 1.12 - Pyro.CastTime) * (1 + K) / (FB.CastTime * X + LB.CastTime * (1-X) + Pyro.CastTime * K)
                        hasteFactor = 1.12f / ((float)Math.Pow(1 - K / (1.0f + K), (5 * 1.12 - Pyro.CastTime) * (1 + K) / (FFB.CastTime * X + Sc.CastTime * Y + LB.CastTime * (1 - X - Y) + Pyro.CastTime * K) + 0.5f) * 0.12f + 1f);
                    }

                    float LBrecastInterval = 12 + 0.5f * ((FFB.CastTime * FFB.CastTime * X + Sc.CastTime * Sc.CastTime * Y + Pyro.CastTime * Pyro.CastTime * K) / (FFB.CastTime * X + Sc.CastTime * Y + Pyro.CastTime * K)) / hasteFactor;

                    P = 1.0f + Sc.CastTime / hasteFactor / (LBrecastInterval * (1.0f - gap));
                    T1 = Sc.CastTime / hasteFactor - P * FFB.CastTime / hasteFactor + (P - 1) * LB.CastTime / hasteFactor - LBrecastInterval * (P - 1);
                    CY = SCcrit - FFBcrit * P + LBcrit * (P - 1);

                    A2 = CY * T1 + Pyro.CastTime / hasteFactor / (1 - T8) * H * CY * CY;
                    A1 = CY * FFB.CastTime / hasteFactor + T1 + FFBcrit * T1 + 2 * Pyro.CastTime / hasteFactor / (1 - T8) * H * FFBcrit * CY;
                    A0 = FFB.CastTime / hasteFactor + FFBcrit * FFB.CastTime / hasteFactor + Pyro.CastTime / hasteFactor / (1 - T8) * H * FFBcrit * FFBcrit;
                    if (Math.Abs(A2) < 0.00001)
                    {
                        Y = -A0 / A1;
                    }
                    else
                    {
                        Y = (float)((-A1 - Math.Sqrt(A1 * A1 - 4 * A2 * A0)) / (2 * A2));
                    }
                    X = 1 - P * Y;
                    C = (FFBcrit * X + SCcrit * Y + LBcrit * (1 - X - Y));
                    averageCastTime = (FFB.CastTime * X + Sc.CastTime * Y + LB.CastTime * (1 - X - Y));
                    K = H * C * C / (1 + C) / (1 - T8);
                }       

            // pyro dot uptime 

            //A := [x * cFB * DFB + (1 - x) * cLB * DLB]  ~ (x * cFB + (1 - x) * cLB)* D[x * FB + (1 - x) * LB]
            //B := [x * (1-cFB) * DFB + (1 - x) * (1-cLB) * DLB] ~ (1 - (x * cFB + (1- x) * cLB)) * D[x * FB + (1 - x) * LB]

            float averageTicks = 0f;
            float k1 = 0;
            float k2 = C * C * H;
            float totalChance = k2;
            int n = 2;

            averageTicks += Math.Min((int)(Pyro.CastTime / hasteFactor / 3.0f), 4) * T8;
            averageTicks += Math.Min((int)((Pyro.CastTime + n * averageCastTime) / hasteFactor / 3.0f), 4) * (1 - T8) * k2;

            while ((Pyro.CastTime + n * averageCastTime) / hasteFactor < 12)
            {
                float tmp = k1;
                k1 = k2;
                k2 = C * (1 - C * H) * tmp + (1 - C) * k1;
                totalChance += k2;
                n++;
                averageTicks += Math.Min((int)((Pyro.CastTime + n * averageCastTime) / hasteFactor / 3.0f), 4) * (1 - T8) * k2;
            }
            averageTicks += 4 * (1 - T8) * (1 - totalChance);

            cycle.AddSpell(needsDisplayCalculations, FFB, X);
            cycle.AddSpell(needsDisplayCalculations, Sc, Y);
            cycle.AddSpell(needsDisplayCalculations, LB, 1 - X - Y);
            cycle.AddSpell(needsDisplayCalculations, Pyro, K, averageTicks / 4.0f);
            cycle.CastTime /= hasteFactor;
            cycle.Calculate();
            return cycle;
        }
예제 #27
0
        public ABSpamMBAM(bool needsDisplayCalculations, CastingState castingState)
            : base(needsDisplayCalculations, castingState)
        {
            Spell AB3;
            float MB, MB3, MB4, MB5, hit, miss;
            Name = "ABSpamMBAM";

            // main cycle is AB3 spam
            // on MB we change into ramp up mode

            // RAMP =
            // AB0-AB1-AB2           0.85*0.85*0.85 = k1
            // AB0-AB1-AB2-(AB3-)MBAM-RAMP 0.85*0.85*0.15 = k2
            // AB0-AB1-(AB2-)MBAM-RAMP     0.85*0.15      = k3
            // AB0-(AB1-)MBAM-RAMP         0.15           = k4

            // RAMP = k1 * (AB0+AB1+AB2) + k2 * (AB0+AB1+AB2+MBAM + RAMP) + k3 * (AB0+AB1+MBAM + RAMP) + k4 * (AB0+MBAM + RAMP)
            // RAMP * (1 - k2 - k3 - k4) = k1 * (AB0+AB1+AB2) + k2 * (AB0+AB1+AB2+MBAM) + k3 * (AB0+AB1+MBAM) + k4 * (AB0+MBAM)
            // RAMP = (AB0+AB1+AB2) + k2 / k1 * (AB0+AB1+AB2+MBAM) + k3 / k1 * (AB0+AB1+MBAM) + k4 / k1 * (AB0+MBAM)

            // RAMP =
            // AB0H-AB1H-AB2H                 0.85*hit*0.85*hit*0.85*hit = k1
            // AB0H-AB1H-AB2H-(AB3-)MBAM-RAMP 0.85*hit*0.85*hit*0.15*hit = k2
            // AB0H-AB1H-(AB2-)MBAM-RAMP      0.85*hit*0.15*hit          = k3
            // AB0H-(AB1-)MBAM-RAMP           0.15*hit                   = k4
            // AB0H-AB1H-AB2M-RAMP            0.85*hit*0.85*hit*miss     = k5
            // AB0H-AB1M-RAMP                 0.85*hit*miss              = k6
            // AB0M-RAMP                      miss                       = k7

            // RAMP = k1 * (AB0H+AB1H+AB2H) + k2 * (AB0H+AB1H+AB2H+AB3+MBAM + RAMP) + k3 * (AB0H+AB1H+AB2+MBAM + RAMP) + k4 * (AB0H+AB1+MBAM + RAMP) + k5 * (AB0H+AB1H+AB2M + RAMP) + k6 * (AB0H+AB1M + RAMP) + k7 * (AB0M + RAMP)
            // RAMP = (AB0H+AB1H+AB2H) + k2 / k1 * (AB0H+AB1H+AB2H+AB3+MBAM) + k3 / k1 * (AB0H+AB1H+AB2+MBAM) + k4 / k1 * (AB0H+AB1+MBAM) + k5 / k1 * (AB0H+AB1H+AB2M) + k6 / k1 * (AB0H+AB1M) + k7 / k1 * (AB0M)

            // AB3H                 0.85*hit
            // AB3H-(AB3-)MBAM-RAMP 0.15*hit
            // AB3M-RAMP            (1-hit)

            Spell AB0 = castingState.GetSpell(SpellId.ArcaneBlast0);
            Spell AB1 = castingState.GetSpell(SpellId.ArcaneBlast1);
            Spell AB2 = castingState.GetSpell(SpellId.ArcaneBlast2);
            AB3 = castingState.GetSpell(SpellId.ArcaneBlast3);
            Spell MBAM = castingState.GetSpell(SpellId.ArcaneMissilesMB);
            Spell MBAM2 = castingState.GetSpell(SpellId.ArcaneMissilesMB2);
            Spell MBAM3 = castingState.GetSpell(SpellId.ArcaneMissilesMB3);

            MB = 0.04f * castingState.MageTalents.MissileBarrage;
            hit = AB3.HitRate;
            miss = 1 - hit;

            if (MB == 0.0)
            {
                // TODO take hit rate into account
                // if we don't have barrage then this degenerates to AB

                AddSpell(needsDisplayCalculations, AB3, 1);
                Calculate();
            }
            else
            {
                MB3 = MB / (1 - MB);
                MB4 = MB / (1 - MB) / (1 - MB);
                MB5 = MB / (1 - MB) / (1 - MB) / (1 - MB);

                //AB3 0.85

                //AB3-MBAM-RAMP 0.15
                AddSpell(needsDisplayCalculations, AB3, MB);
                AddSpell(needsDisplayCalculations, AB3, MB); // account for latency
                AddSpell(needsDisplayCalculations, MBAM3, MB);
                AddSpell(needsDisplayCalculations, AB0, MB);
                AddSpell(needsDisplayCalculations, AB1, MB);
                AddSpell(needsDisplayCalculations, AB2, MB);

                AddSpell(needsDisplayCalculations, AB0, MB * MB3);
                AddSpell(needsDisplayCalculations, AB1, MB * MB3);
                AddSpell(needsDisplayCalculations, AB2, MB * MB3);
                AddSpell(needsDisplayCalculations, AB3, MB * MB3); // account for latency
                AddSpell(needsDisplayCalculations, MBAM3, MB * MB3);

                AddSpell(needsDisplayCalculations, AB0, MB * MB4);
                AddSpell(needsDisplayCalculations, AB1, MB * MB4);
                AddSpell(needsDisplayCalculations, AB2, MB * MB4); // account for latency
                AddSpell(needsDisplayCalculations, MBAM3, MB * MB4);

                AddSpell(needsDisplayCalculations, AB0, MB * MB5);
                AddSpell(needsDisplayCalculations, AB1, MB * MB5); // account for latency
                AddSpell(needsDisplayCalculations, MBAM2, MB * MB5);

                AddSpell(needsDisplayCalculations, AB3, 1 - MB);

                Calculate();
            }
        }
예제 #28
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            Spell FrB, FrBS, ILS;
            float KFrB, KFrBS, KILS;
            cycle.Name = "FrBIL";

            //float T8 = 0;

            // S00: FOF0
            // FrB => S20    fof
            //        S00    (1-fof)

            // S10: FOF1, BF0
            // FrBS-ILS => S10    fof
            //             S00    (1-fof)

            // S20: FOF0, BF0
            // FrBS => S20    fof
            //         S10    (1-fof)


            // S00 = (1-fof) * S00 + (1-fof) * S10
            // S10 = fof * S10 + (1-fof) * S20
            // S20 = fof * S00 + fof * S20
            // S00 + S10 + S20 = 1

            float fof = (castingState.MageTalents.FingersOfFrost == 2 ? 0.15f : 0.07f * castingState.MageTalents.FingersOfFrost);

            float S00 = (1 - fof) / (1 + fof);
            float S10 = fof / (1 + fof);
            float S20 = fof / (1 + fof);

            KFrB = S00;
            KFrBS = S10 + S20;
            KILS = S10;

            FrB = castingState.GetSpell(SpellId.Frostbolt);
            FrBS = castingState.FrozenState.GetSpell(SpellId.Frostbolt);
            ILS = castingState.FrozenState.GetSpell(SpellId.IceLance);

            cycle.AddSpell(needsDisplayCalculations, FrB, KFrB);
            cycle.AddSpell(needsDisplayCalculations, FrBS, KFrBS);
            cycle.AddSpell(needsDisplayCalculations, ILS, KILS);
            cycle.Calculate();
            return cycle;
        }
예제 #29
0
        public ABarAM(bool needsDisplayCalculations, CastingState castingState)
            : base(needsDisplayCalculations, castingState)
        {
            float MB;
            Name = "ABarAM";

            Spell ABar = castingState.GetSpell(SpellId.ArcaneBarrage);
            Spell AM = castingState.GetSpell(SpellId.ArcaneMissiles);
            Spell MBAM = castingState.GetSpell(SpellId.ArcaneMissilesMB);

            MB = 0.04f * castingState.MageTalents.MissileBarrage;

            if (MB == 0.0)
            {
                // if we don't have barrage then this degenerates to ABar-AM
                AddSpell(needsDisplayCalculations, ABar, 1);
                AddSpell(needsDisplayCalculations, AM, 1);

                Calculate();
            }
            else
            {
                //AB-AM 0.85
                AddSpell(needsDisplayCalculations, ABar, 1 - MB);
                AddSpell(needsDisplayCalculations, AM, 1 - MB);

                //AB-MBAM 0.15
                AddSpell(needsDisplayCalculations, ABar, MB);
                AddSpell(needsDisplayCalculations, MBAM, MB);
                if (ABar.CastTime + MBAM.CastTime < 3.0) AddPause(3.0f - ABar.CastTime - MBAM.CastTime, MB);

                Calculate();
            }
        }
예제 #30
0
        public static Cycle GetCycle(bool needsDisplayCalculations, CastingState castingState)
        {
            Cycle cycle = Cycle.New(needsDisplayCalculations, castingState);
            cycle.Name = "AE4AB";

            Spell AB4 = castingState.GetSpell(SpellId.ArcaneBlast4);
            Spell AE4 = castingState.GetSpell(SpellId.ArcaneExplosion4);

            // AEx4-AB

            // 6 seconds on AB debuff - time to refresh AB
            int aeCount = (int)((6.0f - AB4.CastTime) / AE4.CastTime);

            cycle.AddSpell(needsDisplayCalculations, AE4, aeCount);
            cycle.AddSpell(needsDisplayCalculations, AB4, 1);
            cycle.Calculate();

            cycle.AreaEffect = true;

            return cycle;
        }