public CombatTable(Character c, CharacterCalculationsDPSDK calcs, Stats stats, CalculationOptionsDPSDK calcOpts /*, Item additionalItem*/) { character = c; this.calcs = calcs; talents = character.DeathKnightTalents; this.calcOpts = calcOpts; this.stats = stats; this.additionalItem = null; totalMeleeAbilities = 0f; totalSpellAbilities = 0f; /*#if RAWR3 * if (calcOpts.rotation == null) * { * calcOpts.rotation = new Rotation(); * calcOpts.rotation.setRotation(Rotation.Type.Blood); * } #endif*/ float DWExtraHits = 1f;// +talents.ThreatOfThassarian / 3f; totalMeleeAbilities = (float)(calcOpts.rotation.PlagueStrike * DWExtraHits + calcOpts.rotation.ScourgeStrike + calcOpts.rotation.Obliterate * DWExtraHits + calcOpts.rotation.BloodStrike * DWExtraHits + calcOpts.rotation.HeartStrike + calcOpts.rotation.FrostStrike * DWExtraHits + calcOpts.rotation.DeathStrike * DWExtraHits); totalSpellAbilities = (float)(calcOpts.rotation.DeathCoil + calcOpts.rotation.IcyTouch + calcOpts.rotation.HowlingBlast + calcOpts.rotation.Pestilence + calcOpts.rotation.Horn + calcOpts.rotation.GhoulFrenzy); hitBonus = .01f * (float)talents.NervesOfColdSteel; Weapons(); CritsAndResists(); }
public void DPSDK_Rotation() { Rawr.DPSDK.CharacterCalculationsDPSDK CalcDPSDK = new Rawr.DPSDK.CharacterCalculationsDPSDK(); CalculationOptionsDPSDK calcOpts = new CalculationOptionsDPSDK(); Rawr.DK.StatsDK TotalStats = new Rawr.DK.StatsDK(); Rawr.DK.DKCombatTable ct = new Rawr.DK.DKCombatTable(m_char, TotalStats, CalcDPSDK, calcOpts, m_char.BossOptions); Rawr.DK.Rotation rot = new Rawr.DK.Rotation(ct, false); rot.PRE_OneEachRot(); rot.ReportRotation(); Assert.IsTrue(rot.m_DPS > 0, "rotation OneEach produces 0 DPS"); rot.PRE_Frost(); rot.ReportRotation(); Assert.IsTrue(rot.m_DPS > 0, "rotation Frost produces 0 DPS"); rot.PRE_Unholy(); rot.ReportRotation(); Assert.IsTrue(rot.m_DPS > 0, "rotation Unholy produces 0 DPS"); rot.PRE_BloodDiseased(); rot.ReportRotation(); Assert.IsTrue(rot.m_DPS > 0, "rotation BloodDiseased produces 0 DPS"); //rot.Solver(); //rot.ReportRotation(); //Assert.IsTrue(rot.m_DPS > 0, "rotation solver produces 0 DPS"); }
public void DPSDK_Rotation() { Rawr.DPSDK.CharacterCalculationsDPSDK CalcDPSDK = new Rawr.DPSDK.CharacterCalculationsDPSDK(); CalculationOptionsDPSDK calcOpts = new CalculationOptionsDPSDK(); Rawr.DK.StatsDK TotalStats = new Rawr.DK.StatsDK(); Rawr.DK.DKCombatTable ct = new Rawr.DK.DKCombatTable(m_char, TotalStats, CalcDPSDK, calcOpts, m_char.BossOptions); Rawr.DK.Rotation rot = new Rawr.DK.Rotation(ct, false); rot.PRE_OneEachRot(); rot.ReportRotation(); Assert.IsTrue(rot.m_DPS > 0, "rotation OneEach produces 0 DPS"); rot.PRE_Frost(); rot.ReportRotation(); Assert.IsTrue(rot.m_DPS > 0, "rotation Frost produces 0 DPS"); rot.PRE_Unholy(); rot.ReportRotation(); Assert.IsTrue(rot.m_DPS > 0, "rotation Unholy produces 0 DPS"); rot.PRE_BloodDiseased(); rot.ReportRotation(); Assert.IsTrue(rot.m_DPS > 0, "rotation BloodDiseased produces 0 DPS"); //rot.Solver(); //rot.ReportRotation(); //Assert.IsTrue(rot.m_DPS > 0, "rotation solver produces 0 DPS"); }
public DRW(CombatTable combatTable, CharacterCalculationsDPSDK calcs, CalculationOptionsDPSDK calcOpts, Stats stats, Character character, DeathKnightTalents talents) { bool DW = false; float dpsWhite = 0f; float dpsBCB = 0f; float dpsNecrosis = 0f; float dpsDeathCoil = 0f; float dpsIcyTouch = 0f; float dpsPlagueStrike = 0f; float dpsFrostFever = 0f; float dpsBloodPlague = 0f; float dpsDeathStrike = 0f; float dpsHeartStrike = 0f; float dpsWPFromFF = 0f; float dpsWPFromBP = 0f; float dpsWhiteMinusGlancing = 0f; float dpsWhiteBeforeArmor = 0f; float IcyTouchAPMult = 0.1f; float FrostFeverAPMult = 0.055f; float BloodPlagueAPMult = 0.055f; float DeathCoilAPMult = 0.15f; float OHMult = 0.5f; int targetLevel = calcOpts.TargetLevel; float arpBuffs = talents.BloodGorged * 2f / 100; float mitigation = StatConversion.GetArmorDamageReduction(character.Level, calcOpts.BossArmor, stats.ArmorPenetration, arpBuffs, stats.ArmorPenetrationRating); mitigation = 1 - mitigation; float MHDPS = 0f, OHDPS = 0f; #region White Dmg { #region Main Hand { float dpsMHglancing = (StatConversion.WHITE_GLANCE_CHANCE_CAP[targetLevel - 80] * combatTable.MH.DPS) * 0.7f; float dpsMHBeforeArmor = ((combatTable.MH.DPS * (1f - calcs.AvoidedAttacks - StatConversion.WHITE_GLANCE_CHANCE_CAP[targetLevel - 80])) * (1f + combatTable.physCrits)) + dpsMHglancing; dpsWhiteMinusGlancing = dpsMHBeforeArmor - dpsMHglancing; dpsWhiteBeforeArmor = dpsMHBeforeArmor; MHDPS = dpsMHBeforeArmor * mitigation; } #endregion #region Off Hand if (DW || (character.MainHand == null && character.OffHand != null)) { float dpsOHglancing = (StatConversion.WHITE_GLANCE_CHANCE_CAP[targetLevel - 80] * combatTable.OH.DPS) * 0.7f; float dpsOHBeforeArmor = ((combatTable.OH.DPS * (1f - calcs.AvoidedAttacks - StatConversion.WHITE_GLANCE_CHANCE_CAP[targetLevel - 80])) * (1f + combatTable.physCrits)) + dpsOHglancing; dpsOHBeforeArmor *= OHMult; dpsWhiteMinusGlancing += dpsOHBeforeArmor - dpsOHglancing; dpsWhiteBeforeArmor += dpsOHBeforeArmor; OHDPS = dpsOHBeforeArmor * mitigation; } #endregion dpsWhite = MHDPS + OHDPS; } #endregion #region Necrosis { dpsNecrosis = dpsWhiteMinusGlancing * (.04f * (float)talents.Necrosis); // doesn't proc off Glancings } #endregion #region Blood Caked Blade { float dpsMHBCB = 0f; if (combatTable.MH.damage != 0) { float MHBCBDmg = (float)(combatTable.MH.damage * (.25f + .125f * calcOpts.rotation.AvgDiseaseMult)); dpsMHBCB = MHBCBDmg / combatTable.MH.hastedSpeed; } dpsBCB = dpsMHBCB; dpsBCB *= .1f * (float)talents.BloodCakedBlade; } #endregion #region Death Coil { if (calcOpts.rotation.DeathCoil > 0f) { float DCCD = 1; float DCDmg = 443f + (DeathCoilAPMult * stats.AttackPower); dpsDeathCoil = DCDmg / DCCD; float DCCritDmgMult = .5f * (2f + stats.BonusCritMultiplier); float DCCrit = 1f + ((combatTable.spellCrits + stats.BonusDeathCoilCrit) * DCCritDmgMult); dpsDeathCoil *= DCCrit; dpsDeathCoil *= 1f + (.05f * (float)talents.Morbidity); } } #endregion #region Icy Touch { if (calcOpts.rotation.IcyTouch > 0f) { float ITCD = 1; float ITDmg = 236f + (IcyTouchAPMult * stats.AttackPower) + stats.BonusIcyTouchDamage; ITDmg *= 1f + .1f * (float)talents.ImprovedIcyTouch; dpsIcyTouch = ITDmg / ITCD; float ITCritDmgMult = .5f * (2f + stats.CritBonusDamage + stats.BonusCritMultiplier); float ITCrit = 1f + (Math.Min((combatTable.spellCrits + (.05f * (float)talents.Rime)), 1f) * ITCritDmgMult); dpsIcyTouch *= ITCrit; } } #endregion #region Plague Strike { if (calcOpts.rotation.PlagueStrike > 0f) { float PSCD = 1; float PSDmg = (combatTable.MH.baseDamage + ((stats.AttackPower / 14f) * combatTable.normalizationFactor)) * 0.5f + 189f; dpsPlagueStrike = PSDmg / PSCD; float PSCritDmgMult = 1f + (.15f * (float)talents.ViciousStrikes) + stats.BonusCritMultiplier; float PSCrit = 1f + ((combatTable.physCrits + (.03f * (float)talents.ViciousStrikes) + stats.BonusPlagueStrikeCrit) * PSCritDmgMult); dpsPlagueStrike *= PSCrit; dpsPlagueStrike *= 1f + (.1f * (float)talents.Outbreak); } } #endregion #region Frost Fever { if (calcOpts.rotation.IcyTouch > 0f || (talents.GlyphofHowlingBlast && calcOpts.rotation.HowlingBlast > 0f) || (talents.GlyphofDisease && calcOpts.rotation.Pestilence > 0f)) { float FFDmg = FrostFeverAPMult * stats.AttackPower + 25.6f; dpsFrostFever = FFDmg; dpsFrostFever *= 1.15f; // Patch 3.2: Diseases hit 15% harder. dpsWPFromFF = dpsFrostFever * combatTable.physCrits; } } #endregion #region Blood Plague { if (calcOpts.rotation.PlagueStrike > 0f || talents.GlyphofDisease) { float BPDmg = BloodPlagueAPMult * stats.AttackPower + 31.1f; dpsBloodPlague = BPDmg; dpsBloodPlague *= 1.15f; // Patch 3.2: Diseases hit 15% harder. dpsWPFromBP = dpsBloodPlague * combatTable.physCrits; } } #endregion #region Death Strike { if (calcOpts.rotation.DeathStrike > 0f) { float DSCD = 1; // TODO: This should be changed to make use of the new glyph stats: float DSDmg = ((combatTable.MH.baseDamage + ((stats.AttackPower / 14f) * combatTable.normalizationFactor)) * 0.75f) + 222.75f; DSDmg *= 1f + 0.15f * (float)talents.ImprovedDeathStrike; dpsDeathStrike = DSDmg / DSCD; float DSCritDmgMult = 1f + (.15f * (float)talents.MightOfMograine) + stats.BonusCritMultiplier; float DSCrit = 1f + ((combatTable.physCrits + (.03f * (float)talents.ImprovedDeathStrike) + stats.BonusDeathStrikeCrit) * DSCritDmgMult); dpsDeathStrike *= DSCrit; } } #endregion #region Heart Strike { if (talents.HeartStrike > 0 && calcOpts.rotation.HeartStrike > 0f) { float HSCD = 1; float HSDmg = ((combatTable.MH.baseDamage + ((stats.AttackPower / 14f) * combatTable.normalizationFactor)) * 0.5f) + 368f; HSDmg *= 1f + 0.1f * (float)calcOpts.rotation.AvgDiseaseMult * (1f + stats.BonusPerDiseaseHeartStrikeDamage); dpsHeartStrike = HSDmg / HSCD; //float HSCrit = 1f + combatTable.physCrits + ( .03f * (float)talents.Subversion ); float HSCritDmgMult = 1f + (.15f * (float)talents.MightOfMograine) + stats.BonusCritMultiplier; float HSCrit = 1f + ((combatTable.physCrits + (.03f * (float)talents.Subversion)) * HSCritDmgMult); dpsHeartStrike = (dpsHeartStrike) * HSCrit; dpsHeartStrike *= 1f + (.15f * (float)talents.BloodyStrikes); } } #endregion float BCBMult = 1f; float BloodPlagueMult = 1f; float DeathCoilMult = 1f; float FrostFeverMult = 1f; float HeartStrikeMult = 1f; float IcyTouchMult = 1f; float NecrosisMult = 1f; float DeathStrikeMult = 1f; float PlagueStrikeMult = 1f; float WhiteMult = 1f; float spellPowerMult = 1f + stats.BonusSpellPowerMultiplier; float frostSpellPowerMult = 1f + stats.BonusSpellPowerMultiplier + Math.Max((stats.BonusFrostDamageMultiplier - stats.BonusShadowDamageMultiplier), 0f); float partialResist = 0.94f; float physPowerMult = 1f; #region Apply Physical Mitigation { float physMit = mitigation; physMit *= 1f + (!DW ? .02f * talents.TwoHandedWeaponSpecialization : 0f); dpsBCB *= physMit; dpsHeartStrike *= physMit; dpsDeathStrike *= physMit; dpsPlagueStrike *= physMit; WhiteMult += physPowerMult - 1f; BCBMult += physPowerMult - 1f; HeartStrikeMult += physPowerMult - 1f; DeathStrikeMult += physPowerMult - 1f; PlagueStrikeMult += physPowerMult - 1f; } #endregion #region Apply Magical Mitigation { // some of this applies to necrosis, I wonder if it is ever accounted for float magicMit = partialResist /** combatTable.spellResist*/; // magicMit = 1f - magicMit; dpsNecrosis *= magicMit; dpsBloodPlague *= magicMit; dpsDeathCoil *= magicMit * (1f - combatTable.spellResist); dpsFrostFever *= magicMit; dpsIcyTouch *= magicMit; NecrosisMult += spellPowerMult - 1f; BloodPlagueMult += spellPowerMult - 1f; DeathCoilMult += spellPowerMult - 1f; FrostFeverMult += frostSpellPowerMult - 1f; IcyTouchMult += frostSpellPowerMult - 1f; } #endregion #region Apply Multi-Ability Talent Multipliers { float BloodyVengeanceMult = .03f * (float)talents.BloodyVengeance; BCBMult *= 1 + BloodyVengeanceMult; HeartStrikeMult *= 1 + BloodyVengeanceMult; DeathStrikeMult *= 1 + BloodyVengeanceMult; PlagueStrikeMult *= 1 + BloodyVengeanceMult; WhiteMult *= 1 + BloodyVengeanceMult; float HysteriaCoeff = .2f / 2f; // current uptime is 50% for now float HysteriaMult = HysteriaCoeff * (float)talents.Hysteria; BCBMult *= 1 + HysteriaMult; HeartStrikeMult *= 1 + HysteriaMult; DeathStrikeMult *= 1 + HysteriaMult; PlagueStrikeMult *= 1 + HysteriaMult; WhiteMult *= 1 + HysteriaMult; float BlackIceMult = .02f * (float)talents.BlackIce; FrostFeverMult *= 1 + BlackIceMult; IcyTouchMult *= 1 + BlackIceMult; DeathCoilMult *= 1 + BlackIceMult; BloodPlagueMult *= 1 + BlackIceMult; float CryptFeverMult = .1f * (float)talents.CryptFever; float CryptFeverBuff = stats.BonusDiseaseDamageMultiplier; CryptFeverMult = Math.Max(CryptFeverMult, CryptFeverBuff); FrostFeverMult *= 1 + CryptFeverMult; BloodPlagueMult *= 1 + CryptFeverMult; } #endregion dpsDancingRuneWeapon = dpsWhite * WhiteMult * 17f + dpsBCB * BCBMult * 17f + dpsNecrosis * NecrosisMult * 17f + dpsDeathCoil * DeathCoilMult + dpsIcyTouch * IcyTouchMult + dpsPlagueStrike * PlagueStrikeMult + dpsFrostFever * (5f + talents.Epidemic) * FrostFeverMult + dpsBloodPlague * (5f + talents.Epidemic) * BloodPlagueMult + dpsDeathStrike * DeathStrikeMult * (talents.GlyphofDancingRuneWeapon ? 1f : 0f) + dpsHeartStrike * HeartStrikeMult * (5f + (talents.GlyphofDancingRuneWeapon ? 2f : 0f)); dpsDancingRuneWeapon *= 0.5f; }
public DKCombatTable(Character c, StatsDK stats, CharacterCalculationsBase calcs, ICalculationOptionBase calcOpts, BossOptions bossOpts) { m_CState = new CombatState(); if (c != null) { m_CState.m_Char = c; m_CState.m_Talents = c.DeathKnightTalents; m_CState.m_Spec = CalculationsDPSDK.GetSpec(c.DeathKnightTalents); } m_CState.m_Stats = stats; // TODO: Put in check here for null. m_Calcs = calcs as CharacterCalculationsDPSDK; m_Opts = calcOpts as CalculationOptionsDPSDK; m_CState.m_Presence = Presence.Frost; if (calcOpts != null && m_Opts == null) { //throw new Exception("Opts not converted properly."); m_Opts = new CalculationOptionsDPSDK(); } try { m_CState.m_Presence = m_Opts.presence; } catch { } // pass stay w/ default m_BO = bossOpts; if (m_BO == null) { m_BO = new BossOptions(); } // JOTHAY TODO: Kind of an Ugly Hack to do this, but it will give them a value m_CState.m_NumberOfTargets = m_BO.MultiTargs ? m_BO.DynamicCompiler_MultiTargs.GetAverageTargetGroupSize(m_BO.BerserkTimer) : 1f; // m_CState.m_bAttackingFromBehind = m_BO.InBack; m_CState.fBossArmor = m_BO.Armor; SetupExpertise(c); }
/// <summary> /// GetCharacterCalculations is the primary method of each model, where a majority of the calculations /// and formulae will be used. GetCharacterCalculations should call GetCharacterStats(), and based on /// those total stats for the character, and any calculationoptions on the character, perform all the /// calculations required to come up with the final calculations defined in /// CharacterDisplayCalculationLabels, including an Overall rating, and all Sub ratings defined in /// SubPointNameColors. /// </summary> /// <param name="character">The character to perform calculations for.</param> /// <param name="additionalItem">An additional item to treat the character as wearing. /// This is used for gems, which don't have a slot on the character to fit in, so are just /// added onto the character, in order to get gem calculations.</param> /// <returns>A custom CharacterCalculations object which inherits from CharacterCalculationsBase, /// containing all of the final calculations defined in CharacterDisplayCalculationLabels. See /// CharacterCalculationsBase comments for more details.</returns> public override CharacterCalculationsBase GetCharacterCalculations(Character character, Item additionalItem, bool referenceCalculation, bool significantChange, bool needsDisplayCalculations) { // First things first, we need to ensure that we aren't using bad data CharacterCalculationsDPSDK calc = new CharacterCalculationsDPSDK(); if (character == null) { return calc; } CalculationOptionsDPSDK calcOpts = character.CalculationOptions as CalculationOptionsDPSDK; if (calcOpts == null) { return calc; } // StatsDK stats = new StatsDK(); DeathKnightTalents talents = character.DeathKnightTalents; // Setup initial Boss data. // Get Boss from BossOptions data. BossOptions hBossOptions = character.BossOptions; if (hBossOptions == null) hBossOptions = new BossOptions(); int targetLevel = hBossOptions.Level; stats = GetCharacterStats(character, additionalItem) as StatsDK; calc.BasicStats = stats.Clone() as StatsDK; ApplyRatings(calc.BasicStats); DKCombatTable combatTable = new DKCombatTable(character, calc.BasicStats, calc, calcOpts, hBossOptions); if (needsDisplayCalculations) combatTable.PostAbilitiesSingleUse(false); Rotation rot = new Rotation(combatTable); Rotation.Type RotT = rot.GetRotationType(character.DeathKnightTalents); // TODO: Fix this so we're not using pre-set rotations/priorities. if (RotT == Rotation.Type.Frost) rot.PRE_Frost(); else if (RotT == Rotation.Type.Unholy) rot.PRE_Unholy(); else if (RotT == Rotation.Type.Blood) rot.PRE_BloodDiseased(); else rot.Solver(); //TODO: This may need to be handled special since it's to update stats. AccumulateSpecialEffectStats(stats, character, calcOpts, combatTable, rot); // Now add in the special effects. ApplyRatings(stats); #region Cinderglacier if (stats.CinderglacierProc > 0) { // How many frost & shadow abilities do we have per min.? float CGabs = ((rot.m_FrostSpecials + rot.m_ShadowSpecials) / rot.CurRotationDuration) * 60f; float effCG = 0; if (CGabs > 0) // Since 3 of those abilities get the 20% buff // Get the effective ammount of CinderGlacier that would be applied across each ability. // it is a proc after all. effCG = 3 / CGabs; stats.BonusFrostDamageMultiplier += (.2f * effCG); stats.BonusShadowDamageMultiplier += (.2f * effCG); } #endregion // refresh w/ updated stats. combatTable = new DKCombatTable(character, stats, calc, calcOpts, hBossOptions); combatTable.PostAbilitiesSingleUse(false); rot = new Rotation(combatTable); RotT = rot.GetRotationType(character.DeathKnightTalents); // TODO: Fix this so we're not using pre-set rotations. if (RotT == Rotation.Type.Frost) rot.PRE_Frost(); else if (RotT == Rotation.Type.Unholy) rot.PRE_Unholy(); else if (RotT == Rotation.Type.Blood) rot.PRE_BloodDiseased(); else rot.Solver(); #region Pet Handling // For UH, this is valid. For Frost/Blood, we need to have this be 1/3 of the value since it has an uptime of 1 min for every 3. float ghouluptime = 1f; calc.dpsSub[(int)DKability.Gargoyle] = 0; if (RotT != Rotation.Type.Unholy) ghouluptime = 1f / 3f; else { // Unholy will also have gargoyles. Pet Gar = new Gargoyle(stats, talents, hBossOptions, calcOpts.presence); float garuptime = .5f/3f; calc.dpsSub[(int)DKability.Gargoyle] = Gar.DPS * garuptime; calc.damSub[(int)DKability.Gargoyle] = Gar.DPS * 30f; // Duration 30 seconds. } Pet ghoul = new Ghoul(stats, talents, hBossOptions, calcOpts.presence); calc.dpsSub[(int)DKability.Ghoul] = ghoul.DPS * ghouluptime; calc.damSub[(int)DKability.Ghoul] = ghoul.DPS * 60f; // Duration 1 min. #endregion // Stats as Fire damage additive value proc. if (stats.ArcaneDamage > 1) calc.dpsSub[(int)DKability.OtherArcane] += stats.ArcaneDamage; if (stats.FireDamage > 1) calc.dpsSub[(int)DKability.OtherFire] += stats.FireDamage; if (stats.FrostDamage > 1) calc.dpsSub[(int)DKability.OtherFrost] += stats.FrostDamage; if (stats.HolyDamage > 1) calc.dpsSub[(int)DKability.OtherHoly] += stats.HolyDamage; if (stats.NatureDamage > 1) calc.dpsSub[(int)DKability.OtherNature] += stats.NatureDamage; if (stats.ShadowDamage > 1) calc.dpsSub[(int)DKability.OtherShadow] += stats.ShadowDamage; // Fire Dam Multiplier. calc.RotationTime = rot.CurRotationDuration; calc.Blood = rot.m_BloodRunes; calc.Frost = rot.m_FrostRunes; calc.Unholy = rot.m_UnholyRunes; calc.Death = rot.m_DeathRunes; calc.RP = rot.m_RunicPower; calc.FreeRERunes = rot.m_FreeRunesFromRE; calc.EffectiveArmor = stats.Armor; calc.OverallPoints = calc.DPSPoints = rot.m_DPS // Add in supplemental damage from other sources + calc.dpsSub[(int)DKability.Ghoul] + calc.dpsSub[(int)DKability.Gargoyle] + calc.dpsSub[(int)DKability.OtherArcane] + calc.dpsSub[(int)DKability.OtherFire] + calc.dpsSub[(int)DKability.OtherFrost] + calc.dpsSub[(int)DKability.OtherHoly] + calc.dpsSub[(int)DKability.OtherNature] + calc.dpsSub[(int)DKability.OtherShadow]; if (needsDisplayCalculations) { AbilityDK_Base a = rot.GetAbilityOfType(DKability.White); if (rot.ml_Rot.Count > 1) { AbilityDK_Base b; b = rot.GetAbilityOfType(DKability.ScourgeStrike); if (b == null) b = rot.GetAbilityOfType(DKability.FrostStrike); if (b == null) b = rot.GetAbilityOfType(DKability.DeathStrike); calc.YellowHitChance = b.HitChance; } calc.WhiteHitChance = (a == null ? 0 : a.HitChance + a.CritChance + .23f); // + glancing calc.MHWeaponDPS = (a == null ? 0 : rot.GetAbilityOfType(DKability.White).DPS); if (null != combatTable.MH) { calc.MHWeaponDamage = combatTable.MH.damage; calc.MHAttackSpeed = combatTable.MH.hastedSpeed; calc.DodgedAttacks = combatTable.MH.chanceDodged; calc.AvoidedAttacks = combatTable.MH.chanceDodged; if (!hBossOptions.InBack) calc.AvoidedAttacks += combatTable.MH.chanceParried; calc.MissedAttacks = combatTable.MH.chanceMissed; } if (null != combatTable.OH) { a = rot.GetAbilityOfType(DKability.WhiteOH); calc.OHWeaponDPS = (a == null ? 0 : rot.GetAbilityOfType(DKability.WhiteOH).DPS); calc.OHWeaponDamage = combatTable.OH.damage; calc.OHAttackSpeed = combatTable.OH.hastedSpeed; } calcOpts.szRotReport = rot.ReportRotation(); calc.m_RuneCD = (float)rot.m_SingleRuneCD / 1000; calc.DPSBreakdown(rot); } return calc; }