예제 #1
0
        public override RogueRotationCalculation GetRotationCalculations(float durationMult, int cPG, int recupCP, int ruptCP, bool useRS, int finisher, int evisCP, int snDCP, int mHPoison, int oHPoison, bool useTotT, int exposeCP, bool PTRMode)
        {
            Duration             = BossOpts.BerserkTimer;
            UseTotT              = useTotT;
            NumberOfStealths     = getNumberStealths();
            EnergyRegen          = getEnergyRegen();
            TotalEnergyAvailable = getEnergyAvailable();
            float averageGCD          = 1f / (1f - AvoidedMHAttacks);
            float averageFinisherGCD  = 1f / (1f - AvoidedFinisherAttacks);
            float ruptDurationAverage = RuptStats.DurationAverage;
            float snDDurationAverage  = SnDStats.DurationAverage;

            float[] _avgCP = CPG == 1 ? _averageSStrikeCP : _averageNormalCP;

            #region Melee
            float whiteMHAttacks = Duration / MainHandSpeed;
            float whiteOHAttacks = Duration / OffHandSpeed;
            float mGAttacks      = ChanceOnMGAttackOnMHAttack * whiteMHAttacks;
            TotalEnergyAvailable += (whiteOHAttacks * (1f - AvoidedWhiteOHAttacks) + mGAttacks * (1f - AvoidedMHAttacks)) * EnergyOnOHAttack;
            #endregion

            #region Combo Point Generator
            CPGCount  = 0f;
            CPGEnergy = getCPGEnergy();
            CPPerCPG  = getCPPerCPG();
            #endregion

            #region Slice and Dice
            float avgSnDCP       = _avgCP[snDCP];
            float effSnDCP       = Math.Min(RV.MaxCP, avgSnDCP);
            float snDDuration    = SnDStats.DurationAverage + SnDStats.DurationPerCP * effSnDCP;
            float snDCount       = getSnDCount(snDDuration);
            float snDTotalEnergy = snDCount * (SnDStats.EnergyCost - RV.Talents.RelentlessStrikesEnergyBonus * ChanceOnEnergyPerCPFinisher * effSnDCP);
            float snDCPRequired  = snDCount * (avgSnDCP - CPOnFinisher);
            processFinisher(snDCPRequired, snDTotalEnergy);
            #endregion

            #region Expose Armor
            float rSCount     = 0f;
            float exposeCount = 0f;
            if (exposeCP > 0)
            {
                float avgExposeCP    = _avgCP[exposeCP] * (1f - ExposeCPCostMult);
                float effExposeCP    = Math.Min(RV.MaxCP, avgExposeCP);
                float exposeDuration = ExposeStats.DurationAverage + ExposeStats.DurationPerCP * effExposeCP;
                exposeCount = Duration / (exposeDuration * (1f + RSBonus));
                float exposeTotalEnergy = exposeCount * (ExposeStats.EnergyCost - RV.Talents.RelentlessStrikesEnergyBonus * ChanceOnEnergyPerCPFinisher * effExposeCP + (useRS ? exposeCount * RStrikeStats.EnergyCost : 0f));
                float exposeCPRequired  = exposeCount * (Math.Max(0f, avgExposeCP - CPOnFinisher) - (useRS ? RStrikeStats.CPPerSwing : 0f));
                rSCount += useRS ? exposeCount : 0f;
                processFinisher(exposeCPRequired, exposeTotalEnergy);
            }
            #endregion

            #region Damage Finishers
            float ruptCount = 0f;
            float evisCount = 0f;
            float avgRuptCP = _avgCP[ruptCP];
            float effRuptCP = Math.Min(RV.MaxCP, avgRuptCP);
            #region Rupture
            if (ruptCP > 0)
            {
                float ruptDuration = RuptStats.DurationAverage + RuptStats.DurationPerCP * effRuptCP;
                ruptCount = Duration / ruptDuration;
                float ruptTotalEnergy = ruptCount * (RuptStats.EnergyCost + (useRS ? ruptCount * RStrikeStats.EnergyCost : 0f) -
                                                     effRuptCP * (RV.Talents.RelentlessStrikesEnergyBonus * ChanceOnEnergyPerCPFinisher + EnergyRegenTimeOnDamagingCP * EnergyRegen));
                rSCount += useRS ? ruptCount : 0f;
                float ruptCPRequired = ruptCount * (Math.Max(0f, avgRuptCP - CPOnFinisher) - (useRS ? RStrikeStats.CPPerSwing : 0f));
                processFinisher(ruptCPRequired, ruptTotalEnergy);
            }
            #endregion
            #region Eviscerate
            float avgEvisCP       = _avgCP[evisCP];
            float effEvisCP       = Math.Min(RV.MaxCP, avgEvisCP);
            float evisCycleEnergy = ((avgEvisCP - CPOnFinisher - (useRS ? RStrikeStats.CPPerSwing : 0f)) / CPPerCPG) * CPGEnergy + EvisStats.EnergyCost + (useRS ? RStrikeStats.EnergyCost : 0f) - effEvisCP * (RV.Talents.RelentlessStrikesEnergyBonus * ChanceOnEnergyPerCPFinisher + EnergyRegenTimeOnDamagingCP * EnergyRegen);
            evisCount            = TotalEnergyAvailable / evisCycleEnergy;
            CPGCount            += evisCount * (avgEvisCP - CPOnFinisher - (useRS ? RStrikeStats.CPPerSwing : 0f)) / CPPerCPG;
            rSCount             += useRS ? evisCount : 0f;
            TotalEnergyAvailable = 0f;
            #endregion
            #endregion

            #region Poisons
            float mHPoisonHitCount = (whiteMHAttacks * (1f - AvoidedWhiteMHAttacks) + CPGCount + evisCount + ruptCount) * (1f - AvoidedPoisonAttacks);
            float oHPoisonHitCount = whiteOHAttacks * (1f - AvoidedWhiteOHAttacks) * (1f - AvoidedPoisonAttacks);
            float iPCount          = 0f;
            float dPTicks          = 0f;
            float wPCount          = 0f;
            float iPProcRate       = RV.IP.Chance / RV.IP.NormWeapSpeed;
            float dPApplyChance    = RV.DP.Chance;
            #region MainHand Poison
            if (mHPoison == 1)
            {
                iPCount += mHPoisonHitCount * MainHandStats.Weapon._speed * iPProcRate;
            }
            else if (mHPoison == 2 && oHPoison != 2)
            {
                float dPStackTime = RV.DP.MaxStack * MainHandSpeed / (dPApplyChance * (1f - AvoidedPoisonAttacks) * (1f - AvoidedWhiteMHAttacks));
                dPTicks = RV.DP.MaxStack * Duration / RV.DP.TickTime - RV.GetMissedDPTicks(dPStackTime);
                float dPCountAtMaxStack = mHPoisonHitCount * dPApplyChance * (Duration - dPStackTime) / Duration;
                if (oHPoison == 1)
                {
                    iPCount += dPCountAtMaxStack;
                }
                else if (oHPoison == 3)
                {
                    wPCount += dPCountAtMaxStack;
                }
            }
            else if (mHPoison == 3)
            {
                wPCount += mHPoisonHitCount * MainHandStats.Weapon._speed * RV.WP.Chance / RV.WP.NormWeapSpeed;
            }
            #endregion
            #region OffHand Poison
            if (oHPoison == 1)
            {
                iPCount += oHPoisonHitCount * OffHandStats.Weapon._speed * iPProcRate;
            }
            else if (oHPoison == 2 && mHPoison != 2)
            {
                float dPStackTime = RV.DP.MaxStack * OffHandSpeed / (dPApplyChance * (1f - AvoidedPoisonAttacks) * (1f - AvoidedWhiteMHAttacks));
                dPTicks = RV.DP.MaxStack * Duration / RV.DP.TickTime - RV.GetMissedDPTicks(dPStackTime);
                float dPCountAtMaxStack = oHPoisonHitCount * dPApplyChance * (Duration - dPStackTime) / Duration;
                if (mHPoison == 1)
                {
                    iPCount += dPCountAtMaxStack;
                }
                else if (mHPoison == 3)
                {
                    wPCount += dPCountAtMaxStack;
                }
            }
            else if (oHPoison == 3)
            {
                wPCount += oHPoisonHitCount * OffHandStats.Weapon._speed * RV.WP.Chance / RV.WP.NormWeapSpeed;
            }
            #endregion
            iPCount *= (1f - AvoidedPoisonAttacks);
            wPCount *= (1f - AvoidedPoisonAttacks);
            #endregion

            #region Killing Spree & Adrenaline Rush
            float kSAttacks           = 0;
            float kSDuration          = 0;
            float kSDmgBonus          = RV.KS.DmgMult + (Talents.GlyphOfKillingSpree ? RV.Glyph.KSDmgMultBonus : 0f);
            float restlessBladesBonus = _avgCP[ruptCP] * ruptCount + _avgCP[evisCP] * evisCount * Talents.RestlessBlades * RV.Talents.RestlessBladesPerCPCDReduc;
            if (Talents.KillingSpree > 0)
            {
                float kSCount = (Duration + restlessBladesBonus) / RV.KS.CD;
                kSDuration = kSCount * RV.KS.Duration;
                kSAttacks  = RV.KS.StrikeCount * kSCount;
            }
            if (Talents.AdrenalineRush > 0)
            {
                float ARMult = RV.AR.MeleeSpeedMult * (RV.AR.Duration + (Talents.GlyphOfAdrenalineRush ? RV.Glyph.ARDurationBonus : 0f)) * (Duration + restlessBladesBonus) / RV.AR.CD / Duration;
                whiteMHAttacks *= 1f + ARMult;
                whiteOHAttacks *= 1f + ARMult;
            }
            #endregion

            #region Damage Totals
            float evisCrits = (whiteMHAttacks + whiteOHAttacks) * T411 * RV.Set.T114ProcChance;

            float mainHandDamageTotal = whiteMHAttacks * MainHandStats.DamagePerSwing +
                                        kSAttacks * MainHandStats.DamagePerSwing * (1f + kSDmgBonus) / (1f + kSDmgBonus * kSDuration / Duration);
            float offHandDamageTotal = whiteOHAttacks * OffHandStats.DamagePerSwing +
                                       kSAttacks * OffHandStats.DamagePerSwing * (1f + kSDmgBonus) / (1f + kSDmgBonus * kSDuration / Duration);
            float mainGaucheDamageTotal = mGAttacks * MainGaucheStats.DamagePerSwing;
            float sStrikeDamageTotal    = CPGCount * SStrikeStats.DamagePerSwing;
            float rStrikeDamageTotal    = rSCount * RStrikeStats.DamagePerSwing;
            float ruptDamageTotal       = (ruptCount * RuptStats.DamagePerSwingArray[(int)Math.Floor((double)effRuptCP)] + (effRuptCP - (float)Math.Floor((double)effRuptCP)) * (RuptStats.DamagePerSwingArray[(int)Math.Min(Math.Floor((double)effRuptCP) + 1, 5)] - RuptStats.DamagePerSwingArray[(int)Math.Floor((double)effRuptCP)])) * (useRS ? (1f + RSBonus) : 1f);
            float evisDamageTotal       = evisCount * (EvisStats.DamagePerSwing + EvisStats.DamagePerSwingPerCP * Math.Min(_avgCP[evisCP], 5)) * (useRS ? (1f + RSBonus) : 1f) +
                                          evisCrits * (EvisStats.DamagePerCrit + EvisStats.DamagePerCritPerCP * Math.Min(_avgCP[evisCP], 5));
            float instantPoisonTotal = iPCount * IPStats.DamagePerSwing;
            float deadlyPoisonTotal  = dPTicks * DPStats.DamagePerSwing;
            float woundPoisonTotal   = wPCount * WPStats.DamagePerSwing;

            float damageTotal = (mainHandDamageTotal + offHandDamageTotal + sStrikeDamageTotal + rStrikeDamageTotal + ruptDamageTotal + evisDamageTotal + instantPoisonTotal + deadlyPoisonTotal +
                                 woundPoisonTotal) * (1f + kSDmgBonus * kSDuration / Duration);
            if (Talents.BanditsGuile > 0)
            {
                float buildupTime = Duration / (((CPG == 1 ? CPGCount : 0) + rSCount) * RV.Talents.BanditsGuileChance[Talents.BanditsGuile]);
                float guileBonus  = RV.Talents.BanditsGuileStep / buildupTime + 2f * RV.Talents.BanditsGuileStep / buildupTime + 3 * RV.Talents.BanditsGuileStep / RV.Talents.BanditsGuileDuration;
                damageTotal *= 1f + guileBonus;
            }
            #endregion

            return(new RogueRotationCalculation()
            {
                MultipleSegments = Duration < 1f,
                Duration = Duration,
                TotalDamage = damageTotal,
                DPS = damageTotal / Duration,

                MainHandCount = whiteMHAttacks,
                OffHandCount = whiteOHAttacks,
                MGCount = mGAttacks,
                SStrikeCount = CPGCount,
                RStrikeCount = rSCount,
                RuptCount = ruptCount,
                EvisCount = evisCount,
                SnDCount = snDCount,
                EACount = exposeCount,
                IPCount = iPCount,
                DPCount = dPTicks,
                WPCount = wPCount,

                FinisherCP = evisCP,
                EvisCP = Math.Min(_avgCP[evisCP], 5),
                RuptCP = ruptCP,
                SnDCP = snDCP,

                MHPoison = mHPoison,
                OHPoison = oHPoison,

                UseTotT = useTotT,
            });
        }
