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, }); }
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, }); }
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]), }); }