예제 #1
0
        public override ComparisonCalculationBase[] GetCustomChartData(Character character, string chartName)
        {
            switch (chartName)
            {
            case "Combat Table":
                CharacterCalculationsRogue  currentCalculationsRogue = GetCharacterCalculations(character) as CharacterCalculationsRogue;
                ComparisonCalculationsRogue calcMiss   = new ComparisonCalculationsRogue();
                ComparisonCalculationsRogue calcDodge  = new ComparisonCalculationsRogue();
                ComparisonCalculationsRogue calcParry  = new ComparisonCalculationsRogue();
                ComparisonCalculationsRogue calcBlock  = new ComparisonCalculationsRogue();
                ComparisonCalculationsRogue calcGlance = new ComparisonCalculationsRogue();
                ComparisonCalculationsRogue calcCrit   = new ComparisonCalculationsRogue();
                ComparisonCalculationsRogue calcHit    = new ComparisonCalculationsRogue();

                if (currentCalculationsRogue != null)
                {
                    calcMiss.Name   = "    Miss    ";
                    calcDodge.Name  = "   Dodge   ";
                    calcGlance.Name = " Glance ";
                    calcCrit.Name   = "  Crit  ";
                    calcHit.Name    = "Hit";

                    float crits    = 5f;
                    float glancing = 25f;
                    float hits     = 100f - (crits + glancing);

                    calcMiss.OverallPoints   = 0f;
                    calcDodge.OverallPoints  = 0f;
                    calcParry.OverallPoints  = 0f;
                    calcBlock.OverallPoints  = 0f;
                    calcGlance.OverallPoints = 0f;
                    calcCrit.OverallPoints   = 0f;
                    calcHit.OverallPoints    = 0f;
                }
                return(new ComparisonCalculationBase[] { calcMiss, calcDodge, calcParry, calcGlance, calcBlock, calcCrit, calcHit });

            default:
                return(new ComparisonCalculationBase[0]);
            }
        }