예제 #2
0
        public override RogueRotationCalculation GetRotationCalculations(float durationMult, int cPG, int recupCP, int ruptCP, bool useRS, int finisher, int envenomCP, int snDCP, int mHPoison, int oHPoison, bool useTotT, int exposeCP, bool PTRMode)
        {
            DurationMult         = durationMult;
            Duration             = durationMult * BossOpts.BerserkTimer;
            UseTotT              = useTotT;
            CPG                  = cPG;
            NumberOfStealths     = getNumberStealths();
            EnergyRegen          = getEnergyRegen();
            TotalEnergyAvailable = getEnergyAvailable();
            TotalCPAvailable     = getCPAvailable();
            float[] _avgCP = CPG == 0 ? _averageMutiCP : _averageNormalCP;

            #region Melee
            float whiteMHAttacks = Duration / MainHandSpeed;
            float whiteOHAttacks = Duration / OffHandSpeed;
            TotalEnergyAvailable += whiteOHAttacks * (1f - AvoidedWhiteOHAttacks) * EnergyOnOHAttack;
            #endregion

            #region Combo Point Generator
            CPGCount  = 0f;
            CPGEnergy = getCPGEnergy();
            CPPerCPG  = getCPPerCPG();
            #endregion

            #region Slice and Dice
            float avgSnDCP       = _avgCP[snDCP];
            float effSnDCP       = Math.Min(RV.MaxCP, avgSnDCP);
            float snDDuration    = SnDStats.DurationAverage + SnDStats.DurationPerCP * effSnDCP;
            float snDCount       = getSnDCount(snDDuration);
            float snDTotalEnergy = snDCount * (SnDStats.EnergyCost - RV.Talents.RelentlessStrikesEnergyBonus * ChanceOnEnergyPerCPFinisher * effSnDCP);
            float snDCPRequired  = snDCount * (avgSnDCP - CPOnFinisher);
            processFinisher(snDCPRequired, snDTotalEnergy);
            #endregion

            #region Expose Armor
            float exposeCount = 0f;
            if (exposeCP > 0)
            {
                float avgExposeCP    = _avgCP[exposeCP] * (1f - ExposeCPCostMult);
                float effExposeCP    = Math.Min(RV.MaxCP, avgExposeCP);
                float exposeDuration = ExposeStats.DurationAverage + ExposeStats.DurationPerCP * effExposeCP;
                exposeCount = Duration / (exposeDuration * (1f + RSBonus));
                float exposeTotalEnergy = exposeCount * (ExposeStats.EnergyCost - RV.Talents.RelentlessStrikesEnergyBonus * ChanceOnEnergyPerCPFinisher * effExposeCP);
                float exposeCPRequired  = exposeCount * (Math.Max(0f, avgExposeCP - CPOnFinisher));
                processFinisher(exposeCPRequired, exposeTotalEnergy);
            }
            #endregion

            #region Damage Finishers
            float ruptCount    = 0f;
            float envenomCount = 0f;
            float avgRuptCP    = _avgCP[ruptCP];
            float effRuptCP    = Math.Min(RV.MaxCP, avgRuptCP);
            #region Rupture
            if (ruptCP > 0)
            {
                float ruptDuration = RuptStats.DurationAverage + RuptStats.DurationPerCP * effRuptCP;
                ruptCount = Duration / ruptDuration;
                float ruptTotalEnergy = ruptCount * (RuptStats.EnergyCost - effRuptCP * (RV.Talents.RelentlessStrikesEnergyBonus * ChanceOnEnergyPerCPFinisher) -
                                                     ChanceOnEnergyOnGarrRuptTick * RV.Talents.VenomousWoundsEnergy * ruptDuration / RV.Rupt.TickTime);
                float ruptCPRequired = ruptCount * (Math.Max(0f, avgRuptCP - CPOnFinisher));
                processFinisher(ruptCPRequired, ruptTotalEnergy);
            }
            float venomousWoundsCount = ruptCount * (RuptStats.DurationAverage + ruptCP * RuptStats.DurationPerCP) / RV.Rupt.TickTime;
            #endregion
            #region Envenom
            float averageEnvenomCP   = _avgCP[envenomCP];
            float envenomCycleEnergy = ((averageEnvenomCP - CPOnFinisher) / CPPerCPG) * CPGEnergy + EnvenomStats.EnergyCost - RV.Talents.RelentlessStrikesEnergyBonus * ChanceOnEnergyPerCPFinisher * averageEnvenomCP;
            envenomCount         = TotalEnergyAvailable / envenomCycleEnergy;
            CPGCount            += envenomCount * (averageEnvenomCP - CPOnFinisher) / CPPerCPG;
            TotalEnergyAvailable = 0f;
            #endregion
            #endregion

            #region Poisons
            float mHPoisonHitCount = (whiteMHAttacks * (1f - AvoidedWhiteMHAttacks) + CPGCount + envenomCount + ruptCount) * (1f - AvoidedPoisonAttacks);
            float oHPoisonHitCount = (whiteOHAttacks * (1f - AvoidedWhiteOHAttacks) + (CPG == 0 ? CPGCount : 0)) * (1f - AvoidedPoisonAttacks);
            float iPCount          = 0f;
            float dPTicks          = 0f;
            float wPCount          = 0f;
            float iPProcRate       = RV.IP.Chance * (1f + IPFrequencyMultiplier) / RV.IP.NormWeapSpeed;
            float dPApplyChance    = RV.DP.Chance + DPFrequencyBonus;
            float envBuffDuration  = envenomCount > 0 ? RV.Envenom.BuffDuration + Math.Max(5f, _avgCP[envenomCP]) * RV.Envenom.BuffDurationPerCP : 0f;
            float envBuffTime      = envenomCount * envBuffDuration;
            #region MainHand Poison
            if (mHPoison == 1)
            {
                iPCount += mHPoisonHitCount * MainHandStats.Weapon._speed * iPProcRate * (Duration - envBuffTime + (1f + RV.Envenom.BuffIPChanceMult) * envBuffTime) / Duration;
            }
            else if (mHPoison == 2 && oHPoison != 2)
            {
                float dPStackTime      = RV.DP.MaxStack * MainHandSpeed / (dPApplyChance * (1f - AvoidedPoisonAttacks) * (1f - AvoidedWhiteMHAttacks));
                float envBuffRemainder = 0f;
                float dPStackTimeBuff  = 0f;
                #region Calculate DP stack time with Envenom buff
                float dPStackTimeBuffed = (1f - ChanceOnNoDPConsumeOnEnvenom) * RV.DP.MaxStack * MainHandSpeed / ((dPApplyChance + RV.Envenom.BuffDPChanceBonus) * (1f - AvoidedPoisonAttacks) * (1f - AvoidedWhiteMHAttacks));
                if (dPStackTimeBuffed >= envBuffDuration)
                {
                    float dPStackTimeRemainder = (1f - envBuffDuration / dPStackTimeBuffed) * RV.DP.MaxStack * MainHandSpeed / (dPApplyChance * (1f - AvoidedPoisonAttacks) * (1f - AvoidedWhiteMHAttacks));
                    dPStackTimeBuff = envBuffDuration + dPStackTimeRemainder;
                }
                else
                {
                    envBuffRemainder = envBuffDuration - dPStackTimeBuffed;
                    dPStackTimeBuff  = dPStackTimeBuffed;
                }
                #endregion
                dPTicks = RV.DP.MaxStack * Duration / RV.DP.TickTime - (1f - ChanceOnNoDPConsumeOnEnvenom) * envenomCount * RV.GetMissedDPTicks(dPStackTimeBuff) - RV.GetMissedDPTicks(dPStackTime);
                float dPCountAtMaxStack = mHPoisonHitCount * dPApplyChance * (Duration - dPStackTime + envenomCount * (-dPStackTimeBuff + (1f + RV.Envenom.BuffDPChanceBonus) * envBuffRemainder)) / Duration;
                if (oHPoison == 1)
                {
                    iPCount += dPCountAtMaxStack;
                }
                else if (oHPoison == 3)
                {
                    wPCount += dPCountAtMaxStack;
                }
            }
            else if (mHPoison == 3)
            {
                wPCount += mHPoisonHitCount * MainHandStats.Weapon._speed * RV.WP.Chance / RV.WP.NormWeapSpeed;
            }
            #endregion
            #region OffHand Poison
            if (oHPoison == 1)
            {
                iPCount += oHPoisonHitCount * OffHandStats.Weapon._speed * iPProcRate * (Duration - envBuffTime + (1f + RV.Envenom.BuffIPChanceMult) * envBuffTime) / Duration;
            }
            else if (oHPoison == 2 && mHPoison != 2)
            {
                float dPStackTime      = RV.DP.MaxStack * OffHandSpeed / (dPApplyChance * (1f - AvoidedPoisonAttacks) * (1f - AvoidedWhiteMHAttacks));
                float envBuffRemainder = 0f;
                float dPStackTimeBuff  = 0f;
                #region Calculate DP stack time with Envenom buff
                float dPStackTimeBuffed = (1f - ChanceOnNoDPConsumeOnEnvenom) * RV.DP.MaxStack * OffHandSpeed / ((dPApplyChance + RV.Envenom.BuffDPChanceBonus) * (1f - AvoidedPoisonAttacks) * (1f - AvoidedWhiteOHAttacks));
                if (dPStackTimeBuffed >= envBuffDuration)
                {
                    float dPStackTimeRemainder = (1f - envBuffDuration / dPStackTimeBuffed) * RV.DP.MaxStack * OffHandSpeed / (dPApplyChance * (1f - AvoidedPoisonAttacks) * (1f - AvoidedWhiteOHAttacks));
                    dPStackTimeBuff = envBuffDuration + dPStackTimeRemainder;
                }
                else
                {
                    envBuffRemainder = envBuffDuration - dPStackTimeBuffed;
                    dPStackTimeBuff  = dPStackTimeBuffed;
                }
                #endregion
                dPTicks = RV.DP.MaxStack * Duration / RV.DP.TickTime - (1f - ChanceOnNoDPConsumeOnEnvenom) * envenomCount * RV.GetMissedDPTicks(dPStackTimeBuff) - RV.GetMissedDPTicks(dPStackTime);
                float dPCountAtMaxStack = oHPoisonHitCount * dPApplyChance * (Duration - dPStackTime + envenomCount * (-dPStackTimeBuff + (1f + RV.Envenom.BuffDPChanceBonus) * envBuffRemainder)) / Duration;
                if (mHPoison == 1)
                {
                    iPCount += dPCountAtMaxStack;
                }
                else if (mHPoison == 3)
                {
                    wPCount += dPCountAtMaxStack;
                }
            }
            else if (oHPoison == 3)
            {
                wPCount += oHPoisonHitCount * OffHandStats.Weapon._speed * RV.WP.Chance / RV.WP.NormWeapSpeed;
            }
            #endregion
            iPCount *= (1f - AvoidedPoisonAttacks);
            wPCount *= (1f - AvoidedPoisonAttacks);
            #endregion

            #region Damage Totals
            float envenomCrits = (whiteMHAttacks + whiteOHAttacks) * T411 * RV.Set.T114ProcChance;

            float mainHandDamageTotal = whiteMHAttacks * MainHandStats.DamagePerSwing;
            float offHandDamageTotal  = whiteOHAttacks * OffHandStats.DamagePerSwing;
            float mutiDamageTotal     = (CPG == 0 ? CPGCount : 0) * MutiStats.DamagePerSwing;
            float backstabDamageTotal = (CPG == 1 ? CPGCount : 0) * BackstabStats.DamagePerSwing;
            float ruptDamageTotal     = ruptCount * RuptStats.DamagePerSwingArray[(int)Math.Floor((double)effRuptCP)] + (effRuptCP - (float)Math.Floor((double)effRuptCP)) * (RuptStats.DamagePerSwingArray[(int)Math.Min(Math.Floor((double)effRuptCP) + 1, 5)] - RuptStats.DamagePerSwingArray[(int)Math.Floor((double)effRuptCP)]);
            float envenomDamageTotal  = (envenomCount - envenomCrits) * (EnvenomStats.DamagePerSwing + EnvenomStats.DamagePerSwingPerCP * Math.Min(_avgCP[envenomCP], 5)) +
                                        envenomCrits * (EnvenomStats.DamagePerCrit + EnvenomStats.DamagePerCritPerCP * Math.Min(_avgCP[envenomCP], 5));
            float instantPoisonTotal  = iPCount * IPStats.DamagePerSwing;
            float deadlyPoisonTotal   = dPTicks * DPStats.DamagePerSwing;
            float woundPoisonTotal    = wPCount * WPStats.DamagePerSwing;
            float venomousWoundsTotal = venomousWoundsCount * VenomousWoundsStats.DamagePerSwing;

            float damageTotal = (mainHandDamageTotal + offHandDamageTotal + backstabDamageTotal + mutiDamageTotal + ruptDamageTotal + envenomDamageTotal + instantPoisonTotal +
                                 deadlyPoisonTotal + woundPoisonTotal + venomousWoundsTotal);
            #endregion

            return(new RogueRotationCalculation()
            {
                Duration = Duration,
                MultipleSegments = DurationMult < 1f,
                TotalDamage = damageTotal,
                DPS = damageTotal / Duration,

                MainHandCount = whiteMHAttacks,
                OffHandCount = whiteOHAttacks,
                BackstabCount = (CPG == 1 ? CPGCount : 0),
                MutiCount = (CPG == 0 ? CPGCount : 0),
                RuptCount = ruptCount,
                EnvenomCount = envenomCount,
                SnDCount = snDCount,
                EACount = exposeCount,
                IPCount = iPCount,
                DPCount = dPTicks,
                VenomousWoundsCount = venomousWoundsCount,

                FinisherCP = envenomCP,
                EnvenomCP = Math.Min(_avgCP[envenomCP], 5),
                RuptCP = ruptCP,
                SnDCP = snDCP,

                MHPoison = mHPoison,
                OHPoison = oHPoison,

                UseTotT = useTotT,
                CutToTheChase = ChanceOnSnDResetOnEvisEnv,
            });
        }
