Пример #1
0
        /// <summary>
        /// Calculates a rotation based on the FS>LvB>LB priority.
        /// </summary>
        public void CalculateRotation(bool addlb1, bool addlb2, bool useFN, bool useCL, bool useDpsFireTotem, bool useFireEle)
        {
            if (Talents == null || LB == null || FS == null || LvBFS == null || LvB == null || CL == null || FN == null || ST == null || MT == null || FrS == null)
            {
                return;
            }
            this.useDpsFireTotem = useDpsFireTotem;
            spells.Clear();
            Invalidate();

            float LvBreadyAt = 0, FSdropsAt = 0, clReadyAt = 0, fnReadyAt = 0, activeTotemDropsAt = 0;//, fireEleDropsAt = 0, fireEleReadyAt = 0;

            //float lsCharges = 0f, fsTicks = 0f;

            #region GiantBlock
            switch (useDpsFireTotem)
            {
            case true:
                #region Massive Comment Block About Totem Math
                /// Reasoning for this block:
                /// Magma totem is always higher DpS than searing totem.  The old formula, which used DpCT instead of
                /// periodic DpS, always favored searing totem over magma totem, which isn't true in all cases.  The reason
                /// searing eventually "outscales" magma is because magma's excessive use of GCDs for 100% uptime makes it
                /// less favorable in gear with lots of haste, when the shaman begins approaching the GCD with spells.
                /// Losing a GCD when an LB takes 2 seconds to cast is less costly than a GCD with a 1.2 second LB.
                /// Theory behind it:
                /// The higher DpS spell between CL and LB will be the relative benchmark.  The gap in DpS between magma
                /// and searing are taken and multiplied by 20 (the amount of damage gained by using magma in that period).
                /// It is then modified by the cast time difference between MT and the relativeDpSValue.  This adjusts
                /// magma's value according to how much of a gap there is in between the GCD and the cast time of the
                /// benchmark spell.  The larger the gap, the more valuable magma totem's gained DpS.  If the gained DpS
                /// isn't more valuable than the direct DpS of the benchmark, searing is selected instead.
                #endregion

                Spell relativeDpSValue = (CL.DirectDpS > LB.DirectDpS) ? (Spell)CL : (Spell)LB;
                if ((((MT.PeriodicDpS - ST.PeriodicDpS) * MT.Duration) / (MT.CastTime / relativeDpSValue.CastTime))
                    > relativeDpSValue.DirectDpS)
                {
                    ActiveTotem = MT;
                }
                else
                {
                    ActiveTotem = ST;
                }
                break;

            case false:
                ActiveTotem        = null;
                activeTotemDropsAt = float.PositiveInfinity;
                break;
            }

            while (true)
            {
                if (GetTime() >= LvBreadyAt)                              //LvB is ready
                {
                    if (GetTime() + LvBFS.CastTimeWithoutGCD < FSdropsAt) //the LvB cast will be finished before FS runs out
                    {
                        AddSpell(LvBFS);
                        LvBreadyAt = GetTime() + LvBFS.Cooldown;
                    }
                    else if (FSdropsAt == 0) //the first FS
                    {
                        FSdropsAt = GetTime() + FS.Duration;
                        AddSpell(FS);
                    }
                    else //since FS would run out recast FS now -> Rotation end
                    {
                        break; //done
                    }
                }
                else //LvB is not ready
                {
                    if (GetTime() + LvB.CastTime > FSdropsAt) //FS will run out
                    {
                        if (((LB.DpCT > (Math.Max((useCL && clReadyAt < GetTime()) ? CL.DpCT : 0, (useFN && fnReadyAt < GetTime()) ? FN.DpCT : 0)))) &&
                            (LB.DpCT > (((activeTotemDropsAt < GetTime()) && useDpsFireTotem) ? ActiveTotem.PeriodicDamage() : 0)))
                        {                                                             // LB is the best option available
                            if (LvBreadyAt - (GetTime() + FS.CastTime) > LB.CastTime) //there is enough time to fit in another LB and a FS before LvB is ready
                            {
                                AddSpell(LB);
                            }
                            else //if (LvBreadyAt - (GetTime() + FS.CastTime) > 0 && addlb2) //FS would still fit in before LvB is ready
                            {
                                AddSpell(LB);
                                break; //FS recast nescessary -> done
                            }
                        }
                        else if ((((useCL && clReadyAt < GetTime()) ? CL.DpCT : 0) >
                                  ((useFN && fnReadyAt < GetTime()) ? FN.DpCT : 0)) &&
                                 (CL.DpCT > ((activeTotemDropsAt < GetTime()) && (useDpsFireTotem) ? ActiveTotem.PeriodicDamage() : 0)))
                        // CL > FN and CL > Totem [Or totem doesn't need refreshed]
                        {
                            if (LvBreadyAt - (GetTime() + FS.CastTime) > CL.CastTime) // Can fit another CL and FS
                            {
                                AddSpell(CL);
                                clReadyAt = GetTime() + CL.Cooldown;
                            }
                            else
                            {
                                AddSpell(CL);
                                clReadyAt = GetTime() + CL.Cooldown;
                                break;
                            }
                        }
                        else if ((useFN && fnReadyAt < GetTime()) && (activeTotemDropsAt > GetTime()))
                        // FN > CL and FN > Totem [Or totem doesn't need refreshed]
                        {
                            if (LvBreadyAt - (GetTime() + FS.CastTime) > FN.CastTime) // Can fit another FN and FS
                            {
                                AddSpell(FN);
                                fnReadyAt = GetTime() + FN.Cooldown;
                            }
                            else
                            {
                                AddSpell(FN);
                                fnReadyAt = GetTime() + FN.Cooldown;
                                break;
                            }
                        }
                        else // If the totem needs refreshed...
                        {
                            AddSpell(ActiveTotem);
                            activeTotemDropsAt = ActiveTotem.Duration + GetTime();
                        }
                    }
                    else if (LvBreadyAt - GetTime() <= LB.CastTime && !addlb1) //time before the next LvB is lower than LB cast time
                    {
                        AddSpell(new Wait(LvBreadyAt - GetTime()));
                    }
                    else //LvB is on cooldown, FS won't run out soon
                    if (((LB.DpCT > (Math.Max((useCL && clReadyAt < GetTime()) ? CL.DpCT : 0, (useFN && fnReadyAt < GetTime()) ? FN.DpCT : 0)))) &&
                        (LB.DpCT > (((activeTotemDropsAt < GetTime()) && useDpsFireTotem) ? ActiveTotem.PeriodicDamage() : 0)))
                    {        //Is LB Dmg per cast time bigger than the Dpct of CL or FN and are these spells ready?
                        AddSpell(LB);
                    }
                    else if ((((useCL && clReadyAt < GetTime()) ? CL.DpCT : 0) >
                              ((useFN && fnReadyAt < GetTime()) ? FN.DpCT : 0)) &&
                             (CL.DpCT > ((activeTotemDropsAt < GetTime()) && (useDpsFireTotem) ? ActiveTotem.PeriodicDamage() : 0)))
                    // CL > FN and CL > Totem [Or totem doesn't need refreshed]
                    {
                        AddSpell(CL);
                        clReadyAt = GetTime() + CL.Cooldown;
                    }
                    else if ((useFN && fnReadyAt < GetTime()) && (activeTotemDropsAt > GetTime()))
                    {        //FN > CL
                        AddSpell(FN);
                        fnReadyAt = GetTime() + FN.Cooldown;
                    }
                    else     // If the totem needs refreshed...
                    {
                        AddSpell(ActiveTotem);
                        activeTotemDropsAt = ActiveTotem.Duration + GetTime();
                    }
                }
            }
            #endregion

            // Have to move to a priority queue.
        }