예제 #2
0
        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
            CharacterCalculationsRogue calc = new CharacterCalculationsRogue();
            if (character == null) { return calc; }
            CalculationOptionsRogue calcOpts = character.CalculationOptions as CalculationOptionsRogue;
            if (calcOpts == null) { return calc; }
            //
            BossOptions bossOpts = character.BossOptions;
            RogueTalents talents = character.RogueTalents;
            PTRMode = calcOpts.PTRMode;
            #region Spec determination
            int spec;
            int assCounter = 0, combatCounter = 0, subtCounter = 0;
            for (int i = 0; i <= 18; i++) assCounter += int.Parse(talents.ToString()[i].ToString());
            for (int i = 19; i <= 37; i++) combatCounter += int.Parse(talents.ToString()[i].ToString());
            for (int i = 38; i <= 56; i++) subtCounter += int.Parse(talents.ToString()[i].ToString());
            if (assCounter > combatCounter && assCounter > subtCounter) spec = 0;
            else if (combatCounter > subtCounter) spec = 1;
            else spec = 2;
            #endregion
            int targetLevel = bossOpts.Level;
            float targetArmor = bossOpts.Armor;
            bool targetPoisonable = calcOpts.TargetPoisonable;
            WeightedStat[] critRatingUptimes;
            Stats stats = GetCharacterStatsWithTemporaryEffects(character, additionalItem, out critRatingUptimes);
            calc.BasicStats = stats;
            calc.TargetLevel = targetLevel;
            calc.Spec = spec;
            Item mainHand = character.MainHand == null ? new Knuckles() : character.MainHand.Item;
            Item offHand = character.OffHand == null ? new Knuckles() : character.OffHand.Item;
            
            #region Basic Chances and Constants
            #region Constants from talents
            float dmgBonusOnGarrRuptTickChance = RV.Talents.VenomousWoundsProcChance * talents.VenomousWounds;
            float cPGCritDmgMult = RV.Talents.LethalityCritMult * talents.Lethality;
            float ambushBSCostReduc = RV.Talents.SlaughterFTShadowsBSAmbushCostReduc[talents.SlaughterFromTheShadows];
            float ambushCPBonus = RV.Talents.InitiativeChance * talents.Initiative;
            float ambushCritBonus = RV.Talents.ImpAmbushCritBonus * talents.ImprovedAmbush;
            float ambushDmgMult = RV.Talents.ImpAmbushDmgMult * talents.ImprovedAmbush + RV.Talents.OpportunityDmgMult * talents.Opportunity;
            float bSDmgMult = RV.Talents.AggressionDmgMult[talents.Aggression] + RV.Talents.OpportunityDmgMult * talents.Opportunity + (spec == 2 ? RV.Mastery.SinisterCallingMult: 0f);
            float bSCritBonus = talents.PuncturingWounds * RV.Talents.PuncturingWoundsBSCritMult + (stats.Rogue_T11_2P > 0 ? RV.Set.T112CritBonus : 0f);
            float evisCritBonus = (talents.GlyphOfEviscerate ? RV.Glyph.EvisCritMult : 0f);
            float mutiCritBonus = talents.PuncturingWounds * RV.Talents.PuncturingWoundsMutiCritMult + (stats.Rogue_T11_2P > 0 ? RV.Set.T112CritBonus : 0f);
            float ruptDmgMult = (spec == 2 ? RV.Mastery.Executioner + RV.Mastery.ExecutionerPerMast * StatConversion.GetMasteryFromRating(stats.MasteryRating) : 0f);
            float ruptDurationBonus = talents.GlyphOfRupture ? RV.Glyph.RuptBonusDuration : 0;
            float snDDurationBonus = talents.GlyphOfSliceandDice ? RV.Glyph.SnDBonusDuration : 0;
            float exposeDurationBonus = talents.GlyphOfExposeArmor ? RV.Glyph.ExposeBonusDuration : 0;
            float snDDurationMult = RV.Talents.ImpSliceAndDice * talents.ImprovedSliceAndDice;
            float sStrikeCritBonus = (stats.Rogue_T11_2P > 0 ? RV.Set.T112CritBonus : 0f);
            float cPonCPGCritChance = RV.Talents.SealFateChance * talents.SealFate;
            float evisDmgMult = (1f + RV.Talents.AggressionDmgMult[talents.Aggression] + RV.Talents.CoupDeGraceMult[talents.CoupDeGrace]) * (1f + (spec == 2 ? RV.Mastery.Executioner + RV.Mastery.ExecutionerPerMast * StatConversion.GetMasteryFromRating(stats.MasteryRating) : 0f)) - 1f;
            float envenomDmgMult = (1f + RV.Talents.CoupDeGraceMult[talents.CoupDeGrace]) * (1f + (spec == 2 ? RV.Mastery.Executioner + RV.Mastery.ExecutionerPerMast * StatConversion.GetMasteryFromRating(stats.MasteryRating) : 0f)) - 1f;
            float hemoCostReduc = RV.Talents.SlaughterFTShadowsHemoCostReduc * talents.SlaughterFromTheShadows;
            float hemoDmgMult = (spec == 2 ? RV.Mastery.SinisterCallingMult : 0f);
            float meleeDmgMult = spec == 0 && mainHand.Type == ItemType.Dagger && offHand.Type == ItemType.Dagger ? RV.Mastery.AssassinsResolveMeleeDmgBonus : 0f;
            float meleeSpeedMult = (1f + RV.Talents.LightningReflexesSpeedMult * talents.LightningReflexes) * (1f + RV.AR.MeleeSpeedMult * RV.AR.Duration / RV.AR.CD * talents.AdrenalineRush) * (1f + RV.SnD.SpeedBonus) - 1f;
            float mutiCostReduc = talents.GlyphOfMutilate ? RV.Glyph.MutiCostReduc : 0;
            float mutiDmgMult = RV.Talents.OpportunityDmgMult * talents.Opportunity;
            float oHDmgMult = (1f + RV.OHDmgReduc) * (1f + (spec == 1 ? RV.Mastery.AmbidexterityDmgMult : 0f)) - 1f;
            float potentPoisonsMult = (spec == 0 ? RV.Mastery.PotentPoisonsDmgMult + RV.Mastery.PotentPoisonsDmgMultPerMast * StatConversion.GetMasteryFromRating(stats.MasteryRating) : 0f);
            float spellDmgMult = character.ActiveBuffs.Contains(Buff.GetBuffByName("Lightning Breath")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Fire Breath")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Master Poisoner")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Ebon Plaguebringer")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Earth and Moon")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Curse of the Elements")) ? 0f : (calcOpts.TargetPoisonable ? RV.Talents.MasterPoisonerSpellDmgMult * talents.MasterPoisoner : 0f);
            float natureDmgMult = (1f + spellDmgMult) * (1f + stats.BonusNatureDamageMultiplier) * (1f + stats.BonusDamageMultiplier) * (1f + potentPoisonsMult) - 1f;
            float poisonDmgMult = (1f + spellDmgMult) * (1f + stats.BonusNatureDamageMultiplier) * (1f + stats.BonusDamageMultiplier) * (1f + potentPoisonsMult + RV.Talents.VilePoisonsDmgMult[talents.VilePoisons]) - 1f;
            float sSCostReduc = RV.Talents.ImpSinisterStrikeCostReduc * talents.ImprovedSinisterStrike;
            float sSDmgMult = (1f + RV.Talents.ImpSinisterStrikeDmgMult * talents.ImprovedSinisterStrike) * (1f + RV.Talents.AggressionDmgMult[talents.Aggression] * (1f + stats.FangsoftheFatherMultiplier)) - 1f;
            #endregion

            float exposeArmor = character.ActiveBuffs.Contains(Buff.GetBuffByName("Corrosive Spit")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Tear Armor")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Sunder Armor")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Faerie Fire")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Expose Armor")) ? 0f : RV.Expose.ArmorReduc;
            float findWeakness = talents.FindWeakness * RV.Talents.FindWeaknessArmorIgnore * ((RV.SD.Duration + RV.Talents.FindWeaknessDuration) / RV.SD.CD +
                (RV.Talents.FindWeaknessDuration / (RV.Vanish.CD - RV.Talents.ElusivenessVanishCDReduc * talents.Elusiveness) +
                (talents.Preparation > 0 ? RV.Talents.FindWeaknessDuration / (RV.Talents.PreparationCD * talents.Preparation) : 0f)));
            float modArmor = 1f - StatConversion.GetArmorDamageReduction(character.Level, bossOpts.Armor, stats.TargetArmorReduction + exposeArmor, 0f) * (1f - findWeakness);
            float critMultiplier = RV.CritDmgMult * (1f + stats.BonusCritDamageMultiplier);
            float critMultiplierPoison = RV.CritDmgMultPoison * (1f + stats.BonusCritDamageMultiplier);
            float hasteBonus = (1f + StatConversion.GetPhysicalHasteFromRating(stats.HasteRating, CharacterClass.Rogue)) * (1f + stats.PhysicalHaste) - 1f;
            float speedModifier = 1f / (1f + hasteBonus) / (1f + meleeSpeedMult);
            float mainHandSpeed = mainHand == null ? 0f : mainHand._speed * speedModifier;
            float offHandSpeed = offHand == null ? 0f : offHand._speed * speedModifier;

            float mainHandSpeedNorm = mainHand.Type == ItemType.Dagger ? RV.WeapSpeedNormDagger : RV.WeapSpeedNorm;
            float offHandSpeedNorm = mainHand.Type == ItemType.Dagger ? RV.WeapSpeedNormDagger : RV.WeapSpeedNorm;

            float hitBonus = stats.PhysicalHit + StatConversion.GetPhysicalHitFromRating(stats.HitRating, CharacterClass.Rogue);
            float spellHitBonus = stats.SpellHit + StatConversion.GetSpellHitFromRating(stats.HitRating, CharacterClass.Rogue);
            float expertiseMHBonus = ((character.Race == CharacterRace.Human && (mainHand.Type == ItemType.OneHandSword || mainHand.Type == ItemType.OneHandMace)) ? RV.Racial.HumanExpBonus : 0) +
                                        ((character.Race == CharacterRace.Dwarf && (mainHand.Type == ItemType.OneHandMace)) ? RV.Racial.DwarfExpBonus : 0) +
                                        ((character.Race == CharacterRace.Orc && (mainHand.Type == ItemType.OneHandAxe || mainHand.Type == ItemType.FistWeapon)) ? RV.Racial.OrcExpBonus : 0);
            float expertiseOHBonus = ((character.Race == CharacterRace.Human && (offHand.Type == ItemType.OneHandSword || offHand.Type == ItemType.OneHandMace)) ? RV.Racial.HumanExpBonus : 0) +
                                        ((character.Race == CharacterRace.Dwarf && (offHand.Type == ItemType.OneHandMace)) ? RV.Racial.DwarfExpBonus : 0) +
                                        ((character.Race == CharacterRace.Orc && (offHand.Type == ItemType.OneHandAxe || offHand.Type == ItemType.FistWeapon)) ? RV.Racial.OrcExpBonus : 0);
            expertiseMHBonus = StatConversion.GetDodgeParryReducFromExpertise(StatConversion.GetExpertiseFromRating(stats.ExpertiseRating, CharacterClass.Rogue) + stats.Expertise + expertiseMHBonus, CharacterClass.Rogue);
            expertiseOHBonus = StatConversion.GetDodgeParryReducFromExpertise(StatConversion.GetExpertiseFromRating(stats.ExpertiseRating, CharacterClass.Rogue) + stats.Expertise + expertiseOHBonus, CharacterClass.Rogue);

            float chanceMHDodge = Math.Max(0f, StatConversion.WHITE_DODGE_CHANCE_CAP[targetLevel - character.Level] - expertiseMHBonus);
            float chanceOHDodge = Math.Max(0f, StatConversion.WHITE_DODGE_CHANCE_CAP[targetLevel - character.Level] - expertiseOHBonus);
            float chanceParry = 0f; //Math.Max(0f, StatConversion.WHITE_PARRY_CHANCE_CAP[targetLevel - character.Level] - expertiseBonus);
            float chanceWhiteMiss = Math.Max(0f, StatConversion.WHITE_MISS_CHANCE_CAP_DW[targetLevel - character.Level] - hitBonus);
            float chanceMiss = Math.Max(0f, StatConversion.YELLOW_MISS_CHANCE_CAP[targetLevel - character.Level] - hitBonus);
            float chancePoisonMiss = Math.Max(0f, StatConversion.GetSpellMiss(character.Level - targetLevel, false) - spellHitBonus);

            float glanceMultiplier = RV.GlanceMult;
            float chanceWhiteMHAvoided = chanceWhiteMiss + chanceMHDodge + chanceParry;
            float chanceWhiteOHAvoided = chanceWhiteMiss + chanceOHDodge + chanceParry;
            float chanceMHAvoided = chanceMiss + chanceMHDodge + chanceParry;
            float chanceOHAvoided = chanceMiss + chanceOHDodge + chanceParry;
            float chanceFinisherAvoided = chanceMiss + chanceMHDodge + chanceParry;
            float chancePoisonAvoided = chancePoisonMiss;
            float chanceWhiteMHNonAvoided = 1f - chanceWhiteMHAvoided;
            float chanceWhiteOHNonAvoided = 1f - chanceWhiteOHAvoided;
            float chanceMHNonAvoided = 1f - chanceMHAvoided;
            float chanceOHNonAvoided = 1f - chanceOHAvoided;
            float chancePoisonNonAvoided = 1f - chancePoisonAvoided;

            ////Crit Chances
            float chanceCritYellow = 0f;
            float chanceHitYellow = 0f;
            float chanceCritAmbush = 0f;
            float chanceHitAmbush = 0f;
            float chanceCritBackstab = 0f;
            float chanceHitBackstab = 0f;
            float cpPerBackstab = 0f;
            float chanceCritMuti = 0f;
            float chanceHitMuti = 0f;
            float cpPerMuti = 0f;
            float chanceCritSStrike = 0f;
            float chanceHitSStrike = 0f;
            float cpPerSStrike = 0f;
            float chanceCritHemo = 0f;
            float chanceHitHemo = 0f;
            float cpPerHemo = 0f;
            float chanceCritRStrike = 0f;
            float chanceHitRStrike = 0f;
            float cpPerRStrike = 0f;
            float chanceCritEvis = 0f;
            float chanceHitEvis = 0f;
            //float chanceCritBleed = 0f;
            float chanceGlance = StatConversion.WHITE_GLANCE_CHANCE_CAP[targetLevel - character.Level];
            float chanceCritWhiteMainTotal = 0f;
            float chanceCritWhiteMain = 0f;
            float chanceHitWhiteMain = 0f;
            float chanceCritWhiteOffTotal = 0f;
            float chanceCritWhiteOff = 0f;
            float chanceHitWhiteOff = 0f;
            float chanceCritPoison = 0f;
            float chanceHitPoison = 0f;

            for (int i = 0; i < critRatingUptimes.Length; i++)
            { //Sum up the weighted chances for each crit value
                WeightedStat iStat = critRatingUptimes[i];
                //Yellow - 2 Roll, so total of X chance to avoid, total of 1 chance to crit and hit when not avoided
                float chanceCritYellowTemp = Math.Min(1f, StatConversion.GetCritFromRating(stats.CritRating + iStat.Value, CharacterClass.Rogue)
                    + StatConversion.GetCritFromAgility(stats.Agility - RV.BaseStatCalcReduc, CharacterClass.Rogue)
                    + stats.PhysicalCrit
                    + StatConversion.NPC_LEVEL_CRIT_MOD[targetLevel - character.Level]
                    );
                float chanceHitYellowTemp = 1f - chanceCritYellowTemp;
                float chanceCritPoisonTemp = Math.Min(1f, StatConversion.GetSpellCritFromRating(stats.CritRating + iStat.Value)
                    + stats.SpellCrit
                    + stats.SpellCritOnTarget
                    + StatConversion.NPC_LEVEL_CRIT_MOD[targetLevel - character.Level]);
                float chanceHitPoisonTemp = 1f - chanceCritPoisonTemp;

                //Ambush - Identical to Yellow, but higher crit chance
                float chanceCritAmbushTmp = Math.Min(1f, chanceCritYellowTemp + ambushCritBonus);
                float chanceHitAmbushTmp = 1f - chanceCritAmbushTmp;
                float cpPerAmbushTmp = (chanceHitAmbushTmp + chanceCritAmbushTmp * (1f + cPonCPGCritChance)) * (1f + ambushCPBonus);

                //Backstab - Identical to Yellow, with higher crit chance
                float chanceCritBackstabTemp = Math.Min(1f, chanceCritYellowTemp + bSCritBonus);
                float chanceHitBackstabTemp = 1f - chanceCritBackstabTemp;
                float cpPerBackstabTemp = (chanceHitBackstabTemp + chanceCritBackstabTemp * (1f + cPonCPGCritChance));

                //Mutilate - Identical to Yellow, with higher crit chance
                float chanceCritMutiTemp = Math.Min(1f, chanceCritYellowTemp + mutiCritBonus);
                float chanceHitMutiTemp = 1f - chanceCritMutiTemp;
                float cpPerMutiTemp = (1 + chanceHitMutiTemp * chanceHitMutiTemp + (1 - chanceHitMutiTemp * chanceHitMutiTemp) * (1f + cPonCPGCritChance));

                //Sinister Strike - Identical to Yellow, with higher crit chance
                float chanceCritSStrikeTemp = Math.Min(1f, chanceCritYellowTemp + sStrikeCritBonus);
                float chanceHitSStrikeTemp = 1f - chanceCritSStrikeTemp;
                float cpPerSStrikeTemp = (chanceHitSStrikeTemp + chanceCritSStrikeTemp * (1f + cPonCPGCritChance)) * (1f + (talents.GlyphOfSinisterStrike ? RV.Glyph.SSCPBonusChance : 0f));

                //Hemorrhage - Identical to Yellow, with higher crit chance
                float chanceCritHemoTemp = Math.Min(1f, chanceCritYellowTemp);
                float chanceHitHemoTemp = 1f - chanceCritHemoTemp;
                float cpPerHemoTemp = (chanceHitHemoTemp + chanceCritHemoTemp * (1f + cPonCPGCritChance));

                //Revealing Strike - Identical to Yellow, with higher crit chance
                float chanceCritRStrikeTemp = Math.Min(1f, chanceCritYellowTemp);
                float chanceHitRStrikeTemp = 1f - chanceCritRStrikeTemp;
                float cpPerRStrikeTemp = chanceHitRStrikeTemp + chanceCritRStrikeTemp;

                //Eviscerate - Identical to Yellow, with higher crit chance
                float chanceCritEvisTemp = Math.Min(1f, chanceCritYellowTemp + evisCritBonus);
                float chanceHitEvisTemp = 1f - chanceCritEvisTemp;

                //White Mainhand
                float chanceCritWhiteMainTotalTemp = chanceCritYellowTemp;
                float chanceCritWhiteMainTemp = Math.Min(chanceCritYellowTemp, 1f - chanceGlance - chanceWhiteMHAvoided);
                float chanceHitWhiteMainTemp = 1f - chanceCritWhiteMainTemp - chanceWhiteMHAvoided - chanceGlance;
//                float chanceCritWhiteMainTemp = Math.Min(chanceCritYellowTemp, 1f - chanceGlance);
//                float chanceHitWhiteMainTemp = 1f - chanceCritWhiteMainTemp - chanceGlance;
                //White Offhand
                float chanceCritWhiteOffTotalTemp = chanceCritYellowTemp;
                float chanceCritWhiteOffTemp = Math.Min(chanceCritYellowTemp, 1f - chanceGlance - chanceWhiteOHAvoided);
                float chanceHitWhiteOffTemp = 1f - chanceCritWhiteOffTemp - chanceWhiteOHAvoided - chanceGlance;
//                float chanceCritWhiteOffTemp = Math.Min(chanceCritYellowTemp, 1f - chanceGlance);
//                float chanceHitWhiteOffTemp = 1f - chanceCritWhiteOffTemp - chanceGlance;

                chanceCritYellow += iStat.Chance * chanceCritYellowTemp;
                chanceHitYellow += iStat.Chance * chanceHitYellowTemp;
                chanceCritAmbush += iStat.Chance * chanceCritAmbushTmp;
                chanceHitAmbush += iStat.Chance * chanceHitAmbushTmp;
                chanceCritBackstab += iStat.Chance * chanceCritBackstabTemp;
                chanceHitBackstab += iStat.Chance * chanceHitBackstabTemp;
                cpPerBackstab += iStat.Chance * cpPerBackstabTemp;
                chanceCritMuti += iStat.Chance * chanceCritMutiTemp;
                chanceHitMuti += iStat.Chance * chanceHitMutiTemp;
                cpPerMuti += iStat.Chance * cpPerMutiTemp;
                chanceCritSStrike += iStat.Chance * chanceCritSStrikeTemp;
                chanceHitSStrike += iStat.Chance * chanceHitSStrikeTemp;
                cpPerSStrike += iStat.Chance * cpPerSStrikeTemp;
                chanceCritHemo += iStat.Chance * chanceCritHemoTemp;
                chanceHitHemo += iStat.Chance * chanceHitHemoTemp;
                cpPerHemo += iStat.Chance * cpPerHemoTemp;
                chanceCritRStrike += iStat.Chance * chanceCritRStrikeTemp;
                chanceHitRStrike += iStat.Chance * chanceHitRStrikeTemp;
                cpPerRStrike += iStat.Chance * cpPerRStrikeTemp;
                chanceCritEvis += iStat.Chance * chanceCritEvisTemp;
                chanceHitEvis += iStat.Chance * chanceHitEvisTemp;
                chanceCritWhiteMainTotal += iStat.Chance * chanceCritWhiteMainTotalTemp;
                chanceCritWhiteMain += iStat.Chance * chanceCritWhiteMainTemp;
                chanceHitWhiteMain += iStat.Chance * chanceHitWhiteMainTemp;
                chanceCritWhiteOffTotal += iStat.Chance * chanceCritWhiteOffTotalTemp;
                chanceCritWhiteOff += iStat.Chance * chanceCritWhiteOffTemp;
                chanceHitWhiteOff += iStat.Chance * chanceHitWhiteOffTemp;
                chanceCritPoison += iStat.Chance * chanceCritPoisonTemp;
                chanceHitPoison += iStat.Chance * chanceHitPoisonTemp;
            }

            calc.DodgedMHAttacks = chanceMHDodge * 100f;
            calc.DodgedOHAttacks = chanceOHDodge * 100f;
            calc.ParriedAttacks = chanceParry * 100f;
            calc.MissedWhiteAttacks = chanceWhiteMiss * 100f;
            calc.MissedAttacks = chanceMiss * 100f;
            calc.MissedPoisonAttacks = chancePoisonMiss * 100f;

            float timeToReapplyDebuffs = 1f / (1f - chanceMHAvoided) - 1f;
            float lagVariance = (float)calcOpts.Latency / 1000f;
            float ruptDurationUptime = RV.Rupt.BaseDuration + ruptDurationBonus;
            float ruptDurationAverage = ruptDurationUptime + timeToReapplyDebuffs + lagVariance;
            float snDBonusDuration = snDDurationBonus - lagVariance;
            float recupBonusDuration = -lagVariance;
            float eABonusDuration = exposeDurationBonus - lagVariance;
            #endregion

            #region Attack Damages
            float DPSfromAP = stats.AttackPower / RV.APperDPS;
            float baseDamage = (mainHand == null ? 0f : mainHand._speed) * DPSfromAP + stats.WeaponDamage + (mainHand.MinDamage + mainHand.MaxDamage) / 2f;
            float baseDamageNorm = mainHandSpeedNorm * DPSfromAP + stats.WeaponDamage + (mainHand.MinDamage + mainHand.MaxDamage) / 2f;
            float baseOffDamage = ((offHand == null ? 0f : offHand._speed) * DPSfromAP + stats.WeaponDamage + (offHand.MinDamage + offHand.MaxDamage) / 2f) * (1f + oHDmgMult);
            float baseOffDamageNorm = (offHandSpeedNorm * DPSfromAP + stats.WeaponDamage + (offHand.MinDamage + offHand.MaxDamage) / 2f) * (1f + oHDmgMult);
            float meleeBonus = (1f + stats.BonusPhysicalDamageMultiplier) * (1f + stats.BonusDamageMultiplier) * (1f + meleeDmgMult);
            float meleeDamageRaw = baseDamage * meleeBonus * modArmor;
            float meleeOffDamageRaw = baseOffDamage * meleeBonus * modArmor;
            float meleeDamageNormRaw = baseDamageNorm * meleeBonus * modArmor;
            float meleeOffDamageNormRaw = baseOffDamageNorm * meleeBonus * modArmor;
            float backstabDamageRaw = (baseDamageNorm * RV.BS.WeapDmgMult + RV.BS.BonusDmg) * meleeBonus * (1f + bSDmgMult) * modArmor;
            backstabDamageRaw *= (mainHand._type == ItemType.Dagger ? 1f : 0f);
            float hemoDamageRaw = (baseDamageNorm * RV.Hemo.WeapDmgMult * (mainHand._type == ItemType.Dagger ? RV.Hemo.DaggerDmgMult : 0f)) * meleeBonus * (1f + hemoDmgMult) * modArmor;
            hemoDamageRaw *= (talents.Hemorrhage > 0 ? 1f: 0f);
            float sStrikeDamageRaw = (baseDamageNorm + RV.SS.BonusDmg) * meleeBonus * (1f + sSDmgMult) * modArmor;
            float mutiDamageMainRaw = (baseDamageNorm * RV.Muti.WeapDmgMult + RV.Muti.BonusDmg) * meleeBonus * (1f + mutiDmgMult) * (1f + (targetPoisonable ? 0.2f : 0f)) * modArmor;
            mutiDamageMainRaw *= ((spec == 0 && mainHand._type == ItemType.Dagger && offHand._type == ItemType.Dagger) ? 1f : 0f);
            float mutiDamageOffRaw = (baseOffDamageNorm * RV.Muti.WeapDmgMult + RV.Muti.BonusDmg) * meleeBonus * (1f + mutiDmgMult) * (1f + (targetPoisonable ? 0.2f : 0f)) * modArmor;
            mutiDamageOffRaw *= ((spec == 0 && mainHand._type == ItemType.Dagger && offHand._type == ItemType.Dagger) ? 1f : 0f);
            float mutiDamageRaw = mutiDamageMainRaw + mutiDamageOffRaw;
            float rStrikeDamageRaw = (baseDamage * RV.RS.WeapDmgMult) * meleeBonus * (1f + stats.FangsoftheFatherMultiplier) * modArmor;
            rStrikeDamageRaw *= talents.RevealingStrike > 0 ? 1f : 0f;
            float ambushDmgRaw = (baseDamageNorm + RV.Ambush.BonusDmg) * RV.Ambush.WeapDmgMult * (mainHand._type == ItemType.Dagger ? RV.Ambush.DaggerDmgMult : 1f) * (1f + ambushDmgMult);
            float[] ruptDamageRaw = new float[] {0,
                (RV.Rupt.BaseDmg + 1 * RV.Rupt.TickBaseDmg + RV.Rupt.TickAPMult[1] * stats.AttackPower) * (3f + 1f + ruptDurationBonus / RV.Rupt.TickTime) * meleeBonus * (1f + stats.BonusBleedDamageMultiplier),
                (RV.Rupt.BaseDmg + 2 * RV.Rupt.TickBaseDmg + RV.Rupt.TickAPMult[2] * stats.AttackPower) * (3f + 2f + ruptDurationBonus / RV.Rupt.TickTime) * meleeBonus * (1f + stats.BonusBleedDamageMultiplier),
                (RV.Rupt.BaseDmg + 3 * RV.Rupt.TickBaseDmg + RV.Rupt.TickAPMult[3] * stats.AttackPower) * (3f + 3f + ruptDurationBonus / RV.Rupt.TickTime) * meleeBonus * (1f + stats.BonusBleedDamageMultiplier),
                (RV.Rupt.BaseDmg + 4 * RV.Rupt.TickBaseDmg + RV.Rupt.TickAPMult[4] * stats.AttackPower) * (3f + 4f + ruptDurationBonus / RV.Rupt.TickTime) * meleeBonus * (1f + stats.BonusBleedDamageMultiplier),
                (RV.Rupt.BaseDmg + 5 * RV.Rupt.TickBaseDmg + RV.Rupt.TickAPMult[5] * stats.AttackPower) * (3f + 5f + ruptDurationBonus / RV.Rupt.TickTime) * meleeBonus * (1f + stats.BonusBleedDamageMultiplier)};
            float evisBaseDamageRaw = RV.Evis.BaseAvgDmg * meleeBonus * (1f + evisDmgMult) * modArmor;
            float evisCPDamageRaw = (RV.Evis.CPBaseDmg + RV.Evis.CPAPMult * stats.AttackPower) * meleeBonus * (1f + evisDmgMult) * modArmor;
            float envenomBaseDamageRaw = RV.Envenom.BaseDmg * (1f + natureDmgMult) * (1f + envenomDmgMult) * (1f + meleeDmgMult);
            float envenomCPDamageRaw = (RV.Envenom.CPBaseDmg + RV.Envenom.CPAPMult * stats.AttackPower) * (1f + natureDmgMult) * (1f + envenomDmgMult) * (1f + meleeDmgMult);
            float iPDamageRaw = (RV.IP.BaseAvgDmg + RV.IP.APMult * stats.AttackPower) * (1f + poisonDmgMult);
            float dPDamageRaw = (RV.DP.BaseDmg + RV.DP.APMult * stats.AttackPower) * (1f + poisonDmgMult) * RV.DP.TickTime / RV.DP.Duration;
            float wPDamageRaw = (RV.WP.BaseDmg + RV.WP.APMult * stats.AttackPower) * (1f + poisonDmgMult);
            float venomousWoundsRaw = dmgBonusOnGarrRuptTickChance * (RV.Talents.VenomousWoundsBonusDmg + RV.Talents.VenomousWoundsAPMult * stats.AttackPower) * (1f + natureDmgMult);

            float meleeDamageAverage = (chanceGlance * glanceMultiplier + chanceCritWhiteMain * critMultiplier + chanceHitWhiteMain) * meleeDamageRaw;
            float meleeOffDamageAverage = (chanceGlance * glanceMultiplier + chanceCritWhiteOff * critMultiplier + chanceHitWhiteOff) * meleeOffDamageRaw;
            float meleeDamageNormAverage = (chanceGlance * glanceMultiplier + chanceCritWhiteMain * critMultiplier + chanceHitWhiteMain) * meleeDamageNormRaw;
            float meleeOffDamageNormAverage = (chanceGlance * glanceMultiplier + chanceCritWhiteOff * critMultiplier + chanceHitWhiteOff) * meleeOffDamageNormRaw;
            float mainGaucheDmgAvg = (1f - chanceCritYellow) * meleeDamageRaw + chanceCritYellow * meleeDamageRaw * critMultiplier;
            float backstabDamageAverage = (1f - chanceCritBackstab) * backstabDamageRaw + chanceCritBackstab * backstabDamageRaw * (critMultiplier + cPGCritDmgMult);
            float hemoDamageAverage = (1f - chanceCritHemo) * hemoDamageRaw + chanceCritHemo * hemoDamageRaw * (critMultiplier + cPGCritDmgMult);
            float sStrikeDamageAverage = (1f - chanceCritSStrike) * sStrikeDamageRaw + chanceCritSStrike * sStrikeDamageRaw * (critMultiplier + cPGCritDmgMult);
            float mutiDamageAverage = chanceHitMuti * chanceHitMuti * mutiDamageRaw +
                chanceCritMuti * chanceHitMuti * (mutiDamageMainRaw * (critMultiplier + cPGCritDmgMult) + mutiDamageOffRaw) +
                chanceHitMuti * chanceCritMuti * (mutiDamageMainRaw + mutiDamageOffRaw * (critMultiplier + cPGCritDmgMult)) +
                chanceCritMuti * chanceCritMuti * (mutiDamageMainRaw + mutiDamageOffRaw) * (critMultiplier + cPGCritDmgMult);
            float rStrikeDamageAverage = (1f - chanceCritRStrike) * rStrikeDamageRaw + chanceCritRStrike * rStrikeDamageRaw * critMultiplier;
            float ambushDmgAvg = (1f - chanceCritAmbush) * ambushDmgRaw + chanceCritAmbush * ambushDmgRaw * critMultiplier;
            float[] ruptDamageAverage = new float[] {0,
                ((1f - chanceCritYellow) * ruptDamageRaw[1] + chanceCritYellow * ruptDamageRaw[1] * critMultiplier),
                ((1f - chanceCritYellow) * ruptDamageRaw[2] + chanceCritYellow * ruptDamageRaw[2] * critMultiplier),
                ((1f - chanceCritYellow) * ruptDamageRaw[3] + chanceCritYellow * ruptDamageRaw[3] * critMultiplier),
                ((1f - chanceCritYellow) * ruptDamageRaw[4] + chanceCritYellow * ruptDamageRaw[4] * critMultiplier),
                ((1f - chanceCritYellow) * ruptDamageRaw[5] + chanceCritYellow * ruptDamageRaw[5] * critMultiplier)};
            float evisBaseDamageAverage = (1f - chanceCritEvis) * evisBaseDamageRaw + chanceCritEvis * evisBaseDamageRaw * critMultiplier;
            float evisCPDamageAverage = (1f - chanceCritEvis) * evisCPDamageRaw + chanceCritEvis * evisCPDamageRaw * critMultiplier;
            float envenomBaseDamageAverage = (1f - chanceCritYellow) * envenomBaseDamageRaw + chanceCritYellow * envenomBaseDamageRaw * critMultiplier;
            float envenomCPDamageAverage = (1f - chanceCritYellow) * envenomCPDamageRaw + chanceCritYellow * envenomCPDamageRaw * critMultiplier;
            float iPDamageAverage = (1f - chanceCritPoison) * iPDamageRaw + chanceCritPoison * iPDamageRaw * critMultiplierPoison;
            float dPDamageAverage = (1f - chanceCritPoison) * dPDamageRaw + chanceCritPoison * dPDamageRaw * critMultiplierPoison;
            float wPDamageAverage = (1f - chanceCritPoison) * wPDamageRaw + chanceCritPoison * wPDamageRaw * critMultiplierPoison;
            float venomousWoundsAverage = (1f - chanceCritPoison) * venomousWoundsRaw + chanceCritPoison * venomousWoundsRaw * critMultiplierPoison;
            #endregion

            #region Energy Costs
            float ambushEnergyRaw = RV.Ambush.Cost - ambushBSCostReduc;
            //float garrEnergyRaw = RV.Garrote.Cost;
            float backstabEnergyRaw = RV.BS.Cost - ambushBSCostReduc - (talents.GlyphOfBackstab ? chanceCritBackstab * RV.Glyph.BSEnergyOnCrit : 0f);
            float hemoEnergyRaw = RV.Hemo.Cost - hemoCostReduc;
            float sStrikeEnergyRaw = RV.SS.Cost - sSCostReduc;
            float mutiEnergyRaw = RV.Muti.Cost - mutiCostReduc;
            float rSEnergyRaw = RV.RS.Cost;
            float ruptEnergyRaw = RV.Rupt.Cost;
            float evisEnergyRaw = RV.Evis.Cost;
            float envenomEnergyRaw = RV.Envenom.Cost;
            float snDEnergyRaw = RV.SnD.Cost;
            float recupEnergyRaw = RV.Recup.Cost;
            float exposeEnergyRaw = RV.Expose.Cost;

            //[rawCost + ((1/chance_to_land) - 1) * rawCost/5] 
            float energyCostMultiplier = 1f + ((1f / chanceMHNonAvoided) - 1f) * (1 - RV.EnergyReturnOnAvoid);
            float backstabEnergyAverage = backstabEnergyRaw * energyCostMultiplier;
            float hemoEnergyAverage = hemoEnergyRaw * energyCostMultiplier;
            float sStrikeEnergyAverage = sStrikeEnergyRaw * energyCostMultiplier;
            float mutiEnergyAverage = mutiEnergyRaw * energyCostMultiplier;
            float rSEnergyAverage = rSEnergyRaw * energyCostMultiplier;
            float ruptEnergyAverage = ruptEnergyRaw * energyCostMultiplier;
            float evisEnergyAverage = evisEnergyRaw * energyCostMultiplier;
            float envenomEnergyAverage = envenomEnergyRaw * energyCostMultiplier;
            float snDEnergyAverage = snDEnergyRaw * energyCostMultiplier;
            float recupEnergyAverage = recupEnergyRaw * energyCostMultiplier;
            float eAEnergyAverage = exposeEnergyRaw * energyCostMultiplier;
            #endregion

            #region Ability Stats
            RogueAbilityStats mainHandStats = new RogueMHStats()
            {
                DamagePerHit = meleeDamageRaw,
                DamagePerSwing = meleeDamageAverage,
                Weapon = mainHand,
                CritChance = chanceCritWhiteMain,
            };
            RogueAbilityStats offHandStats = new RogueOHStats()
            {
                DamagePerHit = meleeOffDamageRaw,
                DamagePerSwing = meleeOffDamageAverage,
                Weapon = offHand,
                CritChance = chanceCritWhiteOff,
            };
            RogueAbilityStats mainGaucheStats = new RogueMainGaucheStats()
            {
                DamagePerHit = meleeDamageNormRaw,
                DamagePerSwing = mainGaucheDmgAvg,
                Weapon = mainHand,
                CritChance = chanceCritYellow,
            };
            RogueAbilityStats backstabStats = new RogueBackstabStats()
            {
                DamagePerHit = backstabDamageRaw,
                DamagePerSwing = backstabDamageAverage,
                EnergyCost = backstabEnergyAverage,
                CritChance = chanceCritBackstab,
                CPPerSwing = cpPerBackstab,
            };
            RogueAbilityStats hemoStats = new RogueHemoStats()
            {
                DamagePerHit = hemoDamageRaw,
                DamagePerSwing = hemoDamageAverage,
                EnergyCost = hemoEnergyAverage,
                CritChance = chanceCritHemo,
                CPPerSwing = cpPerHemo,
            };
            RogueAbilityStats sStrikeStats = new RogueSStrikeStats()
            {
                DamagePerHit = sStrikeDamageRaw,
                DamagePerSwing = sStrikeDamageAverage,
                EnergyCost = sStrikeEnergyAverage,
                CritChance = chanceCritSStrike,
                CPPerSwing = cpPerSStrike,
            };
            RogueAbilityStats mutiStats = new RogueMutiStats()
            {
                DamagePerHit = mutiDamageRaw,
                DamagePerSwing = mutiDamageAverage,
                EnergyCost = mutiEnergyAverage,
                CritChance = chanceCritMuti,
                CPPerSwing = cpPerMuti,
            };
            RogueAbilityStats rStrikeStats = new RogueRStrikeStats()
            {
                DamagePerHit = rStrikeDamageRaw,
                DamagePerSwing = rStrikeDamageAverage,
                EnergyCost = rSEnergyAverage,
                CritChance = chanceCritRStrike,
                CPPerSwing = cpPerRStrike,
            };
            RogueAbilityStats ruptStats = new RogueRuptStats()
            {
                DamagePerHitArray = new float[] {0,
                    ruptDamageRaw[1],
                    ruptDamageRaw[2],
                    ruptDamageRaw[3],
                    ruptDamageRaw[4],
                    ruptDamageRaw[5]},
                DamagePerSwingArray = new float[] {0,
                    ruptDamageAverage[1],
                    ruptDamageAverage[2],
                    ruptDamageAverage[3],
                    ruptDamageAverage[4],
                    ruptDamageAverage[5]},
                DurationUptime = ruptDurationUptime,
                DurationAverage = ruptDurationAverage,
                DurationPerCP = RV.Rupt.DurationPerCP,
                EnergyCost = ruptEnergyAverage,
            };
            RogueAbilityStats evisStats = new RogueEvisStats()
            {
                DamagePerHit = evisBaseDamageRaw,
                DamagePerSwing = evisBaseDamageAverage,
                DamagePerHitPerCP = evisCPDamageRaw,
                DamagePerSwingPerCP = evisCPDamageAverage,
                EnergyCost = evisEnergyAverage,
                CritChance = chanceCritEvis,
                DamagePerCrit = evisBaseDamageRaw * critMultiplier,
                DamagePerCritPerCP = evisCPDamageRaw * critMultiplier,
            };
            RogueAbilityStats envenomStats = new RogueEnvenomStats()
            {
                DamagePerHit = envenomBaseDamageRaw,
                DamagePerSwing = envenomBaseDamageAverage,
                DamagePerHitPerCP = envenomCPDamageRaw,
                DamagePerSwingPerCP = envenomCPDamageAverage,
                EnergyCost = envenomEnergyAverage,
                CritChance = chanceCritYellow,
                DamagePerCrit = envenomBaseDamageRaw * critMultiplier,
                DamagePerCritPerCP = envenomCPDamageRaw * critMultiplier,
            };
            RogueAbilityStats snDStats = new RogueSnDStats()
            {
                DurationUptime = snDBonusDuration * (1f + snDDurationMult),
                DurationAverage = (RV.SnD.BaseDuration + snDBonusDuration) * (1f + snDDurationMult),
                EnergyCost = snDEnergyAverage,
                DurationPerCP = RV.SnD.DurationPerCP,
            };
            RogueAbilityStats recupStats = new RogueRecupStats()
            {
                DurationUptime = recupBonusDuration,
                DurationAverage = RV.Recup.BaseDuration + recupBonusDuration,
                EnergyCost = recupEnergyAverage,
                DurationPerCP = RV.Recup.DurationPerCP,
            };
            RogueAbilityStats exposeStats = new RogueExposeStats()
            {
                DurationUptime = eABonusDuration,
                DurationAverage = RV.Expose.BaseDuration + eABonusDuration,
                EnergyCost = eAEnergyAverage,
                DurationPerCP = RV.Expose.DurationPerCP,
            };
            RogueAbilityStats iPStats = new RogueIPStats()
            {
                DamagePerHit = iPDamageRaw,
                DamagePerSwing = iPDamageAverage,
            };
            RogueAbilityStats dPStats = new RogueDPStats()
            {
                DamagePerHit = dPDamageRaw,
                DamagePerSwing = dPDamageAverage,
            };
            RogueAbilityStats wPStats = new RogueWPStats()
            {
                DamagePerHit = wPDamageRaw,
                DamagePerSwing = wPDamageAverage,
            };
            RogueAbilityStats venomousWoundsStats = new RogueVenomousWoundsStats()
            {
                DamagePerHit = venomousWoundsRaw,
                DamagePerSwing = venomousWoundsAverage,
            };
            #endregion

            #region Rotations
            RogueRotationCalculator rotationCalculator;
            RogueRotationCalculator.RogueRotationCalculation rotationCalculationOptimal;