예제 #3
0
        public override RogueRotationCalculation GetRotationCalculations(float durationMult, int cPG, int recupCP, int ruptCP, bool useHemo, int finisher, int finisherCP, int snDCP, int mHPoison, int oHPoison, bool useTotT, int exposeCP, bool PTRMode)
        {
            Duration             = BossOpts.BerserkTimer;
            RecupCP              = recupCP;
            UseTotT              = useTotT;
            CPG                  = cPG;
            NumberOfStealths     = getNumberStealths();
            EnergyRegen          = getEnergyRegen();
            TotalEnergyAvailable = getEnergyAvailable();
            TotalCPAvailable     = getCPAvailable();
            float averageGCD          = 1f / (1f - AvoidedMHAttacks);
            float averageFinisherGCD  = 1f / (1f - AvoidedFinisherAttacks);
            float ruptDurationAverage = RuptStats.DurationAverage;
            float snDDurationAverage  = SnDStats.DurationAverage;

            float[] _avgCP            = _averageNormalCP;
            float   averageFinisherCP = _avgCP[5];

            #region Melee
            float whiteMHAttacks = Duration / MainHandSpeed;
            float whiteOHAttacks = Duration / OffHandSpeed;
            TotalEnergyAvailable += whiteOHAttacks * (1f - AvoidedWhiteOHAttacks) * EnergyOnOHAttack;
            #endregion

            #region Combo Point Generator
            CPGCount  = 0f;
            CPGEnergy = getCPGEnergy();
            CPPerCPG  = getCPPerCPG();
            float hemoCount = 0f;
            if (useHemo)
            {
                hemoCount             = Duration / RV.Hemo.DebuffDuration;
                TotalCPAvailable     += hemoCount * HemoStats.CPPerSwing;
                TotalEnergyAvailable -= hemoCount * HemoStats.EnergyCost;
            }
            #endregion

            #region Slice and Dice
            float avgSnDCP       = _avgCP[snDCP];
            float effSnDCP       = Math.Min(RV.MaxCP, avgSnDCP);
            float snDDuration    = SnDStats.DurationAverage + SnDStats.DurationPerCP * effSnDCP;
            float snDCount       = getSnDCount(snDDuration);
            float snDTotalEnergy = snDCount * (SnDStats.EnergyCost - RV.Talents.RelentlessStrikesEnergyBonus * ChanceOnEnergyPerCPFinisher * effSnDCP);
            float snDCPRequired  = snDCount * (avgSnDCP - CPOnFinisher);
            processFinisher(snDCPRequired, snDTotalEnergy);
            #endregion

            #region Recuperate
            float recupCount = 0f;
            if (recupCP > 0)
            {
                float avgRecupCP    = _avgCP[recupCP];
                float effRecupCP    = Math.Min(RV.MaxCP, avgRecupCP);
                float recupDuration = RecupStats.DurationAverage + RecupStats.DurationPerCP * effRecupCP;
                recupCount = Duration / recupDuration;
                float recupTotalEnergy = recupCount * (RecupStats.EnergyCost - RV.Talents.RelentlessStrikesEnergyBonus * ChanceOnEnergyPerCPFinisher * effRecupCP);
                float recupCPRequired  = recupCount * (avgRecupCP - CPOnFinisher);
                processFinisher(recupCPRequired, recupTotalEnergy);
            }
            #endregion

            #region Expose Armor
            float exposeCount = 0f;
            if (exposeCP > 0)
            {
                float avgExposeCP    = _avgCP[exposeCP] * (1f - ExposeCPCostMult);
                float effExposeCP    = Math.Min(RV.MaxCP, avgExposeCP);
                float exposeDuration = ExposeStats.DurationAverage + ExposeStats.DurationPerCP * effExposeCP;
                exposeCount = Duration / exposeDuration;
                float exposeTotalEnergy = exposeCount * (ExposeStats.EnergyCost - RV.Talents.RelentlessStrikesEnergyBonus * ChanceOnEnergyPerCPFinisher * effExposeCP);
                float exposeCPRequired  = exposeCount * (Math.Max(0f, avgExposeCP - CPOnFinisher));
                processFinisher(exposeCPRequired, exposeTotalEnergy);
            }
            #endregion

            #region Damage Finishers
            float ruptCount     = 0f;
            float evisCount     = 0f;
            float avgRuptCP     = _avgCP[ruptCP];
            float effRuptCP     = Math.Min(RV.MaxCP, avgRuptCP);
            float realRuptCount = 0f;
            #region Rupture
            if (ruptCP > 0)
            {
                float ruptDuration = RuptStats.DurationAverage + RuptStats.DurationPerCP * effRuptCP;
                ruptCount     = Duration / ruptDuration;
                realRuptCount = Math.Max(1f, Duration / ruptDuration * (1f - ChanceOnRuptResetonEvisCP * Math.Min(RV.MaxCP, _avgCP[finisherCP])));
                float ruptTotalEnergy = realRuptCount * (RuptStats.EnergyCost - effRuptCP * (RV.Talents.RelentlessStrikesEnergyBonus * ChanceOnEnergyPerCPFinisher));
                float ruptCPRequired  = realRuptCount * (Math.Max(0f, avgRuptCP - CPOnFinisher));
                processFinisher(ruptCPRequired, ruptTotalEnergy);
            }
            #endregion
            #region Eviscerate
            float avgEvisCP       = _avgCP[finisherCP];
            float effEvisCP       = Math.Min(RV.MaxCP, avgEvisCP);
            float evisCycleEnergy = ((avgEvisCP - CPOnFinisher) / CPPerCPG) * CPGEnergy + EvisStats.EnergyCost - RV.Talents.RelentlessStrikesEnergyBonus * ChanceOnEnergyPerCPFinisher * effEvisCP;
            evisCount            = TotalEnergyAvailable / evisCycleEnergy;
            CPGCount            += (evisCount * (avgEvisCP - CPOnFinisher) / CPPerCPG);
            TotalEnergyAvailable = 0f;
            evisCount           += TotalCPAvailable / avgEvisCP;
            TotalCPAvailable     = 0;
            #endregion
            #endregion

            #region Poisons
            float mHPoisonHitCount = (whiteMHAttacks * (1f - AvoidedWhiteMHAttacks) + CPGCount + evisCount + realRuptCount) * (1f - AvoidedPoisonAttacks);
            float oHPoisonHitCount = whiteOHAttacks * (1f - AvoidedWhiteOHAttacks) * (1f - AvoidedPoisonAttacks);
            float iPCount          = 0f;
            float dPTicks          = 0f;
            float wPCount          = 0f;
            float iPProcRate       = RV.IP.Chance / RV.IP.NormWeapSpeed;
            float dPApplyChance    = RV.DP.Chance;
            #region MainHand Poison
            if (mHPoison == 1)
            {
                iPCount += mHPoisonHitCount * MainHandStats.Weapon._speed * iPProcRate;
            }
            else if (mHPoison == 2 && oHPoison != 2)
            {
                float dPStackTime = RV.DP.MaxStack * MainHandSpeed / (dPApplyChance * (1f - AvoidedPoisonAttacks) * (1f - AvoidedWhiteMHAttacks));
                dPTicks = RV.DP.MaxStack * Duration / RV.DP.TickTime - RV.GetMissedDPTicks(dPStackTime);
                float dPCountAtMaxStack = mHPoisonHitCount * dPApplyChance * (Duration - dPStackTime) / Duration;
                if (oHPoison == 1)
                {
                    iPCount += dPCountAtMaxStack;
                }
                else if (oHPoison == 3)
                {
                    wPCount += dPCountAtMaxStack;
                }
            }
            else if (mHPoison == 3)
            {
                wPCount += mHPoisonHitCount * MainHandStats.Weapon._speed * RV.WP.Chance / RV.WP.NormWeapSpeed;
            }
            #endregion
            #region OffHand Poison
            if (oHPoison == 1)
            {
                iPCount += oHPoisonHitCount * OffHandStats.Weapon._speed * iPProcRate;
            }
            else if (oHPoison == 2 && mHPoison != 2)
            {
                float dPStackTime = RV.DP.MaxStack * OffHandSpeed / (dPApplyChance * (1f - AvoidedPoisonAttacks) * (1f - AvoidedWhiteMHAttacks));
                dPTicks = RV.DP.MaxStack * Duration / RV.DP.TickTime - RV.GetMissedDPTicks(dPStackTime);
                float dPCountAtMaxStack = oHPoisonHitCount * dPApplyChance * (Duration - dPStackTime) / Duration;
                if (mHPoison == 1)
                {
                    iPCount += dPCountAtMaxStack;
                }
                else if (mHPoison == 3)
                {
                    wPCount += dPCountAtMaxStack;
                }
            }
            else if (oHPoison == 3)
            {
                wPCount += oHPoisonHitCount * OffHandStats.Weapon._speed * RV.WP.Chance / RV.WP.NormWeapSpeed;
            }
            #endregion
            iPCount *= (1f - AvoidedPoisonAttacks);
            wPCount *= (1f - AvoidedPoisonAttacks);
            #endregion

            #region Damage Totals
            float evisCrits = (whiteMHAttacks + whiteOHAttacks) * T411 * RV.Set.T114ProcChance;

            float mainHandDamageTotal = whiteMHAttacks * MainHandStats.DamagePerSwing;
            float offHandDamageTotal  = whiteOHAttacks * OffHandStats.DamagePerSwing;
            float backstabDamageTotal = (CPG == 0 ? CPGCount : 0) * BackstabStats.DamagePerSwing;
            float hemoDamageTotal     = ((CPG == 1 ? CPGCount : 0) + hemoCount) * HemoStats.DamagePerSwing;
            float ruptDamageTotal     = ruptCount * RuptStats.DamagePerSwingArray[(int)Math.Floor((double)effRuptCP)] + (effRuptCP - (float)Math.Floor((double)effRuptCP)) * (RuptStats.DamagePerSwingArray[(int)Math.Min(Math.Floor((double)effRuptCP) + 1, 5)] - RuptStats.DamagePerSwingArray[(int)Math.Floor((double)effRuptCP)]);
            float evisDamageTotal     = evisCount * (EvisStats.DamagePerSwing + EvisStats.DamagePerSwingPerCP * Math.Min(_avgCP[finisherCP], 5)) +
                                        evisCrits * (EvisStats.DamagePerCrit + EvisStats.DamagePerCritPerCP * Math.Min(_avgCP[finisherCP], 5));
            float instantPoisonTotal = iPCount * IPStats.DamagePerSwing;
            float deadlyPoisonTotal  = dPTicks * DPStats.DamagePerSwing;
            float woundPoisonTotal   = wPCount * WPStats.DamagePerSwing;

            float damageTotal = (mainHandDamageTotal + offHandDamageTotal + backstabDamageTotal + hemoDamageTotal + ruptDamageTotal + evisDamageTotal + instantPoisonTotal + deadlyPoisonTotal
                                 + woundPoisonTotal);
            #endregion

            return(new RogueRotationCalculation()
            {
                MultipleSegments = Duration < 1f,
                Duration = Duration,
                TotalDamage = damageTotal,
                DPS = damageTotal / Duration,

                MainHandCount = whiteMHAttacks,
                OffHandCount = whiteOHAttacks,
                BackstabCount = (CPG == 0 ? CPGCount : 0),
                HemoCount = ((CPG == 1 ? CPGCount : 0) + hemoCount),
                RuptCount = ruptCount,
                EvisCount = evisCount,
                SnDCount = snDCount,
                RecupCount = recupCount,
                EACount = exposeCount,
                IPCount = iPCount,
                DPCount = dPTicks,
                WPCount = wPCount,

                FinisherCP = finisherCP,
                EvisCP = Math.Min(_avgCP[finisherCP], RV.MaxCP),
                RuptCP = ruptCP,
                SnDCP = snDCP,

                MHPoison = mHPoison,
                OHPoison = oHPoison,

                UseTotT = useTotT,
                SerratedBlades = ChanceOnRuptResetonEvisCP * Math.Min(RV.MaxCP, _avgCP[finisherCP]),
            });
        }