//            BonusPhysicalDamageMultiplier = character.ActiveBuffs.Contains(Buff.GetBuffByName("Ravage")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Acid Spit")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Brittle Bones")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Blood Frenzy")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Savage Combat")) ? 0f : RV.Talents.SavageCombatMult * talents.SavageCombat,
            #region Assassination
            if (spec == 0)
            {
                rotationCalculator = new RogueRotationCalculatorAss(character, stats, bossOpts, calcOpts,
                    hasteBonus, mainHandSpeed, offHandSpeed, mainHandSpeedNorm, offHandSpeedNorm, chanceWhiteMHAvoided, chanceWhiteOHAvoided, chanceMHAvoided, chanceOHAvoided,
                    chanceFinisherAvoided, chancePoisonAvoided, chanceCritYellow * cPonCPGCritChance, (1f - chanceHitMuti * chanceHitMuti) * cPonCPGCritChance, mainHandStats,
                    offHandStats, backstabStats, mutiStats, ruptStats, envenomStats, snDStats, exposeStats, iPStats, dPStats, wPStats, venomousWoundsStats);
                rotationCalculationOptimal = new RogueRotationCalculatorAss.RogueRotationCalculation();

                bool segmentedOptimize = talents.MurderousIntent > 0;
                int numberOfSegments = segmentedOptimize ? 2 : 1;
                float durationMultiplier = 1f;
                if (!calcOpts.ForceCustom)
                {
                    while (numberOfSegments > 0)
                    {
                        if (segmentedOptimize && numberOfSegments == 2) durationMultiplier = 1 - RV.Talents.MurderousIntentThreshold;
                        else if (segmentedOptimize && numberOfSegments == 1) durationMultiplier = RV.Talents.MurderousIntentThreshold;
                        RogueRotationCalculator.RogueRotationCalculation rotationCalculationDPS = new RogueRotationCalculatorAss.RogueRotationCalculation();
                        for (int snDCP = 4; snDCP < 6; snDCP++)
                            for (int finisherCP = 4; finisherCP < 6; finisherCP++)
                                for (int CPG = 0; CPG < 2; CPG++)
                                {
                                    if (CPG == 1 && (!calcOpts.EnableBS || backstabStats.DamagePerSwing == 0)) continue;
                                    for (int ruptCP = 3; ruptCP < 6; ruptCP++)
                                    {
                                        if (ruptCP > 3 && !calcOpts.EnableRupt) continue;
                                        for (int mHPoison = 1; mHPoison < 3; mHPoison++)
                                        {
                                            if (mainHand == null) break;
                                            if ((mHPoison == 1 && !calcOpts.EnableIP) ||
                                                (mHPoison == 2 && !calcOpts.EnableDP)) continue;
                                            for (int oHPoison = 1; oHPoison < 3; oHPoison++)
                                            {
                                                if (offHand == null) break;
                                                if ((oHPoison == 1 && !calcOpts.EnableIP) ||
                                                    (oHPoison == 2 && !calcOpts.EnableDP)) continue;
                                                bool useTotT = false;
                                                RogueRotationCalculatorAss.RogueRotationCalculation rotationCalculation =
                                                    rotationCalculator.GetRotationCalculations(durationMultiplier, CPG, 0, (ruptCP == 3 ? 0 : ruptCP), false, 0, finisherCP, snDCP, mHPoison, oHPoison, useTotT, (int)exposeArmor, PTRMode);
                                                if (rotationCalculation.DPS > rotationCalculationDPS.DPS)
                                                    rotationCalculationDPS = rotationCalculation;
                                            }
                                        }
                                    }
                                }
                        if (numberOfSegments == 2) rotationCalculationOptimal = rotationCalculationDPS;
                        else if (segmentedOptimize) rotationCalculationOptimal += rotationCalculationDPS;
                        else rotationCalculationOptimal = rotationCalculationDPS;
                        numberOfSegments--;
                    }
                }

                numberOfSegments = segmentedOptimize ? 2 : 1;
                durationMultiplier = 1f;
                while (numberOfSegments > 0)
                {
                    if (segmentedOptimize && numberOfSegments == 2) durationMultiplier = 1 - RV.Talents.MurderousIntentThreshold;
                    else if (segmentedOptimize && numberOfSegments == 1) durationMultiplier = RV.Talents.MurderousIntentThreshold;
                    RogueRotationCalculator.RogueRotationCalculation rotationCalculationDPS = new RogueRotationCalculatorAss.RogueRotationCalculation();
                    rotationCalculationDPS = rotationCalculator.GetRotationCalculations(
                        durationMultiplier, calcOpts.CustomCPG, calcOpts.CustomRecupCP, calcOpts.CustomRuptCP, calcOpts.CustomUseRS, calcOpts.CustomFinisher, calcOpts.CustomCPFinisher, calcOpts.CustomCPSnD, calcOpts.CustomMHPoison, calcOpts.CustomOHPoison, calcOpts.CustomUseTotT, (int)exposeArmor, PTRMode);
                    if (numberOfSegments == 2) calc.CustomRotation = rotationCalculationDPS;
                    else if (segmentedOptimize) calc.CustomRotation += rotationCalculationDPS;
                    else calc.CustomRotation = rotationCalculationDPS;
                    numberOfSegments--;
                }
            }
            #endregion
            #region Combat
            else if (spec == 1)
            {
                rotationCalculator = new RogueRotationCalculatorCombat(character, stats, bossOpts, calcOpts, hasteBonus, mainHandSpeed, offHandSpeed, mainHandSpeedNorm, offHandSpeedNorm,
                    chanceWhiteMHAvoided, chanceWhiteOHAvoided, chanceMHAvoided, chanceOHAvoided, chanceFinisherAvoided, chancePoisonAvoided, chanceCritYellow * cPonCPGCritChance,
                    mainHandStats, offHandStats, mainGaucheStats, sStrikeStats, rStrikeStats, ruptStats, evisStats, snDStats, exposeStats, iPStats, dPStats, wPStats);
                rotationCalculationOptimal = new RogueRotationCalculatorCombat.RogueRotationCalculation();

                if (!calcOpts.ForceCustom)
                {
                    RogueRotationCalculator.RogueRotationCalculation rotationCalculationDPS = new RogueRotationCalculatorCombat.RogueRotationCalculation();
                    for (int snDCP = 4; snDCP < 6; snDCP++)
                        for (int finisherCP = 4; finisherCP < 6; finisherCP++)
                            for (int ruptCP = 3; ruptCP < 6; ruptCP++)
                                for (int useRS = 0; useRS < 2; useRS++)
                                {
                                    if (useRS == 1 && (!calcOpts.EnableRS || rStrikeStats.DamagePerSwing == 0)) continue;
                                    for (int mHPoison = 1; mHPoison < 4; mHPoison++)
                                    {
                                        if (!targetPoisonable || mainHand == null) break;
                                        if ((mHPoison == 1 && !calcOpts.EnableIP) ||
                                            (mHPoison == 2 && !calcOpts.EnableDP) ||
                                            (mHPoison == 3 && !calcOpts.EnableWP)) continue;
                                        for (int oHPoison = 1; oHPoison < 4; oHPoison++)
                                        {
                                            if (!targetPoisonable || offHand == null) break;
                                            if ((oHPoison == 1 && !calcOpts.EnableIP) ||
                                                (oHPoison == 2 && !calcOpts.EnableDP) ||
                                                (oHPoison == 3 && !calcOpts.EnableWP)) continue;
                                            bool useTotT = false;
                                            RogueRotationCalculator.RogueRotationCalculation rotationCalculation =
                                                rotationCalculator.GetRotationCalculations(0, 0, 0, (ruptCP == 3 ? 0 : ruptCP), useRS == 1, 0, finisherCP, snDCP, mHPoison, oHPoison, useTotT, (int)exposeArmor, PTRMode);
                                            if (rotationCalculation.DPS > rotationCalculationDPS.DPS)
                                                rotationCalculationDPS = rotationCalculation;
                                        }
                                    }
                                }
                    rotationCalculationOptimal = rotationCalculationDPS;
                }
                calc.CustomRotation = rotationCalculator.GetRotationCalculations(0, calcOpts.CustomCPG, calcOpts.CustomRecupCP, calcOpts.CustomRuptCP, calcOpts.CustomUseRS, calcOpts.CustomFinisher,
                    calcOpts.CustomCPFinisher, calcOpts.CustomCPSnD, calcOpts.CustomMHPoison, calcOpts.CustomOHPoison, calcOpts.CustomUseTotT, (int)exposeArmor, PTRMode);
            }
            #endregion
            #region Subtlety
            else
            {
                rotationCalculator = new RogueRotationCalculatorSubt(character, stats, bossOpts, calcOpts, hasteBonus, mainHandSpeed, offHandSpeed, mainHandSpeedNorm, offHandSpeedNorm, chanceWhiteMHAvoided,
                    chanceWhiteOHAvoided, chanceMHAvoided, chanceOHAvoided, chanceFinisherAvoided, chancePoisonAvoided, chanceCritYellow * cPonCPGCritChance, mainHandStats, offHandStats,
                    backstabStats, hemoStats, ruptStats, evisStats, snDStats, recupStats, exposeStats, iPStats, dPStats, wPStats);
                rotationCalculationOptimal = new RogueRotationCalculatorSubt.RogueRotationCalculation();
                bool useHemo = !(character.ActiveBuffs.Contains(Buff.GetBuffByName("Mangle")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Hemorrhage")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Blood Frenzy")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Gore")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Stampede")) || character.ActiveBuffs.Contains(Buff.GetBuffByName("Tendon Rip")));

                if (!calcOpts.ForceCustom)
                {
                    RogueRotationCalculator.RogueRotationCalculation rotationCalculationDPS = new RogueRotationCalculatorSubt.RogueRotationCalculation();
                    for (int snDCP = 4; snDCP < 6; snDCP++)
                        for (int finisherCP = 4; finisherCP < 6; finisherCP++)
                            for (int CPG = 0; CPG < 2; CPG++)
                            {
                                if ((CPG == 0 && (!calcOpts.EnableBS || backstabStats.DamagePerSwing == 0)) ||
                                    (CPG == 1 && (!calcOpts.EnableHemo || hemoStats.DamagePerSwing == 0))) continue;
                                for (int ruptCP = 3; ruptCP < 6; ruptCP++)
                                {
                                    if (ruptCP > 3 && !calcOpts.EnableRupt) continue;
                                    for (int recupCP = 3; recupCP < 6; recupCP++)
                                    {
                                        if (recupCP > 3 && !calcOpts.EnableRecup) continue;
                                        for (int mHPoison = 1; mHPoison < 3; mHPoison++)
                                        {
                                            if (!targetPoisonable || mainHand == null) break;
                                            if ((mHPoison == 1 && !calcOpts.EnableIP) ||
                                                (mHPoison == 2 && !calcOpts.EnableDP)) continue;
                                            for (int oHPoison = 1; oHPoison < 3; oHPoison++)
                                            {
                                                if (!targetPoisonable || offHand == null) break;
                                                if ((oHPoison == 1 && !calcOpts.EnableIP) ||
                                                    (oHPoison == 2 && !calcOpts.EnableDP)) continue;
                                                bool useTotT = false;
                                                RogueRotationCalculator.RogueRotationCalculation rotationCalculation =
                                                    rotationCalculator.GetRotationCalculations(0, CPG, (recupCP == 3 ? 0 : recupCP), (ruptCP == 3 ? 0 : ruptCP), useHemo, 0, finisherCP, snDCP, mHPoison, oHPoison, useTotT, (int)exposeArmor, PTRMode);
                                                if (rotationCalculation.DPS > rotationCalculationDPS.DPS)
                                                    rotationCalculationDPS = rotationCalculation;
                                            }
                                        }
                                    }
                                }
                            }
                    rotationCalculationOptimal = rotationCalculationDPS;
                }
                calc.CustomRotation = rotationCalculator.GetRotationCalculations(0, calcOpts.CustomCPG, calcOpts.CustomRecupCP, calcOpts.CustomRuptCP, calcOpts.CustomUseRS, calcOpts.CustomFinisher,
                    calcOpts.CustomCPFinisher, calcOpts.CustomCPSnD, calcOpts.CustomMHPoison, calcOpts.CustomOHPoison, calcOpts.CustomUseTotT, (int)exposeArmor, PTRMode);
            }
            #endregion
            
            calc.HighestDPSRotation = calcOpts.ForceCustom == false ? rotationCalculationOptimal : calc.CustomRotation;
            #endregion

            calc.AvoidedWhiteMHAttacks = chanceWhiteMHAvoided * 100f;
            calc.AvoidedWhiteOHAttacks = chanceWhiteOHAvoided * 100f;
            calc.AvoidedAttacks = chanceMHAvoided * 100f;
            calc.AvoidedFinisherAttacks = chanceFinisherAvoided * 100f;
            calc.AvoidedPoisonAttacks = chancePoisonAvoided * 100f;
            calc.DodgedMHAttacks = chanceMHDodge * 100f;
            calc.ParriedAttacks = chanceParry * 100f;
            calc.MissedAttacks = chanceMiss * 100f;
            calc.CritChanceYellow = chanceCritYellow * 100f;
            calc.CritChanceMHTotal = chanceCritWhiteMainTotal * 100f;
            calc.CritChanceMH = chanceCritWhiteMain * 100f;
            calc.CritChanceOHTotal = chanceCritWhiteOffTotal * 100f;
            calc.CritChanceOH = chanceCritWhiteOff * 100f;
            calc.MainHandSpeed = mainHandSpeed;
            calc.OffHandSpeed = offHandSpeed;
            calc.ArmorMitigation = (1f - modArmor) * 100f;
            calc.Duration = bossOpts.BerserkTimer;

            calc.MainHandStats = mainHandStats;
            calc.OffHandStats = offHandStats;
            calc.MainGaucheStats = mainGaucheStats;
            calc.BackstabStats = backstabStats;
            calc.HemoStats = hemoStats;
            calc.SStrikeStats = sStrikeStats;
            calc.MutiStats = mutiStats;
            calc.RStrikeStats = rStrikeStats;
            calc.RuptStats = ruptStats;
            calc.SnDStats = snDStats;
            calc.EvisStats = evisStats;
            calc.EnvenomStats = envenomStats;
            calc.IPStats = iPStats;
            calc.DPStats = dPStats;
            calc.WPStats = wPStats;
            calc.VenomousWoundsStats = venomousWoundsStats;

            float magicDPS = 0f; // (stats.ShadowDamage + stats.ArcaneDamage) * (1f + chanceCritYellow);
            calc.DPSPoints = calc.HighestDPSRotation.DPS + magicDPS;
            calc.SurvivabilityPoints = stats.Health / 100f;
            calc.OverallPoints = calc.DPSPoints + calc.SurvivabilityPoints;
            return calc;
        }
예제 #3
0
        /// <summary>
        /// Calculate damage output
        /// </summary>
        /// <param name="character"></param>
        /// <param name="additionalItem"></param>
        /// <returns></returns>
        /// Much of this code is based on Aldriana's RogueCalc
        ///
        public override CharacterCalculationsBase GetCharacterCalculations(Character character, Item additionalItem)
        {
            float  energyCPG, numCPG, sndLength, finisherCost, sndEnergy, sndHaste, cycleTime, energyRegen, ruthlessnessCP;
            float  totalHaste;
            string cpg;
            float  missChance, mhDodgeChance, ohDodgeChance, glanceChance, mhExpertise, ohExpertise, mhCrit, ohCrit, probMHHit, probOHHit;
            float  mhHastedSpeed, ohHastedSpeed, avgMHDmg, avgOHDmg, totalArmor;
            float  mhAttacks, ohAttacks, ohHits, ssHits, wfHits, avgWFDmg;
            float  whiteDPS, finisherDPS, wfDPS, ssDPS, poisonDPS, cpgDPS;
            float  mhWhite, ohWhite, damageReduction, bonusWhiteCritDmg;
            float  avgCPGDmg, bonusCPGCrit, bonusCPGDmgMult, bonusCPGCritDmgMult, cpgCrit;
            float  finisherDmg, evisMod, evisMin, evisMax;
            float  probPoison;
            bool   calcDeadly;

            CalculationOptionsRogue calcOpts = character.CalculationOptions as CalculationOptionsRogue;
            Stats stats = GetCharacterStats(character, additionalItem);
            CharacterCalculationsRogue calculatedStats = new CharacterCalculationsRogue();

            calculatedStats.BasicStats = stats;

            whiteDPS = finisherDPS = wfDPS = ssDPS = poisonDPS = cpgDPS = 0f;

            missChance  = 28f;
            missChance -= calcOpts.Precision + stats.Hit + stats.HitRating * RogueConversions.HitRatingToHit;
            if (missChance < 0f)
            {
                missChance = 0f;
            }

            mhExpertise = ohExpertise = calcOpts.WeaponExpertise * 5f + stats.Expertise + stats.ExpertiseRating * RogueConversions.ExpertiseRatingToExpertise;

            if (character.Race == Character.CharacterRace.Human)
            {
                if (character.MainHand != null && (character.MainHand.Type == Item.ItemType.OneHandSword || character.MainHand.Type == Item.ItemType.OneHandMace))
                {
                    mhExpertise += 5f;
                }
                if (character.OffHand != null && (character.OffHand.Type == Item.ItemType.OneHandSword || character.OffHand.Type == Item.ItemType.OneHandMace))
                {
                    ohExpertise += 5f;
                }
            }

            mhDodgeChance  = 6.5f;
            mhDodgeChance -= .25f * mhExpertise;

            ohDodgeChance  = 6.5f;
            ohDodgeChance -= .25f * ohExpertise;

            if (mhDodgeChance < 0f)
            {
                mhDodgeChance = 0f;
            }
            if (ohDodgeChance < 0f)
            {
                ohDodgeChance = 0f;
            }

            probMHHit = 1f - missChance / 100f - mhDodgeChance / 100f;
            probOHHit = 1f - missChance / 100f - ohDodgeChance / 100f;

            glanceChance = .25f;

            mhCrit = ohCrit = stats.Crit + stats.CritRating * RogueConversions.CritRatingToCrit;
            if (character.MainHand != null && character.MainHand.Type == Item.ItemType.Dagger)
            {
                mhCrit += calcOpts.DaggerSpecialization;
            }
            if (character.OffHand != null && character.OffHand.Type == Item.ItemType.Dagger)
            {
                ohCrit += calcOpts.DaggerSpecialization;
            }
            if (character.MainHand != null && character.MainHand.Type == Item.ItemType.FistWeapon)
            {
                mhCrit += calcOpts.FistSpecialization;
            }
            if (character.OffHand != null && character.OffHand.Type == Item.ItemType.FistWeapon)
            {
                ohCrit += calcOpts.FistSpecialization;
            }

            // if we have mutilate and we're using two daggers, assume we use it to generate CPs
            if (calcOpts.Mutilate > 0 &&
                character.MainHand != null && character.MainHand.Type == Item.ItemType.Dagger &&
                character.OffHand != null && character.OffHand.Type == Item.ItemType.Dagger)
            {
                cpg       = "mutilate";
                energyCPG = 60f;
            }
            // if we're main handing a dagger, assume we're using backstab it to generate CPs
            else if (character.MainHand != null && character.MainHand.Type == Item.ItemType.Dagger)
            {
                cpg       = "backstab";
                energyCPG = 60f;
            }
            // if we have hemo, assume we use it to generate CPs
            else if (calcOpts.Hemorrhage > 0)
            {
                cpg       = "hemo";
                energyCPG = 35f;
            }
            // otherwise use sinister strike
            else
            {
                cpg = "ss";
                switch (calcOpts.ImprovedSinisterStrike)
                {
                case 2:
                    energyCPG = 40f;
                    break;

                case 1:
                    energyCPG = 42f;
                    break;

                default:
                    energyCPG = 45f;
                    break;
                }
            }

            // cycle stuff
            sndLength  = 6f + 3f * calcOpts.DPSCycle['s'];
            sndLength += stats.BonusSnDDuration;
            sndLength *= 1f + 0.15f * calcOpts.ImprovedSliceandDice;

            ruthlessnessCP = .2f * calcOpts.Ruthlessness;

            numCPG = calcOpts.DPSCycle.TotalComboPoints - 2f * ruthlessnessCP;

            if (calcOpts.DPSCycle['r'] > 0)
            {
                finisherCost = 25f;
            }
            else if (calcOpts.DPSCycle['e'] > 0)
            {
                finisherCost = 35f;
            }
            else
            {
                finisherCost = 0f;
            }

            energyRegen = 10f;
            if (calcOpts.AdrenalineRush > 0)
            {
                energyRegen += .5f;
            }

            sndEnergy = (calcOpts.DPSCycle['s'] - ruthlessnessCP) * energyCPG + 25f;
            sndHaste  = .3f;
            sndHaste *= (1f + stats.BonusSnDHaste);

            totalArmor      = calcOpts.TargetArmor - stats.ArmorPenetration;
            damageReduction = 1f - (totalArmor / (totalArmor + 10557.5f));

            #region White Damage
            whiteDPS = mhWhite = ohWhite = 0f;

            totalHaste  = 1f;
            totalHaste *= (1f + sndHaste) * (1f + (stats.HasteRating * RogueConversions.HasteRatingToHaste) / 100);
            totalHaste *= (1f + .2f * 15f / 120f * calcOpts.BladeFlurry);

            bonusWhiteCritDmg = 1f + stats.BonusCritMultiplier;

            // MH
            mhAttacks = 0f;
            avgMHDmg  = 0f;
            ohHits    = 0f;
            if (character.MainHand != null)
            {
                avgMHDmg  = (character.MainHand.MinDamage + character.MainHand.MaxDamage + stats.WeaponDamage * 2) / 2.0f;
                avgMHDmg += (stats.AttackPower / 14.0f) * character.MainHand.Speed;

                //mhHastedSpeed = character.MainHand.Speed / totalHaste;
                mhAttacks = totalHaste / character.MainHand.Speed;

                mhWhite = avgMHDmg * mhAttacks * probMHHit;

                mhWhite  = (1f - mhCrit / 100f) * mhWhite + (mhCrit / 100f) * (mhWhite * (2f * bonusWhiteCritDmg));
                mhWhite *= damageReduction;
            }

            // OH
            ohAttacks = 0f;
            if (character.OffHand != null)
            {
                avgOHDmg  = (character.OffHand.MinDamage + character.OffHand.MaxDamage + stats.WeaponDamage * 2) / 2.0f;
                avgOHDmg += (stats.AttackPower / 14.0f) * character.OffHand.Speed;
                avgOHDmg *= (0.25f + calcOpts.DualWieldSpecialization * 0.1f);

                ohAttacks = totalHaste / character.OffHand.Speed;
                ohHits    = ohAttacks * probOHHit;

                energyRegen += (.2f * 3f * calcOpts.CombatPotency) * ohHits;

                ohWhite  = avgOHDmg * ohHits;
                ohWhite  = (1f - ohCrit / 100f) * ohWhite + (ohCrit / 100f) * (ohWhite * (2f * bonusWhiteCritDmg));
                ohWhite *= damageReduction;
            }

            cycleTime = (numCPG * energyCPG + 25f + finisherCost) / energyRegen;

            #region CPG Damage
            cpgDPS = 0f;
            if (character.MainHand != null)
            {
                avgCPGDmg           = 0f;
                cpgCrit             = 0f;
                bonusCPGCrit        = 0f;
                bonusCPGDmgMult     = 1f;
                bonusCPGCritDmgMult = 2f;

                if (cpg == "mutilate" && character.OffHand != null)
                {
                    bonusCPGCrit        += 5f * calcOpts.PuncturingWounds;
                    bonusCPGCritDmgMult *= (1f + .06f * calcOpts.Lethality);
                    bonusCPGDmgMult     *= (1f + 0.04f * calcOpts.Opportunity);

                    avgCPGDmg  = (character.MainHand.MinDamage + character.MainHand.MaxDamage) / 2f + 121.5f;
                    avgCPGDmg += stats.AttackPower / 14f * 1.7f;
                    avgCPGDmg += (character.OffHand.MinDamage + character.OffHand.MaxDamage) / 2f + 121.5f;
                    avgCPGDmg += stats.AttackPower / 14f * 1.7f;
                    avgCPGDmg *= 1.5f;
                }
                else if (cpg == "backstab")
                {
                    bonusCPGDmgMult     *= (1f + .02f * calcOpts.Aggression);
                    bonusCPGDmgMult     *= (1f + .1f * calcOpts.SurpriseAttacks);
                    bonusCPGDmgMult     *= (1f + 0.04f * calcOpts.Opportunity);
                    bonusCPGCrit        += 10f * calcOpts.PuncturingWounds;
                    bonusCPGCritDmgMult *= (1f + .06f * calcOpts.Lethality);

                    avgCPGDmg  = (character.MainHand.MinDamage + character.MainHand.MaxDamage + stats.WeaponDamage) / 2f;
                    avgCPGDmg += stats.AttackPower / 14f * 1.7f;
                    avgCPGDmg *= 1.5f;
                    avgCPGDmg += 255f;
                }
                else if (cpg == "hemo")
                {
                    bonusCPGDmgMult     *= (1f + .1f * calcOpts.SurpriseAttacks);
                    bonusCPGDmgMult     *= (1f + stats.BonusCPGDamage);
                    bonusCPGCritDmgMult *= (1f + .06f * calcOpts.Lethality);

                    avgCPGDmg  = (character.MainHand.MinDamage + character.MainHand.MaxDamage + stats.WeaponDamage) / 2f;
                    avgCPGDmg += stats.AttackPower / 14f * 2.4f;
                    avgCPGDmg *= 1.1f;
                }
                else
                {
                    // sinister strike
                    avgCPGDmg  = (character.MainHand.MinDamage + character.MainHand.MaxDamage + stats.WeaponDamage) / 2f;
                    avgCPGDmg += stats.AttackPower / 14f * 2.4f;
                    avgCPGDmg += 98f; // TBC max rank

                    bonusCPGDmgMult     *= (1f + .02f * calcOpts.Aggression);
                    bonusCPGDmgMult     *= (1f + .1f * calcOpts.SurpriseAttacks);
                    bonusCPGDmgMult     *= (1f + stats.BonusCPGDamage);
                    bonusCPGCritDmgMult *= (1f + .06f * calcOpts.Lethality);
                }

                avgCPGDmg *= bonusCPGDmgMult;

                cpgCrit = mhCrit + bonusCPGCrit;

                avgCPGDmg = (1f - cpgCrit / 100f) * avgCPGDmg + (cpgCrit / 100f) * (avgCPGDmg * bonusCPGCritDmgMult);

                cpgDPS  = avgCPGDmg * numCPG / cycleTime;
                cpgDPS *= damageReduction;
            }
            #endregion

            #region Finisher Damage
            finisherDPS = 0f;
            if (character.MainHand != null)
            {
                if (calcOpts.DPSCycle['r'] > 0)
                {
                    switch (calcOpts.DPSCycle['r'])
                    {
                    case 5:
                        finisherDmg = 4f * (stats.AttackPower * .01f + 81f);
                        break;

                    case 4:
                        finisherDmg = 5f * (stats.AttackPower * 0.02f + 92f);
                        break;

                    case 3:
                        finisherDmg = 6f * (stats.AttackPower * 0.03f + 103f);
                        break;

                    case 2:
                        finisherDmg = 7f * (stats.AttackPower * 0.03f + 114f);
                        break;

                    default:
                        finisherDmg = 8f * (stats.AttackPower * 0.03f + 125f);
                        break;
                    }

                    finisherDmg *= (1f + .1f * calcOpts.SerratedBlades) * (1f + stats.BonusBleedDamageMultiplier);
                    finisherDmg *= (1f - missChance / 100f);
                    if (calcOpts.SurpriseAttacks < 1)
                    {
                        finisherDmg *= (1f - mhDodgeChance / 100f);
                    }
                    finisherDPS = finisherDmg / cycleTime;
                }
                else if (calcOpts.DPSCycle['e'] > 0)
                {
                    evisMod = stats.AttackPower * calcOpts.DPSCycle['e'] * .03f;
                    evisMin = 245f + (calcOpts.DPSCycle['e'] - 1f) * 185f + evisMod;
                    evisMax = 365f + (calcOpts.DPSCycle['e'] - 1f) * 185f + evisMod;

                    finisherDmg  = (evisMin + evisMax) / 2f;
                    finisherDmg *= (1f + 0.05f * calcOpts.ImprovedEviscerate);
                    finisherDmg *= (1f + 0.02f * calcOpts.Aggression);
                    finisherDmg  = finisherDmg * (1f - (mhCrit / 100f)) + (finisherDmg * 2f) * (mhCrit / 100f);
                    finisherDmg *= (1f - (missChance / 100f));
                    if (calcOpts.SurpriseAttacks < 1)
                    {
                        finisherDmg *= (1f - (mhDodgeChance / 100f));
                    }
                    finisherDmg *= damageReduction;
                    finisherDPS  = finisherDmg / cycleTime;
                }
                else
                {
                }
            }
            #endregion

            #region Sword Spec Damage
            ssDPS  = 0f;
            ssHits = 0f;

            // main hand
            if (character.MainHand != null && character.MainHand.Type == Item.ItemType.OneHandSword)
            {
                ssHits += mhAttacks * 0.01f * calcOpts.SwordSpecialization * probMHHit;

                // CPG
                ssHits += (numCPG / cycleTime) * 0.01f * calcOpts.SwordSpecialization * probMHHit;

                // finishers
                ssHits += 1f / cycleTime * 0.01f * calcOpts.SwordSpecialization * probMHHit;
            }

            // offhand
            if (character.OffHand != null && character.OffHand.Type == Item.ItemType.OneHandSword)
            {
                ssHits += ohAttacks * 0.01f * calcOpts.SwordSpecialization * probOHHit;
            }

            ssDPS  = (ssHits * avgMHDmg) * (1 - mhCrit / 100f) + (ssHits * avgMHDmg * 2f * bonusWhiteCritDmg) * (mhCrit / 100f);
            ssDPS *= damageReduction;
            #endregion

            #region WF Damage
            wfDPS = 0f;
            if (character.MainHand != null && stats.WindfuryAPBonus > 0)
            {
                wfHits  = mhAttacks * probMHHit * .2f * probMHHit;
                wfHits += ssHits * .2f * probMHHit;

                avgWFDmg  = (character.MainHand.MinDamage + character.MainHand.MaxDamage + stats.WeaponDamage * 2) / 2.0f;
                avgWFDmg += (stats.AttackPower + stats.WindfuryAPBonus) / 14f * character.MainHand.Speed;
                avgWFDmg  = avgWFDmg * (1f - mhCrit / 100f) + avgMHDmg * 2f * (mhCrit / 100f);

                wfDPS  = avgWFDmg * wfHits;
                wfDPS *= damageReduction;
            }
            #endregion

            whiteDPS = mhWhite + ohWhite;
            #endregion

            #region Poison DPS
            poisonDPS  = 0f;
            probPoison = (.83f + .05f * calcOpts.MasterPoisoner) * (.2f + .02f * calcOpts.ImprovedPoisons);
            calcDeadly = true;

            if (character.MainHand != null && stats.WindfuryAPBonus == 0f)
            {
                // no WF, consider the main hand poison
                if (calcOpts.TempMainHandEnchant == "Deadly Poison" && calcDeadly)
                {
                    poisonDPS += 180f * calcOpts.VilePoisons * .04f / 12f;
                    calcDeadly = false;
                }
                else if (calcOpts.TempMainHandEnchant == "Instant Poison")
                {
                    poisonDPS += ohHits * probPoison * 170f * (1f + calcOpts.VilePoisons * 0.04f);
                }
            }
            if (character.OffHand != null)
            {
                if (calcOpts.TempOffHandEnchant == "Deadly Poison" && calcDeadly)
                {
                    poisonDPS += 180f * (1f + calcOpts.VilePoisons * .04f) / 12f;
                    calcDeadly = false;
                }
                else if (calcOpts.TempOffHandEnchant == "Instant Poison")
                {
                    poisonDPS += ohHits * probPoison * 170f * (1f + calcOpts.VilePoisons * 0.04f);
                }
            }
            #endregion

            calculatedStats.WhiteDPS      = whiteDPS + ssDPS;
            calculatedStats.CPGDPS        = cpgDPS;
            calculatedStats.FinisherDPS   = finisherDPS;
            calculatedStats.WindfuryDPS   = wfDPS;
            calculatedStats.SwordSpecDPS  = ssDPS;
            calculatedStats.PoisonDPS     = poisonDPS;
            calculatedStats.DPSPoints     = whiteDPS + cpgDPS + finisherDPS + wfDPS + ssDPS + poisonDPS;
            calculatedStats.OverallPoints = calculatedStats.DPSPoints;
            return(calculatedStats);
